<commit_before>var inherits = require('inherits')
  , fs = require('fs')
  , path = require('path')
  , MeatBot = require('meatbot')
  , yoplait = require('yoplait')

inherits(MeatYo, MeatBot)
function MeatYo(yoUser) {
  MeatBot.call(this)
  this.yoUser = yoUser
}

MeatYo.prototype.name = ' '
MeatYo.prototype.fingerprint = 'meatyo'

MeatYo.prototype.respond = function(msg, cb) {
  process.nextTick(cb)
}

var errorPics = []
  , successPics = []
function loadImages() {
  var URI_PREFIX = 'data:image/gif;base64,'

  var errorDir = path.join(__dirname, 'gifs', 'failure')
    , successDir = path.join(__dirname, 'gifs', 'success')

  var errorFiles = fs.readdirSync(errorDir)
    , successFiles = fs.readdirSync(successDir)

  errorPics = errorFiles.filter(gifFilter).map(function(filename) {
    return URI_PREFIX + fs.readFileSync(path.join(errorDir, filename), { encoding: 'base64' })
  })
  successPics = successFiles.filter(gifFilter).map(function(filename) {
    return URI_PREFIX + fs.readFileSync(path.join(successDir, filename), { encoding: 'base64' })
  })

  console.log('Loaded ' + successPics.length + ' success gifs, ' +
    errorPics.length + ' failure gifs.')

  function gifFilter(elem) {
    return /\.gif$/i.test(elem)
  }
}

function getErrorPic() {
  return errorPics[(Math.random() * errorPics.length) | 0]
}

function getSuccessPic() {
  return successPics[(Math.random() * successPics.length) | 0]
}

loadImages()

yoplait.existingUser('MEATSPAC', '4d45415453504143', function(err, yoUser) {
  if (err) {
    return console.log('error registering yo install: ', err)
  }

  console.log('Yo install registered.')

  var bot = new MeatYo(yoUser)

  bot.on('message', function(msg) {
    var match = /^\s*!yo ([a-z0-9]+)/i.exec(msg.message)
    if (!match || match[1] === undefined) {
      return
    }

    var user = match[1].toUpperCase()
      , self = this
    console.log('=> yoing ' + user)
    yoUser.sendYo(user, yoBack)

    function yoBack(err) {
      if (!err) {
        return self.sendMessage(getSuccessPic(), 'YO ' + user + '!', messageCb)
      }

      var errorMessage =
        err.serverCode ? (err.serverCode + ' ' + err.serverError) : JSON.stringify(err)

      self.sendMessage(getErrorPic(), 'Yoing failed yo: ' + errorMessage, messageCb)
      console.log('yoing failed: ',  err)
    }

    function messageCb(err) {
      if (err) {
        console.log('Error sending meatspace message: ', err)
      }
    }
  })

  bot.on('connect', function() {
    console.log('Connected.')
  }).on('disconnect', function() {
    console.log('Disconnected.')
  })

  bot.connect()
})

<commit_msg>Add a specifiable number of times to Yo someone.<commit_after>var inherits = require('inherits')
  , fs = require('fs')
  , path = require('path')
  , MeatBot = require('meatbot')
  , yoplait = require('yoplait')

inherits(MeatYo, MeatBot)
function MeatYo(yoUser) {
  MeatBot.call(this)
  this.yoUser = yoUser
}

MeatYo.prototype.name = ' '
MeatYo.prototype.fingerprint = 'meatyo'

MeatYo.prototype.respond = function(msg, cb) {
  process.nextTick(cb)
}

var errorPics = []
  , successPics = []
