<commit_before>(function() {
    'use strict';

    var request = require('supertest'),
        express = require('express'),
        should = require('chai').should,
        expect = require('chai').expect,
        assert = require('chai').assert;

    var app = require('../').app;

    var exp_id = null,
        model_id = null;

    describe('REST API:', function() {
        describe('Create Experiment: POST /experiment', function() {
            it('should create an experiment with a randomly generated name', function(done) {
                request(app)
                    .post('/api/v1/experiment')
                    .expect(201)
                    .send({
                        'description': 'test'
                    })
                    .end(function(err, res) {
                        exp_id = res.body._id;
                        expect(res.body._id).to.be.ok;
                        expect(res.body.name).to.be.ok;
                        expect(res.body.description).to.equal('test');

                        done(err);
                    });
            });

            it('should get experiment with correct field values', function(done) {
                request(app)
                    .get('/api/v1/experiment/' + exp_id)
                    .expect(200)
                    .end(function(err, res) {
                        expect(res.body._id).to.be.ok;
                        expect(res.body.name).to.be.ok;
                        expect(res.body.description).to.equal('test');

                        done(err);
                    });
            });

            it('should create an experiment with a given generated name', function(done) {
                request(app)
                    .post('/api/v1/experiment')
                    .expect(201)
                    .send({
                        'description': 'test',
                        'name': 'ImageNet 2012'
                    })
                    .end(function(err, res) {
                        expect(res.body._id).to.be.ok;
                        expect(res.body.name).to.be.ok;
                        expect(res.body.description).to.equal('test');
                        expect(res.body.name).to.equal('ImageNet 2012');

                        done(err);
                    });
            });
        });

        describe('Change Experiment: PUT /experiment/:id', function() {
            it('should update the name and description', function(done) {
                request(app)
                    .put('/api/v1/experiment/' + exp_id)
                    .expect(200)
                    .send({
                        'description': 'just testing put',
                        'name': 'ImageNet 2011'
                    })
                    .end(function(err, res) {
                        expect(res.body._id).to.be.ok;
                        expect(res.body.name).to.be.ok;
                        expect(res.body.description).to.equal('just testing put');
                        expect(res.body.name).to.equal('ImageNet 2011');

                        done(err);
                    });
            });
        });

        describe('Create Model: POST /experiment/:id/model', function() {
            var dummyHyperparams = 'distribution: gaußian, n-grams: 2-grams, stopwords: removed',
                dummyName = 'bow naïve bayes',
                dummyDescr = 'some description';

            it('should create model for given experiment', function(done) {
                request(app)
                    .post('/api/v1/experiment/' + exp_id + '/model')
                    .expect(201)
                    .send({
                        'name': dummyName,
                        'description': dummyDescr,
                        'hyperparameter': dummyHyperparams
                    })
                    .end(function(err, res) {
                        model_id = res.body._id;

                        expect(res.body._id).to.be.ok;
                        expect(res.body.name).to.equal(dummyName);
                        expect(res.body.hyperparameter).to.equal(dummyHyperparams);
                        expect(res.body.description).to.equal(dummyDescr);

                        done(err);
                    });
            });

            it('should get the model with correct field values', function(done) {
                request(app)
                    .get('/api/v1/experiment/' + exp_id + '/model/' + model_id)
                    .expect(200)
                    .end(function(err, res) {
                        expect(res.body._id).to.be.ok;
                        expect(res.body.name).to.equal(dummyName);
                        expect(res.body.hyperparameter).to.equal(dummyHyperparams);
                        expect(res.body.description).to.equal(dummyDescr);

                        done(err);
                    });
            });
        });
    });
})();
<commit_msg>implemented test for put model; see #4<commit_after>(function() {
    'use strict';

    var request = require('supertest'),
        express = require('express'),
        should = require('chai').should,
        expect = require('chai').expect,
        assert = require('chai').assert;

    var app = require('../').app;

    var exp_id = null,
        model_id = null;

    describe('REST API:', function() {
        describe('Create Experiment: POST /experiment', function() {
            it('should create an experiment with a randomly generated name', function(done) {
                request(app)
                    .post('/api/v1/experiment')
                    .expect(201)
                    .send({
                        'description': 'test'
                    })
                    .end(function(err, res) {
                        exp_id = res.body._id;
                        expect(res.body._id).to.be.ok;
                        expect(res.body.name).to.be.ok;
                        expect(res.body.description).to.equal('test');

                        done(err);
                    });
            });

            it('should get experiment with correct field values', function(done) {
                request(app)
                    .get('/api/v1/experiment/' + exp_id)
                    .expect(200)
                    .end(function(err, res) {
                        expect(res.body._id).to.be.ok;
                        expect(res.body.name).to.be.ok;
                        expect(res.body.description).to.equal('test');

                        done(err);
                    });
            });

            it('should create an experiment with a given generated name', function(done) {
                request(app)
                    .post('/api/v1/experiment')
                    .expect(201)
                    .send({
                        'description': 'test',
                        'name': 'ImageNet 2012'
                    })
                    .end(function(err, res) {
                        expect(res.body._id).to.be.ok;
                        expect(res.body.name).to.be.ok;
                        expect(res.body.description).to.equal('test');
                        expect(res.body.name).to.equal('ImageNet 2012');

                        done(err);
                    });
            });
        });

        describe('Change Experiment: PUT /experiment/:id', function() {
            it('should update the name and description', function(done) {
                request(app)
                    .put('/api/v1/experiment/' + exp_id)
                    .expect(200)
                    .send({
                        'description': 'just testing put',
                        'name': 'ImageNet 2011'
                    })
                    .end(function(err, res) {
                        expect(res.body._id).to.be.ok;
                        expect(res.body.name).to.be.ok;
                        expect(res.body.description).to.equal('just testing put');
                        expect(res.body.name).to.equal('ImageNet 2011');

                        done(err);
                    });
            });
        });

        describe('Create Model: POST /experiment/:id/model', function() {
            var dummyHyperparams = 'distribution: gaußian, n-grams: 2-grams, stopwords: removed',
                dummyName = 'bow naïve bayes',
                dummyDescr = 'some description';

            it('should create model for given experiment', function(done) {
                request(app)
                    .post('/api/v1/experiment/' + exp_id + '/model')
                    .expect(201)
                    .send({
                        'name': dummyName,
                        'description': dummyDescr,
                        'hyperparameter': dummyHyperparams
                    })
                    .end(function(err, res) {
                        model_id = res.body._id;

                        expect(res.body._id).to.be.ok;
                        expect(res.body.name).to.equal(dummyName);
                        expect(res.body.hyperparameter).to.equal(dummyHyperparams);
                        expect(res.body.description).to.equal(dummyDescr);

                        done(err);
                    });
            });

            it('should get the model with correct field values', function(done) {
                request(app)
                    .get('/api/v1/experiment/' + exp_id + '/model/' + model_id)
                    .expect(200)
                    .end(function(err, res) {
                        expect(res.body._id).to.be.ok;
                        expect(res.body.name).to.equal(dummyName);
                        expect(res.body.hyperparameter).to.equal(dummyHyperparams);
                        expect(res.body.description).to.equal(dummyDescr);

                        done(err);
                    });
            });
        });

        describe('Change Model: PUT /experiment/:id/model', function() {
            it('should change the model data', function(done) {
                request(app)
                    .put('/api/v1/experiment/' + exp_id + '/model/' + model_id)
                    .expect(200)
                    .send({
                        'name': 'foo',
                        'description': 'bar',
                        'hyperparameter': 'baz'
                    })
                    .end(function(err, res) {
                        console.log(res.body);

                        expect(res.body._id).to.be.ok;
                        expect(res.body.name).to.equal('foo');
                        expect(res.body.description).to.equal('bar');
                        expect(res.body.hyperparameter).to.equal('baz');

                        done(err);
                    });
            });
        });
    });
})();
<|endoftext|>


<commit_before>const Discord = require('discord.js')
const listeners = require('../util/listeners.js')
const initialize = require('../util/initialization.js')
const config = require('../config.js')
const ScheduleManager = require('./ScheduleManager.js')
const storage = require('../util/storage.js')
const log = require('../util/logger.js')
const dbOpsBlacklists = require('../util/db/blacklists.js')
const dbOpsFailedLinks = require('../util/db/failedLinks.js')
const dbOpsGeneral = require('../util/db/general.js')
const dbOpsVips = require('../util/db/vips.js')
const redisIndex = require('../structs/db/Redis/index.js')
const checkConfig = require('../util/checkConfig.js')
const connectDb = require('../rss/db/connect.js')
const ClientManager = require('./ClientManager.js')
const EventEmitter = require('events')
const DISABLED_EVENTS = ['TYPING_START', 'MESSAGE_DELETE', 'MESSAGE_UPDATE', 'PRESENCE_UPDATE', 'VOICE_STATE_UPDATE', 'VOICE_SERVER_UPDATE', 'USER_NOTE_UPDATE', 'CHANNEL_PINS_UPDATE']
const SHARDED_OPTIONS = { respawn: false }
const STATES = {
  STOPPED: 'STOPPED',
  STARTING: 'STARTING',
  READY: 'READY'
}
let webClient

function overrideConfigs (configOverrides) {
  // Config overrides must be manually done for it to be changed in the original object (config)
  for (var category in config) {
    const configCategory = config[category]
    if (!configOverrides[category]) continue
    for (var configName in configCategory) {
      if (configOverrides[category][configName] !== undefined && configOverrides[category][configName] !== config[category][configName]) {
        log.general.info(`Overriding config.${category}.${configName} from ${JSON.stringify(config[category][configName])} to ${JSON.stringify(configOverrides[category][configName])} from configOverride.json`)
        configCategory[configName] = configOverrides[category][configName]
      }
    }
  }
}

class Client extends EventEmitter {
  constructor (configOverrides, customSchedules) {
    super()
    // Override from file first
    if (config.web.enabled === true) webClient = require('../web/index.js')
    // Then override from constructor
    if (configOverrides) overrideConfigs(configOverrides)
    const configRes = checkConfig.check(config)
    if (configRes && configRes.fatal) throw new Error(configRes.message)
    else if (configRes) log.general.warning(configRes.message)
    if (configOverrides && Array.isArray(configOverrides.suppressLogLevels)) log.suppressLevel(configOverrides.suppressLogLevels)
    if (customSchedules) {
      if (!Array.isArray(customSchedules)) throw new Error('customSchedules parameter must be an array of objects')
      else {
        for (const schedule of customSchedules) {
          if (schedule.name === 'default') throw new Error('Schedule name cannot be "default"')
          const keys = Object.keys(schedule)
          if (!keys.includes('name')) throw new Error('Schedule "name" must be defined')
          if (!keys.includes('refreshRateMinutes')) throw new Error('Schedule "refreshRateMinutes" must be defined')
          if (!keys.includes('keywords') && !keys.includes('feedIDs')) throw new Error('Schedule "keywords" or "feedIDs" must be defined')
        }
      }
    }
    this.scheduleManager = undefined
    this.configOverrides = configOverrides
    this.customSchedules = customSchedules
    this.STATES = STATES
    this.state = STATES.STOPPED
    this.webClientInstance = undefined
  }

