<commit_before>suiteHasFailed = function (suite) {
  return !!VelocityTestReports.findOne({
    framework: suite.framework,
    ancestors: suite.ancestors,
    result: "failed"
  });
};

frameworkStatus = function (name) {
  var hasTests = VelocityTestReports.find({framework: name}).count() > 0;
  if (!hasTests) return "empty"

  var frameworkExecStatus = VelocityAggregateReports.findOne({name: name});
  var isComplete = (frameworkExecStatus && frameworkExecStatus.result === "completed");
  var hasFailed = !! VelocityTestReports.findOne({framework: name, result: "failed"});

  if (hasFailed)
    return "failed";
  else if (isComplete)
    return "passed";
  else
    return "pending";
}

function mochaPresent() {
  //XXX hard-coding mocha iframe support for now
  return !! VelocityAggregateReports.findOne({'name': 'mocha'});
}
function nightwatchPresent() {
  return !! VelocityAggregateReports.findOne({'name': 'nightwatch'});
}

Template.velocity.created = function () {
  // Only show widget when we know we are NOT running in a Velocity Mirror
  Session.setDefault('velocity.isMirror', true);

  // Determine if user has disabled velocity
  Meteor.call('velocity/isEnabled', function(error, result){
    Session.set('velocity.isEnabled', !!error ||result);
    //Session.set('velocity.isEnabled', result);
  });

  // Determine if session is running in a Velocity mirror or not
  Meteor.call('velocity/isMirror', function (err, res) {
    if (err) {
      // Log error. HTML Reporter will not be shown
      console.error(err);
    } else {
      Session.set('velocity.isMirror', res);
    }
  })
};

Template.velocity.helpers({
  statusWidgetClass: function () {
    var aggregateResult = VelocityAggregateReports.findOne({name: 'aggregateResult'});
    if (aggregateResult && aggregateResult.result === 'failed') {
      return  'failed';
    }

    var aggregateComplete = VelocityAggregateReports.findOne({name: 'aggregateComplete'});
    if (aggregateComplete && aggregateResult
      && aggregateResult.result === 'passed' && aggregateComplete.result === 'completed') {
      return 'passed';
    }
    return 'pending';
  },
  resetting: function () {
    return Session.get('resettingVelocity')
  },
  testReports: function () {
    return VelocityTestReports.find();
  },
  frameworks: function () {
    return VelocityAggregateReports.find({name: {$nin: ["aggregateResult", "aggregateComplete"]}});
  },
  active: function (id) {
    return reamplify.store(id);
  },
  overlayIsVisible: function () {
    return amplify.store('velocityOverlayIsVisible')
  },
  showVelocity: function () {
    // This causes the html reporter to remain hidden if running in a Velocity mirror
    return Session.equals('velocity.isEnabled', true) && Session.equals('velocity.isMirror', false);
  },
  mochaPresent: mochaPresent,
  nightwatchPresent: nightwatchPresent
});

Template.velocityReports.helpers({
  frameworkStatus: function () {
    return frameworkStatus(this.name)
  },
  isPassed: function (status) {
    return status === 'passed'
  },
  frameworkTotalTestCount: function () {
    return VelocityTestReports.find({framework: this.name}).count();
  },
  frameworkPassedTestCount: function () {
    return VelocityTestReports.find({framework: this.name, result: 'passed'}).count();
  },
  noFrameworkFiles: function () {
    // XXX presence of VelocityAggregateReports is a stand-in for
    // Velocity being loaded. This is a bit brittle. It breaks
    // if you call the Velocity "reset" method.
    var velocityIsLoaded = !! VelocityAggregateReports;
    return  ! velocityIsLoaded ?  false : ! VelocityTestFiles.findOne({targetFramework: this.name});
  },
  suites: function () {
    var result =  [];
    var reports = VelocityTestReports.find({framework: this.name}).fetch();
    // XXX for now, ancestors get reduced to a single-tier suite
    // Should we do fancier indenting, etc. for nested suites?
    // If not, forcing packages to concatenate their own "suite" string
    // instead of ancestors array would clean this up.
    if (reports.length > 0) {

      var reports = _.map(reports, function (report) {
        //must clone report.ancestors to not mutate report.ancestors with .reverse()
        var ancestors = report.ancestors ? _.clone(report.ancestors) : [];
        report.suite = ancestors.reverse().join(".");
        return report;
      });

      _.each(reports, function (report) {
        if (! _.findWhere(result, {suite: report.suite}))
          result.push({
            framework: report.framework,
            ancestors: report.ancestors, //needed for future queries
            suite: report.suite
          })
      });

      return result;
    }
  },
  suiteStatus: function () {
    return suiteHasFailed(this) ? 'failed' : 'passed';
  },
  suiteNotHidden: function () {
    if (!reamplify.store('showSuccessful'))
      return suiteHasFailed(this);
    return true;
  },
  reports: function () {
    return VelocityTestReports.find({
      framework: this.framework,
      ancestors: this.ancestors
    });
  }
});

Template.velocitySummary.helpers({
  anyFailed: function () {
    var aggregateResult = VelocityAggregateReports.findOne({name: 'aggregateResult'})
    if (aggregateResult && aggregateResult.result === 'failed') {
      return  true;
    }
    return false;
  },
  totalTime: function () {
    var results = VelocityTestReports.find().fetch();

    var firstTimeStamp, lastTimestamp, lastDuration;
    _.each(results, function (result) {
      if (!firstTimeStamp ||  firstTimeStamp > result.timestamp.getTime()) {
        firstTimeStamp = result.timestamp.getTime();
      }
      if (!lastTimestamp ||  lastTimestamp < result.timestamp.getTime()) {
        lastTimestamp = result.timestamp.getTime();
        lastDuration = result.duration;
      }
    });

    //var ms = results
    //  .reduce(function (tot, i) { return tot + (i.duration || 0) }, 0);

    var ms = lastTimestamp + lastDuration - firstTimeStamp;

    if (ms >= 1000) return Math.round(ms / 1000) + ' s';

    return ms?ms:0 + ' ms';
  },
  regularPlural: function (count, word, suffix) {
    if(count === 1) return word;
    return word + suffix;
  },
  totalFailedTestCount: function () {
    return VelocityTestReports.find({result: 'failed'}).count();
  },
  totalTestCount: function () {
    return VelocityTestReports.find().count();
  },
  totalPassedTestCount: function () {
    return VelocityTestReports.find({result: 'passed'}).count();
  }
});

Template.velocityControlPanel.helpers({
  mochaPresent: mochaPresent,
  nightwatchPresent: nightwatchPresent,
  showActive: function (id) {
    // XXX refactor this to name consistently
    return !reamplify.store(id) ? '' : 'active';
  },
  showActive: function (self) {
    // $self = $("#"+ self);
    return reamplify.store(self) ? 'active' : ''
  }
});

Template.velocityControlPanel.events({
  'click #runNightwatchTests': function () {
    Meteor.call('nightwatch/run');
  }
})

Template.velocityTestReport.helpers({
  reportNotHidden: function () {
    if (this.result === "failed")
      return true;
    else{
      return (reamplify.store('showSuccessful'));
    }
  },
  failed: function () {
    return (this.result === "failed");
  }
});

Template.velocityTestFiles.helpers({
  testFiles: function () {
    return VelocityTestFiles.find();
  },
  isVisible: function () {
    return amplify.store('velocityTestFilesIsVisible') ? 'block' : 'none';
  }
});

Template.velocityLogs.helpers({
  logs: function () {
    return VelocityLogs.find();
  },
  isVisible: function () {
    return amplify.store('velocityLogsIsVisible') ? 'block' : 'none';
  }
});

Template.velocity.events({
  'click .display-toggle': function (e) {
    var targetId = $(e.currentTarget).data('target'),
        $target = $('#' + targetId);
    $target.toggleClass('visible');
    amplify.store(targetId + 'IsVisible', $target.hasClass('visible') );
  },
  'change input:checkbox': function (e) {
    var targetId = e.target.id
    reamplify.store(e.target.id, e.target.checked);
  },
  'click button.control-toggle': function (e) {
    var $target = $('#' + e.target.id);
    $target.toggleClass('active');
    reamplify.store(e.target.id, $target.hasClass('active'));
  },
  'click .velocity-options-toggle': function (e, tpl) {
    tpl.$('.velocity-options').toggleClass('visible')
  }
});

Template.velocityReports.events({
  'click .copy-sample-tests': function (e) {
    Meteor.call('velocity/copySampleTests', {framework: this.name}, function (err, res) {
      // XXX This method for getting the new files to register is slow, but it
      // works. The reset method gets Velocity to see the new files.
      // We then disconnect altogether to prevent flapping of reactive
      // template elements (& overlay a notification to show the user
      // what's happening). Then we simply reload. Is there a way to do this
      // with a lighter touch?

      // make sure the user can see the demo tests, which generally pass.
      reamplify.store('showSuccessful', true);
      Session.set('resettingVelocity', true)
      Meteor.call('velocity/reset');
      Meteor.disconnect();
      location.reload();
    });
  }
});
<commit_msg>removing hotfix since new velocity does not need it. Also adding error messaging<commit_after>suiteHasFailed = function (suite) {
  return !!VelocityTestReports.findOne({
    framework: suite.framework,
    ancestors: suite.ancestors,
    result: "failed"
  });
};

frameworkStatus = function (name) {
  var hasTests = VelocityTestReports.find({framework: name}).count() > 0;
  if (!hasTests) return "empty"

  var frameworkExecStatus = VelocityAggregateReports.findOne({name: name});
  var isComplete = (frameworkExecStatus && frameworkExecStatus.result === "completed");
  var hasFailed = !! VelocityTestReports.findOne({framework: name, result: "failed"});

  if (hasFailed)
    return "failed";
  else if (isComplete)
    return "passed";
  else
    return "pending";
}

function mochaPresent() {
  //XXX hard-coding mocha iframe support for now
  return !! VelocityAggregateReports.findOne({'name': 'mocha'});
}
function nightwatchPresent() {
  return !! VelocityAggregateReports.findOne({'name': 'nightwatch'});
}

Template.velocity.created = function () {
  // Only show widget when we know we are NOT running in a Velocity Mirror
  Session.setDefault('velocity.isMirror', true);

  // Determine if user has disabled velocity
  Meteor.call('velocity/isEnabled', function(error, result){
    if (err) {
      // Log error. HTML Reporter will not be shown
      console.error(err);
    } else {
      Session.set('velocity.isEnabled', result);
    }
  });

  // Determine if session is running in a Velocity mirror or not
  Meteor.call('velocity/isMirror', function (err, res) {
    if (err) {
      // Log error. HTML Reporter will not be shown
      console.error(err);
    } else {
      Session.set('velocity.isMirror', res);
    }
  })
};

