text: // Generated by CoffeeScript 1.6.3
  (function() {
    var Bot, WebSocket, crypto, events, http, net, querystring;
  
    WebSocket = require('./websocket').WebSocket;
  
    events = require('events').EventEmitter;
  
    crypto = require('crypto');
  
    http = require('http');
  
    net = require('net');
  
    querystring = require('querystring');
  
    Bot = (function() {
      function Bot(auth, userId, roomId) {
        var randomHash, _ref;
        if (roomId == null) {
          roomId = null;
        }
        this.auth = auth;
        this.userId = userId;
        this.roomId = roomId;
        this.debug = false;
        this.stdout = 'stdout';
        this.callback = function() {};
        this.currentDjId = null;
        this.currentSongId = null;
        this.lastHeartbeat = Date.now();
        this.lastActivity = Date.now();
        this.clientId = Date.now() + '-0.59633534294921572';
        this.disconnectInterval = 120000;
        this.presenceInterval = 10000;
        this._msgId = 0;
        this._cmds = [];
        this._intervalId = null;
        this._isAuthenticated = false;
        this._isConnected = false;
        this.fanOf = [];
        this.currentStatus = 'available';
        this.currentSearches = [];
        if (this.roomId) {
          this.callback = function() {
            var rq;
            rq = {
              api: 'room.register',
              roomid: this.roomId
            };
            return this._send(rq, null);
          };
        }
        randomHash = crypto.createHash("sha1").update(Math.random().toString()).digest('hex').substr(0, 24);
        this.connect((_ref = this.roomId) != null ? _ref : randomHash);
      }
  
      Bot.prototype.log = function() {
        var args;
        args = Array.prototype.slice.call(arguments);
        if (typeof this.debug === 'function') {
          return this.debug.apply(this, args);
        } else if (this.debug) {
          if (this.stdout === 'stderr') {
            return console.error.apply(this, args);
          } else {
            return console.log.apply(this, args);
          }
        }
      };
  
      Bot.prototype.disconnect = function(err) {
        this._isAuthenticated = false;
        this._isConnected = false;
        if (this.listeners('disconnected').length > 0) {
          return this.emit('disconnected', err);
        } else {
          return this.emit('error', err);
        }
      };
  
      Bot.prototype.connect = function(roomId) {
        if (!/^[0-9a-f]{24}$/.test(roomId)) {
          throw new Error("Invalid roomId: cannot connect to '" + roomId + "'");
        }
        return this.whichServer(roomId, function(host, port) {
          var url,
            _this = this;
          url = "ws://" + host + ":" + port + "/socket.io/websocket";
          this.ws = new WebSocket(url);
          return this.ws.on('message', function(data) {
            return _this.onMessage(data);
          }).on('wserror', function(e) {
            return _this.disconnect(e);
          }).on('close', function() {
            return _this.onClose();
          });
        });
      };
  
      Bot.prototype.whichServer = function(roomid, callback) {
        var options,
          _this = this;
        options = {
          host: 'turntable.fm',
          port: 80,
          path: "/api/room.which_chatserver?roomid=" + roomid
        };
        return http.get(options, function(res) {
          var dataStr;
          dataStr = '';
          res.on('data', function(chunk) {
            return dataStr += chunk.toString();
          });
          return res.on('end', function() {
            var data, err, host, port, _ref;
            try {
              data = JSON.parse(dataStr);
            } catch (_error) {
              err = _error;
              data = [];
            }
            if (data[0]) {
              _ref = data[1].chatserver, host = _ref[0], port = _ref[1];
              return callback.call(_this, host, port);
            } else {
              _this.log("Failed to determine which server to use: " + dataStr);
              return _this.disconnect(new Error('Error parsing server response'));
            }
          });
        }).on('error', function(e) {
          _this.log("whichServer error: " + e);
          return _this.disconnect(e);
        });
      };
  
      Bot.prototype.setTmpSong = function(data) {
        return this.tmpSong = {
          command: 'endsong',
          room: data.room,
          success: true
        };
      };
  
      Bot.prototype.onClose = function() {};
  
      Bot.prototype.isHeartbeat = function(data) {
        var heartbeat_rgx;
        heartbeat_rgx = /~m~[0-9]+~m~(~h~[0-9]+)/;
        return data.match(heartbeat_rgx);
      };
  
      Bot.prototype.isNoSession = function(data) {
        return data === '~m~10~m~no_session';
      };
  
      Bot.prototype.treatHeartbeat = function(packet) {
        var heartbeat_rgx;
        heartbeat_rgx = /~m~[0-9]+~m~(~h~[0-9]+)/;
        this._heartbeat(packet.match(heartbeat_rgx)[1]);
        this.lastHeartbeat = Date.now();
        return this.updatePresence();
      };
  
      Bot.prototype.treatNoSession = function(packet) {
        return this.userAuthenticate(function() {
          this._isAuthenticated = true;
          if (!this._isConnected) {
            this.getFanOf(function(data) {
              this.fanOf = data.fanof;
              this.updatePresence();
              if (this._intervalId) {
                clearInterval(this._intervalId);
              }
              this._intervalId = setInterval(this.maintainPresence.bind(this), this.presenceInterval);
              return this.emit('ready');
            });
          }
          this.callback();
          return this._isConnected = true;
        });
      };
  
      Bot.prototype.maintainPresence = function() {
        var activity;
        if (this.lastHeartbeat > this.lastActivity) {
          activity = this.lastHeartbeat;
        } else {
          activity = this.lastActivity;
        }
        if (this._isConnected && (Date.now() - activity) > this.disconnectInterval) {
          this.log('No response from server; is there a proxy/firewall problem?');
          return this.disconnect(new Error('No response from server'));
        } else {
          return this.updatePresence();
        }
      };
  
      Bot.prototype.extractPacketJson = function(packet) {
        var err, len, len_rgx;
        len_rgx = /~m~([0-9]+)~m~/;
        len = packet.match(len_rgx)[1];
        try {
          return JSON.parse(packet.substr(packet.indexOf('{'), len));
        } catch (_error) {
          err = _error;
          return null;
        }
      };
  
      Bot.prototype.executeCallback = function(json) {
        var clb, currentDj, currentSong, id, index, is_search, rq, _ref, _results,
          _this = this;
        index = 0;
        _results = [];
        while (index < this._cmds.length) {
          _ref = this._cmds[index], id = _ref[0], rq = _ref[1], clb = _ref[2];
          is_search = false;
          if (id === json.msgid) {
            switch (rq.api) {
              case 'room.info':
                if (json.success === true) {
                  currentDj = json.room.metadata.current_dj;
                  currentSong = json.room.metadata.current_song;
                  if (currentDj) {
                    this.currentDjId = currentDj;
                  }
                  if (currentSong) {
                    this.currentSongId = currentSong._id;
                  }
                }
                break;
              case 'room.register':
                if (json.success === true) {
                  this.roomId = rq.roomid;
                  (function(clb) {
                    return _this.roomInfo(function(data) {
                      this.setTmpSong(data);
                      this.emit('roomChanged', data);
                      return clb != null ? clb.call(this, data) : void 0;
                    });
                  })(clb);
                } else {
                  this.emit('roomChanged', json);
                  if (clb != null) {
                    clb.call(this, json);
                  }
                }
                clb = null;
                break;
              case 'room.deregister':
                if (json.success === true) {
                  this.roomId = null;
                }
                break;
              case 'file.search':
                if (json.success === true) {
                  is_search = true;
                  this.currentSearches.push({
                    query: rq.query,
                    callback: clb
                  });
                }
            }
            if (!is_search && clb) {
              clb.call(this, json);
            }
            this._cmds.splice(index, 1);
            break;
          } else {
            _results.push(index++);
          }
        }
        return _results;
      };
  
      Bot.prototype.treatCommand = function(json) {
        var command, i, query, _i, _ref;
        command = json['command'];
        switch (command) {
          case 'nosong':
            this.currentDjId = null;
            this.currentSongId = null;
            this.emit('endsong', this.tmpSong);
            break;
          case 'newsong':
            if (this.currentSongId) {
              this.emit('endsong', this.tmpSong);
            }
            this.currentDjId = json.room.metadata.current_dj;
            this.currentSongId = json.room.metadata.current_song._id;
            this.setTmpSong(json);
            break;
          case 'update_votes':
            if (this.tmpSong) {
              this.tmpSong.room.metadata.upvotes = json.room.metadata.upvotes;
              this.tmpSong.room.metadata.downvotes = json.room.metadata.downvotes;
              this.tmpSong.room.metadata.listeners = json.room.metadata.listeners;
            }
            break;
          case 'rem_dj':
            if (json.modid) {
              this.emit('escort', json);
            }
            break;
          case 'search_complete':
            query = json['query'];
            for (i = _i = 0, _ref = this.currentSearches.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
              if (this.currentSearches[i].query === query && this.currentSearches[i].callback) {
                this.currentSearches[i].callback(json);
                this.currentSearches.splice(i, 1);
                break;
              }
            }
        }
        return this.emit(command, json);
      };
  
      Bot.prototype.treatPacket = function(packet) {
        var json;
        json = this.extractPacketJson(packet);
        this.executeCallback(json);
        return this.treatCommand(json);
      };
  
      Bot.prototype.onMessage = function(data) {
        this.emit('alive');
        if (this.isHeartbeat(data)) {
          return this.treatHeartbeat(data);
        }
        this.log("> " + data);
        if (this.isNoSession(data)) {
          return this.treatNoSession(data);
        }
        this.lastActivity = Date.now();
        return this.treatPacket(data);
      };
  
      Bot.prototype._heartbeat = function(msg) {
        return this.ws.send("~m~" + msg.length + "~m~" + msg);
      };
  
      Bot.prototype.toString = function() {
        return '';
      };
  
      Bot.prototype._send = function(rq, callback) {
        var msg;
        rq.msgid = this._msgId;
        rq.clientid = this.clientId;
        if (rq.userid == null) {
          rq.userid = this.userId;
        }
        rq.userauth = this.auth;
        msg = JSON.stringify(rq);
        this.log("< " + msg);
        if (!this._isAuthenticated && rq.api !== 'user.authenticate') {
          this.log("Bot is not ready. Can't send : '" + rq.api + "'");
          return;
        }
        this.ws.send("~m~" + msg.length + "~m~" + msg);
        this._cmds.push([this._msgId, rq, callback]);
        return this._msgId++;
      };
  
      Bot.prototype.close = function() {
        return this.ws.close();
      };
  
      Bot.prototype.listen = function(port, address) {
        var _this = this;
        return http.createServer(function(req, res) {
          var dataStr;
          dataStr = '';
          req.on('data', function(chunk) {
            return dataStr += chunk.toString();
          });
          return req.on('end', function() {
            var data;
            data = querystring.parse(dataStr);
            req._POST = data;
            return _this.emit('httpRequest', req, res);
          });
        }).listen(port, address);
      };
  
      Bot.prototype.tcpListen = function(port, address) {
        var _this = this;
        return net.createServer(function(socket) {
          socket.on('connect', function() {
            return _this.emit('tcpConnect', socket);
          });
          socket.on('data', function(data) {
            var msg;
            msg = data.toString();
            if (msg[msg.length - 1] === '\n') {
              return _this.emit('tcpMessage', socket, msg.substr(0, msg.length - 1));
            }
          });
          return socket.on('end', function() {
            return this.emit('tcpEnd', socket);
          });
        }).listen(port, address);
      };
  
      Bot.prototype.roomNow = function(callback) {
        var rq;
        rq = {
          api: 'room.now'
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.updatePresence = function(callback) {
        var rq;
        rq = {
          api: 'presence.update',
          status: this.currentStatus
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.listRooms = function(skip, sectionAware, callback) {
        var rq;
        if (skip == null) {
          skip = 0;
        }
        if (typeof sectionAware === 'function' && callback === void 0) {
          callback = sectionAware;
          sectionAware = false;
        } else if (typeof sectionAware !== 'boolean') {
          sectionAware = false;
        }
        rq = {
          api: 'room.list_rooms',
          skip: skip,
          section_aware: sectionAware
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.searchRooms = function(options, callback) {
        var rq, _ref;
        if (typeof options !== 'object') {
          callback = options;
          options = {};
        }
        rq = {
          api: 'room.search',
          limit: (_ref = options.limit) != null ? _ref : 10
        };
        if (options.query) {
          rq.query = options.query;
        }
        return this._send(rq, callback);
      };
  
      Bot.prototype.directoryGraph = function(callback) {
        var rq;
        rq = {
          api: 'room.directory_graph'
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.directoryRooms = function(options, callback) {
        var httpOptions, opt, query, val,
          _this = this;
        if (typeof options !== 'object') {
          callback = options;
          options = {};
        }
        options.client = 'web';
        query = [];
        for (opt in options) {
          val = options[opt];
          query.push("" + opt + "=" + (encodeURIComponent(val)));
        }
        httpOptions = {
          host: 'turntable.fm',
          port: 80,
          path: '/api/room.directory_rooms?' + query.join("&")
        };
        return http.get(httpOptions, function(res) {
          var dataStr;
          dataStr = '';
          res.on('data', function(chunk) {
            return dataStr += chunk.toString();
          });
          return res.on('end', function() {
            var data, err;
            try {
              data = JSON.parse(dataStr);
            } catch (_error) {
              err = _error;
              data = [];
            }
            return callback.call(_this, data);
          });
        });
      };
  
      Bot.prototype.stalk = function() {
        var allInfos, callback, getGraph, userId,
          _this = this;
        userId = '';
        allInfos = false;
        callback = function() {};
        switch (arguments.length) {
          case 2:
            userId = arguments[0];
            callback = arguments[1];
            break;
          case 3:
            userId = arguments[0];
            allInfos = arguments[1];
            callback = arguments[2];
        }
        getGraph = function() {
          return _this.directoryGraph(function(directoryGraphData) {
            var graphObj, room, user, users, _i, _j, _len, _len1, _ref;
            if (!directoryGraphData.success) {
              return callback(directoryGraphData);
            }
            _ref = directoryGraphData.rooms;
            for (_i = 0, _len = _ref.length; _i < _len; _i++) {
              graphObj = _ref[_i];
              room = graphObj[0];
              users = graphObj[1];
              for (_j = 0, _len1 = users.length; _j < _len1; _j++) {
                user = users[_j];
                if (user.userid === userId) {
                  if (allInfos) {
                    return callback({
                      roomId: room.roomid,
                      room: room
                    }, {
                      user: user,
                      success: true
                    });
                  } else {
                    return callback({
                      roomId: room.roomid,
                      success: true
                    });
                  }
                }
              }
            }
            return callback({
              err: 'userId not found.',
              success: false
            });
          });
        };
        if (this.fanOf.indexOf(userId) !== -1) {
          return getGraph();
        } else {
          return this.becomeFan(userId, function(becomeFanData) {
            if (!becomeFanData.success) {
              if (becomeFanData.err !== 'User is already a fan') {
                return callback(becomeFanData);
              }
            }
            return getGraph();
          });
        }
      };
  
      Bot.prototype.getFavorites = function(callback) {
        var rq;
        rq = {
          api: 'room.get_favorites'
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.addFavorite = function(roomId, callback) {
        var rq;
        rq = {
          api: 'room.add_favorite',
          roomid: roomId
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.remFavorite = function(roomId, callback) {
        var rq;
        rq = {
          api: 'room.rem_favorite',
          roomid: roomId
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.roomVerify = function(roomId, callback) {
        var rq;
        rq = {
          api: 'room.info',
          roomid: roomId
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.roomRegister = function(roomId, callback) {
        if (this.ws) {
          this.ws.removeAllListeners('message');
          this.ws.removeAllListeners('wserror');
          this.ws.removeAllListeners('close');
          this.ws.close();
        }
        this.callback = function() {
          var rq;
          rq = {
            api: 'room.register',
            roomid: roomId
          };
          return this._send(rq, callback);
        };
        return this.connect(roomId);
      };
  
      Bot.prototype.roomDeregister = function(callback) {
        var rq;
        rq = {
          api: 'room.deregister',
          roomid: this.roomId
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.roomInfo = function() {
        var callback, rq;
        rq = {
          api: 'room.info',
          roomid: this.roomId
        };
        callback = null;
        if (arguments.length === 1) {
          if (typeof arguments[0] === 'function') {
            callback = arguments[0];
          } else if (arguments[0] === 'boolean') {
            rq.extended = arguments[0];
          }
        } else if (arguments.length === 2) {
          rq.extended = arguments[0];
          callback = arguments[1];
        }
        return this._send(rq, callback);
      };
  
      Bot.prototype.speak = function(msg, callback) {
        var rq;
        rq = {
          api: 'room.speak',
          roomid: this.roomId,
          text: msg.toString()
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.pm = function(msg, userid, callback) {
        var rq;
        rq = {
          api: 'pm.send',
          receiverid: userid,
          text: msg.toString()
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.pmHistory = function(userid, callback) {
        var rq;
        rq = {
          api: 'pm.history',
          receiverid: userid
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.bootUser = function(userId, reason, callback) {
        var rq;
        rq = {
          api: 'room.boot_user',
          roomid: this.roomId,
          target_userid: userId,
          reason: reason
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.boot = function() {
        return this.bootUser.apply(this, arguments);
      };
  
      Bot.prototype.addModerator = function(userId, callback) {
        var rq;
        rq = {
          api: 'room.add_moderator',
          roomid: this.roomId,
          target_userid: userId
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.remModerator = function(userId, callback) {
        var rq;
        rq = {
          api: 'room.rem_moderator',
          roomid: this.roomId,
          target_userid: userId
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.addDj = function(callback) {
        var rq;
        rq = {
          api: 'room.add_dj',
          roomid: this.roomId
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.remDj = function() {
        var callback, djId, rq;
        if (arguments.length === 1) {
          if (typeof arguments[0] === 'function') {
            djId = null;
            callback = arguments[0];
          } else if (typeof arguments[0] === 'string') {
            djId = arguments[0];
            callback = null;
          }
        } else if (arguments.length === 2) {
          djId = arguments[0];
          callback = arguments[1];
        }
        rq = {
          api: 'room.rem_dj',
          roomid: this.roomId
        };
        if (djId) {
          rq.djid = djId;
        }
        return this._send(rq, callback);
      };
  
      Bot.prototype.stopSong = function(callback) {
        var rq;
        rq = {
          api: 'room.stop_song',
          roomid: this.roomId,
          current_song: this.currentSongId
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.skip = function() {
        return this.stopSong.apply(this, arguments);
      };
  
      Bot.prototype.snag = function(callback) {
        var fh, i, rq, sh, vh;
        sh = crypto.createHash("sha1").update(Math.random().toString()).digest('hex');
        fh = crypto.createHash("sha1").update(Math.random().toString()).digest('hex');
        i = [this.userId, this.currentDjId, this.currentSongId, this.roomId, 'queue', 'board', 'false', 'false', sh];
        vh = crypto.createHash("sha1").update(i.join('/')).digest('hex');
        rq = {
          api: 'snag.add',
          djid: this.currentDjId,
          songid: this.currentSongId,
          roomid: this.roomId,
          site: 'queue',
          location: 'board',
          in_queue: 'false',
          blocked: 'false',
          vh: vh,
          sh: sh,
          fh: fh
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.vote = function(val, callback) {
        var ph, rq, th, vh, _ref, _ref1;
        val = (_ref = arguments[0]) != null ? _ref : 'up';
        callback = (_ref1 = arguments[1]) != null ? _ref1 : null;
        vh = crypto.createHash("sha1").update(this.roomId + val + this.currentSongId).digest('hex');
        th = crypto.createHash("sha1").update(Math.random().toString()).digest('hex');
        ph = crypto.createHash("sha1").update(Math.random().toString()).digest('hex');
        rq = {
          api: 'room.vote',
          roomid: this.roomId,
          val: val,
          vh: vh,
          th: th,
          ph: ph
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.bop = function() {
        var args;
        args = Array.prototype.slice.call(arguments);
        args.unshift('up');
        return this.vote.apply(this, args);
      };
  
      Bot.prototype.userAuthenticate = function(callback) {
        var rq;
        rq = {
          api: 'user.authenticate'
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.userInfo = function(callback) {
        var rq;
        rq = {
          api: 'user.info'
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.userAvailableAvatars = function(callback) {
        var rq;
        rq = {
          api: 'user.available_avatars'
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.getAvatarIds = function(callback) {
        return this.userInfo(function(userInfos) {
          var acl, points, _ref, _ref1;
          points = (_ref = userInfos.points) != null ? _ref : -1;
          acl = (_ref1 = userInfos.acl) != null ? _ref1 : 0;
          return this.userAvailableAvatars(function(avatars) {
            var avatar, id, res, _i, _j, _len, _len1, _ref2, _ref3;
            res = [];
            _ref2 = avatars.avatars;
            for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
              avatar = _ref2[_i];
              if (points >= avatar.min) {
                if (avatar.acl && acl < avatar.acl) {
                  continue;
                }
                _ref3 = avatar.avatarids;
                for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) {
                  id = _ref3[_j];
                  if (res.indexOf(id) === -1) {
                    res.push(id);
                  }
                }
              }
            }
            return callback({
              ids: res,
              success: true
            });
          });
        });
      };
  
      Bot.prototype.getFanOf = function() {
        var callback, rq;
        rq = {
          api: 'user.get_fan_of'
        };
        callback = null;
        if (arguments.length === 1) {
          if (typeof arguments[0] === 'function') {
            callback = arguments[0];
          } else if (typeof arguments[0] === 'string') {
            rq.userid = arguments[0];
          }
        } else if (arguments.length === 2) {
          rq.userid = arguments[0];
          callback = arguments[1];
        }
        return this._send(rq, callback);
      };
  
      Bot.prototype.getFans = function() {
        var callback, rq;
        rq = {
          api: 'user.get_fans'
        };
        callback = null;
        if (arguments.length === 1) {
          if (typeof arguments[0] === 'function') {
            callback = arguments[0];
          } else if (typeof arguments[0] === 'string') {
            rq.userid = arguments[0];
          }
        } else if (arguments.length === 2) {
          rq.userid = arguments[0];
          callback = arguments[1];
        }
        return this._send(rq, callback);
      };
  
      Bot.prototype.getUserId = function(name, callback) {
        var rq;
        rq = {
          api: 'user.get_id',
          name: name.toString()
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.getPresence = function() {
        var callback, rq;
        rq = {
          api: 'presence.get'
        };
        callback = null;
        if (arguments.length === 1) {
          if (typeof arguments[0] === 'function') {
            rq.uid = this.userId;
            callback = arguments[0];
          } else if (typeof arguments[0] === 'string') {
            rq.uid = arguments[0];
          }
        } else if (arguments.length === 2) {
          rq.uid = arguments[0];
          callback = arguments[1];
        }
        return this._send(rq, callback);
      };
  
      Bot.prototype.getProfile = function() {
        var callback, rq;
        rq = {
          api: 'user.get_profile_info'
        };
        callback = null;
        if (arguments.length === 1) {
          if (typeof arguments[0] === 'function') {
            rq.profileid = this.userId;
            callback = arguments[0];
          } else if (typeof arguments[0] === 'string') {
            rq.profileid = arguments[0];
          }
        } else if (arguments.length === 2) {
          rq.profileid = arguments[0];
          callback = arguments[1];
        }
        return this._send(rq, callback);
      };
  
      Bot.prototype.modifyProfile = function(profile, callback) {
        var rq;
        rq = {
          api: 'user.modify_profile'
        };
        if (profile.name) {
          rq.name = profile.name;
        }
        if (profile.twitter) {
          rq.twitter = profile.twitter;
        }
        if (profile.soundcloud) {
          rq.soundcloud = profile.soundcloud;
        }
        if (profile.facebook) {
          rq.facebook = profile.facebook;
        }
        if (profile.website) {
          rq.website = profile.website;
        }
        if (profile.about) {
          rq.about = profile.about;
        }
        if (profile.topartists) {
          rq.topartists = profile.topartists;
        }
        if (profile.hangout) {
          rq.hangout = profile.hangout;
        }
        return this._send(rq, callback);
      };
  
      Bot.prototype.modifyLaptop = function(laptop, callback) {
        var rq;
        laptop = laptop != null ? laptop : 'linux';
        rq = {
          api: 'user.modify',
          laptop: laptop
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.modifyName = function(name, callback) {
        var rq;
        rq = {
          api: 'user.modify',
          name: name
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.setAvatar = function(avatarId, callback) {
        var rq;
        rq = {
          api: 'user.set_avatar',
          avatarid: avatarId
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.becomeFan = function(userId, callback) {
        var rq;
        rq = {
          api: 'user.become_fan',
          djid: userId
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.removeFan = function(userId, callback) {
        var rq;
        rq = {
          api: 'user.remove_fan',
          djid: userId
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.playlistListAll = function(callback) {
        var rq;
        rq = {
          api: 'playlist.list_all'
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.playlistCreate = function(playlistName, callback) {
        var rq;
        rq = {
          api: 'playlist.create',
          playlist_name: playlistName
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.playlistDelete = function(playlistName, callback) {
        var rq;
        rq = {
          api: 'playlist.delete',
          playlist_name: playlistName
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.playlistRename = function(oldPlaylistName, newPlaylistName, callback) {
        var rq;
        rq = {
          api: 'playlist.rename',
          old_playlist_name: oldPlaylistName,
          new_playlist_name: newPlaylistName
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.playlistSwitch = function(playlistName, callback) {
        var rq;
        rq = {
          api: 'playlist.switch',
          playlist_name: playlistName
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.playlistNewBlockedSongCount = function(callback) {
        var rq;
        rq = {
          api: 'playlist.new_blocked_song_count'
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.playlistAll = function() {
        var callback, playlistName, rq;
        playlistName = 'default';
        callback = null;
        switch (arguments.length) {
          case 1:
            if (typeof arguments[0] === 'string') {
              playlistName = arguments[0];
            } else if (typeof arguments[0] === 'function') {
              callback = arguments[0];
            }
            break;
          case 2:
            playlistName = arguments[0];
            callback = arguments[1];
        }
        rq = {
          api: 'playlist.all',
          playlist_name: playlistName
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.playlistAdd = function() {
        var callback, index, playlistName, rq, songId;
        playlistName = 'default';
        songId = null;
        index = 0;
        callback = null;
        switch (arguments.length) {
          case 1:
            songId = arguments[0];
            break;
          case 2:
            if (typeof arguments[0] === 'string' && typeof arguments[1] === 'string') {
              playlistName = arguments[0];
              songId = arguments[1];
            } else if (typeof arguments[0] === 'string' && typeof arguments[1] === 'function') {
              songId = arguments[0];
              callback = arguments[1];
            } else if (typeof arguments[0] === 'string' && typeof arguments[1] === 'number') {
              songId = arguments[0];
              index = arguments[1];
            } else if (typeof arguments[0] === 'boolean' && typeof arguments[1] === 'string') {
              songId = arguments[1];
            }
            break;
          case 3:
            if (typeof arguments[0] === 'string' && typeof arguments[1] === 'string' && typeof arguments[2] === 'number') {
              playlistName = arguments[0];
              songId = arguments[1];
              index = arguments[2];
            } else if (typeof arguments[0] === 'string' && typeof arguments[1] === 'string' && typeof arguments[2] === 'function') {
              playlistName = arguments[0];
              songId = arguments[1];
              callback = arguments[2];
            } else if (typeof arguments[0] === 'string' && typeof arguments[1] === 'number' && typeof arguments[2] === 'function') {
              songId = arguments[0];
              index = arguments[1];
              callback = arguments[2];
            } else if (typeof arguments[0] === 'boolean' && typeof arguments[1] === 'string' && typeof arguments[2] === 'function') {
              songId = arguments[1];
              callback = arguments[2];
            }
            break;
          case 4:
            playlistName = arguments[0];
            songId = arguments[1];
            index = arguments[2];
            callback = arguments[3];
        }
        rq = {
          api: 'playlist.add',
          playlist_name: playlistName,
          song_dict: {
            fileid: songId
          },
          index: index
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.playlistRemove = function() {
        var callback, index, playlistName, rq;
        playlistName = 'default';
        index = 0;
        callback = null;
        switch (arguments.length) {
          case 1:
            index = arguments[0];
            break;
          case 2:
            if (typeof arguments[0] === 'string' && typeof arguments[1] === 'number') {
              playlistName = arguments[0];
              index = arguments[1];
            } else if (typeof arguments[0] === 'number' && typeof arguments[1] === 'function') {
              index = arguments[0];
              callback = arguments[1];
            }
            break;
          case 3:
            playlistName = arguments[0];
            index = arguments[1];
            callback = arguments[2];
        }
        rq = {
          api: 'playlist.remove',
          playlist_name: playlistName,
          index: index
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.playlistReorder = function() {
        var callback, indexFrom, indexTo, playlistName, rq;
        playlistName = 'default';
        indexFrom = 0;
        indexTo = 0;
        callback = null;
        switch (arguments.length) {
          case 2:
            indexFrom = arguments[0];
            indexTo = arguments[1];
            break;
          case 3:
            if (typeof arguments[0] === 'string' && typeof arguments[1] === 'number' && typeof arguments[2] === 'number') {
              playlistName = arguments[0];
              indexFrom = arguments[1];
              indexTo = arguments[2];
            } else if (typeof arguments[0] === 'number' && typeof arguments[1] === 'number' && typeof arguments[2] === 'function') {
              indexFrom = arguments[0];
              indexTo = arguments[1];
              callback = arguments[2];
            }
            break;
          case 4:
            playlistName = arguments[0];
            indexFrom = arguments[1];
            indexTo = arguments[2];
            callback = arguments[3];
        }
        rq = {
          api: 'playlist.reorder',
          playlist_name: playlistName,
          index_from: indexFrom,
          index_to: indexTo
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.setStatus = function(status, callback) {
        this.currentStatus = status;
        this.updatePresence();
        if (callback) {
          return callback({
            success: true
          });
        }
      };
  
      Bot.prototype.searchSong = function(query, callback) {
        var rq;
        rq = {
          api: 'file.search',
          query: query
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.getStickers = function(callback) {
        var rq;
        rq = {
          api: 'sticker.get'
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.getStickerPlacements = function(userid, callback) {
        var rq;
        rq = {
          api: 'sticker.get_placements',
          userid: userid
        };
        return this._send(rq, callback);
      };
  
      Bot.prototype.placeStickers = function(placements, callback) {
        var rq;
        rq = {
          api: 'sticker.place',
          placements: placements,
          is_dj: true,
          roomid: this.roomId
        };
        return this._send(rq, callback);
      };
  
      return Bot;
  
    })();
  
    Bot.prototype.__proto__ = events.prototype;
  
    exports.Bot = Bot;
  
  }).call(this);
  