  login (token, noChildren) {
    if (this.bot) return log.general.error('Cannot login when already logged in')
    if (token instanceof Discord.ShardingManager) return new ClientManager(token)
    if (token instanceof Discord.Client) {
      return connectDb()
        .then(() => {
          if (config.web.enabled === true && !this.webClientInstance && (!token.shard || token.shard.count === 0)) this.webClientInstance = webClient()
          this._defineBot(token)
        }).catch(err => {
          throw err
        })
    }
    if (typeof token === 'string') {
      const client = new Discord.Client({ disabledEvents: DISABLED_EVENTS, messageCacheMaxSize: 100 })
      return connectDb()
        .then(() => client.login(token))
        .then(tok => {
          if (config.web.enabled === true && !this.webClientInstance && (!client.shard || client.shard.count === 0)) this.webClientInstance = webClient()
          this._defineBot(client)
        })
        .catch(err => {
          if (!noChildren && err.message.includes('too many guilds')) {
            const shardedClient = new ClientManager(new Discord.ShardingManager('./server.js', SHARDED_OPTIONS), this.configOverrides)
            shardedClient.once('finishInit', () => this.emit('finishInit'))
          } else {
            log.general.error(`Discord.RSS unable to login, retrying in 10 minutes`, err)
            setTimeout(() => this.login.bind(this)(token), 600000)
          }
        })
    }
    throw new TypeError('Argument must be a Discord.Client, Discord.ShardingManager, or a string')
  }

  _defineBot (bot) {
    this.bot = bot
    this.SHARD_PREFIX = bot.shard && bot.shard.count > 0 ? `SH ${bot.shard.id} ` : ''
    if (bot && bot.shard && bot.shard.count > 0) {
      process.send({ _drss: true, type: 'spawned', shardId: bot.shard.id, customSchedules: this.customSchedules && bot.shard.id === 0 ? this.customSchedules : undefined })
    }
    storage.bot = bot
    if (bot.shard && bot.shard.count > 0) this.listenToShardedEvents(bot)
    if (!bot.readyAt) bot.once('ready', this._initialize.bind(this))
    else this._initialize()
  }

  _initialize () {
    const bot = storage.bot
    if (this.configOverrides && this.configOverrides.setPresence === true) {
      if (config.bot.activityType) bot.user.setActivity(config.bot.activityName, { type: config.bot.activityType, url: config.bot.streamActivityURL || undefined })
      else bot.user.setActivity(null)
      bot.user.setStatus(config.bot.status)
    }
    bot.on('error', err => {
      log.general.error(`${this.SHARD_PREFIX}Websocket error`, err)
      if (config.bot.exitOnSocketIssues === true) {
        log.general.info('Stopping all processes due to config.bot.exitOnSocketIssues')
        if (this.scheduleManager) {
          // Check if it exists first since it may disconnect before it's even initialized
          for (var sched of this.scheduleManager.scheduleList) sched.killChildren()
        }
        if (bot.shard && bot.shard.count > 0) bot.shard.send({ _drss: true, type: 'kill' })
        else process.exit(0)
      } else this.stop()
    })
    bot.on('resume', () => {
      log.general.success(`${this.SHARD_PREFIX}Websocket resumed`)
      this.start()
    })
    bot.on('disconnect', () => {
      log.general.error(`${this.SHARD_PREFIX}Websocket disconnected`)
      if (config.bot.exitOnSocketIssues === true) {
        log.general.info('Stopping all processes due to config.bot.exitOnSocketIssues')
        if (this.scheduleManager) {
          // Check if it exists first since it may disconnect before it's even initialized
          for (var sched of this.scheduleManager.scheduleList) sched.killChildren()
        }
        if (bot.shard && bot.shard.count > 0) bot.shard.send({ _drss: true, type: 'kill' })
        else process.exit(0)
      } else this.stop()
    })
    log.general.success(`${this.SHARD_PREFIX}Discord.RSS has logged in as "${bot.user.username}" (ID ${bot.user.id})`)
    if (!bot.shard || bot.shard.count === 0) this.start()
    else process.send({ _drss: true, type: 'shardReady', shardId: bot.shard.id })
  }

  listenToShardedEvents (bot) {
    process.on('message', async message => {
      if (!message._drss) return
      try {
        switch (message.type) {
          case 'kill' :
            process.exit(0)
          case 'startInit':
            if (bot.shard.id === message.shardId) this.start()
            break
          case 'stop':
            this.stop()
            break
          case 'finishedInit':
            storage.initialized = 2
            if (config.database.uri.startsWith('mongodb')) await dbOpsBlacklists.refresh()
            break
          case 'cycleVIPs':
            if (bot.shard.id === message.shardId) await dbOpsVips.refresh(true)
            break
          case 'runSchedule':
            if (bot.shard.id === message.shardId) this.scheduleManager.run(message.refreshRate)
            break
          case 'failedLinks._sendAlert':
            dbOpsFailedLinks._sendAlert(message.link, message.message, true)
            break
          case 'blacklists.uniformize':
            await dbOpsBlacklists.uniformize(message.blacklistGuilds, message.blacklistUsers, true)
            break
          case 'dbRestoreSend':
            const channel = bot.channels.get(message.channelID)
            if (!channel) return
            const channelMsg = channel.messages.get(message.messageID)
            if (channelMsg) channelMsg.edit('Database restore complete! Stopping bot process for manual reboot.').then(m => bot.shard.send({ _drss: true, type: 'kill' }))
            else channel.send('Database restore complete! Stopping bot process for manual reboot.').then(m => bot.shard.send({ _drss: true, type: 'kill' }))
            break
        }
      } catch (err) {
        log.general.warning('client', err, true)
      }
    })
  }

  stop () {
    if (this.state === STATES.STARTING || this.state === STATES.STOPPED) return log.general.warning(`${this.SHARD_PREFIX}Ignoring stop command because of ${this.state} state`)
    log.general.warning(`${this.SHARD_PREFIX}Discord.RSS has received stop command`)
    storage.initialized = 0
    this.scheduleManager.stopSchedules()
    clearInterval(this._vipInterval)
    listeners.disableAll()
    if ((!storage.bot.shard || storage.bot.shard.count === 0) && config.web.enabled === true) this.webClientInstance.disableCP()
    this.state = STATES.STOPPED
  }

  async start (callback) {
    if (this.state === STATES.STARTING || this.state === STATES.READY) return log.general.warning(`${this.SHARD_PREFIX}Ignoring start command because of ${this.state} state`)
    this.state = STATES.STARTING
    listeners.enableCommands()
    const uri = config.database.uri
    log.general.info(`Database URI ${uri} detected as a ${uri.startsWith('mongo') ? 'MongoDB URI' : 'folder URI'}`)
    try {
      await connectDb()
      if (!this.bot.shard || this.bot.shard.count === 0) {
        await dbOpsGeneral.verifyFeedIDs()
        await redisIndex.flushDatabase()
      }
      if (!this.scheduleManager) {
        this.scheduleManager = new ScheduleManager(storage.bot)
        const addSchedulePromises = []
        addSchedulePromises.push(this.scheduleManager.addSchedule({ name: 'default', refreshRateMinutes: config.feeds.refreshRateMinutes }, false, true))
        if (config._vip === true) addSchedulePromises.push(this.scheduleManager.addSchedule({ name: 'vip', refreshRateMinutes: config._vipRefreshRateMinutes || config.feeds.refreshRateMinutes, feedIDs: [] }, false, true))
        const names = new Set()
        for (const schedule of this.customSchedules) {
          const name = schedule.name
          if (name === 'example') continue
          if (names.has(name)) throw new Error(`Schedules cannot have the same name (${name})`)
          names.add(name)
          addSchedulePromises.push(this.scheduleManager.addSchedule(schedule, false, true))
        }
        await Promise.all(addSchedulePromises)
        storage.scheduleManager = this.scheduleManager
      }
      await this.scheduleManager.assignAllSchedules()
      const { missingGuilds, linkTrackerDocs } = await initialize(this.bot)
      this._finishInit(missingGuilds, linkTrackerDocs, callback)
    } catch (err) {
      log.general.error(`Client start`, err, true)
    }
  }

  restart (callback) {
    if (this.state === STATES.STARTING) return log.general.warning(`${this.SHARD_PREFIX}Ignoring restart command because of ${this.state} state`)
    if (this.state === STATES.READY) this.stop()
    this.start(callback)
  }

  _finishInit (missingGuilds, linkDocs, callback) {
    storage.initialized = 2
    this.state = STATES.READY
    if (storage.bot.shard && storage.bot.shard.count > 0) {
      process.send({ _drss: true, type: 'initComplete', missingGuilds: missingGuilds, linkDocs: linkDocs, shard: storage.bot.shard.id })
    } else {
      if (config.web.enabled === true) this.webClientInstance.enableCP()
      if (config._vip) {
        this._vipInterval = setInterval(() => {
          dbOpsVips.refresh().catch(err => log.general.error('Unable to refresh vips on timer', err, true))
        }, 600000)
      }
    }
    listeners.createManagers(storage.bot)
    this.scheduleManager.startSchedules()
    // if (!this.bot.shard || this.bot.shard.count === 0) this.scheduleManager.run()
    if (callback) callback()
    this.emit('finishInit')
  }

  disableCommands () {
    listeners.disableCommands()
    return this
  }
}

module.exports = Client
<commit_msg>Ensure no duplicate schedule refresh rates<commit_after>const Discord = require('discord.js')
const listeners = require('../util/listeners.js')
const initialize = require('../util/initialization.js')
const config = require('../config.js')
const ScheduleManager = require('./ScheduleManager.js')
const storage = require('../util/storage.js')
const log = require('../util/logger.js')
const dbOpsBlacklists = require('../util/db/blacklists.js')
const dbOpsFailedLinks = require('../util/db/failedLinks.js')
const dbOpsGeneral = require('../util/db/general.js')
const dbOpsVips = require('../util/db/vips.js')
const redisIndex = require('../structs/db/Redis/index.js')
const checkConfig = require('../util/checkConfig.js')
const connectDb = require('../rss/db/connect.js')
const ClientManager = require('./ClientManager.js')
const EventEmitter = require('events')
const DISABLED_EVENTS = ['TYPING_START', 'MESSAGE_DELETE', 'MESSAGE_UPDATE', 'PRESENCE_UPDATE', 'VOICE_STATE_UPDATE', 'VOICE_SERVER_UPDATE', 'USER_NOTE_UPDATE', 'CHANNEL_PINS_UPDATE']
const SHARDED_OPTIONS = { respawn: false }
const STATES = {
  STOPPED: 'STOPPED',
  STARTING: 'STARTING',
  READY: 'READY'
}
let webClient