function loadImages() {
  var URI_PREFIX = 'data:image/gif;base64,'

  var errorDir = path.join(__dirname, 'gifs', 'failure')
    , successDir = path.join(__dirname, 'gifs', 'success')

  var errorFiles = fs.readdirSync(errorDir)
    , successFiles = fs.readdirSync(successDir)

  errorPics = errorFiles.filter(gifFilter).map(function(filename) {
    return URI_PREFIX + fs.readFileSync(path.join(errorDir, filename), { encoding: 'base64' })
  })
  successPics = successFiles.filter(gifFilter).map(function(filename) {
    return URI_PREFIX + fs.readFileSync(path.join(successDir, filename), { encoding: 'base64' })
  })

  console.log('Loaded ' + successPics.length + ' success gifs, ' +
    errorPics.length + ' failure gifs.')

  function gifFilter(elem) {
    return /\.gif$/i.test(elem)
  }
}

function getErrorPic() {
  return errorPics[(Math.random() * errorPics.length) | 0]
}

function getSuccessPic() {
  return successPics[(Math.random() * successPics.length) | 0]
}

loadImages()

yoplait.existingUser('MEATSPAC', '4d45415453504143', function(err, yoUser) {
  if (err) {
    return console.log('error registering yo install: ', err)
  }

  console.log('Yo install registered.')

  var bot = new MeatYo(yoUser)

  bot.on('message', function(msg) {
    var match = matchMessage(msg.message)
    if (!match) {
      return
    }

    console.log('=> yoing ' + match.target + ' ' + match.times + ' times')
    sendYos(yoUser, bot, match.target, match.times, yoBack)

    function yoBack(err) {
      if (!err) {
        var message = 'YO' + (match.times > 1 ? ('x' + match.times + ' ') : ' ') +
          match.target + '!'
        return bot.sendMessage(getSuccessPic(), message, messageCb)
      }

      var errorMessage =
        err.serverCode ? (err.serverCode + ' ' + err.serverError) : JSON.stringify(err)

      bot.sendMessage(getErrorPic(), 'Yoing failed yo: ' + errorMessage, messageCb)
      console.log('yoing failed: ',  err)
    }

    function messageCb(err) {
      if (err) {
        console.log('Error sending meatspace message: ', err)
      }
    }
  })

  bot.on('connect', function() {
    console.log('Connected.')
  }).on('disconnect', function() {
    console.log('Disconnected.')
  })

  bot.connect()
})

function matchMessage(msg) {
  var msgParts = msg.toUpperCase().split(/\s+/)
    , isYo = false
    , i
  for (i = 0; i < msgParts.length; i++) {
    if (msgParts[i] == '!YO') {
      isYo = true
      break
    }
  }

  i++
  if (!isYo || i >= msgParts.length) {
    return null
  }

  var target = msgParts[i]
  if (!/[A-Z0-9]/.test(target)) {
    return null
  }

  i++
  if (i >= msgParts.length) {
    return { target: target, times: 1 }
  }

  var times = +msgParts[i]
  if (isNaN(times)) {
    times = 1
  }
  times = Math.max(Math.min(times, 20), 1)

  return { target: target, times: times }
}

var MAX_REQS_OUT = 10
function sendYos(yoUser, bot, target, times, cb) {
  var firstError
    , outstanding = 0
    , left = times
    , successful = 0
    , completed = false

  function sendReqs() {
    while (outstanding < MAX_REQS_OUT && left > 0) {
      yoUser.sendYo(target, yoBack)
      outstanding++
      left--
    }
  }

  function yoBack(err) {
    if (completed) {
      return
    }

    outstanding--
    if (err) {
      if (!firstError) {
        firstError = err
      }
    } else {
      successful++
    }

    if (left && !isPermanentError()) {
      sendReqs()
    } else if (isPermanentError() || (!left && !outstanding)) {
      done()
    }
  }

  function isPermanentError() {
    return firstError && firstError.serverCode == 141 && firstError.serverError == 'NO SUCH USER'
  }

  function done() {
    completed = true
    if (successful) {
      cb(null)
    } else {
      cb(firstError)
    }
  }

  sendReqs()
}
{'fraction_non_alphanumeric': 0.15587980352499278, 'fraction_numerical': 0.009679283444091302, 'mean_word_length': 3.098875074008289, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5666937', 'n_tokens_mistral': 2519, 'n_tokens_neox': 2386, 'n_words': 479}