Template.velocity.helpers({
  statusWidgetClass: function () {
    var aggregateResult = VelocityAggregateReports.findOne({name: 'aggregateResult'});
    if (aggregateResult && aggregateResult.result === 'failed') {
      return  'failed';
    }

    var aggregateComplete = VelocityAggregateReports.findOne({name: 'aggregateComplete'});
    if (aggregateComplete && aggregateResult
      && aggregateResult.result === 'passed' && aggregateComplete.result === 'completed') {
      return 'passed';
    }
    return 'pending';
  },
  resetting: function () {
    return Session.get('resettingVelocity')
  },
  testReports: function () {
    return VelocityTestReports.find();
  },
  frameworks: function () {
    return VelocityAggregateReports.find({name: {$nin: ["aggregateResult", "aggregateComplete"]}});
  },
  active: function (id) {
    return reamplify.store(id);
  },
  overlayIsVisible: function () {
    return amplify.store('velocityOverlayIsVisible')
  },
  showVelocity: function () {
    // This causes the html reporter to remain hidden if running in a Velocity mirror
    return Session.equals('velocity.isEnabled', true) && Session.equals('velocity.isMirror', false);
  },
  mochaPresent: mochaPresent,
  nightwatchPresent: nightwatchPresent
});

Template.velocityReports.helpers({
  frameworkStatus: function () {
    return frameworkStatus(this.name)
  },
  isPassed: function (status) {
    return status === 'passed'
  },
  frameworkTotalTestCount: function () {
    return VelocityTestReports.find({framework: this.name}).count();
  },
  frameworkPassedTestCount: function () {
    return VelocityTestReports.find({framework: this.name, result: 'passed'}).count();
  },
  noFrameworkFiles: function () {
    // XXX presence of VelocityAggregateReports is a stand-in for
    // Velocity being loaded. This is a bit brittle. It breaks
    // if you call the Velocity "reset" method.
    var velocityIsLoaded = !! VelocityAggregateReports;
    return  ! velocityIsLoaded ?  false : ! VelocityTestFiles.findOne({targetFramework: this.name});
  },
  suites: function () {
    var result =  [];
    var reports = VelocityTestReports.find({framework: this.name}).fetch();
    // XXX for now, ancestors get reduced to a single-tier suite
    // Should we do fancier indenting, etc. for nested suites?
    // If not, forcing packages to concatenate their own "suite" string
    // instead of ancestors array would clean this up.
    if (reports.length > 0) {

      var reports = _.map(reports, function (report) {
        //must clone report.ancestors to not mutate report.ancestors with .reverse()
        var ancestors = report.ancestors ? _.clone(report.ancestors) : [];
        report.suite = ancestors.reverse().join(".");
        return report;
      });

      _.each(reports, function (report) {
        if (! _.findWhere(result, {suite: report.suite}))
          result.push({
            framework: report.framework,
            ancestors: report.ancestors, //needed for future queries
            suite: report.suite
          })
      });

      return result;
    }
  },
  suiteStatus: function () {
    return suiteHasFailed(this) ? 'failed' : 'passed';
  },
  suiteNotHidden: function () {
    if (!reamplify.store('showSuccessful'))
      return suiteHasFailed(this);
    return true;
  },
  reports: function () {
    return VelocityTestReports.find({
      framework: this.framework,
      ancestors: this.ancestors
    });
  }
});

Template.velocitySummary.helpers({
  anyFailed: function () {
    var aggregateResult = VelocityAggregateReports.findOne({name: 'aggregateResult'})
    if (aggregateResult && aggregateResult.result === 'failed') {
      return  true;
    }
    return false;
  },
  totalTime: function () {
    var results = VelocityTestReports.find().fetch();

    var firstTimeStamp, lastTimestamp, lastDuration;
    _.each(results, function (result) {
      if (!firstTimeStamp ||  firstTimeStamp > result.timestamp.getTime()) {
        firstTimeStamp = result.timestamp.getTime();
      }
      if (!lastTimestamp ||  lastTimestamp < result.timestamp.getTime()) {
        lastTimestamp = result.timestamp.getTime();
        lastDuration = result.duration;
      }
    });

    //var ms = results
    //  .reduce(function (tot, i) { return tot + (i.duration || 0) }, 0);

    var ms = lastTimestamp + lastDuration - firstTimeStamp;

    if (ms >= 1000) return Math.round(ms / 1000) + ' s';

    return ms?ms:0 + ' ms';
  },
  regularPlural: function (count, word, suffix) {
    if(count === 1) return word;
    return word + suffix;
  },
  totalFailedTestCount: function () {
    return VelocityTestReports.find({result: 'failed'}).count();
  },
  totalTestCount: function () {
    return VelocityTestReports.find().count();
  },
  totalPassedTestCount: function () {
    return VelocityTestReports.find({result: 'passed'}).count();
  }
});

Template.velocityControlPanel.helpers({
  mochaPresent: mochaPresent,
  nightwatchPresent: nightwatchPresent,
  showActive: function (id) {
    // XXX refactor this to name consistently
    return !reamplify.store(id) ? '' : 'active';
  },
  showActive: function (self) {
    // $self = $("#"+ self);
    return reamplify.store(self) ? 'active' : ''
  }
});

Template.velocityControlPanel.events({
  'click #runNightwatchTests': function () {
    Meteor.call('nightwatch/run');
  }
})

Template.velocityTestReport.helpers({
  reportNotHidden: function () {
    if (this.result === "failed")
      return true;
    else{
      return (reamplify.store('showSuccessful'));
    }
  },
  failed: function () {
    return (this.result === "failed");
  }
});

Template.velocityTestFiles.helpers({
  testFiles: function () {
    return VelocityTestFiles.find();
  },
  isVisible: function () {
    return amplify.store('velocityTestFilesIsVisible') ? 'block' : 'none';
  }
});

Template.velocityLogs.helpers({
  logs: function () {
    return VelocityLogs.find();
  },
  isVisible: function () {
    return amplify.store('velocityLogsIsVisible') ? 'block' : 'none';
  }
});

Template.velocity.events({
  'click .display-toggle': function (e) {
    var targetId = $(e.currentTarget).data('target'),
        $target = $('#' + targetId);
    $target.toggleClass('visible');
    amplify.store(targetId + 'IsVisible', $target.hasClass('visible') );
  },
  'change input:checkbox': function (e) {
    var targetId = e.target.id
    reamplify.store(e.target.id, e.target.checked);
  },
  'click button.control-toggle': function (e) {
    var $target = $('#' + e.target.id);
    $target.toggleClass('active');
    reamplify.store(e.target.id, $target.hasClass('active'));
  },
  'click .velocity-options-toggle': function (e, tpl) {
    tpl.$('.velocity-options').toggleClass('visible')
  }
});

Template.velocityReports.events({
  'click .copy-sample-tests': function (e) {
    Meteor.call('velocity/copySampleTests', {framework: this.name}, function (err, res) {
      // XXX This method for getting the new files to register is slow, but it
      // works. The reset method gets Velocity to see the new files.
      // We then disconnect altogether to prevent flapping of reactive
      // template elements (& overlay a notification to show the user
      // what's happening). Then we simply reload. Is there a way to do this
      // with a lighter touch?

      // make sure the user can see the demo tests, which generally pass.
      reamplify.store('showSuccessful', true);
      Session.set('resettingVelocity', true)
      Meteor.call('velocity/reset');
      Meteor.disconnect();
      location.reload();
    });
  }
});
<|endoftext|>


<commit_before>'use strict';

var EventEmitter = require('events').EventEmitter;
var Events = require('./events.js').Events;
var guidManager = require('../utils/guids.js');

var contactsEndpoint = require('../endpoints/contacts-v1.js');
var conversationsEndpoint = require('../endpoints/conversations-v1.js');
var loginEndpoint = require('../endpoints/logins-v1.js');
var groupsEndpoints = require('../endpoints/groups-v1.js');
var notificationsEndpoint = require('../endpoints/notifications-v1.js');
var sessionsEndpoint = require('../endpoints/sessions-v1.js');

var winston = require('winston');

var serverModule = require('./servers.js');
var conversationsModule = require('./conversations.js');
var notificationsModule = require('./notifications.js');

/**
 * Cursejs lib client
 */
class Client extends EventEmitter {
    constructor(debugLevel){
        super();

        if(debugLevel === undefined){
            debugLevel = 'info';
        }

        //Change console settings for the logger
        winston.remove(winston.transports.Console)
        winston.add(winston.transports.Console, {
            level: debugLevel,
            prettyPrint: true,
            colorize: true,
            silent: false,
            timestamp: true
        });

        this._loginSession;
        this._notifier;
        this._loginRequest = {login: "", password: ""};
        this._connected = false;

        this.machineKey = guidManager.getMachineKey();
        this.token;
        this._tokenExpires;
        this._tokenRenewAfter;

        this.servers = {};
        this.channels = {};
        this.conversations = {};
        this.users = {};
        this.messages = {};

        this.clientID;

        this.serverList = [];
        this.friendList = []; //Please don't use them until we can manage friends at user level.

    }

    /**
     * IMPORTANT ! Login function will not get your client ready, if you don't know what you do please use the run function.
     * @param  {string}     login       Your Curse login name
     * @param  {string}     password    Your Curse login password
     * @param  {Function}   callback    Facultative arg, callback: (errors) => {};
     */
    login(login, password, callback){
        //Define an empty void if no callback specified
        if(callback === undefined){
            callback = _ => {};
        }

        this._loginRequest = new loginEndpoint.LoginRequest(login, password);
        var self = this; //Make object avalaible for callbacks

        loginEndpoint.login(this._loginRequest, function(errors, answer){
            if(errors === null){
                self._loginSession = answer.Session;
                self.token = self._loginSession['Token'];
                self._tokenExpires = self._loginSession['Expires'];
                self._tokenRenewAfter = self._loginSession['RenewAfter'];
                self.clientID = self._loginSession['UserID'];
                self._connected = true;

                //Renew session automatically
                self._renewSessionInterval = setInterval(self._renewSession, 604800000);

                winston.log('info', 'Client.login', 'Succesfully connected to REST Curse API.');
                self.emit(Events.CONNECTED);
                callback(null);
            } else {
                winston.log('error', 'Client.login:', 'Status:', errors);
                callback(errors);
            }
        });
    }

    /**
     * Renew the token for all the rest api request before the rest session exprire (renew is automatically scheduled)
     */
    _renewSession(){
        var renewRequest = new loginEndpoint.RenewTokenResponseContract(self.token, self._tokenExpires, self._tokenRenewAfter);
        loginEndpoint.loginRenew(renewRequest, self.token, function(errors, answer){
            if(errors === null){
                self.token = answer.Token;
                self._tokenExpires = answer.Expires;
                self._tokenRenewAfter = answer.RenewAfter;
            } else {
                winston.log('error', 'Client._renewSession', 'Couldn\'t renew the token will try again next time', errors);
            }
        });
    }