function overrideConfigs (configOverrides) {
  // Config overrides must be manually done for it to be changed in the original object (config)
  for (var category in config) {
    const configCategory = config[category]
    if (!configOverrides[category]) continue
    for (var configName in configCategory) {
      if (configOverrides[category][configName] !== undefined && configOverrides[category][configName] !== config[category][configName]) {
        log.general.info(`Overriding config.${category}.${configName} from ${JSON.stringify(config[category][configName])} to ${JSON.stringify(configOverrides[category][configName])} from configOverride.json`)
        configCategory[configName] = configOverrides[category][configName]
      }
    }
  }
}

class Client extends EventEmitter {
  constructor (configOverrides, customSchedules) {
    super()
    // Override from file first
    if (config.web.enabled === true) webClient = require('../web/index.js')
    // Then override from constructor
    if (configOverrides) overrideConfigs(configOverrides)
    const configRes = checkConfig.check(config)
    if (configRes && configRes.fatal) throw new Error(configRes.message)
    else if (configRes) log.general.warning(configRes.message)
    if (configOverrides && Array.isArray(configOverrides.suppressLogLevels)) log.suppressLevel(configOverrides.suppressLogLevels)
    if (customSchedules) {
      if (!Array.isArray(customSchedules)) throw new Error('customSchedules parameter must be an array of objects')
      else {
        for (const schedule of customSchedules) {
          if (schedule.name === 'default') throw new Error('Schedule name cannot be "default"')
          const keys = Object.keys(schedule)
          if (!keys.includes('name')) throw new Error('Schedule "name" must be defined')
          if (!keys.includes('refreshRateMinutes')) throw new Error('Schedule "refreshRateMinutes" must be defined')
          if (!keys.includes('keywords') && !keys.includes('feedIDs')) throw new Error('Schedule "keywords" or "feedIDs" must be defined')
        }
      }
    }
    this.scheduleManager = undefined
    this.configOverrides = configOverrides
    this.customSchedules = customSchedules
    this.STATES = STATES
    this.state = STATES.STOPPED
    this.webClientInstance = undefined
  }

  login (token, noChildren) {
    if (this.bot) return log.general.error('Cannot login when already logged in')
    if (token instanceof Discord.ShardingManager) return new ClientManager(token)
    if (token instanceof Discord.Client) {
      return connectDb()
        .then(() => {
          if (config.web.enabled === true && !this.webClientInstance && (!token.shard || token.shard.count === 0)) this.webClientInstance = webClient()
          this._defineBot(token)
        }).catch(err => {
          throw err
        })
    }
    if (typeof token === 'string') {
      const client = new Discord.Client({ disabledEvents: DISABLED_EVENTS, messageCacheMaxSize: 100 })
      return connectDb()
        .then(() => client.login(token))
        .then(tok => {
          if (config.web.enabled === true && !this.webClientInstance && (!client.shard || client.shard.count === 0)) this.webClientInstance = webClient()
          this._defineBot(client)
        })
        .catch(err => {
          if (!noChildren && err.message.includes('too many guilds')) {
            const shardedClient = new ClientManager(new Discord.ShardingManager('./server.js', SHARDED_OPTIONS), this.configOverrides)
            shardedClient.once('finishInit', () => this.emit('finishInit'))
          } else {
            log.general.error(`Discord.RSS unable to login, retrying in 10 minutes`, err)
            setTimeout(() => this.login.bind(this)(token), 600000)
          }
        })
    }
    throw new TypeError('Argument must be a Discord.Client, Discord.ShardingManager, or a string')
  }

  _defineBot (bot) {
    this.bot = bot
    this.SHARD_PREFIX = bot.shard && bot.shard.count > 0 ? `SH ${bot.shard.id} ` : ''
    if (bot && bot.shard && bot.shard.count > 0) {
      process.send({ _drss: true, type: 'spawned', shardId: bot.shard.id, customSchedules: this.customSchedules && bot.shard.id === 0 ? this.customSchedules : undefined })
    }
    storage.bot = bot
    if (bot.shard && bot.shard.count > 0) this.listenToShardedEvents(bot)
    if (!bot.readyAt) bot.once('ready', this._initialize.bind(this))
    else this._initialize()
  }

  _initialize () {
    const bot = storage.bot
    if (this.configOverrides && this.configOverrides.setPresence === true) {
      if (config.bot.activityType) bot.user.setActivity(config.bot.activityName, { type: config.bot.activityType, url: config.bot.streamActivityURL || undefined })
      else bot.user.setActivity(null)
      bot.user.setStatus(config.bot.status)
    }
    bot.on('error', err => {
      log.general.error(`${this.SHARD_PREFIX}Websocket error`, err)
      if (config.bot.exitOnSocketIssues === true) {
        log.general.info('Stopping all processes due to config.bot.exitOnSocketIssues')
        if (this.scheduleManager) {
          // Check if it exists first since it may disconnect before it's even initialized
          for (var sched of this.scheduleManager.scheduleList) sched.killChildren()
        }
        if (bot.shard && bot.shard.count > 0) bot.shard.send({ _drss: true, type: 'kill' })
        else process.exit(0)
      } else this.stop()
    })
    bot.on('resume', () => {
      log.general.success(`${this.SHARD_PREFIX}Websocket resumed`)
      this.start()
    })
    bot.on('disconnect', () => {
      log.general.error(`${this.SHARD_PREFIX}Websocket disconnected`)
      if (config.bot.exitOnSocketIssues === true) {
        log.general.info('Stopping all processes due to config.bot.exitOnSocketIssues')
        if (this.scheduleManager) {
          // Check if it exists first since it may disconnect before it's even initialized
          for (var sched of this.scheduleManager.scheduleList) sched.killChildren()
        }
        if (bot.shard && bot.shard.count > 0) bot.shard.send({ _drss: true, type: 'kill' })
        else process.exit(0)
      } else this.stop()
    })
    log.general.success(`${this.SHARD_PREFIX}Discord.RSS has logged in as "${bot.user.username}" (ID ${bot.user.id})`)
    if (!bot.shard || bot.shard.count === 0) this.start()
    else process.send({ _drss: true, type: 'shardReady', shardId: bot.shard.id })
  }

  listenToShardedEvents (bot) {
    process.on('message', async message => {
      if (!message._drss) return
      try {
        switch (message.type) {
          case 'kill' :
            process.exit(0)
          case 'startInit':
            if (bot.shard.id === message.shardId) this.start()
            break
          case 'stop':
            this.stop()
            break
          case 'finishedInit':
            storage.initialized = 2
            if (config.database.uri.startsWith('mongodb')) await dbOpsBlacklists.refresh()
            break
          case 'cycleVIPs':
            if (bot.shard.id === message.shardId) await dbOpsVips.refresh(true)
            break
          case 'runSchedule':
            if (bot.shard.id === message.shardId) this.scheduleManager.run(message.refreshRate)
            break
          case 'failedLinks._sendAlert':
            dbOpsFailedLinks._sendAlert(message.link, message.message, true)
            break
          case 'blacklists.uniformize':
            await dbOpsBlacklists.uniformize(message.blacklistGuilds, message.blacklistUsers, true)
            break
          case 'dbRestoreSend':
            const channel = bot.channels.get(message.channelID)
            if (!channel) return
            const channelMsg = channel.messages.get(message.messageID)
            if (channelMsg) channelMsg.edit('Database restore complete! Stopping bot process for manual reboot.').then(m => bot.shard.send({ _drss: true, type: 'kill' }))
            else channel.send('Database restore complete! Stopping bot process for manual reboot.').then(m => bot.shard.send({ _drss: true, type: 'kill' }))
            break
        }
      } catch (err) {
        log.general.warning('client', err, true)
      }
    })
  }

  stop () {
    if (this.state === STATES.STARTING || this.state === STATES.STOPPED) return log.general.warning(`${this.SHARD_PREFIX}Ignoring stop command because of ${this.state} state`)
    log.general.warning(`${this.SHARD_PREFIX}Discord.RSS has received stop command`)
    storage.initialized = 0
    this.scheduleManager.stopSchedules()
    clearInterval(this._vipInterval)
    listeners.disableAll()
    if ((!storage.bot.shard || storage.bot.shard.count === 0) && config.web.enabled === true) this.webClientInstance.disableCP()
    this.state = STATES.STOPPED
  }

  async start (callback) {
    if (this.state === STATES.STARTING || this.state === STATES.READY) return log.general.warning(`${this.SHARD_PREFIX}Ignoring start command because of ${this.state} state`)
    this.state = STATES.STARTING
    listeners.enableCommands()
    const uri = config.database.uri
    log.general.info(`Database URI ${uri} detected as a ${uri.startsWith('mongo') ? 'MongoDB URI' : 'folder URI'}`)
    try {
      await connectDb()
      if (!this.bot.shard || this.bot.shard.count === 0) {
        await dbOpsGeneral.verifyFeedIDs()
        await redisIndex.flushDatabase()
      }
      if (!this.scheduleManager) {
        const refreshRates = new Set()
        refreshRates.add(config.feeds.refreshRateMinutes)
        this.scheduleManager = new ScheduleManager(storage.bot)
        const addSchedulePromises = []
        addSchedulePromises.push(this.scheduleManager.addSchedule({ name: 'default', refreshRateMinutes: config.feeds.refreshRateMinutes }, false, true))
        if (config._vip === true) {
          if (!config._vipRefreshRateMinutes || config.feeds.refreshRateMinutes === config._vipRefreshRateMinutes) {
            throw new Error('Missing valid VIP refresh rate')
          }
          refreshRates.add(config._vipRefreshRateMinutes)
          addSchedulePromises.push(this.scheduleManager.addSchedule({ name: 'vip', refreshRateMinutes: config._vipRefreshRateMinutes, feedIDs: [] }, false, true))
        }
        const names = new Set()
        for (const schedule of this.customSchedules) {
          const name = schedule.name
          if (name === 'example') continue
          if (names.has(name)) throw new Error(`Schedules cannot have the same name (${name})`)
          names.add(name)
          addSchedulePromises.push(this.scheduleManager.addSchedule(schedule, false, true))
          if (refreshRates.has(schedule.refreshRateMinutes)) {
            throw new Error('Duplicate schedule refresh rates are not allowed')
          }
          refreshRates.add(schedule.refreshRateMinutes)
        }
        await Promise.all(addSchedulePromises)
        storage.scheduleManager = this.scheduleManager
      }
      await this.scheduleManager.assignAllSchedules()
      const { missingGuilds, linkTrackerDocs } = await initialize(this.bot)
      this._finishInit(missingGuilds, linkTrackerDocs, callback)
    } catch (err) {
      log.general.error(`Client start`, err, true)
    }
  }

  restart (callback) {
    if (this.state === STATES.STARTING) return log.general.warning(`${this.SHARD_PREFIX}Ignoring restart command because of ${this.state} state`)
    if (this.state === STATES.READY) this.stop()
    this.start(callback)
  }

