Guest User

Untitled

a guest
Aug 19th, 2017
359
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. (function discordio(Discord){
  2. "use strict";
  3. var isNode = typeof(window) === "undefined" && typeof(navigator) === "undefined";
  4. var CURRENT_VERSION = "2.x.x",
  5.     GATEWAY_VERSION = 5,
  6.     LARGE_THRESHOLD = 250,
  7.     CONNECT_WHEN = null,
  8.     Endpoints;
  9.  
  10. if (isNode) {
  11.     var Util        = require('util'),
  12.         FS          = require('fs'),
  13.         UDP         = require('dgram'),
  14.         Zlib        = require('zlib'),
  15.         DNS         = require('dns'),
  16.         Stream      = require('stream'),
  17.         BN          = require('path').basename,
  18.         EE          = require('events').EventEmitter,
  19.         requesters  = {
  20.             http:     require('http'),
  21.             https:    require('https')
  22.         },
  23.         ChildProc   = require('child_process'),
  24.         URL         = require('url'),
  25.         //NPM Modules
  26.         NACL        = require('tweetnacl'),
  27.         Opus        = null
  28. }
  29.  
  30. /* --- Version Check --- */
  31. try {
  32.     CURRENT_VERSION = require('../package.json').version;
  33. } catch(e) {}
  34. if (!isNode) CURRENT_VERSION = CURRENT_VERSION + "-browser";
  35.  
  36. /**
  37.  * Discord Client constructor
  38.  * @class
  39.  * @arg {Object} options
  40.  * @arg {String} options.token - The token of the account you wish to log in with.
  41.  * @arg {Boolean} [options.autorun] - If true, the client runs when constructed without calling `.connect()`.
  42.  * @arg {Number} [options.messageCacheLimit] - The amount of messages to cache in memory, per channel. Used for information on deleted/updated messages. The default is 50.
  43.  * @arg {Array<Number>} [options.shard] - The shard array. The first index is the current shard ID, the second is the amount of shards that should be running.
  44.  */
  45. Discord.Client = function DiscordClient(options) {
  46.     if (!isNode) Emitter.call(this);
  47.     if (!options || options.constructor.name !== 'Object') return console.error("An Object is required to create the discord.io client.");
  48.     if (typeof(options.messageCacheLimit) !== 'number') options.messageCacheLimit = 50;
  49.  
  50.     applyProperties(this, [
  51.         ["_ws", null],
  52.         ["_uIDToDM", {}],
  53.         ["_vChannels", {}],
  54.         ["_messageCache", {}],
  55.         ["_connecting", false],
  56.         ["_mainKeepAlive", null],
  57.         ["_req", APIRequest.bind(this)],
  58.         ["_messageCacheLimit", options.messageCacheLimit],
  59.     ]);
  60.  
  61.     this.presenceStatus = "offline";
  62.     this.connected = false;
  63.     this.inviteURL = null;
  64.     this.connect = this.connect.bind(this, options);
  65.  
  66.     if (options.autorun === true) {
  67.         this.connect();
  68.     }
  69. };
  70. if (isNode) Emitter.call(Discord.Client);
  71.  
  72. /* - DiscordClient - Methods - */
  73. var DCP = Discord.Client.prototype;
  74. /**
  75.  * Manually initiate the WebSocket connection to Discord.
  76.  */
  77. DCP.connect = function() {
  78.     if (!this.connected && !this._connecting) return setTimeout(
  79.         init,
  80.         Math.max(0, CONNECT_WHEN - Date.now()),
  81.         this,
  82.         arguments[0],
  83.         void( CONNECT_WHEN = Math.max(CONNECT_WHEN, Date.now()) + 6000 )
  84.     );
  85. };
  86.  
  87. /**
  88.  * Disconnect the WebSocket connection to Discord.
  89.  */
  90. DCP.disconnect = function() {
  91.     if (this._ws) this._ws.close();
  92. };
  93.  
  94. /**
  95.  * Retrieve a user object from Discord, Bot only endpoint. You don't have to share a server with this user.
  96.  * @arg {Object} input
  97.  * @arg {Snowflake} input.userID
  98.  */
  99. DCP.getUser = function(input, callback) {
  100.     if (!this.bot) return handleErrCB("[getUser] This account is a 'user' type account, and cannot use 'getUser'. Only bots can use this endpoint.", callback);
  101.     this._req('get', Endpoints.USER(input.userID), function(err, res) {
  102.         handleResCB("Could not get user", err, res, callback);
  103.     });
  104. }
  105.  
  106. /**
  107.  * Edit the client's user information.
  108.  * @arg {Object} input
  109.  * @arg {String<Base64>} input.avatar - The last part of a Base64 Data URI. `fs.readFileSync('image.jpg', 'base64')` is enough.
  110.  * @arg {String} input.username - A username.
  111.  * @arg {String} input.email - [User only] An email.
  112.  * @arg {String} input.password - [User only] Your current password.
  113.  * @arg {String} input.new_password - [User only] A new password.
  114.  */
  115. DCP.editUserInfo = function(input, callback) {
  116.     var payload = {
  117.         avatar: this.avatar,
  118.         email: this.email,
  119.         new_password: null,
  120.         password: null,
  121.         username: this.username
  122.     },
  123.         plArr = Object.keys(payload);
  124.  
  125.     for (var key in input) {
  126.         if (plArr.indexOf(key) < 0) return handleErrCB(("[editUserInfo] '" + key + "' is not a valid key. Valid keys are: " + plArr.join(", ")), callback);
  127.         payload[key] = input[key];
  128.     }
  129.     if (input.avatar) payload.avatar = "data:image/jpg;base64," + input.avatar;
  130.  
  131.     this._req('patch', Endpoints.ME, payload, function(err, res) {
  132.         handleResCB("Unable to edit user information", err, res, callback);
  133.     });
  134. };
  135.  
  136. /**
  137.  * Change the client's presence.
  138.  * @arg {Object} input
  139.  * @arg {Number|null} input.idle_since - Use a Number before the current point in time.
  140.  * @arg {Object|null} input.game - Used to set game information.
  141.  * @arg {String|null} input.game.name - The name of the game.
  142.  * @arg {Number|null} input.game.type - Streaming activity, 0 for nothing, 1 for Twitch.
  143.  * @arg {String|null} input.game.url - A URL matching the streaming service you've selected.
  144.  */
  145. DCP.setPresence = function(input) {
  146.     var payload = {
  147.         op: 3,
  148.         d: {
  149.             idle_since: input.idle_since || null,
  150.             game: type(input.game) === 'object' ?
  151.                     {
  152.                         name: input.game.name ? String(input.game.name) : null,
  153.                         type: input.game.type ? Number(input.game.type) : null,
  154.                         url: input.game.url ? String(input.game.url) : null
  155.  
  156.                     } :
  157.                     null
  158.         }
  159.     };
  160.  
  161.     send(this._ws, payload);
  162.  
  163.     if (payload.d.idle_since === null) {
  164.         this.presenceStatus = 'online';
  165.         return;
  166.     }
  167.     this.presenceStatus = 'idle';
  168. };
  169.  
  170. /**
  171.  * Receive OAuth information for the current client.
  172.  */
  173. DCP.getOauthInfo = function(callback) {
  174.     this._req('get', Endpoints.OAUTH, function(err, res) {
  175.         handleResCB("Error GETing OAuth information", err, res, callback);
  176.     });
  177. };
  178.  
  179. /**
  180.  * Receive account settings information for the current client.
  181.  */
  182. DCP.getAccountSettings = function(callback) {
  183.     this._req('get', Endpoints.SETTINGS, function(err, res) {
  184.         handleResCB("Error GETing client settings", err, res, callback);
  185.     });
  186. };
  187.  
  188. /* - DiscordClient - Methods - Content - */
  189.  
  190. /**
  191.  * Upload a file to a channel.
  192.  * @arg {Object} input
  193.  * @arg {Snowflake} input.to - The target Channel or User ID.
  194.  * @arg {Buffer|String} input.file - A Buffer containing the file data, or a String that's a path to the file.
  195.  * @arg {String|null} input.filename - A filename for the uploaded file, required if you provide a Buffer.
  196.  * @arg {String|null} input.message - An optional message to provide.
  197.  */
  198. DCP.uploadFile = function(input, callback) {
  199.     /* After like 15 minutes of fighting with Request, turns out Discord doesn't allow multiple files in one message...
  200.     despite having an attachments array.*/
  201.     var file,
  202.         client = this, multi = new Multipart(), message = generateMessage(input.message || ""),
  203.         isBuffer = (input.file instanceof Buffer), isString = (type(input.file) === 'string');
  204.  
  205.     if (!isBuffer && !isString) return handleErrCB("[uploadFile] uploadFile requires a String or Buffer as the 'file' value", callback);
  206.     if (isBuffer) if (input.filename) file = input.file; else return handleErrCB("[uploadFile] uploadFile requires a 'filename' value to be set if using a Buffer", callback);
  207.     if (isString) try { file = FS.readFileSync(input.file); } catch(e) { return handleErrCB("[uploadFile] File does not exist: " + input.file, callback); }
  208.  
  209.     [
  210.         ["content", message.content],
  211.         ["mentions", ""],
  212.         ["tts", false],
  213.         ["nonce", message.nonce],
  214.         ["file", file, input.filename || BN(input.file)]
  215.     ].forEach(function(a) {
  216.         multi.append(a);
  217.     });
  218.     multi.finalize();
  219.     /*multi.append(["content", message.content]);
  220.     multi.append(["mentions", ""]);
  221.     multi.append(["tts", false]);
  222.     multi.append(["nonce", message.nonce]);
  223.     multi.append(["file", file, input.filename || BN(input.file)]);*/
  224.  
  225.     resolveID(client, input.to, function(channelID) {
  226.         client._req('post', Endpoints.MESSAGES(channelID), multi, function(err, res) {
  227.             handleResCB("Unable to upload file", err, res, callback);
  228.         });
  229.     });
  230. };
  231. /**
  232.  * Send a message to a channel.
  233.  * @arg {Object} input
  234.  * @arg {Snowflake} input.to - The target Channel or User ID.
  235.  * @arg {String} input.message - The message content.
  236.  * @arg {Object} [input.embed] - An embed object to include
  237.  * @arg {Boolean} [input.tts] - Enable Text-to-Speech for this message.
  238.  * @arg {Number} [input.nonce] - Number-used-only-ONCE. The Discord client uses this to change the message color from grey to white.
  239.  * @arg {Boolean} [input.typing] - Indicates whether the message should be sent with simulated typing. Based on message length.
  240.  */
  241. DCP.sendMessage = function(input, callback) {
  242.     var message = generateMessage(input.message || '', input.embed);
  243.     message.tts = (input.tts === true);
  244.     message.nonce = input.nonce || message.nonce;
  245.  
  246.     if (input.typing === true) {
  247.         return simulateTyping(
  248.             this,
  249.             input.to,
  250.             message,
  251.             ( (message.content.length * 0.12) * 1000 ),
  252.             callback
  253.         );
  254.     }
  255.  
  256.     sendMessage(this, input.to, message, callback);
  257. };
  258.  
  259. /**
  260.  * Pull a message object from Discord.
  261.  * @arg {Object} input
  262.  * @arg {Snowflake} input.channelID - The channel ID that the message is from.
  263.  * @arg {Snowflake} input.messageID - The ID of the message.
  264.  */
  265. DCP.getMessage = function(input, callback) {
  266.     this._req('get', Endpoints.MESSAGES(input.channelID, input.messageID), function(err, res) {
  267.         handleResCB("Unable to get message", err, res, callback);
  268.     });
  269. };
  270.  
  271. /**
  272.  * Pull an array of message objects from Discord.
  273.  * @arg {Object} input
  274.  * @arg {Snowflake} input.channelID - The channel ID to pull the messages from.
  275.  * @arg {Number} [input.limit] - How many messages to pull, defaults to 50, max is 100.
  276.  * @arg {Snowflake} [input.before] - Pull messages before this message ID.
  277.  * @arg {Snowflake} [input.after] - Pull messages after this message ID.
  278.  */
  279. DCP.getMessages = function(input, callback) {
  280.     var qs = { limit: (typeof(input.limit) !== 'number' ? 50 : input.limit) };
  281.     if (input.before) qs.before = input.before;
  282.     if (input.after) qs.after = input.after;
  283.  
  284.     this._req('get', Endpoints.MESSAGES(input.channelID) + qstringify(qs), function(err, res) {
  285.         handleResCB("Unable to get messages", err, res, callback);
  286.     });
  287. };
  288.  
  289. /**
  290.  * Edit a previously sent message.
  291.  * @arg {Object} input
  292.  * @arg {Snowflake} input.channelID
  293.  * @arg {Snowflake} input.messageID
  294.  * @arg {Snowflake} input.message - The new message content
  295.  * @arg {Object} [input.embed] - The new Discord Embed object
  296.  */
  297. DCP.editMessage = function(input, callback) {
  298.     this._req('patch', Endpoints.MESSAGES(input.channelID, input.messageID), generateMessage(input.message || '', input.embed), function(err, res) {
  299.         handleResCB("Unable to edit message", err, res, callback);
  300.     });
  301. };
  302.  
  303. /**
  304.  * Delete a posted message.
  305.  * @arg {Object} input
  306.  * @arg {Snowflake} input.channelID
  307.  * @arg {Snowflake} input.messageID
  308.  */
  309. DCP.deleteMessage = function(input, callback) {
  310.     this._req('delete', Endpoints.MESSAGES(input.channelID, input.messageID), function(err, res) {
  311.         handleResCB("Unable to delete message", err, res, callback);
  312.     });
  313. };
  314.  
  315. /**
  316.  * Delete a batch of messages.
  317.  * @arg {Object} input
  318.  * @arg {Snowflake} input.channelID
  319.  * @arg {Array<Snowflake>} input.messageIDs - An Array of message IDs, with a maximum of 100 indexes.
  320.  */
  321. DCP.deleteMessages = function(input, callback) {
  322.     this._req('post', Endpoints.BULK_DELETE(input.channelID), {messages: input.messageIDs.slice(0, 100)}, function(err, res) {
  323.         handleResCB("Unable to delete messages", err, res, callback);
  324.     });
  325. };
  326.  
  327. /**
  328.  * Pin a message to the channel.
  329.  * @arg {Object} input
  330.  * @arg {Snowflake} input.channelID
  331.  * @arg {Snowflake} input.messageID
  332.  */
  333. DCP.pinMessage = function(input, callback) {
  334.     this._req('put', Endpoints.PINNED_MESSAGES(input.channelID, input.messageID), function(err, res) {
  335.         handleResCB("Unable to pin message", err, res, callback);
  336.     });
  337. };
  338.  
  339. /**
  340.  * Get an array of pinned messages from a channel.
  341.  * @arg {Object} input
  342.  * @arg {Snowflake} input.channelID
  343.  */
  344. DCP.getPinnedMessages = function(input, callback) {
  345.     this._req('get', Endpoints.PINNED_MESSAGES(input.channelID), function(err, res) {
  346.         handleResCB("Unable to get pinned messages", err, res, callback);
  347.     });
  348. };
  349.  
  350. /**
  351.  * Delete a pinned message from a channel.
  352.  * @arg {Object} input
  353.  * @arg {Snowflake} input.channelID
  354.  * @arg {Snowflake} input.messageID
  355.  */
  356. DCP.deletePinnedMessage = function(input, callback) {
  357.     this._req('delete', Endpoints.PINNED_MESSAGES(input.channelID, input.messageID), function(err, res) {
  358.         handleResCB("Unable to delete pinned message", err, res, callback);
  359.     });
  360. };
  361.  
  362. /**
  363.  * Send 'typing...' status to a channel
  364.  * @arg {Snowflake} channelID
  365.  */
  366. DCP.simulateTyping = function(channelID, callback) {
  367.     this._req('post', Endpoints.TYPING(channelID), function(err, res) {
  368.         handleResCB("Unable to simulate typing", err, res, callback);
  369.     });
  370. };
  371.  
  372. /**
  373.  * Replace Snowflakes with the names if applicable.
  374.  * @arg {String} message - The message to fix.
  375.  */
  376. DCP.fixMessage = function(message) {
  377.     var client = this;
  378.     return message.replace(/<@&(\d*)>|<@!(\d*)>|<@(\d*)>|<#(\d*)>/g, function(match, RID, NID, UID, CID) {
  379.         var k, i;
  380.         if (UID || CID) {
  381.             if (client.users[UID]) return "@" + client.users[UID].username;
  382.             if (client.channels[CID]) return "#" + client.channels[CID].name;
  383.         }
  384.         if (RID || NID) {
  385.             k = Object.keys(client.servers);
  386.             for (i=0; i<k.length; i++) {
  387.                 if (client.servers[k[i]].roles[RID]) return "@" + client.servers[k[i]].roles[RID].name;
  388.                 if (client.servers[k[i]].members[NID]) return "@" + client.servers[k[i]].members[NID].nick;
  389.             }
  390.         }
  391.     });
  392. };
  393.  
  394. /**
  395.  * Add an emoji reaction to a message.
  396.  * @arg {Object} input
  397.  * @arg {Snowflake} input.channelID
  398.  * @arg {Snowflake} input.messageID
  399.  * @arg {String} input.reaction - Either the emoji unicode or the emoji name:id/object.
  400.  */
  401. DCP.addReaction = function(input, callback) {
  402.     this._req('put', Endpoints.USER_REACTIONS(input.channelID, input.messageID, stringifyEmoji(input.reaction)), function(err, res) {
  403.         handleResCB("Unable to add reaction", err, res, callback);
  404.     });
  405. };
  406.  
  407. /**
  408.  * Get an emoji reaction of a message.
  409.  * @arg {Object} input
  410.  * @arg {Snowflake} input.channelID
  411.  * @arg {Snowflake} input.messageID
  412.  * @arg {String} input.reaction - Either the emoji unicode or the emoji name:id/object.
  413.  * @arg {String} [input.limit]
  414.  */
  415. DCP.getReaction = function(input, callback) {
  416.     var qs = { limit: (typeof(input.limit) !== 'number' ? 100 : input.limit) };
  417.     this._req('get', Endpoints.MESSAGE_REACTIONS(input.channelID, input.messageID, stringifyEmoji(input.reaction)) + qstringify(qs), function(err, res) {
  418.         handleResCB("Unable to get reaction", err, res, callback);
  419.     });
  420. };
  421.  
  422. /**
  423.  * Remove an emoji reaction from a message.
  424.  * @arg {Object} input
  425.  * @arg {Snowflake} input.channelID
  426.  * @arg {Snowflake} input.messageID
  427.  * @arg {Snowflake} [input.userID]
  428.  * @arg {String} input.reaction - Either the emoji unicode or the emoji name:id/object.
  429.  */
  430. DCP.removeReaction = function(input, callback) {
  431.     this._req('delete', Endpoints.USER_REACTIONS(input.channelID, input.messageID, stringifyEmoji(input.reaction), input.userID), function(err, res) {
  432.         handleResCB("Unable to remove reaction", err, res, callback);
  433.     });
  434. };
  435.  
  436. /**
  437.  * Remove all emoji reactions from a message.
  438.  * @arg {Object} input
  439.  * @arg {Snowflake} input.channelID
  440.  * @arg {Snowflake} input.messageID
  441.  */
  442. DCP.removeAllReactions = function(input, callback) {
  443.     this._req('delete', Endpoints.MESSAGE_REACTIONS(input.channelID, input.messageID), function(err, res) {
  444.         handleResCB("Unable to remove reactions", err, res, callback);
  445.     });
  446. };
  447.  
  448. /* - DiscordClient - Methods - Server Management - */
  449.  
  450. /**
  451.  * Remove a user from a server.
  452.  * @arg {Object} input
  453.  * @arg {Snowflake} input.serverID
  454.  * @arg {Snowflake} input.userID
  455.  */
  456. DCP.kick = function(input, callback) {
  457.     this._req('delete', Endpoints.MEMBERS(input.serverID, input.userID), function(err, res) {
  458.         handleResCB("Could not kick user", err, res, callback);
  459.     });
  460. };
  461.  
  462. /**
  463.  * Remove and ban a user from a server.
  464.  * @arg {Object} input
  465.  * @arg {Snowflake} input.serverID
  466.  * @arg {Snowflake} input.userID
  467.  * @arg {Number} [input.lastDays] - Removes their messages up until this point, either 1 or 7 days.
  468.  */
  469. DCP.ban = function(input, callback) {
  470.     if (input.lastDays) {
  471.         input.lastDays = Number(input.lastDays);
  472.         input.lastDays = Math.min(input.lastDays, 7);
  473.         input.lastDays = Math.max(input.lastDays, 1);
  474.     }
  475.  
  476.     this._req('put', Endpoints.BANS(input.serverID, input.userID) + (input.lastDays ? "?delete-message-days=" + input.lastDays : ""), function(err, res) {
  477.         handleResCB("Could not ban user", err, res, callback);
  478.     });
  479. };
  480.  
  481. /**
  482.  * Unban a user from a server.
  483.  * @arg {Object} input
  484.  * @arg {Snowflake} input.serverID
  485.  * @arg {Snowflake} input.userID
  486.  */
  487. DCP.unban = function(input, callback) {
  488.     this._req('delete', Endpoints.BANS(input.serverID, input.userID), function(err, res) {
  489.         handleResCB("Could not unban user", err, res, callback);
  490.     });
  491. };
  492.  
  493. /**
  494.  * Move a user between voice channels.
  495.  * @arg {Object} input
  496.  * @arg {Snowflake} input.serverID
  497.  * @arg {Snowflake} input.userID
  498.  * @arg {Snowflake} input.channelID
  499.  */
  500. DCP.moveUserTo = function(input, callback) {
  501.     this._req('patch', Endpoints.MEMBERS(input.serverID, input.userID), {channel_id: input.channelID}, function(err, res) {
  502.         handleResCB("Could not move the user", err, res, callback);
  503.     });
  504. };
  505.  
  506. /**
  507.  * Server-mute the user from speaking in all voice channels.
  508.  * @arg {Object} input
  509.  * @arg {Snowflake} input.serverID
  510.  * @arg {Snowflake} input.userID
  511.  */
  512. DCP.mute = function(input, callback) {
  513.     this._req('patch', Endpoints.MEMBERS(input.serverID, input.userID), {mute: true}, function(err, res) {
  514.         handleResCB("Could not mute user", err, res, callback);
  515.     });
  516. };
  517.  
  518. /**
  519.  * Remove the server-mute from a user.
  520.  * @arg {Object} input
  521.  * @arg {Snowflake} input.serverID
  522.  * @arg {Snowflake} input.userID
  523.  */
  524. DCP.unmute = function(input, callback) {
  525.     this._req('patch', Endpoints.MEMBERS(input.serverID, input.userID), {mute: false}, function(err, res) {
  526.         handleResCB("Could not unmute user", err, res, callback);
  527.     });
  528. };
  529.  
  530. /**
  531.  * Server-deafan a user.
  532.  * @arg {Object} input
  533.  * @arg {Snowflake} input.serverID
  534.  * @arg {Snowflake} input.userID
  535.  */
  536. DCP.deafen = function(input, callback) {
  537.     this._req('patch', Endpoints.MEMBERS(input.serverID, input.userID), {deaf: true}, function(err, res) {
  538.         handleResCB("Could not deafen user", err, res, callback);
  539.     });
  540. };
  541.  
  542. /**
  543.  * Remove the server-deafan from a user.
  544.  * @arg {Object} input
  545.  * @arg {Snowflake} input.serverID
  546.  * @arg {Snowflake} input.userID
  547.  */
  548. DCP.undeafen = function(input, callback) {
  549.     this._req('patch', Endpoints.MEMBERS(input.serverID, input.userID), {deaf: false}, function(err, res) {
  550.         handleResCB("Could not undeafen user", err, res, callback);
  551.     });
  552. };
  553.  
  554. /*Bot server management actions*/
  555.  
  556. /**
  557.  * Create a server [User only].
  558.  * @arg {Object} input
  559.  * @arg {String} input.name - The server's name
  560.  * @arg {String} [input.region] - The server's region code, check the Gitbook documentation for all of them.
  561.  * @arg {String<Base64>} [input.icon] - The last part of a Base64 Data URI. `fs.readFileSync('image.jpg', 'base64')` is enough.
  562.  */
  563. DCP.createServer = function(input, callback) {
  564.     var payload, client = this;
  565.     payload = {icon: null, name: null, region: null};
  566.     for (var key in input) {
  567.         if (Object.keys(payload).indexOf(key) < 0) continue;
  568.         payload[key] = input[key];
  569.     }
  570.     if (input.icon) payload.icon = "data:image/jpg;base64," + input.icon;
  571.  
  572.     client._req('post', Endpoints.SERVERS(), payload, function(err, res) {
  573.         try {
  574.             client.servers[res.body.id] = {};
  575.             copyKeys(res.body, client.servers[res.body.id]);
  576.         } catch(e) {}
  577.         handleResCB("Could not create server", err, res, callback);
  578.     });
  579. };
  580.  
  581. /**
  582.  * Edit server information.
  583.  * @arg {Object} input
  584.  * @arg {Snowflake} input.serverID
  585.  * @arg {String} [input.name]
  586.  * @arg {String} [input.icon]
  587.  * @arg {String} [input.region]
  588.  * @arg {Snowflake} [input.afk_channel_id] - The ID of the voice channel to move a user to after the afk period.
  589.  * @arg {Number} [input.afk_timeout] - Time in seconds until a user is moved to the afk channel. 60, 300, 900, 1800, or 3600.
  590.  */
  591. DCP.editServer = function(input, callback) {
  592.     var payload, serverID = input.serverID, server, client = this;
  593.     if (!client.servers[serverID]) return handleErrCB(("[editServer] Server " + serverID + " not found."), callback);
  594.  
  595.     server = client.servers[serverID];
  596.     payload = {
  597.         name: server.name,
  598.         icon: server.icon,
  599.         region: server.region,
  600.         afk_channel_id: server.afk_channel_id,
  601.         afk_timeout: server.afk_timeout
  602.     };
  603.  
  604.     for (var key in input) {
  605.         if (Object.keys(payload).indexOf(key) < 0) continue;
  606.         if (key === 'afk_channel_id') {
  607.             if (server.channels[input[key]] && server.channels[input[key]].type === 'voice') payload[key] = input[key];
  608.             continue;
  609.         }
  610.         if (key === 'afk_timeout') {
  611.             if ([60, 300, 900, 1800, 3600].indexOf(Number(input[key])) > -1) payload[key] = input[key];
  612.             continue;
  613.         }
  614.         payload[key] = input[key];
  615.     }
  616.     if (input.icon) payload.icon = "data:image/jpg;base64," + input.icon;
  617.  
  618.     client._req('patch', Endpoints.SERVERS(input.serverID), payload, function(err, res) {
  619.         handleResCB("Unable to edit server", err, res, callback);
  620.     });
  621. };
  622.  
  623. /**
  624.  * Edit the widget information for a server.
  625.  * @arg {Object} input
  626.  * @arg {Snowflake} input.serverID - The ID of the server whose widget you want to edit.
  627.  * @arg {Boolean} [input.enabled] - Whether or not you want the widget to be enabled.
  628.  * @arg {Snowflake} [input.channelID] - [Important] The ID of the channel you want the instant invite to point to.
  629.  */
  630. DCP.editServerWidget = function(input, callback) {
  631.     var client = this, payload, url = Endpoints.SERVERS(input.serverID) + "/embed";
  632.  
  633.     client._req('get', url, function(err, res) {
  634.         if (err) return handleResCB("Unable to GET server widget settings. Can not edit without retrieving first.", err, res, callback);
  635.         payload = {
  636.             enabled: ('enabled' in input ? input.enabled : res.body.enabled),
  637.             channel_id: ('channelID' in input ? input.channelID : res.body.channel_id)
  638.         };
  639.         client._req('patch', url, payload, function(err, res) {
  640.             handleResCB("Unable to edit server widget", err, res, callback);
  641.         });
  642.     });
  643. };
  644.  
  645. /**
  646.  * [User Account] Add an emoji to a server
  647.  * @arg {Object} input
  648.  * @arg {Snowflake} input.serverID
  649.  * @arg {String} input.name - The emoji's name
  650.  * @arg {String<Base64>} input.image - The emoji's image data in Base64
  651.  */
  652. DCP.addServerEmoji = function(input, callback) {
  653.     var payload = {
  654.         name: input.name,
  655.         image: "data:image/png;base64," + input.image
  656.     };
  657.     this._req('post', Endpoints.SERVER_EMOJIS(input.serverID), payload, function(err, res) {
  658.         handleResCB("Unable to add emoji to the server", err, res, callback);
  659.     });
  660. }
  661.  
  662. /**
  663.  * [User Account] Edit a server emoji data (name only, currently)
  664.  * @arg {Object} input
  665.  * @arg {Snowflake} input.serverID
  666.  * @arg {Snowflake} input.emojiID - The emoji's ID
  667.  * @arg {String} [input.name]
  668.  * @arg {Array<Snowflake>} [input.roles] - An array of role IDs you want to limit the emoji's usage to
  669.  */
  670. DCP.editServerEmoji = function(input, callback) {
  671.     var emoji, payload = {};
  672.     if ( !this.servers[input.serverID] ) return handleErrCB(("[editServerEmoji] Server not available: " + input.serverID), callback);
  673.     if ( !this.servers[input.serverID].emojis[input.emojiID]) return handleErrCB(("[editServerEmoji] Emoji not available: " + input.emojiID), callback);
  674.  
  675.     emoji = this.servers[input.serverID].emojis[input.emojiID];
  676.     payload.name = input.name || emoji.name;
  677.     payload.roles = input.roles || emoji.roles;
  678.  
  679.     this._req('patch', Endpoints.SERVER_EMOJIS(input.serverID, input.emojiID), payload, function(err, res) {
  680.         handleResCB("[editServerEmoji] Could not edit server emoji", err, res, callback);
  681.     });
  682. }
  683.  
  684. /**
  685.  * [User Account] Remove an emoji from a server
  686.  * @arg {Object} input
  687.  * @arg {Snowflake} input.serverID
  688.  * @arg {Snowflake} input.emojiID
  689.  */
  690. DCP.deleteServerEmoji = function(input, callback) {
  691.     this._req('delete', Endpoints.SERVER_EMOJIS(input.serverID, input.emojiID), function(err, res) {
  692.         handleResCB("[deleteServerEmoji] Could not delete server emoji", err, res, callback);
  693.     });
  694. }
  695.  
  696. /**
  697.  * Leave a server.
  698.  * @arg {Snowflake} serverID
  699.  */
  700. DCP.leaveServer = function(serverID, callback) {
  701.     this._req('delete', Endpoints.SERVERS_PERSONAL(serverID), function(err, res) {
  702.         handleResCB("Could not leave server", err, res, callback);
  703.     });
  704. };
  705.  
  706. /**
  707.  * Delete a server owned by the client.
  708.  * @arg {Snowflake} serverID
  709.  */
  710. DCP.deleteServer = function(serverID, callback) {
  711.     this._req('delete', Endpoints.SERVERS(serverID), function(err, res) {
  712.         handleResCB("Could not delete server", err, res, callback);
  713.     });
  714. };
  715.  
  716. /**
  717.  * Transfer ownership of a server to another user.
  718.  * @arg {Object} input
  719.  * @arg {Snowflake} input.serverID
  720.  * @arg {Snowflake} input.userID
  721.  */
  722. DCP.transferOwnership = function(input, callback) {
  723.     this._req('patch', Endpoints.SERVERS(input.serverID), {owner_id: input.userID}, function(err, res) {
  724.         handleResCB("Could not transfer server ownership", err, res, callback);
  725.     });
  726. };
  727.  
  728. /**
  729.  * Accept an invite to a server [User Only]
  730.  * @arg {String} inviteCode - The code part of an invite URL (e.g. 0MvHMfHcTKVVmIGP)
  731.  */
  732. DCP.acceptInvite = function(inviteCode, callback) {
  733.     if (this.bot) return handleErrCB("[acceptInvite] This account is a 'bot' type account, and cannot use 'acceptInvite'. Please use the client's inviteURL property instead.", callback);
  734.     var client = this, joinedServers = Object.keys(client.servers);
  735.     this._req('post', Endpoints.INVITES(inviteCode), function(err, res) {
  736.         try {
  737.             //Try to create the server with the small amount of data
  738.             //that Discord provides directly from the HTTP response
  739.             //since the websocket event may take a second to show.
  740.             if (!client.servers[res.body.guild.id]) {
  741.                 client.servers[res.body.guild.id] = res.body.guild;
  742.                 client.servers[res.body.guild.id].channels = {};
  743.                 client.servers[res.body.guild.id].channels[res.body.channel.id] = res.body.channel;
  744.             } else {
  745.                 if (joinedServers.indexOf(res.body.guild.id) > -1) {
  746.                     return handleErrCB(("Already joined server: " + res.body.guild.id), callback);
  747.                 }
  748.             }
  749.         } catch(e) {}
  750.         handleResCB(("The invite code provided " + inviteCode + " is incorrect."), err, res, callback);
  751.     });
  752. };
  753.  
  754. /**
  755.  * Generate an invite URL for a channel.
  756.  * @arg {Object} input
  757.  * @arg {Snowflake} input.channelID
  758.  * @arg {Number} [input.max_age] - Time in seconds.
  759.  * @arg {Number} [input.max_users] - The amount of times the invite code can be used.
  760.  * @arg {Boolean} [input.temporary] - Any users who use this invite will be removed when they disconnect, unless given a role.
  761.  */
  762. DCP.createInvite = function(input, callback) {
  763.     var payload, client = this;
  764.  
  765.     payload = {
  766.         max_age: 0,
  767.         max_users: 0,
  768.         temporary: false
  769.     };
  770.  
  771.     if ( Object.keys(input).length === 1 && input.channelID ) {
  772.         payload = {
  773.             validate: client.internals.lastInviteCode || null
  774.         };
  775.     }
  776.  
  777.     for (var key in input) {
  778.         if (Object.keys(payload).indexOf(key) < 0) continue;
  779.         payload[key] = input[key];
  780.     }
  781.  
  782.     this._req('post', Endpoints.CHANNEL(input.channelID) + "/invites", payload, function(err, res) {
  783.         try {client.internals.lastInviteCode = res.body.code;} catch(e) {}
  784.         handleResCB('Unable to create invite', err, res, callback);
  785.     });
  786. };
  787.  
  788. /**
  789.  * Delete an invite code.
  790.  * @arg {String} inviteCode
  791.  */
  792. DCP.deleteInvite = function(inviteCode, callback) {
  793.     this._req('delete', Endpoints.INVITES(inviteCode), function(err, res) {
  794.         handleResCB('Unable to delete invite', err, res, callback);
  795.     });
  796. };
  797.  
  798. /**
  799.  * Get information on an invite.
  800.  * @arg {String} inviteCode
  801.  */
  802. DCP.queryInvite = function(inviteCode, callback) {
  803.     this._req('get', Endpoints.INVITES(inviteCode), function(err, res) {
  804.         handleResCB('Unable to get information about invite', err, res, callback);
  805.     });
  806. };
  807.  
  808. /**
  809.  * Get all invites for a server.
  810.  * @arg {Snowflake} serverID
  811.  */
  812. DCP.getServerInvites = function(serverID, callback) {
  813.     this._req('get', Endpoints.SERVERS(serverID) + "/invites", function(err, res) {
  814.         handleResCB('Unable to get invite list for server' + serverID, err, res, callback);
  815.     });
  816. };
  817.  
  818. /**
  819.  * Get all invites for a channel.
  820.  * @arg {Snowflake} channelID
  821.  */
  822. DCP.getChannelInvites = function(channelID, callback) {
  823.     this._req('get', Endpoints.CHANNEL(channelID) + "/invites", function(err, res) {
  824.         handleResCB('Unable to get invite list for channel' + channelID, err, res, callback);
  825.     });
  826. };
  827.  
  828. /**
  829.  * Create a channel.
  830.  * @arg {Object} input
  831.  * @arg {Snowflake} input.serverID
  832.  * @arg {String} input.name
  833.  * @arg {String} [input.type] - 'text' or 'voice', defaults to 'text.
  834.  */
  835. DCP.createChannel = function(input, callback) {
  836.     var client = this, payload = {
  837.         name: input.name,
  838.         type: (['text', 'voice'].indexOf(input.type) < 0) ? 'text' : input.type
  839.     };
  840.  
  841.     this._req('post', Endpoints.SERVERS(input.serverID) + "/channels", payload, function(err, res) {
  842.         try {
  843.             var serverID = res.body.guild_id;
  844.             var channelID = res.body.id;
  845.  
  846.             client.channels[channelID] = new Channel( client, client.servers[serverID], res.body );
  847.         } catch(e) {}
  848.         handleResCB('Unable to create channel', err, res, callback);
  849.     });
  850. };
  851.  
  852. /**
  853.  * Create a Direct Message channel.
  854.  * @arg {Snowflake} userID
  855.  */
  856. DCP.createDMChannel = function(userID, callback) {
  857.     var client = this;
  858.     this._req('post', Endpoints.USER(client.id) + "/channels", {recipient_id: userID}, function(err, res) {
  859.         if (!err && goodResponse(res)) client._uIDToDM[res.body.recipient.id] = res.body.id;
  860.         handleResCB("Unable to create DM Channel", err, res, callback);
  861.     });
  862. };
  863.  
  864. /**
  865.  * Delete a channel.
  866.  * @arg {Snowflake} channelID
  867.  */
  868. DCP.deleteChannel = function(channelID, callback) {
  869.     this._req('delete', Endpoints.CHANNEL(channelID), function(err, res) {
  870.         handleResCB("Unable to delete channel", err, res, callback);
  871.     });
  872. };
  873.  
  874. /**
  875.  * Edit a channel's information.
  876.  * @arg {Object} input
  877.  * @arg {Snowflake} input.channelID
  878.  * @arg {String} [input.name]
  879.  * @arg {String} [input.topic] - The topic of the channel.
  880.  * @arg {Number} [input.bitrate] - [Voice Only] The bitrate for the channel.
  881.  * @arg {Number} [input.position] - The channel's position on the list.
  882.  * @arg {Number} [input.user_limit] - [Voice Only] Imposes a user limit on a voice channel.
  883.  */
  884. DCP.editChannelInfo = function(input, callback) {
  885.     var channel, payload;
  886.  
  887.     try {
  888.         channel = this.channels[input.channelID];
  889.         payload = {
  890.             name: channel.name,
  891.             topic: channel.topic,
  892.             bitrate: channel.bitrate,
  893.             position: channel.position,
  894.             user_limit: channel.user_limit
  895.         };
  896.  
  897.         for (var key in input) {
  898.             if (Object.keys(payload).indexOf(key) < 0) continue;
  899.             if (+input[key]) {
  900.                 if (key === 'bitrate') {
  901.                     payload.birate = Math.min( Math.max( input.bitrate, 8000), 96000);
  902.                     continue;
  903.                 }
  904.                 if (key === 'user_limit') {
  905.                     payload.user_limit = Math.min( Math.max( input.user_limit, 0), 99);
  906.                     continue;
  907.                 }
  908.             }
  909.             payload[key] = input[key];
  910.         }
  911.  
  912.         this._req('patch', Endpoints.CHANNEL(input.channelID), payload, function(err, res) {
  913.             handleResCB("Unable to edit channel", err, res, callback);
  914.         });
  915.     } catch(e) {return handleErrCB(e, callback);}
  916. };
  917.  
  918. /**
  919.  * Edit (or creates) a permission override for a channel.
  920.  * @arg {Object} input
  921.  * @arg {Snowflake} channelID
  922.  * @arg {Snowflake} [userID]
  923.  * @arg {Snowflake} [roleID]
  924.  * @arg {Array<Number>} allow - An array of permissions to allow. Discord.Permissions.XXXXXX.
  925.  * @arg {Array<Number>} deny - An array of permissions to deny, same as above.
  926.  * @arg {Array<Number>} default - An array of permissions that cancels out allowed and denied permissions.
  927.  */
  928. DCP.editChannelPermissions = function(input, callback) { //Will shrink this up later
  929.     var payload, pType, ID, channel, permissions, allowed_values;
  930.     if (!input.userID && !input.roleID) return handleErrCB("[editChannelPermissions] No userID or roleID provided", callback);
  931.     if (!this.channels[input.channelID]) return handleErrCB(("[editChannelPermissions] No channel found for ID: " + input.channelID), callback);
  932.     if (!input.allow && !input.deny && !input.default) return handleErrCB("[editChannelPermissions] No allow, deny or default array provided.", callback);
  933.  
  934.     pType = input.userID ? 'user' : 'role';
  935.     ID = input[pType + "ID"];
  936.     channel = this.channels[ input.channelID ];
  937.     permissions = channel.permissions[pType][ID] || { allow: 0, deny: 0 };
  938.     allowed_values = [0, 4, 28].concat((channel.type === 'text' ?
  939.     [10, 11, 12, 13, 14, 15, 16, 17, 18] :
  940.     [20, 21, 22, 23, 24, 25] ));
  941.  
  942.     //Take care of allow first
  943.     if (type(input.allow) === 'array') {
  944.         input.allow.forEach(function(perm) {
  945.             if (allowed_values.indexOf(perm) < 0) return;
  946.             if (hasPermission(perm, permissions.deny)) {
  947.                 permissions.deny = removePermission(perm, permissions.deny);
  948.             }
  949.             permissions.allow = givePermission(perm, permissions.allow);
  950.         });
  951.     }
  952.     //Take care of deny second
  953.     if (type(input.deny) === 'array') {
  954.         input.deny.forEach(function(perm) {
  955.             if (allowed_values.indexOf(perm) < 0) return;
  956.             if (hasPermission(perm, permissions.allow)) {
  957.                 permissions.allow = removePermission(perm, permissions.allow);
  958.             }
  959.             permissions.deny = givePermission(perm, permissions.deny);
  960.         });
  961.     }
  962.     //Take care of defaulting last
  963.     if (type(input.default) === 'array') {
  964.         input.default.forEach(function(perm) {
  965.             if (allowed_values.indexOf(perm) < 0) return;
  966.             permissions.allow = removePermission(perm, permissions.allow);
  967.             permissions.deny = removePermission(perm, permissions.deny);
  968.         });
  969.     }
  970.  
  971.     payload = {
  972.         type: (pType === 'user' ? 'member' : 'role'),
  973.         id: ID,
  974.         deny: permissions.deny,
  975.         allow: permissions.allow
  976.     };
  977.  
  978.     this._req('put', Endpoints.CHANNEL(input.channelID) + "/permissions/" + ID, payload, function(err, res) {
  979.         handleResCB('Unable to edit permission', err, res, callback);
  980.     });
  981. };
  982.  
  983. /**
  984.  * Delete a permission override for a channel.
  985.  * @arg {Object} input
  986.  * @arg {Snowflake} channelID
  987.  * @arg {Snowflake} [userID]
  988.  * @arg {Snowflake} [roleID]
  989.  */
  990. DCP.deleteChannelPermission = function(input, callback) {
  991.     var payload, pType, ID;
  992.     if (!input.userID && !input.roleID) return handleErrCB("[deleteChannelPermission] No userID or roleID provided", callback);
  993.     if (!this.channels[input.channelID]) return handleErrCB(("[deleteChannelPermission] No channel found for ID: " + input.channelID), callback);
  994.  
  995.     pType = input.userID ? 'user' : 'role';
  996.     ID = input[pType + "ID"];
  997.  
  998.     payload = {
  999.         type: (pType === 'user' ? 'member' : 'role'),
  1000.         id: ID
  1001.     };
  1002.  
  1003.     this._req('delete', Endpoints.CHANNEL(input.channelID) + "/permissions/" + ID, payload, function(err, res) {
  1004.         handleResCB('Unable to delete permission', err, res, callback);
  1005.     });
  1006. };
  1007.  
  1008. /**
  1009.  * Create a role for a server.
  1010.  * @arg {Snowflake} serverID
  1011.  */
  1012. DCP.createRole = function(serverID, callback) {
  1013.     var client = this;
  1014.     this._req('post', Endpoints.ROLES(serverID), function(err, res) {
  1015.         try {
  1016.             client.servers[serverID].roles[res.body.id] = new Role(res.body);
  1017.         } catch(e) {}
  1018.         handleResCB("Unable to create role", err, res, callback);
  1019.     });
  1020. };
  1021.  
  1022. /**
  1023.  * Edit a role.
  1024.  * @arg {Object} input
  1025.  * @arg {Snowflake} input.serverID
  1026.  * @arg {Snowflake} input.roleID - The ID of the role.
  1027.  * @arg {String} [input.name]
  1028.  * @arg {String} [input.color] - An HTML `#xxxxxx` color value, or a preset color value. Read the Colors doc.
  1029.  * @arg {Boolean} [input.hoist] - Separates the users in this role from the normal online users.
  1030.  * @arg {Object} [input.permissions] - An Object containing the permission as a key, and `true` or `false` as its value. Read the Permissions doc.
  1031.  * @arg {Boolean} [input.mentionable] - Toggles if users can @Mention this role.
  1032.  */
  1033. DCP.editRole = function(input, callback) {
  1034.     var role, payload;
  1035.     try {
  1036.         role = new Role(this.servers[input.serverID].roles[input.roleID]);
  1037.         payload = {
  1038.             name: role.name,
  1039.             color: role.color,
  1040.             hoist: role.hoist,
  1041.             permissions: role._permissions,
  1042.             mentionable: role.mentionable,
  1043.             position: role.position
  1044.         };
  1045.  
  1046.         for (var key in input) {
  1047.             if (Object.keys(payload).indexOf(key) < 0) continue;
  1048.             if (key === 'permissions') {
  1049.                 for (var perm in input[key]) {
  1050.                     role[perm] = input[key][perm];
  1051.                     payload.permissions = role._permissions;
  1052.                 }
  1053.                 continue;
  1054.             }
  1055.             if (key === 'color') {
  1056.                 if (String(input[key])[0] === '#') payload.color = parseInt(String(input[key]).replace('#', '0x'), 16);
  1057.                 if (Discord.Colors[input[key]]) payload.color = Discord.Colors[input[key]];
  1058.                 continue;
  1059.             }
  1060.             payload[key] = input[key];
  1061.         }
  1062.         this._req('patch', Endpoints.ROLES(input.serverID, input.roleID), payload, function(err, res) {
  1063.             handleResCB("Unable to edit role", err, res, callback);
  1064.         });
  1065.     } catch(e) {return handleErrCB(('[editRole] ' + e), callback);}
  1066. };
  1067.  
  1068. /**
  1069.  * Delete a role.
  1070.  * @arg {Object} input
  1071.  * @arg {Snowflake} input.serverID
  1072.  * @arg {Snowflake} input.roleID
  1073.  */
  1074. DCP.deleteRole = function(input, callback) {
  1075.     this._req('delete', Endpoints.ROLES(input.serverID, input.roleID), function(err, res) {
  1076.         handleResCB("Could not remove role", err, res, callback);
  1077.     });
  1078. };
  1079.  
  1080. /**
  1081.  * Add a user to a role.
  1082.  * @arg {Object} input
  1083.  * @arg {Snowflake} input.serverID
  1084.  * @arg {Snowflake} input.roleID
  1085.  * @arg {Snowflake} input.userID
  1086.  */
  1087. DCP.addToRole = function(input, callback) {
  1088.     this._req('put', Endpoints.MEMBER_ROLES(input.serverID, input.userID, input.roleID), function(err, res) {
  1089.         handleResCB("Could not add role", err, res, callback);
  1090.     });
  1091. };
  1092.  
  1093. /**
  1094.  * Remove a user from a role.
  1095.  * @arg {Object} input
  1096.  * @arg {Snowflake} input.serverID
  1097.  * @arg {Snowflake} input.roleID
  1098.  * @arg {Snowflake} input.userID
  1099.  */
  1100. DCP.removeFromRole = function(input, callback) {
  1101.     this._req('delete', Endpoints.MEMBER_ROLES(input.serverID, input.userID, input.roleID), function(err, res) {
  1102.         handleResCB("Could not remove role", err, res, callback);
  1103.     });
  1104. };
  1105.  
  1106. /**
  1107.  * Edit a user's nickname.
  1108.  * @arg {Object} input
  1109.  * @arg {Snowflake} input.serverID
  1110.  * @arg {Snowflake} input.userID
  1111.  * @arg {String} input.nick - The nickname you'd like displayed.
  1112.  */
  1113. DCP.editNickname = function(input, callback) {
  1114.     var payload = {nick: String( input.nick ? input.nick : "" )};
  1115.     var url = input.userID === this.id ?
  1116.         Endpoints.MEMBERS(input.serverID) + "/@me/nick" :
  1117.         Endpoints.MEMBERS(input.serverID, input.userID);
  1118.  
  1119.     this._req('patch', url, payload, function(err, res) {
  1120.         handleResCB("Could not change nickname", err, res, callback);
  1121.     });
  1122. };
  1123.  
  1124. /**
  1125.  * Edit a user's note.
  1126.  * @arg {Object} input
  1127.  * @arg {Snowflake} input.userID
  1128.  * @arg {String} input.note - The note content that you want to use.
  1129.  */
  1130. DCP.editNote = function(input, callback) {
  1131.     this._req('put', Endpoints.NOTE(input.userID), {note: input.note}, function(err, res) {
  1132.         handleResCB("Could not edit note", err, res, callback);
  1133.     });
  1134. };
  1135.  
  1136. /**
  1137.  * Retrieve a user object from Discord, the library already caches users, however.
  1138.  * @arg {Object} input
  1139.  * @arg {Snowflake} input.serverID
  1140.  * @arg {Snowflake} input.userID
  1141.  */
  1142. DCP.getMember = function(input, callback) {
  1143.     this._req('get', Endpoints.MEMBERS(input.serverID, input.userID), function(err, res) {
  1144.         handleResCB("Could not get member", err, res, callback);
  1145.     });
  1146. };
  1147.  
  1148. /**
  1149.  * Retrieve a group of user objects from Discord.
  1150.  * @arg {Object} input
  1151.  * @arg {Number} [input.limit] - The amount of users to pull, defaults to 50.
  1152.  * @arg {Snowflake} [input.after] - The offset using a user ID.
  1153.  */
  1154. DCP.getMembers = function(input, callback) {
  1155.     var qs = {};
  1156.     qs.limit = (typeof(input.limit) !== 'number' ? 50 : input.limit);
  1157.     if (input.after) qs.after = input.after;
  1158.  
  1159.     this._req('get', Endpoints.MEMBERS(input.serverID) + qstringify(qs), function(err, res) {
  1160.         handleResCB("Could not get members", err, res, callback);
  1161.     });
  1162. };
  1163.  
  1164. /**
  1165.  * Get the ban list from a server
  1166.  * @arg {Snowflake} serverID
  1167.  */
  1168. DCP.getBans = function(serverID, callback) {
  1169.     this._req('get', Endpoints.BANS(serverID), function(err, res) {
  1170.         handleResCB("Could not get ban list", err, res, callback);
  1171.     });
  1172. };
  1173.  
  1174. /**
  1175.  * Get all webhooks for a server
  1176.  * @arg {Snowflake} serverID
  1177.  */
  1178. DCP.getServerWebhooks = function(serverID, callback) {
  1179.     this._req('get', Endpoints.SERVER_WEBHOOKS(serverID), function(err, res) {
  1180.         handleResCB("Could not get server Webhooks", err, res, callback);
  1181.     });
  1182. };
  1183.  
  1184. /**
  1185.  * Get webhooks from a channel
  1186.  * @arg {Snowflake} channelID
  1187.  */
  1188. DCP.getChannelWebhooks = function(channelID, callback) {
  1189.     this._req('get', Endpoints.CHANNEL_WEBHOOKS(channelID), function(err, res) {
  1190.         handleResCB("Could not get channel Webhooks", err, res, callback);
  1191.     });
  1192. };
  1193.  
  1194. /**
  1195.  * Create a webhook for a server
  1196.  * @arg {Snowflake} serverID
  1197.  */
  1198. DCP.createWebhook = function(serverID, callback) {
  1199.     this._req('post', Endpoints.SERVER_WEBHOOKS(serverID), function(err, res) {
  1200.         handleResCB("Could not create a Webhook", err, res, callback);
  1201.     });
  1202. };
  1203.  
  1204. /**
  1205.  * Edit a webhook
  1206.  * @arg {Object} input
  1207.  * @arg {Snowflake} input.webhookID - The Webhook's ID
  1208.  * @arg {String} [input.name]
  1209.  * @arg {String<Base64>} [input.avatar]
  1210.  * @arg {String} [input.channelID]
  1211.  */
  1212. DCP.editWebhook = function(input, callback) {
  1213.     var client = this, payload = {}, allowed = ['avatar', 'name'];
  1214.     this._req('get', Endpoints.WEBHOOKS(input.webhookID), function(err, res) {
  1215.         if (err || !goodResponse(res)) return handleResCB("Couldn't get webhook, do you have permissions to access it?", err, res, callback);
  1216.         allowed.forEach(function(key) {
  1217.             payload[key] = (key in input ? input[key] : res.body[key]);
  1218.         });
  1219.         payload.channel_id = input.channelID || res.body.channel_id;
  1220.  
  1221.         client._req('patch', Endpoints.WEBHOOKS(input.webhookID), payload, function(err, res) {
  1222.             return handleResCB("Couldn't update webhook", err, res, callback);
  1223.         });
  1224.     });
  1225. }
  1226.  
  1227. /* --- Voice --- */
  1228.  
  1229. /**
  1230.  * Join a voice channel.
  1231.  * @arg {Snowflake} channelID
  1232.  */
  1233. DCP.joinVoiceChannel = function(channelID, callback) {
  1234.     var serverID, server, channel, init, voiceSession;
  1235.     try {
  1236.         serverID = this.channels[channelID].guild_id;
  1237.         server = this.servers[serverID];
  1238.         channel = server.channels[channelID];
  1239.     } catch(e) {}
  1240.     if (!serverID) return handleErrCB(("Cannot find the server related to the channel provided: " + channelID), callback);
  1241.     if (channel.type !== 'voice') return handleErrCB(("Selected channel is not a voice channel: " + channelID), callback);
  1242.     if (this._vChannels[channelID]) return handleErrCB(("Voice channel already active: " + channelID), callback);
  1243.  
  1244.     init = {
  1245.         op: 4,
  1246.         d: {
  1247.             guild_id: serverID,
  1248.             channel_id: channelID,
  1249.             self_mute: false,
  1250.             self_deaf: false
  1251.         }
  1252.     };
  1253.     voiceSession = getVoiceSession(this, channelID, server);
  1254.     checkVoiceReady(voiceSession, callback);
  1255.     send(this._ws, init);
  1256. };
  1257.  
  1258. /**
  1259.  * Leave a voice channel.
  1260.  * @arg {Snowflake} channelID
  1261.  */
  1262. DCP.leaveVoiceChannel = function(channelID, callback) {
  1263.     if (!this._vChannels[channelID]) return handleErrCB(("Not in the voice channel: " + channelID), callback);
  1264.     return leaveVoiceChannel(this, channelID, callback);
  1265. };
  1266.  
  1267. /**
  1268.  * Prepare the client for sending/receiving audio.
  1269.  * @arg {Snowflake|Object} channelObj - Either the channel ID, or an Object with `channelID` as a key and the ID as the value.
  1270.  * @arg {Number} [channelObj.maxStreamSize] - The size in KB that you wish to receive before pushing out earlier data. Required if you want to store or receive incoming audio.
  1271.  * @arg {Boolean} [channelObj.stereo] - Sets the audio to be either stereo or mono. Defaults to true.
  1272.  */
  1273. DCP.getAudioContext = function(channelObj, callback) {
  1274.     // #q/qeled gave a proper timing solution. Credit where it's due.
  1275.     if (!isNode) return handleErrCB("Using audio in the browser is currently not supported.", callback);
  1276.     var channelID = channelObj.channelID || channelObj, voiceSession = this._vChannels[channelID], encoder = chooseAudioEncoder(['ffmpeg', 'avconv']);
  1277.  
  1278.     if (!voiceSession) return handleErrCB(("You have not joined the voice channel: " + channelID), callback);
  1279.     if (voiceSession.ready !== true) return handleErrCB(("The connection to the voice channel " + channelID + " has not been initialized yet."), callback);
  1280.     if (!encoder) return handleErrCB("You need either 'ffmpeg' or 'avconv' and they need to be added to PATH", callback);
  1281.  
  1282.     voiceSession.audio = voiceSession.audio || new AudioCB(
  1283.         voiceSession,
  1284.         channelObj.stereo === false ? 1 : 2,
  1285.         encoder,
  1286.         Math.abs(Number(channelObj.maxStreamSize)));
  1287.  
  1288.     return call(callback, [null, voiceSession.audio]);
  1289. };
  1290.  
  1291. /* --- Misc --- */
  1292.  
  1293. /**
  1294.  * Retrieves all offline (and online, if using a user account) users, fires the `allUsers` event when done.
  1295.  */
  1296. DCP.getAllUsers = function(callback) {
  1297.     var servers = Object.keys(this.servers).filter(function(s) {
  1298.             s = this.servers[s];
  1299.             if (s.members) return s.member_count !== Object.keys(s.members).length && (this.bot ? s.large : true);
  1300.         }, this);
  1301.  
  1302.     if (!servers[0]) {
  1303.         this.emit('allUsers');
  1304.         return handleErrCB("There are no users to be collected", callback);
  1305.     }
  1306.     if (!this.bot) send(this._ws, { op: 12, d: Object.keys(this.servers) });
  1307.  
  1308.     return getOfflineUsers(this, servers, callback);
  1309. };
  1310.  
  1311. /* --- Functions --- */
  1312. function handleErrCB(err, callback) {
  1313.     if (!err) return false;
  1314.     return call(callback, [new Error(err)]);
  1315. }
  1316. function handleResCB(errMessage, err, res, callback) {
  1317.     if (typeof(callback) !== 'function') return;
  1318.     res = res || {};
  1319.     if (!err && goodResponse(res)) return (callback(null, res.body), true);
  1320.  
  1321.     var e = new Error( err || errMessage );
  1322.     e.name = "ResponseError";
  1323.     e.statusCode = res.statusCode;
  1324.     e.statusMessage = res.statusMessage;
  1325.     e.response = res.body;
  1326.     return (callback(e), false);
  1327. }
  1328. function goodResponse(response) {
  1329.     return (response.statusCode / 100 | 0) === 2;
  1330. }
  1331. function stringifyError(response) {
  1332.     if (!response) return null;
  1333.     return response.statusCode + " " + response.statusMessage + "\n" + JSON.stringify(response.body);
  1334. }
  1335.  
  1336. /* - Functions - Messages - */
  1337. function sendMessage(client, to, message, callback) {
  1338.     resolveID(client, to, function(channelID) {
  1339.         client._req('post', Endpoints.MESSAGES(channelID), message, function(err, res) {
  1340.             handleResCB("Unable to send messages", err, res, callback);
  1341.         });
  1342.     });
  1343. }
  1344. function cacheMessage(cache, limit, channelID, message) {
  1345.     if (!cache[channelID]) cache[channelID] = {};
  1346.     if (limit === null) return void(cache[channelID][message.id] = message);
  1347.     var k = Object.keys(cache[channelID]);
  1348.     if (k.length > limit) delete(cache[channelID][k[0]]);
  1349.     cache[channelID][message.id] = message;
  1350. }
  1351. function generateMessage(message, embed) {
  1352.     return {
  1353.         content: String(message),
  1354.         nonce: Math.floor(Math.random() * Number.MAX_SAFE_INTEGER),
  1355.         embed: embed || {}
  1356.     };
  1357. }
  1358. function messageHeaders() {
  1359.     var r = {
  1360.         "accept": "*/*",
  1361.         "accept-language": "en-US;q=0.8",
  1362.     };
  1363.     if (isNode) {
  1364.         r["accept-encoding"] = "gzip, deflate";
  1365.         r.user_agent = "DiscordBot (https://github.com/izy521/discord.io, " + CURRENT_VERSION + ")";
  1366.         r.dnt = 1;
  1367.     }
  1368.     try {
  1369.         r.authorization = (this.bot ? "Bot " : "") + this.internals.token;
  1370.     } catch(e) {}
  1371.     return r;
  1372. }
  1373. function simulateTyping(client, to, message, time, callback) {
  1374.     if (time <= 0) return sendMessage(client, to, message, callback);
  1375.  
  1376.     client.simulateTyping(to, function() {
  1377.         setTimeout(simulateTyping, Math.min(time, 5000), client, to, message, time - 5000, callback);
  1378.     });
  1379. }
  1380. function stringifyEmoji(emoji) {
  1381.     if (typeof emoji === 'object') // if (emoji.name && emoji.id)
  1382.         return emoji.name + ':' + emoji.id;
  1383.     if (emoji.indexOf(':') > -1)
  1384.         return emoji;
  1385.     return encodeURIComponent(decodeURIComponent(emoji));
  1386. }
  1387.  
  1388. /* - Functions - Utils */
  1389. function APIRequest(method, url) {
  1390.     var data, callback, opts, req, headers = messageHeaders.call(this);
  1391.     callback = ( typeof(arguments[2]) === 'function' ? arguments[2] : (data = arguments[2], arguments[3]) );
  1392.  
  1393.     if (isNode) {
  1394.         opts = URL.parse(url);
  1395.         opts.method = method;
  1396.         opts.headers = headers;
  1397.  
  1398.         req = requesters[opts.protocol.slice(0, -1)].request(opts, function(res) {
  1399.             var chunks = [];
  1400.             res.on('data', function(c) { chunks[chunks.length] = c; });
  1401.             res.once('end', function() {
  1402.                 chunks = Buffer.concat(chunks);
  1403.                 Zlib.gunzip(chunks, function(err, uc) {
  1404.                     if (!err) uc = uc.toString();
  1405.                     try { res.body = JSON.parse(uc || chunks); } catch(e) {}
  1406.                     return callback(null, res);
  1407.                 });
  1408.             });
  1409.         });
  1410.         if (type(data) === 'object' || method.toLowerCase() === 'get') req.setHeader("Content-Type", "application/json; charset=utf-8");
  1411.         if (data instanceof Multipart) req.setHeader("Content-Type", "multipart/form-data; boundary=" + data.boundary);
  1412.         if (data) req.write( data.result || JSON.stringify(data), data.result ? 'binary' : 'utf-8' );
  1413.         req.end();
  1414.  
  1415.         return req.once('error', function(e) { return callback(e.message); });
  1416.     }
  1417.  
  1418.     req = new XMLHttpRequest();
  1419.     req.open(method.toUpperCase(), url, true);
  1420.     for (var key in headers) {
  1421.         req.setRequestHeader(key, headers[key]);
  1422.     }
  1423.     req.onreadystatechange = function() {
  1424.         if (req.readyState == 4) {
  1425.             req.statusCode = req.status;
  1426.             req.statusMessage = req.statusText;
  1427.             try {req.body = JSON.parse(req.responseText);} catch (e) { return handleErrCB(e, callback); }
  1428.             callback(null, req);
  1429.         }
  1430.     };
  1431.     if (type(data) === 'object' || method.toLowerCase() === 'get') req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
  1432.     if (data instanceof Multipart) req.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + data.boundary);
  1433.     if (data) return req[ (data.result ? "sendAsBinary" : "send") ]( data.result ? data.result : JSON.stringify(data) );
  1434.     req.send(null);
  1435. }
  1436. function send(ws, data) {
  1437.     if (ws && ws.readyState == 1) {
  1438.         ws.send(JSON.stringify(data));
  1439.     }
  1440. }
  1441. function copy(obj) {
  1442.     try {
  1443.         return JSON.parse( JSON.stringify( obj ) );
  1444.     } catch(e) {}
  1445. }
  1446. function copyKeys(from, to, omit) {
  1447.     if (!omit) omit = [];
  1448.     for (var key in from) {
  1449.         if (omit.indexOf(key) > -1) continue;
  1450.         to[key] = from[key];
  1451.     }
  1452. }
  1453. function applyProperties(object, properties) {
  1454.     properties.forEach(function(t) {
  1455.         Object.defineProperty(object, t[0], {
  1456.             configurable: true,
  1457.             writable: true,
  1458.             value: t[1]
  1459.         });
  1460.     }, object);
  1461. }
  1462. function type(v) {
  1463.     return Object.prototype.toString.call(v).match(/ (.*)]/)[1].toLowerCase();
  1464. }
  1465. function call(f, a) {
  1466.     if (typeof(f) != 'function') return;
  1467.     return f.apply(this, a);
  1468. }
  1469. function qstringify(obj) {
  1470.     //.map + .join is 7x slower!
  1471.     var i=0, s = "", k = Object.keys(obj);
  1472.     for (i;i<k.length;i++) {
  1473.         s += k[i] + "=" + obj[k[i]] + "&";
  1474.     }
  1475.     return "?" + s.slice(0, -1);
  1476. }
  1477. function emit(client, message) {
  1478.     if (!message.t) return;
  1479.     var t = message.t.split("_"), i = 1, args = [t[0].toLowerCase()];
  1480.  
  1481.     for (i; i<t.length; i++) {
  1482.         args[0] += t[i][0] + t[i].slice(1).toLowerCase();
  1483.     }
  1484.     for (i=2; i<arguments.length; i++) {
  1485.         args.push(arguments[i]);
  1486.     }
  1487.     args.push(message);
  1488.     client.emit.apply(client, args);
  1489. }
  1490. function decompressWSMessage(m, f) {
  1491.     f = f || {};
  1492.     return f.binary ? JSON.parse(Zlib.inflateSync(m).toString()) : JSON.parse(m);
  1493. }
  1494. function removeAllListeners(emitter, type) {
  1495.     if (!emitter) return;
  1496.     var e = emitter._evts, i, k, o, s, z;
  1497.     if (isNode) return type ? emitter.removeAllListeners(type) : emitter.removeAllListeners();
  1498.  
  1499.     if (type && e[type]) {
  1500.         for (i=0; i<e[type].length; i++) {
  1501.             emitter.removeListener(type, e[type][i]);
  1502.         }
  1503.     }
  1504.  
  1505.     if (!type) {
  1506.         k = Object.keys(e);
  1507.         for (o=0; o<k.length; o++) {
  1508.             s = e[ k[o] ];
  1509.             for (z=0; z<s.length; z++) {
  1510.                 emitter.removeListener(k[o], s[z]);
  1511.             }
  1512.         }
  1513.     }
  1514. }
  1515. function colorFromRole(server, member) {
  1516.     return member.roles.reduce(function(array, ID) {
  1517.         var role = server.roles[ID];
  1518.         if (!role) return array;
  1519.         return role.position > array[0] && role.color ? [role.position, role.color] : array;
  1520.     }, [-1, null])[1];
  1521. }
  1522.  
  1523. function givePermission(bit, permissions) {
  1524.     return permissions | (1 << bit);
  1525. }
  1526. function removePermission(bit, permissions) {
  1527.     return permissions & ~(1 << bit);
  1528. }
  1529. function hasPermission(bit, permissions) {
  1530.     return ((permissions >> bit) & 1) == 1;
  1531. }
  1532. //For the Getters and Setters
  1533. function getPerm(bit) {
  1534.     return function() {
  1535.         return ((this._permissions >> bit) & 1) == 1;
  1536.     };
  1537. }
  1538. function setPerm(bit) {
  1539.     return function(v) {
  1540.         if (v === true) return this._permissions |= (1 << (bit));
  1541.         if (v === false) return this._permissions &= ~(1 << bit);
  1542.     };
  1543. }
  1544.  
  1545. function getServerInfo(client, servArr) {
  1546.     for (var server=0; server<servArr.length; server++) {
  1547.         client.servers[servArr[server].id] = new Server(client, servArr[server]);
  1548.     }
  1549. }
  1550. function getDirectMessages(client, DMArray) {
  1551.     for (var DM=0; DM<DMArray.length; DM++) {
  1552.         client.directMessages[DMArray[DM].id] = new DMChannel(client._uIDToDM, DMArray[DM]);
  1553.     }
  1554. }
  1555. function resolveID(client, ID, callback) {
  1556.     /*Get channel from ServerID, ChannelID or UserID.
  1557.     Only really used for sendMessage and uploadFile.*/
  1558.     //Callback used instead of return because requesting seems necessary.
  1559.  
  1560.     if (client._uIDToDM[ID]) return callback(client._uIDToDM[ID]);
  1561.     //If it's a UserID, and it's in the UserID : ChannelID cache, use the found ChannelID
  1562.  
  1563.     //If the ID isn't in the UserID : ChannelID cache, let's try seeing if it belongs to a user.
  1564.     if (client.users[ID]) return client.createDMChannel(ID, function(err, res) {
  1565.         if (err) return console.log("Internal ID resolver error: " + err);
  1566.         callback(res.id);
  1567.     });
  1568.  
  1569.     return callback(ID); //Finally, the ID must not belong to a User, so send the message directly to it, as it must be a Channel's.
  1570. }
  1571. function resolveEvent(e) {
  1572.     return e.detail || ([e.data][0] ? [e.data] : [e.code]);
  1573. }
  1574.  
  1575. /* --- Initializing --- */
  1576. function init(client, opts) {
  1577.     client.servers = {};
  1578.     client.channels = {};
  1579.     client.users = {};
  1580.     client.directMessages = {};
  1581.     client.internals = {
  1582.         oauth: {},
  1583.         version: CURRENT_VERSION,
  1584.         settings: {}
  1585.     };
  1586.     client._connecting = true;
  1587.  
  1588.     setupPing(client.internals);
  1589.     return getToken(client, opts);
  1590. }
  1591. function getToken(client, opts) {
  1592.     if (opts.token) return getGateway(client, opts, opts.token);
  1593.     if (!isNode) {
  1594.         //Read from localStorage? Sounds like a bad idea, but I'll leave this here.
  1595.     }
  1596. }
  1597. function getGateway(client, opts, token) {
  1598.     client.internals.token = token;
  1599.  
  1600.     return APIRequest('get', Endpoints.GATEWAY, function (err, res) {
  1601.         if (err || !goodResponse(res)) {
  1602.             client._connecting = false;
  1603.             return client.emit("disconnect", "Error GETing gateway:\n" + stringifyError(res), 0);
  1604.         }
  1605.         return startConnection(client, opts, (res.body.url + "/?encoding=json&v=" + GATEWAY_VERSION));
  1606.     });
  1607. }
  1608. function startConnection(client, opts, gateway) {
  1609.     client._ws = new Websocket(gateway);
  1610.     client.internals.gatewayUrl = gateway;
  1611.  
  1612.     client._ws.once('open', handleWSOpen.bind(client, opts));
  1613.     client._ws.once('close', handleWSClose.bind(client));
  1614.     client._ws.once('error', handleWSClose.bind(client));
  1615.     client._ws.on('message', handleWSMessage.bind(client, opts));
  1616. }
  1617. function getOfflineUsers(client, servArr, callback) {
  1618.     if (!servArr[0]) return call(callback);
  1619.  
  1620.     send(client._ws, {
  1621.                 op: 8,
  1622.                 d: {
  1623.                     guild_id: servArr.splice(0, 50),
  1624.                     query: "",
  1625.                     limit: 0
  1626.                 }
  1627.             }
  1628.     );
  1629.     return setTimeout( getOfflineUsers, 0, client, servArr, callback );
  1630. }
  1631. function checkForAllServers(client, ready, message) {
  1632.     var all = Object.keys(client.servers).every(function(s) {
  1633.         return !client.servers[s].unavailable;
  1634.     });
  1635.     if (all || ready[0]) return client.emit('ready', message);
  1636.     return setTimeout(checkForAllServers, 0, client, ready, message);
  1637. }
  1638. function setupPing(obj) {
  1639.     applyProperties(obj, [
  1640.         ["_pings", []],
  1641.         ["_lastHB", 0]
  1642.     ]);
  1643.     Object.defineProperty(obj, 'ping', {
  1644.         get: function() {
  1645.             return ((obj._pings.reduce(function(p, c) { return p + c; }, 0) / obj._pings.length) || 0) | 0;
  1646.         },
  1647.         set: function() {}
  1648.     });
  1649. }
  1650.  
  1651. /* - Functions - Websocket Handling - */
  1652. function handleWSOpen(opts) {
  1653.     var ident = {
  1654.         "op":2,
  1655.         "d": {
  1656.             "token": this.internals.token,
  1657.             "v": GATEWAY_VERSION,
  1658.             "compress": isNode && !!Zlib.inflateSync,
  1659.             "large_threshold": LARGE_THRESHOLD,
  1660.             "properties": {
  1661.                 "$os": isNode ? require('os').platform() : navigator.platform,
  1662.                 "$browser":"discord.io",
  1663.                 "$device":"discord.io",
  1664.                 "$referrer":"",
  1665.                 "$referring_domain":""
  1666.             },
  1667.         }
  1668.     };
  1669.     this._connecting = false;
  1670.     if (type(opts.shard) === 'array'   &&
  1671.         opts.shard.length === 2        &&
  1672.         opts.shard[0] <= opts.shard[1] &&
  1673.         opts.shard[1] > 1
  1674.     ) ident.d.shard = opts.shard;
  1675.  
  1676.     send(this._ws, ident);
  1677. }
  1678. function handleWSMessage(opts, data, flags) {
  1679.     var message = decompressWSMessage(data, flags);
  1680.     var _data = message.d;
  1681.     var client = this, user, server, members, member,
  1682.     key, old, userItem, chItem, voiceSession,
  1683.     userID, serverID, channelID, currentVCID;
  1684.     client.internals.sequence = message.s;
  1685.  
  1686.     if (message.op === 10) {
  1687.         //Start keep-alive interval
  1688.         //Disconnect the client if no ping has been received
  1689.         //in 15 seconds (I think that's a decent duration)
  1690.         client.presenceStatus = 'online';
  1691.         client.connected = true;
  1692.  
  1693.         client._mainKeepAlive = setInterval(function() {
  1694.             client.internals.heartbeat = setTimeout(client.disconnect.bind(client), 15e3);
  1695.             client.internals._lastHB = Date.now();
  1696.             send(client._ws, {op: 1, d: client.internals.sequence});
  1697.         }, _data.heartbeat_interval);
  1698.     }
  1699.  
  1700.     if (message.op === 11) {
  1701.         clearTimeout(client.internals.heartbeat);
  1702.         client.internals._pings.unshift(Date.now() - client.internals._lastHB);
  1703.         client.internals._pings = client.internals._pings.slice(0, 10);
  1704.     }
  1705.  
  1706.     //Events
  1707.     client.emit('any', message);
  1708.     client.emit('debug', message);
  1709.     switch (message.t) {
  1710.         case "READY":
  1711.             copyKeys(_data.user, client);
  1712.             client.internals.sessionID = _data.session_id;
  1713.  
  1714.             getServerInfo(client, _data.guilds);
  1715.             getDirectMessages(client, _data.private_channels);
  1716.  
  1717.             if (client.bot) client.getOauthInfo(function(err, res) {
  1718.                 if (err) return console.log(err);
  1719.                 client.internals.oauth = res;
  1720.                 client.inviteURL = "https://discordapp.com/oauth2/authorize?client_id=" + res.id + "&scope=bot";
  1721.             });
  1722.             if (!client.bot) client.getAccountSettings(function(err, res) {
  1723.                 if (err) return console.log(err);
  1724.                 client.internals.settings = res;
  1725.             });
  1726.  
  1727.             return (function() {
  1728.                 var ready = [false];
  1729.                 setTimeout(function() { ready[0] = true; }, 3500);
  1730.                 checkForAllServers(client, ready, message);
  1731.             })();
  1732.         case "MESSAGE_CREATE":
  1733.             client.emit('message', _data.author.username, _data.author.id, _data.channel_id, _data.content, message);
  1734.             emit(client, message, _data.author.username, _data.author.id, _data.channel_id, _data.content);
  1735.             return cacheMessage(client._messageCache, client._messageCacheLimit, _data.channel_id, _data);
  1736.         case "MESSAGE_UPDATE":
  1737.             try {
  1738.                 emit(client, message, client._messageCache[_data.channel_id][_data.id], _data);
  1739.             } catch (e) { emit(client, message, undefined, _data); }
  1740.             return cacheMessage(client._messageCache, client._messageCacheLimit, _data.channel_id, _data);
  1741.         case "PRESENCE_UPDATE":
  1742.             if (!_data.guild_id) break;
  1743.  
  1744.             serverID = _data.guild_id;
  1745.             userID = _data.user.id;
  1746.  
  1747.             if (!client.users[userID]) client.users[userID] = new User(_data.user);
  1748.  
  1749.             user = client.users[userID];
  1750.             member = client.servers[serverID].members[userID] || {};
  1751.  
  1752.             copyKeys(_data.user, user);
  1753.             user.game = _data.game;
  1754.  
  1755.             copyKeys(_data, member, ['user', 'guild_id', 'game']);
  1756.             client.emit('presence', user.username, user.id, member.status, user.game, message);
  1757.             break;
  1758.         case "USER_UPDATE":
  1759.             copyKeys(_data, client);
  1760.             break;
  1761.         case "USER_SETTINGS_UPDATE":
  1762.             copyKeys(_data, client.internals);
  1763.             break;
  1764.         case "GUILD_CREATE":
  1765.             /*The lib will attempt to create the server using the response from the
  1766.             REST API, if the user using the lib creates the server. There are missing keys, however.
  1767.             So we still need this GUILD_CREATE event to fill in the blanks.
  1768.             If It's not our created server, then there will be no server with that ID in the cache,
  1769.             So go ahead and create one.*/
  1770.             client.servers[_data.id] = new Server(client, _data);
  1771.             return emit(client, message, client.servers[_data.id]);
  1772.         case "GUILD_UPDATE":
  1773.             old = copy(client.servers[_data.id]);
  1774.             Server.update(client, _data);
  1775.             return emit(client, message, old, client.servers[_data.id]);
  1776.         case "GUILD_DELETE":
  1777.             emit(client, message, client.servers[_data.id]);
  1778.             return delete(client.servers[_data.id]);
  1779.         case "GUILD_MEMBER_ADD":
  1780.             client.users[_data.user.id] = new User(_data.user);
  1781.             client.servers[_data.guild_id].members[_data.user.id] = new Member(client, client.servers[_data.guild_id], _data);
  1782.             client.servers[_data.guild_id].member_count += 1;
  1783.             return emit(client, message, client.servers[_data.guild_id].members[_data.user.id]);
  1784.         case "GUILD_MEMBER_UPDATE":
  1785.             old = copy(client.servers[_data.guild_id].members[_data.user.id]);
  1786.             Member.update(client, client.servers[_data.guild_id], _data);
  1787.             return emit(client, message, old, client.servers[_data.guild_id].members[_data.user.id]);
  1788.         case "GUILD_MEMBER_REMOVE":
  1789.             if (_data.user && _data.user.id === client.id) return;
  1790.             client.servers[_data.guild_id].member_count -= 1;
  1791.             emit(client, message, client.servers[_data.guild_id].members[_data.user.id]);
  1792.             return delete(client.servers[_data.guild_id].members[_data.user.id]);
  1793.         case "GUILD_ROLE_CREATE":
  1794.             client.servers[_data.guild_id].roles[_data.role.id] = new Role(_data.role);
  1795.             return emit(client, message, client.servers[_data.guild_id].roles[_data.role.id]);
  1796.         case "GUILD_ROLE_UPDATE":
  1797.             server = client.servers[_data.guild_id];
  1798.             old = copy(server.roles[_data.role.id]);
  1799.             Role.update(server, _data);
  1800.             Object.keys(server.members).forEach(function(memberID) {
  1801.                 var member = server.members[memberID];
  1802.                 if ( member.roles.indexOf(_data.role.id) < 0 ) return;
  1803.                 member.color = colorFromRole(server, member);
  1804.             });
  1805.             return emit(client, message, old, server.roles[_data.role.id]);
  1806.         case "GUILD_ROLE_DELETE":
  1807.             emit(client, message, client.servers[_data.guild_id].roles[_data.role_id]);
  1808.             return delete(client.servers[_data.guild_id].roles[_data.role_id]);
  1809.         case "CHANNEL_CREATE":
  1810.             channelID = _data.id;
  1811.  
  1812.             if (_data.is_private) {
  1813.                 if (client.directMessages[channelID]) return;
  1814.                 client.directMessages[channelID] = new DMChannel(client._uIDToDM, _data);
  1815.                 return emit(client, message, client.directMessages[channelID]);
  1816.             }
  1817.  
  1818.             if (client.channels[channelID]) return;
  1819.             client.channels[channelID] = new Channel(client, client.servers[_data.guild_id], _data);
  1820.             return emit(client, message, client.channels[channelID]);
  1821.         case "CHANNEL_UPDATE":
  1822.             old = copy(client.channels[_data.id]);
  1823.             Channel.update(client, _data);
  1824.             return emit(client, message, old, client.channels[_data.id]);
  1825.         case "CHANNEL_DELETE":
  1826.             if (_data.is_private === true) {
  1827.                 emit(client, message, client.directMessages[_data.id]);
  1828.                 delete(client.directMessages[_data.id]);
  1829.                 return delete(client._uIDToDM[_data.recipient.id]);
  1830.             }
  1831.             emit(client, message, client.servers[_data.guild_id].channels[_data.id]);
  1832.             delete(client.servers[_data.guild_id].channels[_data.id]);
  1833.             return delete(client.channels[_data.id]);
  1834.         case "GUILD_EMOJIS_UPDATE":
  1835.             old = copy(client.servers[_data.guild_id].emojis);
  1836.             Emoji.update(client.servers[_data.guild_id], _data.emojis);
  1837.             return emit(client, message, old, client.servers[_data.guild_id].emojis);
  1838.     case "VOICE_STATE_UPDATE":
  1839.       console.log(_data);
  1840.             serverID = _data.guild_id;
  1841.             channelID = _data.channel_id;
  1842.             userID = _data.user_id;
  1843.       server = client.servers[serverID];
  1844.       let mute = _data.mute;
  1845.       let deaf = _data.deaf;
  1846.       let selfMute = _data.self_mute;
  1847.       let selfDeaf = _data.self_deaf;
  1848.  
  1849.             try {
  1850.                 currentVCID = server.members[userID].voice_channel_id;
  1851.                 if (currentVCID) delete( server.channels[currentVCID].members[userID] );
  1852.                 if (channelID) server.channels[channelID].members[userID] = _data;
  1853.         server.members[userID].voice_channel_id = channelID;
  1854.         mute || selfMute ? server.members[userID].mute = true : server.members[userID].mute = false;
  1855.         deaf || selfDeaf ? server.members[userID].deaf = true : server.members[userID].deaf = false;
  1856.             } catch(e) {}
  1857.  
  1858.             if (userID === client.id) {
  1859.                 if (!server.voiceSession) {
  1860.                     server.voiceSession = getVoiceSession(client, channelID, server);
  1861.                 }
  1862.                 if (channelID === null) {
  1863.                     leaveVoiceChannel(client, server.voiceSession.channelID);
  1864.                     return void(server.voiceSession = null);
  1865.                 }
  1866.                 if (channelID != server.voiceSession.channelID) {
  1867.                     delete( client._vChannels[server.voiceSession.channelID] );
  1868.                     getVoiceSession(client, channelID, server).channelID = channelID;
  1869.                 }
  1870.  
  1871.                 server.voiceSession.session = _data.session_id;
  1872.             }
  1873.             break;
  1874.         case "VOICE_SERVER_UPDATE":
  1875.             serverID = _data.guild_id;
  1876.             server = client.servers[serverID];
  1877.             server.voiceSession.token = _data.token;
  1878.             server.voiceSession.severID = serverID;
  1879.             server.voiceSession.endpoint = _data.endpoint;
  1880.             joinVoiceChannel(client, server.voiceSession);
  1881.             break;
  1882.         case "GUILD_MEMBERS_CHUNK":
  1883.             serverID = _data.guild_id;
  1884.             if (!client.servers[serverID].members) client.servers[serverID].members = {};
  1885.  
  1886.             _data.members.forEach(function(member) {
  1887.                 var uID = member.user.id;
  1888.                 var members = client.servers[serverID].members;
  1889.                 if (members[uID]) return;
  1890.                 if (!client.users[uID]) client.users[uID] = new User(member.user);
  1891.                 members[uID] = new Member(client, client.servers[serverID], member);
  1892.             });
  1893.             var all = Object.keys(client.servers).every(function(server) {
  1894.                 server = client.servers[server];
  1895.                 return server.member_count === Object.keys(server.members).length;
  1896.             });
  1897.  
  1898.             if (all) return client.emit("allUsers");
  1899.             break;
  1900.         case "GUILD_SYNC":
  1901.             _data.members.forEach(function(member) {
  1902.                 var uID = member.user.id;
  1903.                 if (!client.users[uID]) client.users[uID] = new User(member.user);
  1904.                 client.servers[_data.id].members[uID] = new Member(client, client.servers[_data.id], member);
  1905.             });
  1906.  
  1907.             _data.presences.forEach(function(presence) {
  1908.                 var uID = presence.user.id;
  1909.                 var members = client.servers[_data.id].members;
  1910.                 if (!members[uID]) return void(new User(presence.user));
  1911.                 delete(presence.user);
  1912.                 copyKeys(presence, members[uID]);
  1913.             });
  1914.             client.servers[_data.id].large = _data.large;
  1915.             break;
  1916.     }
  1917.     return emit(client, message);
  1918. }
  1919. function handleWSClose(code, data) {
  1920.     var client = this;
  1921.     var eMsg = Discord.Codes.WebSocket[code];
  1922.  
  1923.     clearInterval(client._mainKeepAlive);
  1924.     client.connected = false;
  1925.     client.presenceStatus = "offline";
  1926.  
  1927.     removeAllListeners(client._ws, 'message');
  1928.     client._ws = null;
  1929.  
  1930.     client.emit("disconnect", eMsg, code);
  1931. }
  1932.  
  1933. /* - Functions - Voice - */
  1934. function joinVoiceChannel(client, voiceSession) {
  1935.     var vWS, vUDP, endpoint = voiceSession.endpoint.split(":")[0];
  1936.     //handleVoiceChannelChange(client, voiceSession);
  1937.  
  1938.     voiceSession.ws = {};
  1939.     voiceSession.udp = {};
  1940.     voiceSession.members = {};
  1941.     voiceSession.error = null;
  1942.     voiceSession.ready = false;
  1943.     voiceSession.joined = false;
  1944.     voiceSession.translator = {};
  1945.     voiceSession.wsKeepAlive = null;
  1946.     voiceSession.udpKeepAlive = null;
  1947.     voiceSession.keepAlivePackets = 0;
  1948.     voiceSession.emitter = new Emitter();
  1949.     if (isNode) voiceSession.keepAliveBuffer = new Buffer(8).fill(0);
  1950.     vWS = voiceSession.ws.connection = new Websocket("wss://" + endpoint);
  1951.  
  1952.     if (isNode) return DNS.lookup(endpoint, function(err, address) {
  1953.         if (err) return void(voiceSession.error = err);
  1954.  
  1955.         voiceSession.address = address;
  1956.         vUDP = voiceSession.udp.connection = UDP.createSocket("udp4");
  1957.  
  1958.         vUDP.bind({exclusive: true});
  1959.         vUDP.once('message', handleUDPMessage.bind(client, voiceSession));
  1960.  
  1961.         vWS.once('open',  handlevWSOpen.bind(client, voiceSession));
  1962.         vWS.on('message', handlevWSMessage.bind(client, voiceSession));
  1963.         vWS.once('close', handlevWSClose.bind(client, voiceSession));
  1964.     });
  1965.  
  1966.     vWS.once('open',  handlevWSOpen.bind(client, voiceSession));
  1967.     vWS.on('message', handlevWSMessage.bind(client, voiceSession));
  1968.     vWS.once('close', handlevWSClose.bind(client, voiceSession));
  1969.     return void(voiceSession.joined = true);
  1970. }
  1971.  
  1972. function leaveVoiceChannel(client, channelID, callback) {
  1973.     if (!client._vChannels[channelID]) return;
  1974.  
  1975.     try {
  1976.         client._vChannels[channelID].ws.connection.close();
  1977.         client._vChannels[channelID].udp.connection.close();
  1978.     } catch(e) {}
  1979.  
  1980.     send(client._ws, {
  1981.         op:4,
  1982.         d: {
  1983.             guild_id: client.channels[channelID].guild_id,
  1984.             channel_id: null,
  1985.             self_mute: false,
  1986.             self_deaf: false
  1987.         }
  1988.     });
  1989.  
  1990.     delete(client._vChannels[channelID]);
  1991.     return call(callback, [null]);
  1992. }
  1993.  
  1994. function keepUDPAlive(VS) {
  1995.     if (!VS.keepAliveBuffer) return;
  1996.  
  1997.     if (VS.keepAlivePackets > 4294967294) {
  1998.         VS.keepAlivePackets = 0;
  1999.         VS.keepAliveBuffer.fill(0);
  2000.     }
  2001.     VS.keepAliveBuffer.writeUIntLE(++VS.keepAlivePackets, 0, 6);
  2002.     try {
  2003.         return VS.udp.connection.send(VS.keepAliveBuffer, 0, VS.keepAliveBuffer.length, VS.ws.port, VS.address);
  2004.     } catch(e) {}
  2005. }
  2006.  
  2007. function getVoiceSession(client, channelID, server) {
  2008.     return client._vChannels[channelID] ?
  2009.         client._vChannels[channelID] :
  2010.         client._vChannels[channelID] = (server && server.voiceSession) || {
  2011.             serverID: (server && server.id) || null,
  2012.             channelID: channelID,
  2013.             token: null,
  2014.             session: null,
  2015.             endpoint: null
  2016.         }
  2017. }
  2018.  
  2019. function checkVoiceReady(voiceSession, callback) {
  2020.     return setTimeout(function() {
  2021.         if (voiceSession.error) return call(callback, [error]);
  2022.         if (voiceSession.joined) return call(callback, [null, voiceSession.emitter]);
  2023.         return checkVoiceReady(voiceSession, callback);
  2024.     }, 1);
  2025. }
  2026.  
  2027. /* - Functions - Voice - Handling - */
  2028.  
  2029. function handlevWSOpen(voiceSession) {
  2030.     send(voiceSession.ws.connection, {
  2031.         op: 0,
  2032.         d: {
  2033.             server_id: voiceSession.serverID,
  2034.             user_id: this.id,
  2035.             session_id: voiceSession.session,
  2036.             token: voiceSession.token
  2037.         }
  2038.     });
  2039. }
  2040. function handlevWSMessage(voiceSession, vMessage, vFlags) {
  2041.     var client = this, vData = decompressWSMessage(vMessage, vFlags);
  2042.     switch (vData.op) {
  2043.         case 2: //Ready (Actually means you're READY to initiate the UDP connection)
  2044.             copyKeys(vData.d, voiceSession.ws);
  2045.             voiceSession.wsKeepAlive = setInterval(send, vData.d.heartbeat_interval, voiceSession.ws.connection, { "op": 3, "d": null });
  2046.  
  2047.             if (!isNode) return;
  2048.  
  2049.             var udpDiscPacket = new Buffer(70);
  2050.             udpDiscPacket.writeUIntBE(vData.d.ssrc, 0, 4);
  2051.             voiceSession.udp.connection.send(
  2052.                 udpDiscPacket, 0, udpDiscPacket.length, vData.d.port, voiceSession.address,
  2053.                 function(err) { if (err) {leaveVoiceChannel(client, voiceSession.channelID); handleErrCB("UDP discovery error", callback); } }
  2054.             );
  2055.  
  2056.             voiceSession.udpKeepAlive = setInterval(keepUDPAlive, 5000, voiceSession);
  2057.             break;
  2058.         case 4: //Session Discription (Actually means you're ready to send audio... stupid Discord Devs :I)
  2059.             voiceSession.selectedMode = vData.d.mode;
  2060.             voiceSession.secretKey = vData.d.secret_key;
  2061.             voiceSession.joined = true;
  2062.             voiceSession.ready = true;
  2063.             break;
  2064.         case 5: //Speaking (At least this isn't confusing!)
  2065.             voiceSession.emitter.emit('speaking', vData.d.user_id, vData.d.ssrc, vData.d.speaking);
  2066.             break;
  2067.     }
  2068. }
  2069. function handlevWSClose(voiceSession) {
  2070.     //Kill encoder and decoders
  2071.     var audio = voiceSession.audio, members = voiceSession.members;
  2072.     audio && audio._systemEncoder.kill();
  2073.     audio && audio._mixedDecoder.destroy();
  2074.  
  2075.     Object.keys(members).forEach(function(ID) {
  2076.         var member = members[ID];
  2077.         if (member.decoder) member.decoder.destroy();
  2078.     });
  2079.  
  2080.     //Clear intervals and remove listeners
  2081.     clearInterval(voiceSession.wsKeepAlive);
  2082.     clearInterval(voiceSession.udpKeepAlive);
  2083.     //TODO: Emit ServerID and Channel ID. For v3
  2084.     voiceSession.emitter.emit('disconnect', voiceSession.channelID);
  2085.     removeAllListeners(voiceSession.emitter);
  2086.     removeAllListeners(voiceSession.udp.connection, 'message');
  2087.     removeAllListeners(voiceSession.ws.connection, 'message');
  2088.     return void(voiceSession.emitter = null);
  2089. }
  2090.  
  2091. function handleUDPMessage(voiceSession, msg, rinfo) {
  2092.     var buffArr = JSON.parse(JSON.stringify(msg)).data, client = this, vDiscIP = "", vDiscPort;
  2093.     for (var i=4; i<buffArr.indexOf(0, i); i++) {
  2094.         vDiscIP += String.fromCharCode(buffArr[i]);
  2095.     }
  2096.     vDiscPort = msg.readUIntLE(msg.length - 2, 2).toString(10);
  2097.  
  2098.     var wsDiscPayload = {
  2099.         "op":1,
  2100.         "d":{
  2101.             "protocol":"udp",
  2102.             "data":{
  2103.                 "address": vDiscIP,
  2104.                 "port": Number(vDiscPort),
  2105.                 "mode": voiceSession.ws.modes[1] //'xsalsa20_poly1305'
  2106.             }
  2107.         }
  2108.     };
  2109.     send(voiceSession.ws.connection, wsDiscPayload);
  2110. }
  2111.  
  2112. /* - Functions - Voice - AudioCallback - */
  2113. function AudioCB(voiceSession, audioChannels, encoder, maxStreamSize) {
  2114.     //With the addition of the new Stream API, `playAudioFile`, `stopAudioFile` and `send`
  2115.     //will be removed. However they're deprecated for now, hence the code repetition.
  2116.     if (maxStreamSize && !Opus) Opus = require('cjopus');
  2117.     Stream.Duplex.call(this);
  2118.     var ACBI = this,
  2119.     bHandleIncomingAudio = handleIncomingAudio.bind(this);
  2120.  
  2121.     this.audioChannels = audioChannels;
  2122.     this.members = voiceSession.members;
  2123.  
  2124.     applyProperties(this, [
  2125.         ["_sequence", 0],
  2126.         ["_timestamp", 0],
  2127.         ["_exited", false],
  2128.         ["_readable", false],
  2129.         ["_streamRef", null],
  2130.         ["_startTime", null],
  2131.         ["_systemEncoder", null],
  2132.         ["_playingAudioFile", false],
  2133.         ["_voiceSession", voiceSession],
  2134.         ["_port", voiceSession.ws.port],
  2135.         ["_address", voiceSession.address],
  2136.         ["_decodeNonce", new Uint8Array(24)],
  2137.         ["_vUDP", voiceSession.udp.connection],
  2138.         ["_secretKey", new Uint8Array(voiceSession.secretKey)],
  2139.         ["_mixedDecoder", !Opus ? null : new Opus.OpusEncoder( 48000, audioChannels )],
  2140.     ]);
  2141.  
  2142.     var enc = this._systemEncoder = ChildProc.spawn(encoder, [
  2143.         '-i', 'pipe:0',
  2144.         '-map', '0:a',
  2145.         '-acodec', 'libopus',
  2146.         '-f', 'data',
  2147.         '-sample_fmt', 's16',
  2148.         '-vbr', 'off',
  2149.         '-compression_level', '10',
  2150.         '-ar', '48000',
  2151.         '-ac', ACBI.audioChannels,
  2152.         '-b:a', '128000',
  2153.         'pipe:1'
  2154.     ], {stdio: ['pipe', 'pipe', 'ignore']});
  2155.  
  2156.     enc.stdout.once('error', function(e) {
  2157.         enc.stdout.emit('end');
  2158.         enc.kill();
  2159.         ACBI._exited = true;
  2160.     });
  2161.     enc.stdout.on('readable', function() {
  2162.         if (ACBI._readable) return;
  2163.  
  2164.         ACBI._readable = true;
  2165.         send(ACBI._voiceSession.ws.connection, ACBP._speakingStart);
  2166.         ACBI._startTime = new Date().getTime();
  2167.         prepareAudio(ACBI, enc.stdout, 1);
  2168.     });
  2169.  
  2170.     this._write = enc.stdin.write.bind(enc.stdin);
  2171.     this._read = function() {};
  2172.  
  2173.     if (maxStreamSize) {
  2174.         voiceSession.ws.connection.on('message', function(data, flags) {
  2175.             data = decompressWSMessage(data, flags);
  2176.  
  2177.             if (data.op !== 5) return;
  2178.             if (!voiceSession.members[data.d.user_id]) {
  2179.                 voiceSession.members[data.d.user_id] = new Stream.Readable({
  2180.                     highWaterMark: maxStreamSize,
  2181.                     read: function(s) {}
  2182.                 });
  2183.                 voiceSession.members[data.d.user_id].decoder = new Opus.OpusEncoder( 48000, this.audioChannels );
  2184.             }
  2185.  
  2186.             voiceSession.members[data.d.user_id].ssrc = data.d.ssrc;
  2187.             voiceSession.translator[data.d.ssrc] = voiceSession.members[data.d.user_id];
  2188.         });
  2189.         this._vUDP.on('message', bHandleIncomingAudio);
  2190.     }
  2191. }
  2192. if (isNode) Util.inherits(AudioCB, Stream.Duplex);
  2193. AudioCB.VoicePacket = (function() {
  2194.     if (!isNode) return;
  2195.     var header = new Buffer(12), nonce = new Uint8Array(24), output = new Buffer(2048);
  2196.  
  2197.     header[0] = 0x80;
  2198.     header[1] = 0x78;
  2199.  
  2200.     return function(packet, ssrc, sequence, timestamp, key) {
  2201.         header.writeUIntBE(sequence, 2, 2);
  2202.         header.writeUIntBE(timestamp, 4, 4);
  2203.         header.writeUIntBE(ssrc, 8, 4);
  2204.         //<Buffer 80 78 00 01 00 00 03 c0 00 00 00 01>
  2205.         nonce.set(header);
  2206.         //<Buffer 80 78 00 01 00 00 03 c0 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00>
  2207.  
  2208.         var encrypted = new Buffer(
  2209.             NACL.secretbox(
  2210.                 new Uint8Array(packet),
  2211.                 nonce,
  2212.                 key
  2213.             )
  2214.         );
  2215.  
  2216.         header.copy(output);
  2217.         encrypted.copy(output, 12);
  2218.  
  2219.         return output.slice(0, header.length + encrypted.length);
  2220.     };
  2221. })();
  2222. var ACBP = AudioCB.prototype;
  2223. ACBP._speakingStart = { "op":5, "d":{ "speaking": true, "delay": 0 } };
  2224. ACBP._speakingEnd = { "op":5, "d":{ "speaking": false, "delay":0 } };
  2225.  
  2226. //To Be Removed
  2227. ACBP.playAudioFile = function(location, callback) {
  2228.     if (!this._mixedDecoder) {
  2229.         if (!Opus) Opus = require('cjopus');
  2230.         this._mixedDecoder = new Opus.OpusEncoder( 48000, this.audioChannels );
  2231.     }
  2232.  
  2233.     if (this._playingAudioFile) return handleErrCB("There is already a file being played.", callback);
  2234.     var encs = ['ffmpeg', 'avconv'], selection, enc, ACBI = this;
  2235.  
  2236.     this._playingAudioFile = true;
  2237.     selection = chooseAudioEncoder(encs);
  2238.  
  2239.     if (!selection) return console.log("You need either 'ffmpeg' or 'avconv' and they need to be added to PATH");
  2240.  
  2241.     enc = ChildProc.spawn(selection , [
  2242.         '-i', location,
  2243.         '-f', 's16le',
  2244.         '-ar', '48000',
  2245.         '-ac', ACBI.audioChannels,
  2246.         'pipe:1'
  2247.     ], {stdio: ['pipe', 'pipe', 'ignore']});
  2248.     enc.stdout.once('end', function() {
  2249.         enc.kill();
  2250.         send(ACBI._voiceSession.ws.connection, ACBP._speakingEnd);
  2251.         ACBI._playingAudioFile = false;
  2252.         ACBI.emit('fileEnd');
  2253.     });
  2254.     enc.stdout.once('error', function(e) {
  2255.         enc.stdout.emit('end');
  2256.     });
  2257.     enc.stdout.once('readable', function() {
  2258.         send(ACBI._voiceSession.ws.connection, ACBP._speakingStart);
  2259.         ACBI._startTime = new Date().getTime();
  2260.         prepareAudioOld(ACBI, enc.stdout, 1);
  2261.     });
  2262.     this._streamRef = enc;
  2263. };
  2264. //To Be Removed
  2265. ACBP.stopAudioFile = function(callback) {
  2266.     if (!this._playingAudioFile) return handleErrCB("There is no file being played", callback);
  2267.  
  2268.     this._streamRef.stdout.end();
  2269.     this._streamRef.kill();
  2270.     this._playingAudioFile = false;
  2271.  
  2272.     call(callback);
  2273. };
  2274. //To Be Removed
  2275. ACBP.send = function(stream) {
  2276.     if (!this._mixedDecoder) {
  2277.         if (!Opus) Opus = require('cjopus');
  2278.         this._mixedDecoder = new Opus.OpusEncoder( 48000, this.audioChannels );
  2279.     }
  2280.     send(this._voiceSession.ws.connection, this._speakingStart);
  2281.     this._startTime = new Date().getTime();
  2282.     prepareAudioOld(this, stream, 1);
  2283. };
  2284.  
  2285. function prepareAudio(ACBI, readableStream, cnt) {
  2286.     var data = readableStream.read( 320 ) || readableStream.read(); //(128 [kb] * 20 [frame_size]) / 8 == 320
  2287.  
  2288.     if (!data) {
  2289.         send(ACBI._voiceSession.ws.connection, ACBP._speakingEnd);
  2290.         ACBI._readable = false;
  2291.         return ACBI.emit('done');
  2292.     }
  2293.  
  2294.     return setTimeout(function() {
  2295.         sendAudio(ACBI, data);
  2296.         prepareAudio(ACBI, readableStream, cnt + 1);
  2297.     }, 20 + ( (ACBI._startTime + cnt * 20) - Date.now() ));
  2298. }
  2299.  
  2300. //To Be Removed
  2301. function prepareAudioOld(ACBI, readableStream) {
  2302.     var done = false;
  2303.  
  2304.     readableStream.on('end', function() {
  2305.         done = true;
  2306.         send(ACBI._voiceSession.ws.connection, ACBP._speakingEnd);
  2307.     });
  2308.  
  2309.     _prepareAudio(ACBI, readableStream, 1);
  2310.  
  2311.     function _prepareAudio(ACBI, readableStream, cnt) {
  2312.         if (done) return;
  2313.         var buffer, encoded;
  2314.  
  2315.         buffer = readableStream.read( 1920 * ACBI.audioChannels );
  2316.         encoded = [0xF8, 0xFF, 0xFE];
  2317.  
  2318.         if (buffer && buffer.length === 1920 * ACBI.audioChannels) encoded = ACBI._mixedDecoder.encode(buffer);
  2319.  
  2320.         return setTimeout(function() {
  2321.             sendAudio(ACBI, encoded);
  2322.             _prepareAudio(ACBI, readableStream, cnt + 1);
  2323.         }, 20 + ( (ACBI._startTime + cnt * 20) - Date.now() ));
  2324.     }
  2325. }
  2326.  
  2327. function sendAudio(ACBI, buffer) {
  2328.     ACBI._sequence = ACBI._sequence < 0xFFFF ? ACBI._sequence + 1 : 0;
  2329.     ACBI._timestamp = ACBI._timestamp < 0xFFFFFFFF ? ACBI._timestamp + 960 : 0;
  2330.  
  2331.     var audioPacket = AudioCB.VoicePacket(buffer, ACBI._voiceSession.ws.ssrc, ACBI._sequence, ACBI._timestamp, ACBI._secretKey);
  2332.  
  2333.     try {
  2334.         //It throws a synchronous error if it fails (someone leaves the audio channel while playing audio)
  2335.         ACBI._vUDP.send(audioPacket, 0, audioPacket.length, ACBI._port, ACBI._address);
  2336.     } catch(e) { return; }
  2337. }
  2338.  
  2339. function handleIncomingAudio(msg) {
  2340.     //The response from the UDP keep alive ping
  2341.     if (msg.length === 8) return;
  2342.  
  2343.     var header = msg.slice(0, 12),
  2344.         audio = msg.slice(12),
  2345.         ssrc = header.readUIntBE(8, 4),
  2346.         member = this._voiceSession.translator[ssrc],
  2347.         decrypted, decoded;
  2348.  
  2349.         this._decodeNonce.set(header);
  2350.  
  2351.         try {
  2352.             decrypted = new Buffer(
  2353.                 NACL.secretbox.open(
  2354.                     new Uint8Array(audio),
  2355.                     this._decodeNonce,
  2356.                     this._secretKey
  2357.                 )
  2358.             );
  2359.  
  2360.             if (member) {
  2361.                 decoded = member.decoder.decode(decrypted);
  2362.                 addToStreamBuffer(member, decoded);
  2363.             } else {
  2364.                 decoded = this._mixedDecoder.decode(decrypted);
  2365.             }
  2366.  
  2367.             addToStreamBuffer(this, decoded);
  2368.             this.emit('incoming', ssrc, decoded );
  2369.         } catch(e) {}
  2370. }
  2371. function addToStreamBuffer(RStream, data) {
  2372.     return RStream.push(new Buffer(data)) || !!RStream.read(data.length);
  2373. }
  2374.  
  2375. function chooseAudioEncoder(players) {
  2376.     if (!players[0]) return null;
  2377.     var s = ChildProc.spawnSync(players.shift());
  2378.     return s.error ? chooseAudioEncoder(players) : s.file;
  2379. }
  2380.  
  2381. /* - DiscordClient - Classes - */
  2382. function Resource() {}
  2383. Object.defineProperty(Resource.prototype, "creationTime", {
  2384.     get: function() { return (+this.id / 4194304) + 1420070400000; },
  2385.     set: function(v) { return; }
  2386. });
  2387. [Server, Channel, DMChannel, User, Member, Role].forEach(function(p) {
  2388.     p.prototype = Object.create(Resource.prototype);
  2389.     Object.defineProperty(p.prototype, 'constructor', {value: p, enumerable: false});
  2390. });
  2391.  
  2392. function Server(client, data) {
  2393.     var server = this;
  2394.     //Accept everything now and trim what we don't need, manually. Any data left in is fine, any data left out could lead to a broken lib.
  2395.     copyKeys(data, this);
  2396.     this.large = this.large || this.member_count > LARGE_THRESHOLD;
  2397.     this.voiceSession = null;
  2398.     if (data.unavailable) return;
  2399.  
  2400.     //Objects so we can use direct property accessing without for loops
  2401.     this.channels = {};
  2402.     this.members = {};
  2403.     this.roles = {};
  2404.     this.emojis = {};
  2405.  
  2406.     //Copy the data into the objects using IDs as keys
  2407.     data.channels.forEach(function(channel) {
  2408.         client.channels[channel.id] = new Channel(client, server, channel);
  2409.     });
  2410.     data.roles.forEach(function(role) {
  2411.         server.roles[role.id] = new Role(role);
  2412.     });
  2413.     data.members.forEach(function(member) {
  2414.         client.users[member.user.id] = new User(member.user);
  2415.         server.members[member.user.id] = new Member(client, server, member);
  2416.     });
  2417.     data.presences.forEach(function(presence) {
  2418.         var id = presence.user.id;
  2419.         if (!client.users[id] || !server.members[id]) return;
  2420.         delete(presence.user);
  2421.  
  2422.         client.users[id].game = presence.game;
  2423.         server.members[id].status = presence.status;
  2424.     });
  2425.     data.emojis.forEach(function(emoji) {
  2426.         server.emojis[emoji.id] = new Emoji(emoji);
  2427.     });
  2428.     data.voice_states.forEach(function(vs) {
  2429.         var cID = vs.channel_id;
  2430.         var uID = vs.user_id;
  2431.         if (!server.channels[cID] || !server.members[uID]) return;
  2432.         server.channels[cID].members[uID] = vs;
  2433.         server.members[uID].voice_channel_id = cID;
  2434.     });
  2435.  
  2436.     //Now we can get rid of any of the things we don't need anymore
  2437.     delete(this.voice_states);
  2438.     delete(this.presences);
  2439. }
  2440. function Channel(client, server, data) {
  2441.     var channel = this;
  2442.     this.members = {};
  2443.     this.permissions = { user: {}, role: {} };
  2444.     this.guild_id = server.id;
  2445.     copyKeys(data, this, ['permission_overwrites', 'emojis']);
  2446.     Object.defineProperty(server.channels, channel.id, {
  2447.         get: function() { return client.channels[channel.id]; },
  2448.         set: function(v) { client.channels[channel.id] = v; },
  2449.         enumerable: true,
  2450.         configurable: true
  2451.     });
  2452.     data.permission_overwrites.forEach(function(p) {
  2453.         var type = (p.type === 'member' ? 'user' : 'role');
  2454.         this.permissions[type][p.id] = {allow: p.allow, deny: p.deny};
  2455.     }, this);
  2456.  
  2457.  
  2458.     delete(this.is_private);
  2459. }
  2460. function DMChannel(translator, data) {
  2461.     copyKeys(data, this);
  2462.     translator[data.recipient.id] = data.id;
  2463.     delete(this.is_private);
  2464. }
  2465. function User(data) {
  2466.     copyKeys(data, this);
  2467.     this.bot = this.bot || false;
  2468. }
  2469. function Member(client, server, data) {
  2470.     copyKeys(data, this, ['user', 'joined_at',]);
  2471.     this.id = data.user.id;
  2472.     this.joined_at = Date.parse(data.joined_at);
  2473.     this.color = colorFromRole(server, this);
  2474.     ['username', 'discriminator', 'bot', 'avatar', 'game'].forEach(function(k) {
  2475.         if (k in Member.prototype) return;
  2476.  
  2477.         Object.defineProperty(Member.prototype, k, {
  2478.             get: function() { return client.users[this.id][k]; },
  2479.             set: function(v) { client.users[this.id][k] = v; },
  2480.             enumerable: true,
  2481.         });
  2482.     });
  2483. }
  2484. function Role(data) {
  2485.     copyKeys(data, this, ['permissions']);
  2486.     //Use `permissions` from Discord, or `_permissions` if we're making it out of a cache.
  2487.     this._permissions = data._permissions || data.permissions;
  2488. }
  2489. function Emoji(data) {
  2490.     copyKeys(data, this);
  2491. }
  2492.  
  2493. function Multipart() {
  2494.     this.boundary =
  2495.         "NodeDiscordIO" + "-" + CURRENT_VERSION;
  2496.     this.result = "";
  2497. }
  2498. Multipart.prototype.append = function(data) {
  2499.     /* Header */
  2500.     var str = "\r\n--";
  2501.     str += this.boundary + "\r\n";
  2502.     str += 'Content-Disposition: form-data; name="' + data[0] + '"';
  2503.     if (data[2]) {
  2504.         str += '; filename="' + data[2] + '"\r\n';
  2505.         str += 'Content-Type: application/octet-stream'; //\r\n';
  2506.     }
  2507.     /* Body */
  2508.     str += "\r\n\r\n" + ( data[1] instanceof Buffer ? data[1] : new Buffer(String(data[1]), 'utf-8') ).toString('binary');
  2509.     this.result += str;
  2510. };
  2511. Multipart.prototype.finalize = function() {
  2512.     this.result += "\r\n--" + this.boundary + "--";
  2513. };
  2514.  
  2515. Server.update = function(client, data) {
  2516.     if (!client.servers[data.id]) client.servers[data.id] = {}; // new Server(client, data)?
  2517.     for (var key in data) {
  2518.         if (key === 'roles') {
  2519.             data[key].forEach(function(r) {
  2520.                 client.servers[data.id].roles[r.id] = new Role(r);
  2521.             });
  2522.             continue;
  2523.         }
  2524.         if (key === 'emojis') continue;
  2525.         client.servers[data.id][key] = data[key];
  2526.     }
  2527. };
  2528. Channel.update = function(client, data) {
  2529.     if (!client.channels[data.id]) client.channels[data.id] = {}; // new Channel(client, data)?
  2530.     for (var key in data) {
  2531.         if (key === 'permission_overwrites') {
  2532.             data[key].forEach(function(p) {
  2533.                 var type = (p.type === 'member' ? 'user' : 'role');
  2534.                 client.channels[data.id].permissions[type][p.id] = {
  2535.                     allow: p.allow,
  2536.                     deny: p.deny
  2537.                 };
  2538.             });
  2539.             continue;
  2540.         }
  2541.         client.channels[data.id][key] = data[key];
  2542.     }
  2543.     delete(client.channels[data.id].is_private);
  2544. };
  2545. Member.update = function(client, server, data) {
  2546.     if (!server.members[data.user.id]) return server.members[data.user.id] = new Member(client, server, data);
  2547.     var member = server.members[data.user.id];
  2548.     copyKeys(data, member, ['user']);
  2549.     member.color = colorFromRole(server, member);
  2550. };
  2551. Role.update = function(server, data) {
  2552.     if (!server.roles[data.role.id]) server.roles[data.role.id] = {}; // new Role(data)?
  2553.     server.roles[data.role.id]._permissions = data.role.permissions;
  2554.     copyKeys(data.role, server.roles[data.role.id], ['permissions']);
  2555. };
  2556. Emoji.update = function(server, data) {
  2557.     server.emojis = {};
  2558.     data.forEach(function(emoji) {
  2559.         server.emojis[emoji.id] = new Emoji(emoji);
  2560.     });
  2561. }
  2562.  
  2563. Object.defineProperty(Role.prototype, "permission_values", {
  2564.     get: function() { return this; },
  2565.     set: function(v) {},
  2566.     enumerable: true
  2567. });
  2568.  
  2569. //Discord.OAuth;
  2570. Discord.version = CURRENT_VERSION;
  2571. Discord.Emitter = Emitter;
  2572. Discord.Codes = {};
  2573. Discord.Codes.WebSocket = {
  2574.     "0"   : "Gateway Error",
  2575.     "4000": "Unknown Error",
  2576.     "4001": "Unknown Opcode",
  2577.     "4002": "Decode Error",
  2578.     "4003": "Not Authenticated",
  2579.     "4004": "Authentication Failed",
  2580.     "4005": "Already Authenticated",
  2581.     "4006": "Session Not Valid",
  2582.     "4007": "Invalid Sequence Number",
  2583.     "4008": "Rate Limited",
  2584.     "4009": "Session Timeout",
  2585.     "4010": "Invalid Shard"
  2586. };
  2587. Discord.Colors = {
  2588.     DEFAULT: 0,
  2589.     AQUA: 1752220,
  2590.     GREEN: 3066993,
  2591.     BLUE: 3447003,
  2592.     PURPLE: 10181046,
  2593.     GOLD: 15844367,
  2594.     ORANGE: 15105570,
  2595.     RED: 15158332,
  2596.     GREY: 9807270,
  2597.     DARKER_GREY: 8359053,
  2598.     NAVY: 3426654,
  2599.     DARK_AQUA: 1146986,
  2600.     DARK_GREEN: 2067276,
  2601.     DARK_BLUE: 2123412,
  2602.     DARK_PURPLE: 7419530,
  2603.     DARK_GOLD: 12745742,
  2604.     DARK_ORANGE: 11027200,
  2605.     DARK_RED: 10038562,
  2606.     DARK_GREY: 9936031,
  2607.     LIGHT_GREY: 12370112,
  2608.     DARK_NAVY: 2899536
  2609. };
  2610. Discord.Permissions = {
  2611.     GENERAL_CREATE_INSTANT_INVITE: 0,
  2612.     GENERAL_KICK_MEMBERS: 1,
  2613.     GENERAL_BAN_MEMBERS: 2,
  2614.     GENERAL_ADMINISTRATOR: 3,
  2615.     GENERAL_MANAGE_CHANNELS: 4,
  2616.     GENERAL_MANAGE_GUILD: 5,
  2617.     GENERAL_MANAGE_ROLES: 28,
  2618.     GENERAL_MANAGE_NICKNAMES: 27,
  2619.     GENERAL_CHANGE_NICKNAME: 26,
  2620.     GENERAL_MANAGE_WEBHOOKS: 29,
  2621.     GENERAL_MANAGE_EMOJIS: 30,
  2622.  
  2623.     TEXT_ADD_REACTIONS: 6,
  2624.     TEXT_READ_MESSAGES: 10,
  2625.     TEXT_SEND_MESSAGES: 11,
  2626.     TEXT_SEND_TTS_MESSAGE: 12,
  2627.     TEXT_MANAGE_MESSAGES: 13,
  2628.     TEXT_EMBED_LINKS: 14,
  2629.     TEXT_ATTACH_FILES: 15,
  2630.     TEXT_READ_MESSAGE_HISTORY: 16,
  2631.     TEXT_MENTION_EVERYONE: 17,
  2632.     TEXT_EXTERNAL_EMOJIS: 18,
  2633.  
  2634.     VOICE_CONNECT: 20,
  2635.     VOICE_SPEAK: 21,
  2636.     VOICE_MUTE_MEMBERS: 22,
  2637.     VOICE_DEAFEN_MEMBERS: 23,
  2638.     VOICE_MOVE_MEMBERS: 24,
  2639.     VOICE_USE_VAD: 25,
  2640. };
  2641.  
  2642. Object.keys(Discord.Permissions).forEach(function(pn) {
  2643.     Object.defineProperty(Role.prototype, pn, {
  2644.         get: getPerm( Discord.Permissions[pn] ),
  2645.         set: setPerm( Discord.Permissions[pn] ),
  2646.         enumerable: true
  2647.     });
  2648. });
  2649.  
  2650. /* Wrappers */
  2651. function Emitter() {
  2652.     var emt = this;
  2653.     if (isNode) {
  2654.         EE.call(this);
  2655.         if (this.prototype) return Util.inherits(this, EE);
  2656.         return new EE();
  2657.     }
  2658.     //Thank you, http://stackoverflow.com/a/24216547
  2659.     function _Emitter() {
  2660.         var eventTarget = document.createDocumentFragment();
  2661.         ["addEventListener", "dispatchEvent", "removeEventListener"].forEach(function(method) {
  2662.             if (!this[method]) this[method] = eventTarget[method].bind(eventTarget);
  2663.         }, this);
  2664.     }
  2665.     //But I did the rest myself! D:<
  2666.     _Emitter.call(this);
  2667.     this._evts = {};
  2668.     this.on = function(eName, eFunc) {
  2669.         if (!emt._evts[eName]) emt._evts[eName] = [];
  2670.         emt._evts[eName].push(eOn);
  2671.  
  2672.         return this.addEventListener(eName, eOn);
  2673.  
  2674.         function eOn(e) {
  2675.             return eFunc.apply(null, resolveEvent(e));
  2676.         }
  2677.     };
  2678.     this.once = function(eName, eFunc) {
  2679.         if (!emt._evts[eName]) emt._evts[eName] = [];
  2680.         emt._evts[eName].push(eOnce);
  2681.  
  2682.         return this.addEventListener(eName, eOnce);
  2683.  
  2684.         function eOnce(e) {
  2685.             eFunc.apply(null, resolveEvent(e));
  2686.             return emt.removeListener(eName, eOnce);
  2687.         }
  2688.     };
  2689.     this.removeListener = function(eName, eFunc) {
  2690.         if (emt._evts[eName]) emt._evts[eName].splice(emt._evts[eName].lastIndexOf(eFunc), 1);
  2691.         return this.removeEventListener(eName, eFunc);
  2692.     };
  2693.     this.emit = function(eName) {
  2694.         return this.dispatchEvent( new CustomEvent(eName, {'detail': Array.prototype.slice.call(arguments, 1) }) );
  2695.     };
  2696.     return this;
  2697. }
  2698.  
  2699. function Websocket(url, opts) {
  2700.     if (isNode) return new (require('ws'))(url, opts);
  2701.     return Emitter.call(new WebSocket(url));
  2702. }
  2703.  
  2704. /* Endpoints */
  2705. (function () {
  2706.     var API = "https://discordapp.com/api";
  2707.     var ME  = API + "/users/@me";
  2708.     Endpoints = Discord.Endpoints = {
  2709.         API:        API,
  2710.  
  2711.         ME:         ME,
  2712.         NOTE:       function(userID) {
  2713.             return  ME + "/notes/" + userID;
  2714.         },
  2715.         LOGIN:      API + "/auth/login",
  2716.         OAUTH:      API + "/oauth2/applications/@me",
  2717.         GATEWAY:    API + "/gateway",
  2718.         SETTINGS:   ME + "/settings",
  2719.  
  2720.         SERVERS: function(serverID) {
  2721.             return  API + "/guilds" + (serverID ? "/" + serverID : "");
  2722.         },
  2723.         SERVERS_PERSONAL: function(serverID) {
  2724.             return  this.ME + "/guilds" + (serverID ? "/" + serverID : ""); //Method to list personal servers?
  2725.         },
  2726.         SERVER_EMOJIS: function(serverID, emojiID) {
  2727.             return  this.SERVERS(serverID) + "/emojis" + (emojiID ? "/" + emojiID : "");
  2728.         },
  2729.  
  2730.         CHANNEL: function(channelID) {
  2731.             return  API + "/channels/" + channelID;
  2732.         },
  2733.  
  2734.         MEMBERS: function(serverID, userID) {
  2735.             return  this.SERVERS(serverID) + "/members" + (userID ? "/" + userID : "");
  2736.         },
  2737.         MEMBER_ROLES: function(serverID, userID, roleID) {
  2738.             return  this.MEMBERS(serverID, userID) + "/roles" + (roleID ? "/" + roleID : "");
  2739.         },
  2740.  
  2741.         USER: function(userID) {
  2742.             return  API + "/users/" + userID;
  2743.         },
  2744.  
  2745.         ROLES: function(serverID, roleID) {
  2746.             return  this.SERVERS(serverID) + "/roles" + (roleID ? "/" + roleID : "");
  2747.         },
  2748.  
  2749.         BANS: function(serverID, userID) {
  2750.             return  this.SERVERS(serverID) + "/bans" + (userID ? "/" + userID : "");
  2751.         },
  2752.  
  2753.         MESSAGES: function(channelID, messageID) {
  2754.             return  this.CHANNEL(channelID) + "/messages" + (messageID ? "/" + messageID : "");
  2755.         },
  2756.         PINNED_MESSAGES: function(channelID, messageID) {
  2757.             return  this.CHANNEL(channelID) + "/pins" + (messageID ? "/" + messageID : "");
  2758.         },
  2759.  
  2760.         MESSAGE_REACTIONS: function(channelID, messageID, reaction) {
  2761.             return  this.MESSAGES(channelID, messageID) + "/reactions" + ( reaction ? ("/" + reaction) : "" );
  2762.         },
  2763.         USER_REACTIONS: function(channelID, messageID, reaction, userID) {
  2764.             return  this.MESSAGE_REACTIONS(channelID, messageID, reaction) + '/' + ( (!userID || userID === this.id) ? '@me' : userID );
  2765.         },
  2766.  
  2767.         INVITES: function(inviteCode) {
  2768.             return  API + "/invite/" + inviteCode;
  2769.         },
  2770.  
  2771.         SERVER_WEBHOOKS: function(serverID) {
  2772.             return  this.SERVERS(serverID) + "/webhooks";
  2773.         },
  2774.         CHANNEL_WEBHOOKS: function(channelID) {
  2775.             return  this.CHANNEL(channelID) +"/webhooks";
  2776.         },
  2777.  
  2778.         WEBHOOKS: function(webhookID) {
  2779.             return  API + "/webhooks/" + webhookID;
  2780.         },
  2781.  
  2782.         BULK_DELETE: function(channelID) {
  2783.             return  this.CHANNEL(channelID) + "/messages/bulk-delete";
  2784.         },
  2785.  
  2786.         TYPING: function(channelID) {
  2787.             return  this.CHANNEL(channelID) + "/typing";
  2788.         }
  2789.  
  2790.     };
  2791. })();
  2792.  
  2793. })(typeof exports === 'undefined'? this.Discord = {} : exports);
Add Comment
Please, Sign In to add comment