    /**
     * Fill up the serverList and friendList properties (erasing existing, DO NOT use it to update the server infos)
     * (The erasing thing is not true anymore but it's still not a good idea to do so, we'll get some change later..).
     */
    _loadContacts(callback){
        //Define an empty void if no callback specified
        if(callback === undefined){
            callback = _ => {};
        }

        var self = this;
        contactsEndpoint.contacts(this.token, function(errors, answer){
            if(errors === null){
                answer['Groups'].forEach(function(item){
                    //Take only servers
                    if(item.GroupType == groupsEndpoints.GroupType.Large){
                        //Check that server is not already existing
                        if(self.servers[item.GroupID] === undefined){
                            var server = new serverModule.Server(item, self);
                            self.serverList.push(server);
                        }
                    }
                });

                self.friendList = answer['Friends']; //Thoses friends are not useable yet (who needs friends ?)
                callback(null);
            } else {
                callback(errors);
            }
        });

    }

    get username(){
        if(this._connected){
            return this._loginSession.Username;
        } else {
            return undefined;
        }
    }

    /**
     * All-in-one function that makes the client to work seemlessly
     * @param  {string} login    Your Curse login name
     * @param  {string} password Your Curse login password
     */
    run(login, password){
        var self = this;
        var ready = false;

        this._notifier = new notificationsModule.Notifier(this);

        this.on(Events.CONNECTED, function(){
            self._loadContacts(function(errors){
                if(errors === null){
                    self._notifier.start();
                }
                else {
                    winston.log('error', 'Client.run', 'Cannot get contacts', errors);
                }
            });

        });

        this.on(Events.NOTIFIER_CONNECTED, function(){
            if(!ready){
                //Call Ready event when Websocket connection is established
                self.emit(Events.READY);
                ready = true;
            }
        })

        this.login(login, password);
    }

    /**
     * Send a message in a conversation
     * @param  {Conversation}   conversation    Conversation
     * @param  {string}         content         Message content
     * @param  {Function}       callback        Facultative arg, callback: () => {};
     */
    sendMessage(conversation, content, callback){
        //Define an empty void if no callback specified
        if(callback === undefined){
            callback = _ => {};
        }
        conversation.sendMessage(content, callback);
    }

}

exports.Client = Client;
<commit_msg>Fix renew session function<commit_after>'use strict';

var EventEmitter = require('events').EventEmitter;
var Events = require('./events.js').Events;
var guidManager = require('../utils/guids.js');

var contactsEndpoint = require('../endpoints/contacts-v1.js');
var conversationsEndpoint = require('../endpoints/conversations-v1.js');
var loginEndpoint = require('../endpoints/logins-v1.js');
var groupsEndpoints = require('../endpoints/groups-v1.js');
var notificationsEndpoint = require('../endpoints/notifications-v1.js');
var sessionsEndpoint = require('../endpoints/sessions-v1.js');

var winston = require('winston');

var serverModule = require('./servers.js');
var conversationsModule = require('./conversations.js');
var notificationsModule = require('./notifications.js');

/**
 * Cursejs lib client
 */
class Client extends EventEmitter {
    constructor(debugLevel){
        super();

        if(debugLevel === undefined){
            debugLevel = 'info';
        }

        //Change console settings for the logger
        winston.remove(winston.transports.Console)
        winston.add(winston.transports.Console, {
            level: debugLevel,
            prettyPrint: true,
            colorize: true,
            silent: false,
            timestamp: true
        });

        this._loginSession;
        this._notifier;
        this._loginRequest = {login: "", password: ""};
        this._connected = false;

        this.machineKey = guidManager.getMachineKey();
        this.token;
        this._tokenExpires;
        this._tokenRenewAfter;

        this.servers = {};
        this.channels = {};
        this.conversations = {};
        this.users = {};
        this.messages = {};

        this.clientID;

        this.serverList = [];
        this.friendList = []; //Please don't use them until we can manage friends at user level.

    }

    /**
     * IMPORTANT ! Login function will not get your client ready, if you don't know what you do please use the run function.
     * @param  {string}     login       Your Curse login name
     * @param  {string}     password    Your Curse login password
     * @param  {Function}   callback    Facultative arg, callback: (errors) => {};
     */
    login(login, password, callback){
        //Define an empty void if no callback specified
        if(callback === undefined){
            callback = _ => {};
        }

        this._loginRequest = new loginEndpoint.LoginRequest(login, password);
        var self = this; //Make object avalaible for callbacks

        loginEndpoint.login(this._loginRequest, function(errors, answer){
            if(errors === null){
                self._loginSession = answer.Session;
                self.token = self._loginSession['Token'];
                self._tokenExpires = self._loginSession['Expires'];
                self._tokenRenewAfter = self._loginSession['RenewAfter'];
                self.clientID = self._loginSession['UserID'];
                self._connected = true;

                //Renew session automatically
                self._renewSessionInterval = setInterval(self._renewSession, 604800000);

                winston.log('info', 'Client.login', 'Succesfully connected to REST Curse API.');
                self.emit(Events.CONNECTED);
                callback(null);
            } else {
                winston.log('error', 'Client.login:', 'Status:', errors);
                callback(errors);
            }
        });
    }

    /**
     * Renew the token for all the rest api request before the rest session exprire (renew is automatically scheduled)
     */
    _renewSession(){
        var self = this;
        var renewRequest = new loginEndpoint.RenewTokenResponseContract(this.token, this._tokenExpires, this._tokenRenewAfter);
        loginEndpoint.loginRenew(renewRequest, self.token, function(errors, answer){
            if(errors === null){
                self.token = answer.Token;
                self._tokenExpires = answer.Expires;
                self._tokenRenewAfter = answer.RenewAfter;
            } else {
                winston.log('error', 'Client._renewSession', 'Couldn\'t renew the token will try again next time', errors);
            }
        });
    }

    /**
     * Fill up the serverList and friendList properties (erasing existing, DO NOT use it to update the server infos)
     * (The erasing thing is not true anymore but it's still not a good idea to do so, we'll get some change later..).
     */
    _loadContacts(callback){
        //Define an empty void if no callback specified
        if(callback === undefined){
            callback = _ => {};
        }

        var self = this;
        contactsEndpoint.contacts(this.token, function(errors, answer){
            if(errors === null){
                answer['Groups'].forEach(function(item){
                    //Take only servers
                    if(item.GroupType == groupsEndpoints.GroupType.Large){
                        //Check that server is not already existing
                        if(self.servers[item.GroupID] === undefined){
                            var server = new serverModule.Server(item, self);
                            self.serverList.push(server);
                        }
                    }
                });

                self.friendList = answer['Friends']; //Thoses friends are not useable yet (who needs friends ?)
                callback(null);
            } else {
                callback(errors);
            }
        });

    }

    get username(){
        if(this._connected){
            return this._loginSession.Username;
        } else {
            return undefined;
        }
    }

    /**
     * All-in-one function that makes the client to work seemlessly
     * @param  {string} login    Your Curse login name
     * @param  {string} password Your Curse login password
     */
    run(login, password){
        var self = this;
        var ready = false;

        this._notifier = new notificationsModule.Notifier(this);

        this.on(Events.CONNECTED, function(){
            self._loadContacts(function(errors){
                if(errors === null){
                    self._notifier.start();
                }
                else {
                    winston.log('error', 'Client.run', 'Cannot get contacts', errors);
                }
            });

        });

        this.on(Events.NOTIFIER_CONNECTED, function(){
            if(!ready){
                //Call Ready event when Websocket connection is established
                self.emit(Events.READY);
                ready = true;
            }
        })

        this.login(login, password);
    }

    /**
     * Send a message in a conversation
     * @param  {Conversation}   conversation    Conversation
     * @param  {string}         content         Message content
     * @param  {Function}       callback        Facultative arg, callback: () => {};
     */
    sendMessage(conversation, content, callback){
        //Define an empty void if no callback specified
        if(callback === undefined){
            callback = _ => {};
        }
        conversation.sendMessage(content, callback);
    }

}

exports.Client = Client;
<|endoftext|>


<commit_before>var CloudCommander, CodeMirror;
/* object contains editors CodeMirror
 * and later will be Ace
 */