  _finishInit (missingGuilds, linkDocs, callback) {
    storage.initialized = 2
    this.state = STATES.READY
    if (storage.bot.shard && storage.bot.shard.count > 0) {
      process.send({ _drss: true, type: 'initComplete', missingGuilds: missingGuilds, linkDocs: linkDocs, shard: storage.bot.shard.id })
    } else {
      if (config.web.enabled === true) this.webClientInstance.enableCP()
      if (config._vip) {
        this._vipInterval = setInterval(() => {
          dbOpsVips.refresh().catch(err => log.general.error('Unable to refresh vips on timer', err, true))
        }, 600000)
      }
    }
    listeners.createManagers(storage.bot)
    this.scheduleManager.startSchedules()
    // if (!this.bot.shard || this.bot.shard.count === 0) this.scheduleManager.run()
    if (callback) callback()
    this.emit('finishInit')
  }

  disableCommands () {
    listeners.disableCommands()
    return this
  }
}

module.exports = Client
<|endoftext|>


<commit_before>'use strict';
const cp = require('child_process');
const fs = require('fs');
const chalk = require('chalk');
const async = require('async');

let successfulTests = 0;
let testMessages = [];

fs.stat('../lang', function (err, stats) {
  if (err) {
    console.error(chalk.red('Could not stat executable'));
    return;
  }
  runTests();
});

function equalityTest(name, expectedOutput, command) {
  return function (callback) {
    let child = cp.exec(`../Lang ${command}`, function (err, stdout, stderr) {
      if (err) {
        testFinished(name, `${err.message}\nSignal: ${chalk.red(err.signal)}`, callback);
        return;
      }
      if (stdout === expectedOutput) testFinished(name, callback);
      else testFinished(name, `Command: ${command}\nExpected output: ${expectedOutput}\nRecieved output: ${stdout}`, callback);
    });
    setTimeout(() => {
      child.kill('SIGKILL');
    }, 5 * 1000 /* Kill it after 5 seconds */);
  };
}

let tests = {
  turingComplete: equalityTest('Turing Completeness', '11111\n10001\n10011\n', `-e '
  // Rule 110
  Integer timesToRun = 3;
  String input = "01101";
  input = "0" + input + "0";
  Integer initInputSize = input.length();
  while timesToRun-- > 0 do
    String newState = "";
    Integer i = 0;
    while i <= initInputSize - 3 do
      String result = input.substr(i, 3);
      i++;
      if result == "000" || result == "100" || result == "111" do
        newState += "0";
      else
        newState += "1";
      end
    end
    input = "0" + newState + "0";
    print(newState + "\n");
  end
  '`),
  escapechars: equalityTest('Escape Characters', '\n,\\,\b,J,T',
  `-e '
  print("\\n,\\\\,\\b,\\x4A,\\124")
  '`),
  integers: equalityTest('Literals, Integer', '1 255 5 89',
  `-e '
  print(1);
  print(" ");
  print(0xFF);
  print(" ");
  print(0b101);
  print(" ");
  print(0o131);
  '`),
  strings: equalityTest('Literals, String', 'qwerty1234{}/*-~?',
  `-e '
  print("qwerty1234{}/*-~?")
  '`),
  booleans: equalityTest('Literals, Boolean', 'true',
  `-e '
  print(true)
  '`),
  floats: equalityTest('Literals, Float', '1.2',
  `-e '
  print(1.2)
  '`),
  intPlus: equalityTest('Addition, Integer', '16',
  `-e '
  print(8 + 8)
  '`),
  fltPlus: equalityTest('Addition, Float', '16.32',
  `-e '
  print(8.16 + 8.16)
  '`),
  strPlus: equalityTest('Strings, Concatenation', 'abcdef',
  `-e '
  print("abc" + "def")
  '`),
  strLen: equalityTest('Strings, Length', '9',
  `-e '
  print("123456789".length())
  '`),
  strSub: equalityTest('Strings, Substr', 'sd',
  `-e '
  String aaa = "asdfghjkl";
  print(aaa.substr(1, 2));
  '`),
  assignment: equalityTest('Assignment, Basic', '123abc',
  `-e '
  define a = 123;
  print(a); a = "abc";
  print(a);
  '`),
  multiTypeDef: equalityTest('Types, Multiple', '03.14',
  `-e '
  Integer, Float number = 0;
  print(number);
  number = 3.14;
  print(number);
  '`),
  booleanCond: equalityTest('Expressions, Boolean', 'false',
  `-e '
  print(!(true || false && true || false));
  '`),
  ifTest: equalityTest('Conditionals, Simple', '42',
  `-e '
  if true do
    print(42);
  end
  '`),
  ifComplexTest: equalityTest('Conditionals, Full', '42',
  `-e '
  if true do
    print(42);
  else
    print(420);
  end
  '`),
  whileLoop: equalityTest('Loops, While', '0123',
  `-e '
  Integer i = 0;
  while i < 4 do
    print(i++);
  end
  '`),
  increment: equalityTest('Operators, Increment', '10',
  `-e '
  Integer i = 0;
  print(++i);
  i = 0;
  print(i++);
  '`),
  decrement: equalityTest('Operators, Decrement', '-10',
  `-e '
  Integer i = 0;
  print(--i);
  i = 0;
  print(i--);
  '`),
  basicFunc: equalityTest('Functions, Basic', '1',
  `-e '
  define function printOne do
    print(1);
  end
  printOne();
  '`),
  argumentFunc: equalityTest('Functions, Arguments', '4.2',
  `-e '
  define function add [Integer, Float a] [Integer, Float b] do
    print(a + b);
  end
  add(1, 3.2);
  '`),
  returnFunc: equalityTest('Functions, Return Values', '4',
  `-e '
  define function random => Integer do
    return 4; // Chosen by fair dice roll
  end
  print(random());
  '`),
  fullFunc: equalityTest('Functions, Complete', '4.2',
  `-e '
  define function add [Integer, Float a] [Integer, Float b] => Integer, Float do
    return a + b;
  end
  print(add(1, 3.2));
  '`),
  prefixArgs: equalityTest('Functions, Prefix Arguments', '4.2',
  `-e '
  define function add [a: Integer, Float] [b: Integer, Float] do
    print(a + b);
  end
  add(1, 3.2);
  '`),
  comments1: equalityTest('Comments, Line', '123',
  `-e '
  // print(1234);
  print(123);
  '`),
  comments2: equalityTest('Comments, Multi-Line', '123',
  `-e '
  /* print(1234);
  print(90);
  */
  print(123);
  '`),
  expressions1: equalityTest('Expressions, Simple', '124',
  `-e '
  print((123 + 123) / 2 + 2 >> 1);
  '`),
  expressions2: equalityTest('Expressions, Function', '0',
  `-e '
  print("abc".length() - 3);
  '`),
};

function testFinished(testName, errorString, callback) {
  if (arguments.length == 2) callback = errorString;
  if (errorString && typeof errorString === 'string') {
    testMessages.push(`Test '${chalk.yellow(testName)}' ${chalk.red('failed')}\n${errorString}`);
    callback();
    return;
  }
  testMessages.push(`Test '${chalk.yellow(testName)}' ok ${chalk.green('✓')}`);
  successfulTests++;
  callback();
}

function runTests() {
  let testCount = Object.keys(tests).length;
  async.parallel(tests, function (err) {
    console.log(testMessages.sort().join('\n'));
    if (successfulTests === testCount) {
      console.log(chalk.underline.green('All tests ok!'));
    } else {
      console.log(`${chalk.green(successfulTests)} tests ok\n${chalk.red(String(testCount - successfulTests))} tests failed`);
    }
    // If we got here, it means no test is still alive, so the parent can kill itself as well
    process.exit(0);
  });
}
<commit_msg>Fixed last commit<commit_after>'use strict';
const cp = require('child_process');
const fs = require('fs');
const chalk = require('chalk');
const async = require('async');

let successfulTests = 0;
let testMessages = [];

fs.stat('../lang', function (err, stats) {
  if (err) {
    console.error(chalk.red('Could not stat executable'));
    return;
  }
  runTests();
});

function equalityTest(name, expectedOutput, command) {
  return function (callback) {
    let child = cp.exec(`../lang ${command}`, function (err, stdout, stderr) {
      if (err) {
        testFinished(name, `${err.message}\nSignal: ${chalk.red(err.signal)}`, callback);
        return;
      }
      if (stdout === expectedOutput) testFinished(name, callback);
      else testFinished(name, `Command: ${command}\nExpected output: ${expectedOutput}\nRecieved output: ${stdout}`, callback);
    });
    setTimeout(() => {
      child.kill('SIGKILL');
    }, 5 * 1000 /* Kill it after 5 seconds */);
  };
}