CloudCommander.Editor = {};
CloudCommander.Editor.CodeMirror = {
    load: (function(pParent){ /* function loads CodeMirror js and css files */

        /* function shows editor */
        var createEditorDiv = function(){
            if (!document.getElementById('CloudEditor')) {
                var lEditor=document.createElement('div');
                lEditor.id ='CloudEditor';
                var lFM = document.getElementById('fm');

                if(lFM){
                    lFM.appendChild(lEditor);
                }else console.log('Error. Something went wrong FM not found');

                pParent.show();
            }
        };
        /* function loads css files
         * of CodeMirror
         */
        var loadAll = function(pParent) {
            return function(){
                CloudCommander.cssLoad({
                    src     : 'lib/client/editor/codemirror/pack/codemirror.pack.css'
                });

                CloudCommander.cssLoad({
                    src     : 'lib/client/editor/codemirror/pack/night.pack.css'
                });

                CloudCommander.cssSet({id:'editor',
                    inner : '.CodeMirror{'                          +
                                'font-family :\'Droid Sans Mono\';' +
                                'font-size   :15px;'                +
                                'resize      :vertical;'            +
                                'padding     :20px;'                +
                            '}'                                     +
                            '.CodeMirror-scroll{'                   +
                                'height      : 660px;'              +
                            '}'                                     +
                            '.CodeMirror-scrollbar{'                +
                                 'overflow-y :auto'                 +
                            '}'
                });

                CloudCommander.jsload('lib/client/editor/codemirror/pack/xml.pack.js',
                    createEditorDiv);
            };
        };

        /* load CodeMirror main module */
        CloudCommander.jsload('lib/client/editor/codemirror/pack/codemirror.pack.js',
            loadAll(this));
    }),

    show : (function(){ /* function shows CodeMirror editor */
            /* if CloudEditor is not loaded - loading him */
            if(!document.getElementById('CloudEditor'))
                return this.load(this);
              /* removing keyBinding if set */
            CloudCommander.keyBinded = false;

            var lLeft           = this.getById('left');
            var lCloudEditor    = this.getById('CloudEditor');
            var lCURRENTFILE    = CloudCommander.CURRENT_FILE;

            var lCurrent        = this.getByClass(lCURRENTFILE);
            var lA;
            if(lCurrent.length)
                lA = lCurrent[0].getElementsByTagName('a');

            if(lA.length)
                lA = lA[0].href;

            var lValue = $.ajax(lA);
            if(lValue.responseText)
                lValue = lValue.responseText;

            lLeft   &&
                (lLeft.className = 'panel hidden');

            CodeMirror(lCloudEditor,{
                            mode        : 'xml',
                            value       : lValue,
                            theme       : 'night',
                            lineNumbers : true,
                            //переносим длинные строки
                            lineWrapping: true,
                            autofocus   : true,
                            extraKeys: {
                              //Сохранение
                              "Esc": this.hide(this)
                            }
            });
        }),
    hide :  (function(pParent) {
                return function(){
                    CloudCommander.keyBinded = true;

                    var lLeft           = pParent.getById('left');
                    var lCloudEditor    = pParent.getById('CloudEditor');

                    /*
                    lCloudEditor &&
                        (lCloudEditor.className  = 'hidden');
                    */
                    lLeft       &&
                        (lLeft.className         = 'panel');

                    var lCodeMirror = pParent.getByClass('CodeMirror');
                    if(lCodeMirror.length)
                        lCloudEditor
                            .removeChild(lCodeMirror[0]);
                };
            }),
    getById     : function(pId){return document.getElementById(pId);},

    getByClass  : function(pClass){
        return document.getElementsByClassName(pClass);
    },

    getPanel    : function(){
        var lCurrent = document.getElementsByClassName('current-file');
        lCurrent.length &&
            (lCurrent = lCurrent[0].parentElement);

        return lCurrent && lCurrent.id;
    }
};
CloudCommander.Editor.Keys = (function(){
    "use strict";

    /* loading js and css of CodeMirror */
    CloudCommander.Editor.CodeMirror.show(CloudCommander.Editor.CodeMirror);

    var key_event=function(event){

        /* если клавиши можно обрабатывать */
        if(CloudCommander.keyBinded){
            /* if f4 pressed */
            if(event.keyCode===115){
                CloudCommander.Editor.CodeMirror.show();
            }
        }
    };

    /* добавляем обработчик клавишь */
    if (document.addEventListener)
        document.addEventListener('keydown', key_event,false);

    else
        document.onkeypress=key_event;
});<commit_msg>minor changes<commit_after>var CloudCommander, CodeMirror;
/* object contains editors CodeMirror
 * and later will be Ace
 */
CloudCommander.Editor = {};
CloudCommander.Editor.CodeMirror = {
    load: (function(pParent){ /* function loads CodeMirror js and css files */

        /* function shows editor */
        var createEditorDiv = function(){
            if (!document.getElementById('CloudEditor')) {
                var lEditor=document.createElement('div');
                lEditor.id ='CloudEditor';
                var lFM = document.getElementById('fm');

                if(lFM){
                    lFM.appendChild(lEditor);
                }else console.log('Error. Something went wrong FM not found');

                pParent.show();
            }
        };
        /* function loads css files
         * of CodeMirror
         */
        var loadAll = function(pParent) {
            return function(){
                CloudCommander.cssLoad({
                    src     : 'lib/client/editor/codemirror/pack/codemirror.pack.css'
                });

                CloudCommander.cssLoad({
                    src     : 'lib/client/editor/codemirror/pack/night.pack.css'
                });

                CloudCommander.cssSet({id:'editor',
                    inner : '.CodeMirror{'                          +
                                'font-family :\'Droid Sans Mono\';' +
                                'font-size   :15px;'                +
                                'resize      :vertical;'            +
                                'padding     :20px;'                +
                            '}'                                     +
                            '.CodeMirror-scroll{'                   +
                                'height      : 660px;'              +
                            '}'                                     +
                            '.CodeMirror-scrollbar{'                +
                                 'overflow-y :auto'                 +
                            '}'
                });

                CloudCommander.jsload('lib/client/editor/codemirror/pack/xml.pack.js',
                    createEditorDiv);
            };
        };

        /* load CodeMirror main module */
        CloudCommander.jsload('lib/client/editor/codemirror/pack/codemirror.pack.js',
            loadAll(this));
    }),

    show : (function(){ /* function shows CodeMirror editor */
            /* if CloudEditor is not loaded - loading him */
            if(!document.getElementById('CloudEditor'))
                return this.load(this);
              /* removing keyBinding if set */
            CloudCommander.keyBinded = false;

            var initCodeMirror_f = function(pValue){
                CodeMirror(lCloudEditor,{
                    mode        : 'xml',
                    value       : pValue,
                    theme       : 'night',
                    lineNumbers : true,
                    //переносим длинные строки
                    lineWrapping: true,
                    autofocus   : true,
                    extraKeys: {
                      //Сохранение
                      "Esc": this.hide(this)
                    }
                });
            };

            var lLeft           = this.getById('left');
            var lCloudEditor    = this.getById('CloudEditor');
            var lCURRENTFILE    = CloudCommander.CURRENT_FILE;

            var lCurrent        = this.getByClass(lCURRENTFILE);
            var lA;
            if(lCurrent.length)
                lA = lCurrent[0].getElementsByTagName('a');

            if(lA.length)
                lA = lA[0].href;

            /* reading data from current file */
            var lValue = $.ajax({
                url:lA,

                 error: function(jqXHR, textStatus, errorThrown){
                    console.log(textStatus+' : '+errorThrown);
                    initCodeMirror_f('');
                 },

                 success:function(data, textStatus, jqXHR){
                    initCodeMirror_f(data);
                }
            });
            if(lValue.responseText)
                lValue = lValue.responseText;

            lLeft   &&
                (lLeft.className = 'panel hidden');
        }),
    hide :  (function(pParent) {
                return function(){
                    CloudCommander.keyBinded = true;

                    var lLeft           = pParent.getById('left');
                    var lCloudEditor    = pParent.getById('CloudEditor');

                    /*
                    lCloudEditor &&
                        (lCloudEditor.className  = 'hidden');
                    */
                    lLeft       &&
                        (lLeft.className         = 'panel');

                    var lCodeMirror = pParent.getByClass('CodeMirror');
                    if(lCodeMirror.length)
                        lCloudEditor
                            .removeChild(lCodeMirror[0]);
                };
            }),
    getById     : function(pId){return document.getElementById(pId);},

    getByClass  : function(pClass){
        return document.getElementsByClassName(pClass);
    },

    getPanel    : function(){
        var lCurrent = document.getElementsByClassName('current-file');
        lCurrent.length &&
            (lCurrent = lCurrent[0].parentElement);

        return lCurrent && lCurrent.id;
    }
};
CloudCommander.Editor.Keys = (function(){
    "use strict";

    /* loading js and css of CodeMirror */
    CloudCommander.Editor.CodeMirror.show(CloudCommander.Editor.CodeMirror);

    var key_event=function(event){

        /* если клавиши можно обрабатывать */
        if(CloudCommander.keyBinded){
            /* if f4 pressed */
            if(event.keyCode===115){
                CloudCommander.Editor.CodeMirror.show();
            }
        }
    };

    /* добавляем обработчик клавишь */
    if (document.addEventListener)
        document.addEventListener('keydown', key_event,false);

    else
        document.onkeypress=key_event;
});<|endoftext|>


<commit_before>var _    = require('lodash');
var util = require('util');

module.exports = commandChart;

function commandChart (token, options) {
  this.token = token;
  this.options = options;
}

commandChart.prototype.handle = function (req, res, cb) {
  /*
  {
    "text": "<http://chart.finance.yahoo.com...>",
    "attachments": [
      { "image_url": "<http://chart.finance.yahoo.com...>" }
    ]
  }
  */
  res.setHeader('content-type', 'application/json');
  var chartUrl = "http://chart.finance.yahoo.com/t?lang=en-US&region=US&width=300&height=180&s=";
  //var chartUrl = "http://www.marketwatch.com/kaavio.Webhost/charts/big.chart?&symb="
  //var chartUrl = "http://www.jameshedberg.com/img/samples/carbon-nanotube-3D-model-axial.png";
  var symbol = req.body.text;
  chartUrl += symbol;
  console.log(chartUrl);
  //var output = '<'+chartUrl+'>';
  //var output = '{"text":' + ' "<' + chartUrl + '>"' + ', "unfurl_link": true}';
  var output = '{';
  output += '"response_type": "in_channel",';
  output += '"text":' + ' "' + 'Daily Chart for : ' + symbol + '" ,';
  output += '"attachments":' + '[';
  output += '{';
  output += '"text":' + ' "<' + chartUrl + '>" ,';
  output += '"image_url":' + ' "' + chartUrl + '"';
  //output += '"image_url":' + ' "' + chartUrl + '" ,';
  //output += '"unfurl_media": true';
  output += '}';
  output += ']';
  output += '}';
  cb(null, output);
};
<commit_msg>A little cleanup, and testing with image_url<commit_after>var _    = require('lodash');
var util = require('util');

module.exports = commandChart;

function commandChart (token, options) {
  this.token = token;
  this.options = options;
}

commandChart.prototype.handle = function (req, res, cb) {
  /*
  {
    "text": "Daily Chart for: ibm",
    "attachments": [
      {
        "text": "<http://chart.finance.yahoo.com...>",
        "image_url": "<http://chart.finance.yahoo.com...>"
      }
    ]
  }
  */
  res.setHeader('content-type', 'application/json');
  var chartUrl = "http://chart.finance.yahoo.com/t?lang=en-US&region=US&width=300&height=180&s=";
  var imageUrl = "http://www.jameshedberg.com/img/samples/carbon-nanotube-3D-model-axial.png";
  var symbol = req.body.text;
  chartUrl += symbol;
  console.log(chartUrl);
  var output = '{';
  output += '"response_type": "in_channel",';
  output += '"text":' + ' "' + 'Daily Chart for: ' + symbol + '" ,';
  output += '"attachments":';
  output += '[{';
  output += '"text":' + ' "<' + chartUrl + '>" ,';
  output += '"image_url":' + ' "' + imageUrl + '"';
  output += '}]';
  output += '}';
  cb(null, output);
};
<|endoftext|>


<commit_before>const git = require('git-rev');

const Clapp = require('../modules/clapp-discord');
const cfg = require('../../config.js');
const pkg = require('../../package.json');

module.exports = new Clapp.Command(
  {
    name: "info",
    desc: "Gets information about me",
    fn: (argv, context) => {
      return new Promise(
        (fulfill) => {
          let gitUrl = 'https://github.com/SpyMaster356/nix-discord-bot';

          git.short(
            (gitHash) => {
              let response =
                'Hello!\n\n' +
                'I\'m Nix, and I was created to help automate some things on this Discord' +
                ' server.\n\n' +
                'My creator is SpyMaster356, and you can find him by the same name' +
                ' on Steam, Twitter, Github, Overwatch, and Reddit.\n' +
                '\n' +
                'I\'m currently using build ' + gitHash + ' of my code.\n' +
                'You can view my source code on GitHub at ' + pkg.repository + '\n';
              fulfill(response);
            }
          );
        }
      );
    }
  }
);
<commit_msg>update info message<commit_after>const git = require('git-rev');

const Clapp = require('../modules/clapp-discord');
const cfg = require('../../config.js');
const pkg = require('../../package.json');

module.exports = new Clapp.Command(
  {
    name: "info",
    desc: "Gets information about me",
    fn: (argv, context) => {
      return new Promise(
        (fulfill) => {
          let gitUrl = 'https://github.com/SpyMaster356/nix-discord-bot';

          git.short(
            (gitHash) => {
              let response =
                'Hello!\n' +
                '\n' +
                'My name is Nix, and I was created to help automate some things on this Discord' +
                ' server.\n' +
                '\n' +
                'My creator is SpyMaster356, and you can find him by the same name' +
                ' on Steam, Twitter, Github, Overwatch, and Reddit.\n' +
                '\n' +
                'I\'m currently using build ' + gitHash + ' of my code.\n' +
                '\n' +
                'You can view my source code on GitHub at ' + pkg.repository + '\n';
              fulfill(response);
            }
          );
        }
      );
    }
  }
);
<|endoftext|>


<commit_before>'use strict';

const Command = require('../models/command');
const Watcher = require('../models/watcher');
const Builder = require('../models/builder');
const SilentError = require('silent-error');
const path = require('path');
const Win = require('../utilities/windows-admin');
const existsSync = require('exists-sync');
const assign = require('ember-cli-lodash-subset').assign;
let defaultPort = 7357;

module.exports = Command.extend({
  name: 'test',
  description: 'Runs your app\'s test suite.',
  aliases: ['t'],

  availableOptions: [
    { name: 'environment', type: String,  default: 'test',          aliases: ['e'] },
    { name: 'config-file', type: String,                            aliases: ['c', 'cf'] },
    { name: 'server',      type: Boolean, default: false,           aliases: ['s'] },
    { name: 'host',        type: String,                            aliases: ['H'] },
    { name: 'test-port',   type: Number,  default: defaultPort,     aliases: ['tp'], description: 'The test port to use when running with --server.' },
    { name: 'filter',      type: String,                            aliases: ['f'],  description: 'A string to filter tests to run' },
    { name: 'module',      type: String,                            aliases: ['m'],  description: 'The name of a test module to run' },
    { name: 'watcher',     type: String,  default: 'events',        aliases: ['w'] },
    { name: 'launch',      type: String,  default: false,                            description: 'A comma separated list of browsers to launch for tests.' },
    { name: 'reporter',    type: String,                            aliases: ['r'],  description: 'Test reporter to use [tap|dot|xunit] (default: tap)' },
    { name: 'silent',      type: Boolean, default: false,                            description: 'Suppress any output except for the test report' },
    { name: 'testem-debug', type: String,                                            description: 'File to write a debug log from testem' },
    { name: 'test-page',   type: String,                                             description: 'Test page to invoke' },
    { name: 'path',        type: 'Path',                                             description: 'Reuse an existing build at given path.' },
    { name: 'query',       type: String,                                             description: 'A query string to append to the test page URL.' },
  ],

  init() {
    this._super.apply(this, arguments);

    this.quickTemp = require('quick-temp');

    this.Builder = this.Builder || Builder;
    this.Watcher = this.Watcher || Watcher;

    if (!this.testing) {
      process.env.EMBER_CLI_TEST_COMMAND = true;
    }
  },

  tmp() {
    return this.quickTemp.makeOrRemake(this, '-testsDist');
  },

  rmTmp() {
    this.quickTemp.remove(this, '-testsDist');
    this.quickTemp.remove(this, '-customConfigFile');
  },

  _generateCustomConfigs(options) {
    let config = {};
    if (!options.filter && !options.module && !options.launch && !options.query && !options['test-page']) { return config; }

    let testPage = options['test-page'];
    let queryString = this.buildTestPageQueryString(options);
    if (testPage) {
      let containsQueryString = testPage.indexOf('?') > -1;
      let testPageJoinChar = containsQueryString ? '&' : '?';
      config.testPage = testPage + testPageJoinChar + queryString;
    }
    if (queryString) {
      config.queryString = queryString;
    }

    if (options.launch) {
      config.launch = options.launch;
    }

    return config;
  },

  _generateTestPortNumber(options) {
    if ((options.port && options.testPort !== defaultPort) || (!isNaN(parseInt(options.testPort)) && !options.port)) {
      return options.testPort;
    }

    if (options.port) {
      return parseInt(options.port, 10) + 1;
    }
  },

  buildTestPageQueryString(options) {
    let params = [];

    if (options.module) {
      params.push(`module=${options.module}`);
    }

    if (options.filter) {
      params.push(`filter=${options.filter.toLowerCase()}`);
    }

    if (options.query) {
      params.push(options.query);
    }

    return params.join('&');
  },

  run(commandOptions) {
    let hasBuild = !!commandOptions.path;
    let outputPath;

    if (hasBuild) {
      outputPath = path.resolve(commandOptions.path);

      if (!existsSync(outputPath)) {
        throw new SilentError(`The path ${commandOptions.path} does not exist. Please specify a valid build directory to test.`);
      }
    } else {
      outputPath = this.tmp();
    }

    process.env['EMBER_CLI_TEST_OUTPUT'] = outputPath;

    let testOptions = assign({}, commandOptions, {
      ui: this.ui,
      outputPath,
      project: this.project,
      port: this._generateTestPortNumber(commandOptions),
    }, this._generateCustomConfigs(commandOptions));

    let options = {
      ui: this.ui,
      analytics: this.analytics,
      project: this.project,
    };

    return Win.checkIfSymlinksNeedToBeEnabled(this.ui).then(() => {
      let session;

      if (commandOptions.server) {
        if (hasBuild) {
          throw new SilentError('Specifying a build is not allowed with the `--server` option.');
        }

        let TestServerTask = this.tasks.TestServer;
        let testServer = new TestServerTask(options);
        let builder = new this.Builder(testOptions);

        testOptions.watcher = new this.Watcher(assign(options, {
          builder,
          verbose: false,
          options: commandOptions,
        }));

        session = testServer.run(testOptions)
          .finally(() => builder.cleanup());

      } else {
        let TestTask = this.tasks.Test;
        let test = new TestTask(options);

        if (hasBuild) {
          session = test.run(testOptions);
        } else {
          let BuildTask = this.tasks.Build;
          let build = new BuildTask(options);

          session = build.run({
            environment: commandOptions.environment,
            outputPath,
          })
          .then(() => test.run(testOptions));
        }
      }

      return session.finally(this.rmTmp.bind(this));
    });
  },
});
<commit_msg>Add --test-port 0 for random port<commit_after>'use strict';

const Command = require('../models/command');
const Watcher = require('../models/watcher');
const Builder = require('../models/builder');
const SilentError = require('silent-error');
const path = require('path');
const Win = require('../utilities/windows-admin');
const existsSync = require('exists-sync');
const assign = require('ember-cli-lodash-subset').assign;
let defaultPort = 7357;

module.exports = Command.extend({
  name: 'test',
  description: 'Runs your app\'s test suite.',
  aliases: ['t'],

  availableOptions: [
    { name: 'environment', type: String,  default: 'test',          aliases: ['e'] },
    { name: 'config-file', type: String,                            aliases: ['c', 'cf'] },
    { name: 'server',      type: Boolean, default: false,           aliases: ['s'] },
    { name: 'host',        type: String,                            aliases: ['H'] },
    { name: 'test-port',   type: Number,  default: defaultPort,     aliases: ['tp'], description: 'The test port to use when running with --server. Pass 0 to automatically pick an available port' },
    { name: 'filter',      type: String,                            aliases: ['f'],  description: 'A string to filter tests to run' },
    { name: 'module',      type: String,                            aliases: ['m'],  description: 'The name of a test module to run' },
    { name: 'watcher',     type: String,  default: 'events',        aliases: ['w'] },
    { name: 'launch',      type: String,  default: false,                            description: 'A comma separated list of browsers to launch for tests.' },
    { name: 'reporter',    type: String,                            aliases: ['r'],  description: 'Test reporter to use [tap|dot|xunit] (default: tap)' },
    { name: 'silent',      type: Boolean, default: false,                            description: 'Suppress any output except for the test report' },
    { name: 'testem-debug', type: String,                                            description: 'File to write a debug log from testem' },
    { name: 'test-page',   type: String,                                             description: 'Test page to invoke' },
    { name: 'path',        type: 'Path',                                             description: 'Reuse an existing build at given path.' },
    { name: 'query',       type: String,                                             description: 'A query string to append to the test page URL.' },
  ],

  init() {
    this._super.apply(this, arguments);

    this.quickTemp = require('quick-temp');

    this.Builder = this.Builder || Builder;
    this.Watcher = this.Watcher || Watcher;

    if (!this.testing) {
      process.env.EMBER_CLI_TEST_COMMAND = true;
    }
  },

  tmp() {
    return this.quickTemp.makeOrRemake(this, '-testsDist');
  },

  rmTmp() {
    this.quickTemp.remove(this, '-testsDist');
    this.quickTemp.remove(this, '-customConfigFile');
  },

  _generateCustomConfigs(options) {
    let config = {};
    if (!options.filter && !options.module && !options.launch && !options.query && !options['test-page']) { return config; }

    let testPage = options['test-page'];
    let queryString = this.buildTestPageQueryString(options);
    if (testPage) {
      let containsQueryString = testPage.indexOf('?') > -1;
      let testPageJoinChar = containsQueryString ? '&' : '?';
      config.testPage = testPage + testPageJoinChar + queryString;
    }
    if (queryString) {
      config.queryString = queryString;
    }

    if (options.launch) {
      config.launch = options.launch;
    }

    return config;
  },

  _generateTestPortNumber(options) {
    if ((options.port && options.testPort !== defaultPort) || (!isNaN(parseInt(options.testPort)) && !options.port)) {
      return options.testPort;
    }

    if (options.port) {
      return parseInt(options.port, 10) + 1;
    }
  },

  buildTestPageQueryString(options) {
    let params = [];

    if (options.module) {
      params.push(`module=${options.module}`);
    }

    if (options.filter) {
      params.push(`filter=${options.filter.toLowerCase()}`);
    }

    if (options.query) {
      params.push(options.query);
    }

    return params.join('&');
  },

  run(commandOptions) {
    let hasBuild = !!commandOptions.path;
    let outputPath;

    if (hasBuild) {
      outputPath = path.resolve(commandOptions.path);

      if (!existsSync(outputPath)) {
        throw new SilentError(`The path ${commandOptions.path} does not exist. Please specify a valid build directory to test.`);
      }
    } else {
      outputPath = this.tmp();
    }

    process.env['EMBER_CLI_TEST_OUTPUT'] = outputPath;

    let testOptions = assign({}, commandOptions, {
      ui: this.ui,
      outputPath,
      project: this.project,
      port: this._generateTestPortNumber(commandOptions),
    }, this._generateCustomConfigs(commandOptions));

    let options = {
      ui: this.ui,
      analytics: this.analytics,
      project: this.project,
    };

    return Win.checkIfSymlinksNeedToBeEnabled(this.ui).then(() => {
      let session;

      if (commandOptions.server) {
        if (hasBuild) {
          throw new SilentError('Specifying a build is not allowed with the `--server` option.');
        }

        let TestServerTask = this.tasks.TestServer;
        let testServer = new TestServerTask(options);
        let builder = new this.Builder(testOptions);

        testOptions.watcher = new this.Watcher(assign(options, {
          builder,
          verbose: false,
          options: commandOptions,
        }));

        session = testServer.run(testOptions)
          .finally(() => builder.cleanup());

      } else {
        let TestTask = this.tasks.Test;
        let test = new TestTask(options);

        if (hasBuild) {
          session = test.run(testOptions);
        } else {
          let BuildTask = this.tasks.Build;
          let build = new BuildTask(options);

          session = build.run({
            environment: commandOptions.environment,
            outputPath,
          })
          .then(() => test.run(testOptions));
        }
      }

      return session.finally(this.rmTmp.bind(this));
    });
  },
});
<|endoftext|>