let tests = {
  turingComplete: equalityTest('Turing Completeness', '11111\n10001\n10011\n', `-e '
  // Rule 110
  Integer timesToRun = 3;
  String input = "01101";
  input = "0" + input + "0";
  Integer initInputSize = input.length();
  while timesToRun-- > 0 do
    String newState = "";
    Integer i = 0;
    while i <= initInputSize - 3 do
      String result = input.substr(i, 3);
      i++;
      if result == "000" || result == "100" || result == "111" do
        newState += "0";
      else
        newState += "1";
      end
    end
    input = "0" + newState + "0";
    print(newState + "\n");
  end
  '`),
  escapechars: equalityTest('Escape Characters', '\n,\\,\b,J,T',
  `-e '
  print("\\n,\\\\,\\b,\\x4A,\\124")
  '`),
  integers: equalityTest('Literals, Integer', '1 255 5 89',
  `-e '
  print(1);
  print(" ");
  print(0xFF);
  print(" ");
  print(0b101);
  print(" ");
  print(0o131);
  '`),
  strings: equalityTest('Literals, String', 'qwerty1234{}/*-~?',
  `-e '
  print("qwerty1234{}/*-~?")
  '`),
  booleans: equalityTest('Literals, Boolean', 'true',
  `-e '
  print(true)
  '`),
  floats: equalityTest('Literals, Float', '1.2',
  `-e '
  print(1.2)
  '`),
  intPlus: equalityTest('Addition, Integer', '16',
  `-e '
  print(8 + 8)
  '`),
  fltPlus: equalityTest('Addition, Float', '16.32',
  `-e '
  print(8.16 + 8.16)
  '`),
  strPlus: equalityTest('Strings, Concatenation', 'abcdef',
  `-e '
  print("abc" + "def")
  '`),
  strLen: equalityTest('Strings, Length', '9',
  `-e '
  print("123456789".length())
  '`),
  strSub: equalityTest('Strings, Substr', 'sd',
  `-e '
  String aaa = "asdfghjkl";
  print(aaa.substr(1, 2));
  '`),
  assignment: equalityTest('Assignment, Basic', '123abc',
  `-e '
  define a = 123;
  print(a); a = "abc";
  print(a);
  '`),
  multiTypeDef: equalityTest('Types, Multiple', '03.14',
  `-e '
  Integer, Float number = 0;
  print(number);
  number = 3.14;
  print(number);
  '`),
  booleanCond: equalityTest('Expressions, Boolean', 'false',
  `-e '
  print(!(true || false && true || false));
  '`),
  ifTest: equalityTest('Conditionals, Simple', '42',
  `-e '
  if true do
    print(42);
  end
  '`),
  ifComplexTest: equalityTest('Conditionals, Full', '42',
  `-e '
  if true do
    print(42);
  else
    print(420);
  end
  '`),
  whileLoop: equalityTest('Loops, While', '0123',
  `-e '
  Integer i = 0;
  while i < 4 do
    print(i++);
  end
  '`),
  increment: equalityTest('Operators, Increment', '10',
  `-e '
  Integer i = 0;
  print(++i);
  i = 0;
  print(i++);
  '`),
  decrement: equalityTest('Operators, Decrement', '-10',
  `-e '
  Integer i = 0;
  print(--i);
  i = 0;
  print(i--);
  '`),
  basicFunc: equalityTest('Functions, Basic', '1',
  `-e '
  define function printOne do
    print(1);
  end
  printOne();
  '`),
  argumentFunc: equalityTest('Functions, Arguments', '4.2',
  `-e '
  define function add [Integer, Float a] [Integer, Float b] do
    print(a + b);
  end
  add(1, 3.2);
  '`),
  returnFunc: equalityTest('Functions, Return Values', '4',
  `-e '
  define function random => Integer do
    return 4; // Chosen by fair dice roll
  end
  print(random());
  '`),
  fullFunc: equalityTest('Functions, Complete', '4.2',
  `-e '
  define function add [Integer, Float a] [Integer, Float b] => Integer, Float do
    return a + b;
  end
  print(add(1, 3.2));
  '`),
  prefixArgs: equalityTest('Functions, Prefix Arguments', '4.2',
  `-e '
  define function add [a: Integer, Float] [b: Integer, Float] do
    print(a + b);
  end
  add(1, 3.2);
  '`),
  comments1: equalityTest('Comments, Line', '123',
  `-e '
  // print(1234);
  print(123);
  '`),
  comments2: equalityTest('Comments, Multi-Line', '123',
  `-e '
  /* print(1234);
  print(90);
  */
  print(123);
  '`),
  expressions1: equalityTest('Expressions, Simple', '124',
  `-e '
  print((123 + 123) / 2 + 2 >> 1);
  '`),
  expressions2: equalityTest('Expressions, Function', '0',
  `-e '
  print("abc".length() - 3);
  '`),
};

function testFinished(testName, errorString, callback) {
  if (arguments.length == 2) callback = errorString;
  if (errorString && typeof errorString === 'string') {
    testMessages.push(`Test '${chalk.yellow(testName)}' ${chalk.red('failed')}\n${errorString}`);
    callback();
    return;
  }
  testMessages.push(`Test '${chalk.yellow(testName)}' ok ${chalk.green('✓')}`);
  successfulTests++;
  callback();
}

function runTests() {
  let testCount = Object.keys(tests).length;
  async.parallel(tests, function (err) {
    console.log(testMessages.sort().join('\n'));
    if (successfulTests === testCount) {
      console.log(chalk.underline.green('All tests ok!'));
    } else {
      console.log(`${chalk.green(successfulTests)} tests ok\n${chalk.red(String(testCount - successfulTests))} tests failed`);
    }
    // If we got here, it means no test is still alive, so the parent can kill itself as well
    process.exit(0);
  });
}
<|endoftext|>


<commit_before>/*
---

name: Form.AutoGrow

description: Automatically resizes textareas based on their content.

authors: Christoph Pojer (@cpojer)

credits: Based on a script by Gary Glass (www.bookballoon.com)

license: MIT-style license.

requires: [Core/Class.Extras, Core/Element, Core/Element.Event, Core/Element.Style, Core/Element.Dimensions]

provides: Form.AutoGrow

...
*/