<commit_before>// Copyright (c) 2016, Matt Godbolt
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

const BaseCompiler = require('../base-compiler'),
    argumentParsers = require("./argument-parsers"),
    fs = require('fs-extra'),
    logger = require('./../logger').logger,
    path = require('path'),
    semverParser = require('semver');

class LDCCompiler extends BaseCompiler {
    constructor(info, env) {
        super(info, env);
        this.compiler.supportsIntel = true;
        this.compiler.supportsIrView = true;
        this.compiler.irArg = ['-output-ll'];
    }

    optionsForFilter(filters, outputFilename) {
        let options = ['-g', '-of', this.filename(outputFilename)];
        if (filters.intel && !filters.binary) options = options.concat('-x86-asm-syntax=intel');
        if (!filters.binary) options = options.concat('-output-s');
        return options;
    }

    getArgumentParser() {
        return argumentParsers.Clang;
    }

    filterUserOptions(userOptions) {
        return userOptions.filter(option => option !== '-run');
    }

    isCfgCompiler() {
        return true;
    }

    couldSupportASTDump(version) {
        const versionRegex = /\((\d\.\d+)\.\d+/;
        const versionMatch = versionRegex.exec(version);
        return versionMatch ? semverParser.compare(versionMatch[1] + ".0", "1.4.0") >= 0 : false;
    }

    generateAST(inputFilename, options) {
        // These options make LDC produce an AST dump in a separate file `<inputFilename>.cg`.
        let newOptions = options.concat("-vcg-ast");
        let execOptions = this.getDefaultExecOptions();
        return this.runCompiler(this.compiler.exe, newOptions, this.filename(inputFilename), execOptions)
            .then(this.loadASTOutput);
    }

    loadASTOutput(output) {
        if (output.code !== 0) {
            return `Error generating AST: ${output.code}`;
        }
        // Load the AST output from the `.cg` file.
        // Demangling is not needed.
        const astFilename = output.inputFilename.concat(".cg");
        if (!fs.existsSync(astFilename)) {
            logger.warn(`LDC AST file ${astFilename} requested but it does not exist`);
            return "";
        }
        return fs.readFileSync(astFilename, 'utf-8');
    }

    // Override the IR processing method for LDC because the output file is different from clang.
    processIrOutput(output, filters) {
        const irPath = this.getOutputFilename(path.dirname(output.inputFilename), this.outputFilebase).replace('.s', '.ll');
        if (fs.existsSync(irPath)) {
            const output = fs.readFileSync(irPath, 'utf-8');
            // uses same filters as main compiler
            return this.llvmIr.process(output, filters);
        }
        return output.stderr;
    }
}

module.exports = LDCCompiler;
<commit_msg>Fix build, formatting issue<commit_after>// Copyright (c) 2016, Matt Godbolt
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

const BaseCompiler = require('../base-compiler'),
    argumentParsers = require("./argument-parsers"),
    fs = require('fs-extra'),
    logger = require('./../logger').logger,
    path = require('path'),
    semverParser = require('semver');

class LDCCompiler extends BaseCompiler {
    constructor(info, env) {
        super(info, env);
        this.compiler.supportsIntel = true;
        this.compiler.supportsIrView = true;
        this.compiler.irArg = ['-output-ll'];
    }

    optionsForFilter(filters, outputFilename) {
        let options = ['-g', '-of', this.filename(outputFilename)];
        if (filters.intel && !filters.binary) options = options.concat('-x86-asm-syntax=intel');
        if (!filters.binary) options = options.concat('-output-s');
        return options;
    }

    getArgumentParser() {
        return argumentParsers.Clang;
    }

    filterUserOptions(userOptions) {
        return userOptions.filter(option => option !== '-run');
    }

    isCfgCompiler() {
        return true;
    }

    couldSupportASTDump(version) {
        const versionRegex = /\((\d\.\d+)\.\d+/;
        const versionMatch = versionRegex.exec(version);
        return versionMatch ? semverParser.compare(versionMatch[1] + ".0", "1.4.0") >= 0 : false;
    }

    generateAST(inputFilename, options) {
        // These options make LDC produce an AST dump in a separate file `<inputFilename>.cg`.
        let newOptions = options.concat("-vcg-ast");
        let execOptions = this.getDefaultExecOptions();
        return this.runCompiler(this.compiler.exe, newOptions, this.filename(inputFilename), execOptions)
            .then(this.loadASTOutput);
    }

    loadASTOutput(output) {
        if (output.code !== 0) {
            return `Error generating AST: ${output.code}`;
        }
        // Load the AST output from the `.cg` file.
        // Demangling is not needed.
        const astFilename = output.inputFilename.concat(".cg");
        if (!fs.existsSync(astFilename)) {
            logger.warn(`LDC AST file ${astFilename} requested but it does not exist`);
            return "";
        }
        return fs.readFileSync(astFilename, 'utf-8');
    }

    // Override the IR processing method for LDC because the output file is different from clang.
    processIrOutput(output, filters) {
        const irPath = this.getOutputFilename(path.dirname(output.inputFilename), this.outputFilebase)
            .replace('.s', '.ll');
        if (fs.existsSync(irPath)) {
            const output = fs.readFileSync(irPath, 'utf-8');
            // uses same filters as main compiler
            return this.llvmIr.process(output, filters);
        }
        return output.stderr;
    }
}

module.exports = LDCCompiler;
<|endoftext|>


<commit_before>var env = process.env.NODE_ENV || "development";
var packageJSON = require("../../package.json");
var express = require("express");
var path = require("path");
var logger = require("morgan");
var favicon = require("serve-favicon");

global.App = {
  /*********************************************************************************************************************
   * Global app settings
   ********************************************************************************************************************/
  serviceName: "lips",
  express : express(),
  port: process.env.PORT || 3000,
  version: packageJSON.version,
  root: path.join(__dirname, ".."),

  appPath: function(path) {
    return this.root + "/" + path;
  },

  require: function(path) {
    return require(this.appPath(path));
  },

  env: env,

  start: function() {
    if (!this.started) {
      this.started = true;
      this.express.listen(this.port);
      console.log("Running "+ App.serviceName +" v" + App.version + " on port " + App.port + " in " + App.env + " mode");
    }
  },

  /*********************************************************************************************************************
   * Global image settings
   ********************************************************************************************************************/
  imageSettings: {
    font: "Arial",
    fontSize: "24px",
    fontColor: "000000",
    text: true,
    fill: "09F"
  },

  /*********************************************************************************************************************
   * Global network settings
   ********************************************************************************************************************/
  networkSettings: {
    delay: 0,
    contentType: "png",
    maxAge: 3153600,
    expiryDate: new Date()
  }
};

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));

// Setup middleware
App.express.use(logger('dev'));

// Setup routes
App.require("config/routes")(App.express);

// Views
App.express.set('views', App.appPath('views'));
App.express.set('view engine', 'jade');

<commit_msg>provide sample url in startup message<commit_after>var env = process.env.NODE_ENV || "development";
var packageJSON = require("../../package.json");
var express = require("express");
var path = require("path");
var logger = require("morgan");
var favicon = require("serve-favicon");

global.App = {
  /*********************************************************************************************************************
   * Global app settings
   ********************************************************************************************************************/
  serviceName: "lips",
  express : express(),
  port: process.env.PORT || 3000,
  version: packageJSON.version,
  root: path.join(__dirname, ".."),

  appPath: function(path) {
    return this.root + "/" + path;
  },

  require: function(path) {
    return require(this.appPath(path));
  },

  env: env,

  start: function() {
    if (!this.started) {
      this.started = true;
      this.express.listen(this.port);
      console.log("********************************************************************************");
      console.log("Running "+ App.serviceName +" v" + App.version + " on port " + App.port + " in " + App.env + " mode");
      console.log("--------------------------------------------------------------------------------");
      console.log("visit: http://localhost:3000/"+ App.serviceName +"/200x133.png");
      console.log("********************************************************************************");
    }
  },

  /*********************************************************************************************************************
   * Global image settings
   ********************************************************************************************************************/
  imageSettings: {
    font: "Arial",
    fontSize: "24px",
    fontColor: "000000",
    text: true,
    fill: "09F"
  },

  /*********************************************************************************************************************
   * Global network settings
   ********************************************************************************************************************/
  networkSettings: {
    delay: 0,
    contentType: "png",
    maxAge: 3153600,
    expiryDate: new Date()
  }
};

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));

// Setup middleware
App.express.use(logger('dev'));

// Setup routes
App.require("config/routes")(App.express);

// Views
App.express.set('views', App.appPath('views'));
App.express.set('view engine', 'jade');

<|endoftext|>


<commit_before>import {
  isFunction,
  isArray,
  isNumber,
  bind,
  assign
} from 'min-dash';

var FN_REF = '__fn';

var DEFAULT_PRIORITY = 1000;

var slice = Array.prototype.slice;

/**
 * A general purpose event bus.
 *
 * This component is used to communicate across a diagram instance.
 * Other parts of a diagram can use it to listen to and broadcast events.
 *
 *
 * ## Registering for Events
 *
 * The event bus provides the {@link EventBus#on} and {@link EventBus#once}
 * methods to register for events. {@link EventBus#off} can be used to
 * remove event registrations. Listeners receive an instance of {@link Event}
 * as the first argument. It allows them to hook into the event execution.
 *
 * ```javascript
 *
 * // listen for event
 * eventBus.on('foo', function(event) {
 *
 *   // access event type
 *   event.type; // 'foo'
 *
 *   // stop propagation to other listeners
 *   event.stopPropagation();
 *
 *   // prevent event default
 *   event.preventDefault();
 * });
 *
 * // listen for event with custom payload
 * eventBus.on('bar', function(event, payload) {
 *   console.log(payload);
 * });
 *
 * // listen for event returning value
 * eventBus.on('foobar', function(event) {
 *
 *   // stop event propagation + prevent default
 *   return false;
 *
 *   // stop event propagation + return custom result
 *   return {
 *     complex: 'listening result'
 *   };
 * });
 *
 *
 * // listen with custom priority (default=1000, higher is better)
 * eventBus.on('priorityfoo', 1500, function(event) {
 *   console.log('invoked first!');
 * });
 *
 *
 * // listen for event and pass the context (`this`)
 * eventBus.on('foobar', function(event) {
 *   this.foo();
 * }, this);
 * ```
 *
 *
 * ## Emitting Events
 *
 * Events can be emitted via the event bus using {@link EventBus#fire}.
 *
 * ```javascript
 *
 * // false indicates that the default action
 * // was prevented by listeners
 * if (eventBus.fire('foo') === false) {
 *   console.log('default has been prevented!');
 * };
 *
 *
 * // custom args + return value listener
 * eventBus.on('sum', function(event, a, b) {
 *   return a + b;
 * });
 *
 * // you can pass custom arguments + retrieve result values.
 * var sum = eventBus.fire('sum', 1, 2);
 * console.log(sum); // 3
 * ```
 */
export default function EventBus() {
  this._listeners = {};

  // cleanup on destroy on lowest priority to allow
  // message passing until the bitter end
  this.on('diagram.destroy', 1, this._destroy, this);
}

/**
 * Register an event listener for events with the given name.
 *
 * The callback will be invoked with `event, ...additionalArguments`
 * that have been passed to {@link EventBus#fire}.
 *
 * Returning false from a listener will prevent the events default action
 * (if any is specified). To stop an event from being processed further in
 * other listeners execute {@link Event#stopPropagation}.
 *
 * Returning anything but `undefined` from a listener will stop the listener propagation.
 *
 * @param {String|Array<String>} events
 * @param {Number} [priority=1000] the priority in which this listener is called, larger is higher
 * @param {Function} callback
 * @param {Object} [that] Pass context (`this`) to the callback
 */
EventBus.prototype.on = function(events, priority, callback, that) {

  events = isArray(events) ? events : [ events ];

  if (isFunction(priority)) {
    that = callback;
    callback = priority;
    priority = DEFAULT_PRIORITY;
  }

  if (!isNumber(priority)) {
    throw new Error('priority must be a number');
  }

  var actualCallback = callback;

  if (that) {
    actualCallback = bind(callback, that);

    // make sure we remember and are able to remove
    // bound callbacks via {@link #off} using the original
    // callback
    actualCallback[FN_REF] = callback[FN_REF] || callback;
  }

  var self = this;

  events.forEach(function(e) {
    self._addListener(e, {
      priority: priority,
      callback: actualCallback,
      next: null
    });
  });
};

/**
 * Register an event listener that is executed only once.
 *
 * @param {String} event the event name to register for
 * @param {Function} callback the callback to execute
 * @param {Object} [that] Pass context (`this`) to the callback
 */
EventBus.prototype.once = function(event, priority, callback, that) {
  var self = this;

  if (isFunction(priority)) {
    that = callback;
    callback = priority;
    priority = DEFAULT_PRIORITY;
  }

  if (!isNumber(priority)) {
    throw new Error('priority must be a number');
  }

  function wrappedCallback() {
    var result = callback.apply(that, arguments);

    self.off(event, wrappedCallback);

    return result;
  }

  // make sure we remember and are able to remove
  // bound callbacks via {@link #off} using the original
  // callback
  wrappedCallback[FN_REF] = callback;

  this.on(event, priority, wrappedCallback);
};

/**
 * Removes event listeners by event and callback.
 *
 * If no callback is given, all listeners for a given event name are being removed.
 *
 * @param {String|Array<String>} events
 * @param {Function} [callback]
 */
EventBus.prototype.off = function(events, callback) {

  events = isArray(events) ? events : [ events ];

  var self = this;

  events.forEach(function(event) {
    self._removeListener(event, callback);
  });

};

/**
 * Create an EventBus event.
 *
 * @param {Object} data
 *
 * @return {Object} event, recognized by the eventBus
 */
EventBus.prototype.createEvent = function(data) {
  var event = new InternalEvent();

  event.init(data);

  return event;
};

/**
 * Fires a named event.
 *
 * @example
 *
 * // fire event by name
 * events.fire('foo');
 *
 * // fire event object with nested type
 * var event = { type: 'foo' };
 * events.fire(event);
 *
 * // fire event with explicit type
 * var event = { x: 10, y: 20 };
 * events.fire('element.moved', event);
 *
 * // pass additional arguments to the event
 * events.on('foo', function(event, bar) {
 *   alert(bar);
 * });
 *
 * events.fire({ type: 'foo' }, 'I am bar!');
 *
 * @param {String} [name] the optional event name
 * @param {Object} [event] the event object
 * @param {...Object} additional arguments to be passed to the callback functions
 *
 * @return {Boolean} the events return value, if specified or false if the
 *                   default action was prevented by listeners
 */
EventBus.prototype.fire = function(type, data) {

  var event,
      firstListener,
      returnValue,
      args;

  args = slice.call(arguments);

  if (typeof type === 'object') {
    event = type;
    type = event.type;
  }

  if (!type) {
    throw new Error('no event type specified');
  }

  firstListener = this._listeners[type];

  if (!firstListener) {
    return;
  }

  // we make sure we fire instances of our home made
  // events here. We wrap them only once, though
  if (data instanceof InternalEvent) {
    // we are fine, we alread have an event
    event = data;
  } else {
    event = this.createEvent(data);
  }

  // ensure we pass the event as the first parameter
  args[0] = event;

  // original event type (in case we delegate)
  var originalType = event.type;

  // update event type before delegation
  if (type !== originalType) {
    event.type = type;
  }

  try {
    returnValue = this._invokeListeners(event, args, firstListener);
  } finally {
    // reset event type after delegation
    if (type !== originalType) {
      event.type = originalType;
    }
  }

  // set the return value to false if the event default
  // got prevented and no other return value exists
  if (returnValue === undefined && event.defaultPrevented) {
    returnValue = false;
  }

  return returnValue;
};

EventBus.prototype.handleError = function(error) {
  return this.fire('error', { error: error }) === false;
};

EventBus.prototype._destroy = function() {
  this._listeners = {};
};

EventBus.prototype._invokeListeners = function(event, args, listener) {

  var returnValue;

  while (listener) {

    // handle stopped propagation
    if (event.cancelBubble) {
      break;
    }

    returnValue = this._invokeListener(event, args, listener);

    listener = listener.next;
  }

  return returnValue;
};

EventBus.prototype._invokeListener = function(event, args, listener) {

  var returnValue;

  try {
    // returning false prevents the default action
    returnValue = invokeFunction(listener.callback, args);

    // stop propagation on return value
    if (returnValue !== undefined) {
      event.returnValue = returnValue;
      event.stopPropagation();
    }

    // prevent default on return false
    if (returnValue === false) {
      event.preventDefault();
    }
  } catch (e) {
    if (!this.handleError(e)) {
      console.error('unhandled error in event listener');
      console.error(e.stack);

      throw e;
    }
  }

  return returnValue;
};

/*
 * Add new listener with a certain priority to the list
 * of listeners (for the given event).
 *
 * The semantics of listener registration / listener execution are
 * first register, first serve: New listeners will always be inserted
 * after existing listeners with the same priority.
 *
 * Example: Inserting two listeners with priority 1000 and 1300
 *
 *    * before: [ 1500, 1500, 1000, 1000 ]
 *    * after: [ 1500, 1500, (new=1300), 1000, 1000, (new=1000) ]
 *
 * @param {String} event
 * @param {Object} listener { priority, callback }
 */
EventBus.prototype._addListener = function(event, newListener) {

  var listener = this._getListeners(event),
      previousListener;

  // no prior listeners
  if (!listener) {
    this._setListeners(event, newListener);

    return;
  }

  // ensure we order listeners by priority from
  // 0 (high) to n > 0 (low)
  while (listener) {

    if (listener.priority < newListener.priority) {

      newListener.next = listener;

      if (previousListener) {
        previousListener.next = newListener;
      } else {
        this._setListeners(event, newListener);
      }

      return;
    }

    previousListener = listener;
    listener = listener.next;
  }

  // add new listener to back
  previousListener.next = newListener;
};

EventBus.prototype._getListeners = function(name) {
  return this._listeners[name];
};

EventBus.prototype._setListeners = function(name, listener) {
  this._listeners[name] = listener;
};

EventBus.prototype._removeListener = function(event, callback) {

  var listener = this._getListeners(event),
      nextListener,
      previousListener,
      listenerCallback;

  if (!callback) {
    // clear listeners
    this._setListeners(event, null);

    return;
  }

  while (listener) {

    nextListener = listener.next;

    listenerCallback = listener.callback;

    if (listenerCallback === callback || listenerCallback[FN_REF] === callback) {
      if (previousListener) {
        previousListener.next = nextListener;
      } else {
        // new first listener
        this._setListeners(event, nextListener);
      }
    }

    previousListener = listener;
    listener = nextListener;
  }
};

/**
 * A event that is emitted via the event bus.
 */
function InternalEvent() { }

InternalEvent.prototype.stopPropagation = function() {
  this.cancelBubble = true;
};

InternalEvent.prototype.preventDefault = function() {
  this.defaultPrevented = true;
};

InternalEvent.prototype.init = function(data) {
  assign(this, data || {});
};

/**
 * Invoke function. Be fast...
 *
 * @param {Function} fn
 * @param {Array<Object>} args
 *
 * @return {Any}
 */
function invokeFunction(fn, args) {
  return fn.apply(null, args);
}
<commit_msg>docs(core/EventBus): add missing parameter jsdoc for once method<commit_after>import {
  isFunction,
  isArray,
  isNumber,
  bind,
  assign
} from 'min-dash';

var FN_REF = '__fn';

var DEFAULT_PRIORITY = 1000;

var slice = Array.prototype.slice;