(function(){

var wrapper = new Element('div').setStyles({
	overflowX: 'hidden',
	position: 'absolute',
	top: 0,
	left: -9999
});

var escapeHTML = function(string){
	return string.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
};

if (!this.Form) this.Form = {};

var AutoGrow = this.Form.AutoGrow = new Class({

	Implements: [Options, Class.Singleton, Class.Binds],

	options: {
		minHeightFactor: 2,
		margin: 0
	},

	initialize: function(element, options){
		this.setOptions(options);
		element = this.element = document.id(element);

		return this.check(element) || this.setup();
	},

	setup: function(){
		this.attach().focus().resize();
	},

	toElement: function(){
		return this.element;
	},

	attach: function(){
		this.element.addEvents({
			focus: this.bound('focus'),
			keydown: this.bound('keydown'),
			scroll: this.bound('scroll')
		});

		return this;
	},

	detach: function(){
		this.element.removeEvents({
			focus: this.bound('focus'),
			keydown: this.bound('keydown'),
			scroll: this.bound('scroll')
		});

		return this;
	},

	focus: function(){
		wrapper.setStyles(this.element.getStyles('fontSize', 'fontFamily', 'width', 'lineHeight', 'padding')).inject(document.body);

		this.minHeight = (wrapper.set('html', 'A').getHeight() + this.options.margin) * this.options.minHeightFactor;

		return this;
	},

	keydown: function(){
		this.resize.delay(15, this);
	},

	resize: function(){
		var element = this.element,
			html = escapeHTML(element.get('value')).replace(/\n|\r\n/g, '
A');

		if (wrapper.get('html') == html) return this;

		wrapper.set('html', html);
		var height = wrapper.getHeight() + this.options.margin;
		if (element.getHeight() != height){
			element.setStyle('height', this.minHeight.max(height));

			AutoGrow.fireEvent('resize', [this]);
		}

		return this;
	},

	scroll: function(){
		this.element.scrollTo(0, 0);
	}

});

AutoGrow.extend(new Events);

})();
<commit_msg>* fireEvent => triggerEvent<commit_after>/*
---

name: Form.AutoGrow

description: Automatically resizes textareas based on their content.

authors: Christoph Pojer (@cpojer)

credits: Based on a script by Gary Glass (www.bookballoon.com)

license: MIT-style license.

requires: [Core/Class.Extras, Core/Element, Core/Element.Event, Core/Element.Style, Core/Element.Dimensions]

provides: Form.AutoGrow

...
*/

(function(){

var wrapper = new Element('div').setStyles({
	overflowX: 'hidden',
	position: 'absolute',
	top: 0,
	left: -9999
});

var escapeHTML = function(string){
	return string.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
};

if (!this.Form) this.Form = {};

var AutoGrow = this.Form.AutoGrow = new Class({

	Implements: [Options, Class.Singleton, Class.Binds],

	options: {
		minHeightFactor: 2,
		margin: 0
	},

	initialize: function(element, options){
		this.setOptions(options);
		element = this.element = document.id(element);

		return this.check(element) || this.setup();
	},

	setup: function(){
		this.attach().focus().resize();
	},

	toElement: function(){
		return this.element;
	},

	attach: function(){
		this.element.addEvents({
			focus: this.bound('focus'),
			keydown: this.bound('keydown'),
			scroll: this.bound('scroll')
		});

		return this;
	},

	detach: function(){
		this.element.removeEvents({
			focus: this.bound('focus'),
			keydown: this.bound('keydown'),
			scroll: this.bound('scroll')
		});

		return this;
	},

	focus: function(){
		wrapper.setStyles(this.element.getStyles('fontSize', 'fontFamily', 'width', 'lineHeight', 'padding')).inject(document.body);

		this.minHeight = (wrapper.set('html', 'A').getHeight() + this.options.margin) * this.options.minHeightFactor;

		return this;
	},

	keydown: function(){
		this.resize.delay(15, this);
	},

	resize: function(){
		var element = this.element,
			html = escapeHTML(element.get('value')).replace(/\n|\r\n/g, '
A');

		if (wrapper.get('html') == html) return this;

		wrapper.set('html', html);
		var height = wrapper.getHeight() + this.options.margin;
		if (element.getHeight() != height){
			element.setStyle('height', this.minHeight.max(height));

			AutoGrow.triggerEvent('resize', [this]);
		}

		return this;
	},

	scroll: function(){
		this.element.scrollTo(0, 0);
	}

});

AutoGrow.extend(new Events);

})();
<|endoftext|>


<commit_before>'use strict';

var _ = require('./../src/kit.js');

exports['test kit framework'] = function(assert) {
    var merge = _.merge(
        { a: 'aa', b: { bb: 'bbb' } },
        { a: 'aaa' },
        { a: { aa: 'aaa'} },
        { a: 'aa', b: { bb: 'bbbb' } }
    ), test;

    var arr = ['one', 'two', 'three'],
        arr2 = ['one', 'two', 'three'],
        removed = _.remove(arr2, 'three', 'two'),
        emptyArr = [];

    assert.equal(merge.a, 'aa', 'Assert merge.a === "aa" should return true');
    assert.equal(merge.b.bb, 'bbbb', 'Assert merge.b.bb === "bbbb" should return true');

    assert.equal(_.first(arr), 'one', 'Should return first element of an array');
    assert.equal(_.first(emptyArr), null, 'Should return null on empty array');
    assert.equal(_.last(arr), 'three', 'Should return last element of an array');
    assert.equal(_.last(emptyArr), null, 'Should return null on an empty array');
    assert.equal(removed[0], 'one', 'Should remove two elements from the array');

    assert.equal(_.isObject({}), true, 'Assert isObject({}) should return true');
    assert.equal(_.isFunction(function() {}), true, 'Assert isFunction(function() {}) should return true');
    assert.equal(_.isUndefined(test), true, 'Assert isUndefined(test) should return true');
    assert.equal(_.isArray(['a', 'b', 'c', 'd']), true, 'Assert isArray(["a", "b", "c", "d"]) should return true');
    assert.equal(_.isDate(new Date()), true, 'Assert isDate(new Date) should return true');
    assert.equal(_.isRegExp(/a-z/), true, 'Assert isRegExp(/a-z/) should return true');
    assert.equal(_.isString('its a string! 1+1'), true, 'Assert isString("its a string! 1+1") should return true');
    assert.equal(_.isNumber(1), true, 'Assert isNumber(1) should return true');
    assert.equal(_.isNumber(1.2), true, 'Assert isNumber(1.2) should return true');
    assert.equal(_.isNumber(-1.2), true, 'Assert isNumber(-1.2) should return true');
    assert.equal(_.isInteger(1), true, 'Assert isInteger(1) should return true');
    assert.equal(_.isInteger(1.0), true, 'Assert isInteger(1.0) should return true');
    assert.equal(_.isInteger(1.1), false, 'Assert isInteger(1.1) should return false');
    assert.equal(_.isInteger('1'), false, 'Assert isInteger("1") should return false');
    assert.equal(_.isInteger([]), false, 'Assert isInteger([]) should return false');
    assert.equal(_.isGlobal(global), true, 'Assert isGlobal(global) should return true');
};

if (module == require.main) {
    require('test').run(exports);
}
<commit_msg>added comment<commit_after>'use strict';

var _ = require('./../src/kit.js');
// Create better tests with mocha and chai
exports['test kit framework'] = function(assert) {
    var merge = _.merge(
        { a: 'aa', b: { bb: 'bbb' } },
        { a: 'aaa' },
        { a: { aa: 'aaa'} },
        { a: 'aa', b: { bb: 'bbbb' } }
    ), test;

    var arr = ['one', 'two', 'three'],
        arr2 = ['one', 'two', 'three'],
        removed = _.remove(arr2, 'three', 'two'),
        emptyArr = [];

    assert.equal(merge.a, 'aa', 'Assert merge.a === "aa" should return true');
    assert.equal(merge.b.bb, 'bbbb', 'Assert merge.b.bb === "bbbb" should return true');

    assert.equal(_.first(arr), 'one', 'Should return first element of an array');
    assert.equal(_.first(emptyArr), null, 'Should return null on empty array');
    assert.equal(_.last(arr), 'three', 'Should return last element of an array');
    assert.equal(_.last(emptyArr), null, 'Should return null on an empty array');
    assert.equal(removed[0], 'one', 'Should remove two elements from the array');

    assert.equal(_.isObject({}), true, 'Assert isObject({}) should return true');
    assert.equal(_.isFunction(function() {}), true, 'Assert isFunction(function() {}) should return true');
    assert.equal(_.isUndefined(test), true, 'Assert isUndefined(test) should return true');
    assert.equal(_.isArray(['a', 'b', 'c', 'd']), true, 'Assert isArray(["a", "b", "c", "d"]) should return true');
    assert.equal(_.isDate(new Date()), true, 'Assert isDate(new Date) should return true');
    assert.equal(_.isRegExp(/a-z/), true, 'Assert isRegExp(/a-z/) should return true');
    assert.equal(_.isString('its a string! 1+1'), true, 'Assert isString("its a string! 1+1") should return true');
    assert.equal(_.isNumber(1), true, 'Assert isNumber(1) should return true');
    assert.equal(_.isNumber(1.2), true, 'Assert isNumber(1.2) should return true');
    assert.equal(_.isNumber(-1.2), true, 'Assert isNumber(-1.2) should return true');
    assert.equal(_.isInteger(1), true, 'Assert isInteger(1) should return true');
    assert.equal(_.isInteger(1.0), true, 'Assert isInteger(1.0) should return true');
    assert.equal(_.isInteger(1.1), false, 'Assert isInteger(1.1) should return false');
    assert.equal(_.isInteger('1'), false, 'Assert isInteger("1") should return false');
    assert.equal(_.isInteger([]), false, 'Assert isInteger([]) should return false');
    assert.equal(_.isGlobal(global), true, 'Assert isGlobal(global) should return true');
};

if (module == require.main) {
    require('test').run(exports);
}
<|endoftext|>


<commit_before>/**
 * Run "casperjs _run.js" to run all the tests in this folder.
 * Note: install CasperJS v1.9.2.
 */

var fs = require('fs');
var casper = require('casper').create({
    logLevel: 'debug'
});

// Set the timeout.
var TIMEOUT = 60000;

// Handle JS errors.
casper.once('page.error', function onError(msg, trace) {
    // Workaround for GUI.endGame() causing some errors here.
    if (!this.exists('#gameEnded')) {
        this.die('Test error: ' + msg + '\n\n' + trace);
    }
});

// Show log messages in the console.
casper.on('remote.message', function(message) {
    this.echo('[LOG]: ' + message);
});

// Find all the .html files in the tests directory.
var files = fs.list(fs.workingDirectory);
var tests = [];
files.forEach(function(file) {
    if (file.indexOf('.html', file.length - '.html'.length) !== -1) {
        tests.push(file);
    }
});

// Run all the tests!
casper.echo('Running ' + tests.length + ' tests with a timeout of '
    + TIMEOUT / 1000 + ' s.\n');

var runHtmlTest = function() {
    var path = this.getCurrentUrl();
    var filename = path.substring(path.lastIndexOf('/') + 1);
    this.echo('Running ' + filename + '...');
};

var onTimeout = function() {
    this.die('Test timed out.');
};

var testIndex = 0;
for (var i = 0; i < tests.length; i++) {
    if (i == 0) {
        casper.start(tests[i], runHtmlTest);
        casper.waitForSelector('#gameEnded', null, onTimeout, TIMEOUT);
    } else {
        casper.thenOpen(tests[i], runHtmlTest);
        casper.waitForSelector('#gameEnded', null, onTimeout, TIMEOUT);
    }
}

casper.run();<commit_msg>Rewrite run.js as a test<commit_after>/**
 * Run "casperjs test run.js" to run all the tests in this folder.
 * Note: install CasperJS v1.9.2.
 */

var fs = require('fs');

// Config.
var TIMEOUT = 60000;
var SHOW_CONSOLE_LOG = false;
var DONE_SELECTOR = '#gameEnded';

// Show log messages in the console if needed.
if (SHOW_CONSOLE_LOG) {
    casper.on('remote.message', function(message) {
        this.echo('[LOG]: ' + message);
    });
}

// Find all the .html files in the tests directory.
var files = fs.list(fs.workingDirectory);
var tests = [];
files.forEach(function(file) {
    if (file.indexOf('.html', file.length - '.html'.length) !== -1) {
        tests.push(file);
    }
});

// Run all the tests!
casper.echo('Running ' + tests.length + ' test' + (tests.length != 1 ? 's' : '') +
    ' with a timeout of ' + TIMEOUT / 1000 + ' seconds.\n');

var testIndex = 0;
for (var i = 0; i < tests.length; i++) {
    casper.test.begin(tests[i], 3, function suite(test) {
        var errors = [];
        casper.on('page.error', function onError(msg, trace) {
            errors.push(msg + ': ' + trace);
        });

        casper.start(tests[i]);

        // Wait for either the game to end or an error to appear.
        var timedOut = false;
        casper.waitFor(
            function check() {
                return errors.length != 0 || this.exists(DONE_SELECTOR);
            },
            function gameEnded() {
                test.assertEquals([]], []);
                test.assertExists('#gameEnded');
            },
            function timedOut() {
                timedOut = true;
                test.assertEquals(errors, []);
                test.assertExists('#gameEnded');
            }, TIMEOUT);

        casper.then(function() {
            test.assertFalsy(timedOut);
        });

        casper.run(function() {
            test.done();
        });
    });
}<|endoftext|>


<commit_before>var complexityRegex = /\b(a number of|abundance|accede to|accelerate|accentuate|accompany|accomplish|accorded|accrue|acquiesce|acquire|additional|adjacent to|adjustment|admissible|advantageous|adversely impact|advise|aforementioned|aggregate|aircraft|all of|alleviate|allocate|along the lines of|already existing|alternatively|ameliorate|anticipate|apparent|appreciable|as a means of|as of yet|as to|as yet|ascertain|assistance|at this time|attain|attributable to|authorize|because of the fact that|belated|benefit from|bestow|by virtue of|cease|close proximity|commence|comply with|concerning|consequently|consolidate|constitutes|demonstrate|depart|designate|discontinue|due to the fact that|each and every|economical|eliminate|elucidate|employ|endeavor|enumerate|equitable|equivalent|evaluate|evidenced|exclusively|expedite|expend|expiration|facilitate|factual evidence|feasible|finalize|first and foremost|for the purpose of|forfeit|formulate|honest truth|however|if and when|impacted|implement|in a timely manner|in accordance with|in addition|in all likelihood|in an effort to|in between|in excess of|in lieu of|in light of the fact that|in many cases|in order to|in regard to|in some instances|in terms of|in the near future|in the process of|inception|incumbent upon|indicate|indication|initiate|is applicable to|is authorized to|is responsible for|it is essential|it is|it was|magnitude|maximum|methodology|minimize|minimum|modify|monitor|multiple|necessitate|nevertheless|not certain|not many|not often|not unless|not unlike|notwithstanding|null and void|numerous|objective|obligate|obtain|on the contrary|on the other hand|one particular|optimum|overall|owing to the fact that|participate|particulars|pass away|pertaining to|point in time|portion|possess|preclude|previously|prior to|prioritize|procure|proficiency|provided that|purchase|put simply|readily apparent|refer back|regarding|relocate|remainder|remuneration|requirement|require|residence|reside|retain|satisfy|shall|should you wish|similar to|solicit|span across|strategize|subsequent|substantial|successfully complete|sufficient|terminate|the month of|there are|there is|therefore|time period|took advantage of|transmit|transpire|until such time as|utilization|utilize|validate|various different|very|whether or not|with respect to|with the exception of|witnessed)\b/gi;
var matcher = require("./matcher");

module.exports = function(text) {
  return matcher(complexityRegex, text, "wordy");
};
<commit_msg>removed some phrases; reformatted for readability<commit_after>var matcher = require("./matcher");
var wordyWords = [
  'a number of',
  'abundance',
  'accede to',
  'accelerate',
  'accentuate',
  'accompany',
  'accomplish',
  'accorded',
  'accrue',
  'acquiesce',
  'acquire',
  'additional',
  'adjacent to',
  'adjustment',
  'admissible',
  'advantageous',
  'adversely impact',
  'advise',
  'aforementioned',
  'aggregate',
  'aircraft',
  'all of',
  'alleviate',
  'allocate',
  'along the lines of',
  'already existing',
  'alternatively',
  'ameliorate',
  'anticipate',
  'apparent',
  'appreciable',
  'as a means of',
  'as of yet',
  'as to',
  'as yet',
  'ascertain',
  'assistance',
  'at this time',
  'attain',
  'attributable to',
  'authorize',
  'because of the fact that',
  'belated',
  'benefit from',
  'bestow',
  'by virtue of',
  'cease',
  'close proximity',
  'commence',
  'comply with',
  'concerning',
  'consequently',
  'consolidate',
  'constitutes',
  'demonstrate',
  'depart',
  'designate',
  'discontinue',
  'due to the fact that',
  'each and every',
  'economical',
  'eliminate',
  'elucidate',
  'employ',
  'endeavor',
  'enumerate',
  'equitable',
  'equivalent',
  'evaluate',
  'evidenced',
  'exclusively',
  'expedite',
  'expend',
  'expiration',
  'facilitate',
  'factual evidence',
  'feasible',
  'finalize',
  'first and foremost',
  'for the purpose of',
  'forfeit',
  'formulate',
  'honest truth',
  'however',
  'if and when',
  'impacted',
  'implement',
  'in a timely manner',
  'in accordance with',
  'in addition',
  'in all likelihood',
  'in an effort to',
  'in between',
  'in excess of',
  'in lieu of',
  'in light of the fact that',
  'in many cases',
  'in order to',
  'in regard to',
  'in some instances',
  'in terms of',
  'in the near future',
  'in the process of',
  'inception',
  'incumbent upon',
  'indicate',
  'indication',
  'initiate',
  'is applicable to',
  'is authorized to',
  'is responsible for',
  'it is essential',
  'it is',
  'it was',
  'magnitude',
  'maximum',
  'methodology',
  'minimize',
  'minimum',
  'modify',
  'monitor',
  'multiple',
  'necessitate',
  'nevertheless',
  'not certain',
  'not many',
  'not often',
  'not unless',
  'not unlike',
  'notwithstanding',
  'null and void',
  'numerous',
  'objective',
  'obligate',
  'obtain',
  'on the contrary',
  'on the other hand',
  'one particular',
  'optimum',
  'overall',
  'owing to the fact that',
  'participate',
  'particulars',
  'pass away',
  'pertaining to',
  'point in time',
  'portion',
  'possess',
  'preclude',
  'previously',
  'prior to',
  'prioritize',
  'procure',
  'proficiency',
  'provided that',
  'purchase',
  'put simply',
  'readily apparent',
  'refer back',
  'regarding',
  'relocate',
  'remainder',
  'remuneration',
  'requirement',
  'residence',
  'reside',
  'retain',
  'satisfy',
  'shall',
  'should you wish',
  'similar to',
  'solicit',
  'span across',
  'strategize',
  'subsequent',
  'substantial',
  'successfully complete',
  'sufficient',
  'terminate',
  'the month of',
  'therefore',
  'time period',
  'took advantage of',
  'transmit',
  'transpire',
  'until such time as',
  'utilization',
  'utilize',
  'validate',
  'various different',
  'very',
  'whether or not',
  'with respect to',
  'with the exception of',
  'witnessed'
];

var wordyRegex = new RegExp('\\b(' + wordyWords.join('|') + ')\\b', 'gi');

module.exports = function(text) {
  return matcher(wordyRegex, text, "wordy");
};
<|endoftext|>


<commit_before>var lang = require("./lang")

function translate (node) {
  if (!node) return []

  switch (node.type) {
    case "list_list": return listList(node)
    case "list": return list(node)
    case "s_exp_list": return sExpList(node)
    case "vector": return vector(node)
    case "keyword": return keyword(node)
    case "symbol": return symbol(node)
    case "string": return string(node)
    case "number": return number(node)
    case "boolean": return boolean(node)
    case "leaf": return translate(node.left)
    case "macro": return macro(node)
    default: throw new Error("Compile error. Unknown node type " + node.type)
  }
}

function listList (node) {
  return translate(node.left).concat(translate(node.right))
}

function list (node) {
  var leftNode = node.left
  if (leftNode.left.type == "leaf" && leftNode.left.left.type == "symbol") {
    var left = translate(leftNode.left)
    switch (left[0].name) {
      // Namespace definition
      case "ns":
        return [new lang.Namespace(translate(leftNode.right.left))]
      // Variable definition
      case "def":
        return [new lang.Variable(
          translate(leftNode.right.left),
          translate(leftNode.right.right)
        )]
      // Function definition
      case "defn":
        return [new lang.Function(
          translate(leftNode.right.left),
          new lang.FuncArgs(translate(leftNode.right.right.left)),
          translate(leftNode.right.right.right)
        )]
      // Assignment
      case "set!":
        return [new lang.Assign(
          translate(leftNode.right.left),
          translate(leftNode.right.right)
        )]
      // Comparison
      case "<":
      case ">":
      case "<=":
      case ">=":
      case "==":
        return [new lang.Comparison(
          left,
          translate(leftNode.right.left),
          translate(leftNode.right.right)
        )]
      case "not=":
        return [new lang.Comparison(
          [new lang.Symbol("!=")],
          translate(leftNode.right.left),
          translate(leftNode.right.right)
        )]
      // Variable declarations
      case "let":
        var decs = translate(leftNode.right.left)
        var vars = []
        for (var i = 0; i < decs.length; i += 2) {
          vars.push(new lang.Variable([decs[i]], [decs[i + 1]]))
        }
        return vars.concat(translate(leftNode.right.right))
      // Function call or property access
      default:
        // Function call on object
        if (left[0].name[0] == ".") {
          return [new lang.Invoke(
            [new lang.Symbol(translate(leftNode.right.left)[0].name + left[0].name)],
            translate(leftNode.right.right)
          )]
        // Property access on object
        } else if (left[0].name[0] == "-") {

        }
        return [new lang.Invoke(left, translate(leftNode.right))]
    }
  } else {
    return translate(leftNode.left).concat(translate(leftNode.right))
  }
}

function sExpList (node) {
  return translate(node.left).concat(translate(node.right))
}

function vector (node) {
  return translate(node.left).concat(translate(node.right))
}

function keyword (node) {
  return [new lang.Keyword(node.val)]
}

function symbol (node) {
  return [new lang.Symbol(node.val)]
}

function string (node) {
  return [new lang.String(node.val)]
}

function number (node) {
  return [new lang.Number(node.val)]
}

function boolean (node) {
  return [new lang.Boolean(node.val)]
}

function macro (node) {
  switch (node.left.left.type) {
    case "deref":
      var invoke = new lang.Invoke([new lang.Symbol("deref")], translate(node.right))
      return [invoke]
  }
}

module.exports = function (t) {
  //console.log(JSON.stringify(t, null, 2))
  return translate(t)
}<commit_msg>Translate property access on object<commit_after>var lang = require("./lang")

function translate (node) {
  if (!node) return []

  switch (node.type) {
    case "list_list": return listList(node)
    case "list": return list(node)
    case "s_exp_list": return sExpList(node)
    case "vector": return vector(node)
    case "keyword": return keyword(node)
    case "symbol": return symbol(node)
    case "string": return string(node)
    case "number": return number(node)
    case "boolean": return boolean(node)
    case "leaf": return translate(node.left)
    case "macro": return macro(node)
    default: throw new Error("Compile error. Unknown node type " + node.type)
  }
}

function listList (node) {
  return translate(node.left).concat(translate(node.right))
}

function list (node) {
  var leftNode = node.left
  if (leftNode.left.type == "leaf" && leftNode.left.left.type == "symbol") {
    var left = translate(leftNode.left)
    switch (left[0].name) {
      // Namespace definition
      case "ns":
        return [new lang.Namespace(translate(leftNode.right.left))]
      // Variable definition
      case "def":
        return [new lang.Variable(
          translate(leftNode.right.left),
          translate(leftNode.right.right)
        )]
      // Function definition
      case "defn":
        return [new lang.Function(
          translate(leftNode.right.left),
          new lang.FuncArgs(translate(leftNode.right.right.left)),
          translate(leftNode.right.right.right)
        )]
      // Assignment
      case "set!":
        return [new lang.Assign(
          translate(leftNode.right.left),
          translate(leftNode.right.right)
        )]
      // Comparison
      case "<":
      case ">":
      case "<=":
      case ">=":
      case "==":
        return [new lang.Comparison(
          left,
          translate(leftNode.right.left),
          translate(leftNode.right.right)
        )]
      case "not=":
        return [new lang.Comparison(
          [new lang.Symbol("!=")],
          translate(leftNode.right.left),
          translate(leftNode.right.right)
        )]
      // Variable declarations
      case "let":
        var decs = translate(leftNode.right.left)
        var vars = []
        for (var i = 0; i < decs.length; i += 2) {
          vars.push(new lang.Variable([decs[i]], [decs[i + 1]]))
        }
        return vars.concat(translate(leftNode.right.right))
      // Function call or property access
      default:
        // Property access on object
        if (left[0].name.indexOf(".-") == 0) {
          return [new lang.Symbol(
            translate(leftNode.right.left)[0].name + left[0].name.replace(".-", ".")
          )]
        // Function call on object
        } else if (left[0].name[0] == ".") {
          return [new lang.Invoke(
            [new lang.Symbol(translate(leftNode.right.left)[0].name + left[0].name)],
            translate(leftNode.right.right)
          )]
        }
        return [new lang.Invoke(left, translate(leftNode.right))]
    }
  } else {
    return translate(leftNode.left).concat(translate(leftNode.right))
  }
}

function sExpList (node) {
  return translate(node.left).concat(translate(node.right))
}

function vector (node) {
  return translate(node.left).concat(translate(node.right))
}

function keyword (node) {
  return [new lang.Keyword(node.val)]
}

function symbol (node) {
  return [new lang.Symbol(node.val)]
}

function string (node) {
  return [new lang.String(node.val)]
}

function number (node) {
  return [new lang.Number(node.val)]
}

function boolean (node) {
  return [new lang.Boolean(node.val)]
}

function macro (node) {
  switch (node.left.left.type) {
    case "deref":
      var invoke = new lang.Invoke([new lang.Symbol("deref")], translate(node.right))
      return [invoke]
  }
}

module.exports = function (t) {
  //console.log(JSON.stringify(t, null, 2))
  return translate(t)
}<|endoftext|>


<commit_before>const stats = require('./stats.json');
const config = require('./config.js');
const Discord = require('discord.js');
const feedback = require('./util/feedback');
const fs = require('fs');

const client = new Discord.Client();
const token = config.token;

var played = stats.played == null ? 0 : stats.played;
var trump = stats.trump == null ? 0 : stats.trump;
var clinton = stats.clinton == null ? 0 : stats.clinton;
var merkel = stats.merkel == null ? 0 : stats.merkel;

// cache audios in memory
// TODO

// set listeners
setListeners(client);

// log our bot in
client.login(token);

function setListeners(client) {

    process.on('uncaughtException', function (exception) {
        console.log("Global error: " + exception);
    });

    process.on("unhandledRejection", err => {
        console.error("Uncaught Promise Error: \n" + err.stack);
    });

    client.on('ready', () => {
        client.user.setStatus('online', '!trump --help');
        console.log("Ready!");
    });

    client.on("disconnect", () => {
        console.log("Disconnected!");
    });

    // create listener for messages
    client.on('message', message => {
        handleMessage(message);
    });

}

function handleMessage(message) {

    var content = message.content.toLowerCase();
    var textChannel = message.channel;
    var guild = message.guild;

    var politician;

    if (content.startsWith("!trump")) {
        politician = "trump";
    }
    if (content.startsWith("!clinton")) {
        politician = "clinton";
    }
    if (content.startsWith("!merkel")) {
        politician = "merkel";
    }

    if (politician == null) {
        return;
    }

    var options = new Object();

    // default, will be overwritten by argument if needed
    options.voiceChannel = message.member.voiceChannel;
    options.play = true;
    options.file = getRandomAudio(politician);
    options.author = message.author;

    // has arguments?
    content = content.replace("!" + politician, "").trim();

    if (content != "") {
        var argumentParser = require("./util/argumentParser");
        argumentParser.parse(options, client, content, politician, guild);
    }

    if (options.leave) {
        var voiceConnection = client.voiceConnections.get(guild.id);

        if (voiceConnection) {
            voiceConnection.disconnect();
            voiceConnection.channel.leave();
        }
    }

    var isBusy = isBusyInGuild(guild);

    if (isBusy) {
        options.message = "I am currently needed in Channel '" + isBusy.name + "'."
        options.play = false;
    }

    if (options.play) {

        if (options.voiceChannel == null) {
            textChannel.sendMessage('You have to be in a voice channel to do this.');
        } else {
            checkMilestones(textChannel, options.author);

            playAudio(options.voiceChannel, options.file, politician, textChannel);
        }
    }

    if (options.message) {
        feedback.writeMessage(textChannel, options.message);
    }

}

function isBusyInGuild(guild) {

    var connections = Array.from(client.voiceConnections.values());

    for (i = 0; i < connections.length; i++) {
        var connection = connections[i];

        if (connection.channel.guild == guild) {
            return connection.channel;
        }
    }
    return false;
}

function playAudio(voiceChannel, file, politician, textChannel) {

    // check for permissions first
    if (!voiceChannel.permissionsFor(client.user.id).hasPermission("CONNECT")) {
        feedback.writeMessage(textChannel, "No permission to join this channel.")
        return;
    };
    if (!voiceChannel.permissionsFor(client.user.id).hasPermission("SPEAK")) {
        feedback.writeMessage(textChannel, "No permission to speak in this channel.")
        return;
    };

    voiceChannel.join().then(connection => {

        connection.playFile(file).on("end", () => {

            connection.disconnect();
            voiceChannel.leave();
            played++;

            if (politician == "trump") {
                trump++;
            }
            if (politician == "clinton") {
                clinton++;
            }
            if (politician == "merkel") {
                merkel++;
            }

            writeStats();
        });

    }).catch(error => {
        feedback.writeMessage(textChannel, error.toString());
    });
}

function checkMilestones(textChannel, user) {

    // if the sound is a multiple of 10000
    if (played + 1 % 10000 == 0) {

        console.log("Milestone reached!");

        textChannel.sendMessage(
            user.username
            + " just broke the "
            + played + 1
            + "-milestone! Congratulations, have a friendly handshake! :handshake:");
    }

}

function getRandomAudio(politician) {

    var fs = require('fs');
    var files = fs.readdirSync("./audio/" + politician);

    var index = Math.floor(Math.random() * (files.length));

    return "./audio/" + politician + "/" + files[index];
}

var lastWrite;
function writeStats() {

    client.shard.fetchClientValues('guilds.size').then(results => {
        // return if lastWrite was less than 5secs
        if ((Date.now() - lastWrite) < 5000) {
            return;
        }

        // Set current time
        lastWrite = Date.now();

        // write current stats
        var fileName = './stats.json';
        var file = require(fileName);

        file.played = played;
        file.guildCount = results[0];
        file.trump = trump;
        file.clinton = clinton;
        file.merkel = merkel;

        fs.writeFile(
            fileName,
            JSON.stringify(file, null, 2),
            function (error) {
                if (error) return console.log(error);
            }
        );
    }).catch(console.error);
}<commit_msg>Fixed guildcount finally<commit_after>const stats = require('./stats.json');
const config = require('./config.js');
const Discord = require('discord.js');
const feedback = require('./util/feedback');
const fs = require('fs');

const client = new Discord.Client();
const token = config.token;

var played = stats.played == null ? 0 : stats.played;
var trump = stats.trump == null ? 0 : stats.trump;
var clinton = stats.clinton == null ? 0 : stats.clinton;
var merkel = stats.merkel == null ? 0 : stats.merkel;

// cache audios in memory
// TODO

// set listeners
setListeners(client);

// log our bot in
client.login(token);

function setListeners(client) {

    process.on('uncaughtException', function (exception) {
        console.log("Global error: " + exception);
    });

    process.on("unhandledRejection", err => {
        console.error("Uncaught Promise Error: \n" + err.stack);
    });

    client.on('ready', () => {
        client.user.setStatus('online', '!trump --help');
        console.log("Ready!");
    });

    client.on("disconnect", () => {
        console.log("Disconnected!");
    });

    // create listener for messages
    client.on('message', message => {
        handleMessage(message);
    });

}

function handleMessage(message) {

    var content = message.content.toLowerCase();
    var textChannel = message.channel;
    var guild = message.guild;

    var politician;

    if (content.startsWith("!trump")) {
        politician = "trump";
    }
    if (content.startsWith("!clinton")) {
        politician = "clinton";
    }
    if (content.startsWith("!merkel")) {
        politician = "merkel";
    }

    if (politician == null) {
        return;
    }

    var options = new Object();

    // default, will be overwritten by argument if needed
    options.voiceChannel = message.member.voiceChannel;
    options.play = true;
    options.file = getRandomAudio(politician);
    options.author = message.author;

    // has arguments?
    content = content.replace("!" + politician, "").trim();

    if (content != "") {
        var argumentParser = require("./util/argumentParser");
        argumentParser.parse(options, client, content, politician, guild);
    }

    if (options.leave) {
        var voiceConnection = client.voiceConnections.get(guild.id);

        if (voiceConnection) {
            voiceConnection.disconnect();
            voiceConnection.channel.leave();
        }
    }

    var isBusy = isBusyInGuild(guild);

    if (isBusy) {
        options.message = "I am currently needed in Channel '" + isBusy.name + "'."
        options.play = false;
    }

    if (options.play) {

        if (options.voiceChannel == null) {
            textChannel.sendMessage('You have to be in a voice channel to do this.');
        } else {
            checkMilestones(textChannel, options.author);

            playAudio(options.voiceChannel, options.file, politician, textChannel);
        }
    }

    if (options.message) {
        feedback.writeMessage(textChannel, options.message);
    }

}

function isBusyInGuild(guild) {

    var connections = Array.from(client.voiceConnections.values());

    for (i = 0; i < connections.length; i++) {
        var connection = connections[i];

        if (connection.channel.guild == guild) {
            return connection.channel;
        }
    }
    return false;
}

function playAudio(voiceChannel, file, politician, textChannel) {

    // check for permissions first
    if (!voiceChannel.permissionsFor(client.user.id).hasPermission("CONNECT")) {
        feedback.writeMessage(textChannel, "No permission to join this channel.")
        return;
    };
    if (!voiceChannel.permissionsFor(client.user.id).hasPermission("SPEAK")) {
        feedback.writeMessage(textChannel, "No permission to speak in this channel.")
        return;
    };

    voiceChannel.join().then(connection => {

        connection.playFile(file).on("end", () => {

            connection.disconnect();
            voiceChannel.leave();
            played++;

            if (politician == "trump") {
                trump++;
            }
            if (politician == "clinton") {
                clinton++;
            }
            if (politician == "merkel") {
                merkel++;
            }

            writeStats();
        });

    }).catch(error => {
        feedback.writeMessage(textChannel, error.toString());
    });
}

function checkMilestones(textChannel, user) {

    // if the sound is a multiple of 10000
    if (played + 1 % 10000 == 0) {

        console.log("Milestone reached!");

        textChannel.sendMessage(
            user.username
            + " just broke the "
            + played + 1
            + "-milestone! Congratulations, have a friendly handshake! :handshake:");
    }

}

function getRandomAudio(politician) {

    var fs = require('fs');
    var files = fs.readdirSync("./audio/" + politician);

    var index = Math.floor(Math.random() * (files.length));

    return "./audio/" + politician + "/" + files[index];
}

var lastWrite;
function writeStats() {

    client.shard.fetchClientValues('guilds.size').then(results => {
        // return if lastWrite was less than 5secs
        if ((Date.now() - lastWrite) < 5000) {
            return;
        }

        var guildSum = 0;
        for (var i = 0; i < results.length; i++) {
            guildSum += results[i];
        }

        // Set current time
        lastWrite = Date.now();

        // write current stats
        var fileName = './stats.json';
        var file = require(fileName);

        file.played = played;
        file.guildCount = guildSum;
        file.trump = trump;
        file.clinton = clinton;
        file.merkel = merkel;

        fs.writeFile(
            fileName,
            JSON.stringify(file, null, 2),
            function (error) {
                if (error) return console.log(error);
            }
        );
    }).catch(console.error);
}<|endoftext|>


<commit_before>// Load JS Library in JS
function getScript(url,success) {
  var script=document.createElement('script');
  script.src=url;
  var head=document.getElementsByTagName('head')[0],
  done=false;script.onload=script.onreadystatechange=function(){
    if(!done&&(!this.readyState||this.readyState=='loaded'||this.readyState=='complete')){
    done=true;success();script.onload=script.onreadystatechange=null;head.removeChild(script);
    }
  };
  head.appendChild(script);
}

// Load Latest, Compressed jQuery
getScript('http://code.jquery.com/jquery-latest.min.js', function(){
  return trollEveryoneElse();
});

// Delayed Loop
var forEachDelay = function(delay, f, xs) {
  if (xs.length) {
    setTimeout(function() {
      f(xs[0]);
      forEachDelay(delay, f, xs.slice(1));
    }, delay);
  }
}

// Rek Scrubz
function trollEveryoneElse() {
  var text = $('div.nonHideableWords').text();
  var chars = text.length;
  var arrText = text.split(' ');
  var arrLength = arrText.length;
  var timeRemaining = (((chars/5)*60)/190)*1000;
  var delay = timeRemaining/arrLength;
  forEachDelay(delay, function (text) {
    $('.txtInput').val(text).trigger('keypress');
  }, arrText);
}
<commit_msg>winTheGame()<commit_after>// Load JS Library in JS
function getScript(url,success) {
  var script=document.createElement('script');
  script.src=url;
  var head=document.getElementsByTagName('head')[0],
  done=false;script.onload=script.onreadystatechange=function(){
    if(!done&&(!this.readyState||this.readyState=='loaded'||this.readyState=='complete')){
    done=true;success();script.onload=script.onreadystatechange=null;head.removeChild(script);
    }
  };
  head.appendChild(script);
}

// Load Latest, Compressed jQuery
getScript('http://code.jquery.com/jquery-latest.min.js', function(){
  return winTheGame();
});

// Delayed Loop
var forEachDelay = function(delay, f, xs) {
  if (xs.length) {
    setTimeout(function() {
      f(xs[0]);
      forEachDelay(delay, f, xs.slice(1));
    }, delay);
  }
}

// Rek Scrubz
function winTheGame() {
  var text = $('div.nonHideableWords').text();
  var chars = text.length;
  var arrText = text.split(' ');
  var arrLength = arrText.length;
  var timeRemaining = (((chars/5)*60)/190)*1000;
  var delay = timeRemaining/arrLength;
  forEachDelay(delay, function (text) {
    $('.txtInput').val(text).trigger('keypress');
  }, arrText);
}
<|endoftext|>