/**
 * A general purpose event bus.
 *
 * This component is used to communicate across a diagram instance.
 * Other parts of a diagram can use it to listen to and broadcast events.
 *
 *
 * ## Registering for Events
 *
 * The event bus provides the {@link EventBus#on} and {@link EventBus#once}
 * methods to register for events. {@link EventBus#off} can be used to
 * remove event registrations. Listeners receive an instance of {@link Event}
 * as the first argument. It allows them to hook into the event execution.
 *
 * ```javascript
 *
 * // listen for event
 * eventBus.on('foo', function(event) {
 *
 *   // access event type
 *   event.type; // 'foo'
 *
 *   // stop propagation to other listeners
 *   event.stopPropagation();
 *
 *   // prevent event default
 *   event.preventDefault();
 * });
 *
 * // listen for event with custom payload
 * eventBus.on('bar', function(event, payload) {
 *   console.log(payload);
 * });
 *
 * // listen for event returning value
 * eventBus.on('foobar', function(event) {
 *
 *   // stop event propagation + prevent default
 *   return false;
 *
 *   // stop event propagation + return custom result
 *   return {
 *     complex: 'listening result'
 *   };
 * });
 *
 *
 * // listen with custom priority (default=1000, higher is better)
 * eventBus.on('priorityfoo', 1500, function(event) {
 *   console.log('invoked first!');
 * });
 *
 *
 * // listen for event and pass the context (`this`)
 * eventBus.on('foobar', function(event) {
 *   this.foo();
 * }, this);
 * ```
 *
 *
 * ## Emitting Events
 *
 * Events can be emitted via the event bus using {@link EventBus#fire}.
 *
 * ```javascript
 *
 * // false indicates that the default action
 * // was prevented by listeners
 * if (eventBus.fire('foo') === false) {
 *   console.log('default has been prevented!');
 * };
 *
 *
 * // custom args + return value listener
 * eventBus.on('sum', function(event, a, b) {
 *   return a + b;
 * });
 *
 * // you can pass custom arguments + retrieve result values.
 * var sum = eventBus.fire('sum', 1, 2);
 * console.log(sum); // 3
 * ```
 */
export default function EventBus() {
  this._listeners = {};

  // cleanup on destroy on lowest priority to allow
  // message passing until the bitter end
  this.on('diagram.destroy', 1, this._destroy, this);
}

/**
 * Register an event listener for events with the given name.
 *
 * The callback will be invoked with `event, ...additionalArguments`
 * that have been passed to {@link EventBus#fire}.
 *
 * Returning false from a listener will prevent the events default action
 * (if any is specified). To stop an event from being processed further in
 * other listeners execute {@link Event#stopPropagation}.
 *
 * Returning anything but `undefined` from a listener will stop the listener propagation.
 *
 * @param {String|Array<String>} events
 * @param {Number} [priority=1000] the priority in which this listener is called, larger is higher
 * @param {Function} callback
 * @param {Object} [that] Pass context (`this`) to the callback
 */
EventBus.prototype.on = function(events, priority, callback, that) {

  events = isArray(events) ? events : [ events ];

  if (isFunction(priority)) {
    that = callback;
    callback = priority;
    priority = DEFAULT_PRIORITY;
  }

  if (!isNumber(priority)) {
    throw new Error('priority must be a number');
  }

  var actualCallback = callback;

  if (that) {
    actualCallback = bind(callback, that);

    // make sure we remember and are able to remove
    // bound callbacks via {@link #off} using the original
    // callback
    actualCallback[FN_REF] = callback[FN_REF] || callback;
  }

  var self = this;

  events.forEach(function(e) {
    self._addListener(e, {
      priority: priority,
      callback: actualCallback,
      next: null
    });
  });
};

/**
 * Register an event listener that is executed only once.
 *
 * @param {String} event the event name to register for
 * @param {Number} [priority=1000] the priority in which this listener is called, larger is higher
 * @param {Function} callback the callback to execute
 * @param {Object} [that] Pass context (`this`) to the callback
 */
EventBus.prototype.once = function(event, priority, callback, that) {
  var self = this;

  if (isFunction(priority)) {
    that = callback;
    callback = priority;
    priority = DEFAULT_PRIORITY;
  }

  if (!isNumber(priority)) {
    throw new Error('priority must be a number');
  }

  function wrappedCallback() {
    var result = callback.apply(that, arguments);

    self.off(event, wrappedCallback);

    return result;
  }

  // make sure we remember and are able to remove
  // bound callbacks via {@link #off} using the original
  // callback
  wrappedCallback[FN_REF] = callback;

  this.on(event, priority, wrappedCallback);
};

/**
 * Removes event listeners by event and callback.
 *
 * If no callback is given, all listeners for a given event name are being removed.
 *
 * @param {String|Array<String>} events
 * @param {Function} [callback]
 */
EventBus.prototype.off = function(events, callback) {

  events = isArray(events) ? events : [ events ];

  var self = this;

  events.forEach(function(event) {
    self._removeListener(event, callback);
  });

};

/**
 * Create an EventBus event.
 *
 * @param {Object} data
 *
 * @return {Object} event, recognized by the eventBus
 */
EventBus.prototype.createEvent = function(data) {
  var event = new InternalEvent();

  event.init(data);

  return event;
};

/**
 * Fires a named event.
 *
 * @example
 *
 * // fire event by name
 * events.fire('foo');
 *
 * // fire event object with nested type
 * var event = { type: 'foo' };
 * events.fire(event);
 *
 * // fire event with explicit type
 * var event = { x: 10, y: 20 };
 * events.fire('element.moved', event);
 *
 * // pass additional arguments to the event
 * events.on('foo', function(event, bar) {
 *   alert(bar);
 * });
 *
 * events.fire({ type: 'foo' }, 'I am bar!');
 *
 * @param {String} [name] the optional event name
 * @param {Object} [event] the event object
 * @param {...Object} additional arguments to be passed to the callback functions
 *
 * @return {Boolean} the events return value, if specified or false if the
 *                   default action was prevented by listeners
 */
EventBus.prototype.fire = function(type, data) {

  var event,
      firstListener,
      returnValue,
      args;

  args = slice.call(arguments);

  if (typeof type === 'object') {
    event = type;
    type = event.type;
  }

  if (!type) {
    throw new Error('no event type specified');
  }

  firstListener = this._listeners[type];

  if (!firstListener) {
    return;
  }

  // we make sure we fire instances of our home made
  // events here. We wrap them only once, though
  if (data instanceof InternalEvent) {
    // we are fine, we alread have an event
    event = data;
  } else {
    event = this.createEvent(data);
  }

  // ensure we pass the event as the first parameter
  args[0] = event;

  // original event type (in case we delegate)
  var originalType = event.type;

  // update event type before delegation
  if (type !== originalType) {
    event.type = type;
  }

  try {
    returnValue = this._invokeListeners(event, args, firstListener);
  } finally {
    // reset event type after delegation
    if (type !== originalType) {
      event.type = originalType;
    }
  }

  // set the return value to false if the event default
  // got prevented and no other return value exists
  if (returnValue === undefined && event.defaultPrevented) {
    returnValue = false;
  }

  return returnValue;
};

EventBus.prototype.handleError = function(error) {
  return this.fire('error', { error: error }) === false;
};

EventBus.prototype._destroy = function() {
  this._listeners = {};
};

EventBus.prototype._invokeListeners = function(event, args, listener) {

  var returnValue;

  while (listener) {

    // handle stopped propagation
    if (event.cancelBubble) {
      break;
    }

    returnValue = this._invokeListener(event, args, listener);

    listener = listener.next;
  }

  return returnValue;
};

EventBus.prototype._invokeListener = function(event, args, listener) {

  var returnValue;

  try {
    // returning false prevents the default action
    returnValue = invokeFunction(listener.callback, args);

    // stop propagation on return value
    if (returnValue !== undefined) {
      event.returnValue = returnValue;
      event.stopPropagation();
    }

    // prevent default on return false
    if (returnValue === false) {
      event.preventDefault();
    }
  } catch (e) {
    if (!this.handleError(e)) {
      console.error('unhandled error in event listener');
      console.error(e.stack);

      throw e;
    }
  }

  return returnValue;
};

/*
 * Add new listener with a certain priority to the list
 * of listeners (for the given event).
 *
 * The semantics of listener registration / listener execution are
 * first register, first serve: New listeners will always be inserted
 * after existing listeners with the same priority.
 *
 * Example: Inserting two listeners with priority 1000 and 1300
 *
 *    * before: [ 1500, 1500, 1000, 1000 ]
 *    * after: [ 1500, 1500, (new=1300), 1000, 1000, (new=1000) ]
 *
 * @param {String} event
 * @param {Object} listener { priority, callback }
 */
EventBus.prototype._addListener = function(event, newListener) {

  var listener = this._getListeners(event),
      previousListener;

  // no prior listeners
  if (!listener) {
    this._setListeners(event, newListener);

    return;
  }

  // ensure we order listeners by priority from
  // 0 (high) to n > 0 (low)
  while (listener) {

    if (listener.priority < newListener.priority) {

      newListener.next = listener;

      if (previousListener) {
        previousListener.next = newListener;
      } else {
        this._setListeners(event, newListener);
      }

      return;
    }

    previousListener = listener;
    listener = listener.next;
  }

  // add new listener to back
  previousListener.next = newListener;
};

EventBus.prototype._getListeners = function(name) {
  return this._listeners[name];
};

EventBus.prototype._setListeners = function(name, listener) {
  this._listeners[name] = listener;
};

EventBus.prototype._removeListener = function(event, callback) {

  var listener = this._getListeners(event),
      nextListener,
      previousListener,
      listenerCallback;

  if (!callback) {
    // clear listeners
    this._setListeners(event, null);

    return;
  }

  while (listener) {

    nextListener = listener.next;

    listenerCallback = listener.callback;

    if (listenerCallback === callback || listenerCallback[FN_REF] === callback) {
      if (previousListener) {
        previousListener.next = nextListener;
      } else {
        // new first listener
        this._setListeners(event, nextListener);
      }
    }

    previousListener = listener;
    listener = nextListener;
  }
};

/**
 * A event that is emitted via the event bus.
 */
function InternalEvent() { }

InternalEvent.prototype.stopPropagation = function() {
  this.cancelBubble = true;
};

InternalEvent.prototype.preventDefault = function() {
  this.defaultPrevented = true;
};

InternalEvent.prototype.init = function(data) {
  assign(this, data || {});
};

/**
 * Invoke function. Be fast...
 *
 * @param {Function} fn
 * @param {Array<Object>} args
 *
 * @return {Any}
 */
function invokeFunction(fn, args) {
  return fn.apply(null, args);
}
<|endoftext|>