diff --git a/.gitignore b/.gitignore
index 661f8f613..693710211 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,8 @@ hydrabot/config.json
hydrabot/authority.json
hydrabot/tokencache.json
+.tmp/
+
### Node ###
# Logs
logs
@@ -32,3 +34,4 @@ build/Release
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
+test/auth.json
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 000000000..6998e3244
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,3 @@
+language: node_js
+node_js:
+ - "stable"
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 000000000..81c4b4351
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,2 @@
+// Place your settings in this file to overwrite default and user settings.
+{ "editor.wrappingColumn": 0 }
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 000000000..95c321163
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,220 @@
+// Available variables which can be used inside of strings.
+// ${workspaceRoot}: the root folder of the team
+// ${file}: the current opened file
+// ${fileBasename}: the current opened file's basename
+// ${fileDirname}: the current opened file's dirname
+// ${fileExtname}: the current opened file's extension
+// ${cwd}: the current working directory of the spawned process
+
+// A task runner that calls the Typescript compiler (tsc) and
+// Compiles a HelloWorld.ts program
+{
+ "version": "0.1.0",
+ "command" : "babel",
+ "isShellCommand": true,
+ "tasks": [
+ {
+ "taskName": "watch",
+ "suppressTaskName": true,
+ "isBuildCommand": true,
+ "isWatching": true,
+ "args": [
+ "src", "--out-dir", "lib", "-w"
+ ]
+ }
+ ]
+}
+
+// A task runner that calls the Typescript compiler (tsc) and
+// compiles based on a tsconfig.json file that is present in
+// the root of the folder open in VSCode
+/*
+{
+ "version": "0.1.0",
+
+ // The command is tsc. Assumes that tsc has been installed using npm install -g typescript
+ "command": "tsc",
+
+ // The command is a shell script
+ "isShellCommand": true,
+
+ // Show the output window only if unrecognized errors occur.
+ "showOutput": "silent",
+
+ // Tell the tsc compiler to use the tsconfig.json from the open folder.
+ "args": ["-p", "."],
+
+ // use the standard tsc problem matcher to find compile problems
+ // in the output.
+ "problemMatcher": "$tsc"
+}
+*/
+
+// A task runner configuration for gulp. Gulp provides a less task
+// which compiles less to css.
+/*
+{
+ "version": "0.1.0",
+ "command": "gulp",
+ "isShellCommand": true,
+ "tasks": [
+ {
+ "taskName": "less",
+ // Make this the default build command.
+ "isBuildCommand": true,
+ // Show the output window only if unrecognized errors occur.
+ "showOutput": "silent",
+ // Use the standard less compilation problem matcher.
+ "problemMatcher": "$lessCompile"
+ }
+ ]
+}
+*/
+
+// Uncomment the following section to use gulp in a watching mode that compiles a
+// less file. The gulp task prints "[hh:mm:ss] Starting 'clean-styles'" to the console
+// when existing css files get deleted and "[hh:mm:ss] Finished 'styles'" when the
+// overall less compilation has finished. When the clean pattern is detect internal less
+// problems are cleaned. When the finshed pattern is detected in the output less
+// problems are published.
+/*
+{
+ "version": "0.1.0",
+ "command": "gulp",
+ "isShellCommand": true,
+ "tasks": [
+ {
+ "taskName": "watch-less",
+ // Make this the default build command.
+ "isBuildCommand": true,
+ // Show the output window only if unrecognized errors occur.
+ "showOutput": "silent",
+ // Task is running in watching mode.
+ "isWatching": true,
+ "problemMatcher": {
+ // Use the standard less compilation problem matcher as the base.
+ "base": "$lessCompile",
+ // A regular expression signalling that a watched task begins executing (usually triggered through file watching).
+ "watchedTaskBeginsRegExp": "^\\[\\d+:\\d+:\\d+\\] Starting 'clean-styles'\\.\\.\\.$",
+ // A regular expression signalling that a watched tasks ends executing.
+ "watchedTaskEndsRegExp": "^\\[\\d+:\\d+:\\d+\\] Finished 'styles' after \\d+"
+ }
+ }
+ ]
+}
+*/
+
+// Uncomment the following section to use jake to build a workspace
+// cloned from https://github.com/Microsoft/TypeScript.git
+/*
+{
+ "version": "0.1.0",
+ // Task runner is jake
+ "command": "jake",
+ // Need to be executed in shell / cmd
+ "isShellCommand": true,
+ "showOutput": "silent",
+ "tasks": [
+ {
+ // TS build command is local.
+ "taskName": "local",
+ // Make this the default build command.
+ "isBuildCommand": true,
+ // Show the output window only if unrecognized errors occur.
+ "showOutput": "silent",
+ // Use the redefined Typescript output problem matcher.
+ "problemMatcher": [
+ "$tsc"
+ ]
+ }
+ ]
+}
+*/
+
+// Uncomment the section below to use msbuild and generate problems
+// for csc, cpp, tsc and vb. The configuration assumes that msbuild
+// is available on the path and a solution file exists in the
+// workspace folder root.
+/*
+{
+ "version": "0.1.0",
+ "command": "msbuild",
+ "args": [
+ // Ask msbuild to generate full paths for file names.
+ "/property:GenerateFullPaths=true"
+ ],
+ "taskSelector": "/t:",
+ "showOutput": "silent",
+ "tasks": [
+ {
+ "taskName": "build",
+ // Show the output window only if unrecognized errors occur.
+ "showOutput": "silent",
+ // Use the standard MS compiler pattern to detect errors, warnings
+ // and infos in the output.
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
+*/
+
+// Uncomment the following section to use msbuild which compiles Typescript
+// and less files.
+/*
+{
+ "version": "0.1.0",
+ "command": "msbuild",
+ "args": [
+ // Ask msbuild to generate full paths for file names.
+ "/property:GenerateFullPaths=true"
+ ],
+ "taskSelector": "/t:",
+ "showOutput": "silent",
+ "tasks": [
+ {
+ "taskName": "build",
+ // Show the output window only if unrecognized errors occur.
+ "showOutput": "silent",
+ // Use the standard MS compiler pattern to detect errors, warnings
+ // and infos in the output.
+ "problemMatcher": [
+ "$msCompile",
+ "$lessCompile"
+ ]
+ }
+ ]
+}
+*/
+// A task runner example that defines a problemMatcher inline instead of using
+// a predfined one.
+/*
+{
+ "version": "0.1.0",
+ "command": "tsc",
+ "isShellCommand": true,
+ "args": ["HelloWorld.ts"],
+ "showOutput": "silent",
+ "problemMatcher": {
+ // The problem is owned by the typescript language service. Ensure that the problems
+ // are merged with problems produced by Visual Studio's language service.
+ "owner": "typescript",
+ // The file name for reported problems is relative to the current working directory.
+ "fileLocation": ["relative", "${cwd}"],
+ // The actual pattern to match problems in the output.
+ "pattern": {
+ // The regular expression. Matches HelloWorld.ts(2,10): error TS2339: Property 'logg' does not exist on type 'Console'.
+ "regexp": "^([^\\s].*)\\((\\d+|\\d+,\\d+|\\d+,\\d+,\\d+,\\d+)\\):\\s+(error|warning|info)\\s+(TS\\d+)\\s*:\\s*(.*)$",
+ // The match group that denotes the file containing the problem.
+ "file": 1,
+ // The match group that denotes the problem location.
+ "location": 2,
+ // The match group that denotes the problem's severity. Can be omitted.
+ "severity": 3,
+ // The match group that denotes the problem code. Can be omitted.
+ "code": 4,
+ // The match group that denotes the problem's message.
+ "message": 5
+ }
+ }
+}
+*/
\ No newline at end of file
diff --git a/README.md b/README.md
index 659bc2e8c..38c7f8c09 100644
--- a/README.md
+++ b/README.md
@@ -1,68 +1,79 @@
-# discord.js
-Discord.js is a node module that allows you to interface with the [Discord](https://discordapp.com/) API for creation of things such as bots or loggers.
+
+
+
+
+
-The aim of this API is to make it *really* simple to start developing your bots. This API has server, channel and user tracking, as well as tools to make identification really simple.
+[](https://travis-ci.org/hydrabolt/discord.js) [](http://discordjs.readthedocs.org/en/latest/?badge=latest)
+
-New update features **big speed boosts** (everything cached and sorted with around 1 second of calling the login function) upon connection and allows editing of messages!
-
-**[Find the website here.](http://discord-js.github.io)**
-
-
-**[For more information, click here.](https://github.com/hydrabolt/discord.js/wiki)**
-
-### This module is still in alpha - especially the newer versions!
-
-This node module is still in alpha, and some methods and functions may change or completely disappear!
+discord.js is a node module used as a way of interfacing with
+[Discord](https://discordapp.com/). It is a very useful module for creating
+bots.
### Installation
-``npm install --save discord.js``
+`npm install --save discord.js`
-### Features
+---
-* Send, Receive Delete and **Edit** messages from channels _and_ DMs! Auto-initiates DMs for you!
-* Create, Delete and Leave servers and channels
-* Create invites for Servers
-* Silent Mention - trigger mention notification without actually @mentioning a user!
-* Get complete metadata on users, channels and servers - including avatars.
-* Get limitless logs from channels.
-* Fast and efficient caching
-* Auto-cache messages
-
-### Example usage
+### Example
```js
-/*
- * A basic bot that shows how to connect to a Discord account,
- * how to listen to messages and how to send messages.
- *
- * This bot responds to every "ping" message with a "pong".
- */
+var Discord = require("discord.js");
-var Discord = require( "discord.js" );
+var mybot = new Discord.Client();
-// Create the bot
-var myBot = new Discord.Client();
+mybot.on("message", function(message){
+
+ if(message.content === "ping")
+ mybot.reply(message, "pong");
+
+});
-// Login with an example email and password
-myBot.login( "hello@example.com", "password1" );
-
-// The "ready" event is triggered after the bot successfully connected to
-// Discord and is ready to send messages.
-myBot.on( "ready", function() {
- console.log( "Bot connected successfully." );
-} );
-
-// Add a listener to the "message" event, which triggers upon receiving
-// any message
-myBot.on( "message", function( message ) {
- // message.content accesses the content of the message as a string.
- // If it is equal to "ping", then the bot should respond with "pong".
- if ( message.content === "ping" ) {
- // Send a message ("pong") to the channel the message was sent in,
- // which is accessed by message.channel.
- this.sendMessage( message.channel, "pong" );
- }
-} );
+mybot.login("email", "password");
```
-### TODO
-* Joining servers from an invite
-* Stealthy Ninja support
+---
+
+### Related Projects
+
+Here is a list of other Discord APIs:
+
+#### Java:
+[Discord4J](https://github.com/nerd/Discord4J)
+#### .NET:
+[Discord.Net](https://github.com/RogueException/Discord.Net)
+
+[DiscordSharp](https://github.com/Luigifan/DiscordSharp)
+#### NodeJS
+[discord.io](https://github.com/izy521/node-discord) (similar to discord.js but lower level)
+
+#### PHP
+[DiscordPHP](https://github.com/teamreflex/DiscordPHP)
+
+#### Python
+[discord.py](https://github.com/Rapptz/discord.py)
+
+#### Ruby
+[discordrb](https://github.com/meew0/discordrb)
+
+---
+
+### Links
+**[Documentation](http://discordjs.readthedocs.org/en/latest/)**
+
+**[GitHub](https://github.com/discord-js/discord.js)**
+
+**[Wiki](https://github.com/discord-js/discord.js/wiki)**
+
+**[Website](http://discord-js.github.io/)**
+
+**[NPM](npmjs.com/package/discord.js)**
+
+---
+
+### Contact
+
+If you have an issue or want to know if a feature exists, [read the documentation](http://discordjs.readthedocs.org/en/latest/) before contacting me about any issues! If it's badly/wrongly implemented, let me know!
+
+
+If you would like to contact me, you can create an issue on the GitHub repo, e-mail me via the one available on my NPM profile.
+Or you could just send a DM to **hydrabolt** in [**Discord API**](https://discord.gg/0SBTUU1wZTYd2XyW).
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 000000000..751136e57
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,192 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# User-friendly check for sphinx-build
+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
+endif
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
+
+help:
+ @echo "Please use \`make ' where is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " applehelp to make an Apple Help Book"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " texinfo to make Texinfo files"
+ @echo " info to make Texinfo files and run them through makeinfo"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " xml to make Docutils-native XML files"
+ @echo " pseudoxml to make pseudoxml-XML files for display purposes"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+ @echo " coverage to run coverage check of the documentation (if enabled)"
+
+clean:
+ rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/discordjs.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/discordjs.qhc"
+
+applehelp:
+ $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
+ @echo
+ @echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
+ @echo "N.B. You won't be able to view it unless you put it in" \
+ "~/Library/Documentation/Help or install it in your application" \
+ "bundle."
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/discordjs"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/discordjs"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+latexpdfja:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through platex and dvipdfmx..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+ @echo "Run \`make' in that directory to run these through makeinfo" \
+ "(use \`make info' here to do that automatically)."
+
+info:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo "Running Texinfo files through makeinfo..."
+ make -C $(BUILDDIR)/texinfo info
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+ @echo
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
+
+coverage:
+ $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
+ @echo "Testing of coverage in the sources finished, look at the " \
+ "results in $(BUILDDIR)/coverage/python.txt."
+
+xml:
+ $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+ @echo
+ @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+pseudoxml:
+ $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+ @echo
+ @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 000000000..6ce076bcb
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,284 @@
+# -*- coding: utf-8 -*-
+#
+# discord.js documentation build configuration file, created by
+# sphinx-quickstart on Fri Sep 25 17:25:49 2015.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys
+import os
+import shlex
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'discord.js'
+copyright = u'2015, hydrabolt'
+author = u'hydrabolt'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '3.6'
+# The full version, including alpha/beta/rc tags.
+release = '3.6.1'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# " v documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Language to be used for generating the HTML full-text search index.
+# Sphinx supports the following languages:
+# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
+# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
+#html_search_language = 'en'
+
+# A dictionary with options for the search language support, empty by default.
+# Now only 'ja' uses this config value
+#html_search_options = {'type': 'default'}
+
+# The name of a javascript file (relative to the configuration directory) that
+# implements a search results scorer. If empty, the default will be used.
+#html_search_scorer = 'scorer.js'
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'discordjsdoc'
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+
+# Latex figure (float) alignment
+#'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ (master_doc, 'discordjs.tex', u'discord.js Documentation',
+ u'hydrabolt', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ (master_doc, 'discordjs', u'discord.js Documentation',
+ [author], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ (master_doc, 'discordjs', u'discord.js Documentation',
+ author, 'discordjs', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#texinfo_no_detailmenu = False
diff --git a/docs/create_simple_bot.rst b/docs/create_simple_bot.rst
new file mode 100644
index 000000000..f1115cd12
--- /dev/null
+++ b/docs/create_simple_bot.rst
@@ -0,0 +1,132 @@
+Creating a Simple Bot
+=====================
+
+This page will walk you through writing a simple bot and will introduce you to some of the most important functions and objects you will encounter in the API.
+
+Setting up a Project
+--------------------
+
+Before you start creating your bot, you need to create a directory, for example *discordbot*.
+
+After you've done that, open up the directory and have a look at how to `install the module`_. After you've installed the module, you can progress to the next step
+
+Creating the Bot
+----------------
+
+Now we can begin writing the bot. This bot will just server the user their avatar but at a higher resolution - assuming they have one.
+
+Firstly, create a file named ``bot.js`` in the directory you made earlier. Open it up, and type the following lines of code:
+
+.. code-block:: js
+
+ var Discord = require("discord.js");
+ var bot = new Discord.Client();
+
+This code firstly imports the discord.js module, which contains classes to help you create clients for Discord. The second line creates a new Discord Client, which we can manipulate later. Now, we want the client to be alerted when there is a new message and do something, so we can type this:
+
+.. code-block:: js
+
+ bot.on("message", function(message){
+
+ } )
+
+This will simply get our client to listen out for new messages, but not yet do anything. Let's have a look at this:
+
+.. code-block:: js
+
+ bot.on("message", function(message){
+
+ if( message.content === "avatar me!" ){
+
+ }
+
+ } )
+
+This code will now get our client to execute anything inside the if statement as long as the message sent was "avatar me!" We can now get it to see if the user has an avatar:
+
+.. code-block:: js
+
+ bot.on("message", function(message){
+
+ if( message.content === "avatar me!" ){
+
+ var usersAvatar = message.sender.avatarURL;
+
+ if(usersAvatar){
+ // user has an avatar
+ }else{
+ // user doesn't have an avatar
+ }
+
+ }
+
+ } )
+
+This code will now see if the user has an avatar and then do something based on that, let's finalise it:
+
+.. code-block:: js
+
+ bot.on("message", function(message){
+
+ if( message.content === "avatar me!" ){
+
+ var usersAvatar = message.sender.avatarURL;
+
+ if(usersAvatar){
+ // user has an avatar
+
+ bot.reply(message, "your avatar can be found at " + usersAvatar);
+
+ }else{
+ // user doesn't have an avatar
+
+ bot.reply(message, "you don't have an avatar!");
+ }
+
+ }
+
+ } )
+
+Let's have a look at the function we used here; *bot.reply*. This function takes 2 necessary parameters, a message object to reply to and a message to send. The first parameter we already have, and it is the message we have received. The second parameter is what we want to send.
+
+Now that we've finished the listener event, we need to log the client in:
+
+.. code-block:: js
+
+ bot.login("your discord email", "your discord password");
+
+And that's it! Run the code with ``node bot.js`` and wait a few seconds, and then try sending *avatar me!* to any of the channels that the user you provided has details to.
+
+Final Product
+-------------
+.. code-block:: js
+
+ var Discord = require("discord.js");
+ var bot = new Discord.Client();
+
+ bot.on("message", function(message){
+
+ if( message.content === "avatar me!" ){
+
+ var usersAvatar = message.sender.avatarURL;
+
+ if(usersAvatar){
+ // user has an avatar
+
+ bot.reply(message, "your avatar can be found at " + usersAvatar);
+
+ }else{
+ // user doesn't have an avatar
+
+ bot.reply(message, "you don't have an avatar!");
+ }
+
+ }
+
+ } );
+
+ bot.login("your discord email", "your discord password");
+
+.. note:: This page is still a WIP, check back later for more documentation on it.
+
+.. _install the module : http://discordjs.readthedocs.org/en/latest/get_started.html#installation
\ No newline at end of file
diff --git a/docs/docs_channel.rst b/docs/docs_channel.rst
new file mode 100644
index 000000000..063fb0790
--- /dev/null
+++ b/docs/docs_channel.rst
@@ -0,0 +1,75 @@
+.. include:: ./vars.rst
+
+Channel Documentation
+=====================
+
+The Channel Class is used to represent data about a Channel.
+
+Attributes
+----------
+
+client
+~~~~~~
+
+The Discord Client_ that cached the channel
+
+server
+~~~~~~
+
+The Server_ that the channel belongs to
+
+name
+~~~~
+
+The channel's name, as a `String`.
+
+id
+~~
+
+The channel's id, as a `String`.
+
+type
+~~~~
+
+The type of the channel as a `String`, either ``text`` or ``voice``.
+
+topic
+~~~~~
+
+A `String` that is the topic of the channel, if the channel doesn't have a topic this will be `null`.
+
+messages
+~~~~~~~~
+
+An `Array` of Message_ objects received from the channel. There are up to a 1000 messages here, and the older messages will be deleted if necessary.
+
+members
+~~~~~~~
+
+**Aliases** : `users`
+
+The members in the channel's server, an `Array` of User_ objects.
+
+-----
+
+Functions
+---------
+
+.. note:: When concatenated with a String, the object will become the channel's embed code, e.g. ``"this is " + channel`` would be ``this is <#channelid>``
+
+getMessage(key, value)
+~~~~~~~~~~~~~~~~~~~~~~
+
+Gets a Message_ from the channel that matches the specified criteria. E.g:
+
+.. code-block:: js
+
+ channel.getMessage("id", 1243987349) // returns a Message where message.id === 1243987349
+
+- **key** - a `String` that is the key
+- **value** - a `String` that is the value
+
+equals(object)
+~~~~~~~~~~~~~~
+
+Returns a `Boolean` depending on whether the Channel's ID (``channel.id``) equals the object's ID (``object.id``). You should **always**, always use this if you want to compare channels. **NEVER** do ``channel1 == channel2``.
diff --git a/docs/docs_client.rst b/docs/docs_client.rst
new file mode 100644
index 000000000..cb5ed2bab
--- /dev/null
+++ b/docs/docs_client.rst
@@ -0,0 +1,610 @@
+.. include:: ./vars.rst
+
+Client Documentation
+====================
+
+This page contains documentation on the `Discord.Client` class. This should be used when you want to start creating things with the API.
+
+It might be beneficial to use CTRL+F to search for what you're looking for, or use the navigation provided by readthedocs on the left.
+
+Attributes
+----------
+
+options
+~~~~~~~
+An `Object` containing a configuration for the Client. Currently can only be configured like so:
+
+.. code-block:: js
+
+ {
+ queue : false // whether messages should be sent one after the other or
+ // just send straight away.
+ }
+
+token
+~~~~~
+A `String` that is the token received after logging in. It is used to authorise the Client when joining WebSockets or making HTTP requests. Example token:
+
+.. code-block:: js
+
+ ODAzTOc4MTA2BjQ2MjY4ODg.COmrCA.fEtD_Tc0JU6iZJU_11coEWBOQHE
+
+state
+~~~~~
+An `Integer` representing what state of connection the Client is in.
+
+- **0** is idle, meaning the Client has been created but no login attempts have been made.
+- **1** is logging in, meaning the Client is in the process of logging in.
+- **2** is logged in, meaning the Client is logged in but not necessarily ready.
+- **3** is ready, meaning the Client is ready to begin listening.
+- **4** is disconnected, meaning the Client was disconnected due to any reason.
+
+See also ready_.
+
+.. code-block:: js
+
+ if( bot.state === 3 ) // ready to go
+
+user
+~~~~
+A `User`_ object representing the account of the signed in client. This will only be available when the client is in the ready state (3).
+
+.. code-block:: js
+
+ bot.user.username; // username of the account logged in
+
+email
+~~~~~
+A `String` that is the email used to sign the client in.
+
+password
+~~~~~~~~
+A `String` that is the password used to sign the client in.
+
+readyTime
+~~~~~~~~~
+A `Number` representing the unix timestamp from when the client was ready. `Null` if not yet ready.
+
+.. code-block:: js
+
+ bot.readyTime; // 1443378242464
+
+uptime
+~~~~~~
+A `Number` representing how many milliseconds have passed since the client was ready. `Null` if not yet ready.
+
+.. code-block:: js
+
+ if( bot.uptime > 5000 ) // true if the client has been up for more than 5 seconds
+
+ready
+~~~~~
+A `Boolean` that is true if the client is ready. A shortcut to checking if ``bot.state === 3``.
+
+servers
+~~~~~~~
+An `Array` of Server_ objects that the client has access to.
+
+channels
+~~~~~~~~
+An `Array` of Channel_ objects that the client has access to.
+
+users
+~~~~~
+An `Array` of User_ objects that the client has access to.
+
+PMChannels
+~~~~~~~~~~
+An `Array` of PMChannel_ objects the client has access to.
+
+messages
+~~~~~~~~
+An `Array` of Message_ objects the client has received over its uptime.
+
+Functions
+---------
+
+.. note :: Any functions used here that take callbacks as an optional parameter can also be used as Promises_. Promises take the exact same parameters for each use case, except errors are moved to catch statements instead of then. For example, you can do:
+
+.. code-block:: js
+
+ bot.login(email, password).then(success).catch(err);
+
+ function success(token){
+
+ }
+
+ function err(error){
+
+ }
+
+ // OR use callbacks:
+
+ bot.login(email, password, function(error, token){
+
+ });
+
+-----
+
+login(email, password, `callback`)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Logs the client in to set it up. Use this after registering your event listeners to ensure they are called.
+
+- **email** - A `String` which is the email you want to sign in with.
+- **password** - A `String` which is the password you want to sign in with.
+- **callback** - A `function` that can take the following parameters:
+
+ - **error** - An error if one occurred, otherwise it is null.
+ - **token** - if successful, it is the received authorisation token.
+
+logout(`callback`)
+~~~~~~~~~~~~~~~~~~
+
+Logs the client out if it is logged in. If successful, ``bot.state == 4``.
+
+- **callback** - A `function` that can take the following parameters:
+
+ - **error** - An error if one occurred, otherwise it is null.
+
+createServer(name, region, `callback`)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Creates a server with the specified name or region. See valid regions below:
+
+- **name** - A `String` that will be the name of your server.
+- **region** - A `String` that is a valid Discord region. Currently **us-west**, **us-east**, **singapore**, **london**, **sydney** or **amsterdam**. Providing an invalid region will result in an error. To find the latest available regions, check the `official API here`_.
+- **callback** - A `function` that can take the following parameters:
+
+ - **error** - An error if one occurred, otherwise it is null.
+ - **server** - A Server_ that represents the created Server.
+
+joinServer(invite, `callback`)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Accepts a given invite to join a server. The server is automatically cached ASAP.
+
+- **invite** - An `Invite Resolvable`_ which is the invite that should be accepted.
+- **callback** - A `function` that can take the following parameters:
+
+ - **error** - An error if one occurred, otherwise it is null.
+ - **server** - A Server_ that represents the joined Server.
+
+leaveServer(server, `callback`)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Leaves the given server.
+
+- **server** - A `Server Resolvable`_ that represents the server you want to leave.
+- **callback** - A `function` that can take the following parameters:
+
+ - **error** - An error if one occurred, otherwise it is null.
+
+createInvite(channel, options, `callback`)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Creates an invite for the given channel and returns an Invite_.
+
+- **channel** - A `Channel Resolvable`_ that is the channel you want to create an invite for.
+- **options** - An `object` containing configurable options for the invite. See below for possible configurations.
+- **callback** - A `function` that can take the following parameters:
+
+ - **error** - An error if one occurred, otherwise it is null.
+ - **invite** - An Invite_ object that contains the details about the created invite.
+
+.. code-block:: js
+
+ // default configuration of the options variable:
+
+ options = {
+ max_age : 0, //A number signifying the expiry time for the invite. 0 means infinite.
+ max_uses : 0, //A number signifying the amount of uses of the invite. 0 means infinite.
+ temporary : false, //boolean - whether users who use it are kicked unless promoted within 24h.
+ xkcd : false //boolean - whether the invite's URL should be human-readable
+ }
+
+createChannel(server, channelName, channelType, `callback`)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Creates a channel in the given server.
+
+- **server** - A `Server Resolvable`_ that will be the server the channel is created in.
+- **channelName** - A `String` that is the name of the channel.
+- **channelType** - A `String` that is the type of the channel, either **voice** or **text**.
+- **callback** - A `function` that can take the following parameters:
+
+ - **error** - An error if one occurred, otherwise it is null.
+ - **channel** - An Channel_ object that represents the created channel.
+
+deleteChannel(channel, `callback`)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Deletes the specified channel.
+
+- **channel** - A `Channel Resolvable`_ that will be the channel to delete.
+- **callback** - A `function` that can take the following parameters:
+
+ - **error** - An error if one occurred, otherwise it is null.
+
+getChannelLogs(channel, `amount`, `callback`)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Gets previous messages from the specified channel.
+
+- **channel** - A `Channel Resolvable`_ to take logs from.
+- **amount** - A `Number` that defaults to **500**. This is the amount of messages to try and get.
+- **callback** - A `function` that can take the following parameters:
+
+ - **error** - An error if one occurred, otherwise it is null.
+ - **logs** - An `Array` of Message_ objects that represent the previous messages.
+
+.. warning:: If the logs contain messages from a user who is no longer in the server, the user object *MAY* be malformed.
+
+sendMessage(channel, message, `callback`)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sends a message to the specified channel.
+
+- **channel** - A `Channel Resolvable`_ to send the message to.
+- **message** - A `String` or an Array of strings. If an Array, the array will be joined with a new line as a delimiter and this will be the message to be sent.
+- **callback** - A `function` that can take the following parameters:
+
+ - **error** - An error if one occurred, otherwise it is null.
+ - **message** - A Message_ representing the sent message.
+
+sendFile(channel, file, `fileName`, `callback`)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sends a file to the specified channel. Note that **fileName is necessary in certain cases** for when a file other than an image is sent. For example, if you send a file containing JS code, fileName should be something like ``myCode.js``.
+
+- **channel** - A `Channel Resolvable`_ to send the file to.
+- **file** - The file to send, either a `Buffer` or `String` - if a String, it should be a relative (`./`) or absolute path to a file.
+- **fileName** - A `String` containing the file's name and extension, used by Discord (I didn't make this please don't shoot me :s) Examples include `picture.png`, `text.txt`, `wowanamazingscript.js`
+
+- **callback** - A `function` that can take the following parameters:
+
+ - **error** - An error if one occurred, otherwise it is null.
+ - **message** - A Message_ representing the sent file.
+
+updateMessage(message, content, `callback`)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Updates/edits a message with new content.
+
+- **message** - A Message_ that should be updated.
+- **content** - A `String` or an Array of strings. If an Array, the array will be joined with a new line as a delimiter and this will be the message to be sent.
+- **callback** - A `function` that can take the following parameters:
+
+ - **error** - An error if one occurred, otherwise it is null.
+ - **message** - A Message_ representing the updated message.
+
+reply(message, yourMessage, `callback`)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Alias for sendMessage, but prepends a mention to whoever sent the specified mention. Useful shortcut for directing a message at a user.
+
+.. code-block:: js
+
+ // example usage:
+
+ the user 'bob' sent a message
+
+ bot.reply(message, "hello");
+ // will send the message '@bob, hello' to the channel the message that bob sent was in.
+
+- **message** - A Message_ that should be replied to.
+- **yourMessage** - A `String` or an Array of strings. If an Array, the array will be joined with a new line as a delimiter and this will be the message to be sent.
+- **callback** - A `function` that can take the following parameters:
+
+ - **error** - An error if one occurred, otherwise it is null.
+ - **message** - A Message_ representing the sent message.
+
+setUsername(newName, `callback`)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sets the username of the logged in client.
+
+- **newName** - The new name of the client, a `String`.
+- **callback** - A `function` that can take the following parameters:
+
+ - **error** - An error if one occurred, otherwise it is null.
+
+startTyping(channel, *stopTime*)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Makes the client appear to be typing in the specified channel.
+
+- **channel** - A `Channel Resolvable`_ that should be the channel to start typing in
+- **stopTime** - A `Number` in ms which should make the client stop typing after. Allow 5 seconds.
+
+stopTyping(channel)
+~~~~~~~~~~~~~~~~~~~
+
+Makes the client stop typing in a specified channel.
+
+- **channel** - A `Channel Resolvable`_ that should be the channel to stop typing in.
+
+setStatusOnline()
+~~~~~~~~~~~~~~~~~
+
+**Aliases**: ``setStatusActive()`` and ``setStatusHere()``
+
+Sets the client's status to online; green.
+
+setStatusIdle()
+~~~~~~~~~~~~~~~~~
+
+**Aliases**: ``setStatusAway()``
+
+Sets the client's status to idle; orange.
+
+setTopic(channel, topic, `callback`)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sets the topic of the specified channel
+
+- **channel** - A `Channel Resolvable`_ that is the channel you want to change the topic of
+- **topic** - A `String` that is the topic you want
+- **callback** - A `function` that can take the following parameters:
+
+ - **error** - An error if one occurred, otherwise it is null.
+
+getUser(key, value)
+~~~~~~~~~~~~~~~~~~~
+
+Gets a User_ that matches the specified criteria. E.g:
+
+.. code-block:: js
+
+ bot.getUser("id", 1243987349) // returns a user where user.id === 1243987349
+
+- **key** - a `String` that is the key
+- **value** - a `String` that is the value
+
+getServer(key, value)
+~~~~~~~~~~~~~~~~~~~~~
+
+Gets a Server_ that matches the specified criteria. E.g:
+
+.. code-block:: js
+
+ bot.getServer("id", 1243987349) // returns a server where server.id === 1243987349
+
+- **key** - a `String` that is the key
+- **value** - a `String` that is the value
+
+
+getChannel(key, value)
+~~~~~~~~~~~~~~~~~~~~~~
+
+Gets a Channel_ that matches the specified criteria. E.g:
+
+.. code-block:: js
+
+ bot.getChannel("id", 1243987349) // returns a Channel where channel.id === 1243987349
+
+- **key** - a `String` that is the key
+- **value** - a `String` that is the value
+
+
+getPMChannel(key, value)
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Gets a PMChannel_ that matches the specified criteria. E.g:
+
+.. code-block:: js
+
+ bot.getPMChannel("id", 1243987349) // returns a PMChannel where pmchannel.id === 1243987349
+
+- **key** - a `String` that is the key
+- **value** - a `String` that is the value
+
+setPlayingGame(id)
+~~~~~~~~~~~~~~~~~~
+
+**Aliases** : `playGame`, `playingGame`
+
+Sets the client as playing the specified game name/id.
+
+- **id** - Either a `Number` or a `String`. If it's a Number, it's assumed that you are using a `Discord Game ID`_ and know what you want. If you supply a `String`, it will assume you are entering a game name and try resolving it to a Discord Game ID if it's available. Example:
+
+.. code-block:: js
+
+ client.setPlayingGame(18);
+ // sets the client as playing Minecraft, game ID 18
+
+ client.setPlayingGame("Minecraft");
+ // sets the client as playing Minecraft by resolving the ID to 18
+
+ client.setPlayingGame("my magical made up game")
+ // will stop the client from playing anything as it is unresolved, not a valid game.
+
+-----
+
+Event Management
+----------------
+
+Events are a useful way of listening to events and are available in every API.
+
+Registering Events
+~~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ bot.on("eventName", function(arg1, arg2...){
+ // code here is called when eventName is emitted.
+ })
+
+.. note:: You can only have one listening function per event
+
+Unregistering Events
+~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ bot.off("eventName")
+ // eventName is no longer listened for
+
+Event Types
+-----------
+
+ready
+~~~~~
+
+Called when the bot is ready and you can begin working with it.
+
+disconnected
+~~~~~~~~~~~~
+
+Called when the bot is disconnected for whatever reason.
+
+error
+~~~~~
+
+Called whenever there is an error.
+
+**Parameters**
+
+- **error** - the encountered error
+
+.. note:: There may be more parameters supplied depending on the errors. Use the ``arguments`` variable to check for this for advanced debugging.
+
+debug
+~~~~~
+
+Called when the client debugs some information that might be useful for a developer but not for an end user.
+
+**Parameters**
+
+- **message** - the debug message as a `String`
+
+message
+~~~~~~~
+
+Called when a message has been received by the client.
+
+**Parameters**
+
+- **message** - the received Message_.
+
+messageDelete
+~~~~~~~~~~~~~
+
+Called when a message has been deleted.
+
+**Parameters**
+
+- **channel** - The Channel_ that the deleted message was in.
+- **message** - *May* be available. If the message wasn't previously cached, this will not be supplied and all you would know is that a message was deleted in the channel. If it is available, it will be in the format of a Message_.
+
+messageUpdate
+~~~~~~~~~~~~~
+
+Called when a message has been updated.
+
+**Parameters**
+
+- **newMessage** - The updated Message_.
+- **oldMessage** - The old Message_ before it was updated.
+
+serverDelete
+~~~~~~~~~~~~
+
+Called when a server is deleted.
+
+**Parameters**
+
+- **server** - The deleted Server_.
+
+channelDelete
+~~~~~~~~~~~~~
+
+Called when a channel is deleted.
+
+**Parameters**
+
+- **channel** - The deleted Channel_.
+
+serverCreate
+~~~~~~~~~~~~
+
+Called when a server is created/joined.
+
+**Parameters**
+
+- **server** - The created Server_.
+
+channelCreate
+~~~~~~~~~~~~
+
+Called when a channel is created.
+
+**Parameters**
+
+- **channel** - The created Channel_.
+
+serverNewMember
+~~~~~~~~~~~~~~~
+
+Called when a new member is added to a server.
+
+**Parameters**
+
+- **user** - The User_ that was added.
+- **server** - The Server_ that the user was added to.
+
+serverRemoveMember
+~~~~~~~~~~~~~~~~~~
+
+Called when a member of a server leaves or is kicked out.
+
+**Parameters**
+
+- **user** - The User_ that was removed.
+- **server** - The Server_ that the user was removed from.
+
+userUpdate
+~~~~~~~~~~
+
+Called when information about a user changes, such as their username.
+
+**Parameters**
+
+- **newUser** - A User_ object representing the changes to the old user (this will be in the cache)
+- **oldUser** - A User_ object representing the user before the update.
+
+presence
+~~~~~~~~
+
+Called when a user goes online/offline/away or starts/stops playing a game.
+
+**Parameters**
+
+- **dataObject** - Instead of separate arguments, presence update takes an object containing the following information:
+
+ - **user** - A User_ representing the User that had a presence update
+ - **status** - The status change as a `String`.
+ - **server** - The Server_ that the presence change occurred in.
+ - **gameId** - A `Number` representing the game they are playing if any. Currently, discord.js has no internal support for converting this into a game name.
+
+unknown
+~~~~~~~
+
+Called when an unknown packet was received or there is no handler for it.
+
+**Parameters**
+
+- **data** - A `JSON Object` which is the message received over WebSocket.
+
+raw
+~~~
+
+Called when a WebSocket message is received and it gives you the message.
+
+**Parameters**
+
+- **data** - A `JSON Object` which is the message received over WebSocket.
+
+.. _official API here : https://discordapp.com/api/voice/regions
+
+.. _Discord Game ID : https://raw.githubusercontent.com/hydrabolt/discord.js/master/ref/gameMap.json
\ No newline at end of file
diff --git a/docs/docs_invite.rst b/docs/docs_invite.rst
new file mode 100644
index 000000000..4c1688b1e
--- /dev/null
+++ b/docs/docs_invite.rst
@@ -0,0 +1,64 @@
+.. include:: ./vars.rst
+
+Invite Documentation
+====================
+
+The Invite Class is used to represent data about an Invite.
+
+Attributes
+----------
+
+max_age
+~~~~~~~
+
+A `Number` in minutes for how long the Invite should be valid for. E.g. a value of ``3600`` is equal to 30 minutes.
+
+code
+~~~~
+
+`String` an alphanumeric code for the Invite.
+
+revoked
+~~~~~~~
+
+`Boolean` that dictates whether the Invite has been cancelled or not
+
+created_at
+~~~~~~~~~~
+
+A unix timestamp as a `Number` which is the time that the invite was created.
+
+temporary
+~~~~~~~~~
+
+`Boolean` that dictates whether the invite is temporary.
+
+uses
+~~~~
+
+`Number` the number of uses of the Invite, a value of ``0`` is none.
+
+max_uses
+~~~~~~~~
+
+`Number` that is the maximum amount of uses of the invite, ``0`` is unlimited.
+
+inviter
+~~~~~~~
+
+The User_ that created the invite.
+
+xkcd
+~~~~
+
+`Boolean` that is true if the invite should be human-readable.
+
+channel
+~~~~~~~
+
+The Channel_ that the invite is inviting to.
+
+URL
+~~~
+
+A `String` that generates a clickable link to the invite.
\ No newline at end of file
diff --git a/docs/docs_message.rst b/docs/docs_message.rst
new file mode 100644
index 000000000..7dbbbfc3d
--- /dev/null
+++ b/docs/docs_message.rst
@@ -0,0 +1,84 @@
+.. include:: ./vars.rst
+
+Message Documentation
+=====================
+
+The Message Class is used to represent data about a Message.
+
+Attributes
+----------
+
+tts
+~~~
+
+A `Boolean` that is ``true`` if the sent message was text-to-speech, otherwise ``false``.
+
+timestamp
+~~~~~~~~~
+
+A `unix timestamp` as a `Number` representing when the message was sent.
+
+mentions
+~~~~~~~~
+
+An `Array` of User_ objects that represent the users mentioned in the message.
+
+everyoneMentioned
+~~~~~~~~~~~~~~~~~
+
+A `Boolean` that is ``true`` if **@everyone** was used, otherwise ``false``.
+
+id
+~~
+
+A `String` UUID of the message, will never change.
+
+.. note:: Currently, message IDs are totally unique. However, in the future they may only be unique within a channel. Make sure to check periodically whether this has changed.
+
+embeds
+~~~~~~
+
+A raw, unhandled `JSON object` that will contain embeds of the message - if any.
+
+editedTimestamp
+~~~~~~~~~~~~~~~
+
+A `unix timestamp` as a `Number` that is when the message was last edited.
+
+content
+~~~~~~~
+
+The actual content of the message as a `String`.
+
+channel
+~~~~~~~
+
+The Channel_ that the message was sent in.
+
+author
+~~~~~~
+
+**Aliases** : `sender`
+
+The User_ that sent the message.
+
+attachments
+~~~~~~~~~~~
+
+A raw, unhandled `JSON object` that will contain attachments of the message - if any.
+
+isPrivate
+~~~~~~~~~
+
+A `Boolean` that is ``true`` if the message was sent in a PM / DM chat, or if it was sent in a group chat it will be ``false``.
+
+Functions
+---------
+
+isMentioned(user)
+~~~~~~~~~~~~~~~~~
+
+A `Boolean` that will return ``true`` if the specified user was mentioned in the message. If everyone is mentioned, this will be false - this function checks specifically for if they were mentioned.
+
+
+- **user** - The User_ that you want to see is mentioned or not.
\ No newline at end of file
diff --git a/docs/docs_pmchannel.rst b/docs/docs_pmchannel.rst
new file mode 100644
index 000000000..3f10acec2
--- /dev/null
+++ b/docs/docs_pmchannel.rst
@@ -0,0 +1,41 @@
+.. include:: ./vars.rst
+
+PMChannel Documentation
+=======================
+
+The PMChannel Class is used to represent data about a Private Message Channel.
+
+.. note:: Beware! The PMChannel class does `not` extend the Channel_ class.
+
+Attributes
+----------
+
+user
+~~~~
+
+The recipient User_ of the PM Channel.
+
+id
+~~
+
+`String` UUID of the PM Channel.
+
+messages
+~~~~~~~~
+
+An `Array` of Message_ objects. Contains all the cached messages sent in this channel up to a limit of 1000. If the limit is reached, the oldest message is removed first to make space for it.
+
+Functions
+---------
+
+getMessage(key, value)
+~~~~~~~~~~~~~~~~~~~~~~
+
+Gets a Message_ from the PM Channel that matches the specified criteria. E.g:
+
+.. code-block:: js
+
+ pmchannel.getMessage("id", 1243987349) // returns a Message where message.id === 1243987349
+
+- **key** - a `String` that is the key
+- **value** - a `String` that is the value
\ No newline at end of file
diff --git a/docs/docs_resolvable.rst b/docs/docs_resolvable.rst
new file mode 100644
index 000000000..ebd1f2211
--- /dev/null
+++ b/docs/docs_resolvable.rst
@@ -0,0 +1,27 @@
+.. include:: ./vars.rst
+
+Resolvable Documentation
+========================
+
+To be robust, discord.js needs to handle a wide amount of ambiguous data that is supplied to it. This means you can use functions much more easily. Anything that is resolvable means it can be normalised without you having to do it explicitly.
+
+Resolvables are not objects or classes, they are just ways of expressing what type of data is expected.
+
+Channel Resolvable
+------------------
+
+A Channel Resolvable is data that can be resolved to a channel ID. Here is what is currently supported:
+
+- A Channel_ object
+- A Server_ object (the #general channel of the server will be used)
+- A `String` representing the channel ID
+- A Message_ (the channel the message was sent in will be used)
+- A User_ (will get the PM channel with the specified user)
+
+.. note:: A User cannot always be specified in certain cases. For example, if using `bot.setTopic`, a User or PM Channel can't be specified as these do not support channel topics.
+
+Server Resolvable
+-----------------
+
+Invite Resolvable
+-----------------
\ No newline at end of file
diff --git a/docs/docs_server.rst b/docs/docs_server.rst
new file mode 100644
index 000000000..0baa9d331
--- /dev/null
+++ b/docs/docs_server.rst
@@ -0,0 +1,107 @@
+.. include:: ./vars.rst
+
+Server Documentation
+==================
+
+The Server Class is used to represent data about a server.
+
+Attributes
+----------
+
+client
+~~~~~~
+
+The Discord Client_ that the Server was cached by.
+
+region
+~~~~~~
+
+The region that the server is in, a `String`.
+
+name
+~~~~
+
+The server's name, as a `String`.
+
+id
+~~
+
+The server's id, as a `String`.
+
+members
+~~~~~~~
+
+**Aliases** : `users`
+
+The members in a server, an `Array` of User_ objects.
+
+channels
+~~~~~~~~
+
+The channels in a server, an `Array` of Channel_ objects.
+
+icon
+~~~~
+
+The icon ID of the server if it has one as a `String`, otherwise it is `null`.
+
+iconURL
+~~~~~~~
+
+A `String` that is the URL of the server icon if it has one, otherwise it is `null`.
+
+afkTimeout
+~~~~~~~~~~
+
+A `Number` that is the AFK Timeout of the Server.
+
+afkChannel
+~~~~~~~~~~
+
+A Channel_ that represents the AFK Channel of the server if it has one, otherwise it is `null`.
+
+defaultChannel
+~~~~~~~~~~~~~~
+
+The **#general** Channel_ of the server.
+
+owner
+~~~~~
+
+A User_ object representing the user that owns the server.
+
+-----
+
+Functions
+---------
+
+.. note:: When concatenated with a String, the object will become the server's name, e.g. ``"this is " + server`` would be ``this is Discord API`` if the server was called `Discord API`.
+
+getChannel(key, value)
+~~~~~~~~~~~~~~~~~~~~~~
+
+Gets a Channel_ that matches the specified criteria. E.g:
+
+.. code-block:: js
+
+ server.getChannel("id", 1243987349) // returns a Channel where channel.id === 1243987349
+
+- **key** - a `String` that is the key
+- **value** - a `String` that is the value
+
+getMember(key, value)
+~~~~~~~~~~~~~~~~~~~~~
+
+Gets a User_ that matches the specified criteria. E.g:
+
+.. code-block:: js
+
+ bot.getUser("id", 1243987349) // returns a user where user.id === 1243987349
+
+- **key** - a `String` that is the key
+- **value** - a `String` that is the value
+
+equals(object)
+~~~~~~~~~~~~~~
+
+Returns a `Boolean` depending on whether the Server's ID (``server.id``) equals the object's ID (``object.id``). You should **always**, always use this if you want to compare servers. **NEVER** do ``server1 == server2``.
diff --git a/docs/docs_user.rst b/docs/docs_user.rst
new file mode 100644
index 000000000..70cf51b2d
--- /dev/null
+++ b/docs/docs_user.rst
@@ -0,0 +1,67 @@
+.. include:: ./vars.rst
+
+User Documentation
+==================
+
+The User Class is used to represent data about users.
+
+Attributes
+----------
+
+username
+~~~~~~~~
+
+A `String` that is the username of the user.
+
+discriminator
+~~~~~~~~~~~~~
+
+Used to differentiate users with the same username, provided by Discord. If you want to differentiate users, we'd recommend using the `id` attribute.
+
+id
+~~
+
+A `String` UUID of the user, will never change.
+
+avatar
+~~~~~~
+
+A `String` that is the user's avatar's ID, or if they don't have one this is `null`.
+
+avatarURL
+~~~~~~~~~
+
+A `String` that points to the user's avatar's URL, or if they don't have an avatar this is `null`.
+
+status
+~~~~~~
+
+The status of the user as a `String`; offline/online/idle.
+
+-----
+
+Functions
+---------
+
+mention()
+~~~~~~~~~
+
+Returns a `String`. This function will generate the mention string for the user, which when sent will preview as a mention. E.g:
+
+.. code-block:: js
+
+ user.mention(); // something like <@3245982345035>
+
+This is mainly used internally by the API to correct mentions when sending messages, however you can use it.
+
+.. note:: You can also just concatenate a User object with strings to get the mention code, as the `toString()` method points to this. This is useful when sending messages.
+
+equals(object)
+~~~~~~~~~~~~~~
+
+Returns a `Boolean` depending on whether the User's ID (``user.id``) equals the object's ID (``object.id``). You should **always**, always use this if you want to compare users. **NEVER** do ``user1 == user2``.
+
+equalsStrict(object)
+~~~~~~~~~~~~~~~~~~~~
+
+Sees if the supplied object has the same username, ID, avatar and discriminator of the user. Mainly used internally. Returns a `Boolean` depending on the result.
diff --git a/docs/get_started.rst b/docs/get_started.rst
new file mode 100644
index 000000000..96c7b1af6
--- /dev/null
+++ b/docs/get_started.rst
@@ -0,0 +1,37 @@
+===========
+Get Started
+===========
+
+Installation
+------------
+
+Linux / OS X
+~~~~~~~~~~~~
+Run ``npm install discord.js --save`` in your project's directory and you should be good to go!
+
+Windows
+~~~~~~~~~~~~
+Unfortunately, the Windows installation process is a little more lengthy. You need to have `Visual Studio Express`_ (or any of the other distributions of it). This is necessary for build tools for the WebSocket dependency.
+
+.. note:: If you are using another version of Visual Studio, such as 2012, replace the flag with ``--msvs_version=2012``
+
+After you have obtained these tools, you need to run ``npm install discord.js --save --msvs_version=2015`` in your working directory. Hopefully this should all go well!
+
+Cloning the Repo
+----------------
+If you want to try some examples or make your own changes to discord.js, you can `clone the repo`_. After that run ``npm install`` to install dependencies.
+
+Running Examples
+~~~~~~~~~~~~~~~~
+If you've cloned the repo, you also have the option to run some examples. You can also do this by just copying the examples_ and then running them. I'd be more than happy to get some pull requests if you want to make any patches ;)
+
+
+Before you run them though, you need to configure the ``examples/auth.json`` file. This should contain valid Discord credentials and passwords.
+
+After you've configured your credentials, just run ``node examples/pingpong.js`` to run the ping pong example.
+
+
+
+.. _Visual Studio Express: https://www.visualstudio.com/en-us/downloads/download-visual-studio-vs.aspx
+.. _clone the repo: https://github.com/hydrabolt/discord.js.git
+.. _examples: https://github.com/hydrabolt/discord.js/tree/master/examples
\ No newline at end of file
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 000000000..34e8f71a9
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,49 @@
+.. discord.js documentation master file, created by
+ sphinx-quickstart on Fri Sep 25 17:25:49 2015.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to discord.js's documentation!
+======================================
+
+discord.js is an easy-to-use and intuitive JavaScript API for Discord_. It should be able to
+run in node.js / io.js and in the browser.
+
+.. note:: This documentation is still a work-in-progress, apologies if something isn't yet documented!
+
+Contents:
+
+.. _general-docs:
+
+.. toctree::
+ :maxdepth: 2
+ :caption: General
+
+ get_started
+ troubleshooting
+ create_simple_bot
+
+.. _docs:
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Documentation
+
+ docs_resolvable
+ docs_client
+ docs_user
+ docs_server
+ docs_channel
+ docs_pmchannel
+ docs_message
+ docs_invite
+
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`search`
+
+.. _Discord : https://discordapp.com/
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644
index 000000000..c3d1c3bcc
--- /dev/null
+++ b/docs/make.bat
@@ -0,0 +1,263 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^` where ^ is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. texinfo to make Texinfo files
+ echo. gettext to make PO message catalogs
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. xml to make Docutils-native XML files
+ echo. pseudoxml to make pseudoxml-XML files for display purposes
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ echo. coverage to run coverage check of the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+
+REM Check if sphinx-build is available and fallback to Python version if any
+%SPHINXBUILD% 2> nul
+if errorlevel 9009 goto sphinx_python
+goto sphinx_ok
+
+:sphinx_python
+
+set SPHINXBUILD=python -m sphinx.__init__
+%SPHINXBUILD% 2> nul
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.http://sphinx-doc.org/
+ exit /b 1
+)
+
+:sphinx_ok
+
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\discordjs.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\discordjs.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "latexpdf" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ cd %BUILDDIR%/latex
+ make all-pdf
+ cd %~dp0
+ echo.
+ echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "latexpdfja" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ cd %BUILDDIR%/latex
+ make all-pdf-ja
+ cd %~dp0
+ echo.
+ echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "texinfo" (
+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+ goto end
+)
+
+if "%1" == "gettext" (
+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+if "%1" == "coverage" (
+ %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of coverage in the sources finished, look at the ^
+results in %BUILDDIR%/coverage/python.txt.
+ goto end
+)
+
+if "%1" == "xml" (
+ %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The XML files are in %BUILDDIR%/xml.
+ goto end
+)
+
+if "%1" == "pseudoxml" (
+ %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
+ goto end
+)
+
+:end
diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst
new file mode 100644
index 000000000..3f5fa02ad
--- /dev/null
+++ b/docs/troubleshooting.rst
@@ -0,0 +1,10 @@
+Troubleshooting
+===============
+
+Occasionally, the API can stop working for whatever reason. If it was working previously and it stopped working on the same version, it means that there's been a change to the Discord API. In this case, please `make an issue`_ if one relating to a similar issue doesn't exist. Please post a stacktrace if there is one, and be as detailed as possible - *"the API isn't working"* doesn't help at all.
+
+If there is already an issue, feel free to comment that you're also experiencing the same thing. This helps to see how widespread the bug is.
+
+You can try reconnecting before submitting an issue, as sometimes some of the servers may be slightly different.
+
+.. _make an issue : https://github.com/hydrabolt/discord.js/issues
\ No newline at end of file
diff --git a/docs/vars.rst b/docs/vars.rst
new file mode 100644
index 000000000..ad4b9720a
--- /dev/null
+++ b/docs/vars.rst
@@ -0,0 +1,11 @@
+.. _Client : ./docs_client.html
+.. _User : ./docs_user.html
+.. _ready : #ready
+.. _Server : ./docs_server.html
+.. _Channel : ./docs_channel.html
+.. _Message : ./docs_message.html
+.. _PMChannel : ./docs_pmchannel.html
+.. _Invite : ./docs_invite.html
+.. _Channel Resolvable : ./docs_resolvable.html#channel-resolvable
+.. _Invite Resolvable : ./docs_resolvable.html#invite-resolvable
+.. _Promises : https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise
\ No newline at end of file
diff --git a/examples/auth.json b/examples/auth.json
new file mode 100644
index 000000000..32a7e16e6
--- /dev/null
+++ b/examples/auth.json
@@ -0,0 +1,4 @@
+{
+ "email" : "your discord email here",
+ "password" : "your discord password here"
+}
\ No newline at end of file
diff --git a/examples/avatar.js b/examples/avatar.js
index 32ad48a8f..b0eb1bb27 100644
--- a/examples/avatar.js
+++ b/examples/avatar.js
@@ -1,37 +1,41 @@
/*
- * A bot that shows how to mention users in messages and how to
- * access user avatars.
- */
+ this bot is an avatar bot, and will give a user their avatar's URL
+*/
-var Discord = require( "../" );
-var myBot = new Discord.Client();
+var Discord = require("../");
-myBot.login( "hello@example.com", "password1" );
+// Get the email and password
+var AuthDetails = require("./auth.json");
-// The "ready" event is triggered after the bot successfully connected to
-// Discord and is ready to send messages.
-myBot.on( "ready", function() {
- console.log( "Bot connected successfully." );
-} );
+var bot = new Discord.Client();
-myBot.on( "message", function( message ) {
- // React to all messages with the content "$avatar"
- if ( message.content === "$avatar" ) {
- // Obtain the user who requested the avatar.
- var user = message.author;
+bot.on("ready", function () {
+ console.log("Ready to begin! Serving in " + bot.channels.length + " channels");
+});
- // Check whether the user actually has an avatar.
- if ( user.avatar ) {
- // Construct the avatar URL from the user ID and the avatar ID.
- var url = "https://discordapp.com/api/users/" + user.id + "/avatars/" + user.avatar + ".jpg";
+bot.on("disconnected", function () {
- // A user can be mentioned in a message by inserting the string obtained
- // by user.mention() into the message.
- // Note that simply writing "@user" will NOT work.
- this.sendMessage( message.channel, message.author.mention() + ", here's your avatar: " + url );
- } else {
- // Nothing should be done if the user has not set an avatar.
- this.sendMessage( message.channel, message.author.mention() + ", you don't have an avatar!" );
+ console.log("Disconnected!");
+ process.exit(1); //exit node.js with an error
+
+});
+
+bot.on("message", function (msg) {
+ if (msg.content === "$avatar") {
+
+ //see if the user has an avatar
+ if( msg.sender.avatarURL ){
+ bot.reply(msg, msg.sender.avatarURL);
+ }else{
+ //using reply with a message automatically does:
+ // '@sender, ' for you!
+ bot.reply(msg, "you don't have an avatar!");
}
+
+ //alert the console
+ console.log("served " + msg.sender.username);
+
}
-} );
+});
+
+bot.login(AuthDetails.email, AuthDetails.password);
\ No newline at end of file
diff --git a/examples/catapi.js b/examples/catapi.js
new file mode 100644
index 000000000..ae5b7f6aa
--- /dev/null
+++ b/examples/catapi.js
@@ -0,0 +1,36 @@
+/*
+ this bot will send an image of a cat to a channel.
+ may be slow depending on your internet connection.
+*/
+
+var Discord = require("../");
+
+// Get the email and password
+var AuthDetails = require("./auth.json");
+
+var bot = new Discord.Client();
+
+bot.on("ready", function () {
+ console.log("Ready to begin! Serving in " + bot.channels.length + " channels");
+});
+
+bot.on("disconnected", function () {
+
+ console.log("Disconnected!");
+ process.exit(1); //exit node.js with an error
+
+});
+
+bot.on("message", function (msg) {
+ if (msg.content === "$cat") {
+
+ //send a message to the channel the ping message was sent in.
+ bot.sendMessage(msg.channel, "pong!");
+
+ //alert the console
+ console.log("pong-ed " + msg.sender.username);
+
+ }
+});
+
+bot.login(AuthDetails.email, AuthDetails.password);
\ No newline at end of file
diff --git a/examples/formatting.js b/examples/formatting.js
deleted file mode 100644
index 02756eaaa..000000000
--- a/examples/formatting.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Discord uses a subset of Markdown for formatting, so adding formatting to
- * messages is as simple as inserting the formatting codes into the message.
- */
-
-var Discord = require( "../" );
-var myBot = new Discord.Client();
-
-myBot.login( "hello@example.com", "password1" );
-
-// The "ready" event is triggered after the bot successfully connected to
-// Discord and is ready to send messages.
-myBot.on( "ready", function() {
- console.log( "Bot connected successfully." );
-} );
-
-myBot.on( "message", function( message ) {
- // React to all messages with the content "$formatting".
- if ( message.content === "$formatting" ) {
- // Show off formatting by sending a simple message with formatting codes.
- this.sendMessage( message.channel, "**bold** ****semibold**** *italic* " +
- "_**bold and italic**_ __underline__ ~~strikethrough~~" );
- }
-} );
diff --git a/examples/pingpong.js b/examples/pingpong.js
index 51a2664e3..d5d90588f 100644
--- a/examples/pingpong.js
+++ b/examples/pingpong.js
@@ -1,32 +1,37 @@
/*
- * A basic bot that shows how to connect to a Discord account,
- * how to listen to messages and how to send messages.
- *
- * This bot responds to every "ping" message with a "pong".
- */
+ this bot is a ping pong bot, and every time a message
+ beginning with "ping" is sent, it will reply with
+ "pong".
+*/
-var Discord = require( "../" );
+var Discord = require("../");
-// Create the bot
-var myBot = new Discord.Client();
+// Get the email and password
+var AuthDetails = require("./auth.json");
-// Login with an example email and password
-myBot.login( "hello@example.com", "password1" );
+var bot = new Discord.Client();
-// The "ready" event is triggered after the bot successfully connected to
-// Discord and is ready to send messages.
-myBot.on( "ready", function() {
- console.log( "Bot connected successfully." );
-} );
+bot.on("ready", function () {
+ console.log("Ready to begin! Serving in " + bot.channels.length + " channels");
+});
+
+bot.on("disconnected", function () {
+
+ console.log("Disconnected!");
+ process.exit(1); //exit node.js with an error
+
+});
+
+bot.on("message", function (msg) {
+ if (msg.content.substring(0, 4) === "ping") {
+
+ //send a message to the channel the ping message was sent in.
+ bot.sendMessage(msg.channel, "pong!");
+
+ //alert the console
+ console.log("pong-ed " + msg.sender.username);
-// Add a listener to the "message" event, which triggers upon receiving
-// any message
-myBot.on( "message", function( message ) {
- // message.content accesses the content of the message as a string.
- // If it is equal to "ping", then the bot should respond with "pong".
- if ( message.content === "ping" ) {
- // Send a message ("pong") to the channel the message was sent in,
- // which is accessed by message.channel.
- this.sendMessage( message, "pong" );
}
-} );
+});
+
+bot.login(AuthDetails.email, AuthDetails.password);
\ No newline at end of file
diff --git a/examples/presence.js b/examples/presence.js
deleted file mode 100644
index 9014feea2..000000000
--- a/examples/presence.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * A bot that shows how to listen to presence update events, such as a user
- * joining or leaving.
- */
-
-var Discord = require( "../" );
-var myBot = new Discord.Client();
-
-myBot.login( "hello@example.com", "password1" );
-
-// The "ready" event is triggered after the bot successfully connected to
-// Discord and is ready to send messages.
-myBot.on( "ready", function() {
- console.log( "Bot connected successfully." );
-} );
-
-// The "presence" event is triggered when a user joins a server, leaves it or
-// goes away.
-// The status parameter can be "online", "offline" or "idle", respectively.
-myBot.on( "presence", function( user, status, server ) {
- // Send a message on the default channel of the server, as presence updates
- // are not restricted to one channel.
- var message = user.mention() + " is " + status + " in " + server.name + "!";
- console.log(message);
- this.sendMessage( server.getDefaultChannel(), message );
-} );
diff --git a/examples/query.js b/examples/query.js
deleted file mode 100644
index 9341e7e98..000000000
--- a/examples/query.js
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * A bot that shows how to access and search the logs of a specific channel.
- * Specifically, it returns the last message from a given user in the last
- * 100 messages.
- */
-
-var Discord = require( "discord.js" );
-var myBot = new Discord.Client();
-
-myBot.login( "hello@example.com", "password1" );
-
-myBot.on( "message", function( message ) {
- // React to all messages starting with "$query".
- if ( message.content.startsWith( "$query" ) ) {
- // Obtain the channel for which logs should be accessed.
- var channel = message.channel;
-
- // Find all the arguments to the command.
- var arguments = message.content.split( " " );
-
- // Get the first argument specifically, as it contains the username
- // to be queried for.
- var username = arguments.slice( 1 ).join( " " );
-
- // Exit the event handler unless the user exists.
- if ( !username ) {
- myBot.sendMessage( channel, "That user doesn't exist!" );
- return;
- }
-
- // The getChannelLogs() function takes the channel that should be accessed,
- // the amount of messages to query and a callback as its arguments.
- myBot.getChannelLogs( channel, 100, function( error, messageList ) {
- // filter() takes three arguments, the key to be filtered for (in this
- // case the username, so "username"), the value to look for, and whether
- // only the first finding should be returned (true) or a list of all
- // findings (false).
-
- // Check to see if there is an error, if there isn't this will be null,
- // which equates to false in a conditional.
- if ( error ) {
- // There was an error, so stop proceeding as if there is an error
- // retrieving logs, no logs are returned. We should tell the
- // users that there was an error retrieving logs and return.
- myBot.sendMessage( channel, "There was an error retrieving logs!" );
- return;
- }
-
- var message = messageList.filter( "username", username, true );
-
- // Only continue if the message has been found
- if ( message ) {
- myBot.sendMessage( channel, "The last message from user " + username +
- " is: \"" + message.content + "\"." ).
- } else {
- myBot.sendMessage( "That user has not sent a message " +
- "for the last 100 messages!" )
- }
- } );
- }
-} );
diff --git a/examples/status.js b/examples/status.js
deleted file mode 100644
index 9ee2b9a6a..000000000
--- a/examples/status.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * A bot that doesn't interact with Discord, but instead shows how to listen
- * to the "ready" and "disconnected" events, that are triggered when the bot
- * starts up or shuts down, respectively.
- */
-
-var Discord = require( "../" );
-var myBot = new Discord.Client();
-
-myBot.login( "hello@example.com", "password1" );
-
-// The "ready" event is triggered after the bot successfully connected to
-// Discord and is ready to send messages.
-myBot.on( "ready", function() {
- console.log( "Bot connected successfully." );
-} );
-
-// The "disconnected" event is triggered after the connection to Discord
-// ended.
-// It is also triggered when the connection attempt fails, for example due
-// to a wrong password.
-myBot.on( "disconnected", function(e) {
- console.log( "Bot disconnected from Discord -", e.reason );
-} );
diff --git a/gruntfile.js b/gruntfile.js
new file mode 100644
index 000000000..298e8c7c9
--- /dev/null
+++ b/gruntfile.js
@@ -0,0 +1,49 @@
+module.exports = function (grunt) {
+
+ require('load-grunt-tasks')(grunt);
+
+ grunt.initConfig({
+ pkg: grunt.file.readJSON("package.json"),
+ // define source files and their destinations
+ babel: {
+ dist: {
+ files: [{
+ expand: true,
+ cwd: "src/",
+ src: ["**.*"],
+ dest: "lib/",
+ ext: ".js"
+ }]
+ }
+ },
+ browserify: {
+ dist: {
+ files: {
+ 'web-dist/discord.<%= pkg.version %>.js': ["lib/index.js"],
+ },
+ options: {
+ browserifyOptions: {
+ standalone: "Discord"
+ }
+ }
+ }
+ },
+ uglify: {
+ min: {
+ files: {
+ "./web-dist/discord.min.<%= pkg.version %>.js": "./web-dist/discord.<%= pkg.version %>.js"
+ }
+ }
+ }
+ });
+
+ // load plugins
+ grunt.loadNpmTasks('grunt-browserify');
+ grunt.loadNpmTasks('grunt-contrib-uglify');
+
+ // register at least this one task
+ grunt.registerTask('default', ['babel']);
+ grunt.registerTask('web', ['browserify', "uglify"]);
+ grunt.registerTask("dist", ["babel", "browserify", "uglify"])
+
+};
\ No newline at end of file
diff --git a/hydrabot/.gitignore b/hydrabot/.gitignore
deleted file mode 100644
index 070bc70aa..000000000
--- a/hydrabot/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-config.json
-authority.json
diff --git a/hydrabot/README.md b/hydrabot/README.md
deleted file mode 100644
index 90aeffc4b..000000000
--- a/hydrabot/README.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# hydrabot
-Hydrabot is an open-source bot made with the intents of demonstrating the capabilities of [discord.js](https://github.com/hydrabolt/discord.js/).
-
-### Set up
-The easiest setup would be to clone the discord.js repo, and then open a terminal/cmd in this directory and run `node hydrabot.js`.
-
-If you don't want to clone the repo but instead just use this folder, you need to edit `hydrabot.js` to use `require("discord.js")` as opposed to `require("../")`. Cloned directories will always be using the latest **discord.js**.
-
-### Setting up credentials
-
-Create `config.json` to use your Discord email and password, and then run `node hydrabot.js`.
-
-What config.json should look like:
-```js
-{
- "email" : "your email",
- "password" : "your password"
-}
-```
diff --git a/hydrabot/authority.js b/hydrabot/authority.js
deleted file mode 100644
index 1f7c1c4af..000000000
--- a/hydrabot/authority.js
+++ /dev/null
@@ -1,37 +0,0 @@
-var fs = require( "fs" );
-
-var authCache = {};
-
-exports.init = function() {
- try {
- var fd = fs.openSync( "./authority.json", "wx" );
- exports.writeCache();
- } catch ( e ) {
- if ( e.errno !== -4075 ){
- throw e;
- }else{
- authCache = JSON.parse(fs.readFileSync("./authority.json", "utf8"));
- }
- }
-}
-
-exports.getLevel = function(user){
-
- if(authCache[user.id])
- return authCache[user.id];
- else
- return 0;
-
-}
-
-exports.setLevel = function(user, level){
- authCache[user.id] = level;
- exports.writeCache();
-}
-
-exports.writeCache = function() {
- fs.writeFile( './authority.json', JSON.stringify(authCache), function( err ) {
- if ( err )
- console.log("Error saving Authority Caches - " + err.code);
- } );
-}
diff --git a/hydrabot/commands.js b/hydrabot/commands.js
deleted file mode 100644
index b499d9dce..000000000
--- a/hydrabot/commands.js
+++ /dev/null
@@ -1,516 +0,0 @@
-var Authority = require( "./authority.js" );
-var BotClass = require( "./hydrabot.js" );
-var Discord = BotClass.Discord;
-
-Commands = [];
-
-Commands[ "info" ] = {
- oplevel: 0,
- fn: function( bot, params, message ) {
-
- var verbose = hasFlag( params, "verbose" ) || hasFlag( params, "v" );
- var user = getUser( message, params );
-
- bot.reply( message, [
- "here's some info on " + user.mention() + ":",
- "In channel **#" + message.channel.name + "**" + ( verbose ? " - ID *" + message.channel.id + "*" : "" ), ( message.isPM() ?
- "You're in a private conversation with me!" + ( verbose ? " The ID is " + message.channel.id : "" ) : "In the server **" + message.channel.server.name + "**" + ( verbose ? " - ID *" + message.channel.server.id + "*" : "" )
- ),
- "User ID is *" + user.id + "*",
- "Authority/OP Level to me is **" + Authority.getLevel( user ) + "**"
- ], function( err ) {
- if ( err )
- console.log( err );
- } );
-
- }
-}
-
-Commands[ "loading" ] = {
- oplevel: 0,
- fn: function( bot, params, message ) {
-
- var progress = 0;
- var currentMessage;
- var bars = 20;
-
- function getM() {
- var before = progress;
- var after = bars - progress;
- var ret = "";
- for ( x = 0; x < before; x++ ) {
- ret += "-";
- }
- ret += "**#**";
- for ( y = 0; y < after; y++ ) {
- ret += "-";
- }
- return ret;
- }
-
- function doProg() {
- if ( progress === ( bars + 1 ) ) {
- progress = 0;
- }
-
- if ( currentMessage ) {
- bot.updateMessage( currentMessage, getM(), function( err, msg ) {
- if ( !err )
- currentMessage = msg;
- } );
- progress++;
- }
-
- }
-
- bot.sendMessage( message.channel, getM(), function( err, message ) {
- currentMessage = message;
- setInterval( doProg, 200 );
- } );
-
- }
-}
-
-Commands[ "flashy" ] = {
- oplevel: 0,
- fn: function( bot, params, message ) {
-
- var phase = 0;
- var msg;
-
- var textToSay = getKey( params, "m", "FLASH" );
- var speed = parseInt( getKey( params, "s", "500" ) );
-
- function change() {
- if ( msg ) {
-
- var highlighting = ( ( phase % 2 ) === 0 ? "**" : "" );
- phase++;
- bot.updateMessage( msg, highlighting + textToSay + highlighting, function( err, message ) {
- if ( !err ) {
- msg = message;
- }
- } );
- }
- }
-
- bot.sendMessage( message.channel, textToSay, function( err, message ) {
- msg = message;
- setInterval( change, speed );
- } );
-
- }
-}
-
-Commands[ "echo" ] = {
- oplevel: 0,
- fn: function( bot, params, message ) {
-
- bot.sendMessage( message, params.join( " " ), function( err, msg ) {
- if ( err ) {
- bot.sendMessage( message, "Unable to echo!" );
- console.log( err );
- }
- } );
-
- }
-}
-
-Commands[ "auth" ] = {
- oplevel: 0,
- fn: function( bot, params, message ) {
-
- var level = getKey( params, "level", "0" );
- var method = hasFlag( params, "set" ) ? "set" : "get";
- var user = getUser( message, params );
-
- if ( method === "set" ) {
- if ( authLevel( message.author ) <= level ) {
- bot.reply( message, "that authority level is too high for you to set!" );
- } else if ( user.equals( message.author ) ) {
- bot.reply( message, "you can't alter your own authority level!" );
- } else if ( authLevel( user ) >= authLevel( message.author ) ) {
- bot.reply( message, "that user has a higher or equal OP level to you!" );
- } else if ( level < 0 ) {
- bot.reply( message, "that level's a bit too low :P" );
- } else {
- setAuthLevel( user, level );
- bot.reply( message, "I set the authority of " + user.mention() + " to **" + level + "**" );
- }
- } else {
- bot.reply( message, user.equals( message.author ) ? "Your authority level is **" + authLevel( user ) + "**" : "The authority level of " + user.mention() + " is **" + authLevel( user ) + "**" );
- }
-
- }
-}
-
-Commands[ "clear" ] = {
- oplevel: 0,
- fn: function( bot, params, message ) {
-
- if ( !message.isPM() ) {
- if ( authLevel( message.author ) < 1 ) {
- bot.reply( message, BotClass.AUTH_ERROR );
- return;
- }
- }
-
- var initMessage = false,
- cleared = false;
-
- bot.getChannelLogs( message.channel, 250, function( err, logs ) {
-
- if ( err ) {
- bot.sendMessage( "Couldn't grab logs to delete messages." );
- } else {
-
- var deletedCount = 0,
- failedCount = 0,
- todo = logs.length();
- for ( msg of logs.contents ) {
- if ( msg.author.equals( bot.user ) ) {
- bot.deleteMessage( msg, function( err ) {
- todo--;
- if ( err )
- failedCount++;
- else
- deletedCount++;
-
- if ( todo === 0 ) {
- bot.reply(
- message,
- "Done! " + deletedCount + " message(s) were deleted, with " + failedCount + " error(s).",
- false, {
- selfDestruct: 5000
- }
- );
- cleared = true;
- deleteInitMessage();
- }
- } );
- } else {
- todo--;
- }
- }
-
- }
-
- } );
-
- bot.reply( message, "clearing up my messages...", function( err, msg ) {
- if ( !err ) {
- initMessage = msg;
- if ( cleared )
- deleteInitMessage();
- }
- } );
-
- function deleteInitMessage() {
- if ( initMessage ) {
- bot.deleteMessage( initMessage );
- }
- }
-
- }
-}
-
-Commands[ "leave" ] = {
- oplevel: 3,
- fn: function( bot, params, message ) {
-
- var silent = hasFlag( params, "s" ) || hasFlag( params, "silent" );
-
- if ( message.isPM() ) {
- bot.reply( message, "Umm... I can't leave PMs... How awkward..." );
- } else {
-
- if ( !silent )
- bot.reply( message, "Ok ;( I'm leaving!" );
-
- bot.leaveServer( message.channel.server, function( err ) {
- if ( err ) {
- bot.reply( message, "There was an error leaving... how awkward." );
- }
- } );
- }
- }
-}
-
-Commands[ "avatar" ] = {
- oplevel: 0,
- fn: function( bot, params, message ) {
-
- var user = getUser( message, params, bot );
-
- if ( !user.avatar ) {
- bot.sendMessage( message.channel, user.mention() + " does not have an avatar!" );
- } else {
- bot.reply( message, user.getAvatarURL() );
- }
- }
-}
-
-Commands[ "setusername" ] = {
- oplevel: 3,
- fn: function( bot, params, message ) {
-
- var name = getKey( params, "name", "Boris Johnson" );
-
- bot.setUsername( name, function( err ) {
- if ( err )
- bot.reply( message, err );
- } )
-
- }
-}
-
-Commands[ "cat" ] = {
- oplevel: 0,
- fn: function( bot, params, message ) {
-
- var http = require( "http" );
- var request = require( 'request' );
-
- bot.sendFile( message, request("http://thecatapi.com/api/images/get?type=jpg"), "cat.jpg", function( err ) {
- if(err)
- bot.reply( message, err );
- } );
-
- }
-}
-
-Commands[ "icon" ] = {
- oplevel: 0,
- fn: function( bot, params, message ) {
-
- if ( message.isPM() ) {
- bot.reply( message, "PMs don't have avatars!" );
- return;
- }
-
- if ( !message.channel.server.icon ) {
- bot.reply( message, "this server does not have an icon!" );
- return;
- }
-
- bot.reply( message, message.channel.server.getIconURL() );
-
- }
-}
-
-Commands[ "avataritup" ] = {
- oplevel: 2,
- fn: function( bot, params, message ) {
-
- console.log( message.channel );
- bot.sendMessage( message, message.channel.server.members.getValues( "avatar" ).join( "\n" ) );
-
- }
-}
-
-Commands[ "feedback" ] = {
-
- oplevel: 0,
- fn: function( bot, params, message ) {
-
- var amount = getKey( params, "amount" ) || getKey( params, "n" ) || 1000;
-
- bot.getChannelLogs( message.channel, amount, function( err, logs ) {
-
- console.log( logs );
-
- if ( err ) {
- bot.reply( message, "an error occurred when grabbing the logs.", false, {
- selfDestruct: 3000
- } );
- } else {
-
- var found = [];
- for ( msg of logs.contents ) {
-
- if ( ~msg.content.indexOf( "[request" ) || ~msg.content.indexOf( "[feature" || ~msg.content.indexOf( "[suggestion" ) ) ) {
- if ( msg.content.length > 10 ) {
- found.push( msg );
- }
- }
-
- }
-
- bot.sendMessage( message.author, "Ok, here's a rundown of all feature requests so far:", function( err, ms ) {
-
- if ( !err )
- gothroughit();
-
- } );
-
- bot.reply( message, "I found " + found.length + " result(s) that matched this. I'll send it to you in a PM.", false, {
- selfDestruct: 3000
- } );
-
- function gothroughit() {
- for ( msg of found ) {
-
- bot.sendMessage( message.author, "**" + msg.author.username + "** said:\n " + msg.content );
-
- }
- }
- }
- } );
-
- }
-
-}
-
-Commands[ "acceptinvite" ] = {
- oplevel: 0,
- fn: function( bot, params, message ) {
-
- var inv = getKey( params, "i" );
-
- bot.joinServer( inv, function( err, server ) {
- if ( err ) {
- bot.reply( message, "I couldn't join that server :(" );
- } else {
- bot.reply( message, "I joined **" + server.name + "**, a server with " + server.channels.length() + " channels and " + server.members.length() + " members." );
- }
- } );
-
- }
-}
-
-Commands[ "filtertest" ] = {
- oplevel: 0,
- fn: function( bot, params, message ) {
- console.log( message.channel.server.members.filter( "username", "HYDRABOLT" ) );
- console.log( message.channel.server.members.filter( "username", "HYDRABOLT", false, true ) );
- }
-}
-
-Commands[ "test" ] = {
- oplevel: 0,
- fn: function( bot, params, message ) {
-
- console.log( message.channel.server.channels.filter( "name", "a", true ) );
-
- }
-}
-
-Commands[ "remind" ] = {
- oplevel: 0,
- fn: function( bot, params, message ) {
-
- var time = parseInt( getKey( params, "t" ) || getKey( params, "time" ) ) * 1000 || 21000;
- var msg = getKey( params, "m" ) || getKey( params, "msg" ) || getKey( params, "message" );
-
- bot.reply( message, "I'll remind you to *" + msg + "* in *" + time / 1000 + "* seconds.", false, true, {
- selfDestruct: time
- } );
-
- setTimeout( send, time );
-
- function send() {
- bot.sendMessage( message.author, time + " seconds are up! **" + msg + "**." );
- }
-
- }
-}
-
-Commands[ "annoy" ] = {
- oplevel: 0,
- fn: function( bot, params, message ) {
-
- var user = getUser( message, params );
-
- bot.sendMessage( user, "Ha I'm annoying you on " + message.author.mention() + "'s request!" );
-
- }
-}
-
-Commands[ "activity" ] = {
- oplevel: 0,
- fn: function( bot, params, message ) {
-
- var amount = getKey( params, "amount" ) || getKey( params, "n" ) || 250;
- var limit = getKey( params, "limit" ) || getKey( params, "l" ) || 10;
-
- bot.getChannelLogs( message.channel, amount, function( err, logs ) {
-
- if ( err ) {
- bot.reply( message, "error gettings logs." );
- } else {
-
- var activity = {},
- count = 0;
- for ( msg of logs.contents ) {
-
- count = logs.length();
-
- if ( !activity[ msg.author.id ] )
- activity[ msg.author.id ] = 0;
- activity[ msg.author.id ]++;
- }
-
- var report = "here's a list of activity over the last " + count + " messages :\n\n";
-
- var usernames = {};
- for ( id in activity ) {
- usernames[ id ] = bot.getUser( id ).username;
- }
-
- for ( id in activity ) {
- report += usernames[ id ] + " | " + activity[ id ] + " | **" + Math.round( ( activity[ id ] / count ) * 100 ) + "%**.\n";
- }
-
- bot.reply( message, report, false, false );
- }
-
- } );
-
- }
-}
-
-exports.Commands = Commands;
-
-function hasFlag( array, flag ) {
- return ~array.indexOf( flag );
-}
-
-function getKey( array, key, def ) {
-
- for ( element of array ) {
- var chunks = element.split( "=" );
- if ( chunks.length > 1 ) {
- if ( chunks[ 0 ] == key ) {
- return chunks[ 1 ];
- }
- }
- }
-
- return def;
-
-}
-
-function authLevel( user ) {
- return Authority.getLevel( user );
-}
-
-function setAuthLevel( user, level ) {
- Authority.setLevel( user, level );
-}
-
-function getUser( message, params, bot ) {
- var usr = false;
- if ( !message.isPM() ) {
- var wantedUser = getKey( params, "user", false ) || getKey( params, "u", false );
- if ( wantedUser ) {
- if ( bot ) {
- console.log( bot.getUsers().length() );
- return bot.getUsers().filter( "username", wantedUser, true );
- }
- usr = message.channel.server.members.filter( Discord.isUserID( wantedUser ) ? "id" : "username", wantedUser, true );
- }
- }
- if ( !usr )
- usr = message.author;
- return usr;
-}
diff --git a/hydrabot/hydrabot.js b/hydrabot/hydrabot.js
deleted file mode 100644
index 4e3f287f8..000000000
--- a/hydrabot/hydrabot.js
+++ /dev/null
@@ -1,132 +0,0 @@
-// If you did not clone discord.js, change the require parameter to `discord.js`
-// and then run `npm install --save discord.js` in the same directory as this
-// file. The bot should then run.
-var Discord = require( "../" );
-exports.Discord = Discord;
-
-// Load the config file. If you have not already, make one that follows the
-// structure : { "email" : "discordEmail", "password" : "discordPassword" }
-var BotConfig = require( "./config.json" );
-
-// Load the commands file
-var Commands = require( "./commands.js" ).Commands;
-
-// Load the Authority handler
-var Authority = require( "./authority.js" );
-
-// Initialise it
-Authority.init();
-
-// Create a new Discord Client
-var hydrabot = new Discord.Client();
-
-// An array of single character prefixes the bot will respond to
-var commandPrefixes = [ "$", "£", "`" ];
-
-// Log the client in using the auth details in config.json
-
-hydrabot.on("debug", function(m){
- console.log("debug", m);
-})
-
-console.time("hydrabotbenchmark");
-hydrabot.login( BotConfig.email, BotConfig.password );
-var time = Date.now();
-
-// When the bot is ready to go, output to the console
-hydrabot.on( "ready", function() {
- console.timeEnd("hydrabotbenchmark");
-} );
-
-hydrabot.on("userupdate", function(ol, ne){
-
- var serversInvolved = hydrabot.getServers().deepFilter(["members", "id"], ol.id);
-
- for(server of serversInvolved.contents){
- hydrabot.sendMessage(server.getDefaultChannel(), "Just sayin', "+ol.username+" changed their name to "+ne.username+". I know. Disgraceful.", function(err){
- console.log(err);
- }, {
- selfDestruct: 5000
- });
- }
-
-});
-
-// When the bot gets disconnected, exit.
-hydrabot.on( "disconnected", function( obj ) {
- // Say we couldn't connect and then exit
- console.log( "Disconnected - " + obj.reason );
- process.exit( 0 );
-} );
-
-hydrabot.on("messageDelete", function(message){
- console.log(message);
-})
-
-hydrabot.on("messageUpdate", function(former, edit){
-
- if(former){
-
- if(former.author.equals(this.user) || former.content === edit.content){
- return;
- }
-
- var seconds = Math.round((Date.now() - former.time) / 1000);
-
- var channel = former.channel;
- hydrabot.sendMessage(channel, "**"+former.author.username + "** (edit from message "+seconds+" seconds ago):\n " + former.content);
-
- }
-
-})
-
-hydrabot.on( "message", function( message ) {
-
- // if the message doesn't begin with a valid command prefix exit
-
- if ( commandPrefixes.indexOf( message.content.charAt( 0 ) ) == -1 )
- return;
-
- var command = "",
- params = []; //set the message details
-
- // remove the prefix from the start of the message
- message.content = message.content.substr( 1 );
-
- // split the message by slashes. This will yield something
- // like: ["command", "a", "b", "c"].
- var chunks = message.content.split( "/" );
-
- for ( key in chunks ) { //loop through the chunks and trim them
- chunks[ key ] = chunks[ key ].trim();
- }
-
- command = chunks[ 0 ]; //the first param will be the command
- params = chunks.slice( 1 );
-
- // it's less messy if we outsource to another function
- handleMessage( command, params, message );
-
-} );
-
-function handleMessage( command, params, message ) {
-
- if ( Commands[ command ] ) {
-
- if ( Authority.getLevel( message.author ) >= Commands[ command ].oplevel ) {
- //user has authority to do this
- Commands[ command ].fn( hydrabot, params, message );
-
- } else {
- //user doesn't have authority
- hydrabot.reply( message, exports.AUTH_ERROR );
- }
-
- } else {
- hydrabot.reply( message, exports.NOT_FOUND );
- }
-
-}
-
-exports.AUTH_ERROR = "you don't have authority to do this!";
-exports.NOT_FOUND = "that command was not found!";
diff --git a/index.js b/index.js
deleted file mode 100644
index 648716ac2..000000000
--- a/index.js
+++ /dev/null
@@ -1,1068 +0,0 @@
-var request = require( "superagent" );
-var Endpoints = require( "./lib/endpoints.js" );
-var Server = require( "./lib/server.js" ).Server;
-var Message = require( "./lib/message.js" ).Message;
-var User = require( "./lib/user.js" ).User;
-var Channel = require( "./lib/channel.js" ).Channel;
-var List = require( "./lib/list.js" ).List;
-var Invite = require( "./lib/invite.js" ).Invite;
-var PMChannel = require( "./lib/PMChannel.js" ).PMChannel;
-var WebSocket = require( 'ws' );
-var Internal = require( "./lib/internal.js" ).Internal;
-var TokenManager = require( "./lib/TokenManager.js" ).TokenManager;
-
-var serverCreateRequests = [].globalLoginTime = Date.now();
-
-function tp( time ) {
- return Date.now() - time;
-}
-
-/**
- * The wrapper module for the Discord Client, also provides some helpful objects.
- *
- * @module Discord
- */
-exports;
-
-exports.Endpoints = Endpoints;
-exports.Server = Server;
-exports.Message = Message;
-exports.User = User;
-exports.Channel = Channel;
-exports.List = List;
-exports.Invite = Invite;
-exports.PMChannel = PMChannel;
-
-/**
- * The Discord Client used to interface with the Discord API. Instantiate this to start writing code
- * with discord.js
- * @class Client
- * @constructor
- * @param {Object} [options] An object containing configurable options.
- * @param {Number} [options.maxmessage=5000] The maximum amount of messages to be stored per channel.
- */
-
-exports.Client = function( options ) {
-
- /**
- * Contains the options of the client
- * @attribute options
- * @type {Object}
- */
- this.options = options || {};
- this.options.maxmessage = 5000;
- this.tokenManager = new TokenManager( "./", "tokencache.json" );
- /**
- * Contains the token used to authorise HTTP requests and WebSocket connection. Received when login was successful.
- * @attribute token
- * @readonly
- * @type {String}
- */
- this.token = "";
- /**
- * Indicates whether the client is logged in or not. Does not indicate whether the client is ready.
- * @attribute loggedIn
- * @readonly
- * @type {Boolean}
- */
- this.loggedIn = false;
- /**
- * The WebSocket used when receiving message and other event updates.
- * @type {WebSocket}
- * @attribute websocket
- * @readonly
- */
- this.websocket = null;
- /**
- * An Object containing the functions tied to events. These should be set using Client.on();
- * @type {Object}
- * @attribute events
- */
- this.events = {};
- /**
- * The User of the Client class, set when the initial startup is complete.
- * @attribute user
- * @type {User}
- * @readonly
- */
- this.user = null;
- /**
- * Indicates whether the Client is ready and has cached all servers it as aware of.
- * @type {Boolean}
- * @attribute ready
- * @readonly
- */
- this.ready = false;
- /**
- * A List containing all the Servers the Client has access to.
- * @attribute serverList
- * @type {List}
- * @readonly
- */
- this.serverList = new List( "id" );
- /**
- * A List containing all the PMChannels the Client has access to.
- * @attribute PMList
- * @type {List}
- * @readonly
- */
- this.PMList = new List( "id" );
-
-}
-
-/**
- * Returns a list of all servers that the Discord Client has access to.
- *
- * @method getServers
- * @return {List} ServerList
- */
-exports.Client.prototype.getServers = function() {
- return this.serverList;
-}
-
-/**
- * Returns a list of all servers that the Discord Client has access to.
- * @method getChannels
- * @return {List} Channelist
- */
-exports.Client.prototype.getChannels = function() {
- return this.serverList.concatSublists( "channels", "id" );
-}
-
-/**
- * Returns a Server matching the given id, or false if not found. Will return false if the server is not cached or not available.
- * @method getServer
- * @param {String/Number} id The ID of the Server
- * @return {Server} The Server matching the ID
- */
-exports.Client.prototype.getServer = function( id ) {
- return this.getServers().filter( "id", id, true );
-}
-
-/**
- * Returns a Channel matching the given id, or false if not found. Will return false if the Channel is not cached or not available.
- * @method getChannel
- * @param {String/Number} id The ID of the Channel
- * @return {Server} The Channel matching the ID
- */
-exports.Client.prototype.getChannel = function( id ) {
- return this.getChannels().filter( "id", id, true );
-}
-
-/**
- * Returns a Channel matching the given name, or false if not found. Will return false if the Channel is not cached or not available.
- * @method getChannelByName
- * @param {String/Number} name The Name of the Channel
- * @return {Server} The Channel matching the Name
- */
-exports.Client.prototype.getChannelByName = function( name ) {
- return this.getChannels().filter( "name", name, true );
-}
-
-/**
- * Triggers an .on() event.
- * @param {String} event The event to be triggered
- * @param {Array} args The arguments to be passed onto the method
- * @return {Boolean} whether the event was triggered successfully.
- * @method triggerEvent
- * @private
- */
-exports.Client.prototype.triggerEvent = function( event, args ) {
-
- if ( !this.ready && event !== "raw" && event !== "disconnected" && event !== "debug" ) { //if we're not even loaded yet, don't try doing anything because it always ends badly!
- return false;
- }
-
- if ( this.events[ event ] ) {
- this.events[ event ].apply( this, args );
- return true;
- } else {
- return false;
- }
-
-}
-
-/**
- * Binds a function to an event
- * @param {String} name The event name which the function should be bound to.
- * @param {Function} fn The function that should be bound to the event.
- * @method on
- */
-exports.Client.prototype.on = function( name, fn ) {
- this.events[ name ] = fn;
-}
-
-/**
- * Unbinds a function from an event
- * @param {String} name The event name which should be cleared
- * @method off
- */
-exports.Client.prototype.off = function( name ) {
- this.events[ name ] = function() {};
-}
-
-exports.Client.prototype.cacheServer = function( id, cb, members ) {
- var self = this;
- var serverInput = {};
-
- if ( typeof id === 'string' || id instanceof String ) {
- //actually an ID
-
- if ( this.serverList.filter( "id", id ).length > 0 ) {
- return;
- }
-
- Internal.XHR.getServer( self.token, id, function( err, data ) {
- if ( !err ) {
- makeServer( data );
- }
- } )
-
- } else {
- // got objects because SPEEEDDDD
-
- if ( this.serverList.filter( "id", id.id ).length > 0 ) {
- return;
- }
- serverInput = id;
- id = id.id;
- makeServer( serverInput );
-
- }
-
- function channelsFromHTTP() {
- Internal.XHR.getChannel( self.token, id, function( err ) {
- if ( !err )
- cacheChannels( res.body );
- } )
- }
-
- var server;
-
- function makeServer( dat ) {
- server = new Server( dat.region, dat.owner_id, dat.name, id, serverInput.members || dat.members, dat.icon, dat.afk_timeout, dat.afk_channel_id );
- if ( dat.channels )
- cacheChannels( dat.channels );
- else
- channelsFromHTTP();
- }
-
- function cacheChannels( dat ) {
-
- var channelList = dat;
- for ( channel of channelList ) {
- server.channels.add( new Channel( channel, server ) );
- }
- self.serverList.add( server );
-
- cb( server );
- }
-
-}
-
-/**
- * Logs the Client in with the specified credentials and begins initialising it.
- * @async
- * @method login
- * @param {String} email The Discord email.
- * @param {String} password The Discord password.
- * @param {Function} [callback] Called when received reply from authentication server.
- * @param {Object} callback.error Set to null if there was no error logging in, otherwise is an Object that
- * can be evaluated as true.
- * @param {String} callback.error.reason The reason why there was an error
- * @param {Object} callback.error.error The raw XHR error.
- * @param {String} callback.token The token received when logging in
- */
-exports.Client.prototype.login = function( email, password, callback, noCache ) {
-
- globalLoginTime = Date.now();
-
- this.debug( "login called at " + globalLoginTime );
-
- var self = this;
- callback = callback || function() {};
-
- if ( noCache == undefined || noCache == null ) {
- noCache = false;
- }
-
- self.connectWebsocket();
-
- if ( this.tokenManager.exists( email ) && !noCache ) {
-
- var token = this.tokenManager.getToken( email, password );
- if ( !token.match( /[^\w.-]+/g ) ) {
- done( this.tokenManager.getToken( email, password ) );
- self.debug( "loaded token from caches in " + tp( globalLoginTime ) );
- return;
- } else {
- self.debug( "error getting token from caches, using default auth" );
- }
- }
-
- var time = Date.now();
- Internal.XHR.login( email, password, function( err, token ) {
- if ( err ) {
- self.triggerEvent( "disconnected", [ {
- reason: "failed to log in",
- error: err
- } ] );
- self.websocket.close();
- self.debug( "failed to login in " + tp( globalLoginTime ) );
- } else {
- if ( !noCache ) {
- self.tokenManager.addToken( email, token, password );
- }
- self.debug( "loaded token from auth servers in " + tp( globalLoginTime ) );
- done( token );
- }
-
- } );
-
- function done( token ) {
- self.email = email;
- self.password = password;
- self.debug( "using token " + token );
- self.token = token;
- self.websocket.sendData();
- self.loggedIn = true;
- callback( null, token );
- }
-}
-
-/**
- * Replies to a message with a given message
- * @param {Message/User/Channel/Server/String} destination Where the message should be sent. Channel IDs can also be used here.
- * @param {String/Message/Array} toSend If a message, the message's content will be sent. If an array, a message will be sent of
- * the array seperated by a newline. If a String, the string will be sent.
- * @param {Function} callback Called when a response from the API has been received, the message has either been sent or not.
- * @param {Object} callback.error If there was an error, this would be an XHR Error object. Otherwise, it will be null.
- * @param {Message} callback.message If there were no errors, this will be the sent message in Message form.
- * @param {Object} options see sendMessage(options)
- * @method reply
- */
-exports.Client.prototype.reply = function( destination, toSend, callback, options ) {
-
- if ( toSend instanceof Array ) {
- toSend = toSend.join( "\n" );
- }
-
- toSend = destination.author.mention() + ", " + toSend;
-
- this.sendMessage( destination, toSend, callback, options );
-
-}
-
-exports.Client.prototype.connectWebsocket = function( cb ) {
-
- var self = this;
-
- var sentInitData = false;
-
- this.websocket = new WebSocket( Endpoints.WEBSOCKET_HUB );
- this.websocket.onclose = function( e ) {
- self.triggerEvent( "disconnected", [ {
- reason: "websocket disconnected",
- error: e
- } ] );
- };
- this.websocket.onmessage = function( e ) {
-
- self.triggerEvent( "raw", [ e ] );
-
- var dat = JSON.parse( e.data );
- var webself = this;
-
- switch ( dat.op ) {
-
- case 0:
- if ( dat.t === "READY" ) {
-
- self.debug( "got ready packet" );
-
- var data = dat.d;
-
- self.user = new User( data.user );
-
- var _servers = data.guilds,
- servers = [];
-
- var cached = 0,
- toCache = _servers.length;
-
- for ( x in data.private_channels ) {
- self.PMList.add( new PMChannel( data.private_channels[ x ].recipient, data.private_channels[ x ].id ) );
- }
-
- for ( x in _servers ) {
- _server = _servers[ x ];
-
- self.cacheServer( _server, function( server ) {
- cached++;
- if ( cached === toCache ) {
- self.ready = true;
- self.triggerEvent( "ready" );
- self.debug( "ready triggered" );
- }
- } );
- }
-
- setInterval( function() {
- webself.keepAlive.apply( webself );
- }, data.heartbeat_interval );
-
- } else if ( dat.t === "MESSAGE_CREATE" ) {
- var data = dat.d;
-
- var channel = self.getChannel( data.channel_id );
- var message = new Message( data, channel );
- self.triggerEvent( "message", [ message ] );
- if ( channel.messages )
- channel.messages.add( message );
-
- } else if ( dat.t === "MESSAGE_DELETE" ) {
- var data = dat.d;
-
- var channel = self.getChannel( data.channel_id );
-
- if ( !channel.messages )
- return;
-
- var _msg = channel.messages.filter( "id", data.id, true );
-
- if ( _msg ) {
- self.triggerEvent( "messageDelete", [ _msg ] );
- channel.messages.removeElement( _msg );
- }
-
- } else if ( dat.t === "MESSAGE_UPDATE" ) {
-
- var data = dat.d;
- if ( !self.ready )
- return;
-
- var formerMessage = false;
-
- var channel = self.getChannel( data.channel_id );
-
- if ( channel ) {
-
- formerMessage = channel.messages.filter( "id", data.id, true );
- var newMessage;
-
- data.author = data.author || formerMessage.author;
- data.timestamp = data.time || formerMessage.time;
- data.content = data.content || formerMessage.content;
- data.channel = data.channel || formerMessage.channel;
- data.id = data.id || formerMessage.id;
- data.mentions = data.mentions || formerMessage.mentions;
- data.mention_everyone = data.mention_everyone || formerMessage.everyoneMentioned;
- data.embeds = data.embeds || formerMessage.embeds;
-
- try {
- newMessage = new Message( data, channel );
- } catch ( e ) {
- self.debug( "dropped a message update packet" );
- return;
- }
-
- self.triggerEvent( "messageUpdate", [ formerMessage, newMessage ] );
-
- if ( formerMessage )
- channel.messages.updateElement( formerMessage, newMessage );
- else
- channel.messages.add( newMessage );
-
- }
-
- } else if ( dat.t === "PRESENCE_UPDATE" ) {
-
- var data = dat.d;
- var getUser = self.getUser( data.user.id );
- if ( getUser ) {
- //user already exists
- var usr = new User( data.user );
- if ( usr.equalsStrict( getUser ) ) {
- //no changes, actually a presence.
- } else {
- if ( self.updateUserReferences( data.user.id, getUser, new User( data.user ) ) ) {
- self.triggerEvent( "userupdate", [ getUser, usr ] );
- }
- }
- }
- self.triggerEvent( "presence", [ new User( data.user ), data.status, self.serverList.filter( "id", data.guild_id, true ) ] );
-
- } else if ( dat.t === "GUILD_DELETE" ) {
-
- var deletedServer = self.serverList.filter( "id", dat.d.id, true );
-
- if ( deletedServer ) {
- self.triggerEvent( "serverDelete", [ deletedServer ] );
- }
-
- } else if ( dat.t === "CHANNEL_DELETE" ) {
-
- var delServer = self.serverList.filter( "id", dat.d.guild_id, true );
-
- if ( delServer ) {
- var channel = delServer.channels.filter( "id", dat.d.id, true );
-
- if ( channel ) {
- self.triggerEvent( "channelDelete", [ channel ] );
- }
- }
-
- } else if ( dat.t === "GUILD_CREATE" ) {
-
- if ( !self.serverList.filter( "id", dat.d.id, true ) ) {
- self.cacheServer( dat.d, function( server ) {
- if ( serverCreateRequests[ server.id ] ) {
- serverCreateRequests[ server.id ]( null, server );
- serverCreateRequests[ server.id ] = null;
- } else {
- self.triggerEvent( "serverJoin", [ server ] );
- }
- } );
- }
-
- } else if ( dat.t === "CHANNEL_CREATE" ) {
-
- var srv = self.serverList.filter( "id", dat.d.guild_id, true );
-
- if ( srv ) {
-
- if ( !srv.channels.filter( "id", dat.d.d, true ) ) {
-
- var chann = new Channel( dat.d, srv );
-
- srv.channels.add( new Channel( dat.d, srv ) );
- self.triggerEvent( "channelCreate", [ chann ] );
-
- }
-
- }
-
- } else if ( dat.t === "USER_UPDATE" ) {
-
- if ( dat.d.id === self.user.id ) {
- var newUsr = new User( dat.d );
- self.triggerEvent( "userupdate", [ self.user, newUsr ] );
- self.user = newUsr;
- }
-
- }
- break;
-
- }
-
- };
- this.websocket.sendPacket = function( p ) {
- this.send( JSON.stringify( p ) );
- }
- this.websocket.keepAlive = function() {
-
- if ( this.readyState !== 1 )
- return false;
-
- this.sendPacket( {
- op: 1,
- d: Date.now()
- } );
-
- }
- this.websocket.onopen = function() {
-
- self.debug( "websocket conn open" );
- this.sendData( "onopen" );
-
- }
- this.websocket.sendData = function( why ) {
- if ( this.readyState == 1 && !sentInitData && self.token ) {
- sentInitData = true;
- var connDat = {
- op: 2,
- d: {
- token: self.token,
- v: 2
- }
- };
-
- connDat.d.properties = Internal.WebSocket.properties;
- this.sendPacket( connDat );
- }
- }
-}
-
-exports.Client.prototype.debug = function( msg ) {
- this.triggerEvent( "debug", [ "[SL " + tp( globalLoginTime ) + "] " + msg ] );
-}
-
-/**
- * Logs the current Client out of Discord and closes any connections.
- * @param {Function} callback Called after a response is obtained.
- * @param {Object} callback.error Null unless there was an error, in which case is an XHR error.
- * @method logout
- */
-exports.Client.prototype.logout = function( callback ) {
-
- callback = callback || function() {};
-
- var self = this;
-
- Internal.XHR.logout( self.token, function( err ) {
- if ( err ) {
- callback( err );
- }
- self.loggedIn = false;
- self.websocket.close();
- } );
-
-}
-
-/**
- * Creates a server with the specified name and region and returns it
- * @param {String} name The name of the server
- * @param {String} region The region of the server
- * @param {Function} callback Called when the request is made.
- * @param {Object} callback.error An XHR error or null if there were no errors.
- * @param {Server} callback.server A Server object representing the created server.
- * @method createServer
- * @async
- */
-exports.Client.prototype.createServer = function( name, region, cb ) {
-
- var self = this;
-
- Internal.XHR.createServer( self.token, name, region, function( err, data ) {
-
- if ( err ) {
- cb( err );
- } else {
-
- self.cacheServer( data, function( server ) {
- cb( null, server );
- } );
-
- }
-
- } );
-
-}
-
-/**
- * Makes the Client leave the Server
- * @param {Server} server A server object. The server you want to leave.
- * @param {Function} callback Called when the leave request is made.
- * @param {Object} callback.error An XHR error or null if there were no errors.
- * @param {Server} callback.server A Server object representing the deleted server.
- * @method leaveServer
- * @async
- */
-exports.Client.prototype.leaveServer = function( server, callback ) {
-
- var self = this;
-
- // callback is not necessary for this function
- callback = callback || function() {};
-
- Internal.XHR.leaveServer( self.token, server.id, function( err ) {
-
- if ( err ) {
- callback( err );
- } else {
- self.serverList.removeElement( server );
- callback( null, server );
- }
-
- } );
-
-}
-
-/**
- * Creates an Invite to the specified channel/server with the specified options
- * @param {Channel/Server} channel The channel/server the invite is to be made to.
- * @param {Object} [options] The options for the invite
- * @param {Number} [options.max_age=0] When the invite will expire in seconds
- * @param {Number} [options.max_uses=0] How many uses the invite has
- * @param {Boolean} [options.temporary=false] Whether the invite is temporary
- * @param {Boolean} [options.xkcdpass=false] Whether the invite's code should be composed of words.
- * @param {Function} callback Called when the invite request has been made
- * @param {Object} callback.error An XHR Error or null if there were no errors.
- * @param {Invite} callback.invite An invite object representing the created invite.
- * @method createInvite
- */
-exports.Client.prototype.createInvite = function( channel, options, callback ) {
-
- var self = this;
- var options = options || {};
-
- // callback is not necessary for this function
- callback = callback || function() {};
-
- if ( channel instanceof Server ) {
- channel = channel.getDefaultChannel();
- }
-
- options.max_age = options.max_age || 0;
- options.max_uses = options.max_uses || 0;
- options.temporary = options.temporary || false;
- options.xkcdpass = options.xkcd || false;
-
- Internal.XHR.createInvite( self.token, channel.id, options, function( err, data ) {
-
- if ( err ) {
- callback( err );
- } else {
- callback( null, new Invite( data ) );
- }
-
- } );
-
-}
-
-exports.Client.prototype.startPM = function( user, callback ) {
-
- var self = this;
-
- callback = callback || function() {};
-
- Internal.XHR.startPM( self.token, self.user.id, user.id, function( err, data ) {
-
- if ( err ) {
- callback( err );
- } else {
- var channel = new PMChannel( data.recipient, data.id );
- self.PMList.add( channel );
- callback( null, channel );
- }
-
- } );
-
-}
-
-/**
- * Sends a message to the specified destination.
- * @param {Server/Channel/PMChannel/Message/User/String} destination Where the message should be sent. If this is a String, the String should be a channel ID.
- * @param {String/Array/Message} toSend The message to send. If an array, the array will be seperated into new lines and then sent.
- * @param {Function} callback Called when the message has been sent.
- * @param {Object} error An XHR Error or null if there were no errors.
- * @param {Message} message A message object representing the sent object.
- * @param {Object} [options] An object containing options for the message.
- * @param {Array/Boolean/String} [options.mentions=true] If an Array, it should be an array of User IDs. If a boolean, false will
- * notify no-one, and true will figure out who should be mentioned based on the message. If a String, should be a User
- * ID.
- * @param {Number} [options.selfDestruct=false] If specified, should be the amount of milliseconds at which the message should
- * delete itself after being sent.
- * @method sendMessage
- */
-
-exports.Client.prototype.sendFile = function( destination, toSend, fileName, callback, options ) {
-
- this.sendMessage( destination, toSend, callback, options, fileName );
-
-}
-
-exports.Client.prototype.sendMessage = function( destination, toSend, callback, options, fileName ) {
-
- options = options || {};
- callback = callback || function() {};
-
- var channel_id, message, mentions, self = this;
-
- channel_id = resolveChannel( destination, self );
- if ( !fileName ) {
- message = resolveMessage( toSend );
- mentions = resolveMentions( message, options.mention );
- }
-
- if ( channel_id ) {
- send();
- } else {
- //a channel is being sorted
- }
-
- function send() {
-
- if(fileName){
- Internal.XHR.sendFile( self.token, channel_id, toSend, fileName, function(err){
-
- callback(err);
-
- } );
- return;
- }
-
- Internal.XHR.sendMessage( self.token, channel_id, {
- content: message,
- mentions: mentions
- }, function( err, data ) {
- if ( err ) {
- callback( err );
- } else {
- var msg = new Message( data, self.getChannel( data.channel_id ) );
- if ( options.selfDestruct ) {
- setTimeout( function() {
- self.deleteMessage( msg );
- }, options.selfDestruct );
- }
- callback( null, msg );
- }
- } );
- }
-
- function setChannId( id ) {
- channel_id = id;
- }
-
- function resolveChannel( destination, self ) {
- var channel_id = false;
- if ( destination instanceof Server ) {
- channel_id = destination.getDefaultChannel().id;
- } else if ( destination instanceof Channel ) {
- channel_id = destination.id;
- } else if ( destination instanceof PMChannel ) {
- channel_id = destination.id;
- } else if ( destination instanceof Message ) {
- channel_id = destination.channel.id;
- } else if ( destination instanceof User ) {
- var destId = self.PMList.deepFilter( [ "user", "id" ], destination.id, true );
-
- if ( destId ) {
- channel_id = destId.id;
- } else {
- //start a PM and then get that use that
- self.startPM( destination, function( err, channel ) {
- if ( err ) {
- callback( err );
- } else {
- self.PMList.add( new PMChannel( channel.user, channel.id ) );
- setChannId( channel.id );
- send();
- }
- } );
- return false;
- }
- } else {
- channel_id = destination;
- }
- return channel_id;
- }
-
- function resolveMessage( toSend ) {
- var message;
- if ( typeof toSend === "string" || toSend instanceof String )
- message = toSend;
- else if ( toSend instanceof Array )
- message = toSend.join( "\n" );
- else if ( toSend instanceof Message )
- message = toSend.content;
- else
- message = toSend;
- return message.substring( 0, 2000 );
- }
-
- function resolveMentions( message, mentionsOpt ) {
- var mentions = [];
- if ( mentionsOpt === false ) {} else if ( mentionsOpt || mentionsOpt === "auto" || mentionsOpt == null || mentionsOpt == undefined ) {
- for ( mention of( message.match( /<@[^>]*>/g ) || [] ) ) {
- mentions.push( mention.substring( 2, mention.length - 1 ) );
- }
- } else if ( mentionsOpt instanceof Array ) {
- for ( mention of mentionsOpt ) {
- if ( mention instanceof User ) {
- mentions.push( mention.id );
- } else {
- mentions.push( mention );
- }
- }
- }
- return mentions;
- }
-}
-
-/**
- * Deletes the specified message if the bot has authority
- * @param {Message} message The message to delete
- * @param {Function} callback Called after the message deletion request is sent.
- * @param {Object} callback.error If there was an error, this would be an XHR Error object. Otherwise, it will be null.
- * @param {Message} callback.message A message object representing the deleted object.
- * @method deleteMessage
- */
-exports.Client.prototype.deleteMessage = function( message, callback ) {
- callback = callback || function() {};
-
- var self = this;
-
- Internal.XHR.deleteMessage( self.token, message.channel.id, message.id, callback );
-}
-
-exports.Client.prototype.updateMessage = function( oldMessage, newContent, callback, options ) {
-
- var self = this;
- var channel = oldMessage.channel;
- options = options || {};
-
- Internal.XHR.updateMessage( self.token, channel.id, oldMessage.id, {
- content: newContent,
- mentions: []
- }, function( err, data ) {
- if ( err ) {
- callback( err );
- return;
- }
- var msg = new Message( data, self.getChannel( data.channel_id ) );
- if ( options.selfDestruct ) {
- setTimeout( function() {
- self.deleteMessage( msg );
- }, options.selfDestruct );
- }
- callback( null, msg );
- } );
-
-}
-
-exports.Client.prototype.setUsername = function( username, callback ) {
-
- var self = this;
-
- Internal.XHR.setUsername( self.token, self.user.avatar, self.email, null, self.password, username, function( err ) {
-
- callback( err );
-
- } );
-
-}
-
-exports.Client.prototype.getChannelLogs = function( channel, amount, callback ) {
- var self = this;
-
- Internal.XHR.getChannelLogs( self.token, channel.id, ( amount || 50 ), function( err, data ) {
-
- if ( err ) {
- callback( err );
- return;
- }
-
- var logs = new List( "id" );
- for ( message of data ) {
- logs.add( new Message( message, channel ) );
- }
- callback( null, logs );
-
- } );
-}
-
-exports.Client.prototype.createChannel = function( server, name, type, callback ) {
-
- var self = this;
-
- Internal.XHR.createChannel( self.token, server.id, name, type, function( err, data ) {
-
- if ( err ) {
- callback( err );
- } else {
- var chann = new Channel( data, server );
- server.channels.add( chann );
- callback( null, chann );
- }
-
- } );
-}
-
-exports.Client.prototype.deleteChannel = function( channel, callback ) {
- var self = this;
-
- Internal.XHR.deleteChannel( self.token, channel.id, function( err ) {
-
- channel.server.channels.removeElement( channel );
- self.triggerEvent( "channelDelete", [ channel ] );
- callback( null );
-
- } );
-}
-
-exports.Client.prototype.deleteServer = function( server, callback ) {
-
- var self = this;
-
- Internal.XHR.deleteServer( self.token, server.id, function( err ) {
-
- self.serverList.removeElement( server );
- self.triggerEvent( "serverDelete", [ server ] );
- callback( null );
-
- } );
-
-}
-
-exports.Client.prototype.joinServer = function( invite, callback ) {
-
- var self = this;
-
- var code = ( invite instanceof Invite ? invite.code : invite );
-
- Internal.XHR.acceptInvite( self.token, code, function( err, inviteData ) {
-
- if ( err ) {
- callback( err );
- } else {
- serverCreateRequests[ inviteData.guild.id ] = callback;
- }
-
- } );
-
-}
-
-exports.Client.prototype.getServers = function() {
- return this.serverList;
-}
-
-exports.Client.prototype.getChannels = function() {
- return this.serverList.concatSublists( "channels", "id" );
-}
-
-exports.Client.prototype.getUsers = function() {
- return this.getServers().concatSublists( "members", "id" );
-}
-
-exports.Client.prototype.getServer = function( id ) {
- return this.getServers().filter( "id", id, true );
-}
-
-exports.Client.prototype.getChannel = function( id ) {
- var normalChan = this.getChannels().filter( "id", id, true );
- return normalChan || this.PMList.filter( "id", id, true );
-}
-
-exports.Client.prototype.getChannelByName = function( name ) {
- return this.getChannels().filter( "name", name, true );
-}
-
-exports.Client.prototype.getUser = function( id ) {
- return this.getUsers().filter( "id", id, true );
-}
-
-exports.isUserID = function( id ) {
- return ( ( id + "" ).length === 17 && !isNaN( id ) );
-}
-
-exports.Client.prototype.updateUserReferences = function( id, oldUser, user ) {
-
- if ( oldUser.equalsStrict( user ) ) {
- return false;
- }
-
- for ( server of this.serverList.contents ) {
-
- server.members.updateElement( oldUser, user );
-
- }
-
- this.debug( "Updated references to " + oldUser.username + " to " + this.getUser( id ).username );
- return true;
-
-}
-
-exports.Client.prototype.addPM = function( pm ) {
- this.PMList.add( pm );
-}
diff --git a/jsconfig.json b/jsconfig.json
new file mode 100644
index 000000000..0438b79f6
--- /dev/null
+++ b/jsconfig.json
@@ -0,0 +1,6 @@
+{
+ "compilerOptions": {
+ "target": "ES6",
+ "module": "commonjs"
+ }
+}
\ No newline at end of file
diff --git a/lib/Client.js b/lib/Client.js
new file mode 100644
index 000000000..4d097628b
--- /dev/null
+++ b/lib/Client.js
@@ -0,0 +1,1928 @@
+//discord.js modules
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Endpoints = require("./Endpoints.js");
+var User = require("./user.js");
+var Server = require("./server.js");
+var Channel = require("./channel.js");
+var Message = require("./message.js");
+var Invite = require("./invite.js");
+var PMChannel = require("./PMChannel.js");
+
+var gameMap = require("../ref/gameMap.json");
+
+//node modules
+var request = require("superagent");
+var WebSocket = require("ws");
+var fs = require("fs");
+
+var defaultOptions = {
+ queue: false
+};
+
+var Client = (function () {
+ function Client() {
+ var options = arguments.length <= 0 || arguments[0] === undefined ? defaultOptions : arguments[0];
+ var token = arguments.length <= 1 || arguments[1] === undefined ? undefined : arguments[1];
+
+ _classCallCheck(this, Client);
+
+ /*
+ When created, if a token is specified the Client will
+ try connecting with it. If the token is incorrect, no
+ further efforts will be made to connect.
+ */
+ this.options = options;
+ this.options.queue = this.options.queue;
+ this.token = token;
+ this.state = 0;
+ this.websocket = null;
+ this.events = {};
+ this.user = null;
+ this.alreadySentData = false;
+ this.serverCreateListener = {};
+ this.typingIntervals = {};
+ this.email = "abc";
+ this.password = "abc";
+
+ /*
+ State values:
+ 0 - idle
+ 1 - logging in
+ 2 - logged in
+ 3 - ready
+ 4 - disconnected
+ */
+
+ this.userCache = [];
+ this.channelCache = [];
+ this.serverCache = [];
+ this.pmChannelCache = [];
+ this.readyTime = null;
+ this.checkingQueue = {};
+ this.queue = {};
+
+ this.__idleTime = null;
+ this.__gameId = null;
+ }
+
+ _createClass(Client, [{
+ key: "sendPacket",
+ value: function sendPacket(JSONObject) {
+ if (this.websocket.readyState === 1) {
+ this.websocket.send(JSON.stringify(JSONObject));
+ }
+ }
+
+ //def debug
+ }, {
+ key: "debug",
+ value: function debug(message) {
+ this.trigger("debug", message);
+ }
+ }, {
+ key: "on",
+ value: function on(event, fn) {
+ this.events[event] = fn;
+ }
+ }, {
+ key: "off",
+ value: function off(event) {
+ this.events[event] = null;
+ }
+ }, {
+ key: "keepAlive",
+ value: function keepAlive() {
+ this.debug("keep alive triggered");
+ this.sendPacket({
+ op: 1,
+ d: Date.now()
+ });
+ }
+
+ //def trigger
+ }, {
+ key: "trigger",
+ value: function trigger(event) {
+ var args = [];
+ for (var arg in arguments) {
+ args.push(arguments[arg]);
+ }
+ var evt = this.events[event];
+ if (evt) {
+ evt.apply(this, args.slice(1));
+ }
+ }
+
+ //def login
+ }, {
+ key: "login",
+ value: function login() {
+ var email = arguments.length <= 0 || arguments[0] === undefined ? "foo@bar.com" : arguments[0];
+ var password = arguments.length <= 1 || arguments[1] === undefined ? "pass1234" : arguments[1];
+ var callback = arguments.length <= 2 || arguments[2] === undefined ? function (err, token) {} : arguments[2];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ if (self.state === 0 || self.state === 4) {
+
+ self.state = 1; //set the state to logging in
+
+ self.email = email;
+ self.password = password;
+
+ request.post(Endpoints.LOGIN).send({
+ email: email,
+ password: password
+ }).end(function (err, res) {
+
+ if (err) {
+ self.state = 4; //set state to disconnected
+ self.trigger("disconnected");
+ if (self.websocket) {
+ self.websocket.close();
+ }
+ callback(err);
+ reject(err);
+ } else {
+ self.state = 2; //set state to logged in (not yet ready)
+ self.token = res.body.token; //set our token
+
+ self.getGateway().then(function (url) {
+ self.createws(url);
+ callback(null, self.token);
+ resolve(self.token);
+ })["catch"](function (err) {
+ callback(err);
+ reject(err);
+ });
+ }
+ });
+ } else {
+ reject(new Error("Client already logging in or ready"));
+ }
+ });
+ }
+ }, {
+ key: "logout",
+ value: function logout() {
+ var callback = arguments.length <= 0 || arguments[0] === undefined ? function (err) {} : arguments[0];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ request.post(Endpoints.LOGOUT).set("authorization", self.token).end(function (err, res) {
+
+ if (err) {
+ callback(err);
+ reject(err);
+ } else {
+ self.websocket.close();
+ self.state = 4;
+ callback();
+ resolve();
+ }
+ });
+ });
+ }
+ }, {
+ key: "createServer",
+ value: function createServer(name, region) {
+ var callback = arguments.length <= 2 || arguments[2] === undefined ? function (err, server) {} : arguments[2];
+
+ var self = this;
+ return new Promise(function (resolve, reject) {
+
+ request.post(Endpoints.SERVERS).set("authorization", self.token).send({
+ name: name,
+ region: region
+ }).end(function (err, res) {
+ if (err) {
+ callback(err);
+ reject(err);
+ } else {
+ // potentially redundant in future
+ // creating here does NOT give us the channels of the server
+ // so we must wait for the guild_create event.
+ self.serverCreateListener[res.body.id] = [resolve, callback];
+ /*var srv = self.addServer(res.body);
+ callback(null, srv);
+ resolve(srv);*/
+ }
+ });
+ });
+ }
+ }, {
+ key: "createChannel",
+ value: function createChannel(server, channelName, channelType) {
+ var callback = arguments.length <= 3 || arguments[3] === undefined ? function (err, chann) {} : arguments[3];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ request.post(Endpoints.SERVERS + "/" + self.resolveServerID(server) + "/channels").set("authorization", self.token).send({
+ name: channelName,
+ type: channelType
+ }).end(function (err, res) {
+
+ if (err) {
+ callback(err);
+ reject(err);
+ } else {
+ var server = self.getServer("id", res.body.guild_id);
+ var chann = self.addChannel(res.body, res.body.guild_id);
+ server.addChannel(chann);
+ callback(null, chann);
+ resolve(chann);
+ }
+ });
+ });
+ }
+ }, {
+ key: "leaveServer",
+ value: function leaveServer(server) {
+ var callback = arguments.length <= 1 || arguments[1] === undefined ? function (err, server) {} : arguments[1];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ request.del(Endpoints.SERVERS + "/" + self.resolveServerID(server)).set("authorization", self.token).end(function (err, res) {
+
+ if (err) {
+ callback(err);
+ reject(err);
+ } else {
+ self.serverCache.splice(self.serverCache.indexOf(server), 1);
+ callback(null);
+ resolve();
+ }
+ });
+ });
+ }
+ }, {
+ key: "createInvite",
+ value: function createInvite(serverOrChannel, options) {
+ var callback = arguments.length <= 2 || arguments[2] === undefined ? function (err, invite) {} : arguments[2];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ var destination;
+
+ if (serverOrChannel instanceof Server) {
+ destination = serverOrChannel.id;
+ } else if (serverOrChannel instanceof Channel) {
+ destination = serverOrChannel.id;
+ } else {
+ destination = serverOrChannel;
+ }
+
+ options = options || {};
+ options.max_age = options.maxAge || 0;
+ options.max_uses = options.maxUses || 0;
+ options.temporary = options.temporary || false;
+ options.xkcdpass = options.xkcd || false;
+
+ request.post(Endpoints.CHANNELS + "/" + destination + "/invites").set("authorization", self.token).send(options).end(function (err, res) {
+ if (err) {
+ callback(err);
+ reject(err);
+ } else {
+ var inv = new Invite(res.body, self);
+ callback(null, inv);
+ resolve(inv);
+ }
+ });
+ });
+ }
+ }, {
+ key: "startPM",
+ value: function startPM(user) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ var userId = user;
+ if (user instanceof User) {
+ userId = user.id;
+ }
+ request.post(Endpoints.USERS + "/" + self.user.id + "/channels").set("authorization", self.token).send({
+ recipient_id: userId
+ }).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(self.addPMChannel(res.body));
+ }
+ });
+ });
+ }
+ }, {
+ key: "reply",
+ value: function reply(destination, message, tts) {
+ var callback = arguments.length <= 3 || arguments[3] === undefined ? function (err, msg) {} : arguments[3];
+
+ var self = this;
+
+ return new Promise(function (response, reject) {
+
+ if (typeof tts === "function") {
+ // tts is a function, which means the developer wants this to be the callback
+ callback = tts;
+ tts = false;
+ }
+
+ var user = destination.sender;
+ self.sendMessage(destination, message, tts, callback, user + ", ").then(response)["catch"](reject);
+ });
+ }
+ }, {
+ key: "deleteMessage",
+ value: function deleteMessage(message, timeout) {
+ var callback = arguments.length <= 2 || arguments[2] === undefined ? function (err, msg) {} : arguments[2];
+
+ var self = this;
+
+ var prom = new Promise(function (resolve, reject) {
+ if (timeout) {
+ setTimeout(remove, timeout);
+ } else {
+ remove();
+ }
+
+ function remove() {
+ if (self.options.queue) {
+ if (!self.queue[message.channel.id]) {
+ self.queue[message.channel.id] = [];
+ }
+ self.queue[message.channel.id].push({
+ action: "deleteMessage",
+ message: message,
+ then: good,
+ error: bad
+ });
+
+ self.checkQueue(message.channel.id);
+ } else {
+ self._deleteMessage(message).then(good)["catch"](bad);
+ }
+ }
+
+ function good() {
+ prom.success = true;
+ callback(null);
+ resolve();
+ }
+
+ function bad(err) {
+ prom.error = err;
+ callback(err);
+ reject(err);
+ }
+ });
+
+ return prom;
+ }
+ }, {
+ key: "updateMessage",
+ value: function updateMessage(message, content) {
+ var callback = arguments.length <= 2 || arguments[2] === undefined ? function (err, msg) {} : arguments[2];
+
+ var self = this;
+
+ var prom = new Promise(function (resolve, reject) {
+
+ content = content instanceof Array ? content.join("\n") : content;
+
+ if (self.options.queue) {
+ if (!self.queue[message.channel.id]) {
+ self.queue[message.channel.id] = [];
+ }
+ self.queue[message.channel.id].push({
+ action: "updateMessage",
+ message: message,
+ content: content,
+ then: good,
+ error: bad
+ });
+
+ self.checkQueue(message.channel.id);
+ } else {
+ self._updateMessage(message, content).then(good)["catch"](bad);
+ }
+
+ function good(msg) {
+ prom.message = msg;
+ callback(null, msg);
+ resolve(msg);
+ }
+
+ function bad(error) {
+ prom.error = error;
+ callback(error);
+ reject(error);
+ }
+ });
+
+ return prom;
+ }
+ }, {
+ key: "setUsername",
+ value: function setUsername(newName) {
+ var callback = arguments.length <= 1 || arguments[1] === undefined ? function (err) {} : arguments[1];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request.patch(Endpoints.API + "/users/@me").set("authorization", self.token).send({
+ avatar: self.user.avatar,
+ email: self.email,
+ new_password: null,
+ password: self.password,
+ username: newName
+ }).end(function (err) {
+ callback(err);
+ if (err) reject(err);else resolve();
+ });
+ });
+ }
+ }, {
+ key: "getChannelLogs",
+ value: function getChannelLogs(channel) {
+ var amount = arguments.length <= 1 || arguments[1] === undefined ? 500 : arguments[1];
+ var callback = arguments.length <= 2 || arguments[2] === undefined ? function (err, logs) {} : arguments[2];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ var channelID = channel;
+ if (channel instanceof Channel) {
+ channelID = channel.id;
+ }
+
+ request.get(Endpoints.CHANNELS + "/" + channelID + "/messages?limit=" + amount).set("authorization", self.token).end(function (err, res) {
+
+ if (err) {
+ callback(err);
+ reject(err);
+ } else {
+ var logs = [];
+
+ var channel = self.getChannel("id", channelID);
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = res.body[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var message = _step.value;
+
+ var mentions = [];
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = message.mentions[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var mention = _step2.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2["return"]) {
+ _iterator2["return"]();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+
+ var author = self.addUser(message.author);
+
+ logs.push(new Message(message, channel, mentions, author));
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ callback(null, logs);
+ resolve(logs);
+ }
+ });
+ });
+ }
+ }, {
+ key: "deleteChannel",
+ value: function deleteChannel(channel) {
+ var callback = arguments.length <= 1 || arguments[1] === undefined ? function (err) {} : arguments[1];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ var channelID = channel;
+ if (channel instanceof Channel) {
+ channelID = channel.id;
+ }
+
+ request.del(Endpoints.CHANNELS + "/" + channelID).set("authorization", self.token).end(function (err) {
+ if (err) {
+ callback(err);
+ reject(err);
+ } else {
+ callback(null);
+ resolve();
+ }
+ });
+ });
+ }
+ }, {
+ key: "joinServer",
+ value: function joinServer(invite) {
+ var callback = arguments.length <= 1 || arguments[1] === undefined ? function (err, server) {} : arguments[1];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ var id = invite instanceof Invite ? invite.code : invite;
+
+ request.post(Endpoints.API + "/invite/" + id).set("authorization", self.token).end(function (err, res) {
+ if (err) {
+ callback(err);
+ reject(err);
+ } else {
+ if (self.getServer("id", res.body.guild.id)) {
+ resolve(self.getServer("id", res.body.guild.id));
+ } else {
+ self.serverCreateListener[res.body.guild.id] = [resolve, callback];
+ }
+ }
+ });
+ });
+ }
+ }, {
+ key: "sendFile",
+ value: function sendFile(destination, file) {
+ var fileName = arguments.length <= 2 || arguments[2] === undefined ? "image.png" : arguments[2];
+ var callback = arguments.length <= 3 || arguments[3] === undefined ? function (err, msg) {} : arguments[3];
+
+ var self = this;
+
+ var prom = new Promise(function (resolve, reject) {
+
+ var fstream;
+
+ if (typeof file === "string" || file instanceof String) {
+ fstream = fs.createReadStream(file);
+ fileName = file;
+ } else {
+ fstream = file;
+ }
+
+ self.resolveDestination(destination).then(send)["catch"](bad);
+
+ function send(destination) {
+ if (self.options.queue) {
+ //queue send file too
+ if (!self.queue[destination]) {
+ self.queue[destination] = [];
+ }
+
+ self.queue[destination].push({
+ action: "sendFile",
+ attachment: fstream,
+ attachmentName: fileName,
+ then: good,
+ error: bad
+ });
+
+ self.checkQueue(destination);
+ } else {
+ //not queue
+ self._sendFile(destination, fstream, fileName).then(good)["catch"](bad);
+ }
+ }
+
+ function good(msg) {
+ prom.message = msg;
+ callback(null, msg);
+ resolve(msg);
+ }
+
+ function bad(err) {
+ prom.error = err;
+ callback(err);
+ reject(err);
+ }
+ });
+
+ return prom;
+ }
+ }, {
+ key: "sendMessage",
+ value: function sendMessage(destination, message, tts) {
+ var callback = arguments.length <= 3 || arguments[3] === undefined ? function (err, msg) {} : arguments[3];
+ var premessage = arguments.length <= 4 || arguments[4] === undefined ? "" : arguments[4];
+
+ var self = this;
+
+ var prom = new Promise(function (resolve, reject) {
+
+ if (typeof tts === "function") {
+ // tts is a function, which means the developer wants this to be the callback
+ callback = tts;
+ tts = false;
+ }
+
+ message = premessage + resolveMessage(message);
+ var mentions = resolveMentions();
+ self.resolveDestination(destination).then(send)["catch"](error);
+
+ function error(err) {
+ callback(err);
+ reject(err);
+ }
+
+ function send(destination) {
+ if (self.options.queue) {
+ //we're QUEUEING messages, so sending them sequentially based on servers.
+ if (!self.queue[destination]) {
+ self.queue[destination] = [];
+ }
+
+ self.queue[destination].push({
+ action: "sendMessage",
+ content: message,
+ mentions: mentions,
+ tts: !!tts, //incase it's not a boolean
+ then: mgood,
+ error: mbad
+ });
+
+ self.checkQueue(destination);
+ } else {
+ self._sendMessage(destination, message, tts, mentions).then(mgood)["catch"](mbad);
+ }
+ }
+
+ function mgood(msg) {
+ prom.message = msg;
+ callback(null, msg);
+ resolve(msg);
+ }
+
+ function mbad(error) {
+ prom.error = error;
+ callback(error);
+ reject(error);
+ }
+
+ function resolveMessage() {
+ var msg = message;
+ if (message instanceof Array) {
+ msg = message.join("\n");
+ }
+ return msg;
+ }
+
+ function resolveMentions() {
+ var _mentions = [];
+ var _iteratorNormalCompletion3 = true;
+ var _didIteratorError3 = false;
+ var _iteratorError3 = undefined;
+
+ try {
+ for (var _iterator3 = (message.match(/<@[^>]*>/g) || [])[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var mention = _step3.value;
+
+ _mentions.push(mention.substring(2, mention.length - 1));
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3["return"]) {
+ _iterator3["return"]();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ return _mentions;
+ }
+ });
+
+ return prom;
+ }
+
+ //def createws
+ }, {
+ key: "createws",
+ value: function createws(url) {
+ if (this.websocket) return false;
+
+ var self = this;
+
+ //good to go
+ this.websocket = new WebSocket(url);
+
+ //open
+ this.websocket.onopen = function () {
+ self.trySendConnData(); //try connecting
+ };
+
+ //close
+ this.websocket.onclose = function () {
+ self.trigger("disconnected");
+ };
+
+ //message
+ this.websocket.onmessage = function (e) {
+
+ var dat = false,
+ data = {};
+
+ try {
+ dat = JSON.parse(e.data);
+ data = dat.d;
+ } catch (err) {
+ self.trigger("error", err, e);
+ return;
+ }
+
+ self.trigger("raw", dat);
+
+ //valid message
+ switch (dat.t) {
+
+ case "READY":
+ self.debug("received ready packet");
+
+ self.user = self.addUser(data.user);
+
+ var _iteratorNormalCompletion4 = true;
+ var _didIteratorError4 = false;
+ var _iteratorError4 = undefined;
+
+ try {
+ for (var _iterator4 = data.guilds[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
+ var _server = _step4.value;
+
+ var server = self.addServer(_server);
+ }
+ } catch (err) {
+ _didIteratorError4 = true;
+ _iteratorError4 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion4 && _iterator4["return"]) {
+ _iterator4["return"]();
+ }
+ } finally {
+ if (_didIteratorError4) {
+ throw _iteratorError4;
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion5 = true;
+ var _didIteratorError5 = false;
+ var _iteratorError5 = undefined;
+
+ try {
+ for (var _iterator5 = data.private_channels[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
+ var _pmc = _step5.value;
+
+ var pmc = self.addPMChannel(_pmc);
+ }
+ } catch (err) {
+ _didIteratorError5 = true;
+ _iteratorError5 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion5 && _iterator5["return"]) {
+ _iterator5["return"]();
+ }
+ } finally {
+ if (_didIteratorError5) {
+ throw _iteratorError5;
+ }
+ }
+ }
+
+ self.trigger("ready");
+ self.readyTime = Date.now();
+ self.debug("cached " + self.serverCache.length + " servers, " + self.channelCache.length + " channels, " + self.pmChannelCache.length + " PMs and " + self.userCache.length + " users.");
+ self.state = 3;
+ setInterval(function () {
+ self.keepAlive.apply(self);
+ }, data.heartbeat_interval);
+
+ break;
+ case "MESSAGE_CREATE":
+ self.debug("received message");
+
+ var mentions = [];
+ data.mentions = data.mentions || []; //for some reason this was not defined at some point?
+ var _iteratorNormalCompletion6 = true;
+ var _didIteratorError6 = false;
+ var _iteratorError6 = undefined;
+
+ try {
+ for (var _iterator6 = data.mentions[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
+ var mention = _step6.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError6 = true;
+ _iteratorError6 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion6 && _iterator6["return"]) {
+ _iterator6["return"]();
+ }
+ } finally {
+ if (_didIteratorError6) {
+ throw _iteratorError6;
+ }
+ }
+ }
+
+ var channel = self.getChannel("id", data.channel_id);
+ if (channel) {
+ var msg = channel.addMessage(new Message(data, channel, mentions, self.addUser(data.author)));
+ self.trigger("message", msg);
+ }
+
+ break;
+ case "MESSAGE_DELETE":
+ self.debug("message deleted");
+
+ var channel = self.getChannel("id", data.channel_id);
+ var message = channel.getMessage("id", data.id);
+ if (message) {
+ self.trigger("messageDelete", channel, message);
+ channel.messages.splice(channel.messages.indexOf(message), 1);
+ } else {
+ //don't have the cache of that message ;(
+ self.trigger("messageDelete", channel);
+ }
+ break;
+ case "MESSAGE_UPDATE":
+ self.debug("message updated");
+
+ var channel = self.getChannel("id", data.channel_id);
+ var formerMessage = channel.getMessage("id", data.id);
+
+ if (formerMessage) {
+
+ //new message might be partial, so we need to fill it with whatever the old message was.
+ var info = {};
+
+ for (var key in formerMessage) {
+ info[key] = formerMessage[key];
+ }
+
+ for (var key in data) {
+ info[key] = data[key];
+ }
+
+ var mentions = [];
+ var _iteratorNormalCompletion7 = true;
+ var _didIteratorError7 = false;
+ var _iteratorError7 = undefined;
+
+ try {
+ for (var _iterator7 = info.mentions[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
+ var mention = _step7.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError7 = true;
+ _iteratorError7 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion7 && _iterator7["return"]) {
+ _iterator7["return"]();
+ }
+ } finally {
+ if (_didIteratorError7) {
+ throw _iteratorError7;
+ }
+ }
+ }
+
+ var newMessage = new Message(info, channel, mentions, formerMessage.author);
+
+ self.trigger("messageUpdate", newMessage, formerMessage);
+
+ channel.messages[channel.messages.indexOf(formerMessage)] = newMessage;
+ }
+
+ // message isn't in cache, and if it's a partial it could cause
+ // all hell to break loose... best to just act as if nothing happened
+
+ break;
+
+ case "GUILD_DELETE":
+
+ var server = self.getServer("id", data.id);
+
+ if (server) {
+ self.serverCache.splice(self.serverCache.indexOf(server), 1);
+ self.trigger("serverDelete", server);
+ }
+
+ break;
+
+ case "CHANNEL_DELETE":
+
+ var channel = self.getChannel("id", data.id);
+
+ if (channel) {
+
+ var server = channel.server;
+
+ if (server) {
+
+ server.channels.splice(server.channels.indexOf(channel), 1);
+ }
+
+ self.trigger("channelDelete", channel);
+
+ self.serverCache.splice(self.serverCache.indexOf(channel), 1);
+ }
+
+ break;
+
+ case "GUILD_CREATE":
+
+ var server = self.getServer("id", data.id);
+
+ if (!server) {
+ //if server doesn't already exist because duh
+ server = self.addServer(data);
+ } /*else if(server.channels.length === 0){
+
+ var srv = new Server(data, self);
+ for(channel of data.channels){
+ srv.channels.push(new Channel(channel, data.id));
+ }
+ self.serverCache[self.serverCache.indexOf(server)] = srv;
+
+ }*/
+
+ if (self.serverCreateListener[data.id]) {
+ var cbs = self.serverCreateListener[data.id];
+ cbs[0](server); //promise then callback
+ cbs[1](null, server); //legacy callback
+ self.serverCreateListener[data.id] = null;
+ }
+
+ self.trigger("serverCreate", server);
+
+ break;
+
+ case "CHANNEL_CREATE":
+
+ var channel = self.getChannel("id", data.id);
+
+ if (!channel) {
+
+ var chann = self.addChannel(data, data.guild_id);
+ var srv = self.getServer("id", data.guild_id);
+ if (srv) {
+ srv.addChannel(chann);
+ }
+ self.trigger("channelCreate", chann);
+ }
+
+ break;
+
+ case "GUILD_MEMBER_ADD":
+
+ var server = self.getServer("id", data.guild_id);
+
+ if (server) {
+
+ var user = self.addUser(data.user); //if for whatever reason it doesn't exist..
+
+ if (! ~server.members.indexOf(user)) {
+ server.members.push(user);
+ }
+
+ self.trigger("serverNewMember", user, server);
+ }
+
+ break;
+
+ case "GUILD_MEMBER_REMOVE":
+
+ var server = self.getServer("id", data.guild_id);
+
+ if (server) {
+
+ var user = self.addUser(data.user); //if for whatever reason it doesn't exist..
+
+ if (~server.members.indexOf(user)) {
+ server.members.splice(server.members.indexOf(user), 1);
+ }
+
+ self.trigger("serverRemoveMember", user, server);
+ }
+
+ break;
+
+ case "USER_UPDATE":
+
+ if (self.user && data.id === self.user.id) {
+
+ var newUser = new User(data); //not actually adding to the cache
+
+ self.trigger("userUpdate", newUser, self.user);
+
+ if (~self.userCache.indexOf(self.user)) {
+ self.userCache[self.userCache.indexOf(self.user)] = newUser;
+ }
+
+ self.user = newUser;
+ }
+
+ break;
+
+ case "PRESENCE_UPDATE":
+
+ var userInCache = self.getUser("id", data.user.id);
+
+ if (userInCache) {
+ //user exists
+ var presenceUser = new User(data.user);
+ if (presenceUser.equalsStrict(userInCache)) {
+ //they're exactly the same, an actual presence update
+ userInCache.status = data.status;
+ self.trigger("presence", {
+ user: userInCache,
+ status: data.status,
+ server: self.getServer("id", data.guild_id),
+ gameId: data.game_id
+ });
+ } else {
+ //one of their details changed.
+ self.trigger("userUpdate", userInCache, presenceUser);
+ self.userCache[self.userCache.indexOf(userInCache)] = presenceUser;
+ }
+ }
+
+ break;
+
+ case "CHANNEL_UPDATE":
+
+ var channelInCache = self.getChannel("id", data.id),
+ serverInCache = self.getServer("id", data.guild_id);
+
+ if (channelInCache && serverInCache) {
+
+ var newChann = new Channel(data, serverInCache);
+ newChann.messages = channelInCache.messages;
+
+ self.trigger("channelUpdate", channelInCache, newChann);
+
+ self.channelCache[self.channelCache.indexOf(channelInCache)] = newChann;
+ }
+
+ break;
+
+ default:
+ self.debug("received unknown packet");
+ self.trigger("unknown", dat);
+ break;
+
+ }
+ };
+ }
+
+ //def addUser
+ }, {
+ key: "addUser",
+ value: function addUser(data) {
+ if (!this.getUser("id", data.id)) {
+ this.userCache.push(new User(data));
+ }
+ return this.getUser("id", data.id);
+ }
+
+ //def addChannel
+ }, {
+ key: "addChannel",
+ value: function addChannel(data, serverId) {
+ if (!this.getChannel("id", data.id)) {
+ this.channelCache.push(new Channel(data, this.getServer("id", serverId)));
+ }
+ return this.getChannel("id", data.id);
+ }
+ }, {
+ key: "addPMChannel",
+ value: function addPMChannel(data) {
+ if (!this.getPMChannel("id", data.id)) {
+ this.pmChannelCache.push(new PMChannel(data, this));
+ }
+ return this.getPMChannel("id", data.id);
+ }
+ }, {
+ key: "setTopic",
+ value: function setTopic(channel, topic) {
+ var callback = arguments.length <= 2 || arguments[2] === undefined ? function (err) {} : arguments[2];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ self.resolveDestination(channel).then(next)["catch"](error);
+
+ function error(e) {
+ callback(e);
+ reject(e);
+ }
+
+ function next(destination) {
+
+ var asChan = self.getChannel("id", destination);
+
+ request.patch(Endpoints.CHANNELS + "/" + destination).set("authorization", self.token).send({
+ name: asChan.name,
+ position: 0,
+ topic: topic
+ }).end(function (err, res) {
+ if (err) {
+ error(err);
+ } else {
+ asChan.topic = res.body.topic;
+ resolve();
+ callback();
+ }
+ });
+ }
+ });
+ }
+
+ //def addServer
+ }, {
+ key: "addServer",
+ value: function addServer(data) {
+
+ var self = this;
+ var server = this.getServer("id", data.id);
+
+ if (data.unavailable) {
+ self.trigger("unavailable", data);
+ self.debug("Server ID " + data.id + " has been marked unavailable by Discord. It was not cached.");
+ return;
+ }
+
+ if (!server) {
+ server = new Server(data, this);
+ this.serverCache.push(server);
+ if (data.channels) {
+ var _iteratorNormalCompletion8 = true;
+ var _didIteratorError8 = false;
+ var _iteratorError8 = undefined;
+
+ try {
+ for (var _iterator8 = data.channels[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
+ var channel = _step8.value;
+
+ server.channels.push(this.addChannel(channel, server.id));
+ }
+ } catch (err) {
+ _didIteratorError8 = true;
+ _iteratorError8 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion8 && _iterator8["return"]) {
+ _iterator8["return"]();
+ }
+ } finally {
+ if (_didIteratorError8) {
+ throw _iteratorError8;
+ }
+ }
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion9 = true;
+ var _didIteratorError9 = false;
+ var _iteratorError9 = undefined;
+
+ try {
+ for (var _iterator9 = data.presences[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
+ var presence = _step9.value;
+
+ self.getUser("id", presence.user.id).status = presence.status;
+ }
+ } catch (err) {
+ _didIteratorError9 = true;
+ _iteratorError9 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion9 && _iterator9["return"]) {
+ _iterator9["return"]();
+ }
+ } finally {
+ if (_didIteratorError9) {
+ throw _iteratorError9;
+ }
+ }
+ }
+
+ return server;
+ }
+
+ //def getUser
+ }, {
+ key: "getUser",
+ value: function getUser(key, value) {
+ var _iteratorNormalCompletion10 = true;
+ var _didIteratorError10 = false;
+ var _iteratorError10 = undefined;
+
+ try {
+ for (var _iterator10 = this.userCache[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
+ var user = _step10.value;
+
+ if (user[key] === value) {
+ return user;
+ }
+ }
+ } catch (err) {
+ _didIteratorError10 = true;
+ _iteratorError10 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion10 && _iterator10["return"]) {
+ _iterator10["return"]();
+ }
+ } finally {
+ if (_didIteratorError10) {
+ throw _iteratorError10;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def getChannel
+ }, {
+ key: "getChannel",
+ value: function getChannel(key, value) {
+ var _iteratorNormalCompletion11 = true;
+ var _didIteratorError11 = false;
+ var _iteratorError11 = undefined;
+
+ try {
+ for (var _iterator11 = this.channelCache[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
+ var channel = _step11.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError11 = true;
+ _iteratorError11 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion11 && _iterator11["return"]) {
+ _iterator11["return"]();
+ }
+ } finally {
+ if (_didIteratorError11) {
+ throw _iteratorError11;
+ }
+ }
+ }
+
+ return this.getPMChannel(key, value); //might be a PM
+ }
+ }, {
+ key: "getPMChannel",
+ value: function getPMChannel(key, value) {
+ var _iteratorNormalCompletion12 = true;
+ var _didIteratorError12 = false;
+ var _iteratorError12 = undefined;
+
+ try {
+ for (var _iterator12 = this.pmChannelCache[Symbol.iterator](), _step12; !(_iteratorNormalCompletion12 = (_step12 = _iterator12.next()).done); _iteratorNormalCompletion12 = true) {
+ var channel = _step12.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError12 = true;
+ _iteratorError12 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion12 && _iterator12["return"]) {
+ _iterator12["return"]();
+ }
+ } finally {
+ if (_didIteratorError12) {
+ throw _iteratorError12;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def getServer
+ }, {
+ key: "getServer",
+ value: function getServer(key, value) {
+ var _iteratorNormalCompletion13 = true;
+ var _didIteratorError13 = false;
+ var _iteratorError13 = undefined;
+
+ try {
+ for (var _iterator13 = this.serverCache[Symbol.iterator](), _step13; !(_iteratorNormalCompletion13 = (_step13 = _iterator13.next()).done); _iteratorNormalCompletion13 = true) {
+ var server = _step13.value;
+
+ if (server[key] === value) {
+ return server;
+ }
+ }
+ } catch (err) {
+ _didIteratorError13 = true;
+ _iteratorError13 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion13 && _iterator13["return"]) {
+ _iterator13["return"]();
+ }
+ } finally {
+ if (_didIteratorError13) {
+ throw _iteratorError13;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def trySendConnData
+ }, {
+ key: "trySendConnData",
+ value: function trySendConnData() {
+
+ if (this.token && !this.alreadySentData) {
+
+ this.alreadySentData = true;
+
+ var data = {
+ op: 2,
+ d: {
+ token: this.token,
+ v: 3,
+ properties: {
+ "$os": "discord.js",
+ "$browser": "discord.js",
+ "$device": "discord.js",
+ "$referrer": "",
+ "$referring_domain": ""
+ }
+ }
+ };
+ this.websocket.send(JSON.stringify(data));
+ }
+ }
+ }, {
+ key: "resolveServerID",
+ value: function resolveServerID(resource) {
+
+ if (resource instanceof Server) {
+ return resource.id;
+ } else if (!isNaN(resource) && resource.length && resource.length === 17) {
+ return resource;
+ }
+ }
+ }, {
+ key: "resolveDestination",
+ value: function resolveDestination(destination) {
+ var channId = false;
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ if (destination instanceof Server) {
+ channId = destination.id; //general is the same as server id
+ } else if (destination instanceof Channel) {
+ channId = destination.id;
+ } else if (destination instanceof Message) {
+ channId = destination.channel.id;
+ } else if (destination instanceof PMChannel) {
+ channId = destination.id;
+ } else if (destination instanceof User) {
+
+ //check if we have a PM
+ var _iteratorNormalCompletion14 = true;
+ var _didIteratorError14 = false;
+ var _iteratorError14 = undefined;
+
+ try {
+ for (var _iterator14 = self.pmChannelCache[Symbol.iterator](), _step14; !(_iteratorNormalCompletion14 = (_step14 = _iterator14.next()).done); _iteratorNormalCompletion14 = true) {
+ var pmc = _step14.value;
+
+ if (pmc.user.equals(destination)) {
+ resolve(pmc.id);
+ return;
+ }
+ }
+
+ //we don't, at this point we're late
+ } catch (err) {
+ _didIteratorError14 = true;
+ _iteratorError14 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion14 && _iterator14["return"]) {
+ _iterator14["return"]();
+ }
+ } finally {
+ if (_didIteratorError14) {
+ throw _iteratorError14;
+ }
+ }
+ }
+
+ self.startPM(destination).then(function (pmc) {
+ resolve(pmc.id);
+ })["catch"](reject);
+ } else {
+ channId = destination;
+ }
+ if (channId) resolve(channId);else reject();
+ });
+ }
+ }, {
+ key: "_sendMessage",
+ value: function _sendMessage(destination, content, tts, mentions) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request.post(Endpoints.CHANNELS + "/" + destination + "/messages").set("authorization", self.token).send({
+ content: content,
+ mentions: mentions,
+ tts: tts
+ }).end(function (err, res) {
+
+ if (err) {
+ reject(err);
+ } else {
+ var data = res.body;
+
+ var mentions = [];
+
+ data.mentions = data.mentions || []; //for some reason this was not defined at some point?
+
+ var _iteratorNormalCompletion15 = true;
+ var _didIteratorError15 = false;
+ var _iteratorError15 = undefined;
+
+ try {
+ for (var _iterator15 = data.mentions[Symbol.iterator](), _step15; !(_iteratorNormalCompletion15 = (_step15 = _iterator15.next()).done); _iteratorNormalCompletion15 = true) {
+ var mention = _step15.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError15 = true;
+ _iteratorError15 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion15 && _iterator15["return"]) {
+ _iterator15["return"]();
+ }
+ } finally {
+ if (_didIteratorError15) {
+ throw _iteratorError15;
+ }
+ }
+ }
+
+ var channel = self.getChannel("id", data.channel_id);
+ if (channel) {
+ var msg = channel.addMessage(new Message(data, channel, mentions, self.addUser(data.author)));
+ resolve(msg);
+ }
+ }
+ });
+ });
+ }
+ }, {
+ key: "_sendFile",
+ value: function _sendFile(destination, attachment) {
+ var attachmentName = arguments.length <= 2 || arguments[2] === undefined ? "DEFAULT BECAUSE YOU DIDN'T SPECIFY WHY.png" : arguments[2];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request.post(Endpoints.CHANNELS + "/" + destination + "/messages").set("authorization", self.token).attach("file", attachment, attachmentName).end(function (err, res) {
+
+ if (err) {
+ reject(err);
+ } else {
+
+ var chann = self.getChannel("id", destination);
+ if (chann) {
+ var msg = chann.addMessage(new Message(res.body, chann, [], self.user));
+ resolve(msg);
+ }
+ }
+ });
+ });
+ }
+ }, {
+ key: "_updateMessage",
+ value: function _updateMessage(message, content) {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ request.patch(Endpoints.CHANNELS + "/" + message.channel.id + "/messages/" + message.id).set("authorization", self.token).send({
+ content: content,
+ mentions: []
+ }).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ var msg = new Message(res.body, message.channel, message.mentions, message.sender);
+ resolve(msg);
+ message.channel.messages[message.channel.messages.indexOf(message)] = msg;
+ }
+ });
+ });
+ }
+ }, {
+ key: "_deleteMessage",
+ value: function _deleteMessage(message) {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+
+ request.del(Endpoints.CHANNELS + "/" + message.channel.id + "/messages/" + message.id).set("authorization", self.token).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve();
+ }
+ });
+ });
+ }
+ }, {
+ key: "checkQueue",
+ value: function checkQueue(channelID) {
+ var _this = this;
+
+ var self = this;
+
+ if (!this.checkingQueue[channelID]) {
+ (function () {
+ var doNext = function doNext() {
+ if (self.queue[channelID].length === 0) {
+ done();
+ return;
+ }
+ var queuedEvent = self.queue[channelID][0];
+ switch (queuedEvent.action) {
+ case "sendMessage":
+ var msgToSend = queuedEvent;
+ self._sendMessage(channelID, msgToSend.content, msgToSend.tts, msgToSend.mentions).then(function (msg) {
+ msgToSend.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToSend.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "sendFile":
+ var fileToSend = queuedEvent;
+ self._sendFile(channelID, fileToSend.attachment, fileToSend.attachmentName).then(function (msg) {
+ fileToSend.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ fileToSend.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "updateMessage":
+ var msgToUpd = queuedEvent;
+ self._updateMessage(msgToUpd.message, msgToUpd.content).then(function (msg) {
+ msgToUpd.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToUpd.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "deleteMessage":
+ var msgToDel = queuedEvent;
+ self._deleteMessage(msgToDel.message).then(function (msg) {
+ msgToDel.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToDel.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ default:
+ done();
+ break;
+ }
+ };
+
+ var done = function done() {
+ self.checkingQueue[channelID] = false;
+ return;
+ };
+
+ //if we aren't already checking this queue.
+ _this.checkingQueue[channelID] = true;
+ doNext();
+ })();
+ }
+ }
+ }, {
+ key: "getGateway",
+ value: function getGateway() {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ request.get(Endpoints.API + "/gateway").set("authorization", self.token).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(res.body.url);
+ }
+ });
+ });
+ }
+ }, {
+ key: "setStatusIdle",
+ value: function setStatusIdle() {
+ this.setStatus("idle");
+ }
+ }, {
+ key: "setStatusOnline",
+ value: function setStatusOnline() {
+ this.setStatus("online");
+ }
+ }, {
+ key: "setStatusActive",
+ value: function setStatusActive() {
+ this.setStatusOnline();
+ }
+ }, {
+ key: "setStatusHere",
+ value: function setStatusHere() {
+ this.setStatusOnline();
+ }
+ }, {
+ key: "setStatusAway",
+ value: function setStatusAway() {
+ this.setStatusIdle();
+ }
+ }, {
+ key: "startTyping",
+ value: function startTyping(chann, stopTypeTime) {
+ var self = this;
+
+ this.resolveDestination(chann).then(next);
+
+ function next(channel) {
+ if (self.typingIntervals[channel]) {
+ return;
+ }
+
+ var fn = function fn() {
+ request.post(Endpoints.CHANNELS + "/" + channel + "/typing").set("authorization", self.token).end();
+ };
+
+ fn();
+
+ var interval = setInterval(fn, 3000);
+
+ self.typingIntervals[channel] = interval;
+
+ if (stopTypeTime) {
+ setTimeout(function () {
+ self.stopTyping(channel);
+ }, stopTypeTime);
+ }
+ }
+ }
+ }, {
+ key: "stopTyping",
+ value: function stopTyping(chann) {
+ var self = this;
+
+ this.resolveDestination(chann).then(next);
+
+ function next(channel) {
+ if (!self.typingIntervals[channel]) {
+ return;
+ }
+
+ clearInterval(self.typingIntervals[channel]);
+
+ delete self.typingIntervals[channel];
+ }
+ }
+ }, {
+ key: "setStatus",
+ value: function setStatus(stat) {
+
+ var idleTime = stat === "online" ? null : Date.now();
+
+ this.__idleTime = idleTime;
+
+ this.websocket.send(JSON.stringify({
+ op: 3,
+ d: {
+ idle_since: this.__idleTime,
+ game_id: this.__gameId
+ }
+ }));
+ }
+ }, {
+ key: "setPlayingGame",
+ value: function setPlayingGame(id) {
+
+ if (id instanceof String || typeof id === "string") {
+
+ // working on names
+ var gid = id.trim().toUpperCase();
+
+ id = null;
+
+ var _iteratorNormalCompletion16 = true;
+ var _didIteratorError16 = false;
+ var _iteratorError16 = undefined;
+
+ try {
+ for (var _iterator16 = gameMap[Symbol.iterator](), _step16; !(_iteratorNormalCompletion16 = (_step16 = _iterator16.next()).done); _iteratorNormalCompletion16 = true) {
+ var game = _step16.value;
+
+ if (game.name.trim().toUpperCase() === gid) {
+
+ id = game.id;
+ break;
+ }
+ }
+ } catch (err) {
+ _didIteratorError16 = true;
+ _iteratorError16 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion16 && _iterator16["return"]) {
+ _iterator16["return"]();
+ }
+ } finally {
+ if (_didIteratorError16) {
+ throw _iteratorError16;
+ }
+ }
+ }
+ }
+
+ this.__gameId = id;
+
+ this.websocket.send(JSON.stringify({
+ op: 3,
+ d: {
+ idle_since: this.__idleTime,
+ game_id: this.__gameId
+ }
+ }));
+ }
+ }, {
+ key: "playGame",
+ value: function playGame(id) {
+ this.setPlayingGame(id);
+ }
+ }, {
+ key: "playingGame",
+ value: function playingGame(id) {
+
+ this.setPlayingGame(id);
+ }
+ }, {
+ key: "uptime",
+ get: function get() {
+
+ return this.readyTime ? Date.now() - this.readyTime : null;
+ }
+ }, {
+ key: "ready",
+ get: function get() {
+ return this.state === 3;
+ }
+ }, {
+ key: "servers",
+ get: function get() {
+ return this.serverCache;
+ }
+ }, {
+ key: "channels",
+ get: function get() {
+ return this.channelCache;
+ }
+ }, {
+ key: "users",
+ get: function get() {
+ return this.userCache;
+ }
+ }, {
+ key: "PMChannels",
+ get: function get() {
+ return this.pmChannelCache;
+ }
+ }, {
+ key: "messages",
+ get: function get() {
+
+ var msgs = [];
+ var _iteratorNormalCompletion17 = true;
+ var _didIteratorError17 = false;
+ var _iteratorError17 = undefined;
+
+ try {
+ for (var _iterator17 = this.channelCache[Symbol.iterator](), _step17; !(_iteratorNormalCompletion17 = (_step17 = _iterator17.next()).done); _iteratorNormalCompletion17 = true) {
+ var channel = _step17.value;
+
+ msgs = msgs.concat(channel.messages);
+ }
+ } catch (err) {
+ _didIteratorError17 = true;
+ _iteratorError17 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion17 && _iterator17["return"]) {
+ _iterator17["return"]();
+ }
+ } finally {
+ if (_didIteratorError17) {
+ throw _iteratorError17;
+ }
+ }
+ }
+
+ return msgs;
+ }
+ }]);
+
+ return Client;
+})();
+
+module.exports = Client;
diff --git a/lib/Endpoints.js b/lib/Endpoints.js
new file mode 100644
index 000000000..e55f0f580
--- /dev/null
+++ b/lib/Endpoints.js
@@ -0,0 +1,13 @@
+"use strict";
+
+exports.BASE_DOMAIN = "discordapp.com";
+exports.BASE = "https://" + exports.BASE_DOMAIN;
+exports.WEBSOCKET_HUB = "wss://" + exports.BASE_DOMAIN + "/hub";
+
+exports.API = exports.BASE + "/api";
+exports.AUTH = exports.API + "/auth";
+exports.LOGIN = exports.AUTH + "/login";
+exports.LOGOUT = exports.AUTH + "/logout";
+exports.USERS = exports.API + "/users";
+exports.SERVERS = exports.API + "/guilds";
+exports.CHANNELS = exports.API + "/channels";
diff --git a/lib/Member.js b/lib/Member.js
new file mode 100644
index 000000000..471460e77
--- /dev/null
+++ b/lib/Member.js
@@ -0,0 +1,21 @@
+"use strict";
+
+var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var User = require("./user.js");
+
+var Member = (function (_User) {
+ _inherits(Member, _User);
+
+ function Member(data) {
+ _classCallCheck(this, Member);
+
+ _get(Object.getPrototypeOf(Member.prototype), "constructor", this).call(this, data);
+ }
+
+ return Member;
+})(User);
diff --git a/lib/PMChannel.js b/lib/PMChannel.js
index 1bfe3c155..6eb8134de 100644
--- a/lib/PMChannel.js
+++ b/lib/PMChannel.js
@@ -1,6 +1,71 @@
-var User = require("./user.js").User;
+"use strict";
-exports.PMChannel = function(user, id){
- this.user = new User(user);
- this.id = id;
-}
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var PMChannel = (function () {
+ function PMChannel(data, client) {
+ _classCallCheck(this, PMChannel);
+
+ this.user = client.getUser("id", data.recipient.id);
+ this.id = data.id;
+ this.messages = [];
+ }
+
+ _createClass(PMChannel, [{
+ key: "addMessage",
+ value: function addMessage(data) {
+ if (!this.getMessage("id", data.id)) {
+ this.messages.push(data);
+ }
+ return this.getMessage("id", data.id);
+ }
+ }, {
+ key: "getMessage",
+ value: function getMessage(key, value) {
+
+ if (this.messages.length > 1000) {
+ this.messages.splice(0, 1);
+ }
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.messages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var message = _step.value;
+
+ if (message[key] === value) {
+ return message;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return true;
+ }
+ }]);
+
+ return PMChannel;
+})();
+
+module.exports = PMChannel;
diff --git a/lib/Permissions.js b/lib/Permissions.js
new file mode 100644
index 000000000..3b7c8f256
--- /dev/null
+++ b/lib/Permissions.js
@@ -0,0 +1,48 @@
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Permission = (function () {
+ function Permission(packedPermissions) {
+ _classCallCheck(this, Permission);
+
+ function getBit(x) {
+ return (this.packed >>> x & 1) === 1;
+ }
+
+ this.packed = packedPermissions;
+
+ this.createInstantInvite = getBit(0);
+ this.banMembers = getBit(1);
+ this.kickMembers = getBit(2);
+ this.manageRoles = getBit(3);
+ this.manageChannels = getBit(4);
+ this.manageServer = getBit(5);
+ this.readMessages = getBit(10);
+ this.sendMessages = getBit(11);
+ this.sendTTSMessages = getBit(12);
+ this.manageMessages = getBit(13);
+ this.embedLinks = getBit(14);
+ this.attachFiles = getBit(15);
+ this.readMessageHistory = getBit(16);
+ this.mentionEveryone = getBit(17);
+
+ this.voiceConnect = getBit(20);
+ this.voiceSpeak = getBit(21);
+ this.voiceMuteMembers = getBit(22);
+ this.voiceDeafenMembers = getBit(23);
+ this.voiceMoveMembers = getBit(24);
+ this.voiceUseVoiceActivation = getBit(26);
+ }
+
+ _createClass(Permission, [{
+ key: "getBit",
+ value: function getBit(x) {
+ return (this.packed >>> x & 1) === 1;
+ }
+ }]);
+
+ return Permission;
+})();
diff --git a/lib/TokenManager.js b/lib/TokenManager.js
deleted file mode 100644
index ceeed9ded..000000000
--- a/lib/TokenManager.js
+++ /dev/null
@@ -1,68 +0,0 @@
-var fs = require( "fs" );
-var crypto = require( "crypto" );
-var md5 = require( "md5" );
-
-var tokens = {};
-
-exports.TokenManager = function( folder, file ) {
-
- this.path = folder + file;
-
- var self = this;
-
- try {
- var fd = fs.openSync( self.path, "wx" );
- self.writeTokens();
- } catch ( e ) {
- self.readTokens();
- }
-
-}
-
-exports.TokenManager.prototype.addToken = function( id, token, pass ) {
- tokens[ md5( id ) ] = encrypt( token, pass );
- this.writeTokens();
-}
-
-exports.TokenManager.prototype.readTokens = function() {
- tokens = JSON.parse( fs.readFileSync( this.path, "utf8" ) );
- for ( tkn in tokens ) {
- tokens[ tkn ] = decrypt( tokens[ tkn ], tkn );
- }
-}
-
-exports.TokenManager.prototype.writeTokens = function() {
- var tkn = {};
- for ( token in tokens ) {
- tkn[ token ] = encrypt( tokens[ token ], token );
- }
- fs.writeFile( this.path, JSON.stringify( tkn ), function( err ) {
-
- } );
-}
-
-exports.TokenManager.prototype.exists = function( id ) {
- return tokens[ md5( id ) ];
-}
-
-exports.TokenManager.prototype.getToken = function( id, pass ) {
- try{
- return decrypt( tokens[ md5( id ) ], pass );
- }catch(e){
- return false;
- }
-}
-
-function encrypt( string, password ) {
- var cipher = crypto.createCipher( "aes-256-ctr", password )
- var crypted = cipher.update( string, 'utf8', 'hex' )
- crypted += cipher.final( 'hex' );
- return crypted;
-}
-
-function decrypt( string, password ) {
- var decipher = crypto.createDecipher( "aes-256-ctr", password )
- var dec = decipher.update( string, 'hex', 'utf8' )
- dec += decipher.final( 'utf8' );
- return dec;
-}
diff --git a/lib/channel.js b/lib/channel.js
index 16a8e4a51..90a2d7428 100644
--- a/lib/channel.js
+++ b/lib/channel.js
@@ -1,28 +1,101 @@
-var List = require("./list.js").List;
+"use strict";
-exports.Channel = function(name, server, type, id, isPrivate){
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
- if(!type){ //there's no second argument
- var channel = name;
- name = channel.name;
- server = server;
- type = channel.type;
- id = channel.id;
- isPrivate = channel.is_private;
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Channel = (function () {
+ function Channel(data, server) {
+ _classCallCheck(this, Channel);
+
+ this.server = server;
+ this.name = data.name;
+ this.type = data.type;
+ this.topic = data.topic;
+ this.id = data.id;
+ this.messages = [];
+ //this.isPrivate = isPrivate; //not sure about the implementation of this...
}
- this.name = name;
- this.server = server;
- this.type = type;
- this.id = id;
- this.isPrivate = isPrivate;
- this.messages = new List("id", 5000);
-}
+ _createClass(Channel, [{
+ key: "equals",
+ value: function equals(object) {
+ return object && object.id === this.id;
+ }
+ }, {
+ key: "addMessage",
+ value: function addMessage(data) {
-exports.Channel.equals = function(otherChannel){
- if(otherChannel.id === this.id){
- return true;
- } else {
- return false;
- }
-}
+ if (this.messages.length > 1000) {
+ this.messages.splice(0, 1);
+ }
+
+ if (!this.getMessage("id", data.id)) {
+ this.messages.push(data);
+ }
+
+ return this.getMessage("id", data.id);
+ }
+ }, {
+ key: "getMessage",
+ value: function getMessage(key, value) {
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.messages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var message = _step.value;
+
+ if (message[key] === value) {
+ return message;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ return "<#" + this.id + ">";
+ }
+ }, {
+ key: "client",
+ get: function get() {
+ return this.server.client;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return false;
+ }
+ }, {
+ key: "users",
+ get: function get() {
+ return this.server.members;
+ }
+ }, {
+ key: "members",
+ get: function get() {
+ return this.server.members;
+ }
+ }]);
+
+ return Channel;
+})();
+
+module.exports = Channel;
diff --git a/lib/endpoints.js b/lib/endpoints.js
deleted file mode 100644
index 46ca08090..000000000
--- a/lib/endpoints.js
+++ /dev/null
@@ -1,15 +0,0 @@
-var base = "https://discordapp.com/";
-var apibase = base + "api";
-
-exports.API = apibase;
-
-exports.WEBSOCKET_HUB = "wss://discordapp.com/hub"
-
-exports.USERS = apibase + "/users";
-
-exports.LOGIN = apibase + "/auth/login";
-exports.LOGOUT = apibase + "/auth/logout";
-
-exports.SERVERS = apibase + "/guilds";
-
-exports.CHANNELS = apibase + "/channels";
diff --git a/lib/index.js b/lib/index.js
new file mode 100644
index 000000000..f0c3c0ab7
--- /dev/null
+++ b/lib/index.js
@@ -0,0 +1,12 @@
+"use strict";
+
+var request = require("superagent");
+var Endpoints = require("./Endpoints.js");
+var Client = require("./Client.js");
+
+var Discord = {
+ Endpoints: Endpoints,
+ Client: Client
+};
+
+module.exports = Discord;
diff --git a/lib/internal.js b/lib/internal.js
index 42d0dc689..e8b3385da 100644
--- a/lib/internal.js
+++ b/lib/internal.js
@@ -1,5 +1,7 @@
-var request = require( "superagent" );
-var Endpoints = require( "./endpoints.js" );
+"use strict";
+
+var request = require("superagent");
+var Endpoints = require("./endpoints.js");
var Internal = {};
@@ -14,264 +16,188 @@ Internal.WebSocket.properties = {
"$referring_domain": ""
};
-Internal.XHR.login = function( email, password, callback ) {
+Internal.XHR.login = function (email, password, callback) {
- request
- .post( Endpoints.LOGIN )
- .send( {
- email: email,
- password: password
- } )
- .end( function( err, res ) {
- if ( err ) {
- callback( err );
- } else {
- callback( null, res.body.token );
- }
- } );
+ request.post(Endpoints.LOGIN).send({
+ email: email,
+ password: password
+ }).end(function (err, res) {
+ if (err) {
+ callback(err);
+ } else {
+ callback(null, res.body.token);
+ }
+ });
+};
-}
+Internal.XHR.logout = function (token, callback) {
-Internal.XHR.logout = function( token, callback ) {
+ request.post(Endpoints.LOGOUT).end(function (err, res) {
- request
- .post( Endpoints.LOGOUT )
- .end( function( err, res ) {
+ err ? callback(err) : callback(null);
+ });
+};
- err ? callback( err ) : callback( null );
+Internal.XHR.createServer = function (token, name, region, callback) {
- } );
+ request.post(Endpoints.SERVERS).set("authorization", token).send({
+ name: name,
+ region: region
+ }).end(function (err, res) {
+ if (err) {
+ callback(err);
+ } else {
+ callback(null, res.body);
+ }
+ });
+};
-}
+Internal.XHR.leaveServer = function (token, serverId, callback) {
-Internal.XHR.createServer = function( token, name, region, callback ) {
+ request.del(Endpoints.SERVERS + "/" + serverId).set("authorization", token).end(function (err, res) {
- request
- .post( Endpoints.SERVERS )
- .set( "authorization", token )
- .send( {
- name: name,
- region: region
- } )
- .end( function( err, res ) {
- if ( err ) {
- callback( err );
- } else {
- callback( null, res.body );
- }
- } );
-}
+ err ? callback(err) : callback(null);
+ });
+};
-Internal.XHR.leaveServer = function( token, serverId, callback ) {
+Internal.XHR.createInvite = function (token, channelId, options, callback) {
+ request.post(Endpoints.CHANNELS + "/" + channelId + "/invites").set("authorization", token).send(options).end(function (err, res) {
+ if (err) {
+ callback(err);
+ } else {
+ callback(null, res.body);
+ }
+ });
+};
- request
- .del( Endpoints.SERVERS + "/" + serverId )
- .set( "authorization", token )
- .end( function( err, res ) {
+Internal.XHR.startPM = function (token, selfID, userID, callback) {
- err ? callback( err ) : callback( null );
+ request.post(Endpoints.USERS + "/" + selfID + "/channels").set("authorization", token).send({
+ recipient_id: userID
+ }).end(function (err, res) {
+ if (err) {
+ callback(err);
+ } else {
+ callback(null, res.body);
+ }
+ });
+};
- } );
+Internal.XHR.sendMessage = function (token, channelID, messageParameters, callback) {
+ request.post(Endpoints.CHANNELS + "/" + channelID + "/messages").set("authorization", token).send(messageParameters).end(function (err, res) {
-}
+ if (err) {
+ callback(err);
+ } else {
+ callback(null, res.body);
+ }
+ });
+};
-Internal.XHR.createInvite = function( token, channelId, options, callback ) {
- request
- .post( Endpoints.CHANNELS + "/" + channelId + "/invites" )
- .set( "authorization", token )
- .send( options )
- .end( function( err, res ) {
- if ( err ) {
- callback( err );
- } else {
- callback( null, res.body );
- }
- } )
-}
+Internal.XHR.sendFile = function (token, channelID, file, fileName, callback) {
+ request.post(Endpoints.CHANNELS + "/" + channelID + "/messages").set("authorization", token).attach("file", file, fileName).end(function (err, res) {
-Internal.XHR.startPM = function( token, selfID, userID, callback ) {
+ if (err) {
+ callback(err);
+ } else {
+ callback(null, res.body);
+ }
+ });
+};
- request
- .post( Endpoints.USERS + "/" + selfID + "/channels" )
- .set( "authorization", token )
- .send( {
- recipient_id: userID
- } )
- .end( function( err, res ) {
- if ( err ) {
- callback( err );
- } else {
- callback( null, res.body );
- }
- } );
+Internal.XHR.deleteMessage = function (token, channelID, messageID, callback) {
+ request.del(Endpoints.CHANNELS + "/" + channelID + "/messages/" + messageID).set("authorization", token).end(function (err) {
+ err ? callback(err) : callback(null);
+ });
+};
-}
+Internal.XHR.updateMessage = function (token, channelID, messageID, messageParameters, callback) {
-Internal.XHR.sendMessage = function( token, channelID, messageParameters, callback ) {
- request
- .post( Endpoints.CHANNELS + "/" + channelID + "/messages" )
- .set( "authorization", token )
- .send( messageParameters )
- .end( function( err, res ) {
+ request.patch(Endpoints.CHANNELS + "/" + channelID + "/messages/" + messageID).set("authorization", token).send(messageParameters).end(function (err, res) {
+ if (err) {
+ callback(err);
+ } else {
+ callback(null, res.body);
+ }
+ });
+};
- if ( err ) {
- callback( err );
- } else {
- callback( null, res.body );
- }
+Internal.XHR.getChannelLogs = function (token, channelID, amount, callback) {
+ request.get(Endpoints.CHANNELS + "/" + channelID + "/messages?limit=" + amount).set("authorization", token).end(function (err, res) {
- } );
+ if (err) {
+ callback(err);
+ } else {
+ callback(null, res.body);
+ }
+ });
+};
-}
+Internal.XHR.createChannel = function (token, serverID, name, type, callback) {
+ request.post(Endpoints.SERVERS + "/" + serverID + "/channels").set("authorization", token).send({
+ name: name,
+ type: type
+ }).end(function (err, res) {
+ if (err) {
+ callback(err);
+ } else {
+ callback(null, res.body);
+ }
+ });
+};
-Internal.XHR.sendFile = function( token, channelID, file, fileName, callback ) {
- request
- .post( Endpoints.CHANNELS + "/" + channelID + "/messages" )
- .set( "authorization", token )
- .attach("file", file, fileName)
- .end( function( err, res ) {
+Internal.XHR.deleteChannel = function (token, channelID, callback) {
- if ( err ) {
- callback( err );
- } else {
- callback( null, res.body );
- }
+ request.del(Endpoints.CHANNELS + "/" + channelID).set("authorization", token).end(function (err) {
+ err ? callback(err) : callback(null);
+ });
+};
+Internal.XHR.deleteServer = function (token, serverID, callback) {
+ request.del(Endpoints.SERVERS + "/" + serverID).set("authorization", token).end(function (err) {
+ err ? callback(err) : callback(null);
+ });
+};
- } );
-}
+Internal.XHR.getChannels = function (token, serverID, callback) {
+ request.get(Endpoints.SERVERS + "/" + serverID + "/channels").set("authorization", token).end(function (err) {
+ err ? callback(err) : callback(null);
+ });
+};
-Internal.XHR.deleteMessage = function( token, channelID, messageID, callback ) {
- request
- .del( Endpoints.CHANNELS + "/" + channelID + "/messages/" + messageID )
- .set( "authorization", token )
- .end( function( err ) {
- err ? callback( err ) : callback( null );
- } );
-}
+Internal.XHR.getServer = function (token, serverID, callback) {
-Internal.XHR.updateMessage = function( token, channelID, messageID, messageParameters, callback ) {
+ request.get(Endpoints.SERVERS + "/" + serverID).set("authorization", token).end(function (err, res) {
- request
- .patch( Endpoints.CHANNELS + "/" + channelID + "/messages/" + messageID )
- .set( "authorization", token )
- .send( messageParameters )
- .end( function( err, res ) {
- if ( err ) {
- callback( err );
- } else {
- callback( null, res.body );
- }
- } );
-}
+ if (err) {
+ callback(err);
+ } else {
+ callback(null, res.body);
+ }
+ });
+};
-Internal.XHR.getChannelLogs = function( token, channelID, amount, callback ) {
- request
- .get( Endpoints.CHANNELS + "/" + channelID + "/messages?limit=" + amount )
- .set( "authorization", token )
- .end( function( err, res ) {
+Internal.XHR.acceptInvite = function (token, inviteID, callback) {
- if ( err ) {
- callback( err );
- } else {
- callback( null, res.body );
- }
+ request.post(Endpoints.API + "/invite/" + inviteID).set("authorization", token).end(function (err, res) {
+ if (err) {
+ callback(err);
+ } else {
+ callback(null, res.body);
+ }
+ });
+};
- } );
-}
+Internal.XHR.setUsername = function (token, avatar, email, newPassword, password, username, callback) {
-Internal.XHR.createChannel = function( token, serverID, name, type, callback ) {
- request
- .post( Endpoints.SERVERS + "/" + serverID + "/channels" )
- .set( "authorization", token )
- .send( {
- name: name,
- type: type
- } )
- .end( function( err, res ) {
- if ( err ) {
- callback( err );
- } else {
- callback( null, res.body );
- }
- } );
-}
-
-Internal.XHR.deleteChannel = function( token, channelID, callback ) {
-
- request
- .del( Endpoints.CHANNELS + "/" + channelID )
- .set( "authorization", token )
- .end( function( err ) {
- err ? callback( err ) : callback( null );
- } );
-
-}
-Internal.XHR.deleteServer = function( token, serverID, callback ) {
- request
- .del( Endpoints.SERVERS + "/" + serverID )
- .set( "authorization", token )
- .end( function( err ) {
- err ? callback( err ) : callback( null );
- } );
-}
-
-Internal.XHR.getChannels = function( token, serverID, callback ) {
- request
- .get( Endpoints.SERVERS + "/" + serverID + "/channels" )
- .set( "authorization", token )
- .end( function( err ) {
- err ? callback( err ) : callback( null );
- } );
-}
-
-Internal.XHR.getServer = function( token, serverID, callback ) {
-
- request
- .get( Endpoints.SERVERS + "/" + serverID )
- .set( "authorization", token )
- .end( function( err, res ) {
-
- if ( err ) {
- callback( err );
- } else {
- callback( null, res.body );
- }
-
- } );
-
-}
-
-Internal.XHR.acceptInvite = function( token, inviteID, callback ) {
-
- request
- .post( Endpoints.API + "/invite/" + inviteID )
- .set( "authorization", token )
- .end( function( err, res ) {
- if ( err ) {
- callback( err );
- } else {
- callback( null, res.body )
- }
- } );
-
-}
-
-Internal.XHR.setUsername = function( token, avatar, email, newPassword, password, username, callback ) {
-
- request
- .patch( Endpoints.API + "/users/@me" )
- .set( "authorization", token )
- .send( {
- avatar: avatar,
- email: email,
- new_password: newPassword,
- password: password,
- username: username
- } )
- .end( function( err ) {
- callback( err );
- } );
-
-}
+ request.patch(Endpoints.API + "/users/@me").set("authorization", token).send({
+ avatar: avatar,
+ email: email,
+ new_password: newPassword,
+ password: password,
+ username: username
+ }).end(function (err) {
+ callback(err);
+ });
+};
exports.Internal = Internal;
diff --git a/lib/invite.js b/lib/invite.js
index f2e10077a..7bc8204bd 100644
--- a/lib/invite.js
+++ b/lib/invite.js
@@ -1,21 +1,35 @@
-var User = require("./user.js").User;
+"use strict";
-exports.Invite = function(json){
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
- this.max_age = json.max_age;
- this.code = json.code;
- this.server = json.guild;
- this.revoked = json.revoked;
- this.created_at = Date.parse(json.created_at);
- this.temporary = json.temporary;
- this.uses = json.uses;
- this.max_uses = json.uses;
- this.inviter = new User(json.inviter);
- this.xkcdpass = json.xkcdpass;
- this.channel = json.channel;
-}
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-exports.Invite.prototype.generateInviteURL = function(xkcd){
- var code = (xkcd ? this.xkcdpass : this.code);
- return "https://discord.gg/"+code;
-}
+var Invite = (function () {
+ function Invite(data, client) {
+ _classCallCheck(this, Invite);
+
+ this.max_age = data.max_age;
+ this.code = data.code;
+ this.server = client.getServer("id", data.guild.id);
+ this.revoked = data.revoked;
+ this.created_at = Date.parse(data.created_at);
+ this.temporary = data.temporary;
+ this.uses = data.uses;
+ this.max_uses = data.uses;
+ this.inviter = client.addUser(data.inviter);
+ this.xkcd = data.xkcdpass;
+ this.channel = client.getChannel("id", data.channel.id);
+ }
+
+ _createClass(Invite, [{
+ key: "URL",
+ get: function get() {
+ var code = this.xkcd ? this.xkcdpass : this.code;
+ return "https://discord.gg/" + code;
+ }
+ }]);
+
+ return Invite;
+})();
+
+module.exports = Invite;
diff --git a/lib/list.js b/lib/list.js
deleted file mode 100644
index 5ad268523..000000000
--- a/lib/list.js
+++ /dev/null
@@ -1,248 +0,0 @@
-/**
- * Similar to a Java set. Contains no duplicate elements and includes filter
- * functions. Discriminates between elements based on a discriminator passed
- * when created. Generally "ID"
- * @class List
- */
-exports.List = function( discriminator, cap ) {
- /**
- * What to use to distringuish duplicates
- * @attribute discriminator
- * @type {String}
- */
- this.discriminator = discriminator;
- /**
- * The maximum amount of elements allowed in the list.
- * @default Infinity
- * @attribute cap
- * @type {Number}
- */
- this.cap = cap || Number.MAX_SAFE_INTEGER;
- /**
- * The Array version of the List.
- * @type {Array}
- * @attribute contents
- */
- this.contents = [];
-}
-
-/**
- * Adds an element to the list if it isn't already there.
- * @method add
- * @param {Object/Array} element The element(s) to add
- * @example
- * List.add( obj );
- * List.add( [ obj, obj, obj ] );
- */
-exports.List.prototype.add = function( child ) {
-
- var self = this;
-
- if ( child.constructor === Array ) {
-
- children = child;
- for ( child of children ) {
- addChild( child );
- }
-
- } else {
- addChild( child );
- }
-
- function addChild( child ) {
-
- if ( self.length() > self.cap ) {
- self.splice( 0, 1 );
- }
-
- if ( self.filter( self.discriminator, child[ self.discriminator ] ).length() === 0 )
- self.contents.push( child );
- }
-}
-
-/**
- * Returns the length of the List
- * @method length
- * @return {Number}
- */
-exports.List.prototype.length = function() {
- return this.contents.length;
-}
-
-/**
- * Gets the index of an element in the List or defaults to false
- * @param {Object} object The element we want to get the index of
- * @return {Number/Boolean} The index if the object is in the list, or false.
- * @method getIndex
- */
-exports.List.prototype.getIndex = function( object ) {
-
- var index = false;
-
- for ( elementIndex in this.contents ) {
- var element = this.contents[ elementIndex ];
- if ( element[ this.discriminator ] == object[ this.discriminator ] ) {
- return elementIndex;
- }
-
- }
-
- return index;
-
-}
-
-/**
- * Removes an element at the specified index
- * @param {Number} index
- * @method removeIndex
- */
-exports.List.prototype.removeIndex = function( index ) {
- this.contents.splice( index, 1 );
-}
-
-/**
- * Removes an element from the list
- * @param {Object} element
- * @method removeElement
- * @return {Boolean} whether the operation was successful or not.
- */
-exports.List.prototype.removeElement = function( child ) {
-
- for ( _element in this.contents ) {
- var element = this.contents[ _element ];
- if ( child[ this.discriminator ] == element[ this.discriminator ] ) {
- this.removeIndex( _element, 1 );
- return true;
- }
- }
-
- return false;
-}
-
-/**
- * Replaces an element in the list with a specified element
- * @method updateElement
- * @param {Object} element Element to update.
- * @param {Object} newElement New Element
- * @return {Boolean} whether the operation was successful or not.
- */
-exports.List.prototype.updateElement = function( child, newChild ) {
-
- for ( _element in this.contents ) {
- var element = this.contents[ _element ];
- if ( child[ this.discriminator ] == element[ this.discriminator ] ) {
- this.contents[ _element ] = newChild;
- return true;
- }
- }
-
- return false;
-
-}
-
-exports.List.prototype.concatSublists = function( whereList, discriminator ) {
- //this is meant to look at the contents, and assuming the contents are all lists, concatenate their values.
-
- var concatList = new exports.List( discriminator );
-
- for ( item of this.contents ) {
- var itemList = item[ whereList ];
- concatList.add( itemList.contents );
- }
-
- return concatList;
-}
-
-exports.List.prototype.filter = function( key, value, onlyOne, caseInsen ) {
-
- var results = [];
-
- value = change( value );
-
- for ( index in this.contents ) {
- var child = this.contents[ index ];
- if ( change( child[ key ] ) == value ) {
- if ( onlyOne ) {
- return child;
- } else {
- results.push( child );
- }
- }
- }
-
- function change( val ) {
- if ( caseInsen ) {
- val = val.toUpperCase();
- }
- return val;
- }
-
- if ( onlyOne ) {
- return false;
- }
-
- var retList = new exports.List( this.discriminator );
- retList.contents = results;
-
- return retList;
-}
-
-exports.List.prototype.getValues = function( key ){
-
- var valList = [];
- for( child of this.contents){
- valList.push( child[key] );
- }
- return valList;
-
-}
-
-exports.List.prototype.deepFilter = function( keys, value, onlyOne, caseInsen ) {
-
- var results = [];
-
- value = change( value );
-
- for ( index in this.contents ) {
- var child = this.contents[ index ];
- var buffer = child;
-
- for ( key of keys ) {
- if(buffer instanceof exports.List){
- buffer = buffer.contents;
- }
- if(buffer instanceof Array){
- for(elem of buffer){
- if( change(elem[key]) == value ){
- buffer = elem;
- }
- }
- }
- buffer = buffer[ key ];
- }
-
- if ( change( buffer ) == value ) {
- if ( onlyOne ) {
- return child;
- } else {
- results.push( child );
- }
- }
- }
-
- function change( val ) {
- if ( caseInsen ) {
- val = val.toUpperCase();
- }
- return val;
- }
-
- if ( onlyOne ) {
- return false;
- }
-
- var retList = new exports.List( this.discriminator );
- retList.contents = results;
-
- return retList;
-}
diff --git a/lib/message.js b/lib/message.js
index 121bbf5dd..f3f3c574a 100644
--- a/lib/message.js
+++ b/lib/message.js
@@ -1,39 +1,79 @@
-var User = require( "./user.js" ).User;
-var List = require( "./list.js" ).List;
-var PMChannel = require( "./PMChannel.js" ).PMChannel;
+"use strict";
-exports.Message = function( time, author, content, channel, id, mentions, everyoneMentioned, embeds ) {
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
- if ( !content ) {
- message = time;
- channel = author;
- time = message.timestamp;
- author = message.author;
- content = message.content;
- id = message.id;
- mentions = message.mentions;
- everyoneMentioned = message.mention_everyone;
- embeds = message.embeds;
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var PMChannel = require("./PMChannel.js");
+
+var Message = (function () {
+ function Message(data, channel, mentions, author) {
+ _classCallCheck(this, Message);
+
+ this.tts = data.tts;
+ this.timestamp = Date.parse(data.timestamp);
+ this.nonce = data.nonce;
+ this.mentions = mentions;
+ this.everyoneMentioned = data.mention_everyone;
+ this.id = data.id;
+ this.embeds = data.embeds;
+ this.editedTimestamp = data.edited_timestamp;
+ this.content = data.content.trim();
+ this.channel = channel;
+ this.author = author;
+ this.attachments = data.attachments;
}
- this.time = Date.parse( time );
- this.author = new User( author );
- this.content = content.replace( /\s+/g, ' ' ).trim(); //content.replace(/<[^>]*>/g, "").replace(/\s+/g, ' ').trim();
- this.channel = channel;
- this.id = id;
- this.mentions = new List( "id" );
- this.everyoneMentioned = everyoneMentioned;
- this.embeds = embeds;
- for ( x in mentions ) {
- var _mention = mentions[ x ];
- this.mentions.add( new User( _mention ) );
- }
-}
+ /*exports.Message.prototype.isPM = function() {
+ return ( this.channel instanceof PMChannel );
+ }*/
-exports.Message.prototype.isPM = function() {
- return ( this.channel instanceof PMChannel );
-}
+ _createClass(Message, [{
+ key: "isMentioned",
+ value: function isMentioned(user) {
+ var id = user.id ? user.id : user;
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
-exports.Message.prototype.isMentioned = function( user ) {
- return ( this.mentions.filter( "id", user.id ).length > 0 );
-}
+ try {
+ for (var _iterator = this.mentions[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var mention = _step.value;
+
+ if (mention.id === id) {
+ return true;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return false;
+ }
+ }, {
+ key: "sender",
+ get: function get() {
+ return this.author;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return this.channel.isPrivate;
+ }
+ }]);
+
+ return Message;
+})();
+
+module.exports = Message;
diff --git a/lib/server.js b/lib/server.js
index a5cfaab6a..8bd9332a2 100644
--- a/lib/server.js
+++ b/lib/server.js
@@ -1,106 +1,183 @@
-var User = require( "./user.js" ).User;
-var List = require( "./list.js" ).List;
-/**
- * A wrapper for Server information, contains channels and users too. Developers should not instantiate the class, instead they should
- * manipulate Server objects given to them.
- * @class Server
- * @param {String} region The region of the server
- */
-exports.Server = function( region, ownerID, name, id, members, icon, afkTimeout, afkChannelId ) {
+"use strict";
- /**
- * The region of the Server
- * @type {String}
- * @attribute region
- */
- this.region = region;
- /**
- * The ID of the owner of the Server (not a User!)
- * @type {String}
- * @attribute ownerID
- */
- this.ownerID = ownerID;
- /**
- * The name of the Server
- * @type {String}
- * @attribute name
- */
- this.name = name;
- /**
- * The ID of the Server
- * @type {String}
- * @attribute id
- */
- this.id = id;
- /**
- * List containing members of the Server
- * @param {List}
- * @attribute members
- */
- this.members = new List( "id" );
- /**
- * List containing channelss of the Server
- * @param {List}
- * @attribute channels
- */
- this.channels = new List( "id" );
- /**
- * ID of the Icon of the Server
- * @param {String}
- * @attribute icon
- */
- this.icon = icon;
- /**
- * The amount of seconds that should pass before the user is
- * @type {Number}
- * @attribute afkTimeout
- */
- this.afkTimeout = afkTimeout;
- /**
- * The ID of the AFK Channel, evaluates to false if doesn't exist.
- * @type {String}
- * @attribute afkChannelId
- */
- this.afkChannelId = afkChannelId;
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
- for ( x in members ) {
- var member = members[ x ].user;
- this.members.add( new User( member ) );
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Server = (function () {
+ function Server(data, client) {
+ _classCallCheck(this, Server);
+
+ this.client = client;
+ this.region = data.region;
+ this.ownerID = data.owner_id;
+ this.name = data.name;
+ this.id = data.id;
+ this.members = [];
+ this.channels = [];
+ this.icon = data.icon;
+ this.afkTimeout = data.afk_timeout;
+ this.afkChannelId = data.afk_channel_id;
+
+ if (!data.members) {
+ data.members = [client.user];
+ return;
+ }
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = data.members[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var member = _step.value;
+
+ // first we cache the user in our Discord Client,
+ // then we add it to our list. This way when we
+ // get a user from this server's member list,
+ // it will be identical (unless an async change occurred)
+ // to the client's cache.
+ if (member.user) this.members.push(client.addUser(member.user));
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
}
-}
-/**
- * Returns a valid URL pointing towards the server's icon if it has one.
- * @method getIconURL
- * @return {String/Boolean} If there is an icon, a URL is returned. If not, false is returned.
- */
-exports.Server.prototype.getIconURL = function(){
- if(!this.icon)
- return false;
- return "https://discordapp.com/api/guilds/"+this.id+"/icons/"+this.icon+".jpg";
-}
+ _createClass(Server, [{
+ key: "getChannel",
-/**
- * Returns the AFK Channel if a server has one
- * @method getAFKChannel
- * @return {Channel/Boolean} If there is an AFK Channel, a Channel is returned. If not, false is returned.
- */
-exports.Server.prototype.getAFKChannel = function(){
+ // get/set
+ value: function getChannel(key, value) {
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
- if(!this.afkChannelId)
- return false;
+ try {
+ for (var _iterator2 = this.channels[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var channel = _step2.value;
- return this.channels.filter("id", this.afkChannelId, true);
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2["return"]) {
+ _iterator2["return"]();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
-}
+ return null;
+ }
+ }, {
+ key: "getMember",
+ value: function getMember(key, value) {
+ var _iteratorNormalCompletion3 = true;
+ var _didIteratorError3 = false;
+ var _iteratorError3 = undefined;
-/**
- * Returns the #general channel of the server.
- * @method getDefaultChannel
- * @return {Channel} Returns the #general channel of the Server.
- */
-exports.Server.prototype.getDefaultChannel = function() {
+ try {
+ for (var _iterator3 = this.members[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var member = _step3.value;
- return this.channels.filter( "name", "general", true );
+ if (member[key] === value) {
+ return member;
+ }
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3["return"]) {
+ _iterator3["return"]();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
-}
+ return null;
+ }
+ }, {
+ key: "addChannel",
+ value: function addChannel(chann) {
+ if (!this.getChannel("id", chann.id)) {
+ this.channels.push(chann);
+ }
+ return chann;
+ }
+ }, {
+ key: "addMember",
+ value: function addMember(member) {
+ if (!this.getMember("id", member.id)) {
+ this.members.push(member);
+ }
+ return member;
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ return this.name;
+ }
+ }, {
+ key: "equals",
+ value: function equals(object) {
+ return object.id === this.id;
+ }
+ }, {
+ key: "iconURL",
+ get: function get() {
+ if (!this.icon) return null;
+ return "https://discordapp.com/api/guilds/" + this.id + "/icons/" + this.icon + ".jpg";
+ }
+ }, {
+ key: "afkChannel",
+ get: function get() {
+ if (!this.afkChannelId) return false;
+
+ return this.getChannel("id", this.afkChannelId);
+ }
+ }, {
+ key: "defaultChannel",
+ get: function get() {
+ return this.getChannel("name", "general");
+ }
+ }, {
+ key: "owner",
+ get: function get() {
+ return this.client.getUser("id", this.ownerID);
+ }
+ }, {
+ key: "users",
+ get: function get() {
+ return this.members;
+ }
+ }]);
+
+ return Server;
+})();
+
+module.exports = Server;
diff --git a/lib/user.js b/lib/user.js
index 2bf3cc51b..e2b2ca256 100644
--- a/lib/user.js
+++ b/lib/user.js
@@ -1,37 +1,57 @@
-exports.User = function( username, id, discriminator, avatar ) {
+"use strict";
- if ( !id ) { //there's no second argument
- var user = username;
- username = user.username;
- id = user.id;
- discriminator = user.discriminator;
- avatar = user.avatar;
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var User = (function () {
+ function User(data) {
+ _classCallCheck(this, User);
+
+ this.username = data.username;
+ this.discriminator = data.discriminator;
+ this.id = data.id;
+ this.avatar = data.avatar;
+ this.status = "offline";
}
- this.username = username;
- this.discriminator = discriminator;
- this.id = id;
- this.avatar = avatar;
-}
+ // access using user.avatarURL;
-exports.User.prototype.getAvatarURL = function() {
- if ( !this.avatar )
- return false;
- return "https://discordapp.com/api/users/" + this.id + "/avatars/" + this.avatar + ".jpg";
-}
+ _createClass(User, [{
+ key: "mention",
+ value: function mention() {
+ return "<@" + this.id + ">";
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ /*
+ if we embed a user in a String - like so:
+ "Yo " + user + " what's up?"
+ It would generate something along the lines of:
+ "Yo @hydrabolt what's up?"
+ */
+ return this.mention();
+ }
+ }, {
+ key: "equals",
+ value: function equals(object) {
+ return object.id === this.id;
+ }
+ }, {
+ key: "equalsStrict",
+ value: function equalsStrict(object) {
+ return object.id === this.id && object.avatar === this.avatar && object.username === this.username && object.discriminator === this.discriminator;
+ }
+ }, {
+ key: "avatarURL",
+ get: function get() {
+ if (!this.avatar) return null;
+ return "https://discordapp.com/api/users/" + this.id + "/avatars/" + this.avatar + ".jpg";
+ }
+ }]);
-exports.User.prototype.mention = function() {
- return "<@" + this.id + ">";
-}
+ return User;
+})();
-exports.User.prototype.equals = function( otherUser ) {
-
- return otherUser.id === this.id;
-
-}
-
-exports.User.prototype.equalsStrict = function( otherUser ) {
-
- return ( this.username === otherUser.username && this.discriminator === otherUser.discriminator && this.id === otherUser.id && this.avatar === otherUser.avatar );
-
-}
+module.exports = User;
diff --git a/package.json b/package.json
index 43fbfabd0..74c1b4766 100644
--- a/package.json
+++ b/package.json
@@ -1,14 +1,14 @@
{
"name": "discord.js",
- "version": "2.7.1",
+ "version": "3.7.2",
"description": "A way to interface with the Discord API",
- "main": "index.js",
+ "main": "./lib/index.js",
"scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
+ "test": "node ./test/bot.js"
},
"repository": {
"type": "git",
- "url": "git+https://github.com/discord-js/discord.js.git"
+ "url": "git+https://github.com/hydrabolt/discord.js.git"
},
"keywords": [
"discord",
@@ -21,12 +21,18 @@
"author": "Amish Shah ",
"license": "Apache-2.0",
"bugs": {
- "url": "https://github.com/discord-js/discord.js/issues"
+ "url": "https://github.com/hydrabolt/discord.js/issues"
},
- "homepage": "https://github.com/discord-js/discord.js#readme",
+ "homepage": "https://github.com/hydrabolt/discord.js#readme",
"dependencies": {
- "md5": "^2.0.0",
"superagent": "^1.3.0",
"ws": "^0.7.2"
+ },
+ "devDependencies": {
+ "grunt": "~0.4.5",
+ "grunt-babel": "^5.0.1",
+ "grunt-browserify": "^4.0.0",
+ "grunt-contrib-uglify": "^0.9.2",
+ "load-grunt-tasks": "^3.2.0"
}
}
diff --git a/ref/gameMap.json b/ref/gameMap.json
new file mode 100644
index 000000000..8b351465f
--- /dev/null
+++ b/ref/gameMap.json
@@ -0,0 +1 @@
+[{"executables":{"win32":["pol.exe"]},"id":0,"name":"FINAL FANTASY XI"},{"executables":{"win32":["ffxiv.exe","ffxiv_dx11.exe"]},"id":1,"name":"FINAL FANTASY XIV"},{"executables":{"win32":["Wow.exe","Wow-64.exe"]},"id":3,"name":"World of Warcraft"},{"executables":{"darwin":["LoLLauncher.app"],"win32":["LolClient.exe","League of Legends.exe"]},"id":4,"name":"League of Legends"},{"executables":{"darwin":["Diablo%20III.app"],"win32":["Diablo III.exe"]},"id":5,"name":"Diablo 3"},{"executables":{"darwin":["dota_osx.app"],"win32":["dota2.exe"]},"id":6,"name":"DOTA 2"},{"executables":{"darwin":["Heroes.app"],"win32":["Heroes of the Storm.exe","HeroesOfTheStorm_x64.exe","HeroesOfTheStorm.exe"]},"id":7,"name":"Heroes of the Storm"},{"executables":{"darwin":["Hearthstone.app"],"win32":["Hearthstone.exe"]},"id":8,"name":"Hearthstone"},{"executables":{"win32":["csgo.exe"]},"id":9,"name":"Counter-Strike: Global Offensive"},{"executables":{"win32":["WorldOfTanks.exe"]},"id":10,"name":"World of Tanks"},{"executables":{"darwin":["gw2.app"],"win32":["gw2.exe"]},"id":11,"name":"Guild Wars 2"},{"executables":{"win32":["dayz.exe"]},"id":12,"name":"Day Z"},{"executables":{"darwin":["starcraft%20ii.app"],"win32":["starcraft ii.exe","SC2_x64.exe","SC2.exe"]},"id":13,"name":"Starcraft II"},{"executables":{"win32":["diablo.exe"]},"id":14,"name":"Diablo"},{"executables":{"win32":["diablo ii.exe"]},"id":15,"name":"Diablo 2"},{"executables":{"win32":["left4dead.exe"]},"id":17,"name":"Left 4 Dead"},{"executables":{"darwin":["minecraft.app"],"win32":["minecraft.exe"]},"id":18,"name":"Minecraft"},{"executables":{"win32":["smite.exe"]},"id":19,"name":"Smite"},{"executables":{"win32":["bf4.exe"]},"id":20,"name":"Battlefield 4"},{"executables":{"win32":["AoK HD.exe","empires2.exe"]},"id":101,"name":"Age of Empire II"},{"executables":{"win32":["age3y.exe"]},"id":102,"name":"Age of Empire III"},{"executables":{"win32":["AlanWake.exe"]},"id":104,"name":"Alan Wake"},{"executables":{"win32":["alan_wakes_american_nightmare.exe"]},"id":105,"name":"Alan Wake's American Nightmare"},{"executables":{"win32":["AlienBreed2Assault.exe"]},"id":106,"name":"Alien Breed 2: Assault"},{"executables":{"win32":["Amnesia.exe"]},"id":107,"name":"Amnesia: The Dark Descent"},{"executables":{"win32":["UDK.exe"]},"id":108,"name":"Antichamber"},{"executables":{"win32":["ArcheAge.exe"]},"id":109,"name":"ArcheAge"},{"executables":{"win32":["arma3.exe"]},"id":110,"name":"Arma III"},{"executables":{"win32":["AC3SP.exe"]},"id":111,"name":"Assassin's Creed 3"},{"executables":{"win32":["Bastion.exe"]},"id":112,"name":"Bastion"},{"executables":{"win32":["BF2.exe"]},"id":113,"name":"Battlefield 2"},{"executables":{"win32":["bf3.exe"]},"id":114,"name":"Battlefield 3"},{"executables":{"win32":["Besiege.exe"]},"id":116,"name":"Besiege"},{"executables":{"win32":["Bioshock.exe"]},"id":117,"name":"Bioshock"},{"executables":{"win32":["Bioshock2.exe"]},"id":118,"name":"BioShock II"},{"executables":{"win32":["BioShockInfinite.exe"]},"id":119,"name":"BioShock Infinite"},{"executables":{"win32":["Borderlands2.exe"]},"id":122,"name":"Borderlands 2"},{"executables":{"win32":["braid.exe"]},"id":123,"name":"Braid"},{"executables":{"win32":["ShippingPC-StormGame.exe"]},"id":124,"name":"Bulletstorm"},{"executables":{},"id":125,"name":"Cabal 2"},{"executables":{"win32":["CabalMain.exe"]},"id":126,"name":"Cabal Online"},{"executables":{"win32":["iw4mp.exe","iw4sp.exe"]},"id":127,"name":"Call of Duty: Modern Warfare 2"},{"executables":{"win32":["t6sp.exe"]},"id":128,"name":"Call of Duty: Black Ops"},{"executables":{"win32":["iw5mp.exe"]},"id":129,"name":"Call of Duty: Modern Warfare 3"},{"executables":{"win32":["RelicCOH.exe"]},"id":132,"name":"Company of Heroes"},{"executables":{"win32":["Crysis64.exe"]},"id":135,"name":"Crysis"},{"executables":{"win32":["Crysis2.exe"]},"id":136,"name":"Crysis 2"},{"executables":{"win32":["Crysis3.exe"]},"id":137,"name":"Crysis 3"},{"executables":{"win32":["Crysis.exe"]},"id":138,"name":"Crysis 4 "},{"executables":{"win32":["DATA.exe"]},"id":140,"name":"Dark Souls"},{"executables":{"win32":["DarkSoulsII.exe"]},"id":141,"name":"Dark Souls II"},{"executables":{"win32":["dfuw.exe"]},"id":142,"name":"Darkfall: Unholy Wars"},{"executables":{"win32":["DCGAME.exe"]},"id":144,"name":"DC Universe Online"},{"executables":{"win32":["DeadIslandGame.exe"]},"id":145,"name":"Dead Island"},{"executables":{"win32":["deadspace2.exe"]},"id":146,"name":"Dead Space 2"},{"executables":{"win32":["LOTDGame.exe"]},"id":147,"name":"Deadlight"},{"executables":{"win32":["dxhr.exe"]},"id":148,"name":"Deus Ex: Human Revolution"},{"executables":{"win32":["DeviMayCry4.exe"]},"id":149,"name":"Devil May Cry 4"},{"executables":{"win32":["DMC-DevilMayCry.exe"]},"id":150,"name":"DmC Devil May Cry"},{"executables":{"win32":["dirt2_game.exe"]},"id":154,"name":"DiRT 2"},{"executables":{"win32":["dirt3_game.exe"]},"id":155,"name":"DiRT 3"},{"executables":{"win32":["dota.exe"]},"id":156,"name":"DOTA"},{"executables":{"win32":["DoubleDragon.exe"]},"id":158,"name":"Double Dragon Neon"},{"executables":{"win32":["DragonAge2.exe"]},"id":159,"name":"Dragon Age II"},{"executables":{"win32":["DragonAgeInquisition.exe"]},"id":160,"name":"Dragon Age: Inquisition"},{"executables":{"win32":["daorigins.exe"]},"id":161,"name":"Dragon Age: Origins"},{"executables":{"win32":["DBXV.exe"]},"id":162,"name":"Dragon Ball XenoVerse"},{"executables":{"win32":["DukeForever.exe"]},"id":163,"name":"Duke Nukem Forever"},{"executables":{"darwin":["Dustforce.app"],"win32":["dustforce.exe"]},"id":164,"name":"Dustforce"},{"executables":{"win32":["EliteDangerous32.exe"]},"id":165,"name":"Elite: Dangerous"},{"executables":{"win32":["exefile.exe"]},"id":166,"name":"Eve Online"},{"executables":{"win32":["eqgame.exe"]},"id":167,"name":"EverQuest"},{"executables":{"win32":["EverQuest2.exe"]},"id":168,"name":"EverQuest II"},{"executables":{},"id":169,"name":"EverQuest Next"},{"executables":{"win32":["Engine.exe"]},"id":170,"name":"F.E.A.R."},{"executables":{"win32":["FEAR2.exe"]},"id":171,"name":"F.E.A.R. 2: Project Origin"},{"executables":{"win32":["fallout3.exe"]},"id":172,"name":"Fallout 3"},{"executables":{"win32":["FalloutNV.exe"]},"id":174,"name":"Fallout: New Vegas"},{"executables":{"win32":["farcry3.exe"]},"id":175,"name":"Far Cry 3"},{"executables":{"win32":["fifa15.exe"]},"id":176,"name":"FIFA 15"},{"executables":{"win32":["FTLGame.exe"]},"id":180,"name":"FTL: Faster Than Light"},{"executables":{"win32":["GTAIV.exe"]},"id":181,"name":"Grand Theft Auto 4"},{"executables":{"win32":["GTA5.exe"]},"id":182,"name":"Grand Theft Auto 5"},{"executables":{"win32":["Gw.exe"]},"id":183,"name":"Guild Wars"},{"executables":{"win32":["H1Z1.exe"]},"id":186,"name":"H1Z1"},{"executables":{"win32":["HL2HL2.exe","hl2.exe"]},"id":188,"name":"Half Life 2"},{"executables":{"win32":["HOMEFRONT.exe"]},"id":195,"name":"Homefront"},{"executables":{"win32":["invisibleinc.exe"]},"id":196,"name":"Invisible Inc."},{"executables":{"win32":["LANoire.exe"]},"id":197,"name":"L.A. Noire"},{"executables":{"win32":["Landmark64.exe"]},"id":198,"name":"Landmark"},{"executables":{"win32":["left4dead2.exe"]},"id":201,"name":"Left 4 Dead 2"},{"executables":{"win32":["lineage.exe"]},"id":203,"name":"Lineage"},{"executables":{"win32":["Magicka.exe"]},"id":206,"name":"Magicka"},{"executables":{"win32":["MapleStory.exe"]},"id":208,"name":"MapleStory"},{"executables":{},"id":209,"name":"Mark of the Ninja"},{"executables":{"win32":["MassEffect.exe"]},"id":210,"name":"Mass Effect"},{"executables":{"win32":["MassEffect2.exe"]},"id":211,"name":"Mass Effect 2"},{"executables":{"win32":["MassEffect3Demo.exe"]},"id":212,"name":"Mass Effect 3"},{"executables":{"win32":["METAL GEAR RISING REVENGEANCE.exe"]},"id":214,"name":"Metal Gear Rising: Revengeance"},{"executables":{"win32":["metro2033.exe"]},"id":215,"name":"Metro 2033"},{"executables":{"win32":["MetroLL.exe"]},"id":216,"name":"Metro Last Light"},{"executables":{"win32":["MK10.exe"]},"id":218,"name":"Mortal Kombat X"},{"executables":{"win32":["speed.exe"]},"id":219,"name":"Need For Speed Most Wanted"},{"executables":{},"id":220,"name":"Neverwinder"},{"executables":{"darwin":["Outlast.app"],"win32":["OLGame.exe"]},"id":221,"name":"Outlast"},{"executables":{"win32":["PapersPlease.exe"]},"id":222,"name":"Papers, Please"},{"executables":{"win32":["payday_win32_release.exe"]},"id":223,"name":"PAYDAY"},{"executables":{"win32":["payday2_win32_release.exe"]},"id":224,"name":"PAYDAY2"},{"executables":{"win32":["PillarsOfEternity.exe"]},"id":225,"name":"Pillars of Eternity"},{"executables":{"win32":["PA.exe"]},"id":226,"name":"Planetary Annihilation"},{"executables":{"win32":["planetside2_x86.exe"]},"id":227,"name":"Planetside 2"},{"executables":{"win32":["hl2P.exe"]},"id":228,"name":"Portal"},{"executables":{"win32":["portal2.exe"]},"id":229,"name":"Portal 2"},{"executables":{"win32":["PrimalCarnageGame.exe"]},"id":231,"name":"Primal Cargnage"},{"executables":{"win32":["pCARS.exe"]},"id":232,"name":"Project Cars"},{"executables":{"win32":["RaceTheSun.exe"]},"id":233,"name":"Race The Sun"},{"executables":{"win32":["Rage.exe"]},"id":234,"name":"RAGE"},{"executables":{"win32":["ragexe.exe"]},"id":235,"name":"Ragnarok Online"},{"executables":{"win32":["rift.exe"]},"id":236,"name":"Rift"},{"executables":{"win32":["Rocksmith2014.exe"]},"id":237,"name":"Rocksmith 2014"},{"executables":{"win32":["SwiftKit-RS.exe","JagexLauncher.exe"]},"id":238,"name":"RuneScape"},{"executables":{"win32":["Shadowgrounds.exe"]},"id":239,"name":"Shadowgrounds"},{"executables":{"win32":["survivor.exe"]},"id":240,"name":"Shadowgrounds: Survivor"},{"executables":{"win32":["ShovelKnight.exe"]},"id":241,"name":"Shovel Knight"},{"executables":{"win32":["SimCity.exe"]},"id":242,"name":"SimCity"},{"executables":{"win32":["SporeApp.exe"]},"id":245,"name":"Spore"},{"executables":{"win32":["StarCitizen.exe"]},"id":246,"name":"Star Citizen"},{"executables":{},"id":247,"name":"Star Trek Online"},{"executables":{"win32":["battlefront.exe"]},"id":248,"name":"Star Wars Battlefront"},{"executables":{"win32":["swtor.exe"]},"id":249,"name":"Star Wars: The Old Republic"},{"executables":{"win32":["starbound.exe","starbound_opengl.exe"]},"id":250,"name":"Starbound"},{"executables":{"win32":["starcraft.exe"]},"id":251,"name":"Starcraft"},{"executables":{"win32":["SSFIV.exe"]},"id":253,"name":"Ultra Street Fighter IV"},{"executables":{"win32":["superhexagon.exe"]},"id":254,"name":"Super Hexagon"},{"executables":{"win32":["swordandsworcery_pc.exe"]},"id":255,"name":"Superbrothers: Sword & Sworcery EP"},{"executables":{"win32":["hl2TF.exe"]},"id":256,"name":"Team Fortress 2"},{"executables":{"win32":["TERA.exe"]},"id":258,"name":"TERA"},{"executables":{"win32":["Terraria.exe"]},"id":259,"name":"Terraria"},{"executables":{"win32":["Bethesda.net_Launcher.exe"]},"id":260,"name":"The Elder Scrolls Online"},{"executables":{"win32":["TESV.exe"]},"id":261,"name":"The Elder Scrolls V: Skyrim"},{"executables":{"win32":["TheSecretWorld.exe"]},"id":262,"name":"The Secret World"},{"executables":{"win32":["TS3.exe","ts3w.exe"]},"id":264,"name":"The Sims 3"},{"executables":{"win32":["WALKINGDEAD101.EXE"]},"id":265,"name":"The Walking Dead"},{"executables":{"win32":["TheWalkingDead2.exe"]},"id":266,"name":"The Walking Dead Season Two"},{"executables":{"win32":["witcher3.exe"]},"id":267,"name":"The Witcher 3"},{"executables":{"win32":["Future Soldier.exe"]},"id":268,"name":"Tom Clancy's Ghost Recon: Future Solider"},{"executables":{"win32":["TombRaider.exe"]},"id":269,"name":"Tomb Raider (2013)"},{"executables":{"win32":["Torchlight.exe"]},"id":271,"name":"Torchlight"},{"executables":{"win32":["Torchlight2.exe"]},"id":272,"name":"Torchlight 2"},{"executables":{"win32":["Shogun2.exe"]},"id":273,"name":"Total War: Shogun 2"},{"executables":{"win32":["Transistor.exe"]},"id":274,"name":"Transistor"},{"executables":{"win32":["trine.exe"]},"id":275,"name":"Trine"},{"executables":{"win32":["trine2_32bit.exe"]},"id":276,"name":"Trine 2"},{"executables":{"win32":["UOKR.exe"]},"id":277,"name":"Ultima Online"},{"executables":{"win32":["aces.exe"]},"id":279,"name":"War Thunder"},{"executables":{"win32":["Warcraft III.exe","wc3.exe"]},"id":281,"name":"Warcraft 3: Reign of Chaos"},{"executables":{"win32":["Warcraft II BNE.exe"]},"id":282,"name":"Warcraft II"},{"executables":{"win32":["Warframe.x64.exe","Warframe.exe"]},"id":283,"name":"Warframe"},{"executables":{"win32":["watch_dogs.exe"]},"id":284,"name":"Watch Dogs"},{"executables":{"win32":["WildStar64.exe"]},"id":285,"name":"WildStar"},{"executables":{"win32":["XComGame.exe"]},"id":288,"name":"XCOM: Enemy Unknown"},{"executables":{"win32":["DFO.exe","dfo.exe"]},"id":289,"name":"Dungeon Fighter Online"},{"executables":{"win32":["aclauncher.exe","acclient.exe"]},"id":290,"name":"Asheron's Call"},{"executables":{"win32":["MapleStory2.exe"]},"id":291,"name":"MapleStory 2"},{"executables":{"win32":["ksp.exe"]},"id":292,"name":"Kerbal Space Program"},{"executables":{"win32":["PINBALL.EXE"]},"id":293,"name":"3D Pinball: Space Cadet"},{"executables":{"win32":["dave.exe"]},"id":294,"name":"Dangerous Dave"},{"executables":{"win32":["iwbtgbeta(slomo).exe","iwbtgbeta(fs).exe"]},"id":295,"name":"I Wanna Be The Guy"},{"executables":{"win32":["MechWarriorOnline.exe "]},"id":296,"name":"Mech Warrior Online"},{"executables":{"win32":["dontstarve_steam.exe"]},"id":297,"name":"Don't Starve"},{"executables":{"win32":["GalCiv3.exe"]},"id":298,"name":"Galactic Civilization 3"},{"executables":{"win32":["Risk of Rain.exe"]},"id":299,"name":"Risk of Rain"},{"executables":{"win32":["Binding_of_Isaac.exe","Isaac-ng.exe"]},"id":300,"name":"The Binding of Isaac"},{"executables":{"win32":["RustClient.exe"]},"id":301,"name":"Rust"},{"executables":{"win32":["Clicker Heroes.exe"]},"id":302,"name":"Clicker Heroes"},{"executables":{"win32":["Brawlhalla.exe"]},"id":303,"name":"Brawlhalla"},{"executables":{"win32":["TownOfSalem.exe"]},"id":304,"name":"Town of Salem"},{"executables":{"win32":["osu!.exe"]},"id":305,"name":"osu!"},{"executables":{"win32":["PathOfExileSteam.exe","PathOfExile.exe"]},"id":306,"name":"Path of Exile"},{"executables":{"win32":["Dolphin.exe"]},"id":307,"name":"Dolphin"},{"executables":{"win32":["RocketLeague.exe"]},"id":308,"name":"Rocket League"},{"executables":{"win32":["TJPP.exe"]},"id":309,"name":"Jackbox Party Pack"},{"executables":{"win32":["KFGame.exe"]},"id":310,"name":"Killing Floor 2"},{"executables":{"win32":["ShooterGame.exe"]},"id":311,"name":"Ark: Survival Evolved"},{"executables":{"win32":["LifeIsStrange.exe"]},"id":312,"name":"Life Is Strange"},{"executables":{"win32":["Client_tos.exe"]},"id":313,"name":"Tree of Savior"},{"executables":{"win32":["olliolli2.exe"]},"id":314,"name":"OlliOlli2"},{"executables":{"win32":["cw.exe"]},"id":315,"name":"Closers Dimension Conflict"},{"executables":{"win32":["ESSTEAM.exe","elsword.exe","x2.exe"]},"id":316,"name":"Elsword"},{"executables":{"win32":["ori.exe"]},"id":317,"name":"Ori and the Blind Forest"},{"executables":{"win32":["Skyforge.exe"]},"id":318,"name":"Skyforge"},{"executables":{"win32":["projectzomboid64.exe","projectzomboid32.exe"]},"id":319,"name":"Project Zomboid"},{"executables":{"win32":["From_The_Depths.exe"]},"id":320,"name":"The Depths"},{"executables":{"win32":["TheCrew.exe"]},"id":321,"name":"The Crew"},{"executables":{"win32":["MarvelHeroes2015.exe"]},"id":322,"name":"Marvel Heroes 2015"},{"executables":{"win32":["timeclickers.exe"]},"id":324,"name":"Time Clickers"},{"executables":{"win32":["eurotrucks2.exe"]},"id":325,"name":"Euro Truck Simulator 2"},{"executables":{"win32":["FarmingSimulator2015Game.exe"]},"id":326,"name":"Farming Simulator 15"},{"executables":{"win32":["strife.exe"]},"id":327,"name":"Strife"},{"executables":{"win32":["Awesomenauts.exe"]},"id":328,"name":"Awesomenauts"},{"executables":{"win32":["Dofus.exe"]},"id":329,"name":"Dofus"},{"executables":{"win32":["Boid.exe"]},"id":330,"name":"Boid"},{"executables":{"win32":["adventure-capitalist.exe"]},"id":331,"name":"AdVenture Capitalist"},{"executables":{"win32":["OrcsMustDie2.exe"]},"id":332,"name":"Orcs Must Die! 2"},{"executables":{"win32":["Mountain.exe"]},"id":333,"name":"Mountain"},{"executables":{"win32":["Valkyria.exe"]},"id":335,"name":"Valkyria Chronicles"},{"executables":{"win32":["ffxiiiimg.exe"]},"id":336,"name":"Final Fantasy XIII"},{"executables":{"win32":["TLR.exe"]},"id":337,"name":"The Last Remnant"},{"executables":{"win32":["Cities.exe"]},"id":339,"name":"Cities Skylines"},{"executables":{"win32":["worldofwarships.exe","WoWSLauncher.exe"]},"id":341,"name":"World of Warships"},{"executables":{"win32":["spacegame-Win64-shipping.exe"]},"id":342,"name":"Fractured Space"},{"executables":{"win32":["thespacegame.exe"]},"id":343,"name":"Ascent - The Space Game"},{"executables":{"win32":["DuckGame.exe"]},"id":344,"name":"Duck Game"},{"executables":{"win32":["PPSSPPWindows.exe"]},"id":345,"name":"PPSSPP"},{"executables":{"win32":["MBAA.exe"]},"id":346,"name":"Melty Blood Actress Again: Current Code"},{"executables":{"win32":["TheWolfAmongUs.exe"]},"id":347,"name":"The Wolf Among Us"},{"executables":{"win32":["SpaceEngineers.exe"]},"id":348,"name":"Space Engineers"},{"executables":{"win32":["Borderlands.exe"]},"id":349,"name":"Borderlands"},{"executables":{"win32":["100orange.exe"]},"id":351,"name":"100% Orange Juice"},{"executables":{"win32":["reflex.exe"]},"id":354,"name":"Reflex"},{"executables":{"win32":["pso2.exe"]},"id":355,"name":"Phantasy Star Online 2"},{"executables":{"win32":["AssettoCorsa.exe"]},"id":356,"name":"Assetto Corsa"},{"executables":{"win32":["iw3mp.exe","iw3sp.exe"]},"id":357,"name":"Call of Duty 4: Modern Warfare"},{"executables":{"win32":["WolfOldBlood_x64.exe"]},"id":358,"name":"Wolfenstein: The Old Blood"},{"executables":{"win32":["castle.exe"]},"id":359,"name":"Castle Crashers"},{"executables":{"win32":["vindictus.exe"]},"id":360,"name":"Vindictus"},{"executables":{"win32":["ShooterGame-Win32-Shipping.exe"]},"id":361,"name":"Dirty Bomb"},{"executables":{"win32":["BatmanAK.exe"]},"id":362,"name":"Batman Arkham Knight"},{"executables":{"win32":["drt.exe"]},"id":363,"name":"Dirt Rally"},{"executables":{"win32":["rFactor.exe"]},"id":364,"name":"rFactor"},{"executables":{"win32":["clonk.exe"]},"id":365,"name":"Clonk Rage"},{"executables":{"win32":["SRHK.exe"]},"id":366,"name":"Shadowrun: Hong Kong"},{"executables":{"win32":["Insurgency.exe"]},"id":367,"name":"Insurgency"},{"executables":{"win32":["StepMania.exe"]},"id":368,"name":"Step Mania"},{"executables":{"win32":["FirefallCLient.exe"]},"id":369,"name":"Firefall"},{"executables":{"win32":["mirrorsedge.exe"]},"id":370,"name":"Mirrors Edge"},{"executables":{"win32":["MgsGroundZeroes.exe"]},"id":371,"name":"Metal Gear Solid V: Ground Zeroes"},{"executables":{"win32":["mgsvtpp.exe"]},"id":372,"name":"Metal Gear Solid V: The Phantom Pain"},{"executables":{"win32":["tld.exe"]},"id":373,"name":"The Long Dark"},{"executables":{"win32":["TKOM.exe"]},"id":374,"name":"Take On Mars"},{"executables":{"win32":["robloxplayerlauncher.exe","Roblox.exe"]},"id":375,"name":"Roblox"},{"executables":{"win32":["eu4.exe"]},"id":376,"name":"Europa Universalis 4"},{"executables":{"win32":["APB.exe"]},"id":377,"name":"APB Reloaded"},{"executables":{"win32":["Robocraft.exe"]},"id":378,"name":"Robocraft"},{"executables":{"win32":["Unity.exe"]},"id":379,"name":"Unity"},{"executables":{"win32":["Simpsons.exe"]},"id":380,"name":"The Simpsons: Hit & Run"},{"executables":{"win32":["Dnlauncher.exe","DragonNest.exe"]},"id":381,"name":"Dragon Nest"},{"executables":{"win32":["Trove.exe"]},"id":382,"name":"Trove"},{"executables":{"win32":["EndlessLegend.exe"]},"id":383,"name":"Endless Legend"},{"executables":{"win32":["TurbineLauncher.exe","dndclient.exe"]},"id":384,"name":"Dungeons & Dragons Online"},{"executables":{"win32":["quakelive.exe","quakelive_steam.exe"]},"id":385,"name":"Quake Live"},{"executables":{"win32":["7DaysToDie.exe"]},"id":386,"name":"7DaysToDie"},{"executables":{"win32":["SpeedRunners.exe"]},"id":387,"name":"SpeedRunners"},{"executables":{"win32":["gamemd.exe"]},"id":388,"name":"Command & Conquer: Red Alert 2"},{"executables":{"win32":["generals.exe"]},"id":389,"name":"Command & Conquer Generals: Zero Hour"},{"executables":{"win32":["Oblivion.exe"]},"id":390,"name":"The Elder Scrolls 4: Oblivion"},{"executables":{"win32":["mgsi.exe"]},"id":391,"name":"Metal Gear Solid"},{"executables":{"win32":["EoCApp.exe"]},"id":392,"name":"Divinity - Original Sin"},{"executables":{"win32":["Torment.exe"]},"id":393,"name":"Planescape: Torment"},{"executables":{"win32":["HexPatch.exe"]},"id":394,"name":"Hex: Shards of Fate"},{"executables":{"win32":["NS3FB.exe"]},"id":395,"name":"Naruto Shippuden Ultimate Ninja Storm 3 Full Burst"},{"executables":{"win32":["NSUNSR.exe"]},"id":396,"name":"Naruto Shippuden Ultimate Ninja Storm Revolution"},{"executables":{"win32":["SaintsRowIV.exe"]},"id":397,"name":"Saints Row IV"},{"executables":{"win32":["Shadowrun.exe"]},"id":398,"name":"Shadowrun"},{"executables":{"win32":["DungeonoftheEndless.exe"]},"id":399,"name":"Dungeon of the Endless"},{"executables":{"win32":["Hon.exe"]},"id":400,"name":"Heroes of Newerth"},{"executables":{"win32":["mabinogi.exe"]},"id":401,"name":"Mabinogi"},{"executables":{"win32":["CoD2MP_s.exe","CoDSP_s.exe"]},"id":402,"name":"Call of Duty 2:"},{"executables":{"win32":["CoDWaWmp.exe","CoDWaw.exe"]},"id":403,"name":"Call of Duty: World at War"},{"executables":{"win32":["heroes.exe"]},"id":404,"name":"Mabinogi Heroes (Vindictus) "},{"executables":{"win32":["KanColleViewer.exe"]},"id":405,"name":"KanColle "},{"executables":{"win32":["cyphers.exe"]},"id":406,"name":"Cyphers"},{"executables":{"win32":["RelicCoH2.exe"]},"id":407,"name":"Company of Heroes 2"},{"executables":{"win32":["MJ.exe"]},"id":408,"name":"セガNET麻雀MJ"},{"executables":{"win32":["ge.exe"]},"id":409,"name":"Granado Espada"},{"executables":{"win32":["NovaRO.exe"]},"id":410,"name":"Nova Ragnarok Online"},{"executables":{"win32":["RivalsofAether.exe"]},"id":411,"name":"Rivals of Aether"},{"executables":{"win32":["bfh.exe"]},"id":412,"name":"Battlefield Hardline"},{"executables":{"win32":["GrowHome.exe"]},"id":413,"name":"Grow Home"},{"executables":{"win32":["patriots.exe"]},"id":414,"name":"Rise of Nations Extended"},{"executables":{"win32":["Railroads.exe"]},"id":415,"name":"Sid Meier's Railroads!"},{"executables":{"win32":["Empire.exe"]},"id":416,"name":"Empire: Total War"},{"executables":{"win32":["Napoleon.exe"]},"id":417,"name":"Napoleon: Total War"},{"executables":{"win32":["gta_sa.exe"]},"id":418,"name":"Grand Theft Auto: San Andreas"},{"executables":{"win32":["MadMax.exe"]},"id":419,"name":"Mad Max"},{"executables":{"win32":["Titanfall.exe"]},"id":420,"name":"Titanfall"},{"executables":{"win32":["age2_x1.exe"]},"id":421,"name":"Age of Empires II: The Conquerors"},{"executables":{"win32":["Rome2.exe"]},"id":422,"name":"Total War: ROME 2"},{"executables":{"win32":["ShadowOfMordor.exe"]},"id":423,"name":"Middle-earth: Shadow of Mordor"},{"executables":{"win32":["Subnautica.exe"]},"id":424,"name":"Subnautica"},{"executables":{"win32":["anno5.exe"]},"id":425,"name":"Anno 2070"},{"executables":{"win32":["carrier.exe"]},"id":426,"name":"Carrier Command Gaea Mission"},{"executables":{"win32":["DarksidersPC.exe"]},"id":427,"name":"Darksiders"},{"executables":{"win32":["Darksiders2.exe"]},"id":428,"name":"Darksiders 2"},{"executables":{"win32":["mudlet.exe"]},"id":429,"name":"Mudlet"},{"executables":{"win32":["DunDefLauncher.exe"]},"id":430,"name":"Dungeon Defenders II"},{"executables":{"win32":["hng.exe"]},"id":431,"name":"Heroes and Generals"},{"executables":{"win32":["WFTOGame.exe"]},"id":432,"name":"War of the Overworld"},{"executables":{"win32":["Talisman.exe"]},"id":433,"name":"Talisman: Digital Edition"},{"executables":{"win32":["limbo.exe"]},"id":434,"name":"Limbo"},{"executables":{"win32":["ibbobb.exe"]},"id":435,"name":"ibb & obb"},{"executables":{"win32":["BattleBlockTheater.exe"]},"id":436,"name":"BattleBlock Theater"},{"executables":{"win32":["iracinglauncher.exe","iracingsim.exe","iracingsim64.exe"]},"id":437,"name":"iRacing"},{"executables":{"win32":["CivilizationV_DX11.exe"]},"id":438,"name":"Civilization V"}]
\ No newline at end of file
diff --git a/src/Client.js b/src/Client.js
new file mode 100644
index 000000000..aa396fb4e
--- /dev/null
+++ b/src/Client.js
@@ -0,0 +1,1587 @@
+//discord.js modules
+var Endpoints = require("./Endpoints.js");
+var User = require("./user.js");
+var Server = require("./server.js");
+var Channel = require("./channel.js");
+var Message = require("./message.js");
+var Invite = require("./invite.js");
+var PMChannel = require("./PMChannel.js");
+
+var gameMap = require("../ref/gameMap.json");
+
+//node modules
+var request = require("superagent");
+var WebSocket = require("ws");
+var fs = require("fs");
+
+var defaultOptions = {
+ queue: false
+}
+
+class Client {
+
+ constructor(options = defaultOptions, token = undefined) {
+ /*
+ When created, if a token is specified the Client will
+ try connecting with it. If the token is incorrect, no
+ further efforts will be made to connect.
+ */
+ this.options = options;
+ this.options.queue = this.options.queue;
+ this.token = token;
+ this.state = 0;
+ this.websocket = null;
+ this.events = {};
+ this.user = null;
+ this.alreadySentData = false;
+ this.serverCreateListener = {};
+ this.typingIntervals = {};
+ this.email = "abc";
+ this.password = "abc";
+
+ /*
+ State values:
+ 0 - idle
+ 1 - logging in
+ 2 - logged in
+ 3 - ready
+ 4 - disconnected
+ */
+
+ this.userCache = [];
+ this.channelCache = [];
+ this.serverCache = [];
+ this.pmChannelCache = [];
+ this.readyTime = null;
+ this.checkingQueue = {};
+ this.queue = {};
+
+ this.__idleTime = null;
+ this.__gameId = null;
+ }
+
+ get uptime() {
+
+ return (this.readyTime ? Date.now() - this.readyTime : null);
+
+ }
+
+ get ready() {
+ return this.state === 3;
+ }
+
+ get servers() {
+ return this.serverCache;
+ }
+
+ get channels() {
+ return this.channelCache;
+ }
+
+ get users() {
+ return this.userCache;
+ }
+
+ get PMChannels() {
+ return this.pmChannelCache;
+ }
+
+ get messages() {
+
+ var msgs = [];
+ for (var channel of this.channelCache) {
+ msgs = msgs.concat(channel.messages);
+ }
+ return msgs;
+
+ }
+
+ sendPacket(JSONObject) {
+ if (this.websocket.readyState === 1) {
+ this.websocket.send(JSON.stringify(JSONObject));
+ }
+ }
+
+ //def debug
+ debug(message) {
+ this.trigger("debug", message);
+ }
+
+ on(event, fn) {
+ this.events[event] = fn;
+ }
+
+ off(event) {
+ this.events[event] = null;
+ }
+
+ keepAlive() {
+ this.debug("keep alive triggered");
+ this.sendPacket({
+ op: 1,
+ d: Date.now()
+ });
+ }
+
+ //def trigger
+ trigger(event) {
+ var args = [];
+ for (var arg in arguments) {
+ args.push(arguments[arg]);
+ }
+ var evt = this.events[event];
+ if (evt) {
+ evt.apply(this, args.slice(1));
+ }
+ }
+
+ //def login
+ login(email = "foo@bar.com", password = "pass1234", callback = function (err, token) { }) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ if (self.state === 0 || self.state === 4) {
+
+ self.state = 1; //set the state to logging in
+
+ self.email = email;
+ self.password = password;
+
+ request
+ .post(Endpoints.LOGIN)
+ .send({
+ email: email,
+ password: password
+ }).end(function (err, res) {
+
+ if (err) {
+ self.state = 4; //set state to disconnected
+ self.trigger("disconnected");
+ if (self.websocket) {
+ self.websocket.close();
+ }
+ callback(err);
+ reject(err);
+ } else {
+ self.state = 2; //set state to logged in (not yet ready)
+ self.token = res.body.token; //set our token
+
+ self.getGateway().then(function (url) {
+ self.createws(url);
+ callback(null, self.token);
+ resolve(self.token);
+ }).catch(function (err) {
+ callback(err);
+ reject(err);
+ });
+
+ }
+
+ });
+
+ } else {
+ reject(new Error("Client already logging in or ready"));
+ }
+ });
+
+ }
+
+ logout(callback = function (err) { }) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ request
+ .post(Endpoints.LOGOUT)
+ .set("authorization", self.token)
+ .end(function (err, res) {
+
+ if (err) {
+ callback(err);
+ reject(err);
+ } else {
+ self.websocket.close();
+ self.state = 4;
+ callback();
+ resolve();
+ }
+ });
+
+ });
+
+ }
+
+ createServer(name, region, callback = function (err, server) { }) {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+
+ request
+ .post(Endpoints.SERVERS)
+ .set("authorization", self.token)
+ .send({
+ name: name,
+ region: region
+ })
+ .end(function (err, res) {
+ if (err) {
+ callback(err);
+ reject(err);
+ } else {
+ // potentially redundant in future
+ // creating here does NOT give us the channels of the server
+ // so we must wait for the guild_create event.
+ self.serverCreateListener[res.body.id] = [resolve, callback];
+ /*var srv = self.addServer(res.body);
+ callback(null, srv);
+ resolve(srv);*/
+ }
+ });
+
+ });
+ }
+
+ createChannel(server, channelName, channelType, callback = function (err, chann) { }) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ request
+ .post(`${Endpoints.SERVERS}/${self.resolveServerID(server) }/channels`)
+ .set("authorization", self.token)
+ .send({
+ name: channelName,
+ type: channelType
+ })
+ .end(function (err, res) {
+
+ if (err) {
+ callback(err);
+ reject(err);
+ } else {
+ var server = self.getServer("id", res.body.guild_id);
+ var chann = self.addChannel(res.body, res.body.guild_id);
+ server.addChannel(chann);
+ callback(null, chann);
+ resolve(chann);
+ }
+
+ })
+
+ });
+
+ }
+
+ leaveServer(server, callback = function (err, server) { }) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ request
+ .del(`${Endpoints.SERVERS}/${self.resolveServerID(server) }`)
+ .set("authorization", self.token)
+ .end(function (err, res) {
+
+ if (err) {
+ callback(err);
+ reject(err);
+ } else {
+ self.serverCache.splice(self.serverCache.indexOf(server), 1);
+ callback(null);
+ resolve();
+ }
+
+ });
+
+ });
+
+ }
+
+ createInvite(serverOrChannel, options, callback = function (err, invite) { }) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ var destination;
+
+ if (serverOrChannel instanceof Server) {
+ destination = serverOrChannel.id;
+ } else if (serverOrChannel instanceof Channel) {
+ destination = serverOrChannel.id;
+ } else {
+ destination = serverOrChannel;
+ }
+
+ options = options || {};
+ options.max_age = options.maxAge || 0;
+ options.max_uses = options.maxUses || 0;
+ options.temporary = options.temporary || false;
+ options.xkcdpass = options.xkcd || false;
+
+ request
+ .post(`${Endpoints.CHANNELS}/${destination}/invites`)
+ .set("authorization", self.token)
+ .send(options)
+ .end(function (err, res) {
+ if (err) {
+ callback(err);
+ reject(err);
+ } else {
+ var inv = new Invite(res.body, self);
+ callback(null, inv);
+ resolve(inv);
+ }
+ });
+ });
+
+ }
+
+ startPM(user) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ var userId = user;
+ if (user instanceof User) {
+ userId = user.id;
+ }
+ request
+ .post(`${Endpoints.USERS}/${self.user.id}/channels`)
+ .set("authorization", self.token)
+ .send({
+ recipient_id: userId
+ })
+ .end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(self.addPMChannel(res.body));
+ }
+ });
+ });
+
+ }
+
+ reply(destination, message, tts, callback = function (err, msg) { }) {
+
+ var self = this;
+
+ return new Promise(function (response, reject) {
+
+ if (typeof tts === "function") {
+ // tts is a function, which means the developer wants this to be the callback
+ callback = tts;
+ tts = false;
+ }
+
+ var user = destination.sender;
+ self.sendMessage(destination, message, tts, callback, user + ", ").then(response).catch(reject);
+
+ });
+
+ }
+
+ deleteMessage(message, timeout, callback = function (err, msg) { }) {
+
+ var self = this;
+
+ var prom = new Promise(function (resolve, reject) {
+ if (timeout) {
+ setTimeout(remove, timeout)
+ } else {
+ remove();
+ }
+
+ function remove() {
+ if (self.options.queue) {
+ if (!self.queue[message.channel.id]) {
+ self.queue[message.channel.id] = [];
+ }
+ self.queue[message.channel.id].push({
+ action: "deleteMessage",
+ message: message,
+ then: good,
+ error: bad
+ });
+
+ self.checkQueue(message.channel.id);
+ } else {
+ self._deleteMessage(message).then(good).catch(bad);
+ }
+ }
+
+ function good() {
+ prom.success = true;
+ callback(null);
+ resolve();
+ }
+
+ function bad(err) {
+ prom.error = err;
+ callback(err);
+ reject(err);
+ }
+ });
+
+ return prom;
+ }
+
+ updateMessage(message, content, callback = function (err, msg) { }) {
+
+ var self = this;
+
+ var prom = new Promise(function (resolve, reject) {
+
+ content = (content instanceof Array ? content.join("\n") : content);
+
+ if (self.options.queue) {
+ if (!self.queue[message.channel.id]) {
+ self.queue[message.channel.id] = [];
+ }
+ self.queue[message.channel.id].push({
+ action: "updateMessage",
+ message: message,
+ content: content,
+ then: good,
+ error: bad
+ });
+
+ self.checkQueue(message.channel.id);
+ } else {
+ self._updateMessage(message, content).then(good).catch(bad);
+ }
+
+ function good(msg) {
+ prom.message = msg;
+ callback(null, msg);
+ resolve(msg);
+ }
+
+ function bad(error) {
+ prom.error = error;
+ callback(error);
+ reject(error);
+ }
+
+ });
+
+ return prom;
+ }
+
+ setUsername(newName, callback = function (err) { }) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request
+ .patch(`${Endpoints.API}/users/@me`)
+ .set("authorization", self.token)
+ .send({
+ avatar: self.user.avatar,
+ email: self.email,
+ new_password: null,
+ password: self.password,
+ username: newName
+ })
+ .end(function (err) {
+ callback(err);
+ if (err)
+ reject(err);
+ else
+ resolve();
+ });
+ });
+ }
+
+ getChannelLogs(channel, amount = 500, callback = function (err, logs) { }) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ var channelID = channel;
+ if (channel instanceof Channel) {
+ channelID = channel.id;
+ }
+
+ request
+ .get(`${Endpoints.CHANNELS}/${channelID}/messages?limit=${amount}`)
+ .set("authorization", self.token)
+ .end(function (err, res) {
+
+ if (err) {
+ callback(err);
+ reject(err);
+ } else {
+ var logs = [];
+
+ var channel = self.getChannel("id", channelID);
+
+ for (var message of res.body) {
+
+ var mentions = [];
+ for (var mention of message.mentions) {
+ mentions.push(self.addUser(mention));
+ }
+
+ var author = self.addUser(message.author);
+
+ logs.push(new Message(message, channel, mentions, author));
+ }
+ callback(null, logs);
+ resolve(logs);
+ }
+
+ });
+
+ });
+
+ }
+
+ deleteChannel(channel, callback = function (err) { }) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ var channelID = channel;
+ if (channel instanceof Channel) {
+ channelID = channel.id;
+ }
+
+ request
+ .del(`${Endpoints.CHANNELS}/${channelID}`)
+ .set("authorization", self.token)
+ .end(function (err) {
+ if (err) {
+ callback(err);
+ reject(err);
+ } else {
+ callback(null);
+ resolve();
+ }
+ });
+
+ });
+
+ }
+
+ joinServer(invite, callback = function (err, server) { }) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ var id = (invite instanceof Invite ? invite.code : invite);
+
+ request
+ .post(`${Endpoints.API}/invite/${id}`)
+ .set("authorization", self.token)
+ .end(function (err, res) {
+ if (err) {
+ callback(err);
+ reject(err);
+ } else {
+ if (self.getServer("id", res.body.guild.id)) {
+ resolve(self.getServer("id", res.body.guild.id));
+ } else {
+ self.serverCreateListener[res.body.guild.id] = [resolve, callback];
+ }
+ }
+ });
+
+ });
+
+ }
+
+ sendFile(destination, file, fileName = "image.png", callback = function (err, msg) { }) {
+
+ var self = this;
+
+ var prom = new Promise(function (resolve, reject) {
+
+ var fstream;
+
+ if (typeof file === "string" || file instanceof String) {
+ fstream = fs.createReadStream(file);
+ fileName = file;
+ } else {
+ fstream = file;
+ }
+
+ self.resolveDestination(destination).then(send).catch(bad);
+
+ function send(destination) {
+ if (self.options.queue) {
+ //queue send file too
+ if (!self.queue[destination]) {
+ self.queue[destination] = [];
+ }
+
+ self.queue[destination].push({
+ action: "sendFile",
+ attachment: fstream,
+ attachmentName: fileName,
+ then: good,
+ error: bad
+ });
+
+ self.checkQueue(destination);
+ } else {
+ //not queue
+ self._sendFile(destination, fstream, fileName).then(good).catch(bad);
+ }
+ }
+
+ function good(msg) {
+ prom.message = msg;
+ callback(null, msg);
+ resolve(msg);
+ }
+
+ function bad(err) {
+ prom.error = err;
+ callback(err);
+ reject(err);
+ }
+
+ });
+
+ return prom;
+
+ }
+
+ sendMessage(destination, message, tts, callback = function (err, msg) { }, premessage = "") {
+
+ var self = this;
+
+ var prom = new Promise(function (resolve, reject) {
+
+ if (typeof tts === "function") {
+ // tts is a function, which means the developer wants this to be the callback
+ callback = tts;
+ tts = false;
+ }
+
+ message = premessage + resolveMessage(message);
+ var mentions = resolveMentions();
+ self.resolveDestination(destination).then(send).catch(error);
+
+ function error(err) {
+ callback(err);
+ reject(err);
+ }
+
+ function send(destination) {
+ if (self.options.queue) {
+ //we're QUEUEING messages, so sending them sequentially based on servers.
+ if (!self.queue[destination]) {
+ self.queue[destination] = [];
+ }
+
+ self.queue[destination].push({
+ action: "sendMessage",
+ content: message,
+ mentions: mentions,
+ tts: !!tts, //incase it's not a boolean
+ then: mgood,
+ error: mbad
+ });
+
+ self.checkQueue(destination);
+ } else {
+ self._sendMessage(destination, message, tts, mentions).then(mgood).catch(mbad);
+ }
+
+ }
+
+ function mgood(msg) {
+ prom.message = msg;
+ callback(null, msg);
+ resolve(msg);
+ }
+
+ function mbad(error) {
+ prom.error = error;
+ callback(error);
+ reject(error);
+ }
+
+ function resolveMessage() {
+ var msg = message;
+ if (message instanceof Array) {
+ msg = message.join("\n");
+ }
+ return msg;
+ }
+
+ function resolveMentions() {
+ var _mentions = [];
+ for (var mention of (message.match(/<@[^>]*>/g) || [])) {
+ _mentions.push(mention.substring(2, mention.length - 1));
+ }
+ return _mentions;
+ }
+
+ });
+
+ return prom;
+ }
+
+ //def createws
+ createws(url) {
+ if (this.websocket)
+ return false;
+
+ var self = this;
+
+ //good to go
+ this.websocket = new WebSocket(url);
+
+ //open
+ this.websocket.onopen = function () {
+ self.trySendConnData(); //try connecting
+ };
+
+ //close
+ this.websocket.onclose = function () {
+ self.trigger("disconnected");
+ }
+
+ //message
+ this.websocket.onmessage = function (e) {
+
+ var dat = false, data = {};
+
+ try {
+ dat = JSON.parse(e.data);
+ data = dat.d;
+ } catch (err) {
+ self.trigger("error", err, e);
+ return;
+ }
+
+ self.trigger("raw", dat);
+
+ //valid message
+ switch (dat.t) {
+
+ case "READY":
+ self.debug("received ready packet");
+
+ self.user = self.addUser(data.user);
+
+ for (var _server of data.guilds) {
+
+ var server = self.addServer(_server);
+
+ }
+
+ for (var _pmc of data.private_channels) {
+ var pmc = self.addPMChannel(_pmc);
+ }
+
+ self.trigger("ready");
+ self.readyTime = Date.now();
+ self.debug(`cached ${self.serverCache.length} servers, ${self.channelCache.length} channels, ${self.pmChannelCache.length} PMs and ${self.userCache.length} users.`);
+ self.state = 3;
+ setInterval(function () {
+ self.keepAlive.apply(self);
+ }, data.heartbeat_interval);
+
+ break;
+ case "MESSAGE_CREATE":
+ self.debug("received message");
+
+ var mentions = [];
+ data.mentions = data.mentions || []; //for some reason this was not defined at some point?
+ for (var mention of data.mentions) {
+ mentions.push(self.addUser(mention));
+ }
+
+ var channel = self.getChannel("id", data.channel_id);
+ if (channel) {
+ var msg = channel.addMessage(new Message(data, channel, mentions, self.addUser(data.author)));
+ self.trigger("message", msg);
+ }
+
+ break;
+ case "MESSAGE_DELETE":
+ self.debug("message deleted");
+
+ var channel = self.getChannel("id", data.channel_id);
+ var message = channel.getMessage("id", data.id);
+ if (message) {
+ self.trigger("messageDelete", channel, message);
+ channel.messages.splice(channel.messages.indexOf(message), 1);
+ } else {
+ //don't have the cache of that message ;(
+ self.trigger("messageDelete", channel);
+ }
+ break;
+ case "MESSAGE_UPDATE":
+ self.debug("message updated");
+
+ var channel = self.getChannel("id", data.channel_id);
+ var formerMessage = channel.getMessage("id", data.id);
+
+ if (formerMessage) {
+
+ //new message might be partial, so we need to fill it with whatever the old message was.
+ var info = {};
+
+ for (var key in formerMessage) {
+ info[key] = formerMessage[key];
+ }
+
+ for (var key in data) {
+ info[key] = data[key];
+ }
+
+ var mentions = [];
+ for (var mention of info.mentions) {
+ mentions.push(self.addUser(mention));
+ }
+
+ var newMessage = new Message(info, channel, mentions, formerMessage.author);
+
+ self.trigger("messageUpdate", newMessage, formerMessage);
+
+ channel.messages[channel.messages.indexOf(formerMessage)] = newMessage;
+
+ }
+
+ // message isn't in cache, and if it's a partial it could cause
+ // all hell to break loose... best to just act as if nothing happened
+
+ break;
+
+ case "GUILD_DELETE":
+
+ var server = self.getServer("id", data.id);
+
+ if (server) {
+ self.serverCache.splice(self.serverCache.indexOf(server), 1);
+ self.trigger("serverDelete", server);
+ }
+
+ break;
+
+ case "CHANNEL_DELETE":
+
+ var channel = self.getChannel("id", data.id);
+
+ if (channel) {
+
+ var server = channel.server;
+
+ if (server) {
+
+ server.channels.splice(server.channels.indexOf(channel), 1);
+
+ }
+
+ self.trigger("channelDelete", channel);
+
+ self.serverCache.splice(self.serverCache.indexOf(channel), 1);
+
+ }
+
+ break;
+
+ case "GUILD_CREATE":
+
+ var server = self.getServer("id", data.id);
+
+ if (!server) {
+ //if server doesn't already exist because duh
+ server = self.addServer(data);
+ }/*else if(server.channels.length === 0){
+
+ var srv = new Server(data, self);
+ for(channel of data.channels){
+ srv.channels.push(new Channel(channel, data.id));
+ }
+ self.serverCache[self.serverCache.indexOf(server)] = srv;
+
+ }*/
+
+ if (self.serverCreateListener[data.id]) {
+ var cbs = self.serverCreateListener[data.id];
+ cbs[0](server); //promise then callback
+ cbs[1](null, server); //legacy callback
+ self.serverCreateListener[data.id] = null;
+ }
+
+ self.trigger("serverCreate", server);
+
+ break;
+
+ case "CHANNEL_CREATE":
+
+ var channel = self.getChannel("id", data.id);
+
+ if (!channel) {
+
+ var chann = self.addChannel(data, data.guild_id);
+ var srv = self.getServer("id", data.guild_id);
+ if (srv) {
+ srv.addChannel(chann);
+ }
+ self.trigger("channelCreate", chann);
+
+ }
+
+ break;
+
+ case "GUILD_MEMBER_ADD":
+
+ var server = self.getServer("id", data.guild_id);
+
+ if (server) {
+
+ var user = self.addUser(data.user); //if for whatever reason it doesn't exist..
+
+ if (!~server.members.indexOf(user)) {
+ server.members.push(user);
+ }
+
+ self.trigger("serverNewMember", user, server);
+ }
+
+ break;
+
+ case "GUILD_MEMBER_REMOVE":
+
+ var server = self.getServer("id", data.guild_id);
+
+ if (server) {
+
+ var user = self.addUser(data.user); //if for whatever reason it doesn't exist..
+
+ if (~server.members.indexOf(user)) {
+ server.members.splice(server.members.indexOf(user), 1);
+ }
+
+ self.trigger("serverRemoveMember", user, server);
+ }
+
+ break;
+
+ case "USER_UPDATE":
+
+ if (self.user && data.id === self.user.id) {
+
+ var newUser = new User(data); //not actually adding to the cache
+
+ self.trigger("userUpdate", newUser, self.user);
+
+ if (~self.userCache.indexOf(self.user)) {
+ self.userCache[self.userCache.indexOf(self.user)] = newUser;
+ }
+
+ self.user = newUser;
+
+ }
+
+ break;
+
+ case "PRESENCE_UPDATE":
+
+ var userInCache = self.getUser("id", data.user.id);
+
+ if (userInCache) {
+ //user exists
+ var presenceUser = new User(data.user);
+ if (presenceUser.equalsStrict(userInCache)) {
+ //they're exactly the same, an actual presence update
+ userInCache.status = data.status;
+ self.trigger("presence", {
+ user: userInCache,
+ status: data.status,
+ server: self.getServer("id", data.guild_id),
+ gameId: data.game_id
+ });
+ } else {
+ //one of their details changed.
+ self.trigger("userUpdate", userInCache, presenceUser);
+ self.userCache[self.userCache.indexOf(userInCache)] = presenceUser;
+ }
+ }
+
+ break;
+
+ case "CHANNEL_UPDATE":
+
+ var channelInCache = self.getChannel("id", data.id),
+ serverInCache = self.getServer("id", data.guild_id);
+
+ if(channelInCache && serverInCache){
+
+ var newChann = new Channel(data, serverInCache);
+ newChann.messages = channelInCache.messages;
+
+ self.trigger("channelUpdate", channelInCache, newChann);
+
+ self.channelCache[ self.channelCache.indexOf(channelInCache) ] = newChann;
+ }
+
+ break;
+
+ default:
+ self.debug("received unknown packet");
+ self.trigger("unknown", dat);
+ break;
+
+ }
+
+ }
+
+ }
+
+ //def addUser
+ addUser(data) {
+ if (!this.getUser("id", data.id)) {
+ this.userCache.push(new User(data));
+ }
+ return this.getUser("id", data.id);
+ }
+
+ //def addChannel
+ addChannel(data, serverId) {
+ if (!this.getChannel("id", data.id)) {
+ this.channelCache.push(new Channel(data, this.getServer("id", serverId)));
+ }
+ return this.getChannel("id", data.id);
+ }
+
+ addPMChannel(data) {
+ if (!this.getPMChannel("id", data.id)) {
+ this.pmChannelCache.push(new PMChannel(data, this));
+ }
+ return this.getPMChannel("id", data.id);
+ }
+
+ setTopic(channel, topic, callback = function(err){}){
+
+ var self = this;
+
+ return new Promise(function(resolve, reject){
+
+ self.resolveDestination(channel).then(next).catch(error);
+
+ function error(e){
+ callback(e);
+ reject(e);
+ }
+
+ function next(destination){
+
+ var asChan = self.getChannel("id", destination);
+
+ request
+ .patch(`${Endpoints.CHANNELS}/${destination}`)
+ .set("authorization", self.token)
+ .send({
+ name : asChan.name,
+ position : 0,
+ topic : topic
+ })
+ .end(function(err, res){
+ if(err){
+ error(err);
+ }else{
+ asChan.topic = res.body.topic;
+ resolve();
+ callback();
+ }
+ });
+ }
+
+ });
+
+ }
+
+ //def addServer
+ addServer(data) {
+
+ var self = this;
+ var server = this.getServer("id", data.id);
+
+ if(data.unavailable){
+ self.trigger("unavailable", data);
+ self.debug("Server ID " + data.id + " has been marked unavailable by Discord. It was not cached.");
+ return;
+ }
+
+ if (!server) {
+ server = new Server(data, this);
+ this.serverCache.push(server);
+ if (data.channels) {
+ for (var channel of data.channels) {
+ server.channels.push(this.addChannel(channel, server.id));
+ }
+ }
+ }
+
+ for(var presence of data.presences){
+ self.getUser("id", presence.user.id).status = presence.status;
+ }
+
+ return server;
+ }
+
+ //def getUser
+ getUser(key, value) {
+ for (var user of this.userCache) {
+ if (user[key] === value) {
+ return user;
+ }
+ }
+ return null;
+ }
+
+ //def getChannel
+ getChannel(key, value) {
+ for (var channel of this.channelCache) {
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ return this.getPMChannel(key, value); //might be a PM
+ }
+
+ getPMChannel(key, value) {
+ for (var channel of this.pmChannelCache) {
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ return null;
+ }
+
+ //def getServer
+ getServer(key, value) {
+ for (var server of this.serverCache) {
+ if (server[key] === value) {
+ return server;
+ }
+ }
+ return null;
+ }
+
+ //def trySendConnData
+ trySendConnData() {
+
+ if (this.token && !this.alreadySentData) {
+
+ this.alreadySentData = true;
+
+ var data = {
+ op: 2,
+ d: {
+ token: this.token,
+ v: 3,
+ properties: {
+ "$os": "discord.js",
+ "$browser": "discord.js",
+ "$device": "discord.js",
+ "$referrer": "",
+ "$referring_domain": ""
+ }
+ }
+ };
+ this.websocket.send(JSON.stringify(data));
+ }
+ }
+
+ resolveServerID(resource) {
+
+ if (resource instanceof Server) {
+ return resource.id;
+ } else if (!isNaN(resource) && resource.length && resource.length === 17) {
+ return resource;
+ }
+
+ }
+
+ resolveDestination(destination) {
+ var channId = false;
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ if (destination instanceof Server) {
+ channId = destination.id; //general is the same as server id
+ } else if (destination instanceof Channel) {
+ channId = destination.id;
+ } else if (destination instanceof Message) {
+ channId = destination.channel.id;
+ } else if (destination instanceof PMChannel) {
+ channId = destination.id;
+ } else if (destination instanceof User) {
+
+ //check if we have a PM
+ for (var pmc of self.pmChannelCache) {
+ if (pmc.user.equals(destination)) {
+ resolve(pmc.id);
+ return;
+ }
+ }
+
+ //we don't, at this point we're late
+ self.startPM(destination).then(function (pmc) {
+ resolve(pmc.id);
+ }).catch(reject);
+
+ } else {
+ channId = destination;
+ }
+ if (channId)
+ resolve(channId);
+ else
+ reject();
+ });
+ }
+
+ _sendMessage(destination, content, tts, mentions) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request
+ .post(`${Endpoints.CHANNELS}/${destination}/messages`)
+ .set("authorization", self.token)
+ .send({
+ content: content,
+ mentions: mentions,
+ tts: tts
+ })
+ .end(function (err, res) {
+
+ if (err) {
+ reject(err);
+ } else {
+ var data = res.body;
+
+ var mentions = [];
+
+ data.mentions = data.mentions || []; //for some reason this was not defined at some point?
+
+ for (var mention of data.mentions) {
+ mentions.push(self.addUser(mention));
+ }
+
+ var channel = self.getChannel("id", data.channel_id);
+ if (channel) {
+ var msg = channel.addMessage(new Message(data, channel, mentions, self.addUser(data.author)));
+ resolve(msg);
+ }
+ }
+
+ });
+ });
+
+ }
+
+ _sendFile(destination, attachment, attachmentName = "DEFAULT BECAUSE YOU DIDN'T SPECIFY WHY.png") {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request
+ .post(`${Endpoints.CHANNELS}/${destination}/messages`)
+ .set("authorization", self.token)
+ .attach("file", attachment, attachmentName)
+ .end(function (err, res) {
+
+ if (err) {
+ reject(err);
+ } else {
+
+ var chann = self.getChannel("id", destination);
+ if (chann) {
+ var msg = chann.addMessage(new Message(res.body, chann, [], self.user));
+ resolve(msg);
+ }
+
+
+ }
+
+ });
+ });
+
+ }
+
+ _updateMessage(message, content) {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ request
+ .patch(`${Endpoints.CHANNELS}/${message.channel.id}/messages/${message.id}`)
+ .set("authorization", self.token)
+ .send({
+ content: content,
+ mentions: []
+ })
+ .end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ var msg = new Message(res.body, message.channel, message.mentions, message.sender);
+ resolve(msg);
+ message.channel.messages[message.channel.messages.indexOf(message)] = msg;
+ }
+ });
+ });
+ }
+
+ _deleteMessage(message) {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+
+ request
+ .del(`${Endpoints.CHANNELS}/${message.channel.id}/messages/${message.id}`)
+ .set("authorization", self.token)
+ .end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve();
+ }
+ });
+ });
+ }
+
+ checkQueue(channelID) {
+
+ var self = this;
+
+ if (!this.checkingQueue[channelID]) {
+ //if we aren't already checking this queue.
+ this.checkingQueue[channelID] = true;
+ doNext();
+
+ function doNext() {
+ if (self.queue[channelID].length === 0) {
+ done();
+ return;
+ }
+ var queuedEvent = self.queue[channelID][0];
+ switch (queuedEvent.action) {
+ case "sendMessage":
+ var msgToSend = queuedEvent;
+ self._sendMessage(channelID, msgToSend.content, msgToSend.tts, msgToSend.mentions)
+ .then(function (msg) {
+ msgToSend.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })
+ .catch(function (err) {
+ msgToSend.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "sendFile":
+ var fileToSend = queuedEvent;
+ self._sendFile(channelID, fileToSend.attachment, fileToSend.attachmentName)
+ .then(function (msg) {
+ fileToSend.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })
+ .catch(function (err) {
+ fileToSend.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "updateMessage":
+ var msgToUpd = queuedEvent;
+ self._updateMessage(msgToUpd.message, msgToUpd.content)
+ .then(function (msg) {
+ msgToUpd.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })
+ .catch(function (err) {
+ msgToUpd.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "deleteMessage":
+ var msgToDel = queuedEvent;
+ self._deleteMessage(msgToDel.message)
+ .then(function (msg) {
+ msgToDel.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })
+ .catch(function (err) {
+ msgToDel.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ default:
+ done();
+ break;
+ }
+ }
+
+ function done() {
+ self.checkingQueue[channelID] = false;
+ return;
+ }
+ }
+ }
+
+ getGateway() {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ request
+ .get(`${Endpoints.API}/gateway`)
+ .set("authorization", self.token)
+ .end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(res.body.url);
+ }
+ });
+ });
+ }
+
+ setStatusIdle(){
+ this.setStatus("idle");
+ }
+
+ setStatusOnline(){
+ this.setStatus("online");
+ }
+
+ setStatusActive(){
+ this.setStatusOnline();
+ }
+
+ setStatusHere(){
+ this.setStatusOnline();
+ }
+
+ setStatusAway(){
+ this.setStatusIdle();
+ }
+
+ startTyping(chann, stopTypeTime){
+ var self = this;
+
+ this.resolveDestination(chann).then(next);
+
+ function next(channel){
+ if(self.typingIntervals[channel]){
+ return;
+ }
+
+ var fn = function(){
+ request
+ .post(`${Endpoints.CHANNELS}/${channel}/typing`)
+ .set("authorization", self.token)
+ .end();
+ };
+
+ fn();
+
+ var interval = setInterval(fn, 3000);
+
+ self.typingIntervals[channel] = interval;
+
+ if(stopTypeTime){
+ setTimeout(function(){
+ self.stopTyping(channel);
+ }, stopTypeTime);
+ }
+ }
+ }
+
+ stopTyping(chann){
+ var self = this;
+
+ this.resolveDestination(chann).then(next);
+
+ function next(channel){
+ if(!self.typingIntervals[channel]){
+ return;
+ }
+
+ clearInterval(self.typingIntervals[channel]);
+
+ delete self.typingIntervals[channel];
+
+ }
+ }
+
+ setStatus(stat){
+
+ var idleTime = (stat === "online" ? null : Date.now());
+
+ this.__idleTime = idleTime;
+
+ this.websocket.send(JSON.stringify({
+ op : 3,
+ d : {
+ idle_since : this.__idleTime,
+ game_id : this.__gameId
+ }
+ }));
+ }
+
+ setPlayingGame(id){
+
+ if( id instanceof String || typeof id === `string` ){
+
+ // working on names
+ var gid = id.trim().toUpperCase();
+
+ id = null;
+
+ for( var game of gameMap ){
+
+ if(game.name.trim().toUpperCase() === gid){
+
+ id = game.id;
+ break;
+
+ }
+
+ }
+
+ }
+
+ this.__gameId = id;
+
+ this.websocket.send(JSON.stringify({
+ op : 3,
+ d : {
+ idle_since : this.__idleTime,
+ game_id : this.__gameId
+ }
+ }));
+
+ }
+
+ playGame(id){
+ this.setPlayingGame(id);
+ }
+
+ playingGame(id){
+
+ this.setPlayingGame(id);
+
+ }
+}
+
+module.exports = Client;
\ No newline at end of file
diff --git a/src/Endpoints.js b/src/Endpoints.js
new file mode 100644
index 000000000..450bf0426
--- /dev/null
+++ b/src/Endpoints.js
@@ -0,0 +1,11 @@
+exports.BASE_DOMAIN = "discordapp.com";
+exports.BASE = `https://${exports.BASE_DOMAIN}`;
+exports.WEBSOCKET_HUB = `wss://${exports.BASE_DOMAIN}/hub`;
+
+exports.API = `${exports.BASE}/api`;
+exports.AUTH = `${exports.API}/auth`;
+exports.LOGIN = `${exports.AUTH}/login`;
+exports.LOGOUT = `${exports.AUTH}/logout`;
+exports.USERS = `${exports.API}/users`;
+exports.SERVERS = `${exports.API}/guilds`;
+exports.CHANNELS = `${exports.API}/channels`;
\ No newline at end of file
diff --git a/src/Member.js b/src/Member.js
new file mode 100644
index 000000000..3fa49ebd6
--- /dev/null
+++ b/src/Member.js
@@ -0,0 +1,12 @@
+var User = require("./user.js");
+
+class Member extends User{
+
+ constructor(data){
+ super(data);
+
+
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/PMChannel.js b/src/PMChannel.js
new file mode 100644
index 000000000..d7985f9c4
--- /dev/null
+++ b/src/PMChannel.js
@@ -0,0 +1,34 @@
+class PMChannel {
+ constructor(data, client) {
+ this.user = client.getUser("id", data.recipient.id);
+ this.id = data.id;
+ this.messages = [];
+ }
+
+ addMessage(data){
+ if(!this.getMessage("id", data.id)){
+ this.messages.push(data);
+ }
+ return this.getMessage("id", data.id);
+ }
+
+ getMessage(key, value){
+
+ if(this.messages.length > 1000){
+ this.messages.splice(0,1);
+ }
+
+ for(var message of this.messages){
+ if(message[key] === value){
+ return message;
+ }
+ }
+ return null;
+ }
+
+ get isPrivate(){
+ return true;
+ }
+}
+
+module.exports = PMChannel;
\ No newline at end of file
diff --git a/src/Permissions.js b/src/Permissions.js
new file mode 100644
index 000000000..e0dc4d424
--- /dev/null
+++ b/src/Permissions.js
@@ -0,0 +1,38 @@
+class Permission {
+
+ constructor(packedPermissions) {
+
+ function getBit(x) {
+ return ((this.packed >>> x) & 1) === 1;
+ }
+
+ this.packed = packedPermissions;
+
+ this.createInstantInvite = getBit(0);
+ this.banMembers = getBit(1);
+ this.kickMembers = getBit(2);
+ this.manageRoles = getBit(3);
+ this.manageChannels = getBit(4);
+ this.manageServer = getBit(5);
+ this.readMessages = getBit(10);
+ this.sendMessages = getBit(11);
+ this.sendTTSMessages = getBit(12);
+ this.manageMessages = getBit(13);
+ this.embedLinks = getBit(14);
+ this.attachFiles = getBit(15);
+ this.readMessageHistory = getBit(16);
+ this.mentionEveryone = getBit(17);
+
+ this.voiceConnect = getBit(20);
+ this.voiceSpeak = getBit(21);
+ this.voiceMuteMembers = getBit(22);
+ this.voiceDeafenMembers = getBit(23);
+ this.voiceMoveMembers = getBit(24);
+ this.voiceUseVoiceActivation = getBit(26);
+
+ }
+
+ getBit(x) {
+ return ((this.packed >>> x) & 1) === 1;
+ }
+}
\ No newline at end of file
diff --git a/src/channel.js b/src/channel.js
new file mode 100644
index 000000000..a7185e17f
--- /dev/null
+++ b/src/channel.js
@@ -0,0 +1,60 @@
+class Channel {
+
+ constructor(data, server) {
+ this.server = server;
+ this.name = data.name;
+ this.type = data.type;
+ this.topic = data.topic;
+ this.id = data.id;
+ this.messages = [];
+ //this.isPrivate = isPrivate; //not sure about the implementation of this...
+ }
+
+ get client() {
+ return this.server.client;
+ }
+
+ equals(object) {
+ return (object && object.id === this.id);
+ }
+
+ addMessage(data){
+
+ if(this.messages.length > 1000){
+ this.messages.splice(0,1);
+ }
+
+ if(!this.getMessage("id", data.id)){
+ this.messages.push(data);
+ }
+
+ return this.getMessage("id", data.id);
+ }
+
+ getMessage(key, value){
+ for(var message of this.messages){
+ if(message[key] === value){
+ return message;
+ }
+ }
+ return null;
+ }
+
+ toString(){
+ return "<#" + this.id + ">";
+ }
+
+ get isPrivate(){
+ return false;
+ }
+
+ get users(){
+ return this.server.members;
+ }
+
+ get members(){
+ return this.server.members;
+ }
+}
+
+module.exports = Channel;
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
new file mode 100644
index 000000000..28df53ed9
--- /dev/null
+++ b/src/index.js
@@ -0,0 +1,10 @@
+var request = require("superagent");
+var Endpoints = require("./Endpoints.js");
+var Client = require("./Client.js");
+
+var Discord = {
+ Endpoints : Endpoints,
+ Client : Client
+}
+
+module.exports = Discord;
\ No newline at end of file
diff --git a/src/internal.js b/src/internal.js
new file mode 100644
index 000000000..42d0dc689
--- /dev/null
+++ b/src/internal.js
@@ -0,0 +1,277 @@
+var request = require( "superagent" );
+var Endpoints = require( "./endpoints.js" );
+
+var Internal = {};
+
+Internal.XHR = {};
+Internal.WebSocket = {};
+
+Internal.WebSocket.properties = {
+ "$os": "discord.js",
+ "$browser": "discord.js",
+ "$device": "discord.js",
+ "$referrer": "",
+ "$referring_domain": ""
+};
+
+Internal.XHR.login = function( email, password, callback ) {
+
+ request
+ .post( Endpoints.LOGIN )
+ .send( {
+ email: email,
+ password: password
+ } )
+ .end( function( err, res ) {
+ if ( err ) {
+ callback( err );
+ } else {
+ callback( null, res.body.token );
+ }
+ } );
+
+}
+
+Internal.XHR.logout = function( token, callback ) {
+
+ request
+ .post( Endpoints.LOGOUT )
+ .end( function( err, res ) {
+
+ err ? callback( err ) : callback( null );
+
+ } );
+
+}
+
+Internal.XHR.createServer = function( token, name, region, callback ) {
+
+ request
+ .post( Endpoints.SERVERS )
+ .set( "authorization", token )
+ .send( {
+ name: name,
+ region: region
+ } )
+ .end( function( err, res ) {
+ if ( err ) {
+ callback( err );
+ } else {
+ callback( null, res.body );
+ }
+ } );
+}
+
+Internal.XHR.leaveServer = function( token, serverId, callback ) {
+
+ request
+ .del( Endpoints.SERVERS + "/" + serverId )
+ .set( "authorization", token )
+ .end( function( err, res ) {
+
+ err ? callback( err ) : callback( null );
+
+ } );
+
+}
+
+Internal.XHR.createInvite = function( token, channelId, options, callback ) {
+ request
+ .post( Endpoints.CHANNELS + "/" + channelId + "/invites" )
+ .set( "authorization", token )
+ .send( options )
+ .end( function( err, res ) {
+ if ( err ) {
+ callback( err );
+ } else {
+ callback( null, res.body );
+ }
+ } )
+}
+
+Internal.XHR.startPM = function( token, selfID, userID, callback ) {
+
+ request
+ .post( Endpoints.USERS + "/" + selfID + "/channels" )
+ .set( "authorization", token )
+ .send( {
+ recipient_id: userID
+ } )
+ .end( function( err, res ) {
+ if ( err ) {
+ callback( err );
+ } else {
+ callback( null, res.body );
+ }
+ } );
+
+}
+
+Internal.XHR.sendMessage = function( token, channelID, messageParameters, callback ) {
+ request
+ .post( Endpoints.CHANNELS + "/" + channelID + "/messages" )
+ .set( "authorization", token )
+ .send( messageParameters )
+ .end( function( err, res ) {
+
+ if ( err ) {
+ callback( err );
+ } else {
+ callback( null, res.body );
+ }
+
+ } );
+
+}
+
+Internal.XHR.sendFile = function( token, channelID, file, fileName, callback ) {
+ request
+ .post( Endpoints.CHANNELS + "/" + channelID + "/messages" )
+ .set( "authorization", token )
+ .attach("file", file, fileName)
+ .end( function( err, res ) {
+
+ if ( err ) {
+ callback( err );
+ } else {
+ callback( null, res.body );
+ }
+
+ } );
+}
+
+Internal.XHR.deleteMessage = function( token, channelID, messageID, callback ) {
+ request
+ .del( Endpoints.CHANNELS + "/" + channelID + "/messages/" + messageID )
+ .set( "authorization", token )
+ .end( function( err ) {
+ err ? callback( err ) : callback( null );
+ } );
+}
+
+Internal.XHR.updateMessage = function( token, channelID, messageID, messageParameters, callback ) {
+
+ request
+ .patch( Endpoints.CHANNELS + "/" + channelID + "/messages/" + messageID )
+ .set( "authorization", token )
+ .send( messageParameters )
+ .end( function( err, res ) {
+ if ( err ) {
+ callback( err );
+ } else {
+ callback( null, res.body );
+ }
+ } );
+}
+
+Internal.XHR.getChannelLogs = function( token, channelID, amount, callback ) {
+ request
+ .get( Endpoints.CHANNELS + "/" + channelID + "/messages?limit=" + amount )
+ .set( "authorization", token )
+ .end( function( err, res ) {
+
+ if ( err ) {
+ callback( err );
+ } else {
+ callback( null, res.body );
+ }
+
+ } );
+}
+
+Internal.XHR.createChannel = function( token, serverID, name, type, callback ) {
+ request
+ .post( Endpoints.SERVERS + "/" + serverID + "/channels" )
+ .set( "authorization", token )
+ .send( {
+ name: name,
+ type: type
+ } )
+ .end( function( err, res ) {
+ if ( err ) {
+ callback( err );
+ } else {
+ callback( null, res.body );
+ }
+ } );
+}
+
+Internal.XHR.deleteChannel = function( token, channelID, callback ) {
+
+ request
+ .del( Endpoints.CHANNELS + "/" + channelID )
+ .set( "authorization", token )
+ .end( function( err ) {
+ err ? callback( err ) : callback( null );
+ } );
+
+}
+Internal.XHR.deleteServer = function( token, serverID, callback ) {
+ request
+ .del( Endpoints.SERVERS + "/" + serverID )
+ .set( "authorization", token )
+ .end( function( err ) {
+ err ? callback( err ) : callback( null );
+ } );
+}
+
+Internal.XHR.getChannels = function( token, serverID, callback ) {
+ request
+ .get( Endpoints.SERVERS + "/" + serverID + "/channels" )
+ .set( "authorization", token )
+ .end( function( err ) {
+ err ? callback( err ) : callback( null );
+ } );
+}
+
+Internal.XHR.getServer = function( token, serverID, callback ) {
+
+ request
+ .get( Endpoints.SERVERS + "/" + serverID )
+ .set( "authorization", token )
+ .end( function( err, res ) {
+
+ if ( err ) {
+ callback( err );
+ } else {
+ callback( null, res.body );
+ }
+
+ } );
+
+}
+
+Internal.XHR.acceptInvite = function( token, inviteID, callback ) {
+
+ request
+ .post( Endpoints.API + "/invite/" + inviteID )
+ .set( "authorization", token )
+ .end( function( err, res ) {
+ if ( err ) {
+ callback( err );
+ } else {
+ callback( null, res.body )
+ }
+ } );
+
+}
+
+Internal.XHR.setUsername = function( token, avatar, email, newPassword, password, username, callback ) {
+
+ request
+ .patch( Endpoints.API + "/users/@me" )
+ .set( "authorization", token )
+ .send( {
+ avatar: avatar,
+ email: email,
+ new_password: newPassword,
+ password: password,
+ username: username
+ } )
+ .end( function( err ) {
+ callback( err );
+ } );
+
+}
+
+exports.Internal = Internal;
diff --git a/src/invite.js b/src/invite.js
new file mode 100644
index 000000000..91c43bbd1
--- /dev/null
+++ b/src/invite.js
@@ -0,0 +1,22 @@
+class Invite {
+ constructor(data, client) {
+ this.max_age = data.max_age;
+ this.code = data.code;
+ this.server = client.getServer("id", data.guild.id);
+ this.revoked = data.revoked;
+ this.created_at = Date.parse(data.created_at);
+ this.temporary = data.temporary;
+ this.uses = data.uses;
+ this.max_uses = data.uses;
+ this.inviter = client.addUser(data.inviter);
+ this.xkcd = data.xkcdpass;
+ this.channel = client.getChannel("id", data.channel.id);
+ }
+
+ get URL() {
+ var code = (this.xkcd ? this.xkcdpass : this.code);
+ return "https://discord.gg/" + code;
+ }
+}
+
+module.exports = Invite;
\ No newline at end of file
diff --git a/src/message.js b/src/message.js
new file mode 100644
index 000000000..3462ce88c
--- /dev/null
+++ b/src/message.js
@@ -0,0 +1,42 @@
+var PMChannel = require("./PMChannel.js");
+
+class Message{
+ constructor(data, channel, mentions, author){
+ this.tts = data.tts;
+ this.timestamp = Date.parse(data.timestamp);
+ this.nonce = data.nonce;
+ this.mentions = mentions;
+ this.everyoneMentioned = data.mention_everyone;
+ this.id = data.id;
+ this.embeds = data.embeds;
+ this.editedTimestamp = data.edited_timestamp;
+ this.content = data.content.trim();
+ this.channel = channel;
+ this.author = author;
+ this.attachments = data.attachments;
+ }
+
+ isMentioned( user ){
+ var id = (user.id ? user.id : user);
+ for(var mention of this.mentions){
+ if(mention.id === id){
+ return true;
+ }
+ }
+ return false;
+ }
+
+ get sender(){
+ return this.author;
+ }
+
+ get isPrivate(){
+ return this.channel.isPrivate;
+ }
+}
+
+/*exports.Message.prototype.isPM = function() {
+ return ( this.channel instanceof PMChannel );
+}*/
+
+module.exports = Message;
\ No newline at end of file
diff --git a/src/server.js b/src/server.js
new file mode 100644
index 000000000..d0d56578c
--- /dev/null
+++ b/src/server.js
@@ -0,0 +1,101 @@
+class Server {
+ constructor(data, client) {
+ this.client = client;
+ this.region = data.region;
+ this.ownerID = data.owner_id;
+ this.name = data.name;
+ this.id = data.id;
+ this.members = [];
+ this.channels = [];
+ this.icon = data.icon;
+ this.afkTimeout = data.afk_timeout;
+ this.afkChannelId = data.afk_channel_id;
+
+ if(!data.members){
+ data.members = [ client.user ];
+ return;
+ }
+
+ for (var member of data.members) {
+
+ // first we cache the user in our Discord Client,
+ // then we add it to our list. This way when we
+ // get a user from this server's member list,
+ // it will be identical (unless an async change occurred)
+ // to the client's cache.
+ if(member.user)
+ this.members.push(client.addUser(member.user));
+
+ }
+ }
+
+ get iconURL() {
+ if (!this.icon)
+ return null;
+ return `https://discordapp.com/api/guilds/${this.id}/icons/${this.icon}.jpg`;
+ }
+
+ get afkChannel() {
+ if (!this.afkChannelId)
+ return false;
+
+ return this.getChannel("id", this.afkChannelId);
+ }
+
+ get defaultChannel() {
+ return this.getChannel("name", "general");
+ }
+
+ get owner() {
+ return this.client.getUser("id", this.ownerID);
+ }
+
+ get users() {
+ return this.members;
+ }
+
+ // get/set
+ getChannel(key, value) {
+ for (var channel of this.channels) {
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+
+ return null;
+ }
+
+ getMember(key, value){
+ for (var member of this.members) {
+ if (member[key] === value) {
+ return member;
+ }
+ }
+
+ return null;
+ }
+
+ addChannel(chann) {
+ if (!this.getChannel("id", chann.id)) {
+ this.channels.push(chann);
+ }
+ return chann;
+ }
+
+ addMember(member){
+ if (!this.getMember("id", member.id)){
+ this.members.push(member);
+ }
+ return member;
+ }
+
+ toString(){
+ return this.name;
+ }
+
+ equals(object){
+ return object.id === this.id;
+ }
+}
+
+module.exports = Server;
\ No newline at end of file
diff --git a/src/user.js b/src/user.js
new file mode 100644
index 000000000..73eef604f
--- /dev/null
+++ b/src/user.js
@@ -0,0 +1,40 @@
+class User{
+ constructor( data ){
+ this.username = data.username;
+ this.discriminator = data.discriminator;
+ this.id = data.id;
+ this.avatar = data.avatar;
+ this.status = "offline";
+ }
+
+ // access using user.avatarURL;
+ get avatarURL(){
+ if( !this.avatar )
+ return null;
+ return `https://discordapp.com/api/users/${this.id}/avatars/${this.avatar}.jpg`;
+ }
+
+ mention(){
+ return `<@${this.id}>`;
+ }
+
+ toString(){
+ /*
+ if we embed a user in a String - like so:
+ "Yo " + user + " what's up?"
+ It would generate something along the lines of:
+ "Yo @hydrabolt what's up?"
+ */
+ return this.mention();
+ }
+
+ equals(object){
+ return object.id === this.id;
+ }
+
+ equalsStrict(object){
+ return object.id === this.id && object.avatar === this.avatar && object.username === this.username && object.discriminator === this.discriminator;
+ }
+}
+
+module.exports = User;
\ No newline at end of file
diff --git a/test/bot.1.js b/test/bot.1.js
new file mode 100644
index 000000000..2531ad78e
--- /dev/null
+++ b/test/bot.1.js
@@ -0,0 +1,63 @@
+var Discord = require("../");
+var mybot = new Discord.Client();
+var fs = require("fs");
+
+var server, channel, message, sentMessage = false;
+
+counter = 1;
+
+mybot.on("message", function (message) {
+
+ console.log("Everyone mentioned? " + message.everyoneMentioned);
+ if (mybot.user.equals(message.sender)) {
+ return;
+ }
+
+ if (message.content !== "$$$") {
+ return;
+ }
+
+ // we can go ahead :)
+
+ var onlineUsers = 0;
+
+ counter++;
+
+ mybot.playingGame( "Minecraft" );
+
+});
+
+mybot.on("ready", function () {
+ console.log("im ready");
+
+ for(var server of mybot.servers){
+ if(server.name === "test-server"){
+ mybot.leaveServer(server);
+ }
+ }
+
+});
+
+mybot.on("debug", function(info){
+ console.log(info);
+})
+
+mybot.on("unknown", function(info){
+ console.log("warning!", info);
+})
+
+mybot.on("channelUpdate", function(oldChan, newChan){
+
+ console.log(oldChan.topic + " vs " + newChan.topic);
+
+});
+
+function dump(msg) {
+ console.log(msg);
+}
+
+function error(err) {
+ console.log(err);
+}
+
+mybot.login(process.env["ds_email"], process.env["ds_password"]).catch(error);
\ No newline at end of file
diff --git a/test/bot.js b/test/bot.js
new file mode 100644
index 000000000..f11b4a015
--- /dev/null
+++ b/test/bot.js
@@ -0,0 +1,134 @@
+/*
+ this file should be used for travis builds only
+*/
+
+var Discord = require("../");
+var mybot = new Discord.Client();
+
+var server, channel, message, sentMessage = false;
+
+function init(){
+ console.log("preparing...");
+}
+
+mybot.on("ready", function(){
+ console.log("ready! beginning tests");
+ success1();
+});
+
+function success1(){ //make server
+ mybot.createServer("test-server", "london").then(success2).catch(error);
+}
+
+function success2(_server){ //make channel
+ console.log("test 1 successful");
+ server = _server;
+ mybot.createChannel(server, "test-channel", "text").then(success3).catch(error);
+}
+
+function success3(_channel){ //send message
+ console.log("test 2 successful");
+ channel = _channel;
+ mybot.sendMessage(channel, [mybot.user.avatarURL, "an", "array", "of", "messages"]).then(success4).catch(error);
+}
+
+function success4(_message){ //delete message
+ console.log("test 3 successful");
+ message = _message;
+ mybot.deleteMessage(message).then(success5).catch(error);
+}
+
+function success5(){ //send ping
+ console.log("test 4 successful");
+ mybot.sendMessage(channel, "ping").then(function(msg){
+ message = msg;
+ }).catch(error);
+ setTimeout(checkError, 30 * 1000);
+}
+
+function success7(){
+ console.log("test 6 successful");
+ mybot.deleteChannel(channel).then(success8).catch(error);
+}
+
+function success8(){
+ console.log("test 7 successful");
+ mybot.createInvite(server).then(success9).catch(error);
+}
+
+function success9(invite){
+ console.log("test 8 successful");
+ if(invite.code){
+ success10();
+ }else{
+ error("reference error");
+ }
+}
+
+function success10(){
+ console.log("test 9 succesful");
+ mybot.leaveServer(server).then(success11).catch(error);
+}
+
+function success11(){
+ console.log("test 10 succesful");
+ mybot.joinServer(process.env["ds_invite"]).then(success12).catch(error);
+}
+
+function success12(_server){
+ console.log("test 11 successful");
+ server = mybot.getServer("id", _server.id);
+ if(server){
+ success13();
+ }else{
+ error("reference error");
+ }
+}
+
+function success13(){
+ console.log("test 12 successful");
+ mybot.sendFile(server, "./test/image.png").then(function(msg){
+ mybot.deleteMessage(msg).then(success14).catch(error);
+ }).catch(error);
+}
+
+function success14(msg){
+ console.log("test 13 successful");
+ mybot.leaveServer(server).then(success15).catch(error);
+}
+
+function success15(){
+ console.log("test 14 successful");
+ mybot.logout().then(done).catch(error);
+}
+
+function done(){
+ console.log("All tests completed succesfully.");
+ process.exit(0);
+}
+
+function checkError(){
+ if(!sentMessage){
+ error("failure receiving messages");
+ }
+}
+
+function error(err){
+ console.log("error", err);
+ process.exit(1);
+}
+
+mybot.on("message", function(message){
+
+ if(message.channel.equals(channel)){
+ if(message.content === "ping"){
+ console.log("test 5 successful");
+ sentMessage = true;
+
+ mybot.updateMessage(message, "pong").then(success7).catch(error);
+ }
+ }
+
+});
+
+mybot.login(process.env["ds_email"], process.env["ds_password"]).then(init).catch(error);
\ No newline at end of file
diff --git a/test/image.png b/test/image.png
new file mode 100644
index 000000000..253ecefb0
Binary files /dev/null and b/test/image.png differ
diff --git a/test/msgbot.js b/test/msgbot.js
new file mode 100644
index 000000000..e69de29bb
diff --git a/web-dist/README.md b/web-dist/README.md
new file mode 100644
index 000000000..053576bab
--- /dev/null
+++ b/web-dist/README.md
@@ -0,0 +1,10 @@
+## Web Distributions
+
+Here you can find the latest web-ready distributions of discord.js. These distributions will allow you to run discord.js
+in your browser, which is very useful for making on-the-go bots or clients. For some reason, request times are also much
+shorter in browsers, so your bots will reply much faster.
+
+Web Distributions aren't always fully functional, and sometimes catching errors is a pain. As discord.js's support for
+browserifying is still maturing, please don't expect that it will work out of the box just yet.
+
+Also, if the versions in this folder are out-dated, you can always run `grunt web` to generate the latest library.
\ No newline at end of file
diff --git a/web-dist/discord.3.3.0.js b/web-dist/discord.3.3.0.js
new file mode 100644
index 000000000..6753dcf6b
--- /dev/null
+++ b/web-dist/discord.3.3.0.js
@@ -0,0 +1,3590 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Discord = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o]*>/g) || [])[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var mention = _step3.value;
+
+ _mentions.push(mention.substring(2, mention.length - 1));
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3["return"]) {
+ _iterator3["return"]();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ return _mentions;
+ }
+ });
+
+ return prom;
+ }
+
+ //def createws
+ }, {
+ key: "createws",
+ value: function createws(url) {
+ if (this.websocket) return false;
+
+ var self = this;
+
+ //good to go
+ this.websocket = new WebSocket(url);
+
+ //open
+ this.websocket.onopen = function () {
+ self.trySendConnData(); //try connecting
+ };
+
+ //close
+ this.websocket.onclose = function () {
+ self.trigger("disconnected");
+ };
+
+ //message
+ this.websocket.onmessage = function (e) {
+
+ var dat = false,
+ data = {};
+
+ try {
+ dat = JSON.parse(e.data);
+ data = dat.d;
+ } catch (err) {
+ self.trigger("error", err, e);
+ return;
+ }
+
+ //valid message
+ switch (dat.t) {
+
+ case "READY":
+ self.debug("received ready packet");
+
+ self.user = self.addUser(data.user);
+
+ var _iteratorNormalCompletion4 = true;
+ var _didIteratorError4 = false;
+ var _iteratorError4 = undefined;
+
+ try {
+ for (var _iterator4 = data.guilds[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
+ var _server = _step4.value;
+
+ var server = self.addServer(_server);
+ }
+ } catch (err) {
+ _didIteratorError4 = true;
+ _iteratorError4 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion4 && _iterator4["return"]) {
+ _iterator4["return"]();
+ }
+ } finally {
+ if (_didIteratorError4) {
+ throw _iteratorError4;
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion5 = true;
+ var _didIteratorError5 = false;
+ var _iteratorError5 = undefined;
+
+ try {
+ for (var _iterator5 = data.private_channels[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
+ var _pmc = _step5.value;
+
+ var pmc = self.addPMChannel(_pmc);
+ }
+ } catch (err) {
+ _didIteratorError5 = true;
+ _iteratorError5 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion5 && _iterator5["return"]) {
+ _iterator5["return"]();
+ }
+ } finally {
+ if (_didIteratorError5) {
+ throw _iteratorError5;
+ }
+ }
+ }
+
+ self.trigger("ready");
+ self.readyTime = Date.now();
+ self.debug("cached " + self.serverCache.length + " servers, " + self.channelCache.length + " channels, " + self.pmChannelCache.length + " PMs and " + self.userCache.length + " users.");
+ self.state = 3;
+ setInterval(function () {
+ self.keepAlive.apply(self);
+ }, data.heartbeat_interval);
+
+ break;
+ case "MESSAGE_CREATE":
+ self.debug("received message");
+
+ var mentions = [];
+ data.mentions = data.mentions || []; //for some reason this was not defined at some point?
+ var _iteratorNormalCompletion6 = true;
+ var _didIteratorError6 = false;
+ var _iteratorError6 = undefined;
+
+ try {
+ for (var _iterator6 = data.mentions[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
+ var mention = _step6.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError6 = true;
+ _iteratorError6 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion6 && _iterator6["return"]) {
+ _iterator6["return"]();
+ }
+ } finally {
+ if (_didIteratorError6) {
+ throw _iteratorError6;
+ }
+ }
+ }
+
+ var channel = self.getChannel("id", data.channel_id);
+ if (channel) {
+ var msg = channel.addMessage(new Message(data, channel, mentions, self.addUser(data.author)));
+ self.trigger("message", msg);
+ }
+
+ break;
+ case "MESSAGE_DELETE":
+ self.debug("message deleted");
+
+ var channel = self.getChannel("id", data.channel_id);
+ var message = channel.getMessage("id", data.id);
+ if (message) {
+ self.trigger("messageDelete", channel, message);
+ channel.messages.splice(channel.messages.indexOf(message), 1);
+ } else {
+ //don't have the cache of that message ;(
+ self.trigger("messageDelete", channel);
+ }
+ break;
+ case "MESSAGE_UPDATE":
+ self.debug("message updated");
+
+ var channel = self.getChannel("id", data.channel_id);
+ var formerMessage = channel.getMessage("id", data.id);
+
+ if (formerMessage) {
+
+ //new message might be partial, so we need to fill it with whatever the old message was.
+ var info = {};
+
+ for (var key in formerMessage) {
+ info[key] = formerMessage[key];
+ }
+
+ for (var key in data) {
+ info[key] = data[key];
+ }
+
+ var mentions = [];
+ var _iteratorNormalCompletion7 = true;
+ var _didIteratorError7 = false;
+ var _iteratorError7 = undefined;
+
+ try {
+ for (var _iterator7 = info.mentions[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
+ var mention = _step7.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError7 = true;
+ _iteratorError7 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion7 && _iterator7["return"]) {
+ _iterator7["return"]();
+ }
+ } finally {
+ if (_didIteratorError7) {
+ throw _iteratorError7;
+ }
+ }
+ }
+
+ var newMessage = new Message(info, channel, mentions, formerMessage.author);
+
+ self.trigger("messageUpdate", newMessage, formerMessage);
+
+ channel.messages[channel.messages.indexOf(formerMessage)] = newMessage;
+ }
+
+ // message isn't in cache, and if it's a partial it could cause
+ // all hell to break loose... best to just act as if nothing happened
+
+ break;
+
+ case "GUILD_DELETE":
+
+ var server = self.getServer("id", data.id);
+
+ if (server) {
+ self.serverCache.splice(self.serverCache.indexOf(server), 1);
+ self.trigger("serverDelete", server);
+ }
+
+ break;
+
+ case "CHANNEL_DELETE":
+
+ var channel = self.getChannel("id", data.id);
+
+ if (channel) {
+
+ var server = channel.server;
+
+ if (server) {
+
+ server.channels.splice(server.channels.indexOf(channel), 1);
+ }
+
+ self.trigger("channelDelete", channel);
+
+ self.serverCache.splice(self.serverCache.indexOf(channel), 1);
+ }
+
+ break;
+
+ case "GUILD_CREATE":
+
+ var server = self.getServer("id", data.id);
+
+ if (!server) {
+ //if server doesn't already exist because duh
+ server = self.addServer(data);
+ } /*else if(server.channels.length === 0){
+
+ var srv = new Server(data, self);
+ for(channel of data.channels){
+ srv.channels.push(new Channel(channel, data.id));
+ }
+ self.serverCache[self.serverCache.indexOf(server)] = srv;
+
+ }*/
+
+ if (self.serverCreateListener.get(data.id)) {
+ var cbs = self.serverCreateListener.get(data.id);
+ cbs[0](server); //promise then callback
+ cbs[1](null, server); //legacy callback
+ self.serverCreateListener["delete"](data.id);
+ }
+
+ self.trigger("serverCreate", server);
+
+ break;
+
+ case "CHANNEL_CREATE":
+
+ var channel = self.getChannel("id", data.id);
+
+ if (!channel) {
+
+ var chann = self.addChannel(data, data.guild_id);
+ var srv = self.getServer("id", data.guild_id);
+ if (srv) {
+ srv.addChannel(chann);
+ }
+ self.trigger("channelCreate", chann);
+ }
+
+ break;
+
+ case "GUILD_MEMBER_ADD":
+
+ var server = self.getServer("id", data.guild_id);
+
+ if (server) {
+
+ var user = self.addUser(data.user); //if for whatever reason it doesn't exist..
+
+ if (! ~server.members.indexOf(user)) {
+ server.members.push(user);
+ }
+
+ self.trigger("serverNewMember", user);
+ }
+
+ break;
+
+ case "GUILD_MEMBER_REMOVE":
+
+ var server = self.getServer("id", data.guild_id);
+
+ if (server) {
+
+ var user = self.addUser(data.user); //if for whatever reason it doesn't exist..
+
+ if (~server.members.indexOf(user)) {
+ server.members.splice(server.members.indexOf(user), 1);
+ }
+
+ self.trigger("serverRemoveMember", user);
+ }
+
+ break;
+
+ case "USER_UPDATE":
+
+ if (self.user && data.id === self.user.id) {
+
+ var newUser = new User(data); //not actually adding to the cache
+
+ self.trigger("userUpdate", newUser, self.user);
+
+ if (~self.userCache.indexOf(self.user)) {
+ self.userCache[self.userCache.indexOf(self.user)] = newUser;
+ }
+
+ self.user = newUser;
+ }
+
+ break;
+
+ case "PRESENCE_UPDATE":
+
+ var userInCache = self.getUser("id", data.user.id);
+
+ if (userInCache) {
+ //user exists
+ var presenceUser = new User(data.user);
+ if (presenceUser.equalsStrict(userInCache)) {
+ //they're exactly the same, an actual presence update
+ self.trigger("presence", {
+ user: userInCache,
+ status: data.status,
+ server: self.getServer("id", data.guild_id),
+ gameId: data.game_id
+ });
+ } else {
+ //one of their details changed.
+ self.trigger("userUpdate", userInCache, presenceUser);
+ self.userCache[self.userCache.indexOf(userInCache)] = presenceUser;
+ }
+ }
+
+ break;
+
+ default:
+ self.debug("received unknown packet");
+ self.trigger("unknown", dat);
+ break;
+
+ }
+ };
+ }
+
+ //def addUser
+ }, {
+ key: "addUser",
+ value: function addUser(data) {
+ if (!this.getUser("id", data.id)) {
+ this.userCache.push(new User(data));
+ }
+ return this.getUser("id", data.id);
+ }
+
+ //def addChannel
+ }, {
+ key: "addChannel",
+ value: function addChannel(data, serverId) {
+ if (!this.getChannel("id", data.id)) {
+ this.channelCache.push(new Channel(data, this.getServer("id", serverId)));
+ }
+ return this.getChannel("id", data.id);
+ }
+ }, {
+ key: "addPMChannel",
+ value: function addPMChannel(data) {
+ if (!this.getPMChannel("id", data.id)) {
+ this.pmChannelCache.push(new PMChannel(data, this));
+ }
+ return this.getPMChannel("id", data.id);
+ }
+
+ //def addServer
+ }, {
+ key: "addServer",
+ value: function addServer(data) {
+
+ var server = this.getServer("id", data.id);
+
+ if (!server) {
+ server = new Server(data, this);
+ this.serverCache.push(server);
+ if (data.channels) {
+ var _iteratorNormalCompletion8 = true;
+ var _didIteratorError8 = false;
+ var _iteratorError8 = undefined;
+
+ try {
+ for (var _iterator8 = data.channels[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
+ var channel = _step8.value;
+
+ server.channels.push(this.addChannel(channel, server.id));
+ }
+ } catch (err) {
+ _didIteratorError8 = true;
+ _iteratorError8 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion8 && _iterator8["return"]) {
+ _iterator8["return"]();
+ }
+ } finally {
+ if (_didIteratorError8) {
+ throw _iteratorError8;
+ }
+ }
+ }
+ }
+ }
+
+ return server;
+ }
+
+ //def getUser
+ }, {
+ key: "getUser",
+ value: function getUser(key, value) {
+ var _iteratorNormalCompletion9 = true;
+ var _didIteratorError9 = false;
+ var _iteratorError9 = undefined;
+
+ try {
+ for (var _iterator9 = this.userCache[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
+ var user = _step9.value;
+
+ if (user[key] === value) {
+ return user;
+ }
+ }
+ } catch (err) {
+ _didIteratorError9 = true;
+ _iteratorError9 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion9 && _iterator9["return"]) {
+ _iterator9["return"]();
+ }
+ } finally {
+ if (_didIteratorError9) {
+ throw _iteratorError9;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def getChannel
+ }, {
+ key: "getChannel",
+ value: function getChannel(key, value) {
+ var _iteratorNormalCompletion10 = true;
+ var _didIteratorError10 = false;
+ var _iteratorError10 = undefined;
+
+ try {
+ for (var _iterator10 = this.channelCache[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
+ var channel = _step10.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError10 = true;
+ _iteratorError10 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion10 && _iterator10["return"]) {
+ _iterator10["return"]();
+ }
+ } finally {
+ if (_didIteratorError10) {
+ throw _iteratorError10;
+ }
+ }
+ }
+
+ return this.getPMChannel(key, value); //might be a PM
+ }
+ }, {
+ key: "getPMChannel",
+ value: function getPMChannel(key, value) {
+ var _iteratorNormalCompletion11 = true;
+ var _didIteratorError11 = false;
+ var _iteratorError11 = undefined;
+
+ try {
+ for (var _iterator11 = this.pmChannelCache[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
+ var channel = _step11.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError11 = true;
+ _iteratorError11 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion11 && _iterator11["return"]) {
+ _iterator11["return"]();
+ }
+ } finally {
+ if (_didIteratorError11) {
+ throw _iteratorError11;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def getServer
+ }, {
+ key: "getServer",
+ value: function getServer(key, value) {
+ var _iteratorNormalCompletion12 = true;
+ var _didIteratorError12 = false;
+ var _iteratorError12 = undefined;
+
+ try {
+ for (var _iterator12 = this.serverCache[Symbol.iterator](), _step12; !(_iteratorNormalCompletion12 = (_step12 = _iterator12.next()).done); _iteratorNormalCompletion12 = true) {
+ var server = _step12.value;
+
+ if (server[key] === value) {
+ return server;
+ }
+ }
+ } catch (err) {
+ _didIteratorError12 = true;
+ _iteratorError12 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion12 && _iterator12["return"]) {
+ _iterator12["return"]();
+ }
+ } finally {
+ if (_didIteratorError12) {
+ throw _iteratorError12;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def trySendConnData
+ }, {
+ key: "trySendConnData",
+ value: function trySendConnData() {
+
+ if (this.token && !this.alreadySentData) {
+
+ this.alreadySentData = true;
+
+ var data = {
+ op: 2,
+ d: {
+ token: this.token,
+ v: 2,
+ properties: {
+ "$os": "discord.js",
+ "$browser": "discord.js",
+ "$device": "discord.js",
+ "$referrer": "",
+ "$referring_domain": ""
+ }
+ }
+ };
+ this.websocket.send(JSON.stringify(data));
+ }
+ }
+ }, {
+ key: "resolveServerID",
+ value: function resolveServerID(resource) {
+
+ if (resource instanceof Server) {
+ return resource.id;
+ } else if (!isNaN(resource) && resource.length && resource.length === 17) {
+ return resource;
+ }
+ }
+ }, {
+ key: "resolveDestination",
+ value: function resolveDestination(destination) {
+ var channId = false;
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ if (destination instanceof Server) {
+ channId = destination.id; //general is the same as server id
+ } else if (destination instanceof Channel) {
+ channId = destination.id;
+ } else if (destination instanceof Message) {
+ channId = destination.channel.id;
+ } else if (destination instanceof User) {
+
+ //check if we have a PM
+ var _iteratorNormalCompletion13 = true;
+ var _didIteratorError13 = false;
+ var _iteratorError13 = undefined;
+
+ try {
+ for (var _iterator13 = self.pmChannelCache[Symbol.iterator](), _step13; !(_iteratorNormalCompletion13 = (_step13 = _iterator13.next()).done); _iteratorNormalCompletion13 = true) {
+ var pmc = _step13.value;
+
+ if (pmc.user.equals(destination)) {
+ return pmc.id;
+ }
+ }
+
+ //we don't, at this point we're late
+ } catch (err) {
+ _didIteratorError13 = true;
+ _iteratorError13 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion13 && _iterator13["return"]) {
+ _iterator13["return"]();
+ }
+ } finally {
+ if (_didIteratorError13) {
+ throw _iteratorError13;
+ }
+ }
+ }
+
+ self.startPM(destination).then(function (pmc) {
+ resolve(pmc.id);
+ })["catch"](reject);
+ } else {
+ channId = destination;
+ }
+ if (channId) resolve(channId);
+ });
+ }
+ }, {
+ key: "_sendMessage",
+ value: function _sendMessage(destination, content, tts, mentions) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request.post(Endpoints.CHANNELS + "/" + destination + "/messages").set("authorization", self.token).send({
+ content: content,
+ mentions: mentions,
+ tts: tts
+ }).end(function (err, res) {
+
+ if (err) {
+ reject(err);
+ } else {
+ var data = res.body;
+
+ var mentions = [];
+
+ data.mentions = data.mentions || []; //for some reason this was not defined at some point?
+
+ var _iteratorNormalCompletion14 = true;
+ var _didIteratorError14 = false;
+ var _iteratorError14 = undefined;
+
+ try {
+ for (var _iterator14 = data.mentions[Symbol.iterator](), _step14; !(_iteratorNormalCompletion14 = (_step14 = _iterator14.next()).done); _iteratorNormalCompletion14 = true) {
+ var mention = _step14.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError14 = true;
+ _iteratorError14 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion14 && _iterator14["return"]) {
+ _iterator14["return"]();
+ }
+ } finally {
+ if (_didIteratorError14) {
+ throw _iteratorError14;
+ }
+ }
+ }
+
+ var channel = self.getChannel("id", data.channel_id);
+ if (channel) {
+ var msg = channel.addMessage(new Message(data, channel, mentions, self.addUser(data.author)));
+ resolve(msg);
+ }
+ }
+ });
+ });
+ }
+ }, {
+ key: "_sendFile",
+ value: function _sendFile(destination, attachment) {
+ var attachmentName = arguments.length <= 2 || arguments[2] === undefined ? "DEFAULT BECAUSE YOU DIDN'T SPECIFY WHY.png" : arguments[2];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request.post(Endpoints.CHANNELS + "/" + destination + "/messages").set("authorization", self.token).attach("file", attachment, attachmentName).end(function (err, res) {
+
+ if (err) {
+ reject(err);
+ } else {
+
+ var chann = self.getChannel("id", destination);
+ if (chann) {
+ var msg = chann.addMessage(new Message(res.body, chann, [], self.user));
+ resolve(msg);
+ }
+ }
+ });
+ });
+ }
+ }, {
+ key: "_updateMessage",
+ value: function _updateMessage(message, content) {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ request.patch(Endpoints.CHANNELS + "/" + message.channel.id + "/messages/" + message.id).set("authorization", self.token).send({
+ content: content,
+ mentions: []
+ }).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ var msg = new Message(res.body, message.channel, message.mentions, message.sender);
+ resolve(msg);
+ message.channel.messages[message.channel.messages.indexOf(message)] = msg;
+ }
+ });
+ });
+ }
+ }, {
+ key: "_deleteMessage",
+ value: function _deleteMessage(message) {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ request.del(Endpoints.CHANNELS + "/" + message.channel.id + "/messages/" + message.id).set("authorization", self.token).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve();
+ }
+ });
+ });
+ }
+ }, {
+ key: "checkQueue",
+ value: function checkQueue(channelID) {
+ var _this = this;
+
+ var self = this;
+
+ if (!this.checkingQueue[channelID]) {
+ (function () {
+ var doNext = function doNext() {
+ if (self.queue[channelID].length === 0) {
+ done();
+ return;
+ }
+ var queuedEvent = self.queue[channelID][0];
+ switch (queuedEvent.action) {
+ case "sendMessage":
+ var msgToSend = queuedEvent;
+ self._sendMessage(channelID, msgToSend.content, msgToSend.tts, msgToSend.mentions).then(function (msg) {
+ msgToSend.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToSend.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "sendFile":
+ var fileToSend = queuedEvent;
+ self._sendFile(channelID, fileToSend.attachment, fileToSend.attachmentName).then(function (msg) {
+ fileToSend.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ fileToSend.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "updateMessage":
+ var msgToUpd = queuedEvent;
+ self._updateMessage(msgToUpd.message, msgToUpd.content).then(function (msg) {
+ msgToUpd.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToUpd.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "deleteMessage":
+ var msgToDel = queuedEvent;
+ self._deleteMessage(msgToDel.message).then(function (msg) {
+ msgToDel.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToDel.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ default:
+ done();
+ break;
+ }
+ };
+
+ var done = function done() {
+ self.checkingQueue[channelID] = false;
+ return;
+ };
+
+ //if we aren't already checking this queue.
+ _this.checkingQueue[channelID] = true;
+ doNext();
+ })();
+ }
+ }
+ }, {
+ key: "uptime",
+ get: function get() {
+
+ return this.readyTime ? Date.now() - this.readyTime : null;
+ }
+ }, {
+ key: "ready",
+ get: function get() {
+ return this.state === 3;
+ }
+ }, {
+ key: "servers",
+ get: function get() {
+ return this.serverCache;
+ }
+ }, {
+ key: "channels",
+ get: function get() {
+ return this.channelCache;
+ }
+ }, {
+ key: "users",
+ get: function get() {
+ return this.userCache;
+ }
+ }, {
+ key: "PMChannels",
+ get: function get() {
+ return this.pmChannelCache;
+ }
+ }, {
+ key: "messages",
+ get: function get() {
+
+ var msgs = [];
+ var _iteratorNormalCompletion15 = true;
+ var _didIteratorError15 = false;
+ var _iteratorError15 = undefined;
+
+ try {
+ for (var _iterator15 = this.channelCache[Symbol.iterator](), _step15; !(_iteratorNormalCompletion15 = (_step15 = _iterator15.next()).done); _iteratorNormalCompletion15 = true) {
+ var channel = _step15.value;
+
+ msgs = msgs.concat(channel.messages);
+ }
+ } catch (err) {
+ _didIteratorError15 = true;
+ _iteratorError15 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion15 && _iterator15["return"]) {
+ _iterator15["return"]();
+ }
+ } finally {
+ if (_didIteratorError15) {
+ throw _iteratorError15;
+ }
+ }
+ }
+
+ return msgs;
+ }
+ }]);
+
+ return Client;
+})();
+
+function getGateway() {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request.get(Endpoints.API + "/gateway").end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(res.body.url);
+ }
+ });
+ });
+}
+
+module.exports = Client;
+},{"./Endpoints.js":2,"./PMChannel.js":3,"./channel.js":4,"./invite.js":6,"./message.js":7,"./server.js":8,"./user.js":9,"fs":10,"superagent":11,"ws":14}],2:[function(require,module,exports){
+"use strict";
+
+exports.BASE_DOMAIN = "discordapp.com";
+exports.BASE = "https://" + exports.BASE_DOMAIN;
+exports.WEBSOCKET_HUB = "wss://" + exports.BASE_DOMAIN + "/hub";
+
+exports.API = exports.BASE + "/api";
+exports.AUTH = exports.API + "/auth";
+exports.LOGIN = exports.AUTH + "/login";
+exports.LOGOUT = exports.AUTH + "/logout";
+exports.USERS = exports.API + "/users";
+exports.SERVERS = exports.API + "/guilds";
+exports.CHANNELS = exports.API + "/channels";
+},{}],3:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var PMChannel = (function () {
+ function PMChannel(data, client) {
+ _classCallCheck(this, PMChannel);
+
+ this.user = client.getUser("id", data.recipient.id);
+ this.id = data.id;
+ this.messages = [];
+ }
+
+ _createClass(PMChannel, [{
+ key: "addMessage",
+ value: function addMessage(data) {
+ if (!this.getMessage("id", data.id)) {
+ this.messages.push(data);
+ }
+ return this.getMessage("id", data.id);
+ }
+ }, {
+ key: "getMessage",
+ value: function getMessage(key, value) {
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.messages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var message = _step.value;
+
+ if (message[key] === value) {
+ return message;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return true;
+ }
+ }]);
+
+ return PMChannel;
+})();
+
+module.exports = PMChannel;
+},{}],4:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Channel = (function () {
+ function Channel(data, server) {
+ _classCallCheck(this, Channel);
+
+ this.server = server;
+ this.name = data.name;
+ this.type = data.type;
+ this.id = data.id;
+ this.messages = [];
+ //this.isPrivate = isPrivate; //not sure about the implementation of this...
+ }
+
+ _createClass(Channel, [{
+ key: "equals",
+ value: function equals(object) {
+ return object && object.id === this.id;
+ }
+ }, {
+ key: "addMessage",
+ value: function addMessage(data) {
+ if (!this.getMessage("id", data.id)) {
+ this.messages.push(data);
+ }
+ return this.getMessage("id", data.id);
+ }
+ }, {
+ key: "getMessage",
+ value: function getMessage(key, value) {
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.messages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var message = _step.value;
+
+ if (message[key] === value) {
+ return message;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ return "#" + this.name;
+ }
+ }, {
+ key: "client",
+ get: function get() {
+ return this.server.client;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return false;
+ }
+ }]);
+
+ return Channel;
+})();
+
+module.exports = Channel;
+},{}],5:[function(require,module,exports){
+"use strict";
+
+var request = require("superagent");
+var Endpoints = require("./Endpoints.js");
+var Client = require("./Client.js");
+
+var Discord = {
+ Endpoints: Endpoints,
+ Client: Client
+};
+
+module.exports = Discord;
+},{"./Client.js":1,"./Endpoints.js":2,"superagent":11}],6:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Invite = (function () {
+ function Invite(data, client) {
+ _classCallCheck(this, Invite);
+
+ this.max_age = data.max_age;
+ this.code = data.code;
+ this.server = client.getServer("id", data.guild.id);
+ this.revoked = data.revoked;
+ this.created_at = Date.parse(data.created_at);
+ this.temporary = data.temporary;
+ this.uses = data.uses;
+ this.max_uses = data.uses;
+ this.inviter = client.addUser(data.inviter);
+ this.xkcd = data.xkcdpass;
+ this.channel = client.getChannel("id", data.channel.id);
+ }
+
+ _createClass(Invite, [{
+ key: "URL",
+ get: function get() {
+ var code = this.xkcd ? this.xkcdpass : this.code;
+ return "https://discord.gg/" + code;
+ }
+ }]);
+
+ return Invite;
+})();
+
+module.exports = Invite;
+},{}],7:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var PMChannel = require("./PMChannel.js");
+
+var Message = (function () {
+ function Message(data, channel, mentions, author) {
+ _classCallCheck(this, Message);
+
+ this.tts = data.tts;
+ this.timestamp = Date.parse(data.timestamp);
+ this.nonce = data.nonce;
+ this.mentions = mentions;
+ this.everyoneMentioned = data.mention_everyone;
+ this.id = data.id;
+ this.embeds = data.embeds;
+ this.editedTimestamp = data.edited_timestamp;
+ this.content = data.content.trim();
+ this.channel = channel;
+ this.author = author;
+ this.attachments = data.attachments;
+ }
+
+ /*exports.Message.prototype.isPM = function() {
+ return ( this.channel instanceof PMChannel );
+ }*/
+
+ _createClass(Message, [{
+ key: "isMentioned",
+ value: function isMentioned(user) {
+ var id = user.id ? user.id : user;
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.mentions[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var mention = _step.value;
+
+ if (mention.id === id) {
+ return true;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return false;
+ }
+ }, {
+ key: "sender",
+ get: function get() {
+ return this.author;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return this.channel.isPrivate;
+ }
+ }]);
+
+ return Message;
+})();
+
+module.exports = Message;
+},{"./PMChannel.js":3}],8:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Server = (function () {
+ function Server(data, client) {
+ _classCallCheck(this, Server);
+
+ this.client = client;
+ this.region = data.region;
+ this.ownerID = data.owner_id;
+ this.name = data.name;
+ this.id = data.id;
+ this.members = [];
+ this.channels = [];
+ this.icon = data.icon;
+ this.afkTimeout = data.afk_timeout;
+ this.afkChannelId = data.afk_channel_id;
+
+ if (!data.members) {
+ data.members = [client.user];
+ return;
+ }
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = data.members[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var member = _step.value;
+
+ // first we cache the user in our Discord Client,
+ // then we add it to our list. This way when we
+ // get a user from this server's member list,
+ // it will be identical (unless an async change occurred)
+ // to the client's cache.
+ if (member.user) this.members.push(client.addUser(member.user));
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+ }
+
+ _createClass(Server, [{
+ key: "getChannel",
+
+ // get/set
+ value: function getChannel(key, value) {
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = this.channels[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var channel = _step2.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2["return"]) {
+ _iterator2["return"]();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "getMember",
+ value: function getMember(key, value) {
+ var _iteratorNormalCompletion3 = true;
+ var _didIteratorError3 = false;
+ var _iteratorError3 = undefined;
+
+ try {
+ for (var _iterator3 = this.members[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var member = _step3.value;
+
+ if (member[key] === value) {
+ return member;
+ }
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3["return"]) {
+ _iterator3["return"]();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "addChannel",
+ value: function addChannel(chann) {
+ if (!this.getChannel("id", chann.id)) {
+ this.channels.push(chann);
+ }
+ return chann;
+ }
+ }, {
+ key: "addMember",
+ value: function addMember(member) {
+ if (!this.getMember("id", member.id)) {
+ this.members.push(member);
+ }
+ return member;
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ return this.name;
+ }
+ }, {
+ key: "iconURL",
+ get: function get() {
+ if (!this.icon) return null;
+ return "https://discordapp.com/api/guilds/" + this.id + "/icons/" + this.icon + ".jpg";
+ }
+ }, {
+ key: "afkChannel",
+ get: function get() {
+ if (!this.afkChannelId) return false;
+
+ return this.getChannel("id", this.afkChannelId);
+ }
+ }, {
+ key: "defaultChannel",
+ get: function get() {
+ return this.getChannel("name", "general");
+ }
+ }, {
+ key: "owner",
+ get: function get() {
+ return this.client.getUser("id", this.ownerID);
+ }
+ }]);
+
+ return Server;
+})();
+
+module.exports = Server;
+},{}],9:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var User = (function () {
+ function User(data) {
+ _classCallCheck(this, User);
+
+ this.username = data.username;
+ this.discriminator = data.discriminator;
+ this.id = data.id;
+ this.avatar = data.avatar;
+ }
+
+ // access using user.avatarURL;
+
+ _createClass(User, [{
+ key: "mention",
+ value: function mention() {
+ return "<@" + this.id + ">";
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ /*
+ if we embed a user in a String - like so:
+ "Yo " + user + " what's up?"
+ It would generate something along the lines of:
+ "Yo @hydrabolt what's up?"
+ */
+ return this.mention();
+ }
+ }, {
+ key: "equals",
+ value: function equals(object) {
+ return object.id === this.id;
+ }
+ }, {
+ key: "equalsStrict",
+ value: function equalsStrict(object) {
+ return object.id === this.id && object.avatar === this.avatar && object.username === this.username && object.discriminator === this.discriminator;
+ }
+ }, {
+ key: "avatarURL",
+ get: function get() {
+ if (!this.avatar) return null;
+ return "https://discordapp.com/api/users/" + this.id + "/avatars/" + this.avatar + ".jpg";
+ }
+ }]);
+
+ return User;
+})();
+
+module.exports = User;
+},{}],10:[function(require,module,exports){
+
+},{}],11:[function(require,module,exports){
+/**
+ * Module dependencies.
+ */
+
+var Emitter = require('emitter');
+var reduce = require('reduce');
+
+/**
+ * Root reference for iframes.
+ */
+
+var root = 'undefined' == typeof window
+ ? (this || self)
+ : window;
+
+/**
+ * Noop.
+ */
+
+function noop(){};
+
+/**
+ * Check if `obj` is a host object,
+ * we don't want to serialize these :)
+ *
+ * TODO: future proof, move to compoent land
+ *
+ * @param {Object} obj
+ * @return {Boolean}
+ * @api private
+ */
+
+function isHost(obj) {
+ var str = {}.toString.call(obj);
+
+ switch (str) {
+ case '[object File]':
+ case '[object Blob]':
+ case '[object FormData]':
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Determine XHR.
+ */
+
+request.getXHR = function () {
+ if (root.XMLHttpRequest
+ && (!root.location || 'file:' != root.location.protocol
+ || !root.ActiveXObject)) {
+ return new XMLHttpRequest;
+ } else {
+ try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {}
+ }
+ return false;
+};
+
+/**
+ * Removes leading and trailing whitespace, added to support IE.
+ *
+ * @param {String} s
+ * @return {String}
+ * @api private
+ */
+
+var trim = ''.trim
+ ? function(s) { return s.trim(); }
+ : function(s) { return s.replace(/(^\s*|\s*$)/g, ''); };
+
+/**
+ * Check if `obj` is an object.
+ *
+ * @param {Object} obj
+ * @return {Boolean}
+ * @api private
+ */
+
+function isObject(obj) {
+ return obj === Object(obj);
+}
+
+/**
+ * Serialize the given `obj`.
+ *
+ * @param {Object} obj
+ * @return {String}
+ * @api private
+ */
+
+function serialize(obj) {
+ if (!isObject(obj)) return obj;
+ var pairs = [];
+ for (var key in obj) {
+ if (null != obj[key]) {
+ pairs.push(encodeURIComponent(key)
+ + '=' + encodeURIComponent(obj[key]));
+ }
+ }
+ return pairs.join('&');
+}
+
+/**
+ * Expose serialization method.
+ */
+
+ request.serializeObject = serialize;
+
+ /**
+ * Parse the given x-www-form-urlencoded `str`.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+function parseString(str) {
+ var obj = {};
+ var pairs = str.split('&');
+ var parts;
+ var pair;
+
+ for (var i = 0, len = pairs.length; i < len; ++i) {
+ pair = pairs[i];
+ parts = pair.split('=');
+ obj[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
+ }
+
+ return obj;
+}
+
+/**
+ * Expose parser.
+ */
+
+request.parseString = parseString;
+
+/**
+ * Default MIME type map.
+ *
+ * superagent.types.xml = 'application/xml';
+ *
+ */
+
+request.types = {
+ html: 'text/html',
+ json: 'application/json',
+ xml: 'application/xml',
+ urlencoded: 'application/x-www-form-urlencoded',
+ 'form': 'application/x-www-form-urlencoded',
+ 'form-data': 'application/x-www-form-urlencoded'
+};
+
+/**
+ * Default serialization map.
+ *
+ * superagent.serialize['application/xml'] = function(obj){
+ * return 'generated xml here';
+ * };
+ *
+ */
+
+ request.serialize = {
+ 'application/x-www-form-urlencoded': serialize,
+ 'application/json': JSON.stringify
+ };
+
+ /**
+ * Default parsers.
+ *
+ * superagent.parse['application/xml'] = function(str){
+ * return { object parsed from str };
+ * };
+ *
+ */
+
+request.parse = {
+ 'application/x-www-form-urlencoded': parseString,
+ 'application/json': JSON.parse
+};
+
+/**
+ * Parse the given header `str` into
+ * an object containing the mapped fields.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+function parseHeader(str) {
+ var lines = str.split(/\r?\n/);
+ var fields = {};
+ var index;
+ var line;
+ var field;
+ var val;
+
+ lines.pop(); // trailing CRLF
+
+ for (var i = 0, len = lines.length; i < len; ++i) {
+ line = lines[i];
+ index = line.indexOf(':');
+ field = line.slice(0, index).toLowerCase();
+ val = trim(line.slice(index + 1));
+ fields[field] = val;
+ }
+
+ return fields;
+}
+
+/**
+ * Return the mime type for the given `str`.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+function type(str){
+ return str.split(/ *; */).shift();
+};
+
+/**
+ * Return header field parameters.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+function params(str){
+ return reduce(str.split(/ *; */), function(obj, str){
+ var parts = str.split(/ *= */)
+ , key = parts.shift()
+ , val = parts.shift();
+
+ if (key && val) obj[key] = val;
+ return obj;
+ }, {});
+};
+
+/**
+ * Initialize a new `Response` with the given `xhr`.
+ *
+ * - set flags (.ok, .error, etc)
+ * - parse header
+ *
+ * Examples:
+ *
+ * Aliasing `superagent` as `request` is nice:
+ *
+ * request = superagent;
+ *
+ * We can use the promise-like API, or pass callbacks:
+ *
+ * request.get('/').end(function(res){});
+ * request.get('/', function(res){});
+ *
+ * Sending data can be chained:
+ *
+ * request
+ * .post('/user')
+ * .send({ name: 'tj' })
+ * .end(function(res){});
+ *
+ * Or passed to `.send()`:
+ *
+ * request
+ * .post('/user')
+ * .send({ name: 'tj' }, function(res){});
+ *
+ * Or passed to `.post()`:
+ *
+ * request
+ * .post('/user', { name: 'tj' })
+ * .end(function(res){});
+ *
+ * Or further reduced to a single call for simple cases:
+ *
+ * request
+ * .post('/user', { name: 'tj' }, function(res){});
+ *
+ * @param {XMLHTTPRequest} xhr
+ * @param {Object} options
+ * @api private
+ */
+
+function Response(req, options) {
+ options = options || {};
+ this.req = req;
+ this.xhr = this.req.xhr;
+ // responseText is accessible only if responseType is '' or 'text' and on older browsers
+ this.text = ((this.req.method !='HEAD' && (this.xhr.responseType === '' || this.xhr.responseType === 'text')) || typeof this.xhr.responseType === 'undefined')
+ ? this.xhr.responseText
+ : null;
+ this.statusText = this.req.xhr.statusText;
+ this.setStatusProperties(this.xhr.status);
+ this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders());
+ // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but
+ // getResponseHeader still works. so we get content-type even if getting
+ // other headers fails.
+ this.header['content-type'] = this.xhr.getResponseHeader('content-type');
+ this.setHeaderProperties(this.header);
+ this.body = this.req.method != 'HEAD'
+ ? this.parseBody(this.text ? this.text : this.xhr.response)
+ : null;
+}
+
+/**
+ * Get case-insensitive `field` value.
+ *
+ * @param {String} field
+ * @return {String}
+ * @api public
+ */
+
+Response.prototype.get = function(field){
+ return this.header[field.toLowerCase()];
+};
+
+/**
+ * Set header related properties:
+ *
+ * - `.type` the content type without params
+ *
+ * A response of "Content-Type: text/plain; charset=utf-8"
+ * will provide you with a `.type` of "text/plain".
+ *
+ * @param {Object} header
+ * @api private
+ */
+
+Response.prototype.setHeaderProperties = function(header){
+ // content-type
+ var ct = this.header['content-type'] || '';
+ this.type = type(ct);
+
+ // params
+ var obj = params(ct);
+ for (var key in obj) this[key] = obj[key];
+};
+
+/**
+ * Parse the given body `str`.
+ *
+ * Used for auto-parsing of bodies. Parsers
+ * are defined on the `superagent.parse` object.
+ *
+ * @param {String} str
+ * @return {Mixed}
+ * @api private
+ */
+
+Response.prototype.parseBody = function(str){
+ var parse = request.parse[this.type];
+ return parse && str && (str.length || str instanceof Object)
+ ? parse(str)
+ : null;
+};
+
+/**
+ * Set flags such as `.ok` based on `status`.
+ *
+ * For example a 2xx response will give you a `.ok` of __true__
+ * whereas 5xx will be __false__ and `.error` will be __true__. The
+ * `.clientError` and `.serverError` are also available to be more
+ * specific, and `.statusType` is the class of error ranging from 1..5
+ * sometimes useful for mapping respond colors etc.
+ *
+ * "sugar" properties are also defined for common cases. Currently providing:
+ *
+ * - .noContent
+ * - .badRequest
+ * - .unauthorized
+ * - .notAcceptable
+ * - .notFound
+ *
+ * @param {Number} status
+ * @api private
+ */
+
+Response.prototype.setStatusProperties = function(status){
+ // handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request
+ if (status === 1223) {
+ status = 204;
+ }
+
+ var type = status / 100 | 0;
+
+ // status / class
+ this.status = status;
+ this.statusType = type;
+
+ // basics
+ this.info = 1 == type;
+ this.ok = 2 == type;
+ this.clientError = 4 == type;
+ this.serverError = 5 == type;
+ this.error = (4 == type || 5 == type)
+ ? this.toError()
+ : false;
+
+ // sugar
+ this.accepted = 202 == status;
+ this.noContent = 204 == status;
+ this.badRequest = 400 == status;
+ this.unauthorized = 401 == status;
+ this.notAcceptable = 406 == status;
+ this.notFound = 404 == status;
+ this.forbidden = 403 == status;
+};
+
+/**
+ * Return an `Error` representative of this response.
+ *
+ * @return {Error}
+ * @api public
+ */
+
+Response.prototype.toError = function(){
+ var req = this.req;
+ var method = req.method;
+ var url = req.url;
+
+ var msg = 'cannot ' + method + ' ' + url + ' (' + this.status + ')';
+ var err = new Error(msg);
+ err.status = this.status;
+ err.method = method;
+ err.url = url;
+
+ return err;
+};
+
+/**
+ * Expose `Response`.
+ */
+
+request.Response = Response;
+
+/**
+ * Initialize a new `Request` with the given `method` and `url`.
+ *
+ * @param {String} method
+ * @param {String} url
+ * @api public
+ */
+
+function Request(method, url) {
+ var self = this;
+ Emitter.call(this);
+ this._query = this._query || [];
+ this.method = method;
+ this.url = url;
+ this.header = {};
+ this._header = {};
+ this.on('end', function(){
+ var err = null;
+ var res = null;
+
+ try {
+ res = new Response(self);
+ } catch(e) {
+ err = new Error('Parser is unable to parse the response');
+ err.parse = true;
+ err.original = e;
+ return self.callback(err);
+ }
+
+ self.emit('response', res);
+
+ if (err) {
+ return self.callback(err, res);
+ }
+
+ if (res.status >= 200 && res.status < 300) {
+ return self.callback(err, res);
+ }
+
+ var new_err = new Error(res.statusText || 'Unsuccessful HTTP response');
+ new_err.original = err;
+ new_err.response = res;
+ new_err.status = res.status;
+
+ self.callback(new_err, res);
+ });
+}
+
+/**
+ * Mixin `Emitter`.
+ */
+
+Emitter(Request.prototype);
+
+/**
+ * Allow for extension
+ */
+
+Request.prototype.use = function(fn) {
+ fn(this);
+ return this;
+}
+
+/**
+ * Set timeout to `ms`.
+ *
+ * @param {Number} ms
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.timeout = function(ms){
+ this._timeout = ms;
+ return this;
+};
+
+/**
+ * Clear previous timeout.
+ *
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.clearTimeout = function(){
+ this._timeout = 0;
+ clearTimeout(this._timer);
+ return this;
+};
+
+/**
+ * Abort the request, and clear potential timeout.
+ *
+ * @return {Request}
+ * @api public
+ */
+
+Request.prototype.abort = function(){
+ if (this.aborted) return;
+ this.aborted = true;
+ this.xhr.abort();
+ this.clearTimeout();
+ this.emit('abort');
+ return this;
+};
+
+/**
+ * Set header `field` to `val`, or multiple fields with one object.
+ *
+ * Examples:
+ *
+ * req.get('/')
+ * .set('Accept', 'application/json')
+ * .set('X-API-Key', 'foobar')
+ * .end(callback);
+ *
+ * req.get('/')
+ * .set({ Accept: 'application/json', 'X-API-Key': 'foobar' })
+ * .end(callback);
+ *
+ * @param {String|Object} field
+ * @param {String} val
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.set = function(field, val){
+ if (isObject(field)) {
+ for (var key in field) {
+ this.set(key, field[key]);
+ }
+ return this;
+ }
+ this._header[field.toLowerCase()] = val;
+ this.header[field] = val;
+ return this;
+};
+
+/**
+ * Remove header `field`.
+ *
+ * Example:
+ *
+ * req.get('/')
+ * .unset('User-Agent')
+ * .end(callback);
+ *
+ * @param {String} field
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.unset = function(field){
+ delete this._header[field.toLowerCase()];
+ delete this.header[field];
+ return this;
+};
+
+/**
+ * Get case-insensitive header `field` value.
+ *
+ * @param {String} field
+ * @return {String}
+ * @api private
+ */
+
+Request.prototype.getHeader = function(field){
+ return this._header[field.toLowerCase()];
+};
+
+/**
+ * Set Content-Type to `type`, mapping values from `request.types`.
+ *
+ * Examples:
+ *
+ * superagent.types.xml = 'application/xml';
+ *
+ * request.post('/')
+ * .type('xml')
+ * .send(xmlstring)
+ * .end(callback);
+ *
+ * request.post('/')
+ * .type('application/xml')
+ * .send(xmlstring)
+ * .end(callback);
+ *
+ * @param {String} type
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.type = function(type){
+ this.set('Content-Type', request.types[type] || type);
+ return this;
+};
+
+/**
+ * Set Accept to `type`, mapping values from `request.types`.
+ *
+ * Examples:
+ *
+ * superagent.types.json = 'application/json';
+ *
+ * request.get('/agent')
+ * .accept('json')
+ * .end(callback);
+ *
+ * request.get('/agent')
+ * .accept('application/json')
+ * .end(callback);
+ *
+ * @param {String} accept
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.accept = function(type){
+ this.set('Accept', request.types[type] || type);
+ return this;
+};
+
+/**
+ * Set Authorization field value with `user` and `pass`.
+ *
+ * @param {String} user
+ * @param {String} pass
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.auth = function(user, pass){
+ var str = btoa(user + ':' + pass);
+ this.set('Authorization', 'Basic ' + str);
+ return this;
+};
+
+/**
+* Add query-string `val`.
+*
+* Examples:
+*
+* request.get('/shoes')
+* .query('size=10')
+* .query({ color: 'blue' })
+*
+* @param {Object|String} val
+* @return {Request} for chaining
+* @api public
+*/
+
+Request.prototype.query = function(val){
+ if ('string' != typeof val) val = serialize(val);
+ if (val) this._query.push(val);
+ return this;
+};
+
+/**
+ * Write the field `name` and `val` for "multipart/form-data"
+ * request bodies.
+ *
+ * ``` js
+ * request.post('/upload')
+ * .field('foo', 'bar')
+ * .end(callback);
+ * ```
+ *
+ * @param {String} name
+ * @param {String|Blob|File} val
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.field = function(name, val){
+ if (!this._formData) this._formData = new root.FormData();
+ this._formData.append(name, val);
+ return this;
+};
+
+/**
+ * Queue the given `file` as an attachment to the specified `field`,
+ * with optional `filename`.
+ *
+ * ``` js
+ * request.post('/upload')
+ * .attach(new Blob(['hey! '], { type: "text/html"}))
+ * .end(callback);
+ * ```
+ *
+ * @param {String} field
+ * @param {Blob|File} file
+ * @param {String} filename
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.attach = function(field, file, filename){
+ if (!this._formData) this._formData = new root.FormData();
+ this._formData.append(field, file, filename);
+ return this;
+};
+
+/**
+ * Send `data`, defaulting the `.type()` to "json" when
+ * an object is given.
+ *
+ * Examples:
+ *
+ * // querystring
+ * request.get('/search')
+ * .end(callback)
+ *
+ * // multiple data "writes"
+ * request.get('/search')
+ * .send({ search: 'query' })
+ * .send({ range: '1..5' })
+ * .send({ order: 'desc' })
+ * .end(callback)
+ *
+ * // manual json
+ * request.post('/user')
+ * .type('json')
+ * .send('{"name":"tj"})
+ * .end(callback)
+ *
+ * // auto json
+ * request.post('/user')
+ * .send({ name: 'tj' })
+ * .end(callback)
+ *
+ * // manual x-www-form-urlencoded
+ * request.post('/user')
+ * .type('form')
+ * .send('name=tj')
+ * .end(callback)
+ *
+ * // auto x-www-form-urlencoded
+ * request.post('/user')
+ * .type('form')
+ * .send({ name: 'tj' })
+ * .end(callback)
+ *
+ * // defaults to x-www-form-urlencoded
+ * request.post('/user')
+ * .send('name=tobi')
+ * .send('species=ferret')
+ * .end(callback)
+ *
+ * @param {String|Object} data
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.send = function(data){
+ var obj = isObject(data);
+ var type = this.getHeader('Content-Type');
+
+ // merge
+ if (obj && isObject(this._data)) {
+ for (var key in data) {
+ this._data[key] = data[key];
+ }
+ } else if ('string' == typeof data) {
+ if (!type) this.type('form');
+ type = this.getHeader('Content-Type');
+ if ('application/x-www-form-urlencoded' == type) {
+ this._data = this._data
+ ? this._data + '&' + data
+ : data;
+ } else {
+ this._data = (this._data || '') + data;
+ }
+ } else {
+ this._data = data;
+ }
+
+ if (!obj || isHost(data)) return this;
+ if (!type) this.type('json');
+ return this;
+};
+
+/**
+ * Invoke the callback with `err` and `res`
+ * and handle arity check.
+ *
+ * @param {Error} err
+ * @param {Response} res
+ * @api private
+ */
+
+Request.prototype.callback = function(err, res){
+ var fn = this._callback;
+ this.clearTimeout();
+ fn(err, res);
+};
+
+/**
+ * Invoke callback with x-domain error.
+ *
+ * @api private
+ */
+
+Request.prototype.crossDomainError = function(){
+ var err = new Error('Origin is not allowed by Access-Control-Allow-Origin');
+ err.crossDomain = true;
+ this.callback(err);
+};
+
+/**
+ * Invoke callback with timeout error.
+ *
+ * @api private
+ */
+
+Request.prototype.timeoutError = function(){
+ var timeout = this._timeout;
+ var err = new Error('timeout of ' + timeout + 'ms exceeded');
+ err.timeout = timeout;
+ this.callback(err);
+};
+
+/**
+ * Enable transmission of cookies with x-domain requests.
+ *
+ * Note that for this to work the origin must not be
+ * using "Access-Control-Allow-Origin" with a wildcard,
+ * and also must set "Access-Control-Allow-Credentials"
+ * to "true".
+ *
+ * @api public
+ */
+
+Request.prototype.withCredentials = function(){
+ this._withCredentials = true;
+ return this;
+};
+
+/**
+ * Initiate request, invoking callback `fn(res)`
+ * with an instanceof `Response`.
+ *
+ * @param {Function} fn
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.end = function(fn){
+ var self = this;
+ var xhr = this.xhr = request.getXHR();
+ var query = this._query.join('&');
+ var timeout = this._timeout;
+ var data = this._formData || this._data;
+
+ // store callback
+ this._callback = fn || noop;
+
+ // state change
+ xhr.onreadystatechange = function(){
+ if (4 != xhr.readyState) return;
+
+ // In IE9, reads to any property (e.g. status) off of an aborted XHR will
+ // result in the error "Could not complete the operation due to error c00c023f"
+ var status;
+ try { status = xhr.status } catch(e) { status = 0; }
+
+ if (0 == status) {
+ if (self.timedout) return self.timeoutError();
+ if (self.aborted) return;
+ return self.crossDomainError();
+ }
+ self.emit('end');
+ };
+
+ // progress
+ var handleProgress = function(e){
+ if (e.total > 0) {
+ e.percent = e.loaded / e.total * 100;
+ }
+ self.emit('progress', e);
+ };
+ if (this.hasListeners('progress')) {
+ xhr.onprogress = handleProgress;
+ }
+ try {
+ if (xhr.upload && this.hasListeners('progress')) {
+ xhr.upload.onprogress = handleProgress;
+ }
+ } catch(e) {
+ // Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist.
+ // Reported here:
+ // https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web-worker-context
+ }
+
+ // timeout
+ if (timeout && !this._timer) {
+ this._timer = setTimeout(function(){
+ self.timedout = true;
+ self.abort();
+ }, timeout);
+ }
+
+ // querystring
+ if (query) {
+ query = request.serializeObject(query);
+ this.url += ~this.url.indexOf('?')
+ ? '&' + query
+ : '?' + query;
+ }
+
+ // initiate request
+ xhr.open(this.method, this.url, true);
+
+ // CORS
+ if (this._withCredentials) xhr.withCredentials = true;
+
+ // body
+ if ('GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !isHost(data)) {
+ // serialize stuff
+ var contentType = this.getHeader('Content-Type');
+ var serialize = request.serialize[contentType ? contentType.split(';')[0] : ''];
+ if (serialize) data = serialize(data);
+ }
+
+ // set header fields
+ for (var field in this.header) {
+ if (null == this.header[field]) continue;
+ xhr.setRequestHeader(field, this.header[field]);
+ }
+
+ // send stuff
+ this.emit('request', this);
+ xhr.send(data);
+ return this;
+};
+
+/**
+ * Faux promise support
+ *
+ * @param {Function} fulfill
+ * @param {Function} reject
+ * @return {Request}
+ */
+
+Request.prototype.then = function (fulfill, reject) {
+ return this.end(function(err, res) {
+ err ? reject(err) : fulfill(res);
+ });
+}
+
+/**
+ * Expose `Request`.
+ */
+
+request.Request = Request;
+
+/**
+ * Issue a request:
+ *
+ * Examples:
+ *
+ * request('GET', '/users').end(callback)
+ * request('/users').end(callback)
+ * request('/users', callback)
+ *
+ * @param {String} method
+ * @param {String|Function} url or callback
+ * @return {Request}
+ * @api public
+ */
+
+function request(method, url) {
+ // callback
+ if ('function' == typeof url) {
+ return new Request('GET', method).end(url);
+ }
+
+ // url first
+ if (1 == arguments.length) {
+ return new Request('GET', method);
+ }
+
+ return new Request(method, url);
+}
+
+/**
+ * GET `url` with optional callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed|Function} data or fn
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.get = function(url, data, fn){
+ var req = request('GET', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.query(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * HEAD `url` with optional callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed|Function} data or fn
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.head = function(url, data, fn){
+ var req = request('HEAD', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * DELETE `url` with optional callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.del = function(url, fn){
+ var req = request('DELETE', url);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * PATCH `url` with optional `data` and callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed} data
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.patch = function(url, data, fn){
+ var req = request('PATCH', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * POST `url` with optional `data` and callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed} data
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.post = function(url, data, fn){
+ var req = request('POST', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * PUT `url` with optional `data` and callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed|Function} data or fn
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.put = function(url, data, fn){
+ var req = request('PUT', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * Expose `request`.
+ */
+
+module.exports = request;
+
+},{"emitter":12,"reduce":13}],12:[function(require,module,exports){
+
+/**
+ * Expose `Emitter`.
+ */
+
+module.exports = Emitter;
+
+/**
+ * Initialize a new `Emitter`.
+ *
+ * @api public
+ */
+
+function Emitter(obj) {
+ if (obj) return mixin(obj);
+};
+
+/**
+ * Mixin the emitter properties.
+ *
+ * @param {Object} obj
+ * @return {Object}
+ * @api private
+ */
+
+function mixin(obj) {
+ for (var key in Emitter.prototype) {
+ obj[key] = Emitter.prototype[key];
+ }
+ return obj;
+}
+
+/**
+ * Listen on the given `event` with `fn`.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ * @return {Emitter}
+ * @api public
+ */
+
+Emitter.prototype.on =
+Emitter.prototype.addEventListener = function(event, fn){
+ this._callbacks = this._callbacks || {};
+ (this._callbacks[event] = this._callbacks[event] || [])
+ .push(fn);
+ return this;
+};
+
+/**
+ * Adds an `event` listener that will be invoked a single
+ * time then automatically removed.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ * @return {Emitter}
+ * @api public
+ */
+
+Emitter.prototype.once = function(event, fn){
+ var self = this;
+ this._callbacks = this._callbacks || {};
+
+ function on() {
+ self.off(event, on);
+ fn.apply(this, arguments);
+ }
+
+ on.fn = fn;
+ this.on(event, on);
+ return this;
+};
+
+/**
+ * Remove the given callback for `event` or all
+ * registered callbacks.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ * @return {Emitter}
+ * @api public
+ */
+
+Emitter.prototype.off =
+Emitter.prototype.removeListener =
+Emitter.prototype.removeAllListeners =
+Emitter.prototype.removeEventListener = function(event, fn){
+ this._callbacks = this._callbacks || {};
+
+ // all
+ if (0 == arguments.length) {
+ this._callbacks = {};
+ return this;
+ }
+
+ // specific event
+ var callbacks = this._callbacks[event];
+ if (!callbacks) return this;
+
+ // remove all handlers
+ if (1 == arguments.length) {
+ delete this._callbacks[event];
+ return this;
+ }
+
+ // remove specific handler
+ var cb;
+ for (var i = 0; i < callbacks.length; i++) {
+ cb = callbacks[i];
+ if (cb === fn || cb.fn === fn) {
+ callbacks.splice(i, 1);
+ break;
+ }
+ }
+ return this;
+};
+
+/**
+ * Emit `event` with the given args.
+ *
+ * @param {String} event
+ * @param {Mixed} ...
+ * @return {Emitter}
+ */
+
+Emitter.prototype.emit = function(event){
+ this._callbacks = this._callbacks || {};
+ var args = [].slice.call(arguments, 1)
+ , callbacks = this._callbacks[event];
+
+ if (callbacks) {
+ callbacks = callbacks.slice(0);
+ for (var i = 0, len = callbacks.length; i < len; ++i) {
+ callbacks[i].apply(this, args);
+ }
+ }
+
+ return this;
+};
+
+/**
+ * Return array of callbacks for `event`.
+ *
+ * @param {String} event
+ * @return {Array}
+ * @api public
+ */
+
+Emitter.prototype.listeners = function(event){
+ this._callbacks = this._callbacks || {};
+ return this._callbacks[event] || [];
+};
+
+/**
+ * Check if this emitter has `event` handlers.
+ *
+ * @param {String} event
+ * @return {Boolean}
+ * @api public
+ */
+
+Emitter.prototype.hasListeners = function(event){
+ return !! this.listeners(event).length;
+};
+
+},{}],13:[function(require,module,exports){
+
+/**
+ * Reduce `arr` with `fn`.
+ *
+ * @param {Array} arr
+ * @param {Function} fn
+ * @param {Mixed} initial
+ *
+ * TODO: combatible error handling?
+ */
+
+module.exports = function(arr, fn, initial){
+ var idx = 0;
+ var len = arr.length;
+ var curr = arguments.length == 3
+ ? initial
+ : arr[idx++];
+
+ while (idx < len) {
+ curr = fn.call(null, curr, arr[idx], ++idx, arr);
+ }
+
+ return curr;
+};
+},{}],14:[function(require,module,exports){
+
+/**
+ * Module dependencies.
+ */
+
+var global = (function() { return this; })();
+
+/**
+ * WebSocket constructor.
+ */
+
+var WebSocket = global.WebSocket || global.MozWebSocket;
+
+/**
+ * Module exports.
+ */
+
+module.exports = WebSocket ? ws : null;
+
+/**
+ * WebSocket constructor.
+ *
+ * The third `opts` options object gets ignored in web browsers, since it's
+ * non-standard, and throws a TypeError if passed to the constructor.
+ * See: https://github.com/einaros/ws/issues/227
+ *
+ * @param {String} uri
+ * @param {Array} protocols (optional)
+ * @param {Object) opts (optional)
+ * @api public
+ */
+
+function ws(uri, protocols, opts) {
+ var instance;
+ if (protocols) {
+ instance = new WebSocket(uri, protocols);
+ } else {
+ instance = new WebSocket(uri);
+ }
+ return instance;
+}
+
+if (WebSocket) ws.prototype = WebSocket.prototype;
+
+},{}]},{},[5])(5)
+});
\ No newline at end of file
diff --git a/web-dist/discord.3.3.1.js b/web-dist/discord.3.3.1.js
new file mode 100644
index 000000000..9992d6869
--- /dev/null
+++ b/web-dist/discord.3.3.1.js
@@ -0,0 +1,3590 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Discord = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o]*>/g) || [])[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var mention = _step3.value;
+
+ _mentions.push(mention.substring(2, mention.length - 1));
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3["return"]) {
+ _iterator3["return"]();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ return _mentions;
+ }
+ });
+
+ return prom;
+ }
+
+ //def createws
+ }, {
+ key: "createws",
+ value: function createws(url) {
+ if (this.websocket) return false;
+
+ var self = this;
+
+ //good to go
+ this.websocket = new WebSocket(url);
+
+ //open
+ this.websocket.onopen = function () {
+ self.trySendConnData(); //try connecting
+ };
+
+ //close
+ this.websocket.onclose = function () {
+ self.trigger("disconnected");
+ };
+
+ //message
+ this.websocket.onmessage = function (e) {
+
+ var dat = false,
+ data = {};
+
+ try {
+ dat = JSON.parse(e.data);
+ data = dat.d;
+ } catch (err) {
+ self.trigger("error", err, e);
+ return;
+ }
+
+ //valid message
+ switch (dat.t) {
+
+ case "READY":
+ self.debug("received ready packet");
+
+ self.user = self.addUser(data.user);
+
+ var _iteratorNormalCompletion4 = true;
+ var _didIteratorError4 = false;
+ var _iteratorError4 = undefined;
+
+ try {
+ for (var _iterator4 = data.guilds[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
+ var _server = _step4.value;
+
+ var server = self.addServer(_server);
+ }
+ } catch (err) {
+ _didIteratorError4 = true;
+ _iteratorError4 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion4 && _iterator4["return"]) {
+ _iterator4["return"]();
+ }
+ } finally {
+ if (_didIteratorError4) {
+ throw _iteratorError4;
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion5 = true;
+ var _didIteratorError5 = false;
+ var _iteratorError5 = undefined;
+
+ try {
+ for (var _iterator5 = data.private_channels[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
+ var _pmc = _step5.value;
+
+ var pmc = self.addPMChannel(_pmc);
+ }
+ } catch (err) {
+ _didIteratorError5 = true;
+ _iteratorError5 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion5 && _iterator5["return"]) {
+ _iterator5["return"]();
+ }
+ } finally {
+ if (_didIteratorError5) {
+ throw _iteratorError5;
+ }
+ }
+ }
+
+ self.trigger("ready");
+ self.readyTime = Date.now();
+ self.debug("cached " + self.serverCache.length + " servers, " + self.channelCache.length + " channels, " + self.pmChannelCache.length + " PMs and " + self.userCache.length + " users.");
+ self.state = 3;
+ setInterval(function () {
+ self.keepAlive.apply(self);
+ }, data.heartbeat_interval);
+
+ break;
+ case "MESSAGE_CREATE":
+ self.debug("received message");
+
+ var mentions = [];
+ data.mentions = data.mentions || []; //for some reason this was not defined at some point?
+ var _iteratorNormalCompletion6 = true;
+ var _didIteratorError6 = false;
+ var _iteratorError6 = undefined;
+
+ try {
+ for (var _iterator6 = data.mentions[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
+ var mention = _step6.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError6 = true;
+ _iteratorError6 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion6 && _iterator6["return"]) {
+ _iterator6["return"]();
+ }
+ } finally {
+ if (_didIteratorError6) {
+ throw _iteratorError6;
+ }
+ }
+ }
+
+ var channel = self.getChannel("id", data.channel_id);
+ if (channel) {
+ var msg = channel.addMessage(new Message(data, channel, mentions, self.addUser(data.author)));
+ self.trigger("message", msg);
+ }
+
+ break;
+ case "MESSAGE_DELETE":
+ self.debug("message deleted");
+
+ var channel = self.getChannel("id", data.channel_id);
+ var message = channel.getMessage("id", data.id);
+ if (message) {
+ self.trigger("messageDelete", channel, message);
+ channel.messages.splice(channel.messages.indexOf(message), 1);
+ } else {
+ //don't have the cache of that message ;(
+ self.trigger("messageDelete", channel);
+ }
+ break;
+ case "MESSAGE_UPDATE":
+ self.debug("message updated");
+
+ var channel = self.getChannel("id", data.channel_id);
+ var formerMessage = channel.getMessage("id", data.id);
+
+ if (formerMessage) {
+
+ //new message might be partial, so we need to fill it with whatever the old message was.
+ var info = {};
+
+ for (var key in formerMessage) {
+ info[key] = formerMessage[key];
+ }
+
+ for (var key in data) {
+ info[key] = data[key];
+ }
+
+ var mentions = [];
+ var _iteratorNormalCompletion7 = true;
+ var _didIteratorError7 = false;
+ var _iteratorError7 = undefined;
+
+ try {
+ for (var _iterator7 = info.mentions[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
+ var mention = _step7.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError7 = true;
+ _iteratorError7 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion7 && _iterator7["return"]) {
+ _iterator7["return"]();
+ }
+ } finally {
+ if (_didIteratorError7) {
+ throw _iteratorError7;
+ }
+ }
+ }
+
+ var newMessage = new Message(info, channel, mentions, formerMessage.author);
+
+ self.trigger("messageUpdate", newMessage, formerMessage);
+
+ channel.messages[channel.messages.indexOf(formerMessage)] = newMessage;
+ }
+
+ // message isn't in cache, and if it's a partial it could cause
+ // all hell to break loose... best to just act as if nothing happened
+
+ break;
+
+ case "GUILD_DELETE":
+
+ var server = self.getServer("id", data.id);
+
+ if (server) {
+ self.serverCache.splice(self.serverCache.indexOf(server), 1);
+ self.trigger("serverDelete", server);
+ }
+
+ break;
+
+ case "CHANNEL_DELETE":
+
+ var channel = self.getChannel("id", data.id);
+
+ if (channel) {
+
+ var server = channel.server;
+
+ if (server) {
+
+ server.channels.splice(server.channels.indexOf(channel), 1);
+ }
+
+ self.trigger("channelDelete", channel);
+
+ self.serverCache.splice(self.serverCache.indexOf(channel), 1);
+ }
+
+ break;
+
+ case "GUILD_CREATE":
+
+ var server = self.getServer("id", data.id);
+
+ if (!server) {
+ //if server doesn't already exist because duh
+ server = self.addServer(data);
+ } /*else if(server.channels.length === 0){
+
+ var srv = new Server(data, self);
+ for(channel of data.channels){
+ srv.channels.push(new Channel(channel, data.id));
+ }
+ self.serverCache[self.serverCache.indexOf(server)] = srv;
+
+ }*/
+
+ if (self.serverCreateListener.get(data.id)) {
+ var cbs = self.serverCreateListener.get(data.id);
+ cbs[0](server); //promise then callback
+ cbs[1](null, server); //legacy callback
+ self.serverCreateListener["delete"](data.id);
+ }
+
+ self.trigger("serverCreate", server);
+
+ break;
+
+ case "CHANNEL_CREATE":
+
+ var channel = self.getChannel("id", data.id);
+
+ if (!channel) {
+
+ var chann = self.addChannel(data, data.guild_id);
+ var srv = self.getServer("id", data.guild_id);
+ if (srv) {
+ srv.addChannel(chann);
+ }
+ self.trigger("channelCreate", chann);
+ }
+
+ break;
+
+ case "GUILD_MEMBER_ADD":
+
+ var server = self.getServer("id", data.guild_id);
+
+ if (server) {
+
+ var user = self.addUser(data.user); //if for whatever reason it doesn't exist..
+
+ if (! ~server.members.indexOf(user)) {
+ server.members.push(user);
+ }
+
+ self.trigger("serverNewMember", user, server);
+ }
+
+ break;
+
+ case "GUILD_MEMBER_REMOVE":
+
+ var server = self.getServer("id", data.guild_id);
+
+ if (server) {
+
+ var user = self.addUser(data.user); //if for whatever reason it doesn't exist..
+
+ if (~server.members.indexOf(user)) {
+ server.members.splice(server.members.indexOf(user), 1);
+ }
+
+ self.trigger("serverRemoveMember", user, server);
+ }
+
+ break;
+
+ case "USER_UPDATE":
+
+ if (self.user && data.id === self.user.id) {
+
+ var newUser = new User(data); //not actually adding to the cache
+
+ self.trigger("userUpdate", newUser, self.user);
+
+ if (~self.userCache.indexOf(self.user)) {
+ self.userCache[self.userCache.indexOf(self.user)] = newUser;
+ }
+
+ self.user = newUser;
+ }
+
+ break;
+
+ case "PRESENCE_UPDATE":
+
+ var userInCache = self.getUser("id", data.user.id);
+
+ if (userInCache) {
+ //user exists
+ var presenceUser = new User(data.user);
+ if (presenceUser.equalsStrict(userInCache)) {
+ //they're exactly the same, an actual presence update
+ self.trigger("presence", {
+ user: userInCache,
+ status: data.status,
+ server: self.getServer("id", data.guild_id),
+ gameId: data.game_id
+ });
+ } else {
+ //one of their details changed.
+ self.trigger("userUpdate", userInCache, presenceUser);
+ self.userCache[self.userCache.indexOf(userInCache)] = presenceUser;
+ }
+ }
+
+ break;
+
+ default:
+ self.debug("received unknown packet");
+ self.trigger("unknown", dat);
+ break;
+
+ }
+ };
+ }
+
+ //def addUser
+ }, {
+ key: "addUser",
+ value: function addUser(data) {
+ if (!this.getUser("id", data.id)) {
+ this.userCache.push(new User(data));
+ }
+ return this.getUser("id", data.id);
+ }
+
+ //def addChannel
+ }, {
+ key: "addChannel",
+ value: function addChannel(data, serverId) {
+ if (!this.getChannel("id", data.id)) {
+ this.channelCache.push(new Channel(data, this.getServer("id", serverId)));
+ }
+ return this.getChannel("id", data.id);
+ }
+ }, {
+ key: "addPMChannel",
+ value: function addPMChannel(data) {
+ if (!this.getPMChannel("id", data.id)) {
+ this.pmChannelCache.push(new PMChannel(data, this));
+ }
+ return this.getPMChannel("id", data.id);
+ }
+
+ //def addServer
+ }, {
+ key: "addServer",
+ value: function addServer(data) {
+
+ var server = this.getServer("id", data.id);
+
+ if (!server) {
+ server = new Server(data, this);
+ this.serverCache.push(server);
+ if (data.channels) {
+ var _iteratorNormalCompletion8 = true;
+ var _didIteratorError8 = false;
+ var _iteratorError8 = undefined;
+
+ try {
+ for (var _iterator8 = data.channels[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
+ var channel = _step8.value;
+
+ server.channels.push(this.addChannel(channel, server.id));
+ }
+ } catch (err) {
+ _didIteratorError8 = true;
+ _iteratorError8 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion8 && _iterator8["return"]) {
+ _iterator8["return"]();
+ }
+ } finally {
+ if (_didIteratorError8) {
+ throw _iteratorError8;
+ }
+ }
+ }
+ }
+ }
+
+ return server;
+ }
+
+ //def getUser
+ }, {
+ key: "getUser",
+ value: function getUser(key, value) {
+ var _iteratorNormalCompletion9 = true;
+ var _didIteratorError9 = false;
+ var _iteratorError9 = undefined;
+
+ try {
+ for (var _iterator9 = this.userCache[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
+ var user = _step9.value;
+
+ if (user[key] === value) {
+ return user;
+ }
+ }
+ } catch (err) {
+ _didIteratorError9 = true;
+ _iteratorError9 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion9 && _iterator9["return"]) {
+ _iterator9["return"]();
+ }
+ } finally {
+ if (_didIteratorError9) {
+ throw _iteratorError9;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def getChannel
+ }, {
+ key: "getChannel",
+ value: function getChannel(key, value) {
+ var _iteratorNormalCompletion10 = true;
+ var _didIteratorError10 = false;
+ var _iteratorError10 = undefined;
+
+ try {
+ for (var _iterator10 = this.channelCache[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
+ var channel = _step10.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError10 = true;
+ _iteratorError10 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion10 && _iterator10["return"]) {
+ _iterator10["return"]();
+ }
+ } finally {
+ if (_didIteratorError10) {
+ throw _iteratorError10;
+ }
+ }
+ }
+
+ return this.getPMChannel(key, value); //might be a PM
+ }
+ }, {
+ key: "getPMChannel",
+ value: function getPMChannel(key, value) {
+ var _iteratorNormalCompletion11 = true;
+ var _didIteratorError11 = false;
+ var _iteratorError11 = undefined;
+
+ try {
+ for (var _iterator11 = this.pmChannelCache[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
+ var channel = _step11.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError11 = true;
+ _iteratorError11 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion11 && _iterator11["return"]) {
+ _iterator11["return"]();
+ }
+ } finally {
+ if (_didIteratorError11) {
+ throw _iteratorError11;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def getServer
+ }, {
+ key: "getServer",
+ value: function getServer(key, value) {
+ var _iteratorNormalCompletion12 = true;
+ var _didIteratorError12 = false;
+ var _iteratorError12 = undefined;
+
+ try {
+ for (var _iterator12 = this.serverCache[Symbol.iterator](), _step12; !(_iteratorNormalCompletion12 = (_step12 = _iterator12.next()).done); _iteratorNormalCompletion12 = true) {
+ var server = _step12.value;
+
+ if (server[key] === value) {
+ return server;
+ }
+ }
+ } catch (err) {
+ _didIteratorError12 = true;
+ _iteratorError12 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion12 && _iterator12["return"]) {
+ _iterator12["return"]();
+ }
+ } finally {
+ if (_didIteratorError12) {
+ throw _iteratorError12;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def trySendConnData
+ }, {
+ key: "trySendConnData",
+ value: function trySendConnData() {
+
+ if (this.token && !this.alreadySentData) {
+
+ this.alreadySentData = true;
+
+ var data = {
+ op: 2,
+ d: {
+ token: this.token,
+ v: 2,
+ properties: {
+ "$os": "discord.js",
+ "$browser": "discord.js",
+ "$device": "discord.js",
+ "$referrer": "",
+ "$referring_domain": ""
+ }
+ }
+ };
+ this.websocket.send(JSON.stringify(data));
+ }
+ }
+ }, {
+ key: "resolveServerID",
+ value: function resolveServerID(resource) {
+
+ if (resource instanceof Server) {
+ return resource.id;
+ } else if (!isNaN(resource) && resource.length && resource.length === 17) {
+ return resource;
+ }
+ }
+ }, {
+ key: "resolveDestination",
+ value: function resolveDestination(destination) {
+ var channId = false;
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ if (destination instanceof Server) {
+ channId = destination.id; //general is the same as server id
+ } else if (destination instanceof Channel) {
+ channId = destination.id;
+ } else if (destination instanceof Message) {
+ channId = destination.channel.id;
+ } else if (destination instanceof User) {
+
+ //check if we have a PM
+ var _iteratorNormalCompletion13 = true;
+ var _didIteratorError13 = false;
+ var _iteratorError13 = undefined;
+
+ try {
+ for (var _iterator13 = self.pmChannelCache[Symbol.iterator](), _step13; !(_iteratorNormalCompletion13 = (_step13 = _iterator13.next()).done); _iteratorNormalCompletion13 = true) {
+ var pmc = _step13.value;
+
+ if (pmc.user.equals(destination)) {
+ return pmc.id;
+ }
+ }
+
+ //we don't, at this point we're late
+ } catch (err) {
+ _didIteratorError13 = true;
+ _iteratorError13 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion13 && _iterator13["return"]) {
+ _iterator13["return"]();
+ }
+ } finally {
+ if (_didIteratorError13) {
+ throw _iteratorError13;
+ }
+ }
+ }
+
+ self.startPM(destination).then(function (pmc) {
+ resolve(pmc.id);
+ })["catch"](reject);
+ } else {
+ channId = destination;
+ }
+ if (channId) resolve(channId);
+ });
+ }
+ }, {
+ key: "_sendMessage",
+ value: function _sendMessage(destination, content, tts, mentions) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request.post(Endpoints.CHANNELS + "/" + destination + "/messages").set("authorization", self.token).send({
+ content: content,
+ mentions: mentions,
+ tts: tts
+ }).end(function (err, res) {
+
+ if (err) {
+ reject(err);
+ } else {
+ var data = res.body;
+
+ var mentions = [];
+
+ data.mentions = data.mentions || []; //for some reason this was not defined at some point?
+
+ var _iteratorNormalCompletion14 = true;
+ var _didIteratorError14 = false;
+ var _iteratorError14 = undefined;
+
+ try {
+ for (var _iterator14 = data.mentions[Symbol.iterator](), _step14; !(_iteratorNormalCompletion14 = (_step14 = _iterator14.next()).done); _iteratorNormalCompletion14 = true) {
+ var mention = _step14.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError14 = true;
+ _iteratorError14 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion14 && _iterator14["return"]) {
+ _iterator14["return"]();
+ }
+ } finally {
+ if (_didIteratorError14) {
+ throw _iteratorError14;
+ }
+ }
+ }
+
+ var channel = self.getChannel("id", data.channel_id);
+ if (channel) {
+ var msg = channel.addMessage(new Message(data, channel, mentions, self.addUser(data.author)));
+ resolve(msg);
+ }
+ }
+ });
+ });
+ }
+ }, {
+ key: "_sendFile",
+ value: function _sendFile(destination, attachment) {
+ var attachmentName = arguments.length <= 2 || arguments[2] === undefined ? "DEFAULT BECAUSE YOU DIDN'T SPECIFY WHY.png" : arguments[2];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request.post(Endpoints.CHANNELS + "/" + destination + "/messages").set("authorization", self.token).attach("file", attachment, attachmentName).end(function (err, res) {
+
+ if (err) {
+ reject(err);
+ } else {
+
+ var chann = self.getChannel("id", destination);
+ if (chann) {
+ var msg = chann.addMessage(new Message(res.body, chann, [], self.user));
+ resolve(msg);
+ }
+ }
+ });
+ });
+ }
+ }, {
+ key: "_updateMessage",
+ value: function _updateMessage(message, content) {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ request.patch(Endpoints.CHANNELS + "/" + message.channel.id + "/messages/" + message.id).set("authorization", self.token).send({
+ content: content,
+ mentions: []
+ }).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ var msg = new Message(res.body, message.channel, message.mentions, message.sender);
+ resolve(msg);
+ message.channel.messages[message.channel.messages.indexOf(message)] = msg;
+ }
+ });
+ });
+ }
+ }, {
+ key: "_deleteMessage",
+ value: function _deleteMessage(message) {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ request.del(Endpoints.CHANNELS + "/" + message.channel.id + "/messages/" + message.id).set("authorization", self.token).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve();
+ }
+ });
+ });
+ }
+ }, {
+ key: "checkQueue",
+ value: function checkQueue(channelID) {
+ var _this = this;
+
+ var self = this;
+
+ if (!this.checkingQueue[channelID]) {
+ (function () {
+ var doNext = function doNext() {
+ if (self.queue[channelID].length === 0) {
+ done();
+ return;
+ }
+ var queuedEvent = self.queue[channelID][0];
+ switch (queuedEvent.action) {
+ case "sendMessage":
+ var msgToSend = queuedEvent;
+ self._sendMessage(channelID, msgToSend.content, msgToSend.tts, msgToSend.mentions).then(function (msg) {
+ msgToSend.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToSend.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "sendFile":
+ var fileToSend = queuedEvent;
+ self._sendFile(channelID, fileToSend.attachment, fileToSend.attachmentName).then(function (msg) {
+ fileToSend.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ fileToSend.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "updateMessage":
+ var msgToUpd = queuedEvent;
+ self._updateMessage(msgToUpd.message, msgToUpd.content).then(function (msg) {
+ msgToUpd.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToUpd.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "deleteMessage":
+ var msgToDel = queuedEvent;
+ self._deleteMessage(msgToDel.message).then(function (msg) {
+ msgToDel.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToDel.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ default:
+ done();
+ break;
+ }
+ };
+
+ var done = function done() {
+ self.checkingQueue[channelID] = false;
+ return;
+ };
+
+ //if we aren't already checking this queue.
+ _this.checkingQueue[channelID] = true;
+ doNext();
+ })();
+ }
+ }
+ }, {
+ key: "uptime",
+ get: function get() {
+
+ return this.readyTime ? Date.now() - this.readyTime : null;
+ }
+ }, {
+ key: "ready",
+ get: function get() {
+ return this.state === 3;
+ }
+ }, {
+ key: "servers",
+ get: function get() {
+ return this.serverCache;
+ }
+ }, {
+ key: "channels",
+ get: function get() {
+ return this.channelCache;
+ }
+ }, {
+ key: "users",
+ get: function get() {
+ return this.userCache;
+ }
+ }, {
+ key: "PMChannels",
+ get: function get() {
+ return this.pmChannelCache;
+ }
+ }, {
+ key: "messages",
+ get: function get() {
+
+ var msgs = [];
+ var _iteratorNormalCompletion15 = true;
+ var _didIteratorError15 = false;
+ var _iteratorError15 = undefined;
+
+ try {
+ for (var _iterator15 = this.channelCache[Symbol.iterator](), _step15; !(_iteratorNormalCompletion15 = (_step15 = _iterator15.next()).done); _iteratorNormalCompletion15 = true) {
+ var channel = _step15.value;
+
+ msgs = msgs.concat(channel.messages);
+ }
+ } catch (err) {
+ _didIteratorError15 = true;
+ _iteratorError15 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion15 && _iterator15["return"]) {
+ _iterator15["return"]();
+ }
+ } finally {
+ if (_didIteratorError15) {
+ throw _iteratorError15;
+ }
+ }
+ }
+
+ return msgs;
+ }
+ }]);
+
+ return Client;
+})();
+
+function getGateway() {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request.get(Endpoints.API + "/gateway").end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(res.body.url);
+ }
+ });
+ });
+}
+
+module.exports = Client;
+},{"./Endpoints.js":2,"./PMChannel.js":3,"./channel.js":4,"./invite.js":6,"./message.js":7,"./server.js":8,"./user.js":9,"fs":10,"superagent":11,"ws":14}],2:[function(require,module,exports){
+"use strict";
+
+exports.BASE_DOMAIN = "discordapp.com";
+exports.BASE = "https://" + exports.BASE_DOMAIN;
+exports.WEBSOCKET_HUB = "wss://" + exports.BASE_DOMAIN + "/hub";
+
+exports.API = exports.BASE + "/api";
+exports.AUTH = exports.API + "/auth";
+exports.LOGIN = exports.AUTH + "/login";
+exports.LOGOUT = exports.AUTH + "/logout";
+exports.USERS = exports.API + "/users";
+exports.SERVERS = exports.API + "/guilds";
+exports.CHANNELS = exports.API + "/channels";
+},{}],3:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var PMChannel = (function () {
+ function PMChannel(data, client) {
+ _classCallCheck(this, PMChannel);
+
+ this.user = client.getUser("id", data.recipient.id);
+ this.id = data.id;
+ this.messages = [];
+ }
+
+ _createClass(PMChannel, [{
+ key: "addMessage",
+ value: function addMessage(data) {
+ if (!this.getMessage("id", data.id)) {
+ this.messages.push(data);
+ }
+ return this.getMessage("id", data.id);
+ }
+ }, {
+ key: "getMessage",
+ value: function getMessage(key, value) {
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.messages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var message = _step.value;
+
+ if (message[key] === value) {
+ return message;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return true;
+ }
+ }]);
+
+ return PMChannel;
+})();
+
+module.exports = PMChannel;
+},{}],4:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Channel = (function () {
+ function Channel(data, server) {
+ _classCallCheck(this, Channel);
+
+ this.server = server;
+ this.name = data.name;
+ this.type = data.type;
+ this.id = data.id;
+ this.messages = [];
+ //this.isPrivate = isPrivate; //not sure about the implementation of this...
+ }
+
+ _createClass(Channel, [{
+ key: "equals",
+ value: function equals(object) {
+ return object && object.id === this.id;
+ }
+ }, {
+ key: "addMessage",
+ value: function addMessage(data) {
+ if (!this.getMessage("id", data.id)) {
+ this.messages.push(data);
+ }
+ return this.getMessage("id", data.id);
+ }
+ }, {
+ key: "getMessage",
+ value: function getMessage(key, value) {
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.messages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var message = _step.value;
+
+ if (message[key] === value) {
+ return message;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ return "#" + this.name;
+ }
+ }, {
+ key: "client",
+ get: function get() {
+ return this.server.client;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return false;
+ }
+ }]);
+
+ return Channel;
+})();
+
+module.exports = Channel;
+},{}],5:[function(require,module,exports){
+"use strict";
+
+var request = require("superagent");
+var Endpoints = require("./Endpoints.js");
+var Client = require("./Client.js");
+
+var Discord = {
+ Endpoints: Endpoints,
+ Client: Client
+};
+
+module.exports = Discord;
+},{"./Client.js":1,"./Endpoints.js":2,"superagent":11}],6:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Invite = (function () {
+ function Invite(data, client) {
+ _classCallCheck(this, Invite);
+
+ this.max_age = data.max_age;
+ this.code = data.code;
+ this.server = client.getServer("id", data.guild.id);
+ this.revoked = data.revoked;
+ this.created_at = Date.parse(data.created_at);
+ this.temporary = data.temporary;
+ this.uses = data.uses;
+ this.max_uses = data.uses;
+ this.inviter = client.addUser(data.inviter);
+ this.xkcd = data.xkcdpass;
+ this.channel = client.getChannel("id", data.channel.id);
+ }
+
+ _createClass(Invite, [{
+ key: "URL",
+ get: function get() {
+ var code = this.xkcd ? this.xkcdpass : this.code;
+ return "https://discord.gg/" + code;
+ }
+ }]);
+
+ return Invite;
+})();
+
+module.exports = Invite;
+},{}],7:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var PMChannel = require("./PMChannel.js");
+
+var Message = (function () {
+ function Message(data, channel, mentions, author) {
+ _classCallCheck(this, Message);
+
+ this.tts = data.tts;
+ this.timestamp = Date.parse(data.timestamp);
+ this.nonce = data.nonce;
+ this.mentions = mentions;
+ this.everyoneMentioned = data.mention_everyone;
+ this.id = data.id;
+ this.embeds = data.embeds;
+ this.editedTimestamp = data.edited_timestamp;
+ this.content = data.content.trim();
+ this.channel = channel;
+ this.author = author;
+ this.attachments = data.attachments;
+ }
+
+ /*exports.Message.prototype.isPM = function() {
+ return ( this.channel instanceof PMChannel );
+ }*/
+
+ _createClass(Message, [{
+ key: "isMentioned",
+ value: function isMentioned(user) {
+ var id = user.id ? user.id : user;
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.mentions[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var mention = _step.value;
+
+ if (mention.id === id) {
+ return true;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return false;
+ }
+ }, {
+ key: "sender",
+ get: function get() {
+ return this.author;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return this.channel.isPrivate;
+ }
+ }]);
+
+ return Message;
+})();
+
+module.exports = Message;
+},{"./PMChannel.js":3}],8:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Server = (function () {
+ function Server(data, client) {
+ _classCallCheck(this, Server);
+
+ this.client = client;
+ this.region = data.region;
+ this.ownerID = data.owner_id;
+ this.name = data.name;
+ this.id = data.id;
+ this.members = [];
+ this.channels = [];
+ this.icon = data.icon;
+ this.afkTimeout = data.afk_timeout;
+ this.afkChannelId = data.afk_channel_id;
+
+ if (!data.members) {
+ data.members = [client.user];
+ return;
+ }
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = data.members[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var member = _step.value;
+
+ // first we cache the user in our Discord Client,
+ // then we add it to our list. This way when we
+ // get a user from this server's member list,
+ // it will be identical (unless an async change occurred)
+ // to the client's cache.
+ if (member.user) this.members.push(client.addUser(member.user));
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+ }
+
+ _createClass(Server, [{
+ key: "getChannel",
+
+ // get/set
+ value: function getChannel(key, value) {
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = this.channels[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var channel = _step2.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2["return"]) {
+ _iterator2["return"]();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "getMember",
+ value: function getMember(key, value) {
+ var _iteratorNormalCompletion3 = true;
+ var _didIteratorError3 = false;
+ var _iteratorError3 = undefined;
+
+ try {
+ for (var _iterator3 = this.members[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var member = _step3.value;
+
+ if (member[key] === value) {
+ return member;
+ }
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3["return"]) {
+ _iterator3["return"]();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "addChannel",
+ value: function addChannel(chann) {
+ if (!this.getChannel("id", chann.id)) {
+ this.channels.push(chann);
+ }
+ return chann;
+ }
+ }, {
+ key: "addMember",
+ value: function addMember(member) {
+ if (!this.getMember("id", member.id)) {
+ this.members.push(member);
+ }
+ return member;
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ return this.name;
+ }
+ }, {
+ key: "iconURL",
+ get: function get() {
+ if (!this.icon) return null;
+ return "https://discordapp.com/api/guilds/" + this.id + "/icons/" + this.icon + ".jpg";
+ }
+ }, {
+ key: "afkChannel",
+ get: function get() {
+ if (!this.afkChannelId) return false;
+
+ return this.getChannel("id", this.afkChannelId);
+ }
+ }, {
+ key: "defaultChannel",
+ get: function get() {
+ return this.getChannel("name", "general");
+ }
+ }, {
+ key: "owner",
+ get: function get() {
+ return this.client.getUser("id", this.ownerID);
+ }
+ }]);
+
+ return Server;
+})();
+
+module.exports = Server;
+},{}],9:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var User = (function () {
+ function User(data) {
+ _classCallCheck(this, User);
+
+ this.username = data.username;
+ this.discriminator = data.discriminator;
+ this.id = data.id;
+ this.avatar = data.avatar;
+ }
+
+ // access using user.avatarURL;
+
+ _createClass(User, [{
+ key: "mention",
+ value: function mention() {
+ return "<@" + this.id + ">";
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ /*
+ if we embed a user in a String - like so:
+ "Yo " + user + " what's up?"
+ It would generate something along the lines of:
+ "Yo @hydrabolt what's up?"
+ */
+ return this.mention();
+ }
+ }, {
+ key: "equals",
+ value: function equals(object) {
+ return object.id === this.id;
+ }
+ }, {
+ key: "equalsStrict",
+ value: function equalsStrict(object) {
+ return object.id === this.id && object.avatar === this.avatar && object.username === this.username && object.discriminator === this.discriminator;
+ }
+ }, {
+ key: "avatarURL",
+ get: function get() {
+ if (!this.avatar) return null;
+ return "https://discordapp.com/api/users/" + this.id + "/avatars/" + this.avatar + ".jpg";
+ }
+ }]);
+
+ return User;
+})();
+
+module.exports = User;
+},{}],10:[function(require,module,exports){
+
+},{}],11:[function(require,module,exports){
+/**
+ * Module dependencies.
+ */
+
+var Emitter = require('emitter');
+var reduce = require('reduce');
+
+/**
+ * Root reference for iframes.
+ */
+
+var root = 'undefined' == typeof window
+ ? (this || self)
+ : window;
+
+/**
+ * Noop.
+ */
+
+function noop(){};
+
+/**
+ * Check if `obj` is a host object,
+ * we don't want to serialize these :)
+ *
+ * TODO: future proof, move to compoent land
+ *
+ * @param {Object} obj
+ * @return {Boolean}
+ * @api private
+ */
+
+function isHost(obj) {
+ var str = {}.toString.call(obj);
+
+ switch (str) {
+ case '[object File]':
+ case '[object Blob]':
+ case '[object FormData]':
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Determine XHR.
+ */
+
+request.getXHR = function () {
+ if (root.XMLHttpRequest
+ && (!root.location || 'file:' != root.location.protocol
+ || !root.ActiveXObject)) {
+ return new XMLHttpRequest;
+ } else {
+ try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {}
+ }
+ return false;
+};
+
+/**
+ * Removes leading and trailing whitespace, added to support IE.
+ *
+ * @param {String} s
+ * @return {String}
+ * @api private
+ */
+
+var trim = ''.trim
+ ? function(s) { return s.trim(); }
+ : function(s) { return s.replace(/(^\s*|\s*$)/g, ''); };
+
+/**
+ * Check if `obj` is an object.
+ *
+ * @param {Object} obj
+ * @return {Boolean}
+ * @api private
+ */
+
+function isObject(obj) {
+ return obj === Object(obj);
+}
+
+/**
+ * Serialize the given `obj`.
+ *
+ * @param {Object} obj
+ * @return {String}
+ * @api private
+ */
+
+function serialize(obj) {
+ if (!isObject(obj)) return obj;
+ var pairs = [];
+ for (var key in obj) {
+ if (null != obj[key]) {
+ pairs.push(encodeURIComponent(key)
+ + '=' + encodeURIComponent(obj[key]));
+ }
+ }
+ return pairs.join('&');
+}
+
+/**
+ * Expose serialization method.
+ */
+
+ request.serializeObject = serialize;
+
+ /**
+ * Parse the given x-www-form-urlencoded `str`.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+function parseString(str) {
+ var obj = {};
+ var pairs = str.split('&');
+ var parts;
+ var pair;
+
+ for (var i = 0, len = pairs.length; i < len; ++i) {
+ pair = pairs[i];
+ parts = pair.split('=');
+ obj[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
+ }
+
+ return obj;
+}
+
+/**
+ * Expose parser.
+ */
+
+request.parseString = parseString;
+
+/**
+ * Default MIME type map.
+ *
+ * superagent.types.xml = 'application/xml';
+ *
+ */
+
+request.types = {
+ html: 'text/html',
+ json: 'application/json',
+ xml: 'application/xml',
+ urlencoded: 'application/x-www-form-urlencoded',
+ 'form': 'application/x-www-form-urlencoded',
+ 'form-data': 'application/x-www-form-urlencoded'
+};
+
+/**
+ * Default serialization map.
+ *
+ * superagent.serialize['application/xml'] = function(obj){
+ * return 'generated xml here';
+ * };
+ *
+ */
+
+ request.serialize = {
+ 'application/x-www-form-urlencoded': serialize,
+ 'application/json': JSON.stringify
+ };
+
+ /**
+ * Default parsers.
+ *
+ * superagent.parse['application/xml'] = function(str){
+ * return { object parsed from str };
+ * };
+ *
+ */
+
+request.parse = {
+ 'application/x-www-form-urlencoded': parseString,
+ 'application/json': JSON.parse
+};
+
+/**
+ * Parse the given header `str` into
+ * an object containing the mapped fields.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+function parseHeader(str) {
+ var lines = str.split(/\r?\n/);
+ var fields = {};
+ var index;
+ var line;
+ var field;
+ var val;
+
+ lines.pop(); // trailing CRLF
+
+ for (var i = 0, len = lines.length; i < len; ++i) {
+ line = lines[i];
+ index = line.indexOf(':');
+ field = line.slice(0, index).toLowerCase();
+ val = trim(line.slice(index + 1));
+ fields[field] = val;
+ }
+
+ return fields;
+}
+
+/**
+ * Return the mime type for the given `str`.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+function type(str){
+ return str.split(/ *; */).shift();
+};
+
+/**
+ * Return header field parameters.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+function params(str){
+ return reduce(str.split(/ *; */), function(obj, str){
+ var parts = str.split(/ *= */)
+ , key = parts.shift()
+ , val = parts.shift();
+
+ if (key && val) obj[key] = val;
+ return obj;
+ }, {});
+};
+
+/**
+ * Initialize a new `Response` with the given `xhr`.
+ *
+ * - set flags (.ok, .error, etc)
+ * - parse header
+ *
+ * Examples:
+ *
+ * Aliasing `superagent` as `request` is nice:
+ *
+ * request = superagent;
+ *
+ * We can use the promise-like API, or pass callbacks:
+ *
+ * request.get('/').end(function(res){});
+ * request.get('/', function(res){});
+ *
+ * Sending data can be chained:
+ *
+ * request
+ * .post('/user')
+ * .send({ name: 'tj' })
+ * .end(function(res){});
+ *
+ * Or passed to `.send()`:
+ *
+ * request
+ * .post('/user')
+ * .send({ name: 'tj' }, function(res){});
+ *
+ * Or passed to `.post()`:
+ *
+ * request
+ * .post('/user', { name: 'tj' })
+ * .end(function(res){});
+ *
+ * Or further reduced to a single call for simple cases:
+ *
+ * request
+ * .post('/user', { name: 'tj' }, function(res){});
+ *
+ * @param {XMLHTTPRequest} xhr
+ * @param {Object} options
+ * @api private
+ */
+
+function Response(req, options) {
+ options = options || {};
+ this.req = req;
+ this.xhr = this.req.xhr;
+ // responseText is accessible only if responseType is '' or 'text' and on older browsers
+ this.text = ((this.req.method !='HEAD' && (this.xhr.responseType === '' || this.xhr.responseType === 'text')) || typeof this.xhr.responseType === 'undefined')
+ ? this.xhr.responseText
+ : null;
+ this.statusText = this.req.xhr.statusText;
+ this.setStatusProperties(this.xhr.status);
+ this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders());
+ // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but
+ // getResponseHeader still works. so we get content-type even if getting
+ // other headers fails.
+ this.header['content-type'] = this.xhr.getResponseHeader('content-type');
+ this.setHeaderProperties(this.header);
+ this.body = this.req.method != 'HEAD'
+ ? this.parseBody(this.text ? this.text : this.xhr.response)
+ : null;
+}
+
+/**
+ * Get case-insensitive `field` value.
+ *
+ * @param {String} field
+ * @return {String}
+ * @api public
+ */
+
+Response.prototype.get = function(field){
+ return this.header[field.toLowerCase()];
+};
+
+/**
+ * Set header related properties:
+ *
+ * - `.type` the content type without params
+ *
+ * A response of "Content-Type: text/plain; charset=utf-8"
+ * will provide you with a `.type` of "text/plain".
+ *
+ * @param {Object} header
+ * @api private
+ */
+
+Response.prototype.setHeaderProperties = function(header){
+ // content-type
+ var ct = this.header['content-type'] || '';
+ this.type = type(ct);
+
+ // params
+ var obj = params(ct);
+ for (var key in obj) this[key] = obj[key];
+};
+
+/**
+ * Parse the given body `str`.
+ *
+ * Used for auto-parsing of bodies. Parsers
+ * are defined on the `superagent.parse` object.
+ *
+ * @param {String} str
+ * @return {Mixed}
+ * @api private
+ */
+
+Response.prototype.parseBody = function(str){
+ var parse = request.parse[this.type];
+ return parse && str && (str.length || str instanceof Object)
+ ? parse(str)
+ : null;
+};
+
+/**
+ * Set flags such as `.ok` based on `status`.
+ *
+ * For example a 2xx response will give you a `.ok` of __true__
+ * whereas 5xx will be __false__ and `.error` will be __true__. The
+ * `.clientError` and `.serverError` are also available to be more
+ * specific, and `.statusType` is the class of error ranging from 1..5
+ * sometimes useful for mapping respond colors etc.
+ *
+ * "sugar" properties are also defined for common cases. Currently providing:
+ *
+ * - .noContent
+ * - .badRequest
+ * - .unauthorized
+ * - .notAcceptable
+ * - .notFound
+ *
+ * @param {Number} status
+ * @api private
+ */
+
+Response.prototype.setStatusProperties = function(status){
+ // handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request
+ if (status === 1223) {
+ status = 204;
+ }
+
+ var type = status / 100 | 0;
+
+ // status / class
+ this.status = status;
+ this.statusType = type;
+
+ // basics
+ this.info = 1 == type;
+ this.ok = 2 == type;
+ this.clientError = 4 == type;
+ this.serverError = 5 == type;
+ this.error = (4 == type || 5 == type)
+ ? this.toError()
+ : false;
+
+ // sugar
+ this.accepted = 202 == status;
+ this.noContent = 204 == status;
+ this.badRequest = 400 == status;
+ this.unauthorized = 401 == status;
+ this.notAcceptable = 406 == status;
+ this.notFound = 404 == status;
+ this.forbidden = 403 == status;
+};
+
+/**
+ * Return an `Error` representative of this response.
+ *
+ * @return {Error}
+ * @api public
+ */
+
+Response.prototype.toError = function(){
+ var req = this.req;
+ var method = req.method;
+ var url = req.url;
+
+ var msg = 'cannot ' + method + ' ' + url + ' (' + this.status + ')';
+ var err = new Error(msg);
+ err.status = this.status;
+ err.method = method;
+ err.url = url;
+
+ return err;
+};
+
+/**
+ * Expose `Response`.
+ */
+
+request.Response = Response;
+
+/**
+ * Initialize a new `Request` with the given `method` and `url`.
+ *
+ * @param {String} method
+ * @param {String} url
+ * @api public
+ */
+
+function Request(method, url) {
+ var self = this;
+ Emitter.call(this);
+ this._query = this._query || [];
+ this.method = method;
+ this.url = url;
+ this.header = {};
+ this._header = {};
+ this.on('end', function(){
+ var err = null;
+ var res = null;
+
+ try {
+ res = new Response(self);
+ } catch(e) {
+ err = new Error('Parser is unable to parse the response');
+ err.parse = true;
+ err.original = e;
+ return self.callback(err);
+ }
+
+ self.emit('response', res);
+
+ if (err) {
+ return self.callback(err, res);
+ }
+
+ if (res.status >= 200 && res.status < 300) {
+ return self.callback(err, res);
+ }
+
+ var new_err = new Error(res.statusText || 'Unsuccessful HTTP response');
+ new_err.original = err;
+ new_err.response = res;
+ new_err.status = res.status;
+
+ self.callback(new_err, res);
+ });
+}
+
+/**
+ * Mixin `Emitter`.
+ */
+
+Emitter(Request.prototype);
+
+/**
+ * Allow for extension
+ */
+
+Request.prototype.use = function(fn) {
+ fn(this);
+ return this;
+}
+
+/**
+ * Set timeout to `ms`.
+ *
+ * @param {Number} ms
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.timeout = function(ms){
+ this._timeout = ms;
+ return this;
+};
+
+/**
+ * Clear previous timeout.
+ *
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.clearTimeout = function(){
+ this._timeout = 0;
+ clearTimeout(this._timer);
+ return this;
+};
+
+/**
+ * Abort the request, and clear potential timeout.
+ *
+ * @return {Request}
+ * @api public
+ */
+
+Request.prototype.abort = function(){
+ if (this.aborted) return;
+ this.aborted = true;
+ this.xhr.abort();
+ this.clearTimeout();
+ this.emit('abort');
+ return this;
+};
+
+/**
+ * Set header `field` to `val`, or multiple fields with one object.
+ *
+ * Examples:
+ *
+ * req.get('/')
+ * .set('Accept', 'application/json')
+ * .set('X-API-Key', 'foobar')
+ * .end(callback);
+ *
+ * req.get('/')
+ * .set({ Accept: 'application/json', 'X-API-Key': 'foobar' })
+ * .end(callback);
+ *
+ * @param {String|Object} field
+ * @param {String} val
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.set = function(field, val){
+ if (isObject(field)) {
+ for (var key in field) {
+ this.set(key, field[key]);
+ }
+ return this;
+ }
+ this._header[field.toLowerCase()] = val;
+ this.header[field] = val;
+ return this;
+};
+
+/**
+ * Remove header `field`.
+ *
+ * Example:
+ *
+ * req.get('/')
+ * .unset('User-Agent')
+ * .end(callback);
+ *
+ * @param {String} field
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.unset = function(field){
+ delete this._header[field.toLowerCase()];
+ delete this.header[field];
+ return this;
+};
+
+/**
+ * Get case-insensitive header `field` value.
+ *
+ * @param {String} field
+ * @return {String}
+ * @api private
+ */
+
+Request.prototype.getHeader = function(field){
+ return this._header[field.toLowerCase()];
+};
+
+/**
+ * Set Content-Type to `type`, mapping values from `request.types`.
+ *
+ * Examples:
+ *
+ * superagent.types.xml = 'application/xml';
+ *
+ * request.post('/')
+ * .type('xml')
+ * .send(xmlstring)
+ * .end(callback);
+ *
+ * request.post('/')
+ * .type('application/xml')
+ * .send(xmlstring)
+ * .end(callback);
+ *
+ * @param {String} type
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.type = function(type){
+ this.set('Content-Type', request.types[type] || type);
+ return this;
+};
+
+/**
+ * Set Accept to `type`, mapping values from `request.types`.
+ *
+ * Examples:
+ *
+ * superagent.types.json = 'application/json';
+ *
+ * request.get('/agent')
+ * .accept('json')
+ * .end(callback);
+ *
+ * request.get('/agent')
+ * .accept('application/json')
+ * .end(callback);
+ *
+ * @param {String} accept
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.accept = function(type){
+ this.set('Accept', request.types[type] || type);
+ return this;
+};
+
+/**
+ * Set Authorization field value with `user` and `pass`.
+ *
+ * @param {String} user
+ * @param {String} pass
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.auth = function(user, pass){
+ var str = btoa(user + ':' + pass);
+ this.set('Authorization', 'Basic ' + str);
+ return this;
+};
+
+/**
+* Add query-string `val`.
+*
+* Examples:
+*
+* request.get('/shoes')
+* .query('size=10')
+* .query({ color: 'blue' })
+*
+* @param {Object|String} val
+* @return {Request} for chaining
+* @api public
+*/
+
+Request.prototype.query = function(val){
+ if ('string' != typeof val) val = serialize(val);
+ if (val) this._query.push(val);
+ return this;
+};
+
+/**
+ * Write the field `name` and `val` for "multipart/form-data"
+ * request bodies.
+ *
+ * ``` js
+ * request.post('/upload')
+ * .field('foo', 'bar')
+ * .end(callback);
+ * ```
+ *
+ * @param {String} name
+ * @param {String|Blob|File} val
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.field = function(name, val){
+ if (!this._formData) this._formData = new root.FormData();
+ this._formData.append(name, val);
+ return this;
+};
+
+/**
+ * Queue the given `file` as an attachment to the specified `field`,
+ * with optional `filename`.
+ *
+ * ``` js
+ * request.post('/upload')
+ * .attach(new Blob(['hey! '], { type: "text/html"}))
+ * .end(callback);
+ * ```
+ *
+ * @param {String} field
+ * @param {Blob|File} file
+ * @param {String} filename
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.attach = function(field, file, filename){
+ if (!this._formData) this._formData = new root.FormData();
+ this._formData.append(field, file, filename);
+ return this;
+};
+
+/**
+ * Send `data`, defaulting the `.type()` to "json" when
+ * an object is given.
+ *
+ * Examples:
+ *
+ * // querystring
+ * request.get('/search')
+ * .end(callback)
+ *
+ * // multiple data "writes"
+ * request.get('/search')
+ * .send({ search: 'query' })
+ * .send({ range: '1..5' })
+ * .send({ order: 'desc' })
+ * .end(callback)
+ *
+ * // manual json
+ * request.post('/user')
+ * .type('json')
+ * .send('{"name":"tj"})
+ * .end(callback)
+ *
+ * // auto json
+ * request.post('/user')
+ * .send({ name: 'tj' })
+ * .end(callback)
+ *
+ * // manual x-www-form-urlencoded
+ * request.post('/user')
+ * .type('form')
+ * .send('name=tj')
+ * .end(callback)
+ *
+ * // auto x-www-form-urlencoded
+ * request.post('/user')
+ * .type('form')
+ * .send({ name: 'tj' })
+ * .end(callback)
+ *
+ * // defaults to x-www-form-urlencoded
+ * request.post('/user')
+ * .send('name=tobi')
+ * .send('species=ferret')
+ * .end(callback)
+ *
+ * @param {String|Object} data
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.send = function(data){
+ var obj = isObject(data);
+ var type = this.getHeader('Content-Type');
+
+ // merge
+ if (obj && isObject(this._data)) {
+ for (var key in data) {
+ this._data[key] = data[key];
+ }
+ } else if ('string' == typeof data) {
+ if (!type) this.type('form');
+ type = this.getHeader('Content-Type');
+ if ('application/x-www-form-urlencoded' == type) {
+ this._data = this._data
+ ? this._data + '&' + data
+ : data;
+ } else {
+ this._data = (this._data || '') + data;
+ }
+ } else {
+ this._data = data;
+ }
+
+ if (!obj || isHost(data)) return this;
+ if (!type) this.type('json');
+ return this;
+};
+
+/**
+ * Invoke the callback with `err` and `res`
+ * and handle arity check.
+ *
+ * @param {Error} err
+ * @param {Response} res
+ * @api private
+ */
+
+Request.prototype.callback = function(err, res){
+ var fn = this._callback;
+ this.clearTimeout();
+ fn(err, res);
+};
+
+/**
+ * Invoke callback with x-domain error.
+ *
+ * @api private
+ */
+
+Request.prototype.crossDomainError = function(){
+ var err = new Error('Origin is not allowed by Access-Control-Allow-Origin');
+ err.crossDomain = true;
+ this.callback(err);
+};
+
+/**
+ * Invoke callback with timeout error.
+ *
+ * @api private
+ */
+
+Request.prototype.timeoutError = function(){
+ var timeout = this._timeout;
+ var err = new Error('timeout of ' + timeout + 'ms exceeded');
+ err.timeout = timeout;
+ this.callback(err);
+};
+
+/**
+ * Enable transmission of cookies with x-domain requests.
+ *
+ * Note that for this to work the origin must not be
+ * using "Access-Control-Allow-Origin" with a wildcard,
+ * and also must set "Access-Control-Allow-Credentials"
+ * to "true".
+ *
+ * @api public
+ */
+
+Request.prototype.withCredentials = function(){
+ this._withCredentials = true;
+ return this;
+};
+
+/**
+ * Initiate request, invoking callback `fn(res)`
+ * with an instanceof `Response`.
+ *
+ * @param {Function} fn
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.end = function(fn){
+ var self = this;
+ var xhr = this.xhr = request.getXHR();
+ var query = this._query.join('&');
+ var timeout = this._timeout;
+ var data = this._formData || this._data;
+
+ // store callback
+ this._callback = fn || noop;
+
+ // state change
+ xhr.onreadystatechange = function(){
+ if (4 != xhr.readyState) return;
+
+ // In IE9, reads to any property (e.g. status) off of an aborted XHR will
+ // result in the error "Could not complete the operation due to error c00c023f"
+ var status;
+ try { status = xhr.status } catch(e) { status = 0; }
+
+ if (0 == status) {
+ if (self.timedout) return self.timeoutError();
+ if (self.aborted) return;
+ return self.crossDomainError();
+ }
+ self.emit('end');
+ };
+
+ // progress
+ var handleProgress = function(e){
+ if (e.total > 0) {
+ e.percent = e.loaded / e.total * 100;
+ }
+ self.emit('progress', e);
+ };
+ if (this.hasListeners('progress')) {
+ xhr.onprogress = handleProgress;
+ }
+ try {
+ if (xhr.upload && this.hasListeners('progress')) {
+ xhr.upload.onprogress = handleProgress;
+ }
+ } catch(e) {
+ // Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist.
+ // Reported here:
+ // https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web-worker-context
+ }
+
+ // timeout
+ if (timeout && !this._timer) {
+ this._timer = setTimeout(function(){
+ self.timedout = true;
+ self.abort();
+ }, timeout);
+ }
+
+ // querystring
+ if (query) {
+ query = request.serializeObject(query);
+ this.url += ~this.url.indexOf('?')
+ ? '&' + query
+ : '?' + query;
+ }
+
+ // initiate request
+ xhr.open(this.method, this.url, true);
+
+ // CORS
+ if (this._withCredentials) xhr.withCredentials = true;
+
+ // body
+ if ('GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !isHost(data)) {
+ // serialize stuff
+ var contentType = this.getHeader('Content-Type');
+ var serialize = request.serialize[contentType ? contentType.split(';')[0] : ''];
+ if (serialize) data = serialize(data);
+ }
+
+ // set header fields
+ for (var field in this.header) {
+ if (null == this.header[field]) continue;
+ xhr.setRequestHeader(field, this.header[field]);
+ }
+
+ // send stuff
+ this.emit('request', this);
+ xhr.send(data);
+ return this;
+};
+
+/**
+ * Faux promise support
+ *
+ * @param {Function} fulfill
+ * @param {Function} reject
+ * @return {Request}
+ */
+
+Request.prototype.then = function (fulfill, reject) {
+ return this.end(function(err, res) {
+ err ? reject(err) : fulfill(res);
+ });
+}
+
+/**
+ * Expose `Request`.
+ */
+
+request.Request = Request;
+
+/**
+ * Issue a request:
+ *
+ * Examples:
+ *
+ * request('GET', '/users').end(callback)
+ * request('/users').end(callback)
+ * request('/users', callback)
+ *
+ * @param {String} method
+ * @param {String|Function} url or callback
+ * @return {Request}
+ * @api public
+ */
+
+function request(method, url) {
+ // callback
+ if ('function' == typeof url) {
+ return new Request('GET', method).end(url);
+ }
+
+ // url first
+ if (1 == arguments.length) {
+ return new Request('GET', method);
+ }
+
+ return new Request(method, url);
+}
+
+/**
+ * GET `url` with optional callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed|Function} data or fn
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.get = function(url, data, fn){
+ var req = request('GET', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.query(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * HEAD `url` with optional callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed|Function} data or fn
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.head = function(url, data, fn){
+ var req = request('HEAD', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * DELETE `url` with optional callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.del = function(url, fn){
+ var req = request('DELETE', url);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * PATCH `url` with optional `data` and callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed} data
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.patch = function(url, data, fn){
+ var req = request('PATCH', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * POST `url` with optional `data` and callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed} data
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.post = function(url, data, fn){
+ var req = request('POST', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * PUT `url` with optional `data` and callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed|Function} data or fn
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.put = function(url, data, fn){
+ var req = request('PUT', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * Expose `request`.
+ */
+
+module.exports = request;
+
+},{"emitter":12,"reduce":13}],12:[function(require,module,exports){
+
+/**
+ * Expose `Emitter`.
+ */
+
+module.exports = Emitter;
+
+/**
+ * Initialize a new `Emitter`.
+ *
+ * @api public
+ */
+
+function Emitter(obj) {
+ if (obj) return mixin(obj);
+};
+
+/**
+ * Mixin the emitter properties.
+ *
+ * @param {Object} obj
+ * @return {Object}
+ * @api private
+ */
+
+function mixin(obj) {
+ for (var key in Emitter.prototype) {
+ obj[key] = Emitter.prototype[key];
+ }
+ return obj;
+}
+
+/**
+ * Listen on the given `event` with `fn`.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ * @return {Emitter}
+ * @api public
+ */
+
+Emitter.prototype.on =
+Emitter.prototype.addEventListener = function(event, fn){
+ this._callbacks = this._callbacks || {};
+ (this._callbacks[event] = this._callbacks[event] || [])
+ .push(fn);
+ return this;
+};
+
+/**
+ * Adds an `event` listener that will be invoked a single
+ * time then automatically removed.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ * @return {Emitter}
+ * @api public
+ */
+
+Emitter.prototype.once = function(event, fn){
+ var self = this;
+ this._callbacks = this._callbacks || {};
+
+ function on() {
+ self.off(event, on);
+ fn.apply(this, arguments);
+ }
+
+ on.fn = fn;
+ this.on(event, on);
+ return this;
+};
+
+/**
+ * Remove the given callback for `event` or all
+ * registered callbacks.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ * @return {Emitter}
+ * @api public
+ */
+
+Emitter.prototype.off =
+Emitter.prototype.removeListener =
+Emitter.prototype.removeAllListeners =
+Emitter.prototype.removeEventListener = function(event, fn){
+ this._callbacks = this._callbacks || {};
+
+ // all
+ if (0 == arguments.length) {
+ this._callbacks = {};
+ return this;
+ }
+
+ // specific event
+ var callbacks = this._callbacks[event];
+ if (!callbacks) return this;
+
+ // remove all handlers
+ if (1 == arguments.length) {
+ delete this._callbacks[event];
+ return this;
+ }
+
+ // remove specific handler
+ var cb;
+ for (var i = 0; i < callbacks.length; i++) {
+ cb = callbacks[i];
+ if (cb === fn || cb.fn === fn) {
+ callbacks.splice(i, 1);
+ break;
+ }
+ }
+ return this;
+};
+
+/**
+ * Emit `event` with the given args.
+ *
+ * @param {String} event
+ * @param {Mixed} ...
+ * @return {Emitter}
+ */
+
+Emitter.prototype.emit = function(event){
+ this._callbacks = this._callbacks || {};
+ var args = [].slice.call(arguments, 1)
+ , callbacks = this._callbacks[event];
+
+ if (callbacks) {
+ callbacks = callbacks.slice(0);
+ for (var i = 0, len = callbacks.length; i < len; ++i) {
+ callbacks[i].apply(this, args);
+ }
+ }
+
+ return this;
+};
+
+/**
+ * Return array of callbacks for `event`.
+ *
+ * @param {String} event
+ * @return {Array}
+ * @api public
+ */
+
+Emitter.prototype.listeners = function(event){
+ this._callbacks = this._callbacks || {};
+ return this._callbacks[event] || [];
+};
+
+/**
+ * Check if this emitter has `event` handlers.
+ *
+ * @param {String} event
+ * @return {Boolean}
+ * @api public
+ */
+
+Emitter.prototype.hasListeners = function(event){
+ return !! this.listeners(event).length;
+};
+
+},{}],13:[function(require,module,exports){
+
+/**
+ * Reduce `arr` with `fn`.
+ *
+ * @param {Array} arr
+ * @param {Function} fn
+ * @param {Mixed} initial
+ *
+ * TODO: combatible error handling?
+ */
+
+module.exports = function(arr, fn, initial){
+ var idx = 0;
+ var len = arr.length;
+ var curr = arguments.length == 3
+ ? initial
+ : arr[idx++];
+
+ while (idx < len) {
+ curr = fn.call(null, curr, arr[idx], ++idx, arr);
+ }
+
+ return curr;
+};
+},{}],14:[function(require,module,exports){
+
+/**
+ * Module dependencies.
+ */
+
+var global = (function() { return this; })();
+
+/**
+ * WebSocket constructor.
+ */
+
+var WebSocket = global.WebSocket || global.MozWebSocket;
+
+/**
+ * Module exports.
+ */
+
+module.exports = WebSocket ? ws : null;
+
+/**
+ * WebSocket constructor.
+ *
+ * The third `opts` options object gets ignored in web browsers, since it's
+ * non-standard, and throws a TypeError if passed to the constructor.
+ * See: https://github.com/einaros/ws/issues/227
+ *
+ * @param {String} uri
+ * @param {Array} protocols (optional)
+ * @param {Object) opts (optional)
+ * @api public
+ */
+
+function ws(uri, protocols, opts) {
+ var instance;
+ if (protocols) {
+ instance = new WebSocket(uri, protocols);
+ } else {
+ instance = new WebSocket(uri);
+ }
+ return instance;
+}
+
+if (WebSocket) ws.prototype = WebSocket.prototype;
+
+},{}]},{},[5])(5)
+});
\ No newline at end of file
diff --git a/web-dist/discord.3.3.2.js b/web-dist/discord.3.3.2.js
new file mode 100644
index 000000000..ee7512e4b
--- /dev/null
+++ b/web-dist/discord.3.3.2.js
@@ -0,0 +1,3593 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Discord = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o]*>/g) || [])[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var mention = _step3.value;
+
+ _mentions.push(mention.substring(2, mention.length - 1));
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3["return"]) {
+ _iterator3["return"]();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ return _mentions;
+ }
+ });
+
+ return prom;
+ }
+
+ //def createws
+ }, {
+ key: "createws",
+ value: function createws(url) {
+ if (this.websocket) return false;
+
+ var self = this;
+
+ //good to go
+ this.websocket = new WebSocket(url);
+
+ //open
+ this.websocket.onopen = function () {
+ self.trySendConnData(); //try connecting
+ };
+
+ //close
+ this.websocket.onclose = function () {
+ self.trigger("disconnected");
+ };
+
+ //message
+ this.websocket.onmessage = function (e) {
+
+ var dat = false,
+ data = {};
+
+ try {
+ dat = JSON.parse(e.data);
+ data = dat.d;
+ } catch (err) {
+ self.trigger("error", err, e);
+ return;
+ }
+
+ //valid message
+ switch (dat.t) {
+
+ case "READY":
+ self.debug("received ready packet");
+
+ self.user = self.addUser(data.user);
+
+ var _iteratorNormalCompletion4 = true;
+ var _didIteratorError4 = false;
+ var _iteratorError4 = undefined;
+
+ try {
+ for (var _iterator4 = data.guilds[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
+ var _server = _step4.value;
+
+ var server = self.addServer(_server);
+ }
+ } catch (err) {
+ _didIteratorError4 = true;
+ _iteratorError4 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion4 && _iterator4["return"]) {
+ _iterator4["return"]();
+ }
+ } finally {
+ if (_didIteratorError4) {
+ throw _iteratorError4;
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion5 = true;
+ var _didIteratorError5 = false;
+ var _iteratorError5 = undefined;
+
+ try {
+ for (var _iterator5 = data.private_channels[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
+ var _pmc = _step5.value;
+
+ var pmc = self.addPMChannel(_pmc);
+ }
+ } catch (err) {
+ _didIteratorError5 = true;
+ _iteratorError5 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion5 && _iterator5["return"]) {
+ _iterator5["return"]();
+ }
+ } finally {
+ if (_didIteratorError5) {
+ throw _iteratorError5;
+ }
+ }
+ }
+
+ self.trigger("ready");
+ self.readyTime = Date.now();
+ self.debug("cached " + self.serverCache.length + " servers, " + self.channelCache.length + " channels, " + self.pmChannelCache.length + " PMs and " + self.userCache.length + " users.");
+ self.state = 3;
+ setInterval(function () {
+ self.keepAlive.apply(self);
+ }, data.heartbeat_interval);
+
+ break;
+ case "MESSAGE_CREATE":
+ self.debug("received message");
+
+ var mentions = [];
+ data.mentions = data.mentions || []; //for some reason this was not defined at some point?
+ var _iteratorNormalCompletion6 = true;
+ var _didIteratorError6 = false;
+ var _iteratorError6 = undefined;
+
+ try {
+ for (var _iterator6 = data.mentions[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
+ var mention = _step6.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError6 = true;
+ _iteratorError6 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion6 && _iterator6["return"]) {
+ _iterator6["return"]();
+ }
+ } finally {
+ if (_didIteratorError6) {
+ throw _iteratorError6;
+ }
+ }
+ }
+
+ var channel = self.getChannel("id", data.channel_id);
+ if (channel) {
+ var msg = channel.addMessage(new Message(data, channel, mentions, self.addUser(data.author)));
+ self.trigger("message", msg);
+ }
+
+ break;
+ case "MESSAGE_DELETE":
+ self.debug("message deleted");
+
+ var channel = self.getChannel("id", data.channel_id);
+ var message = channel.getMessage("id", data.id);
+ if (message) {
+ self.trigger("messageDelete", channel, message);
+ channel.messages.splice(channel.messages.indexOf(message), 1);
+ } else {
+ //don't have the cache of that message ;(
+ self.trigger("messageDelete", channel);
+ }
+ break;
+ case "MESSAGE_UPDATE":
+ self.debug("message updated");
+
+ var channel = self.getChannel("id", data.channel_id);
+ var formerMessage = channel.getMessage("id", data.id);
+
+ if (formerMessage) {
+
+ //new message might be partial, so we need to fill it with whatever the old message was.
+ var info = {};
+
+ for (var key in formerMessage) {
+ info[key] = formerMessage[key];
+ }
+
+ for (var key in data) {
+ info[key] = data[key];
+ }
+
+ var mentions = [];
+ var _iteratorNormalCompletion7 = true;
+ var _didIteratorError7 = false;
+ var _iteratorError7 = undefined;
+
+ try {
+ for (var _iterator7 = info.mentions[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
+ var mention = _step7.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError7 = true;
+ _iteratorError7 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion7 && _iterator7["return"]) {
+ _iterator7["return"]();
+ }
+ } finally {
+ if (_didIteratorError7) {
+ throw _iteratorError7;
+ }
+ }
+ }
+
+ var newMessage = new Message(info, channel, mentions, formerMessage.author);
+
+ self.trigger("messageUpdate", newMessage, formerMessage);
+
+ channel.messages[channel.messages.indexOf(formerMessage)] = newMessage;
+ }
+
+ // message isn't in cache, and if it's a partial it could cause
+ // all hell to break loose... best to just act as if nothing happened
+
+ break;
+
+ case "GUILD_DELETE":
+
+ var server = self.getServer("id", data.id);
+
+ if (server) {
+ self.serverCache.splice(self.serverCache.indexOf(server), 1);
+ self.trigger("serverDelete", server);
+ }
+
+ break;
+
+ case "CHANNEL_DELETE":
+
+ var channel = self.getChannel("id", data.id);
+
+ if (channel) {
+
+ var server = channel.server;
+
+ if (server) {
+
+ server.channels.splice(server.channels.indexOf(channel), 1);
+ }
+
+ self.trigger("channelDelete", channel);
+
+ self.serverCache.splice(self.serverCache.indexOf(channel), 1);
+ }
+
+ break;
+
+ case "GUILD_CREATE":
+
+ var server = self.getServer("id", data.id);
+
+ if (!server) {
+ //if server doesn't already exist because duh
+ server = self.addServer(data);
+ } /*else if(server.channels.length === 0){
+
+ var srv = new Server(data, self);
+ for(channel of data.channels){
+ srv.channels.push(new Channel(channel, data.id));
+ }
+ self.serverCache[self.serverCache.indexOf(server)] = srv;
+
+ }*/
+
+ if (self.serverCreateListener.get(data.id)) {
+ var cbs = self.serverCreateListener.get(data.id);
+ cbs[0](server); //promise then callback
+ cbs[1](null, server); //legacy callback
+ self.serverCreateListener["delete"](data.id);
+ }
+
+ self.trigger("serverCreate", server);
+
+ break;
+
+ case "CHANNEL_CREATE":
+
+ var channel = self.getChannel("id", data.id);
+
+ if (!channel) {
+
+ var chann = self.addChannel(data, data.guild_id);
+ var srv = self.getServer("id", data.guild_id);
+ if (srv) {
+ srv.addChannel(chann);
+ }
+ self.trigger("channelCreate", chann);
+ }
+
+ break;
+
+ case "GUILD_MEMBER_ADD":
+
+ var server = self.getServer("id", data.guild_id);
+
+ if (server) {
+
+ var user = self.addUser(data.user); //if for whatever reason it doesn't exist..
+
+ if (! ~server.members.indexOf(user)) {
+ server.members.push(user);
+ }
+
+ self.trigger("serverNewMember", user, server);
+ }
+
+ break;
+
+ case "GUILD_MEMBER_REMOVE":
+
+ var server = self.getServer("id", data.guild_id);
+
+ if (server) {
+
+ var user = self.addUser(data.user); //if for whatever reason it doesn't exist..
+
+ if (~server.members.indexOf(user)) {
+ server.members.splice(server.members.indexOf(user), 1);
+ }
+
+ self.trigger("serverRemoveMember", user, server);
+ }
+
+ break;
+
+ case "USER_UPDATE":
+
+ if (self.user && data.id === self.user.id) {
+
+ var newUser = new User(data); //not actually adding to the cache
+
+ self.trigger("userUpdate", newUser, self.user);
+
+ if (~self.userCache.indexOf(self.user)) {
+ self.userCache[self.userCache.indexOf(self.user)] = newUser;
+ }
+
+ self.user = newUser;
+ }
+
+ break;
+
+ case "PRESENCE_UPDATE":
+
+ var userInCache = self.getUser("id", data.user.id);
+
+ if (userInCache) {
+ //user exists
+ var presenceUser = new User(data.user);
+ if (presenceUser.equalsStrict(userInCache)) {
+ //they're exactly the same, an actual presence update
+ self.trigger("presence", {
+ user: userInCache,
+ status: data.status,
+ server: self.getServer("id", data.guild_id),
+ gameId: data.game_id
+ });
+ } else {
+ //one of their details changed.
+ self.trigger("userUpdate", userInCache, presenceUser);
+ self.userCache[self.userCache.indexOf(userInCache)] = presenceUser;
+ }
+ }
+
+ break;
+
+ default:
+ self.debug("received unknown packet");
+ self.trigger("unknown", dat);
+ break;
+
+ }
+ };
+ }
+
+ //def addUser
+ }, {
+ key: "addUser",
+ value: function addUser(data) {
+ if (!this.getUser("id", data.id)) {
+ this.userCache.push(new User(data));
+ }
+ return this.getUser("id", data.id);
+ }
+
+ //def addChannel
+ }, {
+ key: "addChannel",
+ value: function addChannel(data, serverId) {
+ if (!this.getChannel("id", data.id)) {
+ this.channelCache.push(new Channel(data, this.getServer("id", serverId)));
+ }
+ return this.getChannel("id", data.id);
+ }
+ }, {
+ key: "addPMChannel",
+ value: function addPMChannel(data) {
+ if (!this.getPMChannel("id", data.id)) {
+ this.pmChannelCache.push(new PMChannel(data, this));
+ }
+ return this.getPMChannel("id", data.id);
+ }
+
+ //def addServer
+ }, {
+ key: "addServer",
+ value: function addServer(data) {
+
+ var server = this.getServer("id", data.id);
+
+ if (!server) {
+ server = new Server(data, this);
+ this.serverCache.push(server);
+ if (data.channels) {
+ var _iteratorNormalCompletion8 = true;
+ var _didIteratorError8 = false;
+ var _iteratorError8 = undefined;
+
+ try {
+ for (var _iterator8 = data.channels[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
+ var channel = _step8.value;
+
+ server.channels.push(this.addChannel(channel, server.id));
+ }
+ } catch (err) {
+ _didIteratorError8 = true;
+ _iteratorError8 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion8 && _iterator8["return"]) {
+ _iterator8["return"]();
+ }
+ } finally {
+ if (_didIteratorError8) {
+ throw _iteratorError8;
+ }
+ }
+ }
+ }
+ }
+
+ return server;
+ }
+
+ //def getUser
+ }, {
+ key: "getUser",
+ value: function getUser(key, value) {
+ var _iteratorNormalCompletion9 = true;
+ var _didIteratorError9 = false;
+ var _iteratorError9 = undefined;
+
+ try {
+ for (var _iterator9 = this.userCache[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
+ var user = _step9.value;
+
+ if (user[key] === value) {
+ return user;
+ }
+ }
+ } catch (err) {
+ _didIteratorError9 = true;
+ _iteratorError9 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion9 && _iterator9["return"]) {
+ _iterator9["return"]();
+ }
+ } finally {
+ if (_didIteratorError9) {
+ throw _iteratorError9;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def getChannel
+ }, {
+ key: "getChannel",
+ value: function getChannel(key, value) {
+ var _iteratorNormalCompletion10 = true;
+ var _didIteratorError10 = false;
+ var _iteratorError10 = undefined;
+
+ try {
+ for (var _iterator10 = this.channelCache[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
+ var channel = _step10.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError10 = true;
+ _iteratorError10 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion10 && _iterator10["return"]) {
+ _iterator10["return"]();
+ }
+ } finally {
+ if (_didIteratorError10) {
+ throw _iteratorError10;
+ }
+ }
+ }
+
+ return this.getPMChannel(key, value); //might be a PM
+ }
+ }, {
+ key: "getPMChannel",
+ value: function getPMChannel(key, value) {
+ var _iteratorNormalCompletion11 = true;
+ var _didIteratorError11 = false;
+ var _iteratorError11 = undefined;
+
+ try {
+ for (var _iterator11 = this.pmChannelCache[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
+ var channel = _step11.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError11 = true;
+ _iteratorError11 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion11 && _iterator11["return"]) {
+ _iterator11["return"]();
+ }
+ } finally {
+ if (_didIteratorError11) {
+ throw _iteratorError11;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def getServer
+ }, {
+ key: "getServer",
+ value: function getServer(key, value) {
+ var _iteratorNormalCompletion12 = true;
+ var _didIteratorError12 = false;
+ var _iteratorError12 = undefined;
+
+ try {
+ for (var _iterator12 = this.serverCache[Symbol.iterator](), _step12; !(_iteratorNormalCompletion12 = (_step12 = _iterator12.next()).done); _iteratorNormalCompletion12 = true) {
+ var server = _step12.value;
+
+ if (server[key] === value) {
+ return server;
+ }
+ }
+ } catch (err) {
+ _didIteratorError12 = true;
+ _iteratorError12 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion12 && _iterator12["return"]) {
+ _iterator12["return"]();
+ }
+ } finally {
+ if (_didIteratorError12) {
+ throw _iteratorError12;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def trySendConnData
+ }, {
+ key: "trySendConnData",
+ value: function trySendConnData() {
+
+ if (this.token && !this.alreadySentData) {
+
+ this.alreadySentData = true;
+
+ var data = {
+ op: 2,
+ d: {
+ token: this.token,
+ v: 2,
+ properties: {
+ "$os": "discord.js",
+ "$browser": "discord.js",
+ "$device": "discord.js",
+ "$referrer": "",
+ "$referring_domain": ""
+ }
+ }
+ };
+ this.websocket.send(JSON.stringify(data));
+ }
+ }
+ }, {
+ key: "resolveServerID",
+ value: function resolveServerID(resource) {
+
+ if (resource instanceof Server) {
+ return resource.id;
+ } else if (!isNaN(resource) && resource.length && resource.length === 17) {
+ return resource;
+ }
+ }
+ }, {
+ key: "resolveDestination",
+ value: function resolveDestination(destination) {
+ var channId = false;
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ if (destination instanceof Server) {
+ channId = destination.id; //general is the same as server id
+ } else if (destination instanceof Channel) {
+ channId = destination.id;
+ } else if (destination instanceof Message) {
+ channId = destination.channel.id;
+ } else if (destination instanceof User) {
+
+ //check if we have a PM
+ var _iteratorNormalCompletion13 = true;
+ var _didIteratorError13 = false;
+ var _iteratorError13 = undefined;
+
+ try {
+ for (var _iterator13 = self.pmChannelCache[Symbol.iterator](), _step13; !(_iteratorNormalCompletion13 = (_step13 = _iterator13.next()).done); _iteratorNormalCompletion13 = true) {
+ var pmc = _step13.value;
+
+ if (pmc.user.equals(destination)) {
+ resolve(pmc.id);
+ return;
+ }
+ }
+
+ //we don't, at this point we're late
+ } catch (err) {
+ _didIteratorError13 = true;
+ _iteratorError13 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion13 && _iterator13["return"]) {
+ _iterator13["return"]();
+ }
+ } finally {
+ if (_didIteratorError13) {
+ throw _iteratorError13;
+ }
+ }
+ }
+
+ self.startPM(destination).then(function (pmc) {
+ console.log(pmc);
+ resolve(pmc.id);
+ })["catch"](reject);
+ } else {
+ channId = destination;
+ }
+ if (channId) resolve(channId);
+ });
+ }
+ }, {
+ key: "_sendMessage",
+ value: function _sendMessage(destination, content, tts, mentions) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request.post(Endpoints.CHANNELS + "/" + destination + "/messages").set("authorization", self.token).send({
+ content: content,
+ mentions: mentions,
+ tts: tts
+ }).end(function (err, res) {
+
+ if (err) {
+ reject(err);
+ } else {
+ var data = res.body;
+
+ var mentions = [];
+
+ data.mentions = data.mentions || []; //for some reason this was not defined at some point?
+
+ var _iteratorNormalCompletion14 = true;
+ var _didIteratorError14 = false;
+ var _iteratorError14 = undefined;
+
+ try {
+ for (var _iterator14 = data.mentions[Symbol.iterator](), _step14; !(_iteratorNormalCompletion14 = (_step14 = _iterator14.next()).done); _iteratorNormalCompletion14 = true) {
+ var mention = _step14.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError14 = true;
+ _iteratorError14 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion14 && _iterator14["return"]) {
+ _iterator14["return"]();
+ }
+ } finally {
+ if (_didIteratorError14) {
+ throw _iteratorError14;
+ }
+ }
+ }
+
+ var channel = self.getChannel("id", data.channel_id);
+ if (channel) {
+ var msg = channel.addMessage(new Message(data, channel, mentions, self.addUser(data.author)));
+ resolve(msg);
+ }
+ }
+ });
+ });
+ }
+ }, {
+ key: "_sendFile",
+ value: function _sendFile(destination, attachment) {
+ var attachmentName = arguments.length <= 2 || arguments[2] === undefined ? "DEFAULT BECAUSE YOU DIDN'T SPECIFY WHY.png" : arguments[2];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request.post(Endpoints.CHANNELS + "/" + destination + "/messages").set("authorization", self.token).attach("file", attachment, attachmentName).end(function (err, res) {
+
+ if (err) {
+ reject(err);
+ } else {
+
+ var chann = self.getChannel("id", destination);
+ if (chann) {
+ var msg = chann.addMessage(new Message(res.body, chann, [], self.user));
+ resolve(msg);
+ }
+ }
+ });
+ });
+ }
+ }, {
+ key: "_updateMessage",
+ value: function _updateMessage(message, content) {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ request.patch(Endpoints.CHANNELS + "/" + message.channel.id + "/messages/" + message.id).set("authorization", self.token).send({
+ content: content,
+ mentions: []
+ }).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ var msg = new Message(res.body, message.channel, message.mentions, message.sender);
+ resolve(msg);
+ message.channel.messages[message.channel.messages.indexOf(message)] = msg;
+ }
+ });
+ });
+ }
+ }, {
+ key: "_deleteMessage",
+ value: function _deleteMessage(message) {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+
+ request.del(Endpoints.CHANNELS + "/" + message.channel.id + "/messages/" + message.id).set("authorization", self.token).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve();
+ }
+ });
+ });
+ }
+ }, {
+ key: "checkQueue",
+ value: function checkQueue(channelID) {
+ var _this = this;
+
+ var self = this;
+
+ if (!this.checkingQueue[channelID]) {
+ (function () {
+ var doNext = function doNext() {
+ if (self.queue[channelID].length === 0) {
+ done();
+ return;
+ }
+ var queuedEvent = self.queue[channelID][0];
+ switch (queuedEvent.action) {
+ case "sendMessage":
+ var msgToSend = queuedEvent;
+ self._sendMessage(channelID, msgToSend.content, msgToSend.tts, msgToSend.mentions).then(function (msg) {
+ msgToSend.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToSend.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "sendFile":
+ var fileToSend = queuedEvent;
+ self._sendFile(channelID, fileToSend.attachment, fileToSend.attachmentName).then(function (msg) {
+ fileToSend.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ fileToSend.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "updateMessage":
+ var msgToUpd = queuedEvent;
+ self._updateMessage(msgToUpd.message, msgToUpd.content).then(function (msg) {
+ msgToUpd.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToUpd.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "deleteMessage":
+ var msgToDel = queuedEvent;
+ self._deleteMessage(msgToDel.message).then(function (msg) {
+ msgToDel.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToDel.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ default:
+ done();
+ break;
+ }
+ };
+
+ var done = function done() {
+ self.checkingQueue[channelID] = false;
+ return;
+ };
+
+ //if we aren't already checking this queue.
+ _this.checkingQueue[channelID] = true;
+ doNext();
+ })();
+ }
+ }
+ }, {
+ key: "uptime",
+ get: function get() {
+
+ return this.readyTime ? Date.now() - this.readyTime : null;
+ }
+ }, {
+ key: "ready",
+ get: function get() {
+ return this.state === 3;
+ }
+ }, {
+ key: "servers",
+ get: function get() {
+ return this.serverCache;
+ }
+ }, {
+ key: "channels",
+ get: function get() {
+ return this.channelCache;
+ }
+ }, {
+ key: "users",
+ get: function get() {
+ return this.userCache;
+ }
+ }, {
+ key: "PMChannels",
+ get: function get() {
+ return this.pmChannelCache;
+ }
+ }, {
+ key: "messages",
+ get: function get() {
+
+ var msgs = [];
+ var _iteratorNormalCompletion15 = true;
+ var _didIteratorError15 = false;
+ var _iteratorError15 = undefined;
+
+ try {
+ for (var _iterator15 = this.channelCache[Symbol.iterator](), _step15; !(_iteratorNormalCompletion15 = (_step15 = _iterator15.next()).done); _iteratorNormalCompletion15 = true) {
+ var channel = _step15.value;
+
+ msgs = msgs.concat(channel.messages);
+ }
+ } catch (err) {
+ _didIteratorError15 = true;
+ _iteratorError15 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion15 && _iterator15["return"]) {
+ _iterator15["return"]();
+ }
+ } finally {
+ if (_didIteratorError15) {
+ throw _iteratorError15;
+ }
+ }
+ }
+
+ return msgs;
+ }
+ }]);
+
+ return Client;
+})();
+
+function getGateway() {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request.get(Endpoints.API + "/gateway").end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(res.body.url);
+ }
+ });
+ });
+}
+
+module.exports = Client;
+},{"./Endpoints.js":2,"./PMChannel.js":3,"./channel.js":4,"./invite.js":6,"./message.js":7,"./server.js":8,"./user.js":9,"fs":10,"superagent":11,"ws":14}],2:[function(require,module,exports){
+"use strict";
+
+exports.BASE_DOMAIN = "discordapp.com";
+exports.BASE = "https://" + exports.BASE_DOMAIN;
+exports.WEBSOCKET_HUB = "wss://" + exports.BASE_DOMAIN + "/hub";
+
+exports.API = exports.BASE + "/api";
+exports.AUTH = exports.API + "/auth";
+exports.LOGIN = exports.AUTH + "/login";
+exports.LOGOUT = exports.AUTH + "/logout";
+exports.USERS = exports.API + "/users";
+exports.SERVERS = exports.API + "/guilds";
+exports.CHANNELS = exports.API + "/channels";
+},{}],3:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var PMChannel = (function () {
+ function PMChannel(data, client) {
+ _classCallCheck(this, PMChannel);
+
+ this.user = client.getUser("id", data.recipient.id);
+ this.id = data.id;
+ this.messages = [];
+ }
+
+ _createClass(PMChannel, [{
+ key: "addMessage",
+ value: function addMessage(data) {
+ if (!this.getMessage("id", data.id)) {
+ this.messages.push(data);
+ }
+ return this.getMessage("id", data.id);
+ }
+ }, {
+ key: "getMessage",
+ value: function getMessage(key, value) {
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.messages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var message = _step.value;
+
+ if (message[key] === value) {
+ return message;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return true;
+ }
+ }]);
+
+ return PMChannel;
+})();
+
+module.exports = PMChannel;
+},{}],4:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Channel = (function () {
+ function Channel(data, server) {
+ _classCallCheck(this, Channel);
+
+ this.server = server;
+ this.name = data.name;
+ this.type = data.type;
+ this.id = data.id;
+ this.messages = [];
+ //this.isPrivate = isPrivate; //not sure about the implementation of this...
+ }
+
+ _createClass(Channel, [{
+ key: "equals",
+ value: function equals(object) {
+ return object && object.id === this.id;
+ }
+ }, {
+ key: "addMessage",
+ value: function addMessage(data) {
+ if (!this.getMessage("id", data.id)) {
+ this.messages.push(data);
+ }
+ return this.getMessage("id", data.id);
+ }
+ }, {
+ key: "getMessage",
+ value: function getMessage(key, value) {
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.messages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var message = _step.value;
+
+ if (message[key] === value) {
+ return message;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ return "#" + this.name;
+ }
+ }, {
+ key: "client",
+ get: function get() {
+ return this.server.client;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return false;
+ }
+ }]);
+
+ return Channel;
+})();
+
+module.exports = Channel;
+},{}],5:[function(require,module,exports){
+"use strict";
+
+var request = require("superagent");
+var Endpoints = require("./Endpoints.js");
+var Client = require("./Client.js");
+
+var Discord = {
+ Endpoints: Endpoints,
+ Client: Client
+};
+
+module.exports = Discord;
+},{"./Client.js":1,"./Endpoints.js":2,"superagent":11}],6:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Invite = (function () {
+ function Invite(data, client) {
+ _classCallCheck(this, Invite);
+
+ this.max_age = data.max_age;
+ this.code = data.code;
+ this.server = client.getServer("id", data.guild.id);
+ this.revoked = data.revoked;
+ this.created_at = Date.parse(data.created_at);
+ this.temporary = data.temporary;
+ this.uses = data.uses;
+ this.max_uses = data.uses;
+ this.inviter = client.addUser(data.inviter);
+ this.xkcd = data.xkcdpass;
+ this.channel = client.getChannel("id", data.channel.id);
+ }
+
+ _createClass(Invite, [{
+ key: "URL",
+ get: function get() {
+ var code = this.xkcd ? this.xkcdpass : this.code;
+ return "https://discord.gg/" + code;
+ }
+ }]);
+
+ return Invite;
+})();
+
+module.exports = Invite;
+},{}],7:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var PMChannel = require("./PMChannel.js");
+
+var Message = (function () {
+ function Message(data, channel, mentions, author) {
+ _classCallCheck(this, Message);
+
+ this.tts = data.tts;
+ this.timestamp = Date.parse(data.timestamp);
+ this.nonce = data.nonce;
+ this.mentions = mentions;
+ this.everyoneMentioned = data.mention_everyone;
+ this.id = data.id;
+ this.embeds = data.embeds;
+ this.editedTimestamp = data.edited_timestamp;
+ this.content = data.content.trim();
+ this.channel = channel;
+ this.author = author;
+ this.attachments = data.attachments;
+ }
+
+ /*exports.Message.prototype.isPM = function() {
+ return ( this.channel instanceof PMChannel );
+ }*/
+
+ _createClass(Message, [{
+ key: "isMentioned",
+ value: function isMentioned(user) {
+ var id = user.id ? user.id : user;
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.mentions[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var mention = _step.value;
+
+ if (mention.id === id) {
+ return true;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return false;
+ }
+ }, {
+ key: "sender",
+ get: function get() {
+ return this.author;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return this.channel.isPrivate;
+ }
+ }]);
+
+ return Message;
+})();
+
+module.exports = Message;
+},{"./PMChannel.js":3}],8:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Server = (function () {
+ function Server(data, client) {
+ _classCallCheck(this, Server);
+
+ this.client = client;
+ this.region = data.region;
+ this.ownerID = data.owner_id;
+ this.name = data.name;
+ this.id = data.id;
+ this.members = [];
+ this.channels = [];
+ this.icon = data.icon;
+ this.afkTimeout = data.afk_timeout;
+ this.afkChannelId = data.afk_channel_id;
+
+ if (!data.members) {
+ data.members = [client.user];
+ return;
+ }
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = data.members[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var member = _step.value;
+
+ // first we cache the user in our Discord Client,
+ // then we add it to our list. This way when we
+ // get a user from this server's member list,
+ // it will be identical (unless an async change occurred)
+ // to the client's cache.
+ if (member.user) this.members.push(client.addUser(member.user));
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+ }
+
+ _createClass(Server, [{
+ key: "getChannel",
+
+ // get/set
+ value: function getChannel(key, value) {
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = this.channels[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var channel = _step2.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2["return"]) {
+ _iterator2["return"]();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "getMember",
+ value: function getMember(key, value) {
+ var _iteratorNormalCompletion3 = true;
+ var _didIteratorError3 = false;
+ var _iteratorError3 = undefined;
+
+ try {
+ for (var _iterator3 = this.members[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var member = _step3.value;
+
+ if (member[key] === value) {
+ return member;
+ }
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3["return"]) {
+ _iterator3["return"]();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "addChannel",
+ value: function addChannel(chann) {
+ if (!this.getChannel("id", chann.id)) {
+ this.channels.push(chann);
+ }
+ return chann;
+ }
+ }, {
+ key: "addMember",
+ value: function addMember(member) {
+ if (!this.getMember("id", member.id)) {
+ this.members.push(member);
+ }
+ return member;
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ return this.name;
+ }
+ }, {
+ key: "iconURL",
+ get: function get() {
+ if (!this.icon) return null;
+ return "https://discordapp.com/api/guilds/" + this.id + "/icons/" + this.icon + ".jpg";
+ }
+ }, {
+ key: "afkChannel",
+ get: function get() {
+ if (!this.afkChannelId) return false;
+
+ return this.getChannel("id", this.afkChannelId);
+ }
+ }, {
+ key: "defaultChannel",
+ get: function get() {
+ return this.getChannel("name", "general");
+ }
+ }, {
+ key: "owner",
+ get: function get() {
+ return this.client.getUser("id", this.ownerID);
+ }
+ }]);
+
+ return Server;
+})();
+
+module.exports = Server;
+},{}],9:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var User = (function () {
+ function User(data) {
+ _classCallCheck(this, User);
+
+ this.username = data.username;
+ this.discriminator = data.discriminator;
+ this.id = data.id;
+ this.avatar = data.avatar;
+ }
+
+ // access using user.avatarURL;
+
+ _createClass(User, [{
+ key: "mention",
+ value: function mention() {
+ return "<@" + this.id + ">";
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ /*
+ if we embed a user in a String - like so:
+ "Yo " + user + " what's up?"
+ It would generate something along the lines of:
+ "Yo @hydrabolt what's up?"
+ */
+ return this.mention();
+ }
+ }, {
+ key: "equals",
+ value: function equals(object) {
+ return object.id === this.id;
+ }
+ }, {
+ key: "equalsStrict",
+ value: function equalsStrict(object) {
+ return object.id === this.id && object.avatar === this.avatar && object.username === this.username && object.discriminator === this.discriminator;
+ }
+ }, {
+ key: "avatarURL",
+ get: function get() {
+ if (!this.avatar) return null;
+ return "https://discordapp.com/api/users/" + this.id + "/avatars/" + this.avatar + ".jpg";
+ }
+ }]);
+
+ return User;
+})();
+
+module.exports = User;
+},{}],10:[function(require,module,exports){
+
+},{}],11:[function(require,module,exports){
+/**
+ * Module dependencies.
+ */
+
+var Emitter = require('emitter');
+var reduce = require('reduce');
+
+/**
+ * Root reference for iframes.
+ */
+
+var root = 'undefined' == typeof window
+ ? (this || self)
+ : window;
+
+/**
+ * Noop.
+ */
+
+function noop(){};
+
+/**
+ * Check if `obj` is a host object,
+ * we don't want to serialize these :)
+ *
+ * TODO: future proof, move to compoent land
+ *
+ * @param {Object} obj
+ * @return {Boolean}
+ * @api private
+ */
+
+function isHost(obj) {
+ var str = {}.toString.call(obj);
+
+ switch (str) {
+ case '[object File]':
+ case '[object Blob]':
+ case '[object FormData]':
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Determine XHR.
+ */
+
+request.getXHR = function () {
+ if (root.XMLHttpRequest
+ && (!root.location || 'file:' != root.location.protocol
+ || !root.ActiveXObject)) {
+ return new XMLHttpRequest;
+ } else {
+ try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {}
+ }
+ return false;
+};
+
+/**
+ * Removes leading and trailing whitespace, added to support IE.
+ *
+ * @param {String} s
+ * @return {String}
+ * @api private
+ */
+
+var trim = ''.trim
+ ? function(s) { return s.trim(); }
+ : function(s) { return s.replace(/(^\s*|\s*$)/g, ''); };
+
+/**
+ * Check if `obj` is an object.
+ *
+ * @param {Object} obj
+ * @return {Boolean}
+ * @api private
+ */
+
+function isObject(obj) {
+ return obj === Object(obj);
+}
+
+/**
+ * Serialize the given `obj`.
+ *
+ * @param {Object} obj
+ * @return {String}
+ * @api private
+ */
+
+function serialize(obj) {
+ if (!isObject(obj)) return obj;
+ var pairs = [];
+ for (var key in obj) {
+ if (null != obj[key]) {
+ pairs.push(encodeURIComponent(key)
+ + '=' + encodeURIComponent(obj[key]));
+ }
+ }
+ return pairs.join('&');
+}
+
+/**
+ * Expose serialization method.
+ */
+
+ request.serializeObject = serialize;
+
+ /**
+ * Parse the given x-www-form-urlencoded `str`.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+function parseString(str) {
+ var obj = {};
+ var pairs = str.split('&');
+ var parts;
+ var pair;
+
+ for (var i = 0, len = pairs.length; i < len; ++i) {
+ pair = pairs[i];
+ parts = pair.split('=');
+ obj[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
+ }
+
+ return obj;
+}
+
+/**
+ * Expose parser.
+ */
+
+request.parseString = parseString;
+
+/**
+ * Default MIME type map.
+ *
+ * superagent.types.xml = 'application/xml';
+ *
+ */
+
+request.types = {
+ html: 'text/html',
+ json: 'application/json',
+ xml: 'application/xml',
+ urlencoded: 'application/x-www-form-urlencoded',
+ 'form': 'application/x-www-form-urlencoded',
+ 'form-data': 'application/x-www-form-urlencoded'
+};
+
+/**
+ * Default serialization map.
+ *
+ * superagent.serialize['application/xml'] = function(obj){
+ * return 'generated xml here';
+ * };
+ *
+ */
+
+ request.serialize = {
+ 'application/x-www-form-urlencoded': serialize,
+ 'application/json': JSON.stringify
+ };
+
+ /**
+ * Default parsers.
+ *
+ * superagent.parse['application/xml'] = function(str){
+ * return { object parsed from str };
+ * };
+ *
+ */
+
+request.parse = {
+ 'application/x-www-form-urlencoded': parseString,
+ 'application/json': JSON.parse
+};
+
+/**
+ * Parse the given header `str` into
+ * an object containing the mapped fields.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+function parseHeader(str) {
+ var lines = str.split(/\r?\n/);
+ var fields = {};
+ var index;
+ var line;
+ var field;
+ var val;
+
+ lines.pop(); // trailing CRLF
+
+ for (var i = 0, len = lines.length; i < len; ++i) {
+ line = lines[i];
+ index = line.indexOf(':');
+ field = line.slice(0, index).toLowerCase();
+ val = trim(line.slice(index + 1));
+ fields[field] = val;
+ }
+
+ return fields;
+}
+
+/**
+ * Return the mime type for the given `str`.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+function type(str){
+ return str.split(/ *; */).shift();
+};
+
+/**
+ * Return header field parameters.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+function params(str){
+ return reduce(str.split(/ *; */), function(obj, str){
+ var parts = str.split(/ *= */)
+ , key = parts.shift()
+ , val = parts.shift();
+
+ if (key && val) obj[key] = val;
+ return obj;
+ }, {});
+};
+
+/**
+ * Initialize a new `Response` with the given `xhr`.
+ *
+ * - set flags (.ok, .error, etc)
+ * - parse header
+ *
+ * Examples:
+ *
+ * Aliasing `superagent` as `request` is nice:
+ *
+ * request = superagent;
+ *
+ * We can use the promise-like API, or pass callbacks:
+ *
+ * request.get('/').end(function(res){});
+ * request.get('/', function(res){});
+ *
+ * Sending data can be chained:
+ *
+ * request
+ * .post('/user')
+ * .send({ name: 'tj' })
+ * .end(function(res){});
+ *
+ * Or passed to `.send()`:
+ *
+ * request
+ * .post('/user')
+ * .send({ name: 'tj' }, function(res){});
+ *
+ * Or passed to `.post()`:
+ *
+ * request
+ * .post('/user', { name: 'tj' })
+ * .end(function(res){});
+ *
+ * Or further reduced to a single call for simple cases:
+ *
+ * request
+ * .post('/user', { name: 'tj' }, function(res){});
+ *
+ * @param {XMLHTTPRequest} xhr
+ * @param {Object} options
+ * @api private
+ */
+
+function Response(req, options) {
+ options = options || {};
+ this.req = req;
+ this.xhr = this.req.xhr;
+ // responseText is accessible only if responseType is '' or 'text' and on older browsers
+ this.text = ((this.req.method !='HEAD' && (this.xhr.responseType === '' || this.xhr.responseType === 'text')) || typeof this.xhr.responseType === 'undefined')
+ ? this.xhr.responseText
+ : null;
+ this.statusText = this.req.xhr.statusText;
+ this.setStatusProperties(this.xhr.status);
+ this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders());
+ // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but
+ // getResponseHeader still works. so we get content-type even if getting
+ // other headers fails.
+ this.header['content-type'] = this.xhr.getResponseHeader('content-type');
+ this.setHeaderProperties(this.header);
+ this.body = this.req.method != 'HEAD'
+ ? this.parseBody(this.text ? this.text : this.xhr.response)
+ : null;
+}
+
+/**
+ * Get case-insensitive `field` value.
+ *
+ * @param {String} field
+ * @return {String}
+ * @api public
+ */
+
+Response.prototype.get = function(field){
+ return this.header[field.toLowerCase()];
+};
+
+/**
+ * Set header related properties:
+ *
+ * - `.type` the content type without params
+ *
+ * A response of "Content-Type: text/plain; charset=utf-8"
+ * will provide you with a `.type` of "text/plain".
+ *
+ * @param {Object} header
+ * @api private
+ */
+
+Response.prototype.setHeaderProperties = function(header){
+ // content-type
+ var ct = this.header['content-type'] || '';
+ this.type = type(ct);
+
+ // params
+ var obj = params(ct);
+ for (var key in obj) this[key] = obj[key];
+};
+
+/**
+ * Parse the given body `str`.
+ *
+ * Used for auto-parsing of bodies. Parsers
+ * are defined on the `superagent.parse` object.
+ *
+ * @param {String} str
+ * @return {Mixed}
+ * @api private
+ */
+
+Response.prototype.parseBody = function(str){
+ var parse = request.parse[this.type];
+ return parse && str && (str.length || str instanceof Object)
+ ? parse(str)
+ : null;
+};
+
+/**
+ * Set flags such as `.ok` based on `status`.
+ *
+ * For example a 2xx response will give you a `.ok` of __true__
+ * whereas 5xx will be __false__ and `.error` will be __true__. The
+ * `.clientError` and `.serverError` are also available to be more
+ * specific, and `.statusType` is the class of error ranging from 1..5
+ * sometimes useful for mapping respond colors etc.
+ *
+ * "sugar" properties are also defined for common cases. Currently providing:
+ *
+ * - .noContent
+ * - .badRequest
+ * - .unauthorized
+ * - .notAcceptable
+ * - .notFound
+ *
+ * @param {Number} status
+ * @api private
+ */
+
+Response.prototype.setStatusProperties = function(status){
+ // handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request
+ if (status === 1223) {
+ status = 204;
+ }
+
+ var type = status / 100 | 0;
+
+ // status / class
+ this.status = status;
+ this.statusType = type;
+
+ // basics
+ this.info = 1 == type;
+ this.ok = 2 == type;
+ this.clientError = 4 == type;
+ this.serverError = 5 == type;
+ this.error = (4 == type || 5 == type)
+ ? this.toError()
+ : false;
+
+ // sugar
+ this.accepted = 202 == status;
+ this.noContent = 204 == status;
+ this.badRequest = 400 == status;
+ this.unauthorized = 401 == status;
+ this.notAcceptable = 406 == status;
+ this.notFound = 404 == status;
+ this.forbidden = 403 == status;
+};
+
+/**
+ * Return an `Error` representative of this response.
+ *
+ * @return {Error}
+ * @api public
+ */
+
+Response.prototype.toError = function(){
+ var req = this.req;
+ var method = req.method;
+ var url = req.url;
+
+ var msg = 'cannot ' + method + ' ' + url + ' (' + this.status + ')';
+ var err = new Error(msg);
+ err.status = this.status;
+ err.method = method;
+ err.url = url;
+
+ return err;
+};
+
+/**
+ * Expose `Response`.
+ */
+
+request.Response = Response;
+
+/**
+ * Initialize a new `Request` with the given `method` and `url`.
+ *
+ * @param {String} method
+ * @param {String} url
+ * @api public
+ */
+
+function Request(method, url) {
+ var self = this;
+ Emitter.call(this);
+ this._query = this._query || [];
+ this.method = method;
+ this.url = url;
+ this.header = {};
+ this._header = {};
+ this.on('end', function(){
+ var err = null;
+ var res = null;
+
+ try {
+ res = new Response(self);
+ } catch(e) {
+ err = new Error('Parser is unable to parse the response');
+ err.parse = true;
+ err.original = e;
+ return self.callback(err);
+ }
+
+ self.emit('response', res);
+
+ if (err) {
+ return self.callback(err, res);
+ }
+
+ if (res.status >= 200 && res.status < 300) {
+ return self.callback(err, res);
+ }
+
+ var new_err = new Error(res.statusText || 'Unsuccessful HTTP response');
+ new_err.original = err;
+ new_err.response = res;
+ new_err.status = res.status;
+
+ self.callback(new_err, res);
+ });
+}
+
+/**
+ * Mixin `Emitter`.
+ */
+
+Emitter(Request.prototype);
+
+/**
+ * Allow for extension
+ */
+
+Request.prototype.use = function(fn) {
+ fn(this);
+ return this;
+}
+
+/**
+ * Set timeout to `ms`.
+ *
+ * @param {Number} ms
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.timeout = function(ms){
+ this._timeout = ms;
+ return this;
+};
+
+/**
+ * Clear previous timeout.
+ *
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.clearTimeout = function(){
+ this._timeout = 0;
+ clearTimeout(this._timer);
+ return this;
+};
+
+/**
+ * Abort the request, and clear potential timeout.
+ *
+ * @return {Request}
+ * @api public
+ */
+
+Request.prototype.abort = function(){
+ if (this.aborted) return;
+ this.aborted = true;
+ this.xhr.abort();
+ this.clearTimeout();
+ this.emit('abort');
+ return this;
+};
+
+/**
+ * Set header `field` to `val`, or multiple fields with one object.
+ *
+ * Examples:
+ *
+ * req.get('/')
+ * .set('Accept', 'application/json')
+ * .set('X-API-Key', 'foobar')
+ * .end(callback);
+ *
+ * req.get('/')
+ * .set({ Accept: 'application/json', 'X-API-Key': 'foobar' })
+ * .end(callback);
+ *
+ * @param {String|Object} field
+ * @param {String} val
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.set = function(field, val){
+ if (isObject(field)) {
+ for (var key in field) {
+ this.set(key, field[key]);
+ }
+ return this;
+ }
+ this._header[field.toLowerCase()] = val;
+ this.header[field] = val;
+ return this;
+};
+
+/**
+ * Remove header `field`.
+ *
+ * Example:
+ *
+ * req.get('/')
+ * .unset('User-Agent')
+ * .end(callback);
+ *
+ * @param {String} field
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.unset = function(field){
+ delete this._header[field.toLowerCase()];
+ delete this.header[field];
+ return this;
+};
+
+/**
+ * Get case-insensitive header `field` value.
+ *
+ * @param {String} field
+ * @return {String}
+ * @api private
+ */
+
+Request.prototype.getHeader = function(field){
+ return this._header[field.toLowerCase()];
+};
+
+/**
+ * Set Content-Type to `type`, mapping values from `request.types`.
+ *
+ * Examples:
+ *
+ * superagent.types.xml = 'application/xml';
+ *
+ * request.post('/')
+ * .type('xml')
+ * .send(xmlstring)
+ * .end(callback);
+ *
+ * request.post('/')
+ * .type('application/xml')
+ * .send(xmlstring)
+ * .end(callback);
+ *
+ * @param {String} type
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.type = function(type){
+ this.set('Content-Type', request.types[type] || type);
+ return this;
+};
+
+/**
+ * Set Accept to `type`, mapping values from `request.types`.
+ *
+ * Examples:
+ *
+ * superagent.types.json = 'application/json';
+ *
+ * request.get('/agent')
+ * .accept('json')
+ * .end(callback);
+ *
+ * request.get('/agent')
+ * .accept('application/json')
+ * .end(callback);
+ *
+ * @param {String} accept
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.accept = function(type){
+ this.set('Accept', request.types[type] || type);
+ return this;
+};
+
+/**
+ * Set Authorization field value with `user` and `pass`.
+ *
+ * @param {String} user
+ * @param {String} pass
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.auth = function(user, pass){
+ var str = btoa(user + ':' + pass);
+ this.set('Authorization', 'Basic ' + str);
+ return this;
+};
+
+/**
+* Add query-string `val`.
+*
+* Examples:
+*
+* request.get('/shoes')
+* .query('size=10')
+* .query({ color: 'blue' })
+*
+* @param {Object|String} val
+* @return {Request} for chaining
+* @api public
+*/
+
+Request.prototype.query = function(val){
+ if ('string' != typeof val) val = serialize(val);
+ if (val) this._query.push(val);
+ return this;
+};
+
+/**
+ * Write the field `name` and `val` for "multipart/form-data"
+ * request bodies.
+ *
+ * ``` js
+ * request.post('/upload')
+ * .field('foo', 'bar')
+ * .end(callback);
+ * ```
+ *
+ * @param {String} name
+ * @param {String|Blob|File} val
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.field = function(name, val){
+ if (!this._formData) this._formData = new root.FormData();
+ this._formData.append(name, val);
+ return this;
+};
+
+/**
+ * Queue the given `file` as an attachment to the specified `field`,
+ * with optional `filename`.
+ *
+ * ``` js
+ * request.post('/upload')
+ * .attach(new Blob(['hey! '], { type: "text/html"}))
+ * .end(callback);
+ * ```
+ *
+ * @param {String} field
+ * @param {Blob|File} file
+ * @param {String} filename
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.attach = function(field, file, filename){
+ if (!this._formData) this._formData = new root.FormData();
+ this._formData.append(field, file, filename);
+ return this;
+};
+
+/**
+ * Send `data`, defaulting the `.type()` to "json" when
+ * an object is given.
+ *
+ * Examples:
+ *
+ * // querystring
+ * request.get('/search')
+ * .end(callback)
+ *
+ * // multiple data "writes"
+ * request.get('/search')
+ * .send({ search: 'query' })
+ * .send({ range: '1..5' })
+ * .send({ order: 'desc' })
+ * .end(callback)
+ *
+ * // manual json
+ * request.post('/user')
+ * .type('json')
+ * .send('{"name":"tj"})
+ * .end(callback)
+ *
+ * // auto json
+ * request.post('/user')
+ * .send({ name: 'tj' })
+ * .end(callback)
+ *
+ * // manual x-www-form-urlencoded
+ * request.post('/user')
+ * .type('form')
+ * .send('name=tj')
+ * .end(callback)
+ *
+ * // auto x-www-form-urlencoded
+ * request.post('/user')
+ * .type('form')
+ * .send({ name: 'tj' })
+ * .end(callback)
+ *
+ * // defaults to x-www-form-urlencoded
+ * request.post('/user')
+ * .send('name=tobi')
+ * .send('species=ferret')
+ * .end(callback)
+ *
+ * @param {String|Object} data
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.send = function(data){
+ var obj = isObject(data);
+ var type = this.getHeader('Content-Type');
+
+ // merge
+ if (obj && isObject(this._data)) {
+ for (var key in data) {
+ this._data[key] = data[key];
+ }
+ } else if ('string' == typeof data) {
+ if (!type) this.type('form');
+ type = this.getHeader('Content-Type');
+ if ('application/x-www-form-urlencoded' == type) {
+ this._data = this._data
+ ? this._data + '&' + data
+ : data;
+ } else {
+ this._data = (this._data || '') + data;
+ }
+ } else {
+ this._data = data;
+ }
+
+ if (!obj || isHost(data)) return this;
+ if (!type) this.type('json');
+ return this;
+};
+
+/**
+ * Invoke the callback with `err` and `res`
+ * and handle arity check.
+ *
+ * @param {Error} err
+ * @param {Response} res
+ * @api private
+ */
+
+Request.prototype.callback = function(err, res){
+ var fn = this._callback;
+ this.clearTimeout();
+ fn(err, res);
+};
+
+/**
+ * Invoke callback with x-domain error.
+ *
+ * @api private
+ */
+
+Request.prototype.crossDomainError = function(){
+ var err = new Error('Origin is not allowed by Access-Control-Allow-Origin');
+ err.crossDomain = true;
+ this.callback(err);
+};
+
+/**
+ * Invoke callback with timeout error.
+ *
+ * @api private
+ */
+
+Request.prototype.timeoutError = function(){
+ var timeout = this._timeout;
+ var err = new Error('timeout of ' + timeout + 'ms exceeded');
+ err.timeout = timeout;
+ this.callback(err);
+};
+
+/**
+ * Enable transmission of cookies with x-domain requests.
+ *
+ * Note that for this to work the origin must not be
+ * using "Access-Control-Allow-Origin" with a wildcard,
+ * and also must set "Access-Control-Allow-Credentials"
+ * to "true".
+ *
+ * @api public
+ */
+
+Request.prototype.withCredentials = function(){
+ this._withCredentials = true;
+ return this;
+};
+
+/**
+ * Initiate request, invoking callback `fn(res)`
+ * with an instanceof `Response`.
+ *
+ * @param {Function} fn
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.end = function(fn){
+ var self = this;
+ var xhr = this.xhr = request.getXHR();
+ var query = this._query.join('&');
+ var timeout = this._timeout;
+ var data = this._formData || this._data;
+
+ // store callback
+ this._callback = fn || noop;
+
+ // state change
+ xhr.onreadystatechange = function(){
+ if (4 != xhr.readyState) return;
+
+ // In IE9, reads to any property (e.g. status) off of an aborted XHR will
+ // result in the error "Could not complete the operation due to error c00c023f"
+ var status;
+ try { status = xhr.status } catch(e) { status = 0; }
+
+ if (0 == status) {
+ if (self.timedout) return self.timeoutError();
+ if (self.aborted) return;
+ return self.crossDomainError();
+ }
+ self.emit('end');
+ };
+
+ // progress
+ var handleProgress = function(e){
+ if (e.total > 0) {
+ e.percent = e.loaded / e.total * 100;
+ }
+ self.emit('progress', e);
+ };
+ if (this.hasListeners('progress')) {
+ xhr.onprogress = handleProgress;
+ }
+ try {
+ if (xhr.upload && this.hasListeners('progress')) {
+ xhr.upload.onprogress = handleProgress;
+ }
+ } catch(e) {
+ // Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist.
+ // Reported here:
+ // https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web-worker-context
+ }
+
+ // timeout
+ if (timeout && !this._timer) {
+ this._timer = setTimeout(function(){
+ self.timedout = true;
+ self.abort();
+ }, timeout);
+ }
+
+ // querystring
+ if (query) {
+ query = request.serializeObject(query);
+ this.url += ~this.url.indexOf('?')
+ ? '&' + query
+ : '?' + query;
+ }
+
+ // initiate request
+ xhr.open(this.method, this.url, true);
+
+ // CORS
+ if (this._withCredentials) xhr.withCredentials = true;
+
+ // body
+ if ('GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !isHost(data)) {
+ // serialize stuff
+ var contentType = this.getHeader('Content-Type');
+ var serialize = request.serialize[contentType ? contentType.split(';')[0] : ''];
+ if (serialize) data = serialize(data);
+ }
+
+ // set header fields
+ for (var field in this.header) {
+ if (null == this.header[field]) continue;
+ xhr.setRequestHeader(field, this.header[field]);
+ }
+
+ // send stuff
+ this.emit('request', this);
+ xhr.send(data);
+ return this;
+};
+
+/**
+ * Faux promise support
+ *
+ * @param {Function} fulfill
+ * @param {Function} reject
+ * @return {Request}
+ */
+
+Request.prototype.then = function (fulfill, reject) {
+ return this.end(function(err, res) {
+ err ? reject(err) : fulfill(res);
+ });
+}
+
+/**
+ * Expose `Request`.
+ */
+
+request.Request = Request;
+
+/**
+ * Issue a request:
+ *
+ * Examples:
+ *
+ * request('GET', '/users').end(callback)
+ * request('/users').end(callback)
+ * request('/users', callback)
+ *
+ * @param {String} method
+ * @param {String|Function} url or callback
+ * @return {Request}
+ * @api public
+ */
+
+function request(method, url) {
+ // callback
+ if ('function' == typeof url) {
+ return new Request('GET', method).end(url);
+ }
+
+ // url first
+ if (1 == arguments.length) {
+ return new Request('GET', method);
+ }
+
+ return new Request(method, url);
+}
+
+/**
+ * GET `url` with optional callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed|Function} data or fn
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.get = function(url, data, fn){
+ var req = request('GET', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.query(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * HEAD `url` with optional callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed|Function} data or fn
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.head = function(url, data, fn){
+ var req = request('HEAD', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * DELETE `url` with optional callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.del = function(url, fn){
+ var req = request('DELETE', url);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * PATCH `url` with optional `data` and callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed} data
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.patch = function(url, data, fn){
+ var req = request('PATCH', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * POST `url` with optional `data` and callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed} data
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.post = function(url, data, fn){
+ var req = request('POST', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * PUT `url` with optional `data` and callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed|Function} data or fn
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.put = function(url, data, fn){
+ var req = request('PUT', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * Expose `request`.
+ */
+
+module.exports = request;
+
+},{"emitter":12,"reduce":13}],12:[function(require,module,exports){
+
+/**
+ * Expose `Emitter`.
+ */
+
+module.exports = Emitter;
+
+/**
+ * Initialize a new `Emitter`.
+ *
+ * @api public
+ */
+
+function Emitter(obj) {
+ if (obj) return mixin(obj);
+};
+
+/**
+ * Mixin the emitter properties.
+ *
+ * @param {Object} obj
+ * @return {Object}
+ * @api private
+ */
+
+function mixin(obj) {
+ for (var key in Emitter.prototype) {
+ obj[key] = Emitter.prototype[key];
+ }
+ return obj;
+}
+
+/**
+ * Listen on the given `event` with `fn`.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ * @return {Emitter}
+ * @api public
+ */
+
+Emitter.prototype.on =
+Emitter.prototype.addEventListener = function(event, fn){
+ this._callbacks = this._callbacks || {};
+ (this._callbacks[event] = this._callbacks[event] || [])
+ .push(fn);
+ return this;
+};
+
+/**
+ * Adds an `event` listener that will be invoked a single
+ * time then automatically removed.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ * @return {Emitter}
+ * @api public
+ */
+
+Emitter.prototype.once = function(event, fn){
+ var self = this;
+ this._callbacks = this._callbacks || {};
+
+ function on() {
+ self.off(event, on);
+ fn.apply(this, arguments);
+ }
+
+ on.fn = fn;
+ this.on(event, on);
+ return this;
+};
+
+/**
+ * Remove the given callback for `event` or all
+ * registered callbacks.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ * @return {Emitter}
+ * @api public
+ */
+
+Emitter.prototype.off =
+Emitter.prototype.removeListener =
+Emitter.prototype.removeAllListeners =
+Emitter.prototype.removeEventListener = function(event, fn){
+ this._callbacks = this._callbacks || {};
+
+ // all
+ if (0 == arguments.length) {
+ this._callbacks = {};
+ return this;
+ }
+
+ // specific event
+ var callbacks = this._callbacks[event];
+ if (!callbacks) return this;
+
+ // remove all handlers
+ if (1 == arguments.length) {
+ delete this._callbacks[event];
+ return this;
+ }
+
+ // remove specific handler
+ var cb;
+ for (var i = 0; i < callbacks.length; i++) {
+ cb = callbacks[i];
+ if (cb === fn || cb.fn === fn) {
+ callbacks.splice(i, 1);
+ break;
+ }
+ }
+ return this;
+};
+
+/**
+ * Emit `event` with the given args.
+ *
+ * @param {String} event
+ * @param {Mixed} ...
+ * @return {Emitter}
+ */
+
+Emitter.prototype.emit = function(event){
+ this._callbacks = this._callbacks || {};
+ var args = [].slice.call(arguments, 1)
+ , callbacks = this._callbacks[event];
+
+ if (callbacks) {
+ callbacks = callbacks.slice(0);
+ for (var i = 0, len = callbacks.length; i < len; ++i) {
+ callbacks[i].apply(this, args);
+ }
+ }
+
+ return this;
+};
+
+/**
+ * Return array of callbacks for `event`.
+ *
+ * @param {String} event
+ * @return {Array}
+ * @api public
+ */
+
+Emitter.prototype.listeners = function(event){
+ this._callbacks = this._callbacks || {};
+ return this._callbacks[event] || [];
+};
+
+/**
+ * Check if this emitter has `event` handlers.
+ *
+ * @param {String} event
+ * @return {Boolean}
+ * @api public
+ */
+
+Emitter.prototype.hasListeners = function(event){
+ return !! this.listeners(event).length;
+};
+
+},{}],13:[function(require,module,exports){
+
+/**
+ * Reduce `arr` with `fn`.
+ *
+ * @param {Array} arr
+ * @param {Function} fn
+ * @param {Mixed} initial
+ *
+ * TODO: combatible error handling?
+ */
+
+module.exports = function(arr, fn, initial){
+ var idx = 0;
+ var len = arr.length;
+ var curr = arguments.length == 3
+ ? initial
+ : arr[idx++];
+
+ while (idx < len) {
+ curr = fn.call(null, curr, arr[idx], ++idx, arr);
+ }
+
+ return curr;
+};
+},{}],14:[function(require,module,exports){
+
+/**
+ * Module dependencies.
+ */
+
+var global = (function() { return this; })();
+
+/**
+ * WebSocket constructor.
+ */
+
+var WebSocket = global.WebSocket || global.MozWebSocket;
+
+/**
+ * Module exports.
+ */
+
+module.exports = WebSocket ? ws : null;
+
+/**
+ * WebSocket constructor.
+ *
+ * The third `opts` options object gets ignored in web browsers, since it's
+ * non-standard, and throws a TypeError if passed to the constructor.
+ * See: https://github.com/einaros/ws/issues/227
+ *
+ * @param {String} uri
+ * @param {Array} protocols (optional)
+ * @param {Object) opts (optional)
+ * @api public
+ */
+
+function ws(uri, protocols, opts) {
+ var instance;
+ if (protocols) {
+ instance = new WebSocket(uri, protocols);
+ } else {
+ instance = new WebSocket(uri);
+ }
+ return instance;
+}
+
+if (WebSocket) ws.prototype = WebSocket.prototype;
+
+},{}]},{},[5])(5)
+});
\ No newline at end of file
diff --git a/web-dist/discord.3.4.0.js b/web-dist/discord.3.4.0.js
new file mode 100644
index 000000000..1cbe30419
--- /dev/null
+++ b/web-dist/discord.3.4.0.js
@@ -0,0 +1,3641 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Discord = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o]*>/g) || [])[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var mention = _step3.value;
+
+ _mentions.push(mention.substring(2, mention.length - 1));
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3["return"]) {
+ _iterator3["return"]();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ return _mentions;
+ }
+ });
+
+ return prom;
+ }
+
+ //def createws
+ }, {
+ key: "createws",
+ value: function createws(url) {
+ if (this.websocket) return false;
+
+ var self = this;
+
+ //good to go
+ this.websocket = new WebSocket(url);
+
+ //open
+ this.websocket.onopen = function () {
+ self.trySendConnData(); //try connecting
+ };
+
+ //close
+ this.websocket.onclose = function () {
+ self.trigger("disconnected");
+ };
+
+ //message
+ this.websocket.onmessage = function (e) {
+
+ var dat = false,
+ data = {};
+
+ try {
+ dat = JSON.parse(e.data);
+ data = dat.d;
+ } catch (err) {
+ self.trigger("error", err, e);
+ return;
+ }
+
+ //valid message
+ switch (dat.t) {
+
+ case "READY":
+ self.debug("received ready packet");
+
+ self.user = self.addUser(data.user);
+
+ var _iteratorNormalCompletion4 = true;
+ var _didIteratorError4 = false;
+ var _iteratorError4 = undefined;
+
+ try {
+ for (var _iterator4 = data.guilds[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
+ var _server = _step4.value;
+
+ var server = self.addServer(_server);
+ }
+ } catch (err) {
+ _didIteratorError4 = true;
+ _iteratorError4 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion4 && _iterator4["return"]) {
+ _iterator4["return"]();
+ }
+ } finally {
+ if (_didIteratorError4) {
+ throw _iteratorError4;
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion5 = true;
+ var _didIteratorError5 = false;
+ var _iteratorError5 = undefined;
+
+ try {
+ for (var _iterator5 = data.private_channels[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
+ var _pmc = _step5.value;
+
+ var pmc = self.addPMChannel(_pmc);
+ }
+ } catch (err) {
+ _didIteratorError5 = true;
+ _iteratorError5 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion5 && _iterator5["return"]) {
+ _iterator5["return"]();
+ }
+ } finally {
+ if (_didIteratorError5) {
+ throw _iteratorError5;
+ }
+ }
+ }
+
+ self.trigger("ready");
+ self.readyTime = Date.now();
+ self.debug("cached " + self.serverCache.length + " servers, " + self.channelCache.length + " channels, " + self.pmChannelCache.length + " PMs and " + self.userCache.length + " users.");
+ self.state = 3;
+ setInterval(function () {
+ self.keepAlive.apply(self);
+ }, data.heartbeat_interval);
+
+ break;
+ case "MESSAGE_CREATE":
+ self.debug("received message");
+
+ var mentions = [];
+ data.mentions = data.mentions || []; //for some reason this was not defined at some point?
+ var _iteratorNormalCompletion6 = true;
+ var _didIteratorError6 = false;
+ var _iteratorError6 = undefined;
+
+ try {
+ for (var _iterator6 = data.mentions[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
+ var mention = _step6.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError6 = true;
+ _iteratorError6 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion6 && _iterator6["return"]) {
+ _iterator6["return"]();
+ }
+ } finally {
+ if (_didIteratorError6) {
+ throw _iteratorError6;
+ }
+ }
+ }
+
+ var channel = self.getChannel("id", data.channel_id);
+ if (channel) {
+ var msg = channel.addMessage(new Message(data, channel, mentions, self.addUser(data.author)));
+ self.trigger("message", msg);
+ }
+
+ break;
+ case "MESSAGE_DELETE":
+ self.debug("message deleted");
+
+ var channel = self.getChannel("id", data.channel_id);
+ var message = channel.getMessage("id", data.id);
+ if (message) {
+ self.trigger("messageDelete", channel, message);
+ channel.messages.splice(channel.messages.indexOf(message), 1);
+ } else {
+ //don't have the cache of that message ;(
+ self.trigger("messageDelete", channel);
+ }
+ break;
+ case "MESSAGE_UPDATE":
+ self.debug("message updated");
+
+ var channel = self.getChannel("id", data.channel_id);
+ var formerMessage = channel.getMessage("id", data.id);
+
+ if (formerMessage) {
+
+ //new message might be partial, so we need to fill it with whatever the old message was.
+ var info = {};
+
+ for (var key in formerMessage) {
+ info[key] = formerMessage[key];
+ }
+
+ for (var key in data) {
+ info[key] = data[key];
+ }
+
+ var mentions = [];
+ var _iteratorNormalCompletion7 = true;
+ var _didIteratorError7 = false;
+ var _iteratorError7 = undefined;
+
+ try {
+ for (var _iterator7 = info.mentions[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
+ var mention = _step7.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError7 = true;
+ _iteratorError7 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion7 && _iterator7["return"]) {
+ _iterator7["return"]();
+ }
+ } finally {
+ if (_didIteratorError7) {
+ throw _iteratorError7;
+ }
+ }
+ }
+
+ var newMessage = new Message(info, channel, mentions, formerMessage.author);
+
+ self.trigger("messageUpdate", newMessage, formerMessage);
+
+ channel.messages[channel.messages.indexOf(formerMessage)] = newMessage;
+ }
+
+ // message isn't in cache, and if it's a partial it could cause
+ // all hell to break loose... best to just act as if nothing happened
+
+ break;
+
+ case "GUILD_DELETE":
+
+ var server = self.getServer("id", data.id);
+
+ if (server) {
+ self.serverCache.splice(self.serverCache.indexOf(server), 1);
+ self.trigger("serverDelete", server);
+ }
+
+ break;
+
+ case "CHANNEL_DELETE":
+
+ var channel = self.getChannel("id", data.id);
+
+ if (channel) {
+
+ var server = channel.server;
+
+ if (server) {
+
+ server.channels.splice(server.channels.indexOf(channel), 1);
+ }
+
+ self.trigger("channelDelete", channel);
+
+ self.serverCache.splice(self.serverCache.indexOf(channel), 1);
+ }
+
+ break;
+
+ case "GUILD_CREATE":
+
+ var server = self.getServer("id", data.id);
+
+ if (!server) {
+ //if server doesn't already exist because duh
+ server = self.addServer(data);
+ } /*else if(server.channels.length === 0){
+
+ var srv = new Server(data, self);
+ for(channel of data.channels){
+ srv.channels.push(new Channel(channel, data.id));
+ }
+ self.serverCache[self.serverCache.indexOf(server)] = srv;
+
+ }*/
+
+ if (self.serverCreateListener[data.id]) {
+ var cbs = self.serverCreateListener[data.id];
+ cbs[0](server); //promise then callback
+ cbs[1](null, server); //legacy callback
+ self.serverCreateListener[data.id] = null;
+ }
+
+ self.trigger("serverCreate", server);
+
+ break;
+
+ case "CHANNEL_CREATE":
+
+ var channel = self.getChannel("id", data.id);
+
+ if (!channel) {
+
+ var chann = self.addChannel(data, data.guild_id);
+ var srv = self.getServer("id", data.guild_id);
+ if (srv) {
+ srv.addChannel(chann);
+ }
+ self.trigger("channelCreate", chann);
+ }
+
+ break;
+
+ case "GUILD_MEMBER_ADD":
+
+ var server = self.getServer("id", data.guild_id);
+
+ if (server) {
+
+ var user = self.addUser(data.user); //if for whatever reason it doesn't exist..
+
+ if (! ~server.members.indexOf(user)) {
+ server.members.push(user);
+ }
+
+ self.trigger("serverNewMember", user, server);
+ }
+
+ break;
+
+ case "GUILD_MEMBER_REMOVE":
+
+ var server = self.getServer("id", data.guild_id);
+
+ if (server) {
+
+ var user = self.addUser(data.user); //if for whatever reason it doesn't exist..
+
+ if (~server.members.indexOf(user)) {
+ server.members.splice(server.members.indexOf(user), 1);
+ }
+
+ self.trigger("serverRemoveMember", user, server);
+ }
+
+ break;
+
+ case "USER_UPDATE":
+
+ if (self.user && data.id === self.user.id) {
+
+ var newUser = new User(data); //not actually adding to the cache
+
+ self.trigger("userUpdate", newUser, self.user);
+
+ if (~self.userCache.indexOf(self.user)) {
+ self.userCache[self.userCache.indexOf(self.user)] = newUser;
+ }
+
+ self.user = newUser;
+ }
+
+ break;
+
+ case "PRESENCE_UPDATE":
+
+ var userInCache = self.getUser("id", data.user.id);
+
+ if (userInCache) {
+ //user exists
+ var presenceUser = new User(data.user);
+ if (presenceUser.equalsStrict(userInCache)) {
+ //they're exactly the same, an actual presence update
+ userInCache.status = data.status;
+ self.trigger("presence", {
+ user: userInCache,
+ status: data.status,
+ server: self.getServer("id", data.guild_id),
+ gameId: data.game_id
+ });
+ } else {
+ //one of their details changed.
+ self.trigger("userUpdate", userInCache, presenceUser);
+ self.userCache[self.userCache.indexOf(userInCache)] = presenceUser;
+ }
+ }
+
+ break;
+
+ default:
+ self.debug("received unknown packet");
+ self.trigger("unknown", dat);
+ break;
+
+ }
+ };
+ }
+
+ //def addUser
+ }, {
+ key: "addUser",
+ value: function addUser(data) {
+ if (!this.getUser("id", data.id)) {
+ this.userCache.push(new User(data));
+ }
+ return this.getUser("id", data.id);
+ }
+
+ //def addChannel
+ }, {
+ key: "addChannel",
+ value: function addChannel(data, serverId) {
+ if (!this.getChannel("id", data.id)) {
+ this.channelCache.push(new Channel(data, this.getServer("id", serverId)));
+ }
+ return this.getChannel("id", data.id);
+ }
+ }, {
+ key: "addPMChannel",
+ value: function addPMChannel(data) {
+ if (!this.getPMChannel("id", data.id)) {
+ this.pmChannelCache.push(new PMChannel(data, this));
+ }
+ return this.getPMChannel("id", data.id);
+ }
+
+ //def addServer
+ }, {
+ key: "addServer",
+ value: function addServer(data) {
+
+ var self = this;
+ var server = this.getServer("id", data.id);
+
+ if (!server) {
+ server = new Server(data, this);
+ this.serverCache.push(server);
+ if (data.channels) {
+ var _iteratorNormalCompletion8 = true;
+ var _didIteratorError8 = false;
+ var _iteratorError8 = undefined;
+
+ try {
+ for (var _iterator8 = data.channels[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
+ var channel = _step8.value;
+
+ server.channels.push(this.addChannel(channel, server.id));
+ }
+ } catch (err) {
+ _didIteratorError8 = true;
+ _iteratorError8 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion8 && _iterator8["return"]) {
+ _iterator8["return"]();
+ }
+ } finally {
+ if (_didIteratorError8) {
+ throw _iteratorError8;
+ }
+ }
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion9 = true;
+ var _didIteratorError9 = false;
+ var _iteratorError9 = undefined;
+
+ try {
+ for (var _iterator9 = data.presences[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
+ var presence = _step9.value;
+
+ self.getUser("id", presence.user.id).status = presence.status;
+ }
+ } catch (err) {
+ _didIteratorError9 = true;
+ _iteratorError9 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion9 && _iterator9["return"]) {
+ _iterator9["return"]();
+ }
+ } finally {
+ if (_didIteratorError9) {
+ throw _iteratorError9;
+ }
+ }
+ }
+
+ return server;
+ }
+
+ //def getUser
+ }, {
+ key: "getUser",
+ value: function getUser(key, value) {
+ var _iteratorNormalCompletion10 = true;
+ var _didIteratorError10 = false;
+ var _iteratorError10 = undefined;
+
+ try {
+ for (var _iterator10 = this.userCache[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
+ var user = _step10.value;
+
+ if (user[key] === value) {
+ return user;
+ }
+ }
+ } catch (err) {
+ _didIteratorError10 = true;
+ _iteratorError10 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion10 && _iterator10["return"]) {
+ _iterator10["return"]();
+ }
+ } finally {
+ if (_didIteratorError10) {
+ throw _iteratorError10;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def getChannel
+ }, {
+ key: "getChannel",
+ value: function getChannel(key, value) {
+ var _iteratorNormalCompletion11 = true;
+ var _didIteratorError11 = false;
+ var _iteratorError11 = undefined;
+
+ try {
+ for (var _iterator11 = this.channelCache[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
+ var channel = _step11.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError11 = true;
+ _iteratorError11 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion11 && _iterator11["return"]) {
+ _iterator11["return"]();
+ }
+ } finally {
+ if (_didIteratorError11) {
+ throw _iteratorError11;
+ }
+ }
+ }
+
+ return this.getPMChannel(key, value); //might be a PM
+ }
+ }, {
+ key: "getPMChannel",
+ value: function getPMChannel(key, value) {
+ var _iteratorNormalCompletion12 = true;
+ var _didIteratorError12 = false;
+ var _iteratorError12 = undefined;
+
+ try {
+ for (var _iterator12 = this.pmChannelCache[Symbol.iterator](), _step12; !(_iteratorNormalCompletion12 = (_step12 = _iterator12.next()).done); _iteratorNormalCompletion12 = true) {
+ var channel = _step12.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError12 = true;
+ _iteratorError12 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion12 && _iterator12["return"]) {
+ _iterator12["return"]();
+ }
+ } finally {
+ if (_didIteratorError12) {
+ throw _iteratorError12;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def getServer
+ }, {
+ key: "getServer",
+ value: function getServer(key, value) {
+ var _iteratorNormalCompletion13 = true;
+ var _didIteratorError13 = false;
+ var _iteratorError13 = undefined;
+
+ try {
+ for (var _iterator13 = this.serverCache[Symbol.iterator](), _step13; !(_iteratorNormalCompletion13 = (_step13 = _iterator13.next()).done); _iteratorNormalCompletion13 = true) {
+ var server = _step13.value;
+
+ if (server[key] === value) {
+ return server;
+ }
+ }
+ } catch (err) {
+ _didIteratorError13 = true;
+ _iteratorError13 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion13 && _iterator13["return"]) {
+ _iterator13["return"]();
+ }
+ } finally {
+ if (_didIteratorError13) {
+ throw _iteratorError13;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def trySendConnData
+ }, {
+ key: "trySendConnData",
+ value: function trySendConnData() {
+
+ if (this.token && !this.alreadySentData) {
+
+ this.alreadySentData = true;
+
+ var data = {
+ op: 2,
+ d: {
+ token: this.token,
+ v: 2,
+ properties: {
+ "$os": "discord.js",
+ "$browser": "discord.js",
+ "$device": "discord.js",
+ "$referrer": "",
+ "$referring_domain": ""
+ }
+ }
+ };
+ this.websocket.send(JSON.stringify(data));
+ }
+ }
+ }, {
+ key: "resolveServerID",
+ value: function resolveServerID(resource) {
+
+ if (resource instanceof Server) {
+ return resource.id;
+ } else if (!isNaN(resource) && resource.length && resource.length === 17) {
+ return resource;
+ }
+ }
+ }, {
+ key: "resolveDestination",
+ value: function resolveDestination(destination) {
+ var channId = false;
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ if (destination instanceof Server) {
+ channId = destination.id; //general is the same as server id
+ } else if (destination instanceof Channel) {
+ channId = destination.id;
+ } else if (destination instanceof Message) {
+ channId = destination.channel.id;
+ } else if (destination instanceof User) {
+
+ //check if we have a PM
+ var _iteratorNormalCompletion14 = true;
+ var _didIteratorError14 = false;
+ var _iteratorError14 = undefined;
+
+ try {
+ for (var _iterator14 = self.pmChannelCache[Symbol.iterator](), _step14; !(_iteratorNormalCompletion14 = (_step14 = _iterator14.next()).done); _iteratorNormalCompletion14 = true) {
+ var pmc = _step14.value;
+
+ if (pmc.user.equals(destination)) {
+ resolve(pmc.id);
+ return;
+ }
+ }
+
+ //we don't, at this point we're late
+ } catch (err) {
+ _didIteratorError14 = true;
+ _iteratorError14 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion14 && _iterator14["return"]) {
+ _iterator14["return"]();
+ }
+ } finally {
+ if (_didIteratorError14) {
+ throw _iteratorError14;
+ }
+ }
+ }
+
+ self.startPM(destination).then(function (pmc) {
+ console.log(pmc);
+ resolve(pmc.id);
+ })["catch"](reject);
+ } else {
+ channId = destination;
+ }
+ if (channId) resolve(channId);
+ });
+ }
+ }, {
+ key: "_sendMessage",
+ value: function _sendMessage(destination, content, tts, mentions) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request.post(Endpoints.CHANNELS + "/" + destination + "/messages").set("authorization", self.token).send({
+ content: content,
+ mentions: mentions,
+ tts: tts
+ }).end(function (err, res) {
+
+ if (err) {
+ reject(err);
+ } else {
+ var data = res.body;
+
+ var mentions = [];
+
+ data.mentions = data.mentions || []; //for some reason this was not defined at some point?
+
+ var _iteratorNormalCompletion15 = true;
+ var _didIteratorError15 = false;
+ var _iteratorError15 = undefined;
+
+ try {
+ for (var _iterator15 = data.mentions[Symbol.iterator](), _step15; !(_iteratorNormalCompletion15 = (_step15 = _iterator15.next()).done); _iteratorNormalCompletion15 = true) {
+ var mention = _step15.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError15 = true;
+ _iteratorError15 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion15 && _iterator15["return"]) {
+ _iterator15["return"]();
+ }
+ } finally {
+ if (_didIteratorError15) {
+ throw _iteratorError15;
+ }
+ }
+ }
+
+ var channel = self.getChannel("id", data.channel_id);
+ if (channel) {
+ var msg = channel.addMessage(new Message(data, channel, mentions, self.addUser(data.author)));
+ resolve(msg);
+ }
+ }
+ });
+ });
+ }
+ }, {
+ key: "_sendFile",
+ value: function _sendFile(destination, attachment) {
+ var attachmentName = arguments.length <= 2 || arguments[2] === undefined ? "DEFAULT BECAUSE YOU DIDN'T SPECIFY WHY.png" : arguments[2];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request.post(Endpoints.CHANNELS + "/" + destination + "/messages").set("authorization", self.token).attach("file", attachment, attachmentName).end(function (err, res) {
+
+ if (err) {
+ reject(err);
+ } else {
+
+ var chann = self.getChannel("id", destination);
+ if (chann) {
+ var msg = chann.addMessage(new Message(res.body, chann, [], self.user));
+ resolve(msg);
+ }
+ }
+ });
+ });
+ }
+ }, {
+ key: "_updateMessage",
+ value: function _updateMessage(message, content) {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ request.patch(Endpoints.CHANNELS + "/" + message.channel.id + "/messages/" + message.id).set("authorization", self.token).send({
+ content: content,
+ mentions: []
+ }).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ var msg = new Message(res.body, message.channel, message.mentions, message.sender);
+ resolve(msg);
+ message.channel.messages[message.channel.messages.indexOf(message)] = msg;
+ }
+ });
+ });
+ }
+ }, {
+ key: "_deleteMessage",
+ value: function _deleteMessage(message) {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+
+ request.del(Endpoints.CHANNELS + "/" + message.channel.id + "/messages/" + message.id).set("authorization", self.token).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve();
+ }
+ });
+ });
+ }
+ }, {
+ key: "checkQueue",
+ value: function checkQueue(channelID) {
+ var _this = this;
+
+ var self = this;
+
+ if (!this.checkingQueue[channelID]) {
+ (function () {
+ var doNext = function doNext() {
+ if (self.queue[channelID].length === 0) {
+ done();
+ return;
+ }
+ var queuedEvent = self.queue[channelID][0];
+ switch (queuedEvent.action) {
+ case "sendMessage":
+ var msgToSend = queuedEvent;
+ self._sendMessage(channelID, msgToSend.content, msgToSend.tts, msgToSend.mentions).then(function (msg) {
+ msgToSend.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToSend.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "sendFile":
+ var fileToSend = queuedEvent;
+ self._sendFile(channelID, fileToSend.attachment, fileToSend.attachmentName).then(function (msg) {
+ fileToSend.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ fileToSend.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "updateMessage":
+ var msgToUpd = queuedEvent;
+ self._updateMessage(msgToUpd.message, msgToUpd.content).then(function (msg) {
+ msgToUpd.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToUpd.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "deleteMessage":
+ var msgToDel = queuedEvent;
+ self._deleteMessage(msgToDel.message).then(function (msg) {
+ msgToDel.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToDel.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ default:
+ done();
+ break;
+ }
+ };
+
+ var done = function done() {
+ self.checkingQueue[channelID] = false;
+ return;
+ };
+
+ //if we aren't already checking this queue.
+ _this.checkingQueue[channelID] = true;
+ doNext();
+ })();
+ }
+ }
+ }, {
+ key: "getGateway",
+ value: function getGateway() {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ request.get(Endpoints.API + "/gateway").set("authorization", self.token).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(res.body.url);
+ }
+ });
+ });
+ }
+ }, {
+ key: "uptime",
+ get: function get() {
+
+ return this.readyTime ? Date.now() - this.readyTime : null;
+ }
+ }, {
+ key: "ready",
+ get: function get() {
+ return this.state === 3;
+ }
+ }, {
+ key: "servers",
+ get: function get() {
+ return this.serverCache;
+ }
+ }, {
+ key: "channels",
+ get: function get() {
+ return this.channelCache;
+ }
+ }, {
+ key: "users",
+ get: function get() {
+ return this.userCache;
+ }
+ }, {
+ key: "PMChannels",
+ get: function get() {
+ return this.pmChannelCache;
+ }
+ }, {
+ key: "messages",
+ get: function get() {
+
+ var msgs = [];
+ var _iteratorNormalCompletion16 = true;
+ var _didIteratorError16 = false;
+ var _iteratorError16 = undefined;
+
+ try {
+ for (var _iterator16 = this.channelCache[Symbol.iterator](), _step16; !(_iteratorNormalCompletion16 = (_step16 = _iterator16.next()).done); _iteratorNormalCompletion16 = true) {
+ var channel = _step16.value;
+
+ msgs = msgs.concat(channel.messages);
+ }
+ } catch (err) {
+ _didIteratorError16 = true;
+ _iteratorError16 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion16 && _iterator16["return"]) {
+ _iterator16["return"]();
+ }
+ } finally {
+ if (_didIteratorError16) {
+ throw _iteratorError16;
+ }
+ }
+ }
+
+ return msgs;
+ }
+ }]);
+
+ return Client;
+})();
+
+module.exports = Client;
+},{"./Endpoints.js":2,"./PMChannel.js":3,"./channel.js":4,"./invite.js":6,"./message.js":7,"./server.js":8,"./user.js":9,"fs":10,"superagent":11,"ws":14}],2:[function(require,module,exports){
+"use strict";
+
+exports.BASE_DOMAIN = "discordapp.com";
+exports.BASE = "https://" + exports.BASE_DOMAIN;
+exports.WEBSOCKET_HUB = "wss://" + exports.BASE_DOMAIN + "/hub";
+
+exports.API = exports.BASE + "/api";
+exports.AUTH = exports.API + "/auth";
+exports.LOGIN = exports.AUTH + "/login";
+exports.LOGOUT = exports.AUTH + "/logout";
+exports.USERS = exports.API + "/users";
+exports.SERVERS = exports.API + "/guilds";
+exports.CHANNELS = exports.API + "/channels";
+},{}],3:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var PMChannel = (function () {
+ function PMChannel(data, client) {
+ _classCallCheck(this, PMChannel);
+
+ this.user = client.getUser("id", data.recipient.id);
+ this.id = data.id;
+ this.messages = [];
+ }
+
+ _createClass(PMChannel, [{
+ key: "addMessage",
+ value: function addMessage(data) {
+ if (!this.getMessage("id", data.id)) {
+ this.messages.push(data);
+ }
+ return this.getMessage("id", data.id);
+ }
+ }, {
+ key: "getMessage",
+ value: function getMessage(key, value) {
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.messages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var message = _step.value;
+
+ if (message[key] === value) {
+ return message;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return true;
+ }
+ }]);
+
+ return PMChannel;
+})();
+
+module.exports = PMChannel;
+},{}],4:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Channel = (function () {
+ function Channel(data, server) {
+ _classCallCheck(this, Channel);
+
+ this.server = server;
+ this.name = data.name;
+ this.type = data.type;
+ this.id = data.id;
+ this.messages = [];
+ //this.isPrivate = isPrivate; //not sure about the implementation of this...
+ }
+
+ _createClass(Channel, [{
+ key: "equals",
+ value: function equals(object) {
+ return object && object.id === this.id;
+ }
+ }, {
+ key: "addMessage",
+ value: function addMessage(data) {
+
+ if (this.messages.length > 1000) {
+ this.messages.splice(0, 1);
+ }
+
+ if (!this.getMessage("id", data.id)) {
+ this.messages.push(data);
+ }
+
+ return this.getMessage("id", data.id);
+ }
+ }, {
+ key: "getMessage",
+ value: function getMessage(key, value) {
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.messages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var message = _step.value;
+
+ if (message[key] === value) {
+ return message;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ return "<#" + this.id + ">";
+ }
+ }, {
+ key: "client",
+ get: function get() {
+ return this.server.client;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return false;
+ }
+ }, {
+ key: "users",
+ get: function get() {
+ return this.server.members;
+ }
+ }, {
+ key: "members",
+ get: function get() {
+ return this.server.members;
+ }
+ }]);
+
+ return Channel;
+})();
+
+module.exports = Channel;
+},{}],5:[function(require,module,exports){
+"use strict";
+
+var request = require("superagent");
+var Endpoints = require("./Endpoints.js");
+var Client = require("./Client.js");
+
+var Discord = {
+ Endpoints: Endpoints,
+ Client: Client
+};
+
+module.exports = Discord;
+},{"./Client.js":1,"./Endpoints.js":2,"superagent":11}],6:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Invite = (function () {
+ function Invite(data, client) {
+ _classCallCheck(this, Invite);
+
+ this.max_age = data.max_age;
+ this.code = data.code;
+ this.server = client.getServer("id", data.guild.id);
+ this.revoked = data.revoked;
+ this.created_at = Date.parse(data.created_at);
+ this.temporary = data.temporary;
+ this.uses = data.uses;
+ this.max_uses = data.uses;
+ this.inviter = client.addUser(data.inviter);
+ this.xkcd = data.xkcdpass;
+ this.channel = client.getChannel("id", data.channel.id);
+ }
+
+ _createClass(Invite, [{
+ key: "URL",
+ get: function get() {
+ var code = this.xkcd ? this.xkcdpass : this.code;
+ return "https://discord.gg/" + code;
+ }
+ }]);
+
+ return Invite;
+})();
+
+module.exports = Invite;
+},{}],7:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var PMChannel = require("./PMChannel.js");
+
+var Message = (function () {
+ function Message(data, channel, mentions, author) {
+ _classCallCheck(this, Message);
+
+ this.tts = data.tts;
+ this.timestamp = Date.parse(data.timestamp);
+ this.nonce = data.nonce;
+ this.mentions = mentions;
+ this.everyoneMentioned = data.mention_everyone;
+ this.id = data.id;
+ this.embeds = data.embeds;
+ this.editedTimestamp = data.edited_timestamp;
+ this.content = data.content.trim();
+ this.channel = channel;
+ this.author = author;
+ this.attachments = data.attachments;
+ }
+
+ /*exports.Message.prototype.isPM = function() {
+ return ( this.channel instanceof PMChannel );
+ }*/
+
+ _createClass(Message, [{
+ key: "isMentioned",
+ value: function isMentioned(user) {
+ var id = user.id ? user.id : user;
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.mentions[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var mention = _step.value;
+
+ if (mention.id === id) {
+ return true;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return false;
+ }
+ }, {
+ key: "sender",
+ get: function get() {
+ return this.author;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return this.channel.isPrivate;
+ }
+ }]);
+
+ return Message;
+})();
+
+module.exports = Message;
+},{"./PMChannel.js":3}],8:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Server = (function () {
+ function Server(data, client) {
+ _classCallCheck(this, Server);
+
+ this.client = client;
+ this.region = data.region;
+ this.ownerID = data.owner_id;
+ this.name = data.name;
+ this.id = data.id;
+ this.members = [];
+ this.channels = [];
+ this.icon = data.icon;
+ this.afkTimeout = data.afk_timeout;
+ this.afkChannelId = data.afk_channel_id;
+
+ if (!data.members) {
+ data.members = [client.user];
+ return;
+ }
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = data.members[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var member = _step.value;
+
+ // first we cache the user in our Discord Client,
+ // then we add it to our list. This way when we
+ // get a user from this server's member list,
+ // it will be identical (unless an async change occurred)
+ // to the client's cache.
+ if (member.user) this.members.push(client.addUser(member.user));
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+ }
+
+ _createClass(Server, [{
+ key: "getChannel",
+
+ // get/set
+ value: function getChannel(key, value) {
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = this.channels[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var channel = _step2.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2["return"]) {
+ _iterator2["return"]();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "getMember",
+ value: function getMember(key, value) {
+ var _iteratorNormalCompletion3 = true;
+ var _didIteratorError3 = false;
+ var _iteratorError3 = undefined;
+
+ try {
+ for (var _iterator3 = this.members[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var member = _step3.value;
+
+ if (member[key] === value) {
+ return member;
+ }
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3["return"]) {
+ _iterator3["return"]();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "addChannel",
+ value: function addChannel(chann) {
+ if (!this.getChannel("id", chann.id)) {
+ this.channels.push(chann);
+ }
+ return chann;
+ }
+ }, {
+ key: "addMember",
+ value: function addMember(member) {
+ if (!this.getMember("id", member.id)) {
+ this.members.push(member);
+ }
+ return member;
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ return this.name;
+ }
+ }, {
+ key: "iconURL",
+ get: function get() {
+ if (!this.icon) return null;
+ return "https://discordapp.com/api/guilds/" + this.id + "/icons/" + this.icon + ".jpg";
+ }
+ }, {
+ key: "afkChannel",
+ get: function get() {
+ if (!this.afkChannelId) return false;
+
+ return this.getChannel("id", this.afkChannelId);
+ }
+ }, {
+ key: "defaultChannel",
+ get: function get() {
+ return this.getChannel("name", "general");
+ }
+ }, {
+ key: "owner",
+ get: function get() {
+ return this.client.getUser("id", this.ownerID);
+ }
+ }, {
+ key: "users",
+ get: function get() {
+ return this.members;
+ }
+ }]);
+
+ return Server;
+})();
+
+module.exports = Server;
+},{}],9:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var User = (function () {
+ function User(data) {
+ _classCallCheck(this, User);
+
+ this.username = data.username;
+ this.discriminator = data.discriminator;
+ this.id = data.id;
+ this.avatar = data.avatar;
+ this.status = "offline";
+ }
+
+ // access using user.avatarURL;
+
+ _createClass(User, [{
+ key: "mention",
+ value: function mention() {
+ return "<@" + this.id + ">";
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ /*
+ if we embed a user in a String - like so:
+ "Yo " + user + " what's up?"
+ It would generate something along the lines of:
+ "Yo @hydrabolt what's up?"
+ */
+ return this.mention();
+ }
+ }, {
+ key: "equals",
+ value: function equals(object) {
+ return object.id === this.id;
+ }
+ }, {
+ key: "equalsStrict",
+ value: function equalsStrict(object) {
+ return object.id === this.id && object.avatar === this.avatar && object.username === this.username && object.discriminator === this.discriminator;
+ }
+ }, {
+ key: "avatarURL",
+ get: function get() {
+ if (!this.avatar) return null;
+ return "https://discordapp.com/api/users/" + this.id + "/avatars/" + this.avatar + ".jpg";
+ }
+ }]);
+
+ return User;
+})();
+
+module.exports = User;
+},{}],10:[function(require,module,exports){
+
+},{}],11:[function(require,module,exports){
+/**
+ * Module dependencies.
+ */
+
+var Emitter = require('emitter');
+var reduce = require('reduce');
+
+/**
+ * Root reference for iframes.
+ */
+
+var root = 'undefined' == typeof window
+ ? (this || self)
+ : window;
+
+/**
+ * Noop.
+ */
+
+function noop(){};
+
+/**
+ * Check if `obj` is a host object,
+ * we don't want to serialize these :)
+ *
+ * TODO: future proof, move to compoent land
+ *
+ * @param {Object} obj
+ * @return {Boolean}
+ * @api private
+ */
+
+function isHost(obj) {
+ var str = {}.toString.call(obj);
+
+ switch (str) {
+ case '[object File]':
+ case '[object Blob]':
+ case '[object FormData]':
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Determine XHR.
+ */
+
+request.getXHR = function () {
+ if (root.XMLHttpRequest
+ && (!root.location || 'file:' != root.location.protocol
+ || !root.ActiveXObject)) {
+ return new XMLHttpRequest;
+ } else {
+ try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {}
+ }
+ return false;
+};
+
+/**
+ * Removes leading and trailing whitespace, added to support IE.
+ *
+ * @param {String} s
+ * @return {String}
+ * @api private
+ */
+
+var trim = ''.trim
+ ? function(s) { return s.trim(); }
+ : function(s) { return s.replace(/(^\s*|\s*$)/g, ''); };
+
+/**
+ * Check if `obj` is an object.
+ *
+ * @param {Object} obj
+ * @return {Boolean}
+ * @api private
+ */
+
+function isObject(obj) {
+ return obj === Object(obj);
+}
+
+/**
+ * Serialize the given `obj`.
+ *
+ * @param {Object} obj
+ * @return {String}
+ * @api private
+ */
+
+function serialize(obj) {
+ if (!isObject(obj)) return obj;
+ var pairs = [];
+ for (var key in obj) {
+ if (null != obj[key]) {
+ pairs.push(encodeURIComponent(key)
+ + '=' + encodeURIComponent(obj[key]));
+ }
+ }
+ return pairs.join('&');
+}
+
+/**
+ * Expose serialization method.
+ */
+
+ request.serializeObject = serialize;
+
+ /**
+ * Parse the given x-www-form-urlencoded `str`.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+function parseString(str) {
+ var obj = {};
+ var pairs = str.split('&');
+ var parts;
+ var pair;
+
+ for (var i = 0, len = pairs.length; i < len; ++i) {
+ pair = pairs[i];
+ parts = pair.split('=');
+ obj[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
+ }
+
+ return obj;
+}
+
+/**
+ * Expose parser.
+ */
+
+request.parseString = parseString;
+
+/**
+ * Default MIME type map.
+ *
+ * superagent.types.xml = 'application/xml';
+ *
+ */
+
+request.types = {
+ html: 'text/html',
+ json: 'application/json',
+ xml: 'application/xml',
+ urlencoded: 'application/x-www-form-urlencoded',
+ 'form': 'application/x-www-form-urlencoded',
+ 'form-data': 'application/x-www-form-urlencoded'
+};
+
+/**
+ * Default serialization map.
+ *
+ * superagent.serialize['application/xml'] = function(obj){
+ * return 'generated xml here';
+ * };
+ *
+ */
+
+ request.serialize = {
+ 'application/x-www-form-urlencoded': serialize,
+ 'application/json': JSON.stringify
+ };
+
+ /**
+ * Default parsers.
+ *
+ * superagent.parse['application/xml'] = function(str){
+ * return { object parsed from str };
+ * };
+ *
+ */
+
+request.parse = {
+ 'application/x-www-form-urlencoded': parseString,
+ 'application/json': JSON.parse
+};
+
+/**
+ * Parse the given header `str` into
+ * an object containing the mapped fields.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+function parseHeader(str) {
+ var lines = str.split(/\r?\n/);
+ var fields = {};
+ var index;
+ var line;
+ var field;
+ var val;
+
+ lines.pop(); // trailing CRLF
+
+ for (var i = 0, len = lines.length; i < len; ++i) {
+ line = lines[i];
+ index = line.indexOf(':');
+ field = line.slice(0, index).toLowerCase();
+ val = trim(line.slice(index + 1));
+ fields[field] = val;
+ }
+
+ return fields;
+}
+
+/**
+ * Return the mime type for the given `str`.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+function type(str){
+ return str.split(/ *; */).shift();
+};
+
+/**
+ * Return header field parameters.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+function params(str){
+ return reduce(str.split(/ *; */), function(obj, str){
+ var parts = str.split(/ *= */)
+ , key = parts.shift()
+ , val = parts.shift();
+
+ if (key && val) obj[key] = val;
+ return obj;
+ }, {});
+};
+
+/**
+ * Initialize a new `Response` with the given `xhr`.
+ *
+ * - set flags (.ok, .error, etc)
+ * - parse header
+ *
+ * Examples:
+ *
+ * Aliasing `superagent` as `request` is nice:
+ *
+ * request = superagent;
+ *
+ * We can use the promise-like API, or pass callbacks:
+ *
+ * request.get('/').end(function(res){});
+ * request.get('/', function(res){});
+ *
+ * Sending data can be chained:
+ *
+ * request
+ * .post('/user')
+ * .send({ name: 'tj' })
+ * .end(function(res){});
+ *
+ * Or passed to `.send()`:
+ *
+ * request
+ * .post('/user')
+ * .send({ name: 'tj' }, function(res){});
+ *
+ * Or passed to `.post()`:
+ *
+ * request
+ * .post('/user', { name: 'tj' })
+ * .end(function(res){});
+ *
+ * Or further reduced to a single call for simple cases:
+ *
+ * request
+ * .post('/user', { name: 'tj' }, function(res){});
+ *
+ * @param {XMLHTTPRequest} xhr
+ * @param {Object} options
+ * @api private
+ */
+
+function Response(req, options) {
+ options = options || {};
+ this.req = req;
+ this.xhr = this.req.xhr;
+ // responseText is accessible only if responseType is '' or 'text' and on older browsers
+ this.text = ((this.req.method !='HEAD' && (this.xhr.responseType === '' || this.xhr.responseType === 'text')) || typeof this.xhr.responseType === 'undefined')
+ ? this.xhr.responseText
+ : null;
+ this.statusText = this.req.xhr.statusText;
+ this.setStatusProperties(this.xhr.status);
+ this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders());
+ // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but
+ // getResponseHeader still works. so we get content-type even if getting
+ // other headers fails.
+ this.header['content-type'] = this.xhr.getResponseHeader('content-type');
+ this.setHeaderProperties(this.header);
+ this.body = this.req.method != 'HEAD'
+ ? this.parseBody(this.text ? this.text : this.xhr.response)
+ : null;
+}
+
+/**
+ * Get case-insensitive `field` value.
+ *
+ * @param {String} field
+ * @return {String}
+ * @api public
+ */
+
+Response.prototype.get = function(field){
+ return this.header[field.toLowerCase()];
+};
+
+/**
+ * Set header related properties:
+ *
+ * - `.type` the content type without params
+ *
+ * A response of "Content-Type: text/plain; charset=utf-8"
+ * will provide you with a `.type` of "text/plain".
+ *
+ * @param {Object} header
+ * @api private
+ */
+
+Response.prototype.setHeaderProperties = function(header){
+ // content-type
+ var ct = this.header['content-type'] || '';
+ this.type = type(ct);
+
+ // params
+ var obj = params(ct);
+ for (var key in obj) this[key] = obj[key];
+};
+
+/**
+ * Parse the given body `str`.
+ *
+ * Used for auto-parsing of bodies. Parsers
+ * are defined on the `superagent.parse` object.
+ *
+ * @param {String} str
+ * @return {Mixed}
+ * @api private
+ */
+
+Response.prototype.parseBody = function(str){
+ var parse = request.parse[this.type];
+ return parse && str && (str.length || str instanceof Object)
+ ? parse(str)
+ : null;
+};
+
+/**
+ * Set flags such as `.ok` based on `status`.
+ *
+ * For example a 2xx response will give you a `.ok` of __true__
+ * whereas 5xx will be __false__ and `.error` will be __true__. The
+ * `.clientError` and `.serverError` are also available to be more
+ * specific, and `.statusType` is the class of error ranging from 1..5
+ * sometimes useful for mapping respond colors etc.
+ *
+ * "sugar" properties are also defined for common cases. Currently providing:
+ *
+ * - .noContent
+ * - .badRequest
+ * - .unauthorized
+ * - .notAcceptable
+ * - .notFound
+ *
+ * @param {Number} status
+ * @api private
+ */
+
+Response.prototype.setStatusProperties = function(status){
+ // handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request
+ if (status === 1223) {
+ status = 204;
+ }
+
+ var type = status / 100 | 0;
+
+ // status / class
+ this.status = status;
+ this.statusType = type;
+
+ // basics
+ this.info = 1 == type;
+ this.ok = 2 == type;
+ this.clientError = 4 == type;
+ this.serverError = 5 == type;
+ this.error = (4 == type || 5 == type)
+ ? this.toError()
+ : false;
+
+ // sugar
+ this.accepted = 202 == status;
+ this.noContent = 204 == status;
+ this.badRequest = 400 == status;
+ this.unauthorized = 401 == status;
+ this.notAcceptable = 406 == status;
+ this.notFound = 404 == status;
+ this.forbidden = 403 == status;
+};
+
+/**
+ * Return an `Error` representative of this response.
+ *
+ * @return {Error}
+ * @api public
+ */
+
+Response.prototype.toError = function(){
+ var req = this.req;
+ var method = req.method;
+ var url = req.url;
+
+ var msg = 'cannot ' + method + ' ' + url + ' (' + this.status + ')';
+ var err = new Error(msg);
+ err.status = this.status;
+ err.method = method;
+ err.url = url;
+
+ return err;
+};
+
+/**
+ * Expose `Response`.
+ */
+
+request.Response = Response;
+
+/**
+ * Initialize a new `Request` with the given `method` and `url`.
+ *
+ * @param {String} method
+ * @param {String} url
+ * @api public
+ */
+
+function Request(method, url) {
+ var self = this;
+ Emitter.call(this);
+ this._query = this._query || [];
+ this.method = method;
+ this.url = url;
+ this.header = {};
+ this._header = {};
+ this.on('end', function(){
+ var err = null;
+ var res = null;
+
+ try {
+ res = new Response(self);
+ } catch(e) {
+ err = new Error('Parser is unable to parse the response');
+ err.parse = true;
+ err.original = e;
+ return self.callback(err);
+ }
+
+ self.emit('response', res);
+
+ if (err) {
+ return self.callback(err, res);
+ }
+
+ if (res.status >= 200 && res.status < 300) {
+ return self.callback(err, res);
+ }
+
+ var new_err = new Error(res.statusText || 'Unsuccessful HTTP response');
+ new_err.original = err;
+ new_err.response = res;
+ new_err.status = res.status;
+
+ self.callback(new_err, res);
+ });
+}
+
+/**
+ * Mixin `Emitter`.
+ */
+
+Emitter(Request.prototype);
+
+/**
+ * Allow for extension
+ */
+
+Request.prototype.use = function(fn) {
+ fn(this);
+ return this;
+}
+
+/**
+ * Set timeout to `ms`.
+ *
+ * @param {Number} ms
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.timeout = function(ms){
+ this._timeout = ms;
+ return this;
+};
+
+/**
+ * Clear previous timeout.
+ *
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.clearTimeout = function(){
+ this._timeout = 0;
+ clearTimeout(this._timer);
+ return this;
+};
+
+/**
+ * Abort the request, and clear potential timeout.
+ *
+ * @return {Request}
+ * @api public
+ */
+
+Request.prototype.abort = function(){
+ if (this.aborted) return;
+ this.aborted = true;
+ this.xhr.abort();
+ this.clearTimeout();
+ this.emit('abort');
+ return this;
+};
+
+/**
+ * Set header `field` to `val`, or multiple fields with one object.
+ *
+ * Examples:
+ *
+ * req.get('/')
+ * .set('Accept', 'application/json')
+ * .set('X-API-Key', 'foobar')
+ * .end(callback);
+ *
+ * req.get('/')
+ * .set({ Accept: 'application/json', 'X-API-Key': 'foobar' })
+ * .end(callback);
+ *
+ * @param {String|Object} field
+ * @param {String} val
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.set = function(field, val){
+ if (isObject(field)) {
+ for (var key in field) {
+ this.set(key, field[key]);
+ }
+ return this;
+ }
+ this._header[field.toLowerCase()] = val;
+ this.header[field] = val;
+ return this;
+};
+
+/**
+ * Remove header `field`.
+ *
+ * Example:
+ *
+ * req.get('/')
+ * .unset('User-Agent')
+ * .end(callback);
+ *
+ * @param {String} field
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.unset = function(field){
+ delete this._header[field.toLowerCase()];
+ delete this.header[field];
+ return this;
+};
+
+/**
+ * Get case-insensitive header `field` value.
+ *
+ * @param {String} field
+ * @return {String}
+ * @api private
+ */
+
+Request.prototype.getHeader = function(field){
+ return this._header[field.toLowerCase()];
+};
+
+/**
+ * Set Content-Type to `type`, mapping values from `request.types`.
+ *
+ * Examples:
+ *
+ * superagent.types.xml = 'application/xml';
+ *
+ * request.post('/')
+ * .type('xml')
+ * .send(xmlstring)
+ * .end(callback);
+ *
+ * request.post('/')
+ * .type('application/xml')
+ * .send(xmlstring)
+ * .end(callback);
+ *
+ * @param {String} type
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.type = function(type){
+ this.set('Content-Type', request.types[type] || type);
+ return this;
+};
+
+/**
+ * Set Accept to `type`, mapping values from `request.types`.
+ *
+ * Examples:
+ *
+ * superagent.types.json = 'application/json';
+ *
+ * request.get('/agent')
+ * .accept('json')
+ * .end(callback);
+ *
+ * request.get('/agent')
+ * .accept('application/json')
+ * .end(callback);
+ *
+ * @param {String} accept
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.accept = function(type){
+ this.set('Accept', request.types[type] || type);
+ return this;
+};
+
+/**
+ * Set Authorization field value with `user` and `pass`.
+ *
+ * @param {String} user
+ * @param {String} pass
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.auth = function(user, pass){
+ var str = btoa(user + ':' + pass);
+ this.set('Authorization', 'Basic ' + str);
+ return this;
+};
+
+/**
+* Add query-string `val`.
+*
+* Examples:
+*
+* request.get('/shoes')
+* .query('size=10')
+* .query({ color: 'blue' })
+*
+* @param {Object|String} val
+* @return {Request} for chaining
+* @api public
+*/
+
+Request.prototype.query = function(val){
+ if ('string' != typeof val) val = serialize(val);
+ if (val) this._query.push(val);
+ return this;
+};
+
+/**
+ * Write the field `name` and `val` for "multipart/form-data"
+ * request bodies.
+ *
+ * ``` js
+ * request.post('/upload')
+ * .field('foo', 'bar')
+ * .end(callback);
+ * ```
+ *
+ * @param {String} name
+ * @param {String|Blob|File} val
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.field = function(name, val){
+ if (!this._formData) this._formData = new root.FormData();
+ this._formData.append(name, val);
+ return this;
+};
+
+/**
+ * Queue the given `file` as an attachment to the specified `field`,
+ * with optional `filename`.
+ *
+ * ``` js
+ * request.post('/upload')
+ * .attach(new Blob(['hey! '], { type: "text/html"}))
+ * .end(callback);
+ * ```
+ *
+ * @param {String} field
+ * @param {Blob|File} file
+ * @param {String} filename
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.attach = function(field, file, filename){
+ if (!this._formData) this._formData = new root.FormData();
+ this._formData.append(field, file, filename);
+ return this;
+};
+
+/**
+ * Send `data`, defaulting the `.type()` to "json" when
+ * an object is given.
+ *
+ * Examples:
+ *
+ * // querystring
+ * request.get('/search')
+ * .end(callback)
+ *
+ * // multiple data "writes"
+ * request.get('/search')
+ * .send({ search: 'query' })
+ * .send({ range: '1..5' })
+ * .send({ order: 'desc' })
+ * .end(callback)
+ *
+ * // manual json
+ * request.post('/user')
+ * .type('json')
+ * .send('{"name":"tj"})
+ * .end(callback)
+ *
+ * // auto json
+ * request.post('/user')
+ * .send({ name: 'tj' })
+ * .end(callback)
+ *
+ * // manual x-www-form-urlencoded
+ * request.post('/user')
+ * .type('form')
+ * .send('name=tj')
+ * .end(callback)
+ *
+ * // auto x-www-form-urlencoded
+ * request.post('/user')
+ * .type('form')
+ * .send({ name: 'tj' })
+ * .end(callback)
+ *
+ * // defaults to x-www-form-urlencoded
+ * request.post('/user')
+ * .send('name=tobi')
+ * .send('species=ferret')
+ * .end(callback)
+ *
+ * @param {String|Object} data
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.send = function(data){
+ var obj = isObject(data);
+ var type = this.getHeader('Content-Type');
+
+ // merge
+ if (obj && isObject(this._data)) {
+ for (var key in data) {
+ this._data[key] = data[key];
+ }
+ } else if ('string' == typeof data) {
+ if (!type) this.type('form');
+ type = this.getHeader('Content-Type');
+ if ('application/x-www-form-urlencoded' == type) {
+ this._data = this._data
+ ? this._data + '&' + data
+ : data;
+ } else {
+ this._data = (this._data || '') + data;
+ }
+ } else {
+ this._data = data;
+ }
+
+ if (!obj || isHost(data)) return this;
+ if (!type) this.type('json');
+ return this;
+};
+
+/**
+ * Invoke the callback with `err` and `res`
+ * and handle arity check.
+ *
+ * @param {Error} err
+ * @param {Response} res
+ * @api private
+ */
+
+Request.prototype.callback = function(err, res){
+ var fn = this._callback;
+ this.clearTimeout();
+ fn(err, res);
+};
+
+/**
+ * Invoke callback with x-domain error.
+ *
+ * @api private
+ */
+
+Request.prototype.crossDomainError = function(){
+ var err = new Error('Origin is not allowed by Access-Control-Allow-Origin');
+ err.crossDomain = true;
+ this.callback(err);
+};
+
+/**
+ * Invoke callback with timeout error.
+ *
+ * @api private
+ */
+
+Request.prototype.timeoutError = function(){
+ var timeout = this._timeout;
+ var err = new Error('timeout of ' + timeout + 'ms exceeded');
+ err.timeout = timeout;
+ this.callback(err);
+};
+
+/**
+ * Enable transmission of cookies with x-domain requests.
+ *
+ * Note that for this to work the origin must not be
+ * using "Access-Control-Allow-Origin" with a wildcard,
+ * and also must set "Access-Control-Allow-Credentials"
+ * to "true".
+ *
+ * @api public
+ */
+
+Request.prototype.withCredentials = function(){
+ this._withCredentials = true;
+ return this;
+};
+
+/**
+ * Initiate request, invoking callback `fn(res)`
+ * with an instanceof `Response`.
+ *
+ * @param {Function} fn
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.end = function(fn){
+ var self = this;
+ var xhr = this.xhr = request.getXHR();
+ var query = this._query.join('&');
+ var timeout = this._timeout;
+ var data = this._formData || this._data;
+
+ // store callback
+ this._callback = fn || noop;
+
+ // state change
+ xhr.onreadystatechange = function(){
+ if (4 != xhr.readyState) return;
+
+ // In IE9, reads to any property (e.g. status) off of an aborted XHR will
+ // result in the error "Could not complete the operation due to error c00c023f"
+ var status;
+ try { status = xhr.status } catch(e) { status = 0; }
+
+ if (0 == status) {
+ if (self.timedout) return self.timeoutError();
+ if (self.aborted) return;
+ return self.crossDomainError();
+ }
+ self.emit('end');
+ };
+
+ // progress
+ var handleProgress = function(e){
+ if (e.total > 0) {
+ e.percent = e.loaded / e.total * 100;
+ }
+ self.emit('progress', e);
+ };
+ if (this.hasListeners('progress')) {
+ xhr.onprogress = handleProgress;
+ }
+ try {
+ if (xhr.upload && this.hasListeners('progress')) {
+ xhr.upload.onprogress = handleProgress;
+ }
+ } catch(e) {
+ // Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist.
+ // Reported here:
+ // https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web-worker-context
+ }
+
+ // timeout
+ if (timeout && !this._timer) {
+ this._timer = setTimeout(function(){
+ self.timedout = true;
+ self.abort();
+ }, timeout);
+ }
+
+ // querystring
+ if (query) {
+ query = request.serializeObject(query);
+ this.url += ~this.url.indexOf('?')
+ ? '&' + query
+ : '?' + query;
+ }
+
+ // initiate request
+ xhr.open(this.method, this.url, true);
+
+ // CORS
+ if (this._withCredentials) xhr.withCredentials = true;
+
+ // body
+ if ('GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !isHost(data)) {
+ // serialize stuff
+ var contentType = this.getHeader('Content-Type');
+ var serialize = request.serialize[contentType ? contentType.split(';')[0] : ''];
+ if (serialize) data = serialize(data);
+ }
+
+ // set header fields
+ for (var field in this.header) {
+ if (null == this.header[field]) continue;
+ xhr.setRequestHeader(field, this.header[field]);
+ }
+
+ // send stuff
+ this.emit('request', this);
+ xhr.send(data);
+ return this;
+};
+
+/**
+ * Faux promise support
+ *
+ * @param {Function} fulfill
+ * @param {Function} reject
+ * @return {Request}
+ */
+
+Request.prototype.then = function (fulfill, reject) {
+ return this.end(function(err, res) {
+ err ? reject(err) : fulfill(res);
+ });
+}
+
+/**
+ * Expose `Request`.
+ */
+
+request.Request = Request;
+
+/**
+ * Issue a request:
+ *
+ * Examples:
+ *
+ * request('GET', '/users').end(callback)
+ * request('/users').end(callback)
+ * request('/users', callback)
+ *
+ * @param {String} method
+ * @param {String|Function} url or callback
+ * @return {Request}
+ * @api public
+ */
+
+function request(method, url) {
+ // callback
+ if ('function' == typeof url) {
+ return new Request('GET', method).end(url);
+ }
+
+ // url first
+ if (1 == arguments.length) {
+ return new Request('GET', method);
+ }
+
+ return new Request(method, url);
+}
+
+/**
+ * GET `url` with optional callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed|Function} data or fn
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.get = function(url, data, fn){
+ var req = request('GET', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.query(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * HEAD `url` with optional callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed|Function} data or fn
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.head = function(url, data, fn){
+ var req = request('HEAD', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * DELETE `url` with optional callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.del = function(url, fn){
+ var req = request('DELETE', url);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * PATCH `url` with optional `data` and callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed} data
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.patch = function(url, data, fn){
+ var req = request('PATCH', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * POST `url` with optional `data` and callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed} data
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.post = function(url, data, fn){
+ var req = request('POST', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * PUT `url` with optional `data` and callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed|Function} data or fn
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.put = function(url, data, fn){
+ var req = request('PUT', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * Expose `request`.
+ */
+
+module.exports = request;
+
+},{"emitter":12,"reduce":13}],12:[function(require,module,exports){
+
+/**
+ * Expose `Emitter`.
+ */
+
+module.exports = Emitter;
+
+/**
+ * Initialize a new `Emitter`.
+ *
+ * @api public
+ */
+
+function Emitter(obj) {
+ if (obj) return mixin(obj);
+};
+
+/**
+ * Mixin the emitter properties.
+ *
+ * @param {Object} obj
+ * @return {Object}
+ * @api private
+ */
+
+function mixin(obj) {
+ for (var key in Emitter.prototype) {
+ obj[key] = Emitter.prototype[key];
+ }
+ return obj;
+}
+
+/**
+ * Listen on the given `event` with `fn`.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ * @return {Emitter}
+ * @api public
+ */
+
+Emitter.prototype.on =
+Emitter.prototype.addEventListener = function(event, fn){
+ this._callbacks = this._callbacks || {};
+ (this._callbacks[event] = this._callbacks[event] || [])
+ .push(fn);
+ return this;
+};
+
+/**
+ * Adds an `event` listener that will be invoked a single
+ * time then automatically removed.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ * @return {Emitter}
+ * @api public
+ */
+
+Emitter.prototype.once = function(event, fn){
+ var self = this;
+ this._callbacks = this._callbacks || {};
+
+ function on() {
+ self.off(event, on);
+ fn.apply(this, arguments);
+ }
+
+ on.fn = fn;
+ this.on(event, on);
+ return this;
+};
+
+/**
+ * Remove the given callback for `event` or all
+ * registered callbacks.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ * @return {Emitter}
+ * @api public
+ */
+
+Emitter.prototype.off =
+Emitter.prototype.removeListener =
+Emitter.prototype.removeAllListeners =
+Emitter.prototype.removeEventListener = function(event, fn){
+ this._callbacks = this._callbacks || {};
+
+ // all
+ if (0 == arguments.length) {
+ this._callbacks = {};
+ return this;
+ }
+
+ // specific event
+ var callbacks = this._callbacks[event];
+ if (!callbacks) return this;
+
+ // remove all handlers
+ if (1 == arguments.length) {
+ delete this._callbacks[event];
+ return this;
+ }
+
+ // remove specific handler
+ var cb;
+ for (var i = 0; i < callbacks.length; i++) {
+ cb = callbacks[i];
+ if (cb === fn || cb.fn === fn) {
+ callbacks.splice(i, 1);
+ break;
+ }
+ }
+ return this;
+};
+
+/**
+ * Emit `event` with the given args.
+ *
+ * @param {String} event
+ * @param {Mixed} ...
+ * @return {Emitter}
+ */
+
+Emitter.prototype.emit = function(event){
+ this._callbacks = this._callbacks || {};
+ var args = [].slice.call(arguments, 1)
+ , callbacks = this._callbacks[event];
+
+ if (callbacks) {
+ callbacks = callbacks.slice(0);
+ for (var i = 0, len = callbacks.length; i < len; ++i) {
+ callbacks[i].apply(this, args);
+ }
+ }
+
+ return this;
+};
+
+/**
+ * Return array of callbacks for `event`.
+ *
+ * @param {String} event
+ * @return {Array}
+ * @api public
+ */
+
+Emitter.prototype.listeners = function(event){
+ this._callbacks = this._callbacks || {};
+ return this._callbacks[event] || [];
+};
+
+/**
+ * Check if this emitter has `event` handlers.
+ *
+ * @param {String} event
+ * @return {Boolean}
+ * @api public
+ */
+
+Emitter.prototype.hasListeners = function(event){
+ return !! this.listeners(event).length;
+};
+
+},{}],13:[function(require,module,exports){
+
+/**
+ * Reduce `arr` with `fn`.
+ *
+ * @param {Array} arr
+ * @param {Function} fn
+ * @param {Mixed} initial
+ *
+ * TODO: combatible error handling?
+ */
+
+module.exports = function(arr, fn, initial){
+ var idx = 0;
+ var len = arr.length;
+ var curr = arguments.length == 3
+ ? initial
+ : arr[idx++];
+
+ while (idx < len) {
+ curr = fn.call(null, curr, arr[idx], ++idx, arr);
+ }
+
+ return curr;
+};
+},{}],14:[function(require,module,exports){
+
+/**
+ * Module dependencies.
+ */
+
+var global = (function() { return this; })();
+
+/**
+ * WebSocket constructor.
+ */
+
+var WebSocket = global.WebSocket || global.MozWebSocket;
+
+/**
+ * Module exports.
+ */
+
+module.exports = WebSocket ? ws : null;
+
+/**
+ * WebSocket constructor.
+ *
+ * The third `opts` options object gets ignored in web browsers, since it's
+ * non-standard, and throws a TypeError if passed to the constructor.
+ * See: https://github.com/einaros/ws/issues/227
+ *
+ * @param {String} uri
+ * @param {Array} protocols (optional)
+ * @param {Object) opts (optional)
+ * @api public
+ */
+
+function ws(uri, protocols, opts) {
+ var instance;
+ if (protocols) {
+ instance = new WebSocket(uri, protocols);
+ } else {
+ instance = new WebSocket(uri);
+ }
+ return instance;
+}
+
+if (WebSocket) ws.prototype = WebSocket.prototype;
+
+},{}]},{},[5])(5)
+});
\ No newline at end of file
diff --git a/web-dist/discord.3.6.3.js b/web-dist/discord.3.6.3.js
new file mode 100644
index 000000000..0d9f9341a
--- /dev/null
+++ b/web-dist/discord.3.6.3.js
@@ -0,0 +1,3879 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Discord = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o]*>/g) || [])[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var mention = _step3.value;
+
+ _mentions.push(mention.substring(2, mention.length - 1));
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3["return"]) {
+ _iterator3["return"]();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ return _mentions;
+ }
+ });
+
+ return prom;
+ }
+
+ //def createws
+ }, {
+ key: "createws",
+ value: function createws(url) {
+ if (this.websocket) return false;
+
+ var self = this;
+
+ //good to go
+ this.websocket = new WebSocket(url);
+
+ //open
+ this.websocket.onopen = function () {
+ self.trySendConnData(); //try connecting
+ };
+
+ //close
+ this.websocket.onclose = function () {
+ self.trigger("disconnected");
+ };
+
+ //message
+ this.websocket.onmessage = function (e) {
+
+ var dat = false,
+ data = {};
+
+ try {
+ dat = JSON.parse(e.data);
+ data = dat.d;
+ } catch (err) {
+ self.trigger("error", err, e);
+ return;
+ }
+
+ self.trigger("raw", dat);
+
+ //valid message
+ switch (dat.t) {
+
+ case "READY":
+ self.debug("received ready packet");
+
+ self.user = self.addUser(data.user);
+
+ var _iteratorNormalCompletion4 = true;
+ var _didIteratorError4 = false;
+ var _iteratorError4 = undefined;
+
+ try {
+ for (var _iterator4 = data.guilds[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
+ var _server = _step4.value;
+
+ var server = self.addServer(_server);
+ }
+ } catch (err) {
+ _didIteratorError4 = true;
+ _iteratorError4 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion4 && _iterator4["return"]) {
+ _iterator4["return"]();
+ }
+ } finally {
+ if (_didIteratorError4) {
+ throw _iteratorError4;
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion5 = true;
+ var _didIteratorError5 = false;
+ var _iteratorError5 = undefined;
+
+ try {
+ for (var _iterator5 = data.private_channels[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
+ var _pmc = _step5.value;
+
+ var pmc = self.addPMChannel(_pmc);
+ }
+ } catch (err) {
+ _didIteratorError5 = true;
+ _iteratorError5 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion5 && _iterator5["return"]) {
+ _iterator5["return"]();
+ }
+ } finally {
+ if (_didIteratorError5) {
+ throw _iteratorError5;
+ }
+ }
+ }
+
+ self.trigger("ready");
+ self.readyTime = Date.now();
+ self.debug("cached " + self.serverCache.length + " servers, " + self.channelCache.length + " channels, " + self.pmChannelCache.length + " PMs and " + self.userCache.length + " users.");
+ self.state = 3;
+ setInterval(function () {
+ self.keepAlive.apply(self);
+ }, data.heartbeat_interval);
+
+ break;
+ case "MESSAGE_CREATE":
+ self.debug("received message");
+
+ var mentions = [];
+ data.mentions = data.mentions || []; //for some reason this was not defined at some point?
+ var _iteratorNormalCompletion6 = true;
+ var _didIteratorError6 = false;
+ var _iteratorError6 = undefined;
+
+ try {
+ for (var _iterator6 = data.mentions[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
+ var mention = _step6.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError6 = true;
+ _iteratorError6 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion6 && _iterator6["return"]) {
+ _iterator6["return"]();
+ }
+ } finally {
+ if (_didIteratorError6) {
+ throw _iteratorError6;
+ }
+ }
+ }
+
+ var channel = self.getChannel("id", data.channel_id);
+ if (channel) {
+ var msg = channel.addMessage(new Message(data, channel, mentions, self.addUser(data.author)));
+ self.trigger("message", msg);
+ }
+
+ break;
+ case "MESSAGE_DELETE":
+ self.debug("message deleted");
+
+ var channel = self.getChannel("id", data.channel_id);
+ var message = channel.getMessage("id", data.id);
+ if (message) {
+ self.trigger("messageDelete", channel, message);
+ channel.messages.splice(channel.messages.indexOf(message), 1);
+ } else {
+ //don't have the cache of that message ;(
+ self.trigger("messageDelete", channel);
+ }
+ break;
+ case "MESSAGE_UPDATE":
+ self.debug("message updated");
+
+ var channel = self.getChannel("id", data.channel_id);
+ var formerMessage = channel.getMessage("id", data.id);
+
+ if (formerMessage) {
+
+ //new message might be partial, so we need to fill it with whatever the old message was.
+ var info = {};
+
+ for (var key in formerMessage) {
+ info[key] = formerMessage[key];
+ }
+
+ for (var key in data) {
+ info[key] = data[key];
+ }
+
+ var mentions = [];
+ var _iteratorNormalCompletion7 = true;
+ var _didIteratorError7 = false;
+ var _iteratorError7 = undefined;
+
+ try {
+ for (var _iterator7 = info.mentions[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
+ var mention = _step7.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError7 = true;
+ _iteratorError7 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion7 && _iterator7["return"]) {
+ _iterator7["return"]();
+ }
+ } finally {
+ if (_didIteratorError7) {
+ throw _iteratorError7;
+ }
+ }
+ }
+
+ var newMessage = new Message(info, channel, mentions, formerMessage.author);
+
+ self.trigger("messageUpdate", newMessage, formerMessage);
+
+ channel.messages[channel.messages.indexOf(formerMessage)] = newMessage;
+ }
+
+ // message isn't in cache, and if it's a partial it could cause
+ // all hell to break loose... best to just act as if nothing happened
+
+ break;
+
+ case "GUILD_DELETE":
+
+ var server = self.getServer("id", data.id);
+
+ if (server) {
+ self.serverCache.splice(self.serverCache.indexOf(server), 1);
+ self.trigger("serverDelete", server);
+ }
+
+ break;
+
+ case "CHANNEL_DELETE":
+
+ var channel = self.getChannel("id", data.id);
+
+ if (channel) {
+
+ var server = channel.server;
+
+ if (server) {
+
+ server.channels.splice(server.channels.indexOf(channel), 1);
+ }
+
+ self.trigger("channelDelete", channel);
+
+ self.serverCache.splice(self.serverCache.indexOf(channel), 1);
+ }
+
+ break;
+
+ case "GUILD_CREATE":
+
+ var server = self.getServer("id", data.id);
+
+ if (!server) {
+ //if server doesn't already exist because duh
+ server = self.addServer(data);
+ } /*else if(server.channels.length === 0){
+
+ var srv = new Server(data, self);
+ for(channel of data.channels){
+ srv.channels.push(new Channel(channel, data.id));
+ }
+ self.serverCache[self.serverCache.indexOf(server)] = srv;
+
+ }*/
+
+ if (self.serverCreateListener[data.id]) {
+ var cbs = self.serverCreateListener[data.id];
+ cbs[0](server); //promise then callback
+ cbs[1](null, server); //legacy callback
+ self.serverCreateListener[data.id] = null;
+ }
+
+ self.trigger("serverCreate", server);
+
+ break;
+
+ case "CHANNEL_CREATE":
+
+ var channel = self.getChannel("id", data.id);
+
+ if (!channel) {
+
+ var chann = self.addChannel(data, data.guild_id);
+ var srv = self.getServer("id", data.guild_id);
+ if (srv) {
+ srv.addChannel(chann);
+ }
+ self.trigger("channelCreate", chann);
+ }
+
+ break;
+
+ case "GUILD_MEMBER_ADD":
+
+ var server = self.getServer("id", data.guild_id);
+
+ if (server) {
+
+ var user = self.addUser(data.user); //if for whatever reason it doesn't exist..
+
+ if (! ~server.members.indexOf(user)) {
+ server.members.push(user);
+ }
+
+ self.trigger("serverNewMember", user, server);
+ }
+
+ break;
+
+ case "GUILD_MEMBER_REMOVE":
+
+ var server = self.getServer("id", data.guild_id);
+
+ if (server) {
+
+ var user = self.addUser(data.user); //if for whatever reason it doesn't exist..
+
+ if (~server.members.indexOf(user)) {
+ server.members.splice(server.members.indexOf(user), 1);
+ }
+
+ self.trigger("serverRemoveMember", user, server);
+ }
+
+ break;
+
+ case "USER_UPDATE":
+
+ if (self.user && data.id === self.user.id) {
+
+ var newUser = new User(data); //not actually adding to the cache
+
+ self.trigger("userUpdate", newUser, self.user);
+
+ if (~self.userCache.indexOf(self.user)) {
+ self.userCache[self.userCache.indexOf(self.user)] = newUser;
+ }
+
+ self.user = newUser;
+ }
+
+ break;
+
+ case "PRESENCE_UPDATE":
+
+ var userInCache = self.getUser("id", data.user.id);
+
+ if (userInCache) {
+ //user exists
+ var presenceUser = new User(data.user);
+ if (presenceUser.equalsStrict(userInCache)) {
+ //they're exactly the same, an actual presence update
+ userInCache.status = data.status;
+ self.trigger("presence", {
+ user: userInCache,
+ status: data.status,
+ server: self.getServer("id", data.guild_id),
+ gameId: data.game_id
+ });
+ } else {
+ //one of their details changed.
+ self.trigger("userUpdate", userInCache, presenceUser);
+ self.userCache[self.userCache.indexOf(userInCache)] = presenceUser;
+ }
+ }
+
+ break;
+
+ case "CHANNEL_UPDATE":
+
+ var channelInCache = self.getChannel("id", data.id),
+ serverInCache = self.getServer("id", data.guild_id);
+
+ if (channelInCache && serverInCache) {
+
+ var newChann = new Channel(data, serverInCache);
+ newChann.messages = channelInCache.messages;
+
+ self.trigger("channelUpdate", channelInCache, newChann);
+
+ self.channelCache[self.channelCache.indexOf(channelInCache)] = newChann;
+ }
+
+ break;
+
+ default:
+ self.debug("received unknown packet");
+ self.trigger("unknown", dat);
+ break;
+
+ }
+ };
+ }
+
+ //def addUser
+ }, {
+ key: "addUser",
+ value: function addUser(data) {
+ if (!this.getUser("id", data.id)) {
+ this.userCache.push(new User(data));
+ }
+ return this.getUser("id", data.id);
+ }
+
+ //def addChannel
+ }, {
+ key: "addChannel",
+ value: function addChannel(data, serverId) {
+ if (!this.getChannel("id", data.id)) {
+ this.channelCache.push(new Channel(data, this.getServer("id", serverId)));
+ }
+ return this.getChannel("id", data.id);
+ }
+ }, {
+ key: "addPMChannel",
+ value: function addPMChannel(data) {
+ if (!this.getPMChannel("id", data.id)) {
+ this.pmChannelCache.push(new PMChannel(data, this));
+ }
+ return this.getPMChannel("id", data.id);
+ }
+ }, {
+ key: "setTopic",
+ value: function setTopic(channel, topic) {
+ var callback = arguments.length <= 2 || arguments[2] === undefined ? function (err) {} : arguments[2];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ self.resolveDestination(channel).then(next)["catch"](error);
+
+ function error(e) {
+ callback(e);
+ reject(e);
+ }
+
+ function next(destination) {
+
+ var asChan = self.getChannel("id", destination);
+
+ request.patch(Endpoints.CHANNELS + "/" + destination).set("authorization", self.token).send({
+ name: asChan.name,
+ position: 0,
+ topic: topic
+ }).end(function (err, res) {
+ if (err) {
+ error(err);
+ } else {
+ asChan.topic = res.body.topic;
+ resolve();
+ callback();
+ }
+ });
+ }
+ });
+ }
+
+ //def addServer
+ }, {
+ key: "addServer",
+ value: function addServer(data) {
+
+ var self = this;
+ var server = this.getServer("id", data.id);
+
+ if (data.unavailable) {
+ self.trigger("unavailable", data);
+ self.debug("Server ID " + data.id + " has been marked unavailable by Discord. It was not cached.");
+ return;
+ }
+
+ if (!server) {
+ server = new Server(data, this);
+ this.serverCache.push(server);
+ if (data.channels) {
+ var _iteratorNormalCompletion8 = true;
+ var _didIteratorError8 = false;
+ var _iteratorError8 = undefined;
+
+ try {
+ for (var _iterator8 = data.channels[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
+ var channel = _step8.value;
+
+ server.channels.push(this.addChannel(channel, server.id));
+ }
+ } catch (err) {
+ _didIteratorError8 = true;
+ _iteratorError8 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion8 && _iterator8["return"]) {
+ _iterator8["return"]();
+ }
+ } finally {
+ if (_didIteratorError8) {
+ throw _iteratorError8;
+ }
+ }
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion9 = true;
+ var _didIteratorError9 = false;
+ var _iteratorError9 = undefined;
+
+ try {
+ for (var _iterator9 = data.presences[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
+ var presence = _step9.value;
+
+ self.getUser("id", presence.user.id).status = presence.status;
+ }
+ } catch (err) {
+ _didIteratorError9 = true;
+ _iteratorError9 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion9 && _iterator9["return"]) {
+ _iterator9["return"]();
+ }
+ } finally {
+ if (_didIteratorError9) {
+ throw _iteratorError9;
+ }
+ }
+ }
+
+ return server;
+ }
+
+ //def getUser
+ }, {
+ key: "getUser",
+ value: function getUser(key, value) {
+ var _iteratorNormalCompletion10 = true;
+ var _didIteratorError10 = false;
+ var _iteratorError10 = undefined;
+
+ try {
+ for (var _iterator10 = this.userCache[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
+ var user = _step10.value;
+
+ if (user[key] === value) {
+ return user;
+ }
+ }
+ } catch (err) {
+ _didIteratorError10 = true;
+ _iteratorError10 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion10 && _iterator10["return"]) {
+ _iterator10["return"]();
+ }
+ } finally {
+ if (_didIteratorError10) {
+ throw _iteratorError10;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def getChannel
+ }, {
+ key: "getChannel",
+ value: function getChannel(key, value) {
+ var _iteratorNormalCompletion11 = true;
+ var _didIteratorError11 = false;
+ var _iteratorError11 = undefined;
+
+ try {
+ for (var _iterator11 = this.channelCache[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
+ var channel = _step11.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError11 = true;
+ _iteratorError11 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion11 && _iterator11["return"]) {
+ _iterator11["return"]();
+ }
+ } finally {
+ if (_didIteratorError11) {
+ throw _iteratorError11;
+ }
+ }
+ }
+
+ return this.getPMChannel(key, value); //might be a PM
+ }
+ }, {
+ key: "getPMChannel",
+ value: function getPMChannel(key, value) {
+ var _iteratorNormalCompletion12 = true;
+ var _didIteratorError12 = false;
+ var _iteratorError12 = undefined;
+
+ try {
+ for (var _iterator12 = this.pmChannelCache[Symbol.iterator](), _step12; !(_iteratorNormalCompletion12 = (_step12 = _iterator12.next()).done); _iteratorNormalCompletion12 = true) {
+ var channel = _step12.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError12 = true;
+ _iteratorError12 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion12 && _iterator12["return"]) {
+ _iterator12["return"]();
+ }
+ } finally {
+ if (_didIteratorError12) {
+ throw _iteratorError12;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def getServer
+ }, {
+ key: "getServer",
+ value: function getServer(key, value) {
+ var _iteratorNormalCompletion13 = true;
+ var _didIteratorError13 = false;
+ var _iteratorError13 = undefined;
+
+ try {
+ for (var _iterator13 = this.serverCache[Symbol.iterator](), _step13; !(_iteratorNormalCompletion13 = (_step13 = _iterator13.next()).done); _iteratorNormalCompletion13 = true) {
+ var server = _step13.value;
+
+ if (server[key] === value) {
+ return server;
+ }
+ }
+ } catch (err) {
+ _didIteratorError13 = true;
+ _iteratorError13 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion13 && _iterator13["return"]) {
+ _iterator13["return"]();
+ }
+ } finally {
+ if (_didIteratorError13) {
+ throw _iteratorError13;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def trySendConnData
+ }, {
+ key: "trySendConnData",
+ value: function trySendConnData() {
+
+ if (this.token && !this.alreadySentData) {
+
+ this.alreadySentData = true;
+
+ var data = {
+ op: 2,
+ d: {
+ token: this.token,
+ v: 3,
+ properties: {
+ "$os": "discord.js",
+ "$browser": "discord.js",
+ "$device": "discord.js",
+ "$referrer": "",
+ "$referring_domain": ""
+ }
+ }
+ };
+ this.websocket.send(JSON.stringify(data));
+ }
+ }
+ }, {
+ key: "resolveServerID",
+ value: function resolveServerID(resource) {
+
+ if (resource instanceof Server) {
+ return resource.id;
+ } else if (!isNaN(resource) && resource.length && resource.length === 17) {
+ return resource;
+ }
+ }
+ }, {
+ key: "resolveDestination",
+ value: function resolveDestination(destination) {
+ var channId = false;
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ if (destination instanceof Server) {
+ channId = destination.id; //general is the same as server id
+ } else if (destination instanceof Channel) {
+ channId = destination.id;
+ } else if (destination instanceof Message) {
+ channId = destination.channel.id;
+ } else if (destination instanceof PMChannel) {
+ channId = destination.id;
+ } else if (destination instanceof User) {
+
+ //check if we have a PM
+ var _iteratorNormalCompletion14 = true;
+ var _didIteratorError14 = false;
+ var _iteratorError14 = undefined;
+
+ try {
+ for (var _iterator14 = self.pmChannelCache[Symbol.iterator](), _step14; !(_iteratorNormalCompletion14 = (_step14 = _iterator14.next()).done); _iteratorNormalCompletion14 = true) {
+ var pmc = _step14.value;
+
+ if (pmc.user.equals(destination)) {
+ resolve(pmc.id);
+ return;
+ }
+ }
+
+ //we don't, at this point we're late
+ } catch (err) {
+ _didIteratorError14 = true;
+ _iteratorError14 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion14 && _iterator14["return"]) {
+ _iterator14["return"]();
+ }
+ } finally {
+ if (_didIteratorError14) {
+ throw _iteratorError14;
+ }
+ }
+ }
+
+ self.startPM(destination).then(function (pmc) {
+ resolve(pmc.id);
+ })["catch"](reject);
+ } else {
+ channId = destination;
+ }
+ if (channId) resolve(channId);else reject();
+ });
+ }
+ }, {
+ key: "_sendMessage",
+ value: function _sendMessage(destination, content, tts, mentions) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request.post(Endpoints.CHANNELS + "/" + destination + "/messages").set("authorization", self.token).send({
+ content: content,
+ mentions: mentions,
+ tts: tts
+ }).end(function (err, res) {
+
+ if (err) {
+ reject(err);
+ } else {
+ var data = res.body;
+
+ var mentions = [];
+
+ data.mentions = data.mentions || []; //for some reason this was not defined at some point?
+
+ var _iteratorNormalCompletion15 = true;
+ var _didIteratorError15 = false;
+ var _iteratorError15 = undefined;
+
+ try {
+ for (var _iterator15 = data.mentions[Symbol.iterator](), _step15; !(_iteratorNormalCompletion15 = (_step15 = _iterator15.next()).done); _iteratorNormalCompletion15 = true) {
+ var mention = _step15.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError15 = true;
+ _iteratorError15 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion15 && _iterator15["return"]) {
+ _iterator15["return"]();
+ }
+ } finally {
+ if (_didIteratorError15) {
+ throw _iteratorError15;
+ }
+ }
+ }
+
+ var channel = self.getChannel("id", data.channel_id);
+ if (channel) {
+ var msg = channel.addMessage(new Message(data, channel, mentions, self.addUser(data.author)));
+ resolve(msg);
+ }
+ }
+ });
+ });
+ }
+ }, {
+ key: "_sendFile",
+ value: function _sendFile(destination, attachment) {
+ var attachmentName = arguments.length <= 2 || arguments[2] === undefined ? "DEFAULT BECAUSE YOU DIDN'T SPECIFY WHY.png" : arguments[2];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request.post(Endpoints.CHANNELS + "/" + destination + "/messages").set("authorization", self.token).attach("file", attachment, attachmentName).end(function (err, res) {
+
+ if (err) {
+ reject(err);
+ } else {
+
+ var chann = self.getChannel("id", destination);
+ if (chann) {
+ var msg = chann.addMessage(new Message(res.body, chann, [], self.user));
+ resolve(msg);
+ }
+ }
+ });
+ });
+ }
+ }, {
+ key: "_updateMessage",
+ value: function _updateMessage(message, content) {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ request.patch(Endpoints.CHANNELS + "/" + message.channel.id + "/messages/" + message.id).set("authorization", self.token).send({
+ content: content,
+ mentions: []
+ }).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ var msg = new Message(res.body, message.channel, message.mentions, message.sender);
+ resolve(msg);
+ message.channel.messages[message.channel.messages.indexOf(message)] = msg;
+ }
+ });
+ });
+ }
+ }, {
+ key: "_deleteMessage",
+ value: function _deleteMessage(message) {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+
+ request.del(Endpoints.CHANNELS + "/" + message.channel.id + "/messages/" + message.id).set("authorization", self.token).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve();
+ }
+ });
+ });
+ }
+ }, {
+ key: "checkQueue",
+ value: function checkQueue(channelID) {
+ var _this = this;
+
+ var self = this;
+
+ if (!this.checkingQueue[channelID]) {
+ (function () {
+ var doNext = function doNext() {
+ if (self.queue[channelID].length === 0) {
+ done();
+ return;
+ }
+ var queuedEvent = self.queue[channelID][0];
+ switch (queuedEvent.action) {
+ case "sendMessage":
+ var msgToSend = queuedEvent;
+ self._sendMessage(channelID, msgToSend.content, msgToSend.tts, msgToSend.mentions).then(function (msg) {
+ msgToSend.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToSend.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "sendFile":
+ var fileToSend = queuedEvent;
+ self._sendFile(channelID, fileToSend.attachment, fileToSend.attachmentName).then(function (msg) {
+ fileToSend.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ fileToSend.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "updateMessage":
+ var msgToUpd = queuedEvent;
+ self._updateMessage(msgToUpd.message, msgToUpd.content).then(function (msg) {
+ msgToUpd.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToUpd.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "deleteMessage":
+ var msgToDel = queuedEvent;
+ self._deleteMessage(msgToDel.message).then(function (msg) {
+ msgToDel.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToDel.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ default:
+ done();
+ break;
+ }
+ };
+
+ var done = function done() {
+ self.checkingQueue[channelID] = false;
+ return;
+ };
+
+ //if we aren't already checking this queue.
+ _this.checkingQueue[channelID] = true;
+ doNext();
+ })();
+ }
+ }
+ }, {
+ key: "getGateway",
+ value: function getGateway() {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ request.get(Endpoints.API + "/gateway").set("authorization", self.token).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(res.body.url);
+ }
+ });
+ });
+ }
+ }, {
+ key: "setStatusIdle",
+ value: function setStatusIdle() {
+ this.setStatus("idle");
+ }
+ }, {
+ key: "setStatusOnline",
+ value: function setStatusOnline() {
+ this.setStatus("online");
+ }
+ }, {
+ key: "setStatusActive",
+ value: function setStatusActive() {
+ this.setStatusOnline();
+ }
+ }, {
+ key: "setStatusHere",
+ value: function setStatusHere() {
+ this.setStatusOnline();
+ }
+ }, {
+ key: "setStatusAway",
+ value: function setStatusAway() {
+ this.setStatusIdle();
+ }
+ }, {
+ key: "startTyping",
+ value: function startTyping(chann, stopTypeTime) {
+ var self = this;
+
+ this.resolveDestination(chann).then(next);
+
+ function next(channel) {
+ if (self.typingIntervals[channel]) {
+ return;
+ }
+
+ var fn = function fn() {
+ request.post(Endpoints.CHANNELS + "/" + channel + "/typing").set("authorization", self.token).end();
+ };
+
+ fn();
+
+ var interval = setInterval(fn, 3000);
+
+ self.typingIntervals[channel] = interval;
+
+ if (stopTypeTime) {
+ setTimeout(function () {
+ self.stopTyping(channel);
+ }, stopTypeTime);
+ }
+ }
+ }
+ }, {
+ key: "stopTyping",
+ value: function stopTyping(chann) {
+ var self = this;
+
+ this.resolveDestination(chann).then(next);
+
+ function next(channel) {
+ if (!self.typingIntervals[channel]) {
+ return;
+ }
+
+ clearInterval(self.typingIntervals[channel]);
+
+ delete self.typingIntervals[channel];
+ }
+ }
+ }, {
+ key: "setStatus",
+ value: function setStatus(stat) {
+
+ var idleTime = stat === "online" ? null : Date.now();
+
+ this.__idleTime = idleTime;
+
+ this.websocket.send(JSON.stringify({
+ op: 3,
+ d: {
+ idle_since: this.__idleTime,
+ game_id: this.__gameId
+ }
+ }));
+ }
+ }, {
+ key: "setPlayingGame",
+ value: function setPlayingGame(id) {
+
+ if (id instanceof String || typeof id === "string") {
+
+ // working on names
+ var gid = id.trim().toUpperCase();
+
+ id = null;
+
+ var _iteratorNormalCompletion16 = true;
+ var _didIteratorError16 = false;
+ var _iteratorError16 = undefined;
+
+ try {
+ for (var _iterator16 = gameMap[Symbol.iterator](), _step16; !(_iteratorNormalCompletion16 = (_step16 = _iterator16.next()).done); _iteratorNormalCompletion16 = true) {
+ var game = _step16.value;
+
+ if (game.name.trim().toUpperCase() === gid) {
+
+ id = game.id;
+ break;
+ }
+ }
+ } catch (err) {
+ _didIteratorError16 = true;
+ _iteratorError16 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion16 && _iterator16["return"]) {
+ _iterator16["return"]();
+ }
+ } finally {
+ if (_didIteratorError16) {
+ throw _iteratorError16;
+ }
+ }
+ }
+ }
+
+ this.__gameId = id;
+
+ this.websocket.send(JSON.stringify({
+ op: 3,
+ d: {
+ idle_since: this.__idleTime,
+ game_id: this.__gameId
+ }
+ }));
+ }
+ }, {
+ key: "playGame",
+ value: function playGame(id) {
+ this.setPlayingGame(id);
+ }
+ }, {
+ key: "playingGame",
+ value: function playingGame(id) {
+
+ this.setPlayingGame(id);
+ }
+ }, {
+ key: "uptime",
+ get: function get() {
+
+ return this.readyTime ? Date.now() - this.readyTime : null;
+ }
+ }, {
+ key: "ready",
+ get: function get() {
+ return this.state === 3;
+ }
+ }, {
+ key: "servers",
+ get: function get() {
+ return this.serverCache;
+ }
+ }, {
+ key: "channels",
+ get: function get() {
+ return this.channelCache;
+ }
+ }, {
+ key: "users",
+ get: function get() {
+ return this.userCache;
+ }
+ }, {
+ key: "PMChannels",
+ get: function get() {
+ return this.pmChannelCache;
+ }
+ }, {
+ key: "messages",
+ get: function get() {
+
+ var msgs = [];
+ var _iteratorNormalCompletion17 = true;
+ var _didIteratorError17 = false;
+ var _iteratorError17 = undefined;
+
+ try {
+ for (var _iterator17 = this.channelCache[Symbol.iterator](), _step17; !(_iteratorNormalCompletion17 = (_step17 = _iterator17.next()).done); _iteratorNormalCompletion17 = true) {
+ var channel = _step17.value;
+
+ msgs = msgs.concat(channel.messages);
+ }
+ } catch (err) {
+ _didIteratorError17 = true;
+ _iteratorError17 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion17 && _iterator17["return"]) {
+ _iterator17["return"]();
+ }
+ } finally {
+ if (_didIteratorError17) {
+ throw _iteratorError17;
+ }
+ }
+ }
+
+ return msgs;
+ }
+ }]);
+
+ return Client;
+})();
+
+module.exports = Client;
+
+},{"../ref/gameMap.json":15,"./Endpoints.js":2,"./PMChannel.js":3,"./channel.js":4,"./invite.js":6,"./message.js":7,"./server.js":8,"./user.js":9,"fs":10,"superagent":11,"ws":14}],2:[function(require,module,exports){
+"use strict";
+
+exports.BASE_DOMAIN = "discordapp.com";
+exports.BASE = "https://" + exports.BASE_DOMAIN;
+exports.WEBSOCKET_HUB = "wss://" + exports.BASE_DOMAIN + "/hub";
+
+exports.API = exports.BASE + "/api";
+exports.AUTH = exports.API + "/auth";
+exports.LOGIN = exports.AUTH + "/login";
+exports.LOGOUT = exports.AUTH + "/logout";
+exports.USERS = exports.API + "/users";
+exports.SERVERS = exports.API + "/guilds";
+exports.CHANNELS = exports.API + "/channels";
+
+},{}],3:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var PMChannel = (function () {
+ function PMChannel(data, client) {
+ _classCallCheck(this, PMChannel);
+
+ this.user = client.getUser("id", data.recipient.id);
+ this.id = data.id;
+ this.messages = [];
+ }
+
+ _createClass(PMChannel, [{
+ key: "addMessage",
+ value: function addMessage(data) {
+ if (!this.getMessage("id", data.id)) {
+ this.messages.push(data);
+ }
+ return this.getMessage("id", data.id);
+ }
+ }, {
+ key: "getMessage",
+ value: function getMessage(key, value) {
+
+ if (this.messages.length > 1000) {
+ this.messages.splice(0, 1);
+ }
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.messages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var message = _step.value;
+
+ if (message[key] === value) {
+ return message;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return true;
+ }
+ }]);
+
+ return PMChannel;
+})();
+
+module.exports = PMChannel;
+
+},{}],4:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Channel = (function () {
+ function Channel(data, server) {
+ _classCallCheck(this, Channel);
+
+ this.server = server;
+ this.name = data.name;
+ this.type = data.type;
+ this.topic = data.topic;
+ this.id = data.id;
+ this.messages = [];
+ //this.isPrivate = isPrivate; //not sure about the implementation of this...
+ }
+
+ _createClass(Channel, [{
+ key: "equals",
+ value: function equals(object) {
+ return object && object.id === this.id;
+ }
+ }, {
+ key: "addMessage",
+ value: function addMessage(data) {
+
+ if (this.messages.length > 1000) {
+ this.messages.splice(0, 1);
+ }
+
+ if (!this.getMessage("id", data.id)) {
+ this.messages.push(data);
+ }
+
+ return this.getMessage("id", data.id);
+ }
+ }, {
+ key: "getMessage",
+ value: function getMessage(key, value) {
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.messages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var message = _step.value;
+
+ if (message[key] === value) {
+ return message;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ return "<#" + this.id + ">";
+ }
+ }, {
+ key: "client",
+ get: function get() {
+ return this.server.client;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return false;
+ }
+ }, {
+ key: "users",
+ get: function get() {
+ return this.server.members;
+ }
+ }, {
+ key: "members",
+ get: function get() {
+ return this.server.members;
+ }
+ }]);
+
+ return Channel;
+})();
+
+module.exports = Channel;
+
+},{}],5:[function(require,module,exports){
+"use strict";
+
+var request = require("superagent");
+var Endpoints = require("./Endpoints.js");
+var Client = require("./Client.js");
+
+var Discord = {
+ Endpoints: Endpoints,
+ Client: Client
+};
+
+module.exports = Discord;
+
+},{"./Client.js":1,"./Endpoints.js":2,"superagent":11}],6:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Invite = (function () {
+ function Invite(data, client) {
+ _classCallCheck(this, Invite);
+
+ this.max_age = data.max_age;
+ this.code = data.code;
+ this.server = client.getServer("id", data.guild.id);
+ this.revoked = data.revoked;
+ this.created_at = Date.parse(data.created_at);
+ this.temporary = data.temporary;
+ this.uses = data.uses;
+ this.max_uses = data.uses;
+ this.inviter = client.addUser(data.inviter);
+ this.xkcd = data.xkcdpass;
+ this.channel = client.getChannel("id", data.channel.id);
+ }
+
+ _createClass(Invite, [{
+ key: "URL",
+ get: function get() {
+ var code = this.xkcd ? this.xkcdpass : this.code;
+ return "https://discord.gg/" + code;
+ }
+ }]);
+
+ return Invite;
+})();
+
+module.exports = Invite;
+
+},{}],7:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var PMChannel = require("./PMChannel.js");
+
+var Message = (function () {
+ function Message(data, channel, mentions, author) {
+ _classCallCheck(this, Message);
+
+ this.tts = data.tts;
+ this.timestamp = Date.parse(data.timestamp);
+ this.nonce = data.nonce;
+ this.mentions = mentions;
+ this.everyoneMentioned = data.mention_everyone;
+ this.id = data.id;
+ this.embeds = data.embeds;
+ this.editedTimestamp = data.edited_timestamp;
+ this.content = data.content.trim();
+ this.channel = channel;
+ this.author = author;
+ this.attachments = data.attachments;
+ }
+
+ /*exports.Message.prototype.isPM = function() {
+ return ( this.channel instanceof PMChannel );
+ }*/
+
+ _createClass(Message, [{
+ key: "isMentioned",
+ value: function isMentioned(user) {
+ var id = user.id ? user.id : user;
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.mentions[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var mention = _step.value;
+
+ if (mention.id === id) {
+ return true;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return false;
+ }
+ }, {
+ key: "sender",
+ get: function get() {
+ return this.author;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return this.channel.isPrivate;
+ }
+ }]);
+
+ return Message;
+})();
+
+module.exports = Message;
+
+},{"./PMChannel.js":3}],8:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Server = (function () {
+ function Server(data, client) {
+ _classCallCheck(this, Server);
+
+ this.client = client;
+ this.region = data.region;
+ this.ownerID = data.owner_id;
+ this.name = data.name;
+ this.id = data.id;
+ this.members = [];
+ this.channels = [];
+ this.icon = data.icon;
+ this.afkTimeout = data.afk_timeout;
+ this.afkChannelId = data.afk_channel_id;
+
+ if (!data.members) {
+ data.members = [client.user];
+ return;
+ }
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = data.members[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var member = _step.value;
+
+ // first we cache the user in our Discord Client,
+ // then we add it to our list. This way when we
+ // get a user from this server's member list,
+ // it will be identical (unless an async change occurred)
+ // to the client's cache.
+ if (member.user) this.members.push(client.addUser(member.user));
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+ }
+
+ _createClass(Server, [{
+ key: "getChannel",
+
+ // get/set
+ value: function getChannel(key, value) {
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = this.channels[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var channel = _step2.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2["return"]) {
+ _iterator2["return"]();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "getMember",
+ value: function getMember(key, value) {
+ var _iteratorNormalCompletion3 = true;
+ var _didIteratorError3 = false;
+ var _iteratorError3 = undefined;
+
+ try {
+ for (var _iterator3 = this.members[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var member = _step3.value;
+
+ if (member[key] === value) {
+ return member;
+ }
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3["return"]) {
+ _iterator3["return"]();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "addChannel",
+ value: function addChannel(chann) {
+ if (!this.getChannel("id", chann.id)) {
+ this.channels.push(chann);
+ }
+ return chann;
+ }
+ }, {
+ key: "addMember",
+ value: function addMember(member) {
+ if (!this.getMember("id", member.id)) {
+ this.members.push(member);
+ }
+ return member;
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ return this.name;
+ }
+ }, {
+ key: "equals",
+ value: function equals(object) {
+ return object.id === this.id;
+ }
+ }, {
+ key: "iconURL",
+ get: function get() {
+ if (!this.icon) return null;
+ return "https://discordapp.com/api/guilds/" + this.id + "/icons/" + this.icon + ".jpg";
+ }
+ }, {
+ key: "afkChannel",
+ get: function get() {
+ if (!this.afkChannelId) return false;
+
+ return this.getChannel("id", this.afkChannelId);
+ }
+ }, {
+ key: "defaultChannel",
+ get: function get() {
+ return this.getChannel("name", "general");
+ }
+ }, {
+ key: "owner",
+ get: function get() {
+ return this.client.getUser("id", this.ownerID);
+ }
+ }, {
+ key: "users",
+ get: function get() {
+ return this.members;
+ }
+ }]);
+
+ return Server;
+})();
+
+module.exports = Server;
+
+},{}],9:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var User = (function () {
+ function User(data) {
+ _classCallCheck(this, User);
+
+ this.username = data.username;
+ this.discriminator = data.discriminator;
+ this.id = data.id;
+ this.avatar = data.avatar;
+ this.status = "offline";
+ }
+
+ // access using user.avatarURL;
+
+ _createClass(User, [{
+ key: "mention",
+ value: function mention() {
+ return "<@" + this.id + ">";
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ /*
+ if we embed a user in a String - like so:
+ "Yo " + user + " what's up?"
+ It would generate something along the lines of:
+ "Yo @hydrabolt what's up?"
+ */
+ return this.mention();
+ }
+ }, {
+ key: "equals",
+ value: function equals(object) {
+ return object.id === this.id;
+ }
+ }, {
+ key: "equalsStrict",
+ value: function equalsStrict(object) {
+ return object.id === this.id && object.avatar === this.avatar && object.username === this.username && object.discriminator === this.discriminator;
+ }
+ }, {
+ key: "avatarURL",
+ get: function get() {
+ if (!this.avatar) return null;
+ return "https://discordapp.com/api/users/" + this.id + "/avatars/" + this.avatar + ".jpg";
+ }
+ }]);
+
+ return User;
+})();
+
+module.exports = User;
+
+},{}],10:[function(require,module,exports){
+
+},{}],11:[function(require,module,exports){
+/**
+ * Module dependencies.
+ */
+
+var Emitter = require('emitter');
+var reduce = require('reduce');
+
+/**
+ * Root reference for iframes.
+ */
+
+var root = 'undefined' == typeof window
+ ? (this || self)
+ : window;
+
+/**
+ * Noop.
+ */
+
+function noop(){};
+
+/**
+ * Check if `obj` is a host object,
+ * we don't want to serialize these :)
+ *
+ * TODO: future proof, move to compoent land
+ *
+ * @param {Object} obj
+ * @return {Boolean}
+ * @api private
+ */
+
+function isHost(obj) {
+ var str = {}.toString.call(obj);
+
+ switch (str) {
+ case '[object File]':
+ case '[object Blob]':
+ case '[object FormData]':
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Determine XHR.
+ */
+
+request.getXHR = function () {
+ if (root.XMLHttpRequest
+ && (!root.location || 'file:' != root.location.protocol
+ || !root.ActiveXObject)) {
+ return new XMLHttpRequest;
+ } else {
+ try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {}
+ }
+ return false;
+};
+
+/**
+ * Removes leading and trailing whitespace, added to support IE.
+ *
+ * @param {String} s
+ * @return {String}
+ * @api private
+ */
+
+var trim = ''.trim
+ ? function(s) { return s.trim(); }
+ : function(s) { return s.replace(/(^\s*|\s*$)/g, ''); };
+
+/**
+ * Check if `obj` is an object.
+ *
+ * @param {Object} obj
+ * @return {Boolean}
+ * @api private
+ */
+
+function isObject(obj) {
+ return obj === Object(obj);
+}
+
+/**
+ * Serialize the given `obj`.
+ *
+ * @param {Object} obj
+ * @return {String}
+ * @api private
+ */
+
+function serialize(obj) {
+ if (!isObject(obj)) return obj;
+ var pairs = [];
+ for (var key in obj) {
+ if (null != obj[key]) {
+ pairs.push(encodeURIComponent(key)
+ + '=' + encodeURIComponent(obj[key]));
+ }
+ }
+ return pairs.join('&');
+}
+
+/**
+ * Expose serialization method.
+ */
+
+ request.serializeObject = serialize;
+
+ /**
+ * Parse the given x-www-form-urlencoded `str`.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+function parseString(str) {
+ var obj = {};
+ var pairs = str.split('&');
+ var parts;
+ var pair;
+
+ for (var i = 0, len = pairs.length; i < len; ++i) {
+ pair = pairs[i];
+ parts = pair.split('=');
+ obj[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
+ }
+
+ return obj;
+}
+
+/**
+ * Expose parser.
+ */
+
+request.parseString = parseString;
+
+/**
+ * Default MIME type map.
+ *
+ * superagent.types.xml = 'application/xml';
+ *
+ */
+
+request.types = {
+ html: 'text/html',
+ json: 'application/json',
+ xml: 'application/xml',
+ urlencoded: 'application/x-www-form-urlencoded',
+ 'form': 'application/x-www-form-urlencoded',
+ 'form-data': 'application/x-www-form-urlencoded'
+};
+
+/**
+ * Default serialization map.
+ *
+ * superagent.serialize['application/xml'] = function(obj){
+ * return 'generated xml here';
+ * };
+ *
+ */
+
+ request.serialize = {
+ 'application/x-www-form-urlencoded': serialize,
+ 'application/json': JSON.stringify
+ };
+
+ /**
+ * Default parsers.
+ *
+ * superagent.parse['application/xml'] = function(str){
+ * return { object parsed from str };
+ * };
+ *
+ */
+
+request.parse = {
+ 'application/x-www-form-urlencoded': parseString,
+ 'application/json': JSON.parse
+};
+
+/**
+ * Parse the given header `str` into
+ * an object containing the mapped fields.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+function parseHeader(str) {
+ var lines = str.split(/\r?\n/);
+ var fields = {};
+ var index;
+ var line;
+ var field;
+ var val;
+
+ lines.pop(); // trailing CRLF
+
+ for (var i = 0, len = lines.length; i < len; ++i) {
+ line = lines[i];
+ index = line.indexOf(':');
+ field = line.slice(0, index).toLowerCase();
+ val = trim(line.slice(index + 1));
+ fields[field] = val;
+ }
+
+ return fields;
+}
+
+/**
+ * Return the mime type for the given `str`.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+function type(str){
+ return str.split(/ *; */).shift();
+};
+
+/**
+ * Return header field parameters.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+function params(str){
+ return reduce(str.split(/ *; */), function(obj, str){
+ var parts = str.split(/ *= */)
+ , key = parts.shift()
+ , val = parts.shift();
+
+ if (key && val) obj[key] = val;
+ return obj;
+ }, {});
+};
+
+/**
+ * Initialize a new `Response` with the given `xhr`.
+ *
+ * - set flags (.ok, .error, etc)
+ * - parse header
+ *
+ * Examples:
+ *
+ * Aliasing `superagent` as `request` is nice:
+ *
+ * request = superagent;
+ *
+ * We can use the promise-like API, or pass callbacks:
+ *
+ * request.get('/').end(function(res){});
+ * request.get('/', function(res){});
+ *
+ * Sending data can be chained:
+ *
+ * request
+ * .post('/user')
+ * .send({ name: 'tj' })
+ * .end(function(res){});
+ *
+ * Or passed to `.send()`:
+ *
+ * request
+ * .post('/user')
+ * .send({ name: 'tj' }, function(res){});
+ *
+ * Or passed to `.post()`:
+ *
+ * request
+ * .post('/user', { name: 'tj' })
+ * .end(function(res){});
+ *
+ * Or further reduced to a single call for simple cases:
+ *
+ * request
+ * .post('/user', { name: 'tj' }, function(res){});
+ *
+ * @param {XMLHTTPRequest} xhr
+ * @param {Object} options
+ * @api private
+ */
+
+function Response(req, options) {
+ options = options || {};
+ this.req = req;
+ this.xhr = this.req.xhr;
+ // responseText is accessible only if responseType is '' or 'text' and on older browsers
+ this.text = ((this.req.method !='HEAD' && (this.xhr.responseType === '' || this.xhr.responseType === 'text')) || typeof this.xhr.responseType === 'undefined')
+ ? this.xhr.responseText
+ : null;
+ this.statusText = this.req.xhr.statusText;
+ this.setStatusProperties(this.xhr.status);
+ this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders());
+ // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but
+ // getResponseHeader still works. so we get content-type even if getting
+ // other headers fails.
+ this.header['content-type'] = this.xhr.getResponseHeader('content-type');
+ this.setHeaderProperties(this.header);
+ this.body = this.req.method != 'HEAD'
+ ? this.parseBody(this.text ? this.text : this.xhr.response)
+ : null;
+}
+
+/**
+ * Get case-insensitive `field` value.
+ *
+ * @param {String} field
+ * @return {String}
+ * @api public
+ */
+
+Response.prototype.get = function(field){
+ return this.header[field.toLowerCase()];
+};
+
+/**
+ * Set header related properties:
+ *
+ * - `.type` the content type without params
+ *
+ * A response of "Content-Type: text/plain; charset=utf-8"
+ * will provide you with a `.type` of "text/plain".
+ *
+ * @param {Object} header
+ * @api private
+ */
+
+Response.prototype.setHeaderProperties = function(header){
+ // content-type
+ var ct = this.header['content-type'] || '';
+ this.type = type(ct);
+
+ // params
+ var obj = params(ct);
+ for (var key in obj) this[key] = obj[key];
+};
+
+/**
+ * Parse the given body `str`.
+ *
+ * Used for auto-parsing of bodies. Parsers
+ * are defined on the `superagent.parse` object.
+ *
+ * @param {String} str
+ * @return {Mixed}
+ * @api private
+ */
+
+Response.prototype.parseBody = function(str){
+ var parse = request.parse[this.type];
+ return parse && str && (str.length || str instanceof Object)
+ ? parse(str)
+ : null;
+};
+
+/**
+ * Set flags such as `.ok` based on `status`.
+ *
+ * For example a 2xx response will give you a `.ok` of __true__
+ * whereas 5xx will be __false__ and `.error` will be __true__. The
+ * `.clientError` and `.serverError` are also available to be more
+ * specific, and `.statusType` is the class of error ranging from 1..5
+ * sometimes useful for mapping respond colors etc.
+ *
+ * "sugar" properties are also defined for common cases. Currently providing:
+ *
+ * - .noContent
+ * - .badRequest
+ * - .unauthorized
+ * - .notAcceptable
+ * - .notFound
+ *
+ * @param {Number} status
+ * @api private
+ */
+
+Response.prototype.setStatusProperties = function(status){
+ // handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request
+ if (status === 1223) {
+ status = 204;
+ }
+
+ var type = status / 100 | 0;
+
+ // status / class
+ this.status = status;
+ this.statusType = type;
+
+ // basics
+ this.info = 1 == type;
+ this.ok = 2 == type;
+ this.clientError = 4 == type;
+ this.serverError = 5 == type;
+ this.error = (4 == type || 5 == type)
+ ? this.toError()
+ : false;
+
+ // sugar
+ this.accepted = 202 == status;
+ this.noContent = 204 == status;
+ this.badRequest = 400 == status;
+ this.unauthorized = 401 == status;
+ this.notAcceptable = 406 == status;
+ this.notFound = 404 == status;
+ this.forbidden = 403 == status;
+};
+
+/**
+ * Return an `Error` representative of this response.
+ *
+ * @return {Error}
+ * @api public
+ */
+
+Response.prototype.toError = function(){
+ var req = this.req;
+ var method = req.method;
+ var url = req.url;
+
+ var msg = 'cannot ' + method + ' ' + url + ' (' + this.status + ')';
+ var err = new Error(msg);
+ err.status = this.status;
+ err.method = method;
+ err.url = url;
+
+ return err;
+};
+
+/**
+ * Expose `Response`.
+ */
+
+request.Response = Response;
+
+/**
+ * Initialize a new `Request` with the given `method` and `url`.
+ *
+ * @param {String} method
+ * @param {String} url
+ * @api public
+ */
+
+function Request(method, url) {
+ var self = this;
+ Emitter.call(this);
+ this._query = this._query || [];
+ this.method = method;
+ this.url = url;
+ this.header = {};
+ this._header = {};
+ this.on('end', function(){
+ var err = null;
+ var res = null;
+
+ try {
+ res = new Response(self);
+ } catch(e) {
+ err = new Error('Parser is unable to parse the response');
+ err.parse = true;
+ err.original = e;
+ return self.callback(err);
+ }
+
+ self.emit('response', res);
+
+ if (err) {
+ return self.callback(err, res);
+ }
+
+ if (res.status >= 200 && res.status < 300) {
+ return self.callback(err, res);
+ }
+
+ var new_err = new Error(res.statusText || 'Unsuccessful HTTP response');
+ new_err.original = err;
+ new_err.response = res;
+ new_err.status = res.status;
+
+ self.callback(new_err, res);
+ });
+}
+
+/**
+ * Mixin `Emitter`.
+ */
+
+Emitter(Request.prototype);
+
+/**
+ * Allow for extension
+ */
+
+Request.prototype.use = function(fn) {
+ fn(this);
+ return this;
+}
+
+/**
+ * Set timeout to `ms`.
+ *
+ * @param {Number} ms
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.timeout = function(ms){
+ this._timeout = ms;
+ return this;
+};
+
+/**
+ * Clear previous timeout.
+ *
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.clearTimeout = function(){
+ this._timeout = 0;
+ clearTimeout(this._timer);
+ return this;
+};
+
+/**
+ * Abort the request, and clear potential timeout.
+ *
+ * @return {Request}
+ * @api public
+ */
+
+Request.prototype.abort = function(){
+ if (this.aborted) return;
+ this.aborted = true;
+ this.xhr.abort();
+ this.clearTimeout();
+ this.emit('abort');
+ return this;
+};
+
+/**
+ * Set header `field` to `val`, or multiple fields with one object.
+ *
+ * Examples:
+ *
+ * req.get('/')
+ * .set('Accept', 'application/json')
+ * .set('X-API-Key', 'foobar')
+ * .end(callback);
+ *
+ * req.get('/')
+ * .set({ Accept: 'application/json', 'X-API-Key': 'foobar' })
+ * .end(callback);
+ *
+ * @param {String|Object} field
+ * @param {String} val
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.set = function(field, val){
+ if (isObject(field)) {
+ for (var key in field) {
+ this.set(key, field[key]);
+ }
+ return this;
+ }
+ this._header[field.toLowerCase()] = val;
+ this.header[field] = val;
+ return this;
+};
+
+/**
+ * Remove header `field`.
+ *
+ * Example:
+ *
+ * req.get('/')
+ * .unset('User-Agent')
+ * .end(callback);
+ *
+ * @param {String} field
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.unset = function(field){
+ delete this._header[field.toLowerCase()];
+ delete this.header[field];
+ return this;
+};
+
+/**
+ * Get case-insensitive header `field` value.
+ *
+ * @param {String} field
+ * @return {String}
+ * @api private
+ */
+
+Request.prototype.getHeader = function(field){
+ return this._header[field.toLowerCase()];
+};
+
+/**
+ * Set Content-Type to `type`, mapping values from `request.types`.
+ *
+ * Examples:
+ *
+ * superagent.types.xml = 'application/xml';
+ *
+ * request.post('/')
+ * .type('xml')
+ * .send(xmlstring)
+ * .end(callback);
+ *
+ * request.post('/')
+ * .type('application/xml')
+ * .send(xmlstring)
+ * .end(callback);
+ *
+ * @param {String} type
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.type = function(type){
+ this.set('Content-Type', request.types[type] || type);
+ return this;
+};
+
+/**
+ * Set Accept to `type`, mapping values from `request.types`.
+ *
+ * Examples:
+ *
+ * superagent.types.json = 'application/json';
+ *
+ * request.get('/agent')
+ * .accept('json')
+ * .end(callback);
+ *
+ * request.get('/agent')
+ * .accept('application/json')
+ * .end(callback);
+ *
+ * @param {String} accept
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.accept = function(type){
+ this.set('Accept', request.types[type] || type);
+ return this;
+};
+
+/**
+ * Set Authorization field value with `user` and `pass`.
+ *
+ * @param {String} user
+ * @param {String} pass
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.auth = function(user, pass){
+ var str = btoa(user + ':' + pass);
+ this.set('Authorization', 'Basic ' + str);
+ return this;
+};
+
+/**
+* Add query-string `val`.
+*
+* Examples:
+*
+* request.get('/shoes')
+* .query('size=10')
+* .query({ color: 'blue' })
+*
+* @param {Object|String} val
+* @return {Request} for chaining
+* @api public
+*/
+
+Request.prototype.query = function(val){
+ if ('string' != typeof val) val = serialize(val);
+ if (val) this._query.push(val);
+ return this;
+};
+
+/**
+ * Write the field `name` and `val` for "multipart/form-data"
+ * request bodies.
+ *
+ * ``` js
+ * request.post('/upload')
+ * .field('foo', 'bar')
+ * .end(callback);
+ * ```
+ *
+ * @param {String} name
+ * @param {String|Blob|File} val
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.field = function(name, val){
+ if (!this._formData) this._formData = new root.FormData();
+ this._formData.append(name, val);
+ return this;
+};
+
+/**
+ * Queue the given `file` as an attachment to the specified `field`,
+ * with optional `filename`.
+ *
+ * ``` js
+ * request.post('/upload')
+ * .attach(new Blob(['hey! '], { type: "text/html"}))
+ * .end(callback);
+ * ```
+ *
+ * @param {String} field
+ * @param {Blob|File} file
+ * @param {String} filename
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.attach = function(field, file, filename){
+ if (!this._formData) this._formData = new root.FormData();
+ this._formData.append(field, file, filename);
+ return this;
+};
+
+/**
+ * Send `data`, defaulting the `.type()` to "json" when
+ * an object is given.
+ *
+ * Examples:
+ *
+ * // querystring
+ * request.get('/search')
+ * .end(callback)
+ *
+ * // multiple data "writes"
+ * request.get('/search')
+ * .send({ search: 'query' })
+ * .send({ range: '1..5' })
+ * .send({ order: 'desc' })
+ * .end(callback)
+ *
+ * // manual json
+ * request.post('/user')
+ * .type('json')
+ * .send('{"name":"tj"})
+ * .end(callback)
+ *
+ * // auto json
+ * request.post('/user')
+ * .send({ name: 'tj' })
+ * .end(callback)
+ *
+ * // manual x-www-form-urlencoded
+ * request.post('/user')
+ * .type('form')
+ * .send('name=tj')
+ * .end(callback)
+ *
+ * // auto x-www-form-urlencoded
+ * request.post('/user')
+ * .type('form')
+ * .send({ name: 'tj' })
+ * .end(callback)
+ *
+ * // defaults to x-www-form-urlencoded
+ * request.post('/user')
+ * .send('name=tobi')
+ * .send('species=ferret')
+ * .end(callback)
+ *
+ * @param {String|Object} data
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.send = function(data){
+ var obj = isObject(data);
+ var type = this.getHeader('Content-Type');
+
+ // merge
+ if (obj && isObject(this._data)) {
+ for (var key in data) {
+ this._data[key] = data[key];
+ }
+ } else if ('string' == typeof data) {
+ if (!type) this.type('form');
+ type = this.getHeader('Content-Type');
+ if ('application/x-www-form-urlencoded' == type) {
+ this._data = this._data
+ ? this._data + '&' + data
+ : data;
+ } else {
+ this._data = (this._data || '') + data;
+ }
+ } else {
+ this._data = data;
+ }
+
+ if (!obj || isHost(data)) return this;
+ if (!type) this.type('json');
+ return this;
+};
+
+/**
+ * Invoke the callback with `err` and `res`
+ * and handle arity check.
+ *
+ * @param {Error} err
+ * @param {Response} res
+ * @api private
+ */
+
+Request.prototype.callback = function(err, res){
+ var fn = this._callback;
+ this.clearTimeout();
+ fn(err, res);
+};
+
+/**
+ * Invoke callback with x-domain error.
+ *
+ * @api private
+ */
+
+Request.prototype.crossDomainError = function(){
+ var err = new Error('Origin is not allowed by Access-Control-Allow-Origin');
+ err.crossDomain = true;
+ this.callback(err);
+};
+
+/**
+ * Invoke callback with timeout error.
+ *
+ * @api private
+ */
+
+Request.prototype.timeoutError = function(){
+ var timeout = this._timeout;
+ var err = new Error('timeout of ' + timeout + 'ms exceeded');
+ err.timeout = timeout;
+ this.callback(err);
+};
+
+/**
+ * Enable transmission of cookies with x-domain requests.
+ *
+ * Note that for this to work the origin must not be
+ * using "Access-Control-Allow-Origin" with a wildcard,
+ * and also must set "Access-Control-Allow-Credentials"
+ * to "true".
+ *
+ * @api public
+ */
+
+Request.prototype.withCredentials = function(){
+ this._withCredentials = true;
+ return this;
+};
+
+/**
+ * Initiate request, invoking callback `fn(res)`
+ * with an instanceof `Response`.
+ *
+ * @param {Function} fn
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.end = function(fn){
+ var self = this;
+ var xhr = this.xhr = request.getXHR();
+ var query = this._query.join('&');
+ var timeout = this._timeout;
+ var data = this._formData || this._data;
+
+ // store callback
+ this._callback = fn || noop;
+
+ // state change
+ xhr.onreadystatechange = function(){
+ if (4 != xhr.readyState) return;
+
+ // In IE9, reads to any property (e.g. status) off of an aborted XHR will
+ // result in the error "Could not complete the operation due to error c00c023f"
+ var status;
+ try { status = xhr.status } catch(e) { status = 0; }
+
+ if (0 == status) {
+ if (self.timedout) return self.timeoutError();
+ if (self.aborted) return;
+ return self.crossDomainError();
+ }
+ self.emit('end');
+ };
+
+ // progress
+ var handleProgress = function(e){
+ if (e.total > 0) {
+ e.percent = e.loaded / e.total * 100;
+ }
+ self.emit('progress', e);
+ };
+ if (this.hasListeners('progress')) {
+ xhr.onprogress = handleProgress;
+ }
+ try {
+ if (xhr.upload && this.hasListeners('progress')) {
+ xhr.upload.onprogress = handleProgress;
+ }
+ } catch(e) {
+ // Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist.
+ // Reported here:
+ // https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web-worker-context
+ }
+
+ // timeout
+ if (timeout && !this._timer) {
+ this._timer = setTimeout(function(){
+ self.timedout = true;
+ self.abort();
+ }, timeout);
+ }
+
+ // querystring
+ if (query) {
+ query = request.serializeObject(query);
+ this.url += ~this.url.indexOf('?')
+ ? '&' + query
+ : '?' + query;
+ }
+
+ // initiate request
+ xhr.open(this.method, this.url, true);
+
+ // CORS
+ if (this._withCredentials) xhr.withCredentials = true;
+
+ // body
+ if ('GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !isHost(data)) {
+ // serialize stuff
+ var contentType = this.getHeader('Content-Type');
+ var serialize = request.serialize[contentType ? contentType.split(';')[0] : ''];
+ if (serialize) data = serialize(data);
+ }
+
+ // set header fields
+ for (var field in this.header) {
+ if (null == this.header[field]) continue;
+ xhr.setRequestHeader(field, this.header[field]);
+ }
+
+ // send stuff
+ this.emit('request', this);
+ xhr.send(data);
+ return this;
+};
+
+/**
+ * Faux promise support
+ *
+ * @param {Function} fulfill
+ * @param {Function} reject
+ * @return {Request}
+ */
+
+Request.prototype.then = function (fulfill, reject) {
+ return this.end(function(err, res) {
+ err ? reject(err) : fulfill(res);
+ });
+}
+
+/**
+ * Expose `Request`.
+ */
+
+request.Request = Request;
+
+/**
+ * Issue a request:
+ *
+ * Examples:
+ *
+ * request('GET', '/users').end(callback)
+ * request('/users').end(callback)
+ * request('/users', callback)
+ *
+ * @param {String} method
+ * @param {String|Function} url or callback
+ * @return {Request}
+ * @api public
+ */
+
+function request(method, url) {
+ // callback
+ if ('function' == typeof url) {
+ return new Request('GET', method).end(url);
+ }
+
+ // url first
+ if (1 == arguments.length) {
+ return new Request('GET', method);
+ }
+
+ return new Request(method, url);
+}
+
+/**
+ * GET `url` with optional callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed|Function} data or fn
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.get = function(url, data, fn){
+ var req = request('GET', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.query(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * HEAD `url` with optional callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed|Function} data or fn
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.head = function(url, data, fn){
+ var req = request('HEAD', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * DELETE `url` with optional callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.del = function(url, fn){
+ var req = request('DELETE', url);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * PATCH `url` with optional `data` and callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed} data
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.patch = function(url, data, fn){
+ var req = request('PATCH', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * POST `url` with optional `data` and callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed} data
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.post = function(url, data, fn){
+ var req = request('POST', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * PUT `url` with optional `data` and callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed|Function} data or fn
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.put = function(url, data, fn){
+ var req = request('PUT', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * Expose `request`.
+ */
+
+module.exports = request;
+
+},{"emitter":12,"reduce":13}],12:[function(require,module,exports){
+
+/**
+ * Expose `Emitter`.
+ */
+
+module.exports = Emitter;
+
+/**
+ * Initialize a new `Emitter`.
+ *
+ * @api public
+ */
+
+function Emitter(obj) {
+ if (obj) return mixin(obj);
+};
+
+/**
+ * Mixin the emitter properties.
+ *
+ * @param {Object} obj
+ * @return {Object}
+ * @api private
+ */
+
+function mixin(obj) {
+ for (var key in Emitter.prototype) {
+ obj[key] = Emitter.prototype[key];
+ }
+ return obj;
+}
+
+/**
+ * Listen on the given `event` with `fn`.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ * @return {Emitter}
+ * @api public
+ */
+
+Emitter.prototype.on =
+Emitter.prototype.addEventListener = function(event, fn){
+ this._callbacks = this._callbacks || {};
+ (this._callbacks[event] = this._callbacks[event] || [])
+ .push(fn);
+ return this;
+};
+
+/**
+ * Adds an `event` listener that will be invoked a single
+ * time then automatically removed.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ * @return {Emitter}
+ * @api public
+ */
+
+Emitter.prototype.once = function(event, fn){
+ var self = this;
+ this._callbacks = this._callbacks || {};
+
+ function on() {
+ self.off(event, on);
+ fn.apply(this, arguments);
+ }
+
+ on.fn = fn;
+ this.on(event, on);
+ return this;
+};
+
+/**
+ * Remove the given callback for `event` or all
+ * registered callbacks.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ * @return {Emitter}
+ * @api public
+ */
+
+Emitter.prototype.off =
+Emitter.prototype.removeListener =
+Emitter.prototype.removeAllListeners =
+Emitter.prototype.removeEventListener = function(event, fn){
+ this._callbacks = this._callbacks || {};
+
+ // all
+ if (0 == arguments.length) {
+ this._callbacks = {};
+ return this;
+ }
+
+ // specific event
+ var callbacks = this._callbacks[event];
+ if (!callbacks) return this;
+
+ // remove all handlers
+ if (1 == arguments.length) {
+ delete this._callbacks[event];
+ return this;
+ }
+
+ // remove specific handler
+ var cb;
+ for (var i = 0; i < callbacks.length; i++) {
+ cb = callbacks[i];
+ if (cb === fn || cb.fn === fn) {
+ callbacks.splice(i, 1);
+ break;
+ }
+ }
+ return this;
+};
+
+/**
+ * Emit `event` with the given args.
+ *
+ * @param {String} event
+ * @param {Mixed} ...
+ * @return {Emitter}
+ */
+
+Emitter.prototype.emit = function(event){
+ this._callbacks = this._callbacks || {};
+ var args = [].slice.call(arguments, 1)
+ , callbacks = this._callbacks[event];
+
+ if (callbacks) {
+ callbacks = callbacks.slice(0);
+ for (var i = 0, len = callbacks.length; i < len; ++i) {
+ callbacks[i].apply(this, args);
+ }
+ }
+
+ return this;
+};
+
+/**
+ * Return array of callbacks for `event`.
+ *
+ * @param {String} event
+ * @return {Array}
+ * @api public
+ */
+
+Emitter.prototype.listeners = function(event){
+ this._callbacks = this._callbacks || {};
+ return this._callbacks[event] || [];
+};
+
+/**
+ * Check if this emitter has `event` handlers.
+ *
+ * @param {String} event
+ * @return {Boolean}
+ * @api public
+ */
+
+Emitter.prototype.hasListeners = function(event){
+ return !! this.listeners(event).length;
+};
+
+},{}],13:[function(require,module,exports){
+
+/**
+ * Reduce `arr` with `fn`.
+ *
+ * @param {Array} arr
+ * @param {Function} fn
+ * @param {Mixed} initial
+ *
+ * TODO: combatible error handling?
+ */
+
+module.exports = function(arr, fn, initial){
+ var idx = 0;
+ var len = arr.length;
+ var curr = arguments.length == 3
+ ? initial
+ : arr[idx++];
+
+ while (idx < len) {
+ curr = fn.call(null, curr, arr[idx], ++idx, arr);
+ }
+
+ return curr;
+};
+},{}],14:[function(require,module,exports){
+
+/**
+ * Module dependencies.
+ */
+
+var global = (function() { return this; })();
+
+/**
+ * WebSocket constructor.
+ */
+
+var WebSocket = global.WebSocket || global.MozWebSocket;
+
+/**
+ * Module exports.
+ */
+
+module.exports = WebSocket ? ws : null;
+
+/**
+ * WebSocket constructor.
+ *
+ * The third `opts` options object gets ignored in web browsers, since it's
+ * non-standard, and throws a TypeError if passed to the constructor.
+ * See: https://github.com/einaros/ws/issues/227
+ *
+ * @param {String} uri
+ * @param {Array} protocols (optional)
+ * @param {Object) opts (optional)
+ * @api public
+ */
+
+function ws(uri, protocols, opts) {
+ var instance;
+ if (protocols) {
+ instance = new WebSocket(uri, protocols);
+ } else {
+ instance = new WebSocket(uri);
+ }
+ return instance;
+}
+
+if (WebSocket) ws.prototype = WebSocket.prototype;
+
+},{}],15:[function(require,module,exports){
+module.exports=[{"executables":{"win32":["pol.exe"]},"id":0,"name":"FINAL FANTASY XI"},{"executables":{"win32":["ffxiv.exe","ffxiv_dx11.exe"]},"id":1,"name":"FINAL FANTASY XIV"},{"executables":{"win32":["Wow.exe","Wow-64.exe"]},"id":3,"name":"World of Warcraft"},{"executables":{"darwin":["LoLLauncher.app"],"win32":["LolClient.exe","League of Legends.exe"]},"id":4,"name":"League of Legends"},{"executables":{"darwin":["Diablo%20III.app"],"win32":["Diablo III.exe"]},"id":5,"name":"Diablo 3"},{"executables":{"darwin":["dota_osx.app"],"win32":["dota2.exe"]},"id":6,"name":"DOTA 2"},{"executables":{"darwin":["Heroes.app"],"win32":["Heroes of the Storm.exe","HeroesOfTheStorm_x64.exe","HeroesOfTheStorm.exe"]},"id":7,"name":"Heroes of the Storm"},{"executables":{"darwin":["Hearthstone.app"],"win32":["Hearthstone.exe"]},"id":8,"name":"Hearthstone"},{"executables":{"win32":["csgo.exe"]},"id":9,"name":"Counter-Strike: Global Offensive"},{"executables":{"win32":["WorldOfTanks.exe"]},"id":10,"name":"World of Tanks"},{"executables":{"darwin":["gw2.app"],"win32":["gw2.exe"]},"id":11,"name":"Guild Wars 2"},{"executables":{"win32":["dayz.exe"]},"id":12,"name":"Day Z"},{"executables":{"darwin":["starcraft%20ii.app"],"win32":["starcraft ii.exe","SC2_x64.exe","SC2.exe"]},"id":13,"name":"Starcraft II"},{"executables":{"win32":["diablo.exe"]},"id":14,"name":"Diablo"},{"executables":{"win32":["diablo ii.exe"]},"id":15,"name":"Diablo 2"},{"executables":{"win32":["left4dead.exe"]},"id":17,"name":"Left 4 Dead"},{"executables":{"darwin":["minecraft.app"],"win32":["minecraft.exe"]},"id":18,"name":"Minecraft"},{"executables":{"win32":["smite.exe"]},"id":19,"name":"Smite"},{"executables":{"win32":["bf4.exe"]},"id":20,"name":"Battlefield 4"},{"executables":{"win32":["AoK HD.exe","empires2.exe"]},"id":101,"name":"Age of Empire II"},{"executables":{"win32":["age3y.exe"]},"id":102,"name":"Age of Empire III"},{"executables":{"win32":["AlanWake.exe"]},"id":104,"name":"Alan Wake"},{"executables":{"win32":["alan_wakes_american_nightmare.exe"]},"id":105,"name":"Alan Wake's American Nightmare"},{"executables":{"win32":["AlienBreed2Assault.exe"]},"id":106,"name":"Alien Breed 2: Assault"},{"executables":{"win32":["Amnesia.exe"]},"id":107,"name":"Amnesia: The Dark Descent"},{"executables":{"win32":["UDK.exe"]},"id":108,"name":"Antichamber"},{"executables":{"win32":["ArcheAge.exe"]},"id":109,"name":"ArcheAge"},{"executables":{"win32":["arma3.exe"]},"id":110,"name":"Arma III"},{"executables":{"win32":["AC3SP.exe"]},"id":111,"name":"Assassin's Creed 3"},{"executables":{"win32":["Bastion.exe"]},"id":112,"name":"Bastion"},{"executables":{"win32":["BF2.exe"]},"id":113,"name":"Battlefield 2"},{"executables":{"win32":["bf3.exe"]},"id":114,"name":"Battlefield 3"},{"executables":{"win32":["Besiege.exe"]},"id":116,"name":"Besiege"},{"executables":{"win32":["Bioshock.exe"]},"id":117,"name":"Bioshock"},{"executables":{"win32":["Bioshock2.exe"]},"id":118,"name":"BioShock II"},{"executables":{"win32":["BioShockInfinite.exe"]},"id":119,"name":"BioShock Infinite"},{"executables":{"win32":["Borderlands2.exe"]},"id":122,"name":"Borderlands 2"},{"executables":{"win32":["braid.exe"]},"id":123,"name":"Braid"},{"executables":{"win32":["ShippingPC-StormGame.exe"]},"id":124,"name":"Bulletstorm"},{"executables":{},"id":125,"name":"Cabal 2"},{"executables":{"win32":["CabalMain.exe"]},"id":126,"name":"Cabal Online"},{"executables":{"win32":["iw4mp.exe","iw4sp.exe"]},"id":127,"name":"Call of Duty: Modern Warfare 2"},{"executables":{"win32":["t6sp.exe"]},"id":128,"name":"Call of Duty: Black Ops"},{"executables":{"win32":["iw5mp.exe"]},"id":129,"name":"Call of Duty: Modern Warfare 3"},{"executables":{"win32":["RelicCOH.exe"]},"id":132,"name":"Company of Heroes"},{"executables":{"win32":["Crysis64.exe"]},"id":135,"name":"Crysis"},{"executables":{"win32":["Crysis2.exe"]},"id":136,"name":"Crysis 2"},{"executables":{"win32":["Crysis3.exe"]},"id":137,"name":"Crysis 3"},{"executables":{"win32":["Crysis.exe"]},"id":138,"name":"Crysis 4 "},{"executables":{"win32":["DATA.exe"]},"id":140,"name":"Dark Souls"},{"executables":{"win32":["DarkSoulsII.exe"]},"id":141,"name":"Dark Souls II"},{"executables":{"win32":["dfuw.exe"]},"id":142,"name":"Darkfall: Unholy Wars"},{"executables":{"win32":["DCGAME.exe"]},"id":144,"name":"DC Universe Online"},{"executables":{"win32":["DeadIslandGame.exe"]},"id":145,"name":"Dead Island"},{"executables":{"win32":["deadspace2.exe"]},"id":146,"name":"Dead Space 2"},{"executables":{"win32":["LOTDGame.exe"]},"id":147,"name":"Deadlight"},{"executables":{"win32":["dxhr.exe"]},"id":148,"name":"Deus Ex: Human Revolution"},{"executables":{"win32":["DeviMayCry4.exe"]},"id":149,"name":"Devil May Cry 4"},{"executables":{"win32":["DMC-DevilMayCry.exe"]},"id":150,"name":"DmC Devil May Cry"},{"executables":{"win32":["dirt2_game.exe"]},"id":154,"name":"DiRT 2"},{"executables":{"win32":["dirt3_game.exe"]},"id":155,"name":"DiRT 3"},{"executables":{"win32":["dota.exe"]},"id":156,"name":"DOTA"},{"executables":{"win32":["DoubleDragon.exe"]},"id":158,"name":"Double Dragon Neon"},{"executables":{"win32":["DragonAge2.exe"]},"id":159,"name":"Dragon Age II"},{"executables":{"win32":["DragonAgeInquisition.exe"]},"id":160,"name":"Dragon Age: Inquisition"},{"executables":{"win32":["daorigins.exe"]},"id":161,"name":"Dragon Age: Origins"},{"executables":{"win32":["DBXV.exe"]},"id":162,"name":"Dragon Ball XenoVerse"},{"executables":{"win32":["DukeForever.exe"]},"id":163,"name":"Duke Nukem Forever"},{"executables":{"darwin":["Dustforce.app"],"win32":["dustforce.exe"]},"id":164,"name":"Dustforce"},{"executables":{"win32":["EliteDangerous32.exe"]},"id":165,"name":"Elite: Dangerous"},{"executables":{"win32":["exefile.exe"]},"id":166,"name":"Eve Online"},{"executables":{"win32":["eqgame.exe"]},"id":167,"name":"EverQuest"},{"executables":{"win32":["EverQuest2.exe"]},"id":168,"name":"EverQuest II"},{"executables":{},"id":169,"name":"EverQuest Next"},{"executables":{"win32":["Engine.exe"]},"id":170,"name":"F.E.A.R."},{"executables":{"win32":["FEAR2.exe"]},"id":171,"name":"F.E.A.R. 2: Project Origin"},{"executables":{"win32":["fallout3.exe"]},"id":172,"name":"Fallout 3"},{"executables":{"win32":["FalloutNV.exe"]},"id":174,"name":"Fallout: New Vegas"},{"executables":{"win32":["farcry3.exe"]},"id":175,"name":"Far Cry 3"},{"executables":{"win32":["fifa15.exe"]},"id":176,"name":"FIFA 15"},{"executables":{"win32":["FTLGame.exe"]},"id":180,"name":"FTL: Faster Than Light"},{"executables":{"win32":["GTAIV.exe"]},"id":181,"name":"Grand Theft Auto 4"},{"executables":{"win32":["GTA5.exe"]},"id":182,"name":"Grand Theft Auto 5"},{"executables":{"win32":["Gw.exe"]},"id":183,"name":"Guild Wars"},{"executables":{"win32":["H1Z1.exe"]},"id":186,"name":"H1Z1"},{"executables":{"win32":["HL2HL2.exe","hl2.exe"]},"id":188,"name":"Half Life 2"},{"executables":{"win32":["HOMEFRONT.exe"]},"id":195,"name":"Homefront"},{"executables":{"win32":["invisibleinc.exe"]},"id":196,"name":"Invisible Inc."},{"executables":{"win32":["LANoire.exe"]},"id":197,"name":"L.A. Noire"},{"executables":{"win32":["Landmark64.exe"]},"id":198,"name":"Landmark"},{"executables":{"win32":["left4dead2.exe"]},"id":201,"name":"Left 4 Dead 2"},{"executables":{"win32":["lineage.exe"]},"id":203,"name":"Lineage"},{"executables":{"win32":["Magicka.exe"]},"id":206,"name":"Magicka"},{"executables":{"win32":["MapleStory.exe"]},"id":208,"name":"MapleStory"},{"executables":{},"id":209,"name":"Mark of the Ninja"},{"executables":{"win32":["MassEffect.exe"]},"id":210,"name":"Mass Effect"},{"executables":{"win32":["MassEffect2.exe"]},"id":211,"name":"Mass Effect 2"},{"executables":{"win32":["MassEffect3Demo.exe"]},"id":212,"name":"Mass Effect 3"},{"executables":{"win32":["METAL GEAR RISING REVENGEANCE.exe"]},"id":214,"name":"Metal Gear Rising: Revengeance"},{"executables":{"win32":["metro2033.exe"]},"id":215,"name":"Metro 2033"},{"executables":{"win32":["MetroLL.exe"]},"id":216,"name":"Metro Last Light"},{"executables":{"win32":["MK10.exe"]},"id":218,"name":"Mortal Kombat X"},{"executables":{"win32":["speed.exe"]},"id":219,"name":"Need For Speed Most Wanted"},{"executables":{},"id":220,"name":"Neverwinder"},{"executables":{"darwin":["Outlast.app"],"win32":["OLGame.exe"]},"id":221,"name":"Outlast"},{"executables":{"win32":["PapersPlease.exe"]},"id":222,"name":"Papers, Please"},{"executables":{"win32":["payday_win32_release.exe"]},"id":223,"name":"PAYDAY"},{"executables":{"win32":["payday2_win32_release.exe"]},"id":224,"name":"PAYDAY2"},{"executables":{"win32":["PillarsOfEternity.exe"]},"id":225,"name":"Pillars of Eternity"},{"executables":{"win32":["PA.exe"]},"id":226,"name":"Planetary Annihilation"},{"executables":{"win32":["planetside2_x86.exe"]},"id":227,"name":"Planetside 2"},{"executables":{"win32":["hl2P.exe"]},"id":228,"name":"Portal"},{"executables":{"win32":["portal2.exe"]},"id":229,"name":"Portal 2"},{"executables":{"win32":["PrimalCarnageGame.exe"]},"id":231,"name":"Primal Cargnage"},{"executables":{"win32":["pCARS.exe"]},"id":232,"name":"Project Cars"},{"executables":{"win32":["RaceTheSun.exe"]},"id":233,"name":"Race The Sun"},{"executables":{"win32":["Rage.exe"]},"id":234,"name":"RAGE"},{"executables":{"win32":["ragexe.exe"]},"id":235,"name":"Ragnarok Online"},{"executables":{"win32":["rift.exe"]},"id":236,"name":"Rift"},{"executables":{"win32":["Rocksmith2014.exe"]},"id":237,"name":"Rocksmith 2014"},{"executables":{"win32":["SwiftKit-RS.exe","JagexLauncher.exe"]},"id":238,"name":"RuneScape"},{"executables":{"win32":["Shadowgrounds.exe"]},"id":239,"name":"Shadowgrounds"},{"executables":{"win32":["survivor.exe"]},"id":240,"name":"Shadowgrounds: Survivor"},{"executables":{"win32":["ShovelKnight.exe"]},"id":241,"name":"Shovel Knight"},{"executables":{"win32":["SimCity.exe"]},"id":242,"name":"SimCity"},{"executables":{"win32":["SporeApp.exe"]},"id":245,"name":"Spore"},{"executables":{"win32":["StarCitizen.exe"]},"id":246,"name":"Star Citizen"},{"executables":{},"id":247,"name":"Star Trek Online"},{"executables":{"win32":["battlefront.exe"]},"id":248,"name":"Star Wars Battlefront"},{"executables":{"win32":["swtor.exe"]},"id":249,"name":"Star Wars: The Old Republic"},{"executables":{"win32":["starbound.exe","starbound_opengl.exe"]},"id":250,"name":"Starbound"},{"executables":{"win32":["starcraft.exe"]},"id":251,"name":"Starcraft"},{"executables":{"win32":["SSFIV.exe"]},"id":253,"name":"Ultra Street Fighter IV"},{"executables":{"win32":["superhexagon.exe"]},"id":254,"name":"Super Hexagon"},{"executables":{"win32":["swordandsworcery_pc.exe"]},"id":255,"name":"Superbrothers: Sword & Sworcery EP"},{"executables":{"win32":["hl2TF.exe"]},"id":256,"name":"Team Fortress 2"},{"executables":{"win32":["TERA.exe"]},"id":258,"name":"TERA"},{"executables":{"win32":["Terraria.exe"]},"id":259,"name":"Terraria"},{"executables":{"win32":["Bethesda.net_Launcher.exe"]},"id":260,"name":"The Elder Scrolls Online"},{"executables":{"win32":["TESV.exe"]},"id":261,"name":"The Elder Scrolls V: Skyrim"},{"executables":{"win32":["TheSecretWorld.exe"]},"id":262,"name":"The Secret World"},{"executables":{"win32":["TS3.exe","ts3w.exe"]},"id":264,"name":"The Sims 3"},{"executables":{"win32":["WALKINGDEAD101.EXE"]},"id":265,"name":"The Walking Dead"},{"executables":{"win32":["TheWalkingDead2.exe"]},"id":266,"name":"The Walking Dead Season Two"},{"executables":{"win32":["witcher3.exe"]},"id":267,"name":"The Witcher 3"},{"executables":{"win32":["Future Soldier.exe"]},"id":268,"name":"Tom Clancy's Ghost Recon: Future Solider"},{"executables":{"win32":["TombRaider.exe"]},"id":269,"name":"Tomb Raider (2013)"},{"executables":{"win32":["Torchlight.exe"]},"id":271,"name":"Torchlight"},{"executables":{"win32":["Torchlight2.exe"]},"id":272,"name":"Torchlight 2"},{"executables":{"win32":["Shogun2.exe"]},"id":273,"name":"Total War: Shogun 2"},{"executables":{"win32":["Transistor.exe"]},"id":274,"name":"Transistor"},{"executables":{"win32":["trine.exe"]},"id":275,"name":"Trine"},{"executables":{"win32":["trine2_32bit.exe"]},"id":276,"name":"Trine 2"},{"executables":{"win32":["UOKR.exe"]},"id":277,"name":"Ultima Online"},{"executables":{"win32":["aces.exe"]},"id":279,"name":"War Thunder"},{"executables":{"win32":["Warcraft III.exe","wc3.exe"]},"id":281,"name":"Warcraft 3: Reign of Chaos"},{"executables":{"win32":["Warcraft II BNE.exe"]},"id":282,"name":"Warcraft II"},{"executables":{"win32":["Warframe.x64.exe","Warframe.exe"]},"id":283,"name":"Warframe"},{"executables":{"win32":["watch_dogs.exe"]},"id":284,"name":"Watch Dogs"},{"executables":{"win32":["WildStar64.exe"]},"id":285,"name":"WildStar"},{"executables":{"win32":["XComGame.exe"]},"id":288,"name":"XCOM: Enemy Unknown"},{"executables":{"win32":["DFO.exe","dfo.exe"]},"id":289,"name":"Dungeon Fighter Online"},{"executables":{"win32":["aclauncher.exe","acclient.exe"]},"id":290,"name":"Asheron's Call"},{"executables":{"win32":["MapleStory2.exe"]},"id":291,"name":"MapleStory 2"},{"executables":{"win32":["ksp.exe"]},"id":292,"name":"Kerbal Space Program"},{"executables":{"win32":["PINBALL.EXE"]},"id":293,"name":"3D Pinball: Space Cadet"},{"executables":{"win32":["dave.exe"]},"id":294,"name":"Dangerous Dave"},{"executables":{"win32":["iwbtgbeta(slomo).exe","iwbtgbeta(fs).exe"]},"id":295,"name":"I Wanna Be The Guy"},{"executables":{"win32":["MechWarriorOnline.exe "]},"id":296,"name":"Mech Warrior Online"},{"executables":{"win32":["dontstarve_steam.exe"]},"id":297,"name":"Don't Starve"},{"executables":{"win32":["GalCiv3.exe"]},"id":298,"name":"Galactic Civilization 3"},{"executables":{"win32":["Risk of Rain.exe"]},"id":299,"name":"Risk of Rain"},{"executables":{"win32":["Binding_of_Isaac.exe","Isaac-ng.exe"]},"id":300,"name":"The Binding of Isaac"},{"executables":{"win32":["RustClient.exe"]},"id":301,"name":"Rust"},{"executables":{"win32":["Clicker Heroes.exe"]},"id":302,"name":"Clicker Heroes"},{"executables":{"win32":["Brawlhalla.exe"]},"id":303,"name":"Brawlhalla"},{"executables":{"win32":["TownOfSalem.exe"]},"id":304,"name":"Town of Salem"},{"executables":{"win32":["osu!.exe"]},"id":305,"name":"osu!"},{"executables":{"win32":["PathOfExileSteam.exe","PathOfExile.exe"]},"id":306,"name":"Path of Exile"},{"executables":{"win32":["Dolphin.exe"]},"id":307,"name":"Dolphin"},{"executables":{"win32":["RocketLeague.exe"]},"id":308,"name":"Rocket League"},{"executables":{"win32":["TJPP.exe"]},"id":309,"name":"Jackbox Party Pack"},{"executables":{"win32":["KFGame.exe"]},"id":310,"name":"Killing Floor 2"},{"executables":{"win32":["ShooterGame.exe"]},"id":311,"name":"Ark: Survival Evolved"},{"executables":{"win32":["LifeIsStrange.exe"]},"id":312,"name":"Life Is Strange"},{"executables":{"win32":["Client_tos.exe"]},"id":313,"name":"Tree of Savior"},{"executables":{"win32":["olliolli2.exe"]},"id":314,"name":"OlliOlli2"},{"executables":{"win32":["cw.exe"]},"id":315,"name":"Closers Dimension Conflict"},{"executables":{"win32":["ESSTEAM.exe","elsword.exe","x2.exe"]},"id":316,"name":"Elsword"},{"executables":{"win32":["ori.exe"]},"id":317,"name":"Ori and the Blind Forest"},{"executables":{"win32":["Skyforge.exe"]},"id":318,"name":"Skyforge"},{"executables":{"win32":["projectzomboid64.exe","projectzomboid32.exe"]},"id":319,"name":"Project Zomboid"},{"executables":{"win32":["From_The_Depths.exe"]},"id":320,"name":"The Depths"},{"executables":{"win32":["TheCrew.exe"]},"id":321,"name":"The Crew"},{"executables":{"win32":["MarvelHeroes2015.exe"]},"id":322,"name":"Marvel Heroes 2015"},{"executables":{"win32":["timeclickers.exe"]},"id":324,"name":"Time Clickers"},{"executables":{"win32":["eurotrucks2.exe"]},"id":325,"name":"Euro Truck Simulator 2"},{"executables":{"win32":["FarmingSimulator2015Game.exe"]},"id":326,"name":"Farming Simulator 15"},{"executables":{"win32":["strife.exe"]},"id":327,"name":"Strife"},{"executables":{"win32":["Awesomenauts.exe"]},"id":328,"name":"Awesomenauts"},{"executables":{"win32":["Dofus.exe"]},"id":329,"name":"Dofus"},{"executables":{"win32":["Boid.exe"]},"id":330,"name":"Boid"},{"executables":{"win32":["adventure-capitalist.exe"]},"id":331,"name":"AdVenture Capitalist"},{"executables":{"win32":["OrcsMustDie2.exe"]},"id":332,"name":"Orcs Must Die! 2"},{"executables":{"win32":["Mountain.exe"]},"id":333,"name":"Mountain"},{"executables":{"win32":["Valkyria.exe"]},"id":335,"name":"Valkyria Chronicles"},{"executables":{"win32":["ffxiiiimg.exe"]},"id":336,"name":"Final Fantasy XIII"},{"executables":{"win32":["TLR.exe"]},"id":337,"name":"The Last Remnant"},{"executables":{"win32":["Cities.exe"]},"id":339,"name":"Cities Skylines"},{"executables":{"win32":["worldofwarships.exe","WoWSLauncher.exe"]},"id":341,"name":"World of Warships"},{"executables":{"win32":["spacegame-Win64-shipping.exe"]},"id":342,"name":"Fractured Space"},{"executables":{"win32":["thespacegame.exe"]},"id":343,"name":"Ascent - The Space Game"},{"executables":{"win32":["DuckGame.exe"]},"id":344,"name":"Duck Game"},{"executables":{"win32":["PPSSPPWindows.exe"]},"id":345,"name":"PPSSPP"},{"executables":{"win32":["MBAA.exe"]},"id":346,"name":"Melty Blood Actress Again: Current Code"},{"executables":{"win32":["TheWolfAmongUs.exe"]},"id":347,"name":"The Wolf Among Us"},{"executables":{"win32":["SpaceEngineers.exe"]},"id":348,"name":"Space Engineers"},{"executables":{"win32":["Borderlands.exe"]},"id":349,"name":"Borderlands"},{"executables":{"win32":["100orange.exe"]},"id":351,"name":"100% Orange Juice"},{"executables":{"win32":["reflex.exe"]},"id":354,"name":"Reflex"},{"executables":{"win32":["pso2.exe"]},"id":355,"name":"Phantasy Star Online 2"},{"executables":{"win32":["AssettoCorsa.exe"]},"id":356,"name":"Assetto Corsa"},{"executables":{"win32":["iw3mp.exe","iw3sp.exe"]},"id":357,"name":"Call of Duty 4: Modern Warfare"},{"executables":{"win32":["WolfOldBlood_x64.exe"]},"id":358,"name":"Wolfenstein: The Old Blood"},{"executables":{"win32":["castle.exe"]},"id":359,"name":"Castle Crashers"},{"executables":{"win32":["vindictus.exe"]},"id":360,"name":"Vindictus"},{"executables":{"win32":["ShooterGame-Win32-Shipping.exe"]},"id":361,"name":"Dirty Bomb"},{"executables":{"win32":["BatmanAK.exe"]},"id":362,"name":"Batman Arkham Knight"},{"executables":{"win32":["drt.exe"]},"id":363,"name":"Dirt Rally"},{"executables":{"win32":["rFactor.exe"]},"id":364,"name":"rFactor"},{"executables":{"win32":["clonk.exe"]},"id":365,"name":"Clonk Rage"},{"executables":{"win32":["SRHK.exe"]},"id":366,"name":"Shadowrun: Hong Kong"},{"executables":{"win32":["Insurgency.exe"]},"id":367,"name":"Insurgency"},{"executables":{"win32":["StepMania.exe"]},"id":368,"name":"Step Mania"},{"executables":{"win32":["FirefallCLient.exe"]},"id":369,"name":"Firefall"},{"executables":{"win32":["mirrorsedge.exe"]},"id":370,"name":"Mirrors Edge"},{"executables":{"win32":["MgsGroundZeroes.exe"]},"id":371,"name":"Metal Gear Solid V: Ground Zeroes"},{"executables":{"win32":["mgsvtpp.exe"]},"id":372,"name":"Metal Gear Solid V: The Phantom Pain"},{"executables":{"win32":["tld.exe"]},"id":373,"name":"The Long Dark"},{"executables":{"win32":["TKOM.exe"]},"id":374,"name":"Take On Mars"},{"executables":{"win32":["robloxplayerlauncher.exe","Roblox.exe"]},"id":375,"name":"Roblox"},{"executables":{"win32":["eu4.exe"]},"id":376,"name":"Europa Universalis 4"},{"executables":{"win32":["APB.exe"]},"id":377,"name":"APB Reloaded"},{"executables":{"win32":["Robocraft.exe"]},"id":378,"name":"Robocraft"},{"executables":{"win32":["Unity.exe"]},"id":379,"name":"Unity"},{"executables":{"win32":["Simpsons.exe"]},"id":380,"name":"The Simpsons: Hit & Run"},{"executables":{"win32":["Dnlauncher.exe","DragonNest.exe"]},"id":381,"name":"Dragon Nest"},{"executables":{"win32":["Trove.exe"]},"id":382,"name":"Trove"},{"executables":{"win32":["EndlessLegend.exe"]},"id":383,"name":"Endless Legend"},{"executables":{"win32":["TurbineLauncher.exe","dndclient.exe"]},"id":384,"name":"Dungeons & Dragons Online"},{"executables":{"win32":["quakelive.exe","quakelive_steam.exe"]},"id":385,"name":"Quake Live"},{"executables":{"win32":["7DaysToDie.exe"]},"id":386,"name":"7DaysToDie"},{"executables":{"win32":["SpeedRunners.exe"]},"id":387,"name":"SpeedRunners"},{"executables":{"win32":["gamemd.exe"]},"id":388,"name":"Command & Conquer: Red Alert 2"},{"executables":{"win32":["generals.exe"]},"id":389,"name":"Command & Conquer Generals: Zero Hour"},{"executables":{"win32":["Oblivion.exe"]},"id":390,"name":"The Elder Scrolls 4: Oblivion"},{"executables":{"win32":["mgsi.exe"]},"id":391,"name":"Metal Gear Solid"},{"executables":{"win32":["EoCApp.exe"]},"id":392,"name":"Divinity - Original Sin"},{"executables":{"win32":["Torment.exe"]},"id":393,"name":"Planescape: Torment"},{"executables":{"win32":["HexPatch.exe"]},"id":394,"name":"Hex: Shards of Fate"},{"executables":{"win32":["NS3FB.exe"]},"id":395,"name":"Naruto Shippuden Ultimate Ninja Storm 3 Full Burst"},{"executables":{"win32":["NSUNSR.exe"]},"id":396,"name":"Naruto Shippuden Ultimate Ninja Storm Revolution"},{"executables":{"win32":["SaintsRowIV.exe"]},"id":397,"name":"Saints Row IV"},{"executables":{"win32":["Shadowrun.exe"]},"id":398,"name":"Shadowrun"},{"executables":{"win32":["DungeonoftheEndless.exe"]},"id":399,"name":"Dungeon of the Endless"},{"executables":{"win32":["Hon.exe"]},"id":400,"name":"Heroes of Newerth"},{"executables":{"win32":["mabinogi.exe"]},"id":401,"name":"Mabinogi"},{"executables":{"win32":["CoD2MP_s.exe","CoDSP_s.exe"]},"id":402,"name":"Call of Duty 2:"},{"executables":{"win32":["CoDWaWmp.exe","CoDWaw.exe"]},"id":403,"name":"Call of Duty: World at War"},{"executables":{"win32":["heroes.exe"]},"id":404,"name":"Mabinogi Heroes (Vindictus) "},{"executables":{"win32":["KanColleViewer.exe"]},"id":405,"name":"KanColle "},{"executables":{"win32":["cyphers.exe"]},"id":406,"name":"Cyphers"},{"executables":{"win32":["RelicCoH2.exe"]},"id":407,"name":"Company of Heroes 2"},{"executables":{"win32":["MJ.exe"]},"id":408,"name":"セガNET麻雀MJ"},{"executables":{"win32":["ge.exe"]},"id":409,"name":"Granado Espada"},{"executables":{"win32":["NovaRO.exe"]},"id":410,"name":"Nova Ragnarok Online"},{"executables":{"win32":["RivalsofAether.exe"]},"id":411,"name":"Rivals of Aether"},{"executables":{"win32":["bfh.exe"]},"id":412,"name":"Battlefield Hardline"},{"executables":{"win32":["GrowHome.exe"]},"id":413,"name":"Grow Home"},{"executables":{"win32":["patriots.exe"]},"id":414,"name":"Rise of Nations Extended"},{"executables":{"win32":["Railroads.exe"]},"id":415,"name":"Sid Meier's Railroads!"},{"executables":{"win32":["Empire.exe"]},"id":416,"name":"Empire: Total War"},{"executables":{"win32":["Napoleon.exe"]},"id":417,"name":"Napoleon: Total War"},{"executables":{"win32":["gta_sa.exe"]},"id":418,"name":"Grand Theft Auto: San Andreas"},{"executables":{"win32":["MadMax.exe"]},"id":419,"name":"Mad Max"},{"executables":{"win32":["Titanfall.exe"]},"id":420,"name":"Titanfall"},{"executables":{"win32":["age2_x1.exe"]},"id":421,"name":"Age of Empires II: The Conquerors"},{"executables":{"win32":["Rome2.exe"]},"id":422,"name":"Total War: ROME 2"},{"executables":{"win32":["ShadowOfMordor.exe"]},"id":423,"name":"Middle-earth: Shadow of Mordor"},{"executables":{"win32":["Subnautica.exe"]},"id":424,"name":"Subnautica"},{"executables":{"win32":["anno5.exe"]},"id":425,"name":"Anno 2070"},{"executables":{"win32":["carrier.exe"]},"id":426,"name":"Carrier Command Gaea Mission"},{"executables":{"win32":["DarksidersPC.exe"]},"id":427,"name":"Darksiders"},{"executables":{"win32":["Darksiders2.exe"]},"id":428,"name":"Darksiders 2"},{"executables":{"win32":["mudlet.exe"]},"id":429,"name":"Mudlet"},{"executables":{"win32":["DunDefLauncher.exe"]},"id":430,"name":"Dungeon Defenders II"},{"executables":{"win32":["hng.exe"]},"id":431,"name":"Heroes and Generals"},{"executables":{"win32":["WFTOGame.exe"]},"id":432,"name":"War of the Overworld"},{"executables":{"win32":["Talisman.exe"]},"id":433,"name":"Talisman: Digital Edition"},{"executables":{"win32":["limbo.exe"]},"id":434,"name":"Limbo"},{"executables":{"win32":["ibbobb.exe"]},"id":435,"name":"ibb & obb"},{"executables":{"win32":["BattleBlockTheater.exe"]},"id":436,"name":"BattleBlock Theater"},{"executables":{"win32":["iracinglauncher.exe","iracingsim.exe","iracingsim64.exe"]},"id":437,"name":"iRacing"},{"executables":{"win32":["CivilizationV_DX11.exe"]},"id":438,"name":"Civilization V"}]
+},{}]},{},[5])(5)
+});
\ No newline at end of file
diff --git a/web-dist/discord.3.7.1.js b/web-dist/discord.3.7.1.js
new file mode 100644
index 000000000..0d9f9341a
--- /dev/null
+++ b/web-dist/discord.3.7.1.js
@@ -0,0 +1,3879 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Discord = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o]*>/g) || [])[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var mention = _step3.value;
+
+ _mentions.push(mention.substring(2, mention.length - 1));
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3["return"]) {
+ _iterator3["return"]();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ return _mentions;
+ }
+ });
+
+ return prom;
+ }
+
+ //def createws
+ }, {
+ key: "createws",
+ value: function createws(url) {
+ if (this.websocket) return false;
+
+ var self = this;
+
+ //good to go
+ this.websocket = new WebSocket(url);
+
+ //open
+ this.websocket.onopen = function () {
+ self.trySendConnData(); //try connecting
+ };
+
+ //close
+ this.websocket.onclose = function () {
+ self.trigger("disconnected");
+ };
+
+ //message
+ this.websocket.onmessage = function (e) {
+
+ var dat = false,
+ data = {};
+
+ try {
+ dat = JSON.parse(e.data);
+ data = dat.d;
+ } catch (err) {
+ self.trigger("error", err, e);
+ return;
+ }
+
+ self.trigger("raw", dat);
+
+ //valid message
+ switch (dat.t) {
+
+ case "READY":
+ self.debug("received ready packet");
+
+ self.user = self.addUser(data.user);
+
+ var _iteratorNormalCompletion4 = true;
+ var _didIteratorError4 = false;
+ var _iteratorError4 = undefined;
+
+ try {
+ for (var _iterator4 = data.guilds[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
+ var _server = _step4.value;
+
+ var server = self.addServer(_server);
+ }
+ } catch (err) {
+ _didIteratorError4 = true;
+ _iteratorError4 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion4 && _iterator4["return"]) {
+ _iterator4["return"]();
+ }
+ } finally {
+ if (_didIteratorError4) {
+ throw _iteratorError4;
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion5 = true;
+ var _didIteratorError5 = false;
+ var _iteratorError5 = undefined;
+
+ try {
+ for (var _iterator5 = data.private_channels[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
+ var _pmc = _step5.value;
+
+ var pmc = self.addPMChannel(_pmc);
+ }
+ } catch (err) {
+ _didIteratorError5 = true;
+ _iteratorError5 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion5 && _iterator5["return"]) {
+ _iterator5["return"]();
+ }
+ } finally {
+ if (_didIteratorError5) {
+ throw _iteratorError5;
+ }
+ }
+ }
+
+ self.trigger("ready");
+ self.readyTime = Date.now();
+ self.debug("cached " + self.serverCache.length + " servers, " + self.channelCache.length + " channels, " + self.pmChannelCache.length + " PMs and " + self.userCache.length + " users.");
+ self.state = 3;
+ setInterval(function () {
+ self.keepAlive.apply(self);
+ }, data.heartbeat_interval);
+
+ break;
+ case "MESSAGE_CREATE":
+ self.debug("received message");
+
+ var mentions = [];
+ data.mentions = data.mentions || []; //for some reason this was not defined at some point?
+ var _iteratorNormalCompletion6 = true;
+ var _didIteratorError6 = false;
+ var _iteratorError6 = undefined;
+
+ try {
+ for (var _iterator6 = data.mentions[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
+ var mention = _step6.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError6 = true;
+ _iteratorError6 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion6 && _iterator6["return"]) {
+ _iterator6["return"]();
+ }
+ } finally {
+ if (_didIteratorError6) {
+ throw _iteratorError6;
+ }
+ }
+ }
+
+ var channel = self.getChannel("id", data.channel_id);
+ if (channel) {
+ var msg = channel.addMessage(new Message(data, channel, mentions, self.addUser(data.author)));
+ self.trigger("message", msg);
+ }
+
+ break;
+ case "MESSAGE_DELETE":
+ self.debug("message deleted");
+
+ var channel = self.getChannel("id", data.channel_id);
+ var message = channel.getMessage("id", data.id);
+ if (message) {
+ self.trigger("messageDelete", channel, message);
+ channel.messages.splice(channel.messages.indexOf(message), 1);
+ } else {
+ //don't have the cache of that message ;(
+ self.trigger("messageDelete", channel);
+ }
+ break;
+ case "MESSAGE_UPDATE":
+ self.debug("message updated");
+
+ var channel = self.getChannel("id", data.channel_id);
+ var formerMessage = channel.getMessage("id", data.id);
+
+ if (formerMessage) {
+
+ //new message might be partial, so we need to fill it with whatever the old message was.
+ var info = {};
+
+ for (var key in formerMessage) {
+ info[key] = formerMessage[key];
+ }
+
+ for (var key in data) {
+ info[key] = data[key];
+ }
+
+ var mentions = [];
+ var _iteratorNormalCompletion7 = true;
+ var _didIteratorError7 = false;
+ var _iteratorError7 = undefined;
+
+ try {
+ for (var _iterator7 = info.mentions[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
+ var mention = _step7.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError7 = true;
+ _iteratorError7 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion7 && _iterator7["return"]) {
+ _iterator7["return"]();
+ }
+ } finally {
+ if (_didIteratorError7) {
+ throw _iteratorError7;
+ }
+ }
+ }
+
+ var newMessage = new Message(info, channel, mentions, formerMessage.author);
+
+ self.trigger("messageUpdate", newMessage, formerMessage);
+
+ channel.messages[channel.messages.indexOf(formerMessage)] = newMessage;
+ }
+
+ // message isn't in cache, and if it's a partial it could cause
+ // all hell to break loose... best to just act as if nothing happened
+
+ break;
+
+ case "GUILD_DELETE":
+
+ var server = self.getServer("id", data.id);
+
+ if (server) {
+ self.serverCache.splice(self.serverCache.indexOf(server), 1);
+ self.trigger("serverDelete", server);
+ }
+
+ break;
+
+ case "CHANNEL_DELETE":
+
+ var channel = self.getChannel("id", data.id);
+
+ if (channel) {
+
+ var server = channel.server;
+
+ if (server) {
+
+ server.channels.splice(server.channels.indexOf(channel), 1);
+ }
+
+ self.trigger("channelDelete", channel);
+
+ self.serverCache.splice(self.serverCache.indexOf(channel), 1);
+ }
+
+ break;
+
+ case "GUILD_CREATE":
+
+ var server = self.getServer("id", data.id);
+
+ if (!server) {
+ //if server doesn't already exist because duh
+ server = self.addServer(data);
+ } /*else if(server.channels.length === 0){
+
+ var srv = new Server(data, self);
+ for(channel of data.channels){
+ srv.channels.push(new Channel(channel, data.id));
+ }
+ self.serverCache[self.serverCache.indexOf(server)] = srv;
+
+ }*/
+
+ if (self.serverCreateListener[data.id]) {
+ var cbs = self.serverCreateListener[data.id];
+ cbs[0](server); //promise then callback
+ cbs[1](null, server); //legacy callback
+ self.serverCreateListener[data.id] = null;
+ }
+
+ self.trigger("serverCreate", server);
+
+ break;
+
+ case "CHANNEL_CREATE":
+
+ var channel = self.getChannel("id", data.id);
+
+ if (!channel) {
+
+ var chann = self.addChannel(data, data.guild_id);
+ var srv = self.getServer("id", data.guild_id);
+ if (srv) {
+ srv.addChannel(chann);
+ }
+ self.trigger("channelCreate", chann);
+ }
+
+ break;
+
+ case "GUILD_MEMBER_ADD":
+
+ var server = self.getServer("id", data.guild_id);
+
+ if (server) {
+
+ var user = self.addUser(data.user); //if for whatever reason it doesn't exist..
+
+ if (! ~server.members.indexOf(user)) {
+ server.members.push(user);
+ }
+
+ self.trigger("serverNewMember", user, server);
+ }
+
+ break;
+
+ case "GUILD_MEMBER_REMOVE":
+
+ var server = self.getServer("id", data.guild_id);
+
+ if (server) {
+
+ var user = self.addUser(data.user); //if for whatever reason it doesn't exist..
+
+ if (~server.members.indexOf(user)) {
+ server.members.splice(server.members.indexOf(user), 1);
+ }
+
+ self.trigger("serverRemoveMember", user, server);
+ }
+
+ break;
+
+ case "USER_UPDATE":
+
+ if (self.user && data.id === self.user.id) {
+
+ var newUser = new User(data); //not actually adding to the cache
+
+ self.trigger("userUpdate", newUser, self.user);
+
+ if (~self.userCache.indexOf(self.user)) {
+ self.userCache[self.userCache.indexOf(self.user)] = newUser;
+ }
+
+ self.user = newUser;
+ }
+
+ break;
+
+ case "PRESENCE_UPDATE":
+
+ var userInCache = self.getUser("id", data.user.id);
+
+ if (userInCache) {
+ //user exists
+ var presenceUser = new User(data.user);
+ if (presenceUser.equalsStrict(userInCache)) {
+ //they're exactly the same, an actual presence update
+ userInCache.status = data.status;
+ self.trigger("presence", {
+ user: userInCache,
+ status: data.status,
+ server: self.getServer("id", data.guild_id),
+ gameId: data.game_id
+ });
+ } else {
+ //one of their details changed.
+ self.trigger("userUpdate", userInCache, presenceUser);
+ self.userCache[self.userCache.indexOf(userInCache)] = presenceUser;
+ }
+ }
+
+ break;
+
+ case "CHANNEL_UPDATE":
+
+ var channelInCache = self.getChannel("id", data.id),
+ serverInCache = self.getServer("id", data.guild_id);
+
+ if (channelInCache && serverInCache) {
+
+ var newChann = new Channel(data, serverInCache);
+ newChann.messages = channelInCache.messages;
+
+ self.trigger("channelUpdate", channelInCache, newChann);
+
+ self.channelCache[self.channelCache.indexOf(channelInCache)] = newChann;
+ }
+
+ break;
+
+ default:
+ self.debug("received unknown packet");
+ self.trigger("unknown", dat);
+ break;
+
+ }
+ };
+ }
+
+ //def addUser
+ }, {
+ key: "addUser",
+ value: function addUser(data) {
+ if (!this.getUser("id", data.id)) {
+ this.userCache.push(new User(data));
+ }
+ return this.getUser("id", data.id);
+ }
+
+ //def addChannel
+ }, {
+ key: "addChannel",
+ value: function addChannel(data, serverId) {
+ if (!this.getChannel("id", data.id)) {
+ this.channelCache.push(new Channel(data, this.getServer("id", serverId)));
+ }
+ return this.getChannel("id", data.id);
+ }
+ }, {
+ key: "addPMChannel",
+ value: function addPMChannel(data) {
+ if (!this.getPMChannel("id", data.id)) {
+ this.pmChannelCache.push(new PMChannel(data, this));
+ }
+ return this.getPMChannel("id", data.id);
+ }
+ }, {
+ key: "setTopic",
+ value: function setTopic(channel, topic) {
+ var callback = arguments.length <= 2 || arguments[2] === undefined ? function (err) {} : arguments[2];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ self.resolveDestination(channel).then(next)["catch"](error);
+
+ function error(e) {
+ callback(e);
+ reject(e);
+ }
+
+ function next(destination) {
+
+ var asChan = self.getChannel("id", destination);
+
+ request.patch(Endpoints.CHANNELS + "/" + destination).set("authorization", self.token).send({
+ name: asChan.name,
+ position: 0,
+ topic: topic
+ }).end(function (err, res) {
+ if (err) {
+ error(err);
+ } else {
+ asChan.topic = res.body.topic;
+ resolve();
+ callback();
+ }
+ });
+ }
+ });
+ }
+
+ //def addServer
+ }, {
+ key: "addServer",
+ value: function addServer(data) {
+
+ var self = this;
+ var server = this.getServer("id", data.id);
+
+ if (data.unavailable) {
+ self.trigger("unavailable", data);
+ self.debug("Server ID " + data.id + " has been marked unavailable by Discord. It was not cached.");
+ return;
+ }
+
+ if (!server) {
+ server = new Server(data, this);
+ this.serverCache.push(server);
+ if (data.channels) {
+ var _iteratorNormalCompletion8 = true;
+ var _didIteratorError8 = false;
+ var _iteratorError8 = undefined;
+
+ try {
+ for (var _iterator8 = data.channels[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
+ var channel = _step8.value;
+
+ server.channels.push(this.addChannel(channel, server.id));
+ }
+ } catch (err) {
+ _didIteratorError8 = true;
+ _iteratorError8 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion8 && _iterator8["return"]) {
+ _iterator8["return"]();
+ }
+ } finally {
+ if (_didIteratorError8) {
+ throw _iteratorError8;
+ }
+ }
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion9 = true;
+ var _didIteratorError9 = false;
+ var _iteratorError9 = undefined;
+
+ try {
+ for (var _iterator9 = data.presences[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
+ var presence = _step9.value;
+
+ self.getUser("id", presence.user.id).status = presence.status;
+ }
+ } catch (err) {
+ _didIteratorError9 = true;
+ _iteratorError9 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion9 && _iterator9["return"]) {
+ _iterator9["return"]();
+ }
+ } finally {
+ if (_didIteratorError9) {
+ throw _iteratorError9;
+ }
+ }
+ }
+
+ return server;
+ }
+
+ //def getUser
+ }, {
+ key: "getUser",
+ value: function getUser(key, value) {
+ var _iteratorNormalCompletion10 = true;
+ var _didIteratorError10 = false;
+ var _iteratorError10 = undefined;
+
+ try {
+ for (var _iterator10 = this.userCache[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
+ var user = _step10.value;
+
+ if (user[key] === value) {
+ return user;
+ }
+ }
+ } catch (err) {
+ _didIteratorError10 = true;
+ _iteratorError10 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion10 && _iterator10["return"]) {
+ _iterator10["return"]();
+ }
+ } finally {
+ if (_didIteratorError10) {
+ throw _iteratorError10;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def getChannel
+ }, {
+ key: "getChannel",
+ value: function getChannel(key, value) {
+ var _iteratorNormalCompletion11 = true;
+ var _didIteratorError11 = false;
+ var _iteratorError11 = undefined;
+
+ try {
+ for (var _iterator11 = this.channelCache[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
+ var channel = _step11.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError11 = true;
+ _iteratorError11 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion11 && _iterator11["return"]) {
+ _iterator11["return"]();
+ }
+ } finally {
+ if (_didIteratorError11) {
+ throw _iteratorError11;
+ }
+ }
+ }
+
+ return this.getPMChannel(key, value); //might be a PM
+ }
+ }, {
+ key: "getPMChannel",
+ value: function getPMChannel(key, value) {
+ var _iteratorNormalCompletion12 = true;
+ var _didIteratorError12 = false;
+ var _iteratorError12 = undefined;
+
+ try {
+ for (var _iterator12 = this.pmChannelCache[Symbol.iterator](), _step12; !(_iteratorNormalCompletion12 = (_step12 = _iterator12.next()).done); _iteratorNormalCompletion12 = true) {
+ var channel = _step12.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError12 = true;
+ _iteratorError12 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion12 && _iterator12["return"]) {
+ _iterator12["return"]();
+ }
+ } finally {
+ if (_didIteratorError12) {
+ throw _iteratorError12;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def getServer
+ }, {
+ key: "getServer",
+ value: function getServer(key, value) {
+ var _iteratorNormalCompletion13 = true;
+ var _didIteratorError13 = false;
+ var _iteratorError13 = undefined;
+
+ try {
+ for (var _iterator13 = this.serverCache[Symbol.iterator](), _step13; !(_iteratorNormalCompletion13 = (_step13 = _iterator13.next()).done); _iteratorNormalCompletion13 = true) {
+ var server = _step13.value;
+
+ if (server[key] === value) {
+ return server;
+ }
+ }
+ } catch (err) {
+ _didIteratorError13 = true;
+ _iteratorError13 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion13 && _iterator13["return"]) {
+ _iterator13["return"]();
+ }
+ } finally {
+ if (_didIteratorError13) {
+ throw _iteratorError13;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //def trySendConnData
+ }, {
+ key: "trySendConnData",
+ value: function trySendConnData() {
+
+ if (this.token && !this.alreadySentData) {
+
+ this.alreadySentData = true;
+
+ var data = {
+ op: 2,
+ d: {
+ token: this.token,
+ v: 3,
+ properties: {
+ "$os": "discord.js",
+ "$browser": "discord.js",
+ "$device": "discord.js",
+ "$referrer": "",
+ "$referring_domain": ""
+ }
+ }
+ };
+ this.websocket.send(JSON.stringify(data));
+ }
+ }
+ }, {
+ key: "resolveServerID",
+ value: function resolveServerID(resource) {
+
+ if (resource instanceof Server) {
+ return resource.id;
+ } else if (!isNaN(resource) && resource.length && resource.length === 17) {
+ return resource;
+ }
+ }
+ }, {
+ key: "resolveDestination",
+ value: function resolveDestination(destination) {
+ var channId = false;
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ if (destination instanceof Server) {
+ channId = destination.id; //general is the same as server id
+ } else if (destination instanceof Channel) {
+ channId = destination.id;
+ } else if (destination instanceof Message) {
+ channId = destination.channel.id;
+ } else if (destination instanceof PMChannel) {
+ channId = destination.id;
+ } else if (destination instanceof User) {
+
+ //check if we have a PM
+ var _iteratorNormalCompletion14 = true;
+ var _didIteratorError14 = false;
+ var _iteratorError14 = undefined;
+
+ try {
+ for (var _iterator14 = self.pmChannelCache[Symbol.iterator](), _step14; !(_iteratorNormalCompletion14 = (_step14 = _iterator14.next()).done); _iteratorNormalCompletion14 = true) {
+ var pmc = _step14.value;
+
+ if (pmc.user.equals(destination)) {
+ resolve(pmc.id);
+ return;
+ }
+ }
+
+ //we don't, at this point we're late
+ } catch (err) {
+ _didIteratorError14 = true;
+ _iteratorError14 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion14 && _iterator14["return"]) {
+ _iterator14["return"]();
+ }
+ } finally {
+ if (_didIteratorError14) {
+ throw _iteratorError14;
+ }
+ }
+ }
+
+ self.startPM(destination).then(function (pmc) {
+ resolve(pmc.id);
+ })["catch"](reject);
+ } else {
+ channId = destination;
+ }
+ if (channId) resolve(channId);else reject();
+ });
+ }
+ }, {
+ key: "_sendMessage",
+ value: function _sendMessage(destination, content, tts, mentions) {
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request.post(Endpoints.CHANNELS + "/" + destination + "/messages").set("authorization", self.token).send({
+ content: content,
+ mentions: mentions,
+ tts: tts
+ }).end(function (err, res) {
+
+ if (err) {
+ reject(err);
+ } else {
+ var data = res.body;
+
+ var mentions = [];
+
+ data.mentions = data.mentions || []; //for some reason this was not defined at some point?
+
+ var _iteratorNormalCompletion15 = true;
+ var _didIteratorError15 = false;
+ var _iteratorError15 = undefined;
+
+ try {
+ for (var _iterator15 = data.mentions[Symbol.iterator](), _step15; !(_iteratorNormalCompletion15 = (_step15 = _iterator15.next()).done); _iteratorNormalCompletion15 = true) {
+ var mention = _step15.value;
+
+ mentions.push(self.addUser(mention));
+ }
+ } catch (err) {
+ _didIteratorError15 = true;
+ _iteratorError15 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion15 && _iterator15["return"]) {
+ _iterator15["return"]();
+ }
+ } finally {
+ if (_didIteratorError15) {
+ throw _iteratorError15;
+ }
+ }
+ }
+
+ var channel = self.getChannel("id", data.channel_id);
+ if (channel) {
+ var msg = channel.addMessage(new Message(data, channel, mentions, self.addUser(data.author)));
+ resolve(msg);
+ }
+ }
+ });
+ });
+ }
+ }, {
+ key: "_sendFile",
+ value: function _sendFile(destination, attachment) {
+ var attachmentName = arguments.length <= 2 || arguments[2] === undefined ? "DEFAULT BECAUSE YOU DIDN'T SPECIFY WHY.png" : arguments[2];
+
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ request.post(Endpoints.CHANNELS + "/" + destination + "/messages").set("authorization", self.token).attach("file", attachment, attachmentName).end(function (err, res) {
+
+ if (err) {
+ reject(err);
+ } else {
+
+ var chann = self.getChannel("id", destination);
+ if (chann) {
+ var msg = chann.addMessage(new Message(res.body, chann, [], self.user));
+ resolve(msg);
+ }
+ }
+ });
+ });
+ }
+ }, {
+ key: "_updateMessage",
+ value: function _updateMessage(message, content) {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ request.patch(Endpoints.CHANNELS + "/" + message.channel.id + "/messages/" + message.id).set("authorization", self.token).send({
+ content: content,
+ mentions: []
+ }).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ var msg = new Message(res.body, message.channel, message.mentions, message.sender);
+ resolve(msg);
+ message.channel.messages[message.channel.messages.indexOf(message)] = msg;
+ }
+ });
+ });
+ }
+ }, {
+ key: "_deleteMessage",
+ value: function _deleteMessage(message) {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+
+ request.del(Endpoints.CHANNELS + "/" + message.channel.id + "/messages/" + message.id).set("authorization", self.token).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve();
+ }
+ });
+ });
+ }
+ }, {
+ key: "checkQueue",
+ value: function checkQueue(channelID) {
+ var _this = this;
+
+ var self = this;
+
+ if (!this.checkingQueue[channelID]) {
+ (function () {
+ var doNext = function doNext() {
+ if (self.queue[channelID].length === 0) {
+ done();
+ return;
+ }
+ var queuedEvent = self.queue[channelID][0];
+ switch (queuedEvent.action) {
+ case "sendMessage":
+ var msgToSend = queuedEvent;
+ self._sendMessage(channelID, msgToSend.content, msgToSend.tts, msgToSend.mentions).then(function (msg) {
+ msgToSend.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToSend.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "sendFile":
+ var fileToSend = queuedEvent;
+ self._sendFile(channelID, fileToSend.attachment, fileToSend.attachmentName).then(function (msg) {
+ fileToSend.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ fileToSend.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "updateMessage":
+ var msgToUpd = queuedEvent;
+ self._updateMessage(msgToUpd.message, msgToUpd.content).then(function (msg) {
+ msgToUpd.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToUpd.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ case "deleteMessage":
+ var msgToDel = queuedEvent;
+ self._deleteMessage(msgToDel.message).then(function (msg) {
+ msgToDel.then(msg);
+ self.queue[channelID].shift();
+ doNext();
+ })["catch"](function (err) {
+ msgToDel.error(err);
+ self.queue[channelID].shift();
+ doNext();
+ });
+ break;
+ default:
+ done();
+ break;
+ }
+ };
+
+ var done = function done() {
+ self.checkingQueue[channelID] = false;
+ return;
+ };
+
+ //if we aren't already checking this queue.
+ _this.checkingQueue[channelID] = true;
+ doNext();
+ })();
+ }
+ }
+ }, {
+ key: "getGateway",
+ value: function getGateway() {
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ request.get(Endpoints.API + "/gateway").set("authorization", self.token).end(function (err, res) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(res.body.url);
+ }
+ });
+ });
+ }
+ }, {
+ key: "setStatusIdle",
+ value: function setStatusIdle() {
+ this.setStatus("idle");
+ }
+ }, {
+ key: "setStatusOnline",
+ value: function setStatusOnline() {
+ this.setStatus("online");
+ }
+ }, {
+ key: "setStatusActive",
+ value: function setStatusActive() {
+ this.setStatusOnline();
+ }
+ }, {
+ key: "setStatusHere",
+ value: function setStatusHere() {
+ this.setStatusOnline();
+ }
+ }, {
+ key: "setStatusAway",
+ value: function setStatusAway() {
+ this.setStatusIdle();
+ }
+ }, {
+ key: "startTyping",
+ value: function startTyping(chann, stopTypeTime) {
+ var self = this;
+
+ this.resolveDestination(chann).then(next);
+
+ function next(channel) {
+ if (self.typingIntervals[channel]) {
+ return;
+ }
+
+ var fn = function fn() {
+ request.post(Endpoints.CHANNELS + "/" + channel + "/typing").set("authorization", self.token).end();
+ };
+
+ fn();
+
+ var interval = setInterval(fn, 3000);
+
+ self.typingIntervals[channel] = interval;
+
+ if (stopTypeTime) {
+ setTimeout(function () {
+ self.stopTyping(channel);
+ }, stopTypeTime);
+ }
+ }
+ }
+ }, {
+ key: "stopTyping",
+ value: function stopTyping(chann) {
+ var self = this;
+
+ this.resolveDestination(chann).then(next);
+
+ function next(channel) {
+ if (!self.typingIntervals[channel]) {
+ return;
+ }
+
+ clearInterval(self.typingIntervals[channel]);
+
+ delete self.typingIntervals[channel];
+ }
+ }
+ }, {
+ key: "setStatus",
+ value: function setStatus(stat) {
+
+ var idleTime = stat === "online" ? null : Date.now();
+
+ this.__idleTime = idleTime;
+
+ this.websocket.send(JSON.stringify({
+ op: 3,
+ d: {
+ idle_since: this.__idleTime,
+ game_id: this.__gameId
+ }
+ }));
+ }
+ }, {
+ key: "setPlayingGame",
+ value: function setPlayingGame(id) {
+
+ if (id instanceof String || typeof id === "string") {
+
+ // working on names
+ var gid = id.trim().toUpperCase();
+
+ id = null;
+
+ var _iteratorNormalCompletion16 = true;
+ var _didIteratorError16 = false;
+ var _iteratorError16 = undefined;
+
+ try {
+ for (var _iterator16 = gameMap[Symbol.iterator](), _step16; !(_iteratorNormalCompletion16 = (_step16 = _iterator16.next()).done); _iteratorNormalCompletion16 = true) {
+ var game = _step16.value;
+
+ if (game.name.trim().toUpperCase() === gid) {
+
+ id = game.id;
+ break;
+ }
+ }
+ } catch (err) {
+ _didIteratorError16 = true;
+ _iteratorError16 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion16 && _iterator16["return"]) {
+ _iterator16["return"]();
+ }
+ } finally {
+ if (_didIteratorError16) {
+ throw _iteratorError16;
+ }
+ }
+ }
+ }
+
+ this.__gameId = id;
+
+ this.websocket.send(JSON.stringify({
+ op: 3,
+ d: {
+ idle_since: this.__idleTime,
+ game_id: this.__gameId
+ }
+ }));
+ }
+ }, {
+ key: "playGame",
+ value: function playGame(id) {
+ this.setPlayingGame(id);
+ }
+ }, {
+ key: "playingGame",
+ value: function playingGame(id) {
+
+ this.setPlayingGame(id);
+ }
+ }, {
+ key: "uptime",
+ get: function get() {
+
+ return this.readyTime ? Date.now() - this.readyTime : null;
+ }
+ }, {
+ key: "ready",
+ get: function get() {
+ return this.state === 3;
+ }
+ }, {
+ key: "servers",
+ get: function get() {
+ return this.serverCache;
+ }
+ }, {
+ key: "channels",
+ get: function get() {
+ return this.channelCache;
+ }
+ }, {
+ key: "users",
+ get: function get() {
+ return this.userCache;
+ }
+ }, {
+ key: "PMChannels",
+ get: function get() {
+ return this.pmChannelCache;
+ }
+ }, {
+ key: "messages",
+ get: function get() {
+
+ var msgs = [];
+ var _iteratorNormalCompletion17 = true;
+ var _didIteratorError17 = false;
+ var _iteratorError17 = undefined;
+
+ try {
+ for (var _iterator17 = this.channelCache[Symbol.iterator](), _step17; !(_iteratorNormalCompletion17 = (_step17 = _iterator17.next()).done); _iteratorNormalCompletion17 = true) {
+ var channel = _step17.value;
+
+ msgs = msgs.concat(channel.messages);
+ }
+ } catch (err) {
+ _didIteratorError17 = true;
+ _iteratorError17 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion17 && _iterator17["return"]) {
+ _iterator17["return"]();
+ }
+ } finally {
+ if (_didIteratorError17) {
+ throw _iteratorError17;
+ }
+ }
+ }
+
+ return msgs;
+ }
+ }]);
+
+ return Client;
+})();
+
+module.exports = Client;
+
+},{"../ref/gameMap.json":15,"./Endpoints.js":2,"./PMChannel.js":3,"./channel.js":4,"./invite.js":6,"./message.js":7,"./server.js":8,"./user.js":9,"fs":10,"superagent":11,"ws":14}],2:[function(require,module,exports){
+"use strict";
+
+exports.BASE_DOMAIN = "discordapp.com";
+exports.BASE = "https://" + exports.BASE_DOMAIN;
+exports.WEBSOCKET_HUB = "wss://" + exports.BASE_DOMAIN + "/hub";
+
+exports.API = exports.BASE + "/api";
+exports.AUTH = exports.API + "/auth";
+exports.LOGIN = exports.AUTH + "/login";
+exports.LOGOUT = exports.AUTH + "/logout";
+exports.USERS = exports.API + "/users";
+exports.SERVERS = exports.API + "/guilds";
+exports.CHANNELS = exports.API + "/channels";
+
+},{}],3:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var PMChannel = (function () {
+ function PMChannel(data, client) {
+ _classCallCheck(this, PMChannel);
+
+ this.user = client.getUser("id", data.recipient.id);
+ this.id = data.id;
+ this.messages = [];
+ }
+
+ _createClass(PMChannel, [{
+ key: "addMessage",
+ value: function addMessage(data) {
+ if (!this.getMessage("id", data.id)) {
+ this.messages.push(data);
+ }
+ return this.getMessage("id", data.id);
+ }
+ }, {
+ key: "getMessage",
+ value: function getMessage(key, value) {
+
+ if (this.messages.length > 1000) {
+ this.messages.splice(0, 1);
+ }
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.messages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var message = _step.value;
+
+ if (message[key] === value) {
+ return message;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return true;
+ }
+ }]);
+
+ return PMChannel;
+})();
+
+module.exports = PMChannel;
+
+},{}],4:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Channel = (function () {
+ function Channel(data, server) {
+ _classCallCheck(this, Channel);
+
+ this.server = server;
+ this.name = data.name;
+ this.type = data.type;
+ this.topic = data.topic;
+ this.id = data.id;
+ this.messages = [];
+ //this.isPrivate = isPrivate; //not sure about the implementation of this...
+ }
+
+ _createClass(Channel, [{
+ key: "equals",
+ value: function equals(object) {
+ return object && object.id === this.id;
+ }
+ }, {
+ key: "addMessage",
+ value: function addMessage(data) {
+
+ if (this.messages.length > 1000) {
+ this.messages.splice(0, 1);
+ }
+
+ if (!this.getMessage("id", data.id)) {
+ this.messages.push(data);
+ }
+
+ return this.getMessage("id", data.id);
+ }
+ }, {
+ key: "getMessage",
+ value: function getMessage(key, value) {
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.messages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var message = _step.value;
+
+ if (message[key] === value) {
+ return message;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ return "<#" + this.id + ">";
+ }
+ }, {
+ key: "client",
+ get: function get() {
+ return this.server.client;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return false;
+ }
+ }, {
+ key: "users",
+ get: function get() {
+ return this.server.members;
+ }
+ }, {
+ key: "members",
+ get: function get() {
+ return this.server.members;
+ }
+ }]);
+
+ return Channel;
+})();
+
+module.exports = Channel;
+
+},{}],5:[function(require,module,exports){
+"use strict";
+
+var request = require("superagent");
+var Endpoints = require("./Endpoints.js");
+var Client = require("./Client.js");
+
+var Discord = {
+ Endpoints: Endpoints,
+ Client: Client
+};
+
+module.exports = Discord;
+
+},{"./Client.js":1,"./Endpoints.js":2,"superagent":11}],6:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Invite = (function () {
+ function Invite(data, client) {
+ _classCallCheck(this, Invite);
+
+ this.max_age = data.max_age;
+ this.code = data.code;
+ this.server = client.getServer("id", data.guild.id);
+ this.revoked = data.revoked;
+ this.created_at = Date.parse(data.created_at);
+ this.temporary = data.temporary;
+ this.uses = data.uses;
+ this.max_uses = data.uses;
+ this.inviter = client.addUser(data.inviter);
+ this.xkcd = data.xkcdpass;
+ this.channel = client.getChannel("id", data.channel.id);
+ }
+
+ _createClass(Invite, [{
+ key: "URL",
+ get: function get() {
+ var code = this.xkcd ? this.xkcdpass : this.code;
+ return "https://discord.gg/" + code;
+ }
+ }]);
+
+ return Invite;
+})();
+
+module.exports = Invite;
+
+},{}],7:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var PMChannel = require("./PMChannel.js");
+
+var Message = (function () {
+ function Message(data, channel, mentions, author) {
+ _classCallCheck(this, Message);
+
+ this.tts = data.tts;
+ this.timestamp = Date.parse(data.timestamp);
+ this.nonce = data.nonce;
+ this.mentions = mentions;
+ this.everyoneMentioned = data.mention_everyone;
+ this.id = data.id;
+ this.embeds = data.embeds;
+ this.editedTimestamp = data.edited_timestamp;
+ this.content = data.content.trim();
+ this.channel = channel;
+ this.author = author;
+ this.attachments = data.attachments;
+ }
+
+ /*exports.Message.prototype.isPM = function() {
+ return ( this.channel instanceof PMChannel );
+ }*/
+
+ _createClass(Message, [{
+ key: "isMentioned",
+ value: function isMentioned(user) {
+ var id = user.id ? user.id : user;
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = this.mentions[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var mention = _step.value;
+
+ if (mention.id === id) {
+ return true;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return false;
+ }
+ }, {
+ key: "sender",
+ get: function get() {
+ return this.author;
+ }
+ }, {
+ key: "isPrivate",
+ get: function get() {
+ return this.channel.isPrivate;
+ }
+ }]);
+
+ return Message;
+})();
+
+module.exports = Message;
+
+},{"./PMChannel.js":3}],8:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Server = (function () {
+ function Server(data, client) {
+ _classCallCheck(this, Server);
+
+ this.client = client;
+ this.region = data.region;
+ this.ownerID = data.owner_id;
+ this.name = data.name;
+ this.id = data.id;
+ this.members = [];
+ this.channels = [];
+ this.icon = data.icon;
+ this.afkTimeout = data.afk_timeout;
+ this.afkChannelId = data.afk_channel_id;
+
+ if (!data.members) {
+ data.members = [client.user];
+ return;
+ }
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = data.members[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var member = _step.value;
+
+ // first we cache the user in our Discord Client,
+ // then we add it to our list. This way when we
+ // get a user from this server's member list,
+ // it will be identical (unless an async change occurred)
+ // to the client's cache.
+ if (member.user) this.members.push(client.addUser(member.user));
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator["return"]) {
+ _iterator["return"]();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+ }
+
+ _createClass(Server, [{
+ key: "getChannel",
+
+ // get/set
+ value: function getChannel(key, value) {
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = this.channels[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var channel = _step2.value;
+
+ if (channel[key] === value) {
+ return channel;
+ }
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2["return"]) {
+ _iterator2["return"]();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "getMember",
+ value: function getMember(key, value) {
+ var _iteratorNormalCompletion3 = true;
+ var _didIteratorError3 = false;
+ var _iteratorError3 = undefined;
+
+ try {
+ for (var _iterator3 = this.members[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var member = _step3.value;
+
+ if (member[key] === value) {
+ return member;
+ }
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3["return"]) {
+ _iterator3["return"]();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ return null;
+ }
+ }, {
+ key: "addChannel",
+ value: function addChannel(chann) {
+ if (!this.getChannel("id", chann.id)) {
+ this.channels.push(chann);
+ }
+ return chann;
+ }
+ }, {
+ key: "addMember",
+ value: function addMember(member) {
+ if (!this.getMember("id", member.id)) {
+ this.members.push(member);
+ }
+ return member;
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ return this.name;
+ }
+ }, {
+ key: "equals",
+ value: function equals(object) {
+ return object.id === this.id;
+ }
+ }, {
+ key: "iconURL",
+ get: function get() {
+ if (!this.icon) return null;
+ return "https://discordapp.com/api/guilds/" + this.id + "/icons/" + this.icon + ".jpg";
+ }
+ }, {
+ key: "afkChannel",
+ get: function get() {
+ if (!this.afkChannelId) return false;
+
+ return this.getChannel("id", this.afkChannelId);
+ }
+ }, {
+ key: "defaultChannel",
+ get: function get() {
+ return this.getChannel("name", "general");
+ }
+ }, {
+ key: "owner",
+ get: function get() {
+ return this.client.getUser("id", this.ownerID);
+ }
+ }, {
+ key: "users",
+ get: function get() {
+ return this.members;
+ }
+ }]);
+
+ return Server;
+})();
+
+module.exports = Server;
+
+},{}],9:[function(require,module,exports){
+"use strict";
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var User = (function () {
+ function User(data) {
+ _classCallCheck(this, User);
+
+ this.username = data.username;
+ this.discriminator = data.discriminator;
+ this.id = data.id;
+ this.avatar = data.avatar;
+ this.status = "offline";
+ }
+
+ // access using user.avatarURL;
+
+ _createClass(User, [{
+ key: "mention",
+ value: function mention() {
+ return "<@" + this.id + ">";
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ /*
+ if we embed a user in a String - like so:
+ "Yo " + user + " what's up?"
+ It would generate something along the lines of:
+ "Yo @hydrabolt what's up?"
+ */
+ return this.mention();
+ }
+ }, {
+ key: "equals",
+ value: function equals(object) {
+ return object.id === this.id;
+ }
+ }, {
+ key: "equalsStrict",
+ value: function equalsStrict(object) {
+ return object.id === this.id && object.avatar === this.avatar && object.username === this.username && object.discriminator === this.discriminator;
+ }
+ }, {
+ key: "avatarURL",
+ get: function get() {
+ if (!this.avatar) return null;
+ return "https://discordapp.com/api/users/" + this.id + "/avatars/" + this.avatar + ".jpg";
+ }
+ }]);
+
+ return User;
+})();
+
+module.exports = User;
+
+},{}],10:[function(require,module,exports){
+
+},{}],11:[function(require,module,exports){
+/**
+ * Module dependencies.
+ */
+
+var Emitter = require('emitter');
+var reduce = require('reduce');
+
+/**
+ * Root reference for iframes.
+ */
+
+var root = 'undefined' == typeof window
+ ? (this || self)
+ : window;
+
+/**
+ * Noop.
+ */
+
+function noop(){};
+
+/**
+ * Check if `obj` is a host object,
+ * we don't want to serialize these :)
+ *
+ * TODO: future proof, move to compoent land
+ *
+ * @param {Object} obj
+ * @return {Boolean}
+ * @api private
+ */
+
+function isHost(obj) {
+ var str = {}.toString.call(obj);
+
+ switch (str) {
+ case '[object File]':
+ case '[object Blob]':
+ case '[object FormData]':
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Determine XHR.
+ */
+
+request.getXHR = function () {
+ if (root.XMLHttpRequest
+ && (!root.location || 'file:' != root.location.protocol
+ || !root.ActiveXObject)) {
+ return new XMLHttpRequest;
+ } else {
+ try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {}
+ }
+ return false;
+};
+
+/**
+ * Removes leading and trailing whitespace, added to support IE.
+ *
+ * @param {String} s
+ * @return {String}
+ * @api private
+ */
+
+var trim = ''.trim
+ ? function(s) { return s.trim(); }
+ : function(s) { return s.replace(/(^\s*|\s*$)/g, ''); };
+
+/**
+ * Check if `obj` is an object.
+ *
+ * @param {Object} obj
+ * @return {Boolean}
+ * @api private
+ */
+
+function isObject(obj) {
+ return obj === Object(obj);
+}
+
+/**
+ * Serialize the given `obj`.
+ *
+ * @param {Object} obj
+ * @return {String}
+ * @api private
+ */
+
+function serialize(obj) {
+ if (!isObject(obj)) return obj;
+ var pairs = [];
+ for (var key in obj) {
+ if (null != obj[key]) {
+ pairs.push(encodeURIComponent(key)
+ + '=' + encodeURIComponent(obj[key]));
+ }
+ }
+ return pairs.join('&');
+}
+
+/**
+ * Expose serialization method.
+ */
+
+ request.serializeObject = serialize;
+
+ /**
+ * Parse the given x-www-form-urlencoded `str`.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+function parseString(str) {
+ var obj = {};
+ var pairs = str.split('&');
+ var parts;
+ var pair;
+
+ for (var i = 0, len = pairs.length; i < len; ++i) {
+ pair = pairs[i];
+ parts = pair.split('=');
+ obj[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
+ }
+
+ return obj;
+}
+
+/**
+ * Expose parser.
+ */
+
+request.parseString = parseString;
+
+/**
+ * Default MIME type map.
+ *
+ * superagent.types.xml = 'application/xml';
+ *
+ */
+
+request.types = {
+ html: 'text/html',
+ json: 'application/json',
+ xml: 'application/xml',
+ urlencoded: 'application/x-www-form-urlencoded',
+ 'form': 'application/x-www-form-urlencoded',
+ 'form-data': 'application/x-www-form-urlencoded'
+};
+
+/**
+ * Default serialization map.
+ *
+ * superagent.serialize['application/xml'] = function(obj){
+ * return 'generated xml here';
+ * };
+ *
+ */
+
+ request.serialize = {
+ 'application/x-www-form-urlencoded': serialize,
+ 'application/json': JSON.stringify
+ };
+
+ /**
+ * Default parsers.
+ *
+ * superagent.parse['application/xml'] = function(str){
+ * return { object parsed from str };
+ * };
+ *
+ */
+
+request.parse = {
+ 'application/x-www-form-urlencoded': parseString,
+ 'application/json': JSON.parse
+};
+
+/**
+ * Parse the given header `str` into
+ * an object containing the mapped fields.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+function parseHeader(str) {
+ var lines = str.split(/\r?\n/);
+ var fields = {};
+ var index;
+ var line;
+ var field;
+ var val;
+
+ lines.pop(); // trailing CRLF
+
+ for (var i = 0, len = lines.length; i < len; ++i) {
+ line = lines[i];
+ index = line.indexOf(':');
+ field = line.slice(0, index).toLowerCase();
+ val = trim(line.slice(index + 1));
+ fields[field] = val;
+ }
+
+ return fields;
+}
+
+/**
+ * Return the mime type for the given `str`.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+function type(str){
+ return str.split(/ *; */).shift();
+};
+
+/**
+ * Return header field parameters.
+ *
+ * @param {String} str
+ * @return {Object}
+ * @api private
+ */
+
+function params(str){
+ return reduce(str.split(/ *; */), function(obj, str){
+ var parts = str.split(/ *= */)
+ , key = parts.shift()
+ , val = parts.shift();
+
+ if (key && val) obj[key] = val;
+ return obj;
+ }, {});
+};
+
+/**
+ * Initialize a new `Response` with the given `xhr`.
+ *
+ * - set flags (.ok, .error, etc)
+ * - parse header
+ *
+ * Examples:
+ *
+ * Aliasing `superagent` as `request` is nice:
+ *
+ * request = superagent;
+ *
+ * We can use the promise-like API, or pass callbacks:
+ *
+ * request.get('/').end(function(res){});
+ * request.get('/', function(res){});
+ *
+ * Sending data can be chained:
+ *
+ * request
+ * .post('/user')
+ * .send({ name: 'tj' })
+ * .end(function(res){});
+ *
+ * Or passed to `.send()`:
+ *
+ * request
+ * .post('/user')
+ * .send({ name: 'tj' }, function(res){});
+ *
+ * Or passed to `.post()`:
+ *
+ * request
+ * .post('/user', { name: 'tj' })
+ * .end(function(res){});
+ *
+ * Or further reduced to a single call for simple cases:
+ *
+ * request
+ * .post('/user', { name: 'tj' }, function(res){});
+ *
+ * @param {XMLHTTPRequest} xhr
+ * @param {Object} options
+ * @api private
+ */
+
+function Response(req, options) {
+ options = options || {};
+ this.req = req;
+ this.xhr = this.req.xhr;
+ // responseText is accessible only if responseType is '' or 'text' and on older browsers
+ this.text = ((this.req.method !='HEAD' && (this.xhr.responseType === '' || this.xhr.responseType === 'text')) || typeof this.xhr.responseType === 'undefined')
+ ? this.xhr.responseText
+ : null;
+ this.statusText = this.req.xhr.statusText;
+ this.setStatusProperties(this.xhr.status);
+ this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders());
+ // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but
+ // getResponseHeader still works. so we get content-type even if getting
+ // other headers fails.
+ this.header['content-type'] = this.xhr.getResponseHeader('content-type');
+ this.setHeaderProperties(this.header);
+ this.body = this.req.method != 'HEAD'
+ ? this.parseBody(this.text ? this.text : this.xhr.response)
+ : null;
+}
+
+/**
+ * Get case-insensitive `field` value.
+ *
+ * @param {String} field
+ * @return {String}
+ * @api public
+ */
+
+Response.prototype.get = function(field){
+ return this.header[field.toLowerCase()];
+};
+
+/**
+ * Set header related properties:
+ *
+ * - `.type` the content type without params
+ *
+ * A response of "Content-Type: text/plain; charset=utf-8"
+ * will provide you with a `.type` of "text/plain".
+ *
+ * @param {Object} header
+ * @api private
+ */
+
+Response.prototype.setHeaderProperties = function(header){
+ // content-type
+ var ct = this.header['content-type'] || '';
+ this.type = type(ct);
+
+ // params
+ var obj = params(ct);
+ for (var key in obj) this[key] = obj[key];
+};
+
+/**
+ * Parse the given body `str`.
+ *
+ * Used for auto-parsing of bodies. Parsers
+ * are defined on the `superagent.parse` object.
+ *
+ * @param {String} str
+ * @return {Mixed}
+ * @api private
+ */
+
+Response.prototype.parseBody = function(str){
+ var parse = request.parse[this.type];
+ return parse && str && (str.length || str instanceof Object)
+ ? parse(str)
+ : null;
+};
+
+/**
+ * Set flags such as `.ok` based on `status`.
+ *
+ * For example a 2xx response will give you a `.ok` of __true__
+ * whereas 5xx will be __false__ and `.error` will be __true__. The
+ * `.clientError` and `.serverError` are also available to be more
+ * specific, and `.statusType` is the class of error ranging from 1..5
+ * sometimes useful for mapping respond colors etc.
+ *
+ * "sugar" properties are also defined for common cases. Currently providing:
+ *
+ * - .noContent
+ * - .badRequest
+ * - .unauthorized
+ * - .notAcceptable
+ * - .notFound
+ *
+ * @param {Number} status
+ * @api private
+ */
+
+Response.prototype.setStatusProperties = function(status){
+ // handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request
+ if (status === 1223) {
+ status = 204;
+ }
+
+ var type = status / 100 | 0;
+
+ // status / class
+ this.status = status;
+ this.statusType = type;
+
+ // basics
+ this.info = 1 == type;
+ this.ok = 2 == type;
+ this.clientError = 4 == type;
+ this.serverError = 5 == type;
+ this.error = (4 == type || 5 == type)
+ ? this.toError()
+ : false;
+
+ // sugar
+ this.accepted = 202 == status;
+ this.noContent = 204 == status;
+ this.badRequest = 400 == status;
+ this.unauthorized = 401 == status;
+ this.notAcceptable = 406 == status;
+ this.notFound = 404 == status;
+ this.forbidden = 403 == status;
+};
+
+/**
+ * Return an `Error` representative of this response.
+ *
+ * @return {Error}
+ * @api public
+ */
+
+Response.prototype.toError = function(){
+ var req = this.req;
+ var method = req.method;
+ var url = req.url;
+
+ var msg = 'cannot ' + method + ' ' + url + ' (' + this.status + ')';
+ var err = new Error(msg);
+ err.status = this.status;
+ err.method = method;
+ err.url = url;
+
+ return err;
+};
+
+/**
+ * Expose `Response`.
+ */
+
+request.Response = Response;
+
+/**
+ * Initialize a new `Request` with the given `method` and `url`.
+ *
+ * @param {String} method
+ * @param {String} url
+ * @api public
+ */
+
+function Request(method, url) {
+ var self = this;
+ Emitter.call(this);
+ this._query = this._query || [];
+ this.method = method;
+ this.url = url;
+ this.header = {};
+ this._header = {};
+ this.on('end', function(){
+ var err = null;
+ var res = null;
+
+ try {
+ res = new Response(self);
+ } catch(e) {
+ err = new Error('Parser is unable to parse the response');
+ err.parse = true;
+ err.original = e;
+ return self.callback(err);
+ }
+
+ self.emit('response', res);
+
+ if (err) {
+ return self.callback(err, res);
+ }
+
+ if (res.status >= 200 && res.status < 300) {
+ return self.callback(err, res);
+ }
+
+ var new_err = new Error(res.statusText || 'Unsuccessful HTTP response');
+ new_err.original = err;
+ new_err.response = res;
+ new_err.status = res.status;
+
+ self.callback(new_err, res);
+ });
+}
+
+/**
+ * Mixin `Emitter`.
+ */
+
+Emitter(Request.prototype);
+
+/**
+ * Allow for extension
+ */
+
+Request.prototype.use = function(fn) {
+ fn(this);
+ return this;
+}
+
+/**
+ * Set timeout to `ms`.
+ *
+ * @param {Number} ms
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.timeout = function(ms){
+ this._timeout = ms;
+ return this;
+};
+
+/**
+ * Clear previous timeout.
+ *
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.clearTimeout = function(){
+ this._timeout = 0;
+ clearTimeout(this._timer);
+ return this;
+};
+
+/**
+ * Abort the request, and clear potential timeout.
+ *
+ * @return {Request}
+ * @api public
+ */
+
+Request.prototype.abort = function(){
+ if (this.aborted) return;
+ this.aborted = true;
+ this.xhr.abort();
+ this.clearTimeout();
+ this.emit('abort');
+ return this;
+};
+
+/**
+ * Set header `field` to `val`, or multiple fields with one object.
+ *
+ * Examples:
+ *
+ * req.get('/')
+ * .set('Accept', 'application/json')
+ * .set('X-API-Key', 'foobar')
+ * .end(callback);
+ *
+ * req.get('/')
+ * .set({ Accept: 'application/json', 'X-API-Key': 'foobar' })
+ * .end(callback);
+ *
+ * @param {String|Object} field
+ * @param {String} val
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.set = function(field, val){
+ if (isObject(field)) {
+ for (var key in field) {
+ this.set(key, field[key]);
+ }
+ return this;
+ }
+ this._header[field.toLowerCase()] = val;
+ this.header[field] = val;
+ return this;
+};
+
+/**
+ * Remove header `field`.
+ *
+ * Example:
+ *
+ * req.get('/')
+ * .unset('User-Agent')
+ * .end(callback);
+ *
+ * @param {String} field
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.unset = function(field){
+ delete this._header[field.toLowerCase()];
+ delete this.header[field];
+ return this;
+};
+
+/**
+ * Get case-insensitive header `field` value.
+ *
+ * @param {String} field
+ * @return {String}
+ * @api private
+ */
+
+Request.prototype.getHeader = function(field){
+ return this._header[field.toLowerCase()];
+};
+
+/**
+ * Set Content-Type to `type`, mapping values from `request.types`.
+ *
+ * Examples:
+ *
+ * superagent.types.xml = 'application/xml';
+ *
+ * request.post('/')
+ * .type('xml')
+ * .send(xmlstring)
+ * .end(callback);
+ *
+ * request.post('/')
+ * .type('application/xml')
+ * .send(xmlstring)
+ * .end(callback);
+ *
+ * @param {String} type
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.type = function(type){
+ this.set('Content-Type', request.types[type] || type);
+ return this;
+};
+
+/**
+ * Set Accept to `type`, mapping values from `request.types`.
+ *
+ * Examples:
+ *
+ * superagent.types.json = 'application/json';
+ *
+ * request.get('/agent')
+ * .accept('json')
+ * .end(callback);
+ *
+ * request.get('/agent')
+ * .accept('application/json')
+ * .end(callback);
+ *
+ * @param {String} accept
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.accept = function(type){
+ this.set('Accept', request.types[type] || type);
+ return this;
+};
+
+/**
+ * Set Authorization field value with `user` and `pass`.
+ *
+ * @param {String} user
+ * @param {String} pass
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.auth = function(user, pass){
+ var str = btoa(user + ':' + pass);
+ this.set('Authorization', 'Basic ' + str);
+ return this;
+};
+
+/**
+* Add query-string `val`.
+*
+* Examples:
+*
+* request.get('/shoes')
+* .query('size=10')
+* .query({ color: 'blue' })
+*
+* @param {Object|String} val
+* @return {Request} for chaining
+* @api public
+*/
+
+Request.prototype.query = function(val){
+ if ('string' != typeof val) val = serialize(val);
+ if (val) this._query.push(val);
+ return this;
+};
+
+/**
+ * Write the field `name` and `val` for "multipart/form-data"
+ * request bodies.
+ *
+ * ``` js
+ * request.post('/upload')
+ * .field('foo', 'bar')
+ * .end(callback);
+ * ```
+ *
+ * @param {String} name
+ * @param {String|Blob|File} val
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.field = function(name, val){
+ if (!this._formData) this._formData = new root.FormData();
+ this._formData.append(name, val);
+ return this;
+};
+
+/**
+ * Queue the given `file` as an attachment to the specified `field`,
+ * with optional `filename`.
+ *
+ * ``` js
+ * request.post('/upload')
+ * .attach(new Blob(['hey! '], { type: "text/html"}))
+ * .end(callback);
+ * ```
+ *
+ * @param {String} field
+ * @param {Blob|File} file
+ * @param {String} filename
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.attach = function(field, file, filename){
+ if (!this._formData) this._formData = new root.FormData();
+ this._formData.append(field, file, filename);
+ return this;
+};
+
+/**
+ * Send `data`, defaulting the `.type()` to "json" when
+ * an object is given.
+ *
+ * Examples:
+ *
+ * // querystring
+ * request.get('/search')
+ * .end(callback)
+ *
+ * // multiple data "writes"
+ * request.get('/search')
+ * .send({ search: 'query' })
+ * .send({ range: '1..5' })
+ * .send({ order: 'desc' })
+ * .end(callback)
+ *
+ * // manual json
+ * request.post('/user')
+ * .type('json')
+ * .send('{"name":"tj"})
+ * .end(callback)
+ *
+ * // auto json
+ * request.post('/user')
+ * .send({ name: 'tj' })
+ * .end(callback)
+ *
+ * // manual x-www-form-urlencoded
+ * request.post('/user')
+ * .type('form')
+ * .send('name=tj')
+ * .end(callback)
+ *
+ * // auto x-www-form-urlencoded
+ * request.post('/user')
+ * .type('form')
+ * .send({ name: 'tj' })
+ * .end(callback)
+ *
+ * // defaults to x-www-form-urlencoded
+ * request.post('/user')
+ * .send('name=tobi')
+ * .send('species=ferret')
+ * .end(callback)
+ *
+ * @param {String|Object} data
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.send = function(data){
+ var obj = isObject(data);
+ var type = this.getHeader('Content-Type');
+
+ // merge
+ if (obj && isObject(this._data)) {
+ for (var key in data) {
+ this._data[key] = data[key];
+ }
+ } else if ('string' == typeof data) {
+ if (!type) this.type('form');
+ type = this.getHeader('Content-Type');
+ if ('application/x-www-form-urlencoded' == type) {
+ this._data = this._data
+ ? this._data + '&' + data
+ : data;
+ } else {
+ this._data = (this._data || '') + data;
+ }
+ } else {
+ this._data = data;
+ }
+
+ if (!obj || isHost(data)) return this;
+ if (!type) this.type('json');
+ return this;
+};
+
+/**
+ * Invoke the callback with `err` and `res`
+ * and handle arity check.
+ *
+ * @param {Error} err
+ * @param {Response} res
+ * @api private
+ */
+
+Request.prototype.callback = function(err, res){
+ var fn = this._callback;
+ this.clearTimeout();
+ fn(err, res);
+};
+
+/**
+ * Invoke callback with x-domain error.
+ *
+ * @api private
+ */
+
+Request.prototype.crossDomainError = function(){
+ var err = new Error('Origin is not allowed by Access-Control-Allow-Origin');
+ err.crossDomain = true;
+ this.callback(err);
+};
+
+/**
+ * Invoke callback with timeout error.
+ *
+ * @api private
+ */
+
+Request.prototype.timeoutError = function(){
+ var timeout = this._timeout;
+ var err = new Error('timeout of ' + timeout + 'ms exceeded');
+ err.timeout = timeout;
+ this.callback(err);
+};
+
+/**
+ * Enable transmission of cookies with x-domain requests.
+ *
+ * Note that for this to work the origin must not be
+ * using "Access-Control-Allow-Origin" with a wildcard,
+ * and also must set "Access-Control-Allow-Credentials"
+ * to "true".
+ *
+ * @api public
+ */
+
+Request.prototype.withCredentials = function(){
+ this._withCredentials = true;
+ return this;
+};
+
+/**
+ * Initiate request, invoking callback `fn(res)`
+ * with an instanceof `Response`.
+ *
+ * @param {Function} fn
+ * @return {Request} for chaining
+ * @api public
+ */
+
+Request.prototype.end = function(fn){
+ var self = this;
+ var xhr = this.xhr = request.getXHR();
+ var query = this._query.join('&');
+ var timeout = this._timeout;
+ var data = this._formData || this._data;
+
+ // store callback
+ this._callback = fn || noop;
+
+ // state change
+ xhr.onreadystatechange = function(){
+ if (4 != xhr.readyState) return;
+
+ // In IE9, reads to any property (e.g. status) off of an aborted XHR will
+ // result in the error "Could not complete the operation due to error c00c023f"
+ var status;
+ try { status = xhr.status } catch(e) { status = 0; }
+
+ if (0 == status) {
+ if (self.timedout) return self.timeoutError();
+ if (self.aborted) return;
+ return self.crossDomainError();
+ }
+ self.emit('end');
+ };
+
+ // progress
+ var handleProgress = function(e){
+ if (e.total > 0) {
+ e.percent = e.loaded / e.total * 100;
+ }
+ self.emit('progress', e);
+ };
+ if (this.hasListeners('progress')) {
+ xhr.onprogress = handleProgress;
+ }
+ try {
+ if (xhr.upload && this.hasListeners('progress')) {
+ xhr.upload.onprogress = handleProgress;
+ }
+ } catch(e) {
+ // Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist.
+ // Reported here:
+ // https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web-worker-context
+ }
+
+ // timeout
+ if (timeout && !this._timer) {
+ this._timer = setTimeout(function(){
+ self.timedout = true;
+ self.abort();
+ }, timeout);
+ }
+
+ // querystring
+ if (query) {
+ query = request.serializeObject(query);
+ this.url += ~this.url.indexOf('?')
+ ? '&' + query
+ : '?' + query;
+ }
+
+ // initiate request
+ xhr.open(this.method, this.url, true);
+
+ // CORS
+ if (this._withCredentials) xhr.withCredentials = true;
+
+ // body
+ if ('GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !isHost(data)) {
+ // serialize stuff
+ var contentType = this.getHeader('Content-Type');
+ var serialize = request.serialize[contentType ? contentType.split(';')[0] : ''];
+ if (serialize) data = serialize(data);
+ }
+
+ // set header fields
+ for (var field in this.header) {
+ if (null == this.header[field]) continue;
+ xhr.setRequestHeader(field, this.header[field]);
+ }
+
+ // send stuff
+ this.emit('request', this);
+ xhr.send(data);
+ return this;
+};
+
+/**
+ * Faux promise support
+ *
+ * @param {Function} fulfill
+ * @param {Function} reject
+ * @return {Request}
+ */
+
+Request.prototype.then = function (fulfill, reject) {
+ return this.end(function(err, res) {
+ err ? reject(err) : fulfill(res);
+ });
+}
+
+/**
+ * Expose `Request`.
+ */
+
+request.Request = Request;
+
+/**
+ * Issue a request:
+ *
+ * Examples:
+ *
+ * request('GET', '/users').end(callback)
+ * request('/users').end(callback)
+ * request('/users', callback)
+ *
+ * @param {String} method
+ * @param {String|Function} url or callback
+ * @return {Request}
+ * @api public
+ */
+
+function request(method, url) {
+ // callback
+ if ('function' == typeof url) {
+ return new Request('GET', method).end(url);
+ }
+
+ // url first
+ if (1 == arguments.length) {
+ return new Request('GET', method);
+ }
+
+ return new Request(method, url);
+}
+
+/**
+ * GET `url` with optional callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed|Function} data or fn
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.get = function(url, data, fn){
+ var req = request('GET', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.query(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * HEAD `url` with optional callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed|Function} data or fn
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.head = function(url, data, fn){
+ var req = request('HEAD', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * DELETE `url` with optional callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.del = function(url, fn){
+ var req = request('DELETE', url);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * PATCH `url` with optional `data` and callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed} data
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.patch = function(url, data, fn){
+ var req = request('PATCH', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * POST `url` with optional `data` and callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed} data
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.post = function(url, data, fn){
+ var req = request('POST', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * PUT `url` with optional `data` and callback `fn(res)`.
+ *
+ * @param {String} url
+ * @param {Mixed|Function} data or fn
+ * @param {Function} fn
+ * @return {Request}
+ * @api public
+ */
+
+request.put = function(url, data, fn){
+ var req = request('PUT', url);
+ if ('function' == typeof data) fn = data, data = null;
+ if (data) req.send(data);
+ if (fn) req.end(fn);
+ return req;
+};
+
+/**
+ * Expose `request`.
+ */
+
+module.exports = request;
+
+},{"emitter":12,"reduce":13}],12:[function(require,module,exports){
+
+/**
+ * Expose `Emitter`.
+ */
+
+module.exports = Emitter;
+
+/**
+ * Initialize a new `Emitter`.
+ *
+ * @api public
+ */
+
+function Emitter(obj) {
+ if (obj) return mixin(obj);
+};
+
+/**
+ * Mixin the emitter properties.
+ *
+ * @param {Object} obj
+ * @return {Object}
+ * @api private
+ */
+
+function mixin(obj) {
+ for (var key in Emitter.prototype) {
+ obj[key] = Emitter.prototype[key];
+ }
+ return obj;
+}
+
+/**
+ * Listen on the given `event` with `fn`.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ * @return {Emitter}
+ * @api public
+ */
+
+Emitter.prototype.on =
+Emitter.prototype.addEventListener = function(event, fn){
+ this._callbacks = this._callbacks || {};
+ (this._callbacks[event] = this._callbacks[event] || [])
+ .push(fn);
+ return this;
+};
+
+/**
+ * Adds an `event` listener that will be invoked a single
+ * time then automatically removed.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ * @return {Emitter}
+ * @api public
+ */
+
+Emitter.prototype.once = function(event, fn){
+ var self = this;
+ this._callbacks = this._callbacks || {};
+
+ function on() {
+ self.off(event, on);
+ fn.apply(this, arguments);
+ }
+
+ on.fn = fn;
+ this.on(event, on);
+ return this;
+};
+
+/**
+ * Remove the given callback for `event` or all
+ * registered callbacks.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ * @return {Emitter}
+ * @api public
+ */
+
+Emitter.prototype.off =
+Emitter.prototype.removeListener =
+Emitter.prototype.removeAllListeners =
+Emitter.prototype.removeEventListener = function(event, fn){
+ this._callbacks = this._callbacks || {};
+
+ // all
+ if (0 == arguments.length) {
+ this._callbacks = {};
+ return this;
+ }
+
+ // specific event
+ var callbacks = this._callbacks[event];
+ if (!callbacks) return this;
+
+ // remove all handlers
+ if (1 == arguments.length) {
+ delete this._callbacks[event];
+ return this;
+ }
+
+ // remove specific handler
+ var cb;
+ for (var i = 0; i < callbacks.length; i++) {
+ cb = callbacks[i];
+ if (cb === fn || cb.fn === fn) {
+ callbacks.splice(i, 1);
+ break;
+ }
+ }
+ return this;
+};
+
+/**
+ * Emit `event` with the given args.
+ *
+ * @param {String} event
+ * @param {Mixed} ...
+ * @return {Emitter}
+ */
+
+Emitter.prototype.emit = function(event){
+ this._callbacks = this._callbacks || {};
+ var args = [].slice.call(arguments, 1)
+ , callbacks = this._callbacks[event];
+
+ if (callbacks) {
+ callbacks = callbacks.slice(0);
+ for (var i = 0, len = callbacks.length; i < len; ++i) {
+ callbacks[i].apply(this, args);
+ }
+ }
+
+ return this;
+};
+
+/**
+ * Return array of callbacks for `event`.
+ *
+ * @param {String} event
+ * @return {Array}
+ * @api public
+ */
+
+Emitter.prototype.listeners = function(event){
+ this._callbacks = this._callbacks || {};
+ return this._callbacks[event] || [];
+};
+
+/**
+ * Check if this emitter has `event` handlers.
+ *
+ * @param {String} event
+ * @return {Boolean}
+ * @api public
+ */
+
+Emitter.prototype.hasListeners = function(event){
+ return !! this.listeners(event).length;
+};
+
+},{}],13:[function(require,module,exports){
+
+/**
+ * Reduce `arr` with `fn`.
+ *
+ * @param {Array} arr
+ * @param {Function} fn
+ * @param {Mixed} initial
+ *
+ * TODO: combatible error handling?
+ */
+
+module.exports = function(arr, fn, initial){
+ var idx = 0;
+ var len = arr.length;
+ var curr = arguments.length == 3
+ ? initial
+ : arr[idx++];
+
+ while (idx < len) {
+ curr = fn.call(null, curr, arr[idx], ++idx, arr);
+ }
+
+ return curr;
+};
+},{}],14:[function(require,module,exports){
+
+/**
+ * Module dependencies.
+ */
+
+var global = (function() { return this; })();
+
+/**
+ * WebSocket constructor.
+ */
+
+var WebSocket = global.WebSocket || global.MozWebSocket;
+
+/**
+ * Module exports.
+ */
+
+module.exports = WebSocket ? ws : null;
+
+/**
+ * WebSocket constructor.
+ *
+ * The third `opts` options object gets ignored in web browsers, since it's
+ * non-standard, and throws a TypeError if passed to the constructor.
+ * See: https://github.com/einaros/ws/issues/227
+ *
+ * @param {String} uri
+ * @param {Array} protocols (optional)
+ * @param {Object) opts (optional)
+ * @api public
+ */
+
+function ws(uri, protocols, opts) {
+ var instance;
+ if (protocols) {
+ instance = new WebSocket(uri, protocols);
+ } else {
+ instance = new WebSocket(uri);
+ }
+ return instance;
+}
+
+if (WebSocket) ws.prototype = WebSocket.prototype;
+
+},{}],15:[function(require,module,exports){
+module.exports=[{"executables":{"win32":["pol.exe"]},"id":0,"name":"FINAL FANTASY XI"},{"executables":{"win32":["ffxiv.exe","ffxiv_dx11.exe"]},"id":1,"name":"FINAL FANTASY XIV"},{"executables":{"win32":["Wow.exe","Wow-64.exe"]},"id":3,"name":"World of Warcraft"},{"executables":{"darwin":["LoLLauncher.app"],"win32":["LolClient.exe","League of Legends.exe"]},"id":4,"name":"League of Legends"},{"executables":{"darwin":["Diablo%20III.app"],"win32":["Diablo III.exe"]},"id":5,"name":"Diablo 3"},{"executables":{"darwin":["dota_osx.app"],"win32":["dota2.exe"]},"id":6,"name":"DOTA 2"},{"executables":{"darwin":["Heroes.app"],"win32":["Heroes of the Storm.exe","HeroesOfTheStorm_x64.exe","HeroesOfTheStorm.exe"]},"id":7,"name":"Heroes of the Storm"},{"executables":{"darwin":["Hearthstone.app"],"win32":["Hearthstone.exe"]},"id":8,"name":"Hearthstone"},{"executables":{"win32":["csgo.exe"]},"id":9,"name":"Counter-Strike: Global Offensive"},{"executables":{"win32":["WorldOfTanks.exe"]},"id":10,"name":"World of Tanks"},{"executables":{"darwin":["gw2.app"],"win32":["gw2.exe"]},"id":11,"name":"Guild Wars 2"},{"executables":{"win32":["dayz.exe"]},"id":12,"name":"Day Z"},{"executables":{"darwin":["starcraft%20ii.app"],"win32":["starcraft ii.exe","SC2_x64.exe","SC2.exe"]},"id":13,"name":"Starcraft II"},{"executables":{"win32":["diablo.exe"]},"id":14,"name":"Diablo"},{"executables":{"win32":["diablo ii.exe"]},"id":15,"name":"Diablo 2"},{"executables":{"win32":["left4dead.exe"]},"id":17,"name":"Left 4 Dead"},{"executables":{"darwin":["minecraft.app"],"win32":["minecraft.exe"]},"id":18,"name":"Minecraft"},{"executables":{"win32":["smite.exe"]},"id":19,"name":"Smite"},{"executables":{"win32":["bf4.exe"]},"id":20,"name":"Battlefield 4"},{"executables":{"win32":["AoK HD.exe","empires2.exe"]},"id":101,"name":"Age of Empire II"},{"executables":{"win32":["age3y.exe"]},"id":102,"name":"Age of Empire III"},{"executables":{"win32":["AlanWake.exe"]},"id":104,"name":"Alan Wake"},{"executables":{"win32":["alan_wakes_american_nightmare.exe"]},"id":105,"name":"Alan Wake's American Nightmare"},{"executables":{"win32":["AlienBreed2Assault.exe"]},"id":106,"name":"Alien Breed 2: Assault"},{"executables":{"win32":["Amnesia.exe"]},"id":107,"name":"Amnesia: The Dark Descent"},{"executables":{"win32":["UDK.exe"]},"id":108,"name":"Antichamber"},{"executables":{"win32":["ArcheAge.exe"]},"id":109,"name":"ArcheAge"},{"executables":{"win32":["arma3.exe"]},"id":110,"name":"Arma III"},{"executables":{"win32":["AC3SP.exe"]},"id":111,"name":"Assassin's Creed 3"},{"executables":{"win32":["Bastion.exe"]},"id":112,"name":"Bastion"},{"executables":{"win32":["BF2.exe"]},"id":113,"name":"Battlefield 2"},{"executables":{"win32":["bf3.exe"]},"id":114,"name":"Battlefield 3"},{"executables":{"win32":["Besiege.exe"]},"id":116,"name":"Besiege"},{"executables":{"win32":["Bioshock.exe"]},"id":117,"name":"Bioshock"},{"executables":{"win32":["Bioshock2.exe"]},"id":118,"name":"BioShock II"},{"executables":{"win32":["BioShockInfinite.exe"]},"id":119,"name":"BioShock Infinite"},{"executables":{"win32":["Borderlands2.exe"]},"id":122,"name":"Borderlands 2"},{"executables":{"win32":["braid.exe"]},"id":123,"name":"Braid"},{"executables":{"win32":["ShippingPC-StormGame.exe"]},"id":124,"name":"Bulletstorm"},{"executables":{},"id":125,"name":"Cabal 2"},{"executables":{"win32":["CabalMain.exe"]},"id":126,"name":"Cabal Online"},{"executables":{"win32":["iw4mp.exe","iw4sp.exe"]},"id":127,"name":"Call of Duty: Modern Warfare 2"},{"executables":{"win32":["t6sp.exe"]},"id":128,"name":"Call of Duty: Black Ops"},{"executables":{"win32":["iw5mp.exe"]},"id":129,"name":"Call of Duty: Modern Warfare 3"},{"executables":{"win32":["RelicCOH.exe"]},"id":132,"name":"Company of Heroes"},{"executables":{"win32":["Crysis64.exe"]},"id":135,"name":"Crysis"},{"executables":{"win32":["Crysis2.exe"]},"id":136,"name":"Crysis 2"},{"executables":{"win32":["Crysis3.exe"]},"id":137,"name":"Crysis 3"},{"executables":{"win32":["Crysis.exe"]},"id":138,"name":"Crysis 4 "},{"executables":{"win32":["DATA.exe"]},"id":140,"name":"Dark Souls"},{"executables":{"win32":["DarkSoulsII.exe"]},"id":141,"name":"Dark Souls II"},{"executables":{"win32":["dfuw.exe"]},"id":142,"name":"Darkfall: Unholy Wars"},{"executables":{"win32":["DCGAME.exe"]},"id":144,"name":"DC Universe Online"},{"executables":{"win32":["DeadIslandGame.exe"]},"id":145,"name":"Dead Island"},{"executables":{"win32":["deadspace2.exe"]},"id":146,"name":"Dead Space 2"},{"executables":{"win32":["LOTDGame.exe"]},"id":147,"name":"Deadlight"},{"executables":{"win32":["dxhr.exe"]},"id":148,"name":"Deus Ex: Human Revolution"},{"executables":{"win32":["DeviMayCry4.exe"]},"id":149,"name":"Devil May Cry 4"},{"executables":{"win32":["DMC-DevilMayCry.exe"]},"id":150,"name":"DmC Devil May Cry"},{"executables":{"win32":["dirt2_game.exe"]},"id":154,"name":"DiRT 2"},{"executables":{"win32":["dirt3_game.exe"]},"id":155,"name":"DiRT 3"},{"executables":{"win32":["dota.exe"]},"id":156,"name":"DOTA"},{"executables":{"win32":["DoubleDragon.exe"]},"id":158,"name":"Double Dragon Neon"},{"executables":{"win32":["DragonAge2.exe"]},"id":159,"name":"Dragon Age II"},{"executables":{"win32":["DragonAgeInquisition.exe"]},"id":160,"name":"Dragon Age: Inquisition"},{"executables":{"win32":["daorigins.exe"]},"id":161,"name":"Dragon Age: Origins"},{"executables":{"win32":["DBXV.exe"]},"id":162,"name":"Dragon Ball XenoVerse"},{"executables":{"win32":["DukeForever.exe"]},"id":163,"name":"Duke Nukem Forever"},{"executables":{"darwin":["Dustforce.app"],"win32":["dustforce.exe"]},"id":164,"name":"Dustforce"},{"executables":{"win32":["EliteDangerous32.exe"]},"id":165,"name":"Elite: Dangerous"},{"executables":{"win32":["exefile.exe"]},"id":166,"name":"Eve Online"},{"executables":{"win32":["eqgame.exe"]},"id":167,"name":"EverQuest"},{"executables":{"win32":["EverQuest2.exe"]},"id":168,"name":"EverQuest II"},{"executables":{},"id":169,"name":"EverQuest Next"},{"executables":{"win32":["Engine.exe"]},"id":170,"name":"F.E.A.R."},{"executables":{"win32":["FEAR2.exe"]},"id":171,"name":"F.E.A.R. 2: Project Origin"},{"executables":{"win32":["fallout3.exe"]},"id":172,"name":"Fallout 3"},{"executables":{"win32":["FalloutNV.exe"]},"id":174,"name":"Fallout: New Vegas"},{"executables":{"win32":["farcry3.exe"]},"id":175,"name":"Far Cry 3"},{"executables":{"win32":["fifa15.exe"]},"id":176,"name":"FIFA 15"},{"executables":{"win32":["FTLGame.exe"]},"id":180,"name":"FTL: Faster Than Light"},{"executables":{"win32":["GTAIV.exe"]},"id":181,"name":"Grand Theft Auto 4"},{"executables":{"win32":["GTA5.exe"]},"id":182,"name":"Grand Theft Auto 5"},{"executables":{"win32":["Gw.exe"]},"id":183,"name":"Guild Wars"},{"executables":{"win32":["H1Z1.exe"]},"id":186,"name":"H1Z1"},{"executables":{"win32":["HL2HL2.exe","hl2.exe"]},"id":188,"name":"Half Life 2"},{"executables":{"win32":["HOMEFRONT.exe"]},"id":195,"name":"Homefront"},{"executables":{"win32":["invisibleinc.exe"]},"id":196,"name":"Invisible Inc."},{"executables":{"win32":["LANoire.exe"]},"id":197,"name":"L.A. Noire"},{"executables":{"win32":["Landmark64.exe"]},"id":198,"name":"Landmark"},{"executables":{"win32":["left4dead2.exe"]},"id":201,"name":"Left 4 Dead 2"},{"executables":{"win32":["lineage.exe"]},"id":203,"name":"Lineage"},{"executables":{"win32":["Magicka.exe"]},"id":206,"name":"Magicka"},{"executables":{"win32":["MapleStory.exe"]},"id":208,"name":"MapleStory"},{"executables":{},"id":209,"name":"Mark of the Ninja"},{"executables":{"win32":["MassEffect.exe"]},"id":210,"name":"Mass Effect"},{"executables":{"win32":["MassEffect2.exe"]},"id":211,"name":"Mass Effect 2"},{"executables":{"win32":["MassEffect3Demo.exe"]},"id":212,"name":"Mass Effect 3"},{"executables":{"win32":["METAL GEAR RISING REVENGEANCE.exe"]},"id":214,"name":"Metal Gear Rising: Revengeance"},{"executables":{"win32":["metro2033.exe"]},"id":215,"name":"Metro 2033"},{"executables":{"win32":["MetroLL.exe"]},"id":216,"name":"Metro Last Light"},{"executables":{"win32":["MK10.exe"]},"id":218,"name":"Mortal Kombat X"},{"executables":{"win32":["speed.exe"]},"id":219,"name":"Need For Speed Most Wanted"},{"executables":{},"id":220,"name":"Neverwinder"},{"executables":{"darwin":["Outlast.app"],"win32":["OLGame.exe"]},"id":221,"name":"Outlast"},{"executables":{"win32":["PapersPlease.exe"]},"id":222,"name":"Papers, Please"},{"executables":{"win32":["payday_win32_release.exe"]},"id":223,"name":"PAYDAY"},{"executables":{"win32":["payday2_win32_release.exe"]},"id":224,"name":"PAYDAY2"},{"executables":{"win32":["PillarsOfEternity.exe"]},"id":225,"name":"Pillars of Eternity"},{"executables":{"win32":["PA.exe"]},"id":226,"name":"Planetary Annihilation"},{"executables":{"win32":["planetside2_x86.exe"]},"id":227,"name":"Planetside 2"},{"executables":{"win32":["hl2P.exe"]},"id":228,"name":"Portal"},{"executables":{"win32":["portal2.exe"]},"id":229,"name":"Portal 2"},{"executables":{"win32":["PrimalCarnageGame.exe"]},"id":231,"name":"Primal Cargnage"},{"executables":{"win32":["pCARS.exe"]},"id":232,"name":"Project Cars"},{"executables":{"win32":["RaceTheSun.exe"]},"id":233,"name":"Race The Sun"},{"executables":{"win32":["Rage.exe"]},"id":234,"name":"RAGE"},{"executables":{"win32":["ragexe.exe"]},"id":235,"name":"Ragnarok Online"},{"executables":{"win32":["rift.exe"]},"id":236,"name":"Rift"},{"executables":{"win32":["Rocksmith2014.exe"]},"id":237,"name":"Rocksmith 2014"},{"executables":{"win32":["SwiftKit-RS.exe","JagexLauncher.exe"]},"id":238,"name":"RuneScape"},{"executables":{"win32":["Shadowgrounds.exe"]},"id":239,"name":"Shadowgrounds"},{"executables":{"win32":["survivor.exe"]},"id":240,"name":"Shadowgrounds: Survivor"},{"executables":{"win32":["ShovelKnight.exe"]},"id":241,"name":"Shovel Knight"},{"executables":{"win32":["SimCity.exe"]},"id":242,"name":"SimCity"},{"executables":{"win32":["SporeApp.exe"]},"id":245,"name":"Spore"},{"executables":{"win32":["StarCitizen.exe"]},"id":246,"name":"Star Citizen"},{"executables":{},"id":247,"name":"Star Trek Online"},{"executables":{"win32":["battlefront.exe"]},"id":248,"name":"Star Wars Battlefront"},{"executables":{"win32":["swtor.exe"]},"id":249,"name":"Star Wars: The Old Republic"},{"executables":{"win32":["starbound.exe","starbound_opengl.exe"]},"id":250,"name":"Starbound"},{"executables":{"win32":["starcraft.exe"]},"id":251,"name":"Starcraft"},{"executables":{"win32":["SSFIV.exe"]},"id":253,"name":"Ultra Street Fighter IV"},{"executables":{"win32":["superhexagon.exe"]},"id":254,"name":"Super Hexagon"},{"executables":{"win32":["swordandsworcery_pc.exe"]},"id":255,"name":"Superbrothers: Sword & Sworcery EP"},{"executables":{"win32":["hl2TF.exe"]},"id":256,"name":"Team Fortress 2"},{"executables":{"win32":["TERA.exe"]},"id":258,"name":"TERA"},{"executables":{"win32":["Terraria.exe"]},"id":259,"name":"Terraria"},{"executables":{"win32":["Bethesda.net_Launcher.exe"]},"id":260,"name":"The Elder Scrolls Online"},{"executables":{"win32":["TESV.exe"]},"id":261,"name":"The Elder Scrolls V: Skyrim"},{"executables":{"win32":["TheSecretWorld.exe"]},"id":262,"name":"The Secret World"},{"executables":{"win32":["TS3.exe","ts3w.exe"]},"id":264,"name":"The Sims 3"},{"executables":{"win32":["WALKINGDEAD101.EXE"]},"id":265,"name":"The Walking Dead"},{"executables":{"win32":["TheWalkingDead2.exe"]},"id":266,"name":"The Walking Dead Season Two"},{"executables":{"win32":["witcher3.exe"]},"id":267,"name":"The Witcher 3"},{"executables":{"win32":["Future Soldier.exe"]},"id":268,"name":"Tom Clancy's Ghost Recon: Future Solider"},{"executables":{"win32":["TombRaider.exe"]},"id":269,"name":"Tomb Raider (2013)"},{"executables":{"win32":["Torchlight.exe"]},"id":271,"name":"Torchlight"},{"executables":{"win32":["Torchlight2.exe"]},"id":272,"name":"Torchlight 2"},{"executables":{"win32":["Shogun2.exe"]},"id":273,"name":"Total War: Shogun 2"},{"executables":{"win32":["Transistor.exe"]},"id":274,"name":"Transistor"},{"executables":{"win32":["trine.exe"]},"id":275,"name":"Trine"},{"executables":{"win32":["trine2_32bit.exe"]},"id":276,"name":"Trine 2"},{"executables":{"win32":["UOKR.exe"]},"id":277,"name":"Ultima Online"},{"executables":{"win32":["aces.exe"]},"id":279,"name":"War Thunder"},{"executables":{"win32":["Warcraft III.exe","wc3.exe"]},"id":281,"name":"Warcraft 3: Reign of Chaos"},{"executables":{"win32":["Warcraft II BNE.exe"]},"id":282,"name":"Warcraft II"},{"executables":{"win32":["Warframe.x64.exe","Warframe.exe"]},"id":283,"name":"Warframe"},{"executables":{"win32":["watch_dogs.exe"]},"id":284,"name":"Watch Dogs"},{"executables":{"win32":["WildStar64.exe"]},"id":285,"name":"WildStar"},{"executables":{"win32":["XComGame.exe"]},"id":288,"name":"XCOM: Enemy Unknown"},{"executables":{"win32":["DFO.exe","dfo.exe"]},"id":289,"name":"Dungeon Fighter Online"},{"executables":{"win32":["aclauncher.exe","acclient.exe"]},"id":290,"name":"Asheron's Call"},{"executables":{"win32":["MapleStory2.exe"]},"id":291,"name":"MapleStory 2"},{"executables":{"win32":["ksp.exe"]},"id":292,"name":"Kerbal Space Program"},{"executables":{"win32":["PINBALL.EXE"]},"id":293,"name":"3D Pinball: Space Cadet"},{"executables":{"win32":["dave.exe"]},"id":294,"name":"Dangerous Dave"},{"executables":{"win32":["iwbtgbeta(slomo).exe","iwbtgbeta(fs).exe"]},"id":295,"name":"I Wanna Be The Guy"},{"executables":{"win32":["MechWarriorOnline.exe "]},"id":296,"name":"Mech Warrior Online"},{"executables":{"win32":["dontstarve_steam.exe"]},"id":297,"name":"Don't Starve"},{"executables":{"win32":["GalCiv3.exe"]},"id":298,"name":"Galactic Civilization 3"},{"executables":{"win32":["Risk of Rain.exe"]},"id":299,"name":"Risk of Rain"},{"executables":{"win32":["Binding_of_Isaac.exe","Isaac-ng.exe"]},"id":300,"name":"The Binding of Isaac"},{"executables":{"win32":["RustClient.exe"]},"id":301,"name":"Rust"},{"executables":{"win32":["Clicker Heroes.exe"]},"id":302,"name":"Clicker Heroes"},{"executables":{"win32":["Brawlhalla.exe"]},"id":303,"name":"Brawlhalla"},{"executables":{"win32":["TownOfSalem.exe"]},"id":304,"name":"Town of Salem"},{"executables":{"win32":["osu!.exe"]},"id":305,"name":"osu!"},{"executables":{"win32":["PathOfExileSteam.exe","PathOfExile.exe"]},"id":306,"name":"Path of Exile"},{"executables":{"win32":["Dolphin.exe"]},"id":307,"name":"Dolphin"},{"executables":{"win32":["RocketLeague.exe"]},"id":308,"name":"Rocket League"},{"executables":{"win32":["TJPP.exe"]},"id":309,"name":"Jackbox Party Pack"},{"executables":{"win32":["KFGame.exe"]},"id":310,"name":"Killing Floor 2"},{"executables":{"win32":["ShooterGame.exe"]},"id":311,"name":"Ark: Survival Evolved"},{"executables":{"win32":["LifeIsStrange.exe"]},"id":312,"name":"Life Is Strange"},{"executables":{"win32":["Client_tos.exe"]},"id":313,"name":"Tree of Savior"},{"executables":{"win32":["olliolli2.exe"]},"id":314,"name":"OlliOlli2"},{"executables":{"win32":["cw.exe"]},"id":315,"name":"Closers Dimension Conflict"},{"executables":{"win32":["ESSTEAM.exe","elsword.exe","x2.exe"]},"id":316,"name":"Elsword"},{"executables":{"win32":["ori.exe"]},"id":317,"name":"Ori and the Blind Forest"},{"executables":{"win32":["Skyforge.exe"]},"id":318,"name":"Skyforge"},{"executables":{"win32":["projectzomboid64.exe","projectzomboid32.exe"]},"id":319,"name":"Project Zomboid"},{"executables":{"win32":["From_The_Depths.exe"]},"id":320,"name":"The Depths"},{"executables":{"win32":["TheCrew.exe"]},"id":321,"name":"The Crew"},{"executables":{"win32":["MarvelHeroes2015.exe"]},"id":322,"name":"Marvel Heroes 2015"},{"executables":{"win32":["timeclickers.exe"]},"id":324,"name":"Time Clickers"},{"executables":{"win32":["eurotrucks2.exe"]},"id":325,"name":"Euro Truck Simulator 2"},{"executables":{"win32":["FarmingSimulator2015Game.exe"]},"id":326,"name":"Farming Simulator 15"},{"executables":{"win32":["strife.exe"]},"id":327,"name":"Strife"},{"executables":{"win32":["Awesomenauts.exe"]},"id":328,"name":"Awesomenauts"},{"executables":{"win32":["Dofus.exe"]},"id":329,"name":"Dofus"},{"executables":{"win32":["Boid.exe"]},"id":330,"name":"Boid"},{"executables":{"win32":["adventure-capitalist.exe"]},"id":331,"name":"AdVenture Capitalist"},{"executables":{"win32":["OrcsMustDie2.exe"]},"id":332,"name":"Orcs Must Die! 2"},{"executables":{"win32":["Mountain.exe"]},"id":333,"name":"Mountain"},{"executables":{"win32":["Valkyria.exe"]},"id":335,"name":"Valkyria Chronicles"},{"executables":{"win32":["ffxiiiimg.exe"]},"id":336,"name":"Final Fantasy XIII"},{"executables":{"win32":["TLR.exe"]},"id":337,"name":"The Last Remnant"},{"executables":{"win32":["Cities.exe"]},"id":339,"name":"Cities Skylines"},{"executables":{"win32":["worldofwarships.exe","WoWSLauncher.exe"]},"id":341,"name":"World of Warships"},{"executables":{"win32":["spacegame-Win64-shipping.exe"]},"id":342,"name":"Fractured Space"},{"executables":{"win32":["thespacegame.exe"]},"id":343,"name":"Ascent - The Space Game"},{"executables":{"win32":["DuckGame.exe"]},"id":344,"name":"Duck Game"},{"executables":{"win32":["PPSSPPWindows.exe"]},"id":345,"name":"PPSSPP"},{"executables":{"win32":["MBAA.exe"]},"id":346,"name":"Melty Blood Actress Again: Current Code"},{"executables":{"win32":["TheWolfAmongUs.exe"]},"id":347,"name":"The Wolf Among Us"},{"executables":{"win32":["SpaceEngineers.exe"]},"id":348,"name":"Space Engineers"},{"executables":{"win32":["Borderlands.exe"]},"id":349,"name":"Borderlands"},{"executables":{"win32":["100orange.exe"]},"id":351,"name":"100% Orange Juice"},{"executables":{"win32":["reflex.exe"]},"id":354,"name":"Reflex"},{"executables":{"win32":["pso2.exe"]},"id":355,"name":"Phantasy Star Online 2"},{"executables":{"win32":["AssettoCorsa.exe"]},"id":356,"name":"Assetto Corsa"},{"executables":{"win32":["iw3mp.exe","iw3sp.exe"]},"id":357,"name":"Call of Duty 4: Modern Warfare"},{"executables":{"win32":["WolfOldBlood_x64.exe"]},"id":358,"name":"Wolfenstein: The Old Blood"},{"executables":{"win32":["castle.exe"]},"id":359,"name":"Castle Crashers"},{"executables":{"win32":["vindictus.exe"]},"id":360,"name":"Vindictus"},{"executables":{"win32":["ShooterGame-Win32-Shipping.exe"]},"id":361,"name":"Dirty Bomb"},{"executables":{"win32":["BatmanAK.exe"]},"id":362,"name":"Batman Arkham Knight"},{"executables":{"win32":["drt.exe"]},"id":363,"name":"Dirt Rally"},{"executables":{"win32":["rFactor.exe"]},"id":364,"name":"rFactor"},{"executables":{"win32":["clonk.exe"]},"id":365,"name":"Clonk Rage"},{"executables":{"win32":["SRHK.exe"]},"id":366,"name":"Shadowrun: Hong Kong"},{"executables":{"win32":["Insurgency.exe"]},"id":367,"name":"Insurgency"},{"executables":{"win32":["StepMania.exe"]},"id":368,"name":"Step Mania"},{"executables":{"win32":["FirefallCLient.exe"]},"id":369,"name":"Firefall"},{"executables":{"win32":["mirrorsedge.exe"]},"id":370,"name":"Mirrors Edge"},{"executables":{"win32":["MgsGroundZeroes.exe"]},"id":371,"name":"Metal Gear Solid V: Ground Zeroes"},{"executables":{"win32":["mgsvtpp.exe"]},"id":372,"name":"Metal Gear Solid V: The Phantom Pain"},{"executables":{"win32":["tld.exe"]},"id":373,"name":"The Long Dark"},{"executables":{"win32":["TKOM.exe"]},"id":374,"name":"Take On Mars"},{"executables":{"win32":["robloxplayerlauncher.exe","Roblox.exe"]},"id":375,"name":"Roblox"},{"executables":{"win32":["eu4.exe"]},"id":376,"name":"Europa Universalis 4"},{"executables":{"win32":["APB.exe"]},"id":377,"name":"APB Reloaded"},{"executables":{"win32":["Robocraft.exe"]},"id":378,"name":"Robocraft"},{"executables":{"win32":["Unity.exe"]},"id":379,"name":"Unity"},{"executables":{"win32":["Simpsons.exe"]},"id":380,"name":"The Simpsons: Hit & Run"},{"executables":{"win32":["Dnlauncher.exe","DragonNest.exe"]},"id":381,"name":"Dragon Nest"},{"executables":{"win32":["Trove.exe"]},"id":382,"name":"Trove"},{"executables":{"win32":["EndlessLegend.exe"]},"id":383,"name":"Endless Legend"},{"executables":{"win32":["TurbineLauncher.exe","dndclient.exe"]},"id":384,"name":"Dungeons & Dragons Online"},{"executables":{"win32":["quakelive.exe","quakelive_steam.exe"]},"id":385,"name":"Quake Live"},{"executables":{"win32":["7DaysToDie.exe"]},"id":386,"name":"7DaysToDie"},{"executables":{"win32":["SpeedRunners.exe"]},"id":387,"name":"SpeedRunners"},{"executables":{"win32":["gamemd.exe"]},"id":388,"name":"Command & Conquer: Red Alert 2"},{"executables":{"win32":["generals.exe"]},"id":389,"name":"Command & Conquer Generals: Zero Hour"},{"executables":{"win32":["Oblivion.exe"]},"id":390,"name":"The Elder Scrolls 4: Oblivion"},{"executables":{"win32":["mgsi.exe"]},"id":391,"name":"Metal Gear Solid"},{"executables":{"win32":["EoCApp.exe"]},"id":392,"name":"Divinity - Original Sin"},{"executables":{"win32":["Torment.exe"]},"id":393,"name":"Planescape: Torment"},{"executables":{"win32":["HexPatch.exe"]},"id":394,"name":"Hex: Shards of Fate"},{"executables":{"win32":["NS3FB.exe"]},"id":395,"name":"Naruto Shippuden Ultimate Ninja Storm 3 Full Burst"},{"executables":{"win32":["NSUNSR.exe"]},"id":396,"name":"Naruto Shippuden Ultimate Ninja Storm Revolution"},{"executables":{"win32":["SaintsRowIV.exe"]},"id":397,"name":"Saints Row IV"},{"executables":{"win32":["Shadowrun.exe"]},"id":398,"name":"Shadowrun"},{"executables":{"win32":["DungeonoftheEndless.exe"]},"id":399,"name":"Dungeon of the Endless"},{"executables":{"win32":["Hon.exe"]},"id":400,"name":"Heroes of Newerth"},{"executables":{"win32":["mabinogi.exe"]},"id":401,"name":"Mabinogi"},{"executables":{"win32":["CoD2MP_s.exe","CoDSP_s.exe"]},"id":402,"name":"Call of Duty 2:"},{"executables":{"win32":["CoDWaWmp.exe","CoDWaw.exe"]},"id":403,"name":"Call of Duty: World at War"},{"executables":{"win32":["heroes.exe"]},"id":404,"name":"Mabinogi Heroes (Vindictus) "},{"executables":{"win32":["KanColleViewer.exe"]},"id":405,"name":"KanColle "},{"executables":{"win32":["cyphers.exe"]},"id":406,"name":"Cyphers"},{"executables":{"win32":["RelicCoH2.exe"]},"id":407,"name":"Company of Heroes 2"},{"executables":{"win32":["MJ.exe"]},"id":408,"name":"セガNET麻雀MJ"},{"executables":{"win32":["ge.exe"]},"id":409,"name":"Granado Espada"},{"executables":{"win32":["NovaRO.exe"]},"id":410,"name":"Nova Ragnarok Online"},{"executables":{"win32":["RivalsofAether.exe"]},"id":411,"name":"Rivals of Aether"},{"executables":{"win32":["bfh.exe"]},"id":412,"name":"Battlefield Hardline"},{"executables":{"win32":["GrowHome.exe"]},"id":413,"name":"Grow Home"},{"executables":{"win32":["patriots.exe"]},"id":414,"name":"Rise of Nations Extended"},{"executables":{"win32":["Railroads.exe"]},"id":415,"name":"Sid Meier's Railroads!"},{"executables":{"win32":["Empire.exe"]},"id":416,"name":"Empire: Total War"},{"executables":{"win32":["Napoleon.exe"]},"id":417,"name":"Napoleon: Total War"},{"executables":{"win32":["gta_sa.exe"]},"id":418,"name":"Grand Theft Auto: San Andreas"},{"executables":{"win32":["MadMax.exe"]},"id":419,"name":"Mad Max"},{"executables":{"win32":["Titanfall.exe"]},"id":420,"name":"Titanfall"},{"executables":{"win32":["age2_x1.exe"]},"id":421,"name":"Age of Empires II: The Conquerors"},{"executables":{"win32":["Rome2.exe"]},"id":422,"name":"Total War: ROME 2"},{"executables":{"win32":["ShadowOfMordor.exe"]},"id":423,"name":"Middle-earth: Shadow of Mordor"},{"executables":{"win32":["Subnautica.exe"]},"id":424,"name":"Subnautica"},{"executables":{"win32":["anno5.exe"]},"id":425,"name":"Anno 2070"},{"executables":{"win32":["carrier.exe"]},"id":426,"name":"Carrier Command Gaea Mission"},{"executables":{"win32":["DarksidersPC.exe"]},"id":427,"name":"Darksiders"},{"executables":{"win32":["Darksiders2.exe"]},"id":428,"name":"Darksiders 2"},{"executables":{"win32":["mudlet.exe"]},"id":429,"name":"Mudlet"},{"executables":{"win32":["DunDefLauncher.exe"]},"id":430,"name":"Dungeon Defenders II"},{"executables":{"win32":["hng.exe"]},"id":431,"name":"Heroes and Generals"},{"executables":{"win32":["WFTOGame.exe"]},"id":432,"name":"War of the Overworld"},{"executables":{"win32":["Talisman.exe"]},"id":433,"name":"Talisman: Digital Edition"},{"executables":{"win32":["limbo.exe"]},"id":434,"name":"Limbo"},{"executables":{"win32":["ibbobb.exe"]},"id":435,"name":"ibb & obb"},{"executables":{"win32":["BattleBlockTheater.exe"]},"id":436,"name":"BattleBlock Theater"},{"executables":{"win32":["iracinglauncher.exe","iracingsim.exe","iracingsim64.exe"]},"id":437,"name":"iRacing"},{"executables":{"win32":["CivilizationV_DX11.exe"]},"id":438,"name":"Civilization V"}]
+},{}]},{},[5])(5)
+});
\ No newline at end of file
diff --git a/web-dist/discord.min.3.3.0.js b/web-dist/discord.min.3.3.0.js
new file mode 100644
index 000000000..71f1235d5
--- /dev/null
+++ b/web-dist/discord.min.3.3.0.js
@@ -0,0 +1,2 @@
+!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.Discord=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g]*>/g)||[])[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;a.push(h.substring(2,h.length-1))}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return a}"function"==typeof c&&(d=c,c=!1),b=e+n(b);var p=o();f.resolveDestination(a).then(k)["catch"](j)});return g}},{key:"createws",value:function(a){if(this.websocket)return!1;var b=this;this.websocket=new o(a),this.websocket.onopen=function(){b.trySendConnData()},this.websocket.onclose=function(){b.trigger("disconnected")},this.websocket.onmessage=function(a){var c=!1,d={};try{c=JSON.parse(a.data),d=c.d}catch(e){return void b.trigger("error",e,a)}switch(c.t){case"READY":b.debug("received ready packet"),b.user=b.addUser(d.user);var f=!0,g=!1,i=void 0;try{for(var j,l=d.guilds[Symbol.iterator]();!(f=(j=l.next()).done);f=!0)var m=j.value,n=b.addServer(m)}catch(e){g=!0,i=e}finally{try{!f&&l["return"]&&l["return"]()}finally{if(g)throw i}}var o=!0,p=!1,q=void 0;try{for(var r,s=d.private_channels[Symbol.iterator]();!(o=(r=s.next()).done);o=!0){var t=r.value;b.addPMChannel(t)}}catch(e){p=!0,q=e}finally{try{!o&&s["return"]&&s["return"]()}finally{if(p)throw q}}b.trigger("ready"),b.readyTime=Date.now(),b.debug("cached "+b.serverCache.length+" servers, "+b.channelCache.length+" channels, "+b.pmChannelCache.length+" PMs and "+b.userCache.length+" users."),b.state=3,setInterval(function(){b.keepAlive.apply(b)},d.heartbeat_interval);break;case"MESSAGE_CREATE":b.debug("received message");var u=[];d.mentions=d.mentions||[];var v=!0,w=!1,x=void 0;try{for(var y,z=d.mentions[Symbol.iterator]();!(v=(y=z.next()).done);v=!0){var A=y.value;u.push(b.addUser(A))}}catch(e){w=!0,x=e}finally{try{!v&&z["return"]&&z["return"]()}finally{if(w)throw x}}var B=b.getChannel("id",d.channel_id);if(B){var C=B.addMessage(new k(d,B,u,b.addUser(d.author)));b.trigger("message",C)}break;case"MESSAGE_DELETE":b.debug("message deleted");var B=b.getChannel("id",d.channel_id),D=B.getMessage("id",d.id);D?(b.trigger("messageDelete",B,D),B.messages.splice(B.messages.indexOf(D),1)):b.trigger("messageDelete",B);break;case"MESSAGE_UPDATE":b.debug("message updated");var B=b.getChannel("id",d.channel_id),E=B.getMessage("id",d.id);if(E){var F={};for(var G in E)F[G]=E[G];for(var G in d)F[G]=d[G];var u=[],H=!0,I=!1,J=void 0;try{for(var K,L=F.mentions[Symbol.iterator]();!(H=(K=L.next()).done);H=!0){var A=K.value;u.push(b.addUser(A))}}catch(e){I=!0,J=e}finally{try{!H&&L["return"]&&L["return"]()}finally{if(I)throw J}}var M=new k(F,B,u,E.author);b.trigger("messageUpdate",M,E),B.messages[B.messages.indexOf(E)]=M}break;case"GUILD_DELETE":var n=b.getServer("id",d.id);n&&(b.serverCache.splice(b.serverCache.indexOf(n),1),b.trigger("serverDelete",n));break;case"CHANNEL_DELETE":var B=b.getChannel("id",d.id);if(B){var n=B.server;n&&n.channels.splice(n.channels.indexOf(B),1),b.trigger("channelDelete",B),b.serverCache.splice(b.serverCache.indexOf(B),1)}break;case"GUILD_CREATE":var n=b.getServer("id",d.id);if(n||(n=b.addServer(d)),b.serverCreateListener.get(d.id)){var N=b.serverCreateListener.get(d.id);N[0](n),N[1](null,n),b.serverCreateListener["delete"](d.id)}b.trigger("serverCreate",n);break;case"CHANNEL_CREATE":var B=b.getChannel("id",d.id);if(!B){var O=b.addChannel(d,d.guild_id),P=b.getServer("id",d.guild_id);P&&P.addChannel(O),b.trigger("channelCreate",O)}break;case"GUILD_MEMBER_ADD":var n=b.getServer("id",d.guild_id);if(n){var Q=b.addUser(d.user);~n.members.indexOf(Q)||n.members.push(Q),b.trigger("serverNewMember",Q)}break;case"GUILD_MEMBER_REMOVE":var n=b.getServer("id",d.guild_id);if(n){var Q=b.addUser(d.user);~n.members.indexOf(Q)&&n.members.splice(n.members.indexOf(Q),1),b.trigger("serverRemoveMember",Q)}break;case"USER_UPDATE":if(b.user&&d.id===b.user.id){var R=new h(d);b.trigger("userUpdate",R,b.user),~b.userCache.indexOf(b.user)&&(b.userCache[b.userCache.indexOf(b.user)]=R),b.user=R}break;case"PRESENCE_UPDATE":var S=b.getUser("id",d.user.id);if(S){var T=new h(d.user);T.equalsStrict(S)?b.trigger("presence",{user:S,status:d.status,server:b.getServer("id",d.guild_id),gameId:d.game_id}):(b.trigger("userUpdate",S,T),b.userCache[b.userCache.indexOf(S)]=T)}break;default:b.debug("received unknown packet"),b.trigger("unknown",c)}}}},{key:"addUser",value:function(a){return this.getUser("id",a.id)||this.userCache.push(new h(a)),this.getUser("id",a.id)}},{key:"addChannel",value:function(a,b){return this.getChannel("id",a.id)||this.channelCache.push(new j(a,this.getServer("id",b))),this.getChannel("id",a.id)}},{key:"addPMChannel",value:function(a){return this.getPMChannel("id",a.id)||this.pmChannelCache.push(new m(a,this)),this.getPMChannel("id",a.id)}},{key:"addServer",value:function(a){var b=this.getServer("id",a.id);if(!b&&(b=new i(a,this),this.serverCache.push(b),a.channels)){var c=!0,d=!1,e=void 0;try{for(var f,g=a.channels[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;b.channels.push(this.addChannel(h,b.id))}}catch(j){d=!0,e=j}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}}return b}},{key:"getUser",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.userCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"getChannel",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.channelCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return this.getPMChannel(a,b)}},{key:"getPMChannel",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.pmChannelCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"getServer",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.serverCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"trySendConnData",value:function(){if(this.token&&!this.alreadySentData){this.alreadySentData=!0;var a={op:2,d:{token:this.token,v:2,properties:{$os:"discord.js",$browser:"discord.js",$device:"discord.js",$referrer:"",$referring_domain:""}}};this.websocket.send(JSON.stringify(a))}}},{key:"resolveServerID",value:function(a){return a instanceof i?a.id:!isNaN(a)&&a.length&&17===a.length?a:void 0}},{key:"resolveDestination",value:function(a){var b=!1,c=this;return new Promise(function(d,e){if(a instanceof i)b=a.id;else if(a instanceof j)b=a.id;else if(a instanceof k)b=a.channel.id;else if(a instanceof h){var f=!0,g=!1,l=void 0;try{for(var m,n=c.pmChannelCache[Symbol.iterator]();!(f=(m=n.next()).done);f=!0){var o=m.value;if(o.user.equals(a))return o.id}}catch(p){g=!0,l=p}finally{try{!f&&n["return"]&&n["return"]()}finally{if(g)throw l}}c.startPM(a).then(function(a){d(a.id)})["catch"](e)}else b=a;b&&d(b)})}},{key:"_sendMessage",value:function(a,b,c,d){var e=this;return new Promise(function(f,h){n.post(g.CHANNELS+"/"+a+"/messages").set("authorization",e.token).send({content:b,mentions:d,tts:c}).end(function(a,b){if(a)h(a);else{var c=b.body,d=[];c.mentions=c.mentions||[];var g=!0,i=!1,j=void 0;try{for(var l,m=c.mentions[Symbol.iterator]();!(g=(l=m.next()).done);g=!0){var n=l.value;d.push(e.addUser(n))}}catch(a){i=!0,j=a}finally{try{!g&&m["return"]&&m["return"]()}finally{if(i)throw j}}var o=e.getChannel("id",c.channel_id);if(o){var p=o.addMessage(new k(c,o,d,e.addUser(c.author)));f(p)}}})})}},{key:"_sendFile",value:function(a,b){var c=arguments.length<=2||void 0===arguments[2]?"DEFAULT BECAUSE YOU DIDN'T SPECIFY WHY.png":arguments[2],d=this;return new Promise(function(e,f){n.post(g.CHANNELS+"/"+a+"/messages").set("authorization",d.token).attach("file",b,c).end(function(b,c){if(b)f(b);else{var g=d.getChannel("id",a);if(g){var h=g.addMessage(new k(c.body,g,[],d.user));e(h)}}})})}},{key:"_updateMessage",value:function(a,b){var c=this;return new Promise(function(d,e){n.patch(g.CHANNELS+"/"+a.channel.id+"/messages/"+a.id).set("authorization",c.token).send({content:b,mentions:[]}).end(function(b,c){if(b)e(b);else{var f=new k(c.body,a.channel,a.mentions,a.sender);d(f),a.channel.messages[a.channel.messages.indexOf(a)]=f}})})}},{key:"_deleteMessage",value:function(a){var b=this;return new Promise(function(c,d){n.del(g.CHANNELS+"/"+a.channel.id+"/messages/"+a.id).set("authorization",b.token).end(function(a,b){a?d(a):c()})})}},{key:"checkQueue",value:function(a){var b=this,c=this;this.checkingQueue[a]||!function(){var d=function f(){if(0===c.queue[a].length)return void e();var b=c.queue[a][0];switch(b.action){case"sendMessage":var d=b;c._sendMessage(a,d.content,d.tts,d.mentions).then(function(b){d.then(b),c.queue[a].shift(),f()})["catch"](function(b){d.error(b),c.queue[a].shift(),f()});break;case"sendFile":var g=b;c._sendFile(a,g.attachment,g.attachmentName).then(function(b){g.then(b),c.queue[a].shift(),f()})["catch"](function(b){g.error(b),c.queue[a].shift(),f()});break;case"updateMessage":var h=b;c._updateMessage(h.message,h.content).then(function(b){h.then(b),c.queue[a].shift(),f()})["catch"](function(b){h.error(b),c.queue[a].shift(),f()});break;case"deleteMessage":var i=b;c._deleteMessage(i.message).then(function(b){i.then(b),c.queue[a].shift(),f()})["catch"](function(b){i.error(b),c.queue[a].shift(),f()});break;default:e()}},e=function(){c.checkingQueue[a]=!1};b.checkingQueue[a]=!0,d()}()}},{key:"uptime",get:function(){return this.readyTime?Date.now()-this.readyTime:null}},{key:"ready",get:function(){return 3===this.state}},{key:"servers",get:function(){return this.serverCache}},{key:"channels",get:function(){return this.channelCache}},{key:"users",get:function(){return this.userCache}},{key:"PMChannels",get:function(){return this.pmChannelCache}},{key:"messages",get:function(){var a=[],b=!0,c=!1,d=void 0;try{for(var e,f=this.channelCache[Symbol.iterator]();!(b=(e=f.next()).done);b=!0){var g=e.value;a=a.concat(g.messages)}}catch(h){c=!0,d=h}finally{try{!b&&f["return"]&&f["return"]()}finally{if(c)throw d}}return a}}]),a}();b.exports=r},{"./Endpoints.js":2,"./PMChannel.js":3,"./channel.js":4,"./invite.js":6,"./message.js":7,"./server.js":8,"./user.js":9,fs:10,superagent:11,ws:14}],2:[function(a,b,c){"use strict";c.BASE_DOMAIN="discordapp.com",c.BASE="https://"+c.BASE_DOMAIN,c.WEBSOCKET_HUB="wss://"+c.BASE_DOMAIN+"/hub",c.API=c.BASE+"/api",c.AUTH=c.API+"/auth",c.LOGIN=c.AUTH+"/login",c.LOGOUT=c.AUTH+"/logout",c.USERS=c.API+"/users",c.SERVERS=c.API+"/guilds",c.CHANNELS=c.API+"/channels"},{}],3:[function(a,b,c){"use strict";function d(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}var e=function(){function a(a,b){for(var c=0;c"}},{key:"toString",value:function(){return this.mention()}},{key:"equals",value:function(a){return a.id===this.id}},{key:"equalsStrict",value:function(a){return a.id===this.id&&a.avatar===this.avatar&&a.username===this.username&&a.discriminator===this.discriminator}},{key:"avatarURL",get:function(){return this.avatar?"https://discordapp.com/api/users/"+this.id+"/avatars/"+this.avatar+".jpg":null}}]),a}();b.exports=f},{}],10:[function(a,b,c){},{}],11:[function(a,b,c){function d(){}function e(a){var b={}.toString.call(a);switch(b){case"[object File]":case"[object Blob]":case"[object FormData]":return!0;default:return!1}}function f(a){return a===Object(a)}function g(a){if(!f(a))return a;var b=[];for(var c in a)null!=a[c]&&b.push(encodeURIComponent(c)+"="+encodeURIComponent(a[c]));return b.join("&")}function h(a){for(var b,c,d={},e=a.split("&"),f=0,g=e.length;g>f;++f)c=e[f],b=c.split("="),d[decodeURIComponent(b[0])]=decodeURIComponent(b[1]);return d}function i(a){var b,c,d,e,f=a.split(/\r?\n/),g={};f.pop();for(var h=0,i=f.length;i>h;++h)c=f[h],b=c.indexOf(":"),d=c.slice(0,b).toLowerCase(),e=r(c.slice(b+1)),g[d]=e;return g}function j(a){return a.split(/ *; */).shift()}function k(a){return p(a.split(/ *; */),function(a,b){var c=b.split(/ *= */),d=c.shift(),e=c.shift();return d&&e&&(a[d]=e),a},{})}function l(a,b){b=b||{},this.req=a,this.xhr=this.req.xhr,this.text="HEAD"!=this.req.method&&(""===this.xhr.responseType||"text"===this.xhr.responseType)||"undefined"==typeof this.xhr.responseType?this.xhr.responseText:null,this.statusText=this.req.xhr.statusText,this.setStatusProperties(this.xhr.status),this.header=this.headers=i(this.xhr.getAllResponseHeaders()),this.header["content-type"]=this.xhr.getResponseHeader("content-type"),this.setHeaderProperties(this.header),this.body="HEAD"!=this.req.method?this.parseBody(this.text?this.text:this.xhr.response):null}function m(a,b){var c=this;o.call(this),this._query=this._query||[],this.method=a,this.url=b,this.header={},this._header={},this.on("end",function(){var a=null,b=null;try{b=new l(c)}catch(d){return a=new Error("Parser is unable to parse the response"),a.parse=!0,a.original=d,c.callback(a)}if(c.emit("response",b),a)return c.callback(a,b);if(b.status>=200&&b.status<300)return c.callback(a,b);var e=new Error(b.statusText||"Unsuccessful HTTP response");e.original=a,e.response=b,e.status=b.status,c.callback(e,b)})}function n(a,b){return"function"==typeof b?new m("GET",a).end(b):1==arguments.length?new m("GET",a):new m(a,b)}var o=a("emitter"),p=a("reduce"),q="undefined"==typeof window?this||self:window;n.getXHR=function(){if(!(!q.XMLHttpRequest||q.location&&"file:"==q.location.protocol&&q.ActiveXObject))return new XMLHttpRequest;try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(a){}return!1};var r="".trim?function(a){return a.trim()}:function(a){return a.replace(/(^\s*|\s*$)/g,"")};n.serializeObject=g,n.parseString=h,n.types={html:"text/html",json:"application/json",xml:"application/xml",urlencoded:"application/x-www-form-urlencoded",form:"application/x-www-form-urlencoded","form-data":"application/x-www-form-urlencoded"},n.serialize={"application/x-www-form-urlencoded":g,"application/json":JSON.stringify},n.parse={"application/x-www-form-urlencoded":h,"application/json":JSON.parse},l.prototype.get=function(a){return this.header[a.toLowerCase()]},l.prototype.setHeaderProperties=function(a){var b=this.header["content-type"]||"";this.type=j(b);var c=k(b);for(var d in c)this[d]=c[d]},l.prototype.parseBody=function(a){var b=n.parse[this.type];return b&&a&&(a.length||a instanceof Object)?b(a):null},l.prototype.setStatusProperties=function(a){1223===a&&(a=204);var b=a/100|0;this.status=a,this.statusType=b,this.info=1==b,this.ok=2==b,this.clientError=4==b,this.serverError=5==b,this.error=4==b||5==b?this.toError():!1,this.accepted=202==a,this.noContent=204==a,this.badRequest=400==a,this.unauthorized=401==a,this.notAcceptable=406==a,this.notFound=404==a,this.forbidden=403==a},l.prototype.toError=function(){var a=this.req,b=a.method,c=a.url,d="cannot "+b+" "+c+" ("+this.status+")",e=new Error(d);return e.status=this.status,e.method=b,e.url=c,e},n.Response=l,o(m.prototype),m.prototype.use=function(a){return a(this),this},m.prototype.timeout=function(a){return this._timeout=a,this},m.prototype.clearTimeout=function(){return this._timeout=0,clearTimeout(this._timer),this},m.prototype.abort=function(){return this.aborted?void 0:(this.aborted=!0,this.xhr.abort(),
+this.clearTimeout(),this.emit("abort"),this)},m.prototype.set=function(a,b){if(f(a)){for(var c in a)this.set(c,a[c]);return this}return this._header[a.toLowerCase()]=b,this.header[a]=b,this},m.prototype.unset=function(a){return delete this._header[a.toLowerCase()],delete this.header[a],this},m.prototype.getHeader=function(a){return this._header[a.toLowerCase()]},m.prototype.type=function(a){return this.set("Content-Type",n.types[a]||a),this},m.prototype.accept=function(a){return this.set("Accept",n.types[a]||a),this},m.prototype.auth=function(a,b){var c=btoa(a+":"+b);return this.set("Authorization","Basic "+c),this},m.prototype.query=function(a){return"string"!=typeof a&&(a=g(a)),a&&this._query.push(a),this},m.prototype.field=function(a,b){return this._formData||(this._formData=new q.FormData),this._formData.append(a,b),this},m.prototype.attach=function(a,b,c){return this._formData||(this._formData=new q.FormData),this._formData.append(a,b,c),this},m.prototype.send=function(a){var b=f(a),c=this.getHeader("Content-Type");if(b&&f(this._data))for(var d in a)this._data[d]=a[d];else"string"==typeof a?(c||this.type("form"),c=this.getHeader("Content-Type"),"application/x-www-form-urlencoded"==c?this._data=this._data?this._data+"&"+a:a:this._data=(this._data||"")+a):this._data=a;return!b||e(a)?this:(c||this.type("json"),this)},m.prototype.callback=function(a,b){var c=this._callback;this.clearTimeout(),c(a,b)},m.prototype.crossDomainError=function(){var a=new Error("Origin is not allowed by Access-Control-Allow-Origin");a.crossDomain=!0,this.callback(a)},m.prototype.timeoutError=function(){var a=this._timeout,b=new Error("timeout of "+a+"ms exceeded");b.timeout=a,this.callback(b)},m.prototype.withCredentials=function(){return this._withCredentials=!0,this},m.prototype.end=function(a){var b=this,c=this.xhr=n.getXHR(),f=this._query.join("&"),g=this._timeout,h=this._formData||this._data;this._callback=a||d,c.onreadystatechange=function(){if(4==c.readyState){var a;try{a=c.status}catch(d){a=0}if(0==a){if(b.timedout)return b.timeoutError();if(b.aborted)return;return b.crossDomainError()}b.emit("end")}};var i=function(a){a.total>0&&(a.percent=a.loaded/a.total*100),b.emit("progress",a)};this.hasListeners("progress")&&(c.onprogress=i);try{c.upload&&this.hasListeners("progress")&&(c.upload.onprogress=i)}catch(j){}if(g&&!this._timer&&(this._timer=setTimeout(function(){b.timedout=!0,b.abort()},g)),f&&(f=n.serializeObject(f),this.url+=~this.url.indexOf("?")?"&"+f:"?"+f),c.open(this.method,this.url,!0),this._withCredentials&&(c.withCredentials=!0),"GET"!=this.method&&"HEAD"!=this.method&&"string"!=typeof h&&!e(h)){var k=this.getHeader("Content-Type"),l=n.serialize[k?k.split(";")[0]:""];l&&(h=l(h))}for(var m in this.header)null!=this.header[m]&&c.setRequestHeader(m,this.header[m]);return this.emit("request",this),c.send(h),this},m.prototype.then=function(a,b){return this.end(function(c,d){c?b(c):a(d)})},n.Request=m,n.get=function(a,b,c){var d=n("GET",a);return"function"==typeof b&&(c=b,b=null),b&&d.query(b),c&&d.end(c),d},n.head=function(a,b,c){var d=n("HEAD",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},n.del=function(a,b){var c=n("DELETE",a);return b&&c.end(b),c},n.patch=function(a,b,c){var d=n("PATCH",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},n.post=function(a,b,c){var d=n("POST",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},n.put=function(a,b,c){var d=n("PUT",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},b.exports=n},{emitter:12,reduce:13}],12:[function(a,b,c){function d(a){return a?e(a):void 0}function e(a){for(var b in d.prototype)a[b]=d.prototype[b];return a}b.exports=d,d.prototype.on=d.prototype.addEventListener=function(a,b){return this._callbacks=this._callbacks||{},(this._callbacks[a]=this._callbacks[a]||[]).push(b),this},d.prototype.once=function(a,b){function c(){d.off(a,c),b.apply(this,arguments)}var d=this;return this._callbacks=this._callbacks||{},c.fn=b,this.on(a,c),this},d.prototype.off=d.prototype.removeListener=d.prototype.removeAllListeners=d.prototype.removeEventListener=function(a,b){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var c=this._callbacks[a];if(!c)return this;if(1==arguments.length)return delete this._callbacks[a],this;for(var d,e=0;ed;++d)c[d].apply(this,b)}return this},d.prototype.listeners=function(a){return this._callbacks=this._callbacks||{},this._callbacks[a]||[]},d.prototype.hasListeners=function(a){return!!this.listeners(a).length}},{}],13:[function(a,b,c){b.exports=function(a,b,c){for(var d=0,e=a.length,f=3==arguments.length?c:a[d++];e>d;)f=b.call(null,f,a[d],++d,a);return f}},{}],14:[function(a,b,c){function d(a,b,c){var d;return d=b?new f(a,b):new f(a)}var e=function(){return this}(),f=e.WebSocket||e.MozWebSocket;b.exports=f?d:null,f&&(d.prototype=f.prototype)},{}]},{},[5])(5)});
\ No newline at end of file
diff --git a/web-dist/discord.min.3.3.1.js b/web-dist/discord.min.3.3.1.js
new file mode 100644
index 000000000..2079f39b6
--- /dev/null
+++ b/web-dist/discord.min.3.3.1.js
@@ -0,0 +1,2 @@
+!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.Discord=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g]*>/g)||[])[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;a.push(h.substring(2,h.length-1))}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return a}"function"==typeof c&&(d=c,c=!1),b=e+n(b);var p=o();f.resolveDestination(a).then(k)["catch"](j)});return g}},{key:"createws",value:function(a){if(this.websocket)return!1;var b=this;this.websocket=new o(a),this.websocket.onopen=function(){b.trySendConnData()},this.websocket.onclose=function(){b.trigger("disconnected")},this.websocket.onmessage=function(a){var c=!1,d={};try{c=JSON.parse(a.data),d=c.d}catch(e){return void b.trigger("error",e,a)}switch(c.t){case"READY":b.debug("received ready packet"),b.user=b.addUser(d.user);var f=!0,g=!1,i=void 0;try{for(var j,l=d.guilds[Symbol.iterator]();!(f=(j=l.next()).done);f=!0)var m=j.value,n=b.addServer(m)}catch(e){g=!0,i=e}finally{try{!f&&l["return"]&&l["return"]()}finally{if(g)throw i}}var o=!0,p=!1,q=void 0;try{for(var r,s=d.private_channels[Symbol.iterator]();!(o=(r=s.next()).done);o=!0){var t=r.value;b.addPMChannel(t)}}catch(e){p=!0,q=e}finally{try{!o&&s["return"]&&s["return"]()}finally{if(p)throw q}}b.trigger("ready"),b.readyTime=Date.now(),b.debug("cached "+b.serverCache.length+" servers, "+b.channelCache.length+" channels, "+b.pmChannelCache.length+" PMs and "+b.userCache.length+" users."),b.state=3,setInterval(function(){b.keepAlive.apply(b)},d.heartbeat_interval);break;case"MESSAGE_CREATE":b.debug("received message");var u=[];d.mentions=d.mentions||[];var v=!0,w=!1,x=void 0;try{for(var y,z=d.mentions[Symbol.iterator]();!(v=(y=z.next()).done);v=!0){var A=y.value;u.push(b.addUser(A))}}catch(e){w=!0,x=e}finally{try{!v&&z["return"]&&z["return"]()}finally{if(w)throw x}}var B=b.getChannel("id",d.channel_id);if(B){var C=B.addMessage(new k(d,B,u,b.addUser(d.author)));b.trigger("message",C)}break;case"MESSAGE_DELETE":b.debug("message deleted");var B=b.getChannel("id",d.channel_id),D=B.getMessage("id",d.id);D?(b.trigger("messageDelete",B,D),B.messages.splice(B.messages.indexOf(D),1)):b.trigger("messageDelete",B);break;case"MESSAGE_UPDATE":b.debug("message updated");var B=b.getChannel("id",d.channel_id),E=B.getMessage("id",d.id);if(E){var F={};for(var G in E)F[G]=E[G];for(var G in d)F[G]=d[G];var u=[],H=!0,I=!1,J=void 0;try{for(var K,L=F.mentions[Symbol.iterator]();!(H=(K=L.next()).done);H=!0){var A=K.value;u.push(b.addUser(A))}}catch(e){I=!0,J=e}finally{try{!H&&L["return"]&&L["return"]()}finally{if(I)throw J}}var M=new k(F,B,u,E.author);b.trigger("messageUpdate",M,E),B.messages[B.messages.indexOf(E)]=M}break;case"GUILD_DELETE":var n=b.getServer("id",d.id);n&&(b.serverCache.splice(b.serverCache.indexOf(n),1),b.trigger("serverDelete",n));break;case"CHANNEL_DELETE":var B=b.getChannel("id",d.id);if(B){var n=B.server;n&&n.channels.splice(n.channels.indexOf(B),1),b.trigger("channelDelete",B),b.serverCache.splice(b.serverCache.indexOf(B),1)}break;case"GUILD_CREATE":var n=b.getServer("id",d.id);if(n||(n=b.addServer(d)),b.serverCreateListener.get(d.id)){var N=b.serverCreateListener.get(d.id);N[0](n),N[1](null,n),b.serverCreateListener["delete"](d.id)}b.trigger("serverCreate",n);break;case"CHANNEL_CREATE":var B=b.getChannel("id",d.id);if(!B){var O=b.addChannel(d,d.guild_id),P=b.getServer("id",d.guild_id);P&&P.addChannel(O),b.trigger("channelCreate",O)}break;case"GUILD_MEMBER_ADD":var n=b.getServer("id",d.guild_id);if(n){var Q=b.addUser(d.user);~n.members.indexOf(Q)||n.members.push(Q),b.trigger("serverNewMember",Q,n)}break;case"GUILD_MEMBER_REMOVE":var n=b.getServer("id",d.guild_id);if(n){var Q=b.addUser(d.user);~n.members.indexOf(Q)&&n.members.splice(n.members.indexOf(Q),1),b.trigger("serverRemoveMember",Q,n)}break;case"USER_UPDATE":if(b.user&&d.id===b.user.id){var R=new h(d);b.trigger("userUpdate",R,b.user),~b.userCache.indexOf(b.user)&&(b.userCache[b.userCache.indexOf(b.user)]=R),b.user=R}break;case"PRESENCE_UPDATE":var S=b.getUser("id",d.user.id);if(S){var T=new h(d.user);T.equalsStrict(S)?b.trigger("presence",{user:S,status:d.status,server:b.getServer("id",d.guild_id),gameId:d.game_id}):(b.trigger("userUpdate",S,T),b.userCache[b.userCache.indexOf(S)]=T)}break;default:b.debug("received unknown packet"),b.trigger("unknown",c)}}}},{key:"addUser",value:function(a){return this.getUser("id",a.id)||this.userCache.push(new h(a)),this.getUser("id",a.id)}},{key:"addChannel",value:function(a,b){return this.getChannel("id",a.id)||this.channelCache.push(new j(a,this.getServer("id",b))),this.getChannel("id",a.id)}},{key:"addPMChannel",value:function(a){return this.getPMChannel("id",a.id)||this.pmChannelCache.push(new m(a,this)),this.getPMChannel("id",a.id)}},{key:"addServer",value:function(a){var b=this.getServer("id",a.id);if(!b&&(b=new i(a,this),this.serverCache.push(b),a.channels)){var c=!0,d=!1,e=void 0;try{for(var f,g=a.channels[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;b.channels.push(this.addChannel(h,b.id))}}catch(j){d=!0,e=j}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}}return b}},{key:"getUser",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.userCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"getChannel",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.channelCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return this.getPMChannel(a,b)}},{key:"getPMChannel",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.pmChannelCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"getServer",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.serverCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"trySendConnData",value:function(){if(this.token&&!this.alreadySentData){this.alreadySentData=!0;var a={op:2,d:{token:this.token,v:2,properties:{$os:"discord.js",$browser:"discord.js",$device:"discord.js",$referrer:"",$referring_domain:""}}};this.websocket.send(JSON.stringify(a))}}},{key:"resolveServerID",value:function(a){return a instanceof i?a.id:!isNaN(a)&&a.length&&17===a.length?a:void 0}},{key:"resolveDestination",value:function(a){var b=!1,c=this;return new Promise(function(d,e){if(a instanceof i)b=a.id;else if(a instanceof j)b=a.id;else if(a instanceof k)b=a.channel.id;else if(a instanceof h){var f=!0,g=!1,l=void 0;try{for(var m,n=c.pmChannelCache[Symbol.iterator]();!(f=(m=n.next()).done);f=!0){var o=m.value;if(o.user.equals(a))return o.id}}catch(p){g=!0,l=p}finally{try{!f&&n["return"]&&n["return"]()}finally{if(g)throw l}}c.startPM(a).then(function(a){d(a.id)})["catch"](e)}else b=a;b&&d(b)})}},{key:"_sendMessage",value:function(a,b,c,d){var e=this;return new Promise(function(f,h){n.post(g.CHANNELS+"/"+a+"/messages").set("authorization",e.token).send({content:b,mentions:d,tts:c}).end(function(a,b){if(a)h(a);else{var c=b.body,d=[];c.mentions=c.mentions||[];var g=!0,i=!1,j=void 0;try{for(var l,m=c.mentions[Symbol.iterator]();!(g=(l=m.next()).done);g=!0){var n=l.value;d.push(e.addUser(n))}}catch(a){i=!0,j=a}finally{try{!g&&m["return"]&&m["return"]()}finally{if(i)throw j}}var o=e.getChannel("id",c.channel_id);if(o){var p=o.addMessage(new k(c,o,d,e.addUser(c.author)));f(p)}}})})}},{key:"_sendFile",value:function(a,b){var c=arguments.length<=2||void 0===arguments[2]?"DEFAULT BECAUSE YOU DIDN'T SPECIFY WHY.png":arguments[2],d=this;return new Promise(function(e,f){n.post(g.CHANNELS+"/"+a+"/messages").set("authorization",d.token).attach("file",b,c).end(function(b,c){if(b)f(b);else{var g=d.getChannel("id",a);if(g){var h=g.addMessage(new k(c.body,g,[],d.user));e(h)}}})})}},{key:"_updateMessage",value:function(a,b){var c=this;return new Promise(function(d,e){n.patch(g.CHANNELS+"/"+a.channel.id+"/messages/"+a.id).set("authorization",c.token).send({content:b,mentions:[]}).end(function(b,c){if(b)e(b);else{var f=new k(c.body,a.channel,a.mentions,a.sender);d(f),a.channel.messages[a.channel.messages.indexOf(a)]=f}})})}},{key:"_deleteMessage",value:function(a){var b=this;return new Promise(function(c,d){n.del(g.CHANNELS+"/"+a.channel.id+"/messages/"+a.id).set("authorization",b.token).end(function(a,b){a?d(a):c()})})}},{key:"checkQueue",value:function(a){var b=this,c=this;this.checkingQueue[a]||!function(){var d=function f(){if(0===c.queue[a].length)return void e();var b=c.queue[a][0];switch(b.action){case"sendMessage":var d=b;c._sendMessage(a,d.content,d.tts,d.mentions).then(function(b){d.then(b),c.queue[a].shift(),f()})["catch"](function(b){d.error(b),c.queue[a].shift(),f()});break;case"sendFile":var g=b;c._sendFile(a,g.attachment,g.attachmentName).then(function(b){g.then(b),c.queue[a].shift(),f()})["catch"](function(b){g.error(b),c.queue[a].shift(),f()});break;case"updateMessage":var h=b;c._updateMessage(h.message,h.content).then(function(b){h.then(b),c.queue[a].shift(),f()})["catch"](function(b){h.error(b),c.queue[a].shift(),f()});break;case"deleteMessage":var i=b;c._deleteMessage(i.message).then(function(b){i.then(b),c.queue[a].shift(),f()})["catch"](function(b){i.error(b),c.queue[a].shift(),f()});break;default:e()}},e=function(){c.checkingQueue[a]=!1};b.checkingQueue[a]=!0,d()}()}},{key:"uptime",get:function(){return this.readyTime?Date.now()-this.readyTime:null}},{key:"ready",get:function(){return 3===this.state}},{key:"servers",get:function(){return this.serverCache}},{key:"channels",get:function(){return this.channelCache}},{key:"users",get:function(){return this.userCache}},{key:"PMChannels",get:function(){return this.pmChannelCache}},{key:"messages",get:function(){var a=[],b=!0,c=!1,d=void 0;try{for(var e,f=this.channelCache[Symbol.iterator]();!(b=(e=f.next()).done);b=!0){var g=e.value;a=a.concat(g.messages)}}catch(h){c=!0,d=h}finally{try{!b&&f["return"]&&f["return"]()}finally{if(c)throw d}}return a}}]),a}();b.exports=r},{"./Endpoints.js":2,"./PMChannel.js":3,"./channel.js":4,"./invite.js":6,"./message.js":7,"./server.js":8,"./user.js":9,fs:10,superagent:11,ws:14}],2:[function(a,b,c){"use strict";c.BASE_DOMAIN="discordapp.com",c.BASE="https://"+c.BASE_DOMAIN,c.WEBSOCKET_HUB="wss://"+c.BASE_DOMAIN+"/hub",c.API=c.BASE+"/api",c.AUTH=c.API+"/auth",c.LOGIN=c.AUTH+"/login",c.LOGOUT=c.AUTH+"/logout",c.USERS=c.API+"/users",c.SERVERS=c.API+"/guilds",c.CHANNELS=c.API+"/channels"},{}],3:[function(a,b,c){"use strict";function d(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}var e=function(){function a(a,b){for(var c=0;c"}},{key:"toString",value:function(){return this.mention()}},{key:"equals",value:function(a){return a.id===this.id}},{key:"equalsStrict",value:function(a){return a.id===this.id&&a.avatar===this.avatar&&a.username===this.username&&a.discriminator===this.discriminator}},{key:"avatarURL",get:function(){return this.avatar?"https://discordapp.com/api/users/"+this.id+"/avatars/"+this.avatar+".jpg":null}}]),a}();b.exports=f},{}],10:[function(a,b,c){},{}],11:[function(a,b,c){function d(){}function e(a){var b={}.toString.call(a);switch(b){case"[object File]":case"[object Blob]":case"[object FormData]":return!0;default:return!1}}function f(a){return a===Object(a)}function g(a){if(!f(a))return a;var b=[];for(var c in a)null!=a[c]&&b.push(encodeURIComponent(c)+"="+encodeURIComponent(a[c]));return b.join("&")}function h(a){for(var b,c,d={},e=a.split("&"),f=0,g=e.length;g>f;++f)c=e[f],b=c.split("="),d[decodeURIComponent(b[0])]=decodeURIComponent(b[1]);return d}function i(a){var b,c,d,e,f=a.split(/\r?\n/),g={};f.pop();for(var h=0,i=f.length;i>h;++h)c=f[h],b=c.indexOf(":"),d=c.slice(0,b).toLowerCase(),e=r(c.slice(b+1)),g[d]=e;return g}function j(a){return a.split(/ *; */).shift()}function k(a){return p(a.split(/ *; */),function(a,b){var c=b.split(/ *= */),d=c.shift(),e=c.shift();return d&&e&&(a[d]=e),a},{})}function l(a,b){b=b||{},this.req=a,this.xhr=this.req.xhr,this.text="HEAD"!=this.req.method&&(""===this.xhr.responseType||"text"===this.xhr.responseType)||"undefined"==typeof this.xhr.responseType?this.xhr.responseText:null,this.statusText=this.req.xhr.statusText,this.setStatusProperties(this.xhr.status),this.header=this.headers=i(this.xhr.getAllResponseHeaders()),this.header["content-type"]=this.xhr.getResponseHeader("content-type"),this.setHeaderProperties(this.header),this.body="HEAD"!=this.req.method?this.parseBody(this.text?this.text:this.xhr.response):null}function m(a,b){var c=this;o.call(this),this._query=this._query||[],this.method=a,this.url=b,this.header={},this._header={},this.on("end",function(){var a=null,b=null;try{b=new l(c)}catch(d){return a=new Error("Parser is unable to parse the response"),a.parse=!0,a.original=d,c.callback(a)}if(c.emit("response",b),a)return c.callback(a,b);if(b.status>=200&&b.status<300)return c.callback(a,b);var e=new Error(b.statusText||"Unsuccessful HTTP response");e.original=a,e.response=b,e.status=b.status,c.callback(e,b)})}function n(a,b){return"function"==typeof b?new m("GET",a).end(b):1==arguments.length?new m("GET",a):new m(a,b)}var o=a("emitter"),p=a("reduce"),q="undefined"==typeof window?this||self:window;n.getXHR=function(){if(!(!q.XMLHttpRequest||q.location&&"file:"==q.location.protocol&&q.ActiveXObject))return new XMLHttpRequest;try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(a){}return!1};var r="".trim?function(a){return a.trim()}:function(a){return a.replace(/(^\s*|\s*$)/g,"")};n.serializeObject=g,n.parseString=h,n.types={html:"text/html",json:"application/json",xml:"application/xml",urlencoded:"application/x-www-form-urlencoded",form:"application/x-www-form-urlencoded","form-data":"application/x-www-form-urlencoded"},n.serialize={"application/x-www-form-urlencoded":g,"application/json":JSON.stringify},n.parse={"application/x-www-form-urlencoded":h,"application/json":JSON.parse},l.prototype.get=function(a){return this.header[a.toLowerCase()]},l.prototype.setHeaderProperties=function(a){var b=this.header["content-type"]||"";this.type=j(b);var c=k(b);for(var d in c)this[d]=c[d]},l.prototype.parseBody=function(a){var b=n.parse[this.type];return b&&a&&(a.length||a instanceof Object)?b(a):null},l.prototype.setStatusProperties=function(a){1223===a&&(a=204);var b=a/100|0;this.status=a,this.statusType=b,this.info=1==b,this.ok=2==b,this.clientError=4==b,this.serverError=5==b,this.error=4==b||5==b?this.toError():!1,this.accepted=202==a,this.noContent=204==a,this.badRequest=400==a,this.unauthorized=401==a,this.notAcceptable=406==a,this.notFound=404==a,this.forbidden=403==a},l.prototype.toError=function(){var a=this.req,b=a.method,c=a.url,d="cannot "+b+" "+c+" ("+this.status+")",e=new Error(d);return e.status=this.status,e.method=b,e.url=c,e},n.Response=l,o(m.prototype),m.prototype.use=function(a){return a(this),this},m.prototype.timeout=function(a){return this._timeout=a,this},m.prototype.clearTimeout=function(){return this._timeout=0,clearTimeout(this._timer),this},m.prototype.abort=function(){return this.aborted?void 0:(this.aborted=!0,this.xhr.abort(),
+this.clearTimeout(),this.emit("abort"),this)},m.prototype.set=function(a,b){if(f(a)){for(var c in a)this.set(c,a[c]);return this}return this._header[a.toLowerCase()]=b,this.header[a]=b,this},m.prototype.unset=function(a){return delete this._header[a.toLowerCase()],delete this.header[a],this},m.prototype.getHeader=function(a){return this._header[a.toLowerCase()]},m.prototype.type=function(a){return this.set("Content-Type",n.types[a]||a),this},m.prototype.accept=function(a){return this.set("Accept",n.types[a]||a),this},m.prototype.auth=function(a,b){var c=btoa(a+":"+b);return this.set("Authorization","Basic "+c),this},m.prototype.query=function(a){return"string"!=typeof a&&(a=g(a)),a&&this._query.push(a),this},m.prototype.field=function(a,b){return this._formData||(this._formData=new q.FormData),this._formData.append(a,b),this},m.prototype.attach=function(a,b,c){return this._formData||(this._formData=new q.FormData),this._formData.append(a,b,c),this},m.prototype.send=function(a){var b=f(a),c=this.getHeader("Content-Type");if(b&&f(this._data))for(var d in a)this._data[d]=a[d];else"string"==typeof a?(c||this.type("form"),c=this.getHeader("Content-Type"),"application/x-www-form-urlencoded"==c?this._data=this._data?this._data+"&"+a:a:this._data=(this._data||"")+a):this._data=a;return!b||e(a)?this:(c||this.type("json"),this)},m.prototype.callback=function(a,b){var c=this._callback;this.clearTimeout(),c(a,b)},m.prototype.crossDomainError=function(){var a=new Error("Origin is not allowed by Access-Control-Allow-Origin");a.crossDomain=!0,this.callback(a)},m.prototype.timeoutError=function(){var a=this._timeout,b=new Error("timeout of "+a+"ms exceeded");b.timeout=a,this.callback(b)},m.prototype.withCredentials=function(){return this._withCredentials=!0,this},m.prototype.end=function(a){var b=this,c=this.xhr=n.getXHR(),f=this._query.join("&"),g=this._timeout,h=this._formData||this._data;this._callback=a||d,c.onreadystatechange=function(){if(4==c.readyState){var a;try{a=c.status}catch(d){a=0}if(0==a){if(b.timedout)return b.timeoutError();if(b.aborted)return;return b.crossDomainError()}b.emit("end")}};var i=function(a){a.total>0&&(a.percent=a.loaded/a.total*100),b.emit("progress",a)};this.hasListeners("progress")&&(c.onprogress=i);try{c.upload&&this.hasListeners("progress")&&(c.upload.onprogress=i)}catch(j){}if(g&&!this._timer&&(this._timer=setTimeout(function(){b.timedout=!0,b.abort()},g)),f&&(f=n.serializeObject(f),this.url+=~this.url.indexOf("?")?"&"+f:"?"+f),c.open(this.method,this.url,!0),this._withCredentials&&(c.withCredentials=!0),"GET"!=this.method&&"HEAD"!=this.method&&"string"!=typeof h&&!e(h)){var k=this.getHeader("Content-Type"),l=n.serialize[k?k.split(";")[0]:""];l&&(h=l(h))}for(var m in this.header)null!=this.header[m]&&c.setRequestHeader(m,this.header[m]);return this.emit("request",this),c.send(h),this},m.prototype.then=function(a,b){return this.end(function(c,d){c?b(c):a(d)})},n.Request=m,n.get=function(a,b,c){var d=n("GET",a);return"function"==typeof b&&(c=b,b=null),b&&d.query(b),c&&d.end(c),d},n.head=function(a,b,c){var d=n("HEAD",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},n.del=function(a,b){var c=n("DELETE",a);return b&&c.end(b),c},n.patch=function(a,b,c){var d=n("PATCH",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},n.post=function(a,b,c){var d=n("POST",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},n.put=function(a,b,c){var d=n("PUT",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},b.exports=n},{emitter:12,reduce:13}],12:[function(a,b,c){function d(a){return a?e(a):void 0}function e(a){for(var b in d.prototype)a[b]=d.prototype[b];return a}b.exports=d,d.prototype.on=d.prototype.addEventListener=function(a,b){return this._callbacks=this._callbacks||{},(this._callbacks[a]=this._callbacks[a]||[]).push(b),this},d.prototype.once=function(a,b){function c(){d.off(a,c),b.apply(this,arguments)}var d=this;return this._callbacks=this._callbacks||{},c.fn=b,this.on(a,c),this},d.prototype.off=d.prototype.removeListener=d.prototype.removeAllListeners=d.prototype.removeEventListener=function(a,b){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var c=this._callbacks[a];if(!c)return this;if(1==arguments.length)return delete this._callbacks[a],this;for(var d,e=0;ed;++d)c[d].apply(this,b)}return this},d.prototype.listeners=function(a){return this._callbacks=this._callbacks||{},this._callbacks[a]||[]},d.prototype.hasListeners=function(a){return!!this.listeners(a).length}},{}],13:[function(a,b,c){b.exports=function(a,b,c){for(var d=0,e=a.length,f=3==arguments.length?c:a[d++];e>d;)f=b.call(null,f,a[d],++d,a);return f}},{}],14:[function(a,b,c){function d(a,b,c){var d;return d=b?new f(a,b):new f(a)}var e=function(){return this}(),f=e.WebSocket||e.MozWebSocket;b.exports=f?d:null,f&&(d.prototype=f.prototype)},{}]},{},[5])(5)});
\ No newline at end of file
diff --git a/web-dist/discord.min.3.3.2.js b/web-dist/discord.min.3.3.2.js
new file mode 100644
index 000000000..9a41bcaad
--- /dev/null
+++ b/web-dist/discord.min.3.3.2.js
@@ -0,0 +1,2 @@
+!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.Discord=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g]*>/g)||[])[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;a.push(h.substring(2,h.length-1))}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return a}"function"==typeof c&&(d=c,c=!1),b=e+n(b);var p=o();f.resolveDestination(a).then(k)["catch"](j)});return g}},{key:"createws",value:function(a){if(this.websocket)return!1;var b=this;this.websocket=new o(a),this.websocket.onopen=function(){b.trySendConnData()},this.websocket.onclose=function(){b.trigger("disconnected")},this.websocket.onmessage=function(a){var c=!1,d={};try{c=JSON.parse(a.data),d=c.d}catch(e){return void b.trigger("error",e,a)}switch(c.t){case"READY":b.debug("received ready packet"),b.user=b.addUser(d.user);var f=!0,g=!1,i=void 0;try{for(var j,l=d.guilds[Symbol.iterator]();!(f=(j=l.next()).done);f=!0)var m=j.value,n=b.addServer(m)}catch(e){g=!0,i=e}finally{try{!f&&l["return"]&&l["return"]()}finally{if(g)throw i}}var o=!0,p=!1,q=void 0;try{for(var r,s=d.private_channels[Symbol.iterator]();!(o=(r=s.next()).done);o=!0){var t=r.value;b.addPMChannel(t)}}catch(e){p=!0,q=e}finally{try{!o&&s["return"]&&s["return"]()}finally{if(p)throw q}}b.trigger("ready"),b.readyTime=Date.now(),b.debug("cached "+b.serverCache.length+" servers, "+b.channelCache.length+" channels, "+b.pmChannelCache.length+" PMs and "+b.userCache.length+" users."),b.state=3,setInterval(function(){b.keepAlive.apply(b)},d.heartbeat_interval);break;case"MESSAGE_CREATE":b.debug("received message");var u=[];d.mentions=d.mentions||[];var v=!0,w=!1,x=void 0;try{for(var y,z=d.mentions[Symbol.iterator]();!(v=(y=z.next()).done);v=!0){var A=y.value;u.push(b.addUser(A))}}catch(e){w=!0,x=e}finally{try{!v&&z["return"]&&z["return"]()}finally{if(w)throw x}}var B=b.getChannel("id",d.channel_id);if(B){var C=B.addMessage(new k(d,B,u,b.addUser(d.author)));b.trigger("message",C)}break;case"MESSAGE_DELETE":b.debug("message deleted");var B=b.getChannel("id",d.channel_id),D=B.getMessage("id",d.id);D?(b.trigger("messageDelete",B,D),B.messages.splice(B.messages.indexOf(D),1)):b.trigger("messageDelete",B);break;case"MESSAGE_UPDATE":b.debug("message updated");var B=b.getChannel("id",d.channel_id),E=B.getMessage("id",d.id);if(E){var F={};for(var G in E)F[G]=E[G];for(var G in d)F[G]=d[G];var u=[],H=!0,I=!1,J=void 0;try{for(var K,L=F.mentions[Symbol.iterator]();!(H=(K=L.next()).done);H=!0){var A=K.value;u.push(b.addUser(A))}}catch(e){I=!0,J=e}finally{try{!H&&L["return"]&&L["return"]()}finally{if(I)throw J}}var M=new k(F,B,u,E.author);b.trigger("messageUpdate",M,E),B.messages[B.messages.indexOf(E)]=M}break;case"GUILD_DELETE":var n=b.getServer("id",d.id);n&&(b.serverCache.splice(b.serverCache.indexOf(n),1),b.trigger("serverDelete",n));break;case"CHANNEL_DELETE":var B=b.getChannel("id",d.id);if(B){var n=B.server;n&&n.channels.splice(n.channels.indexOf(B),1),b.trigger("channelDelete",B),b.serverCache.splice(b.serverCache.indexOf(B),1)}break;case"GUILD_CREATE":var n=b.getServer("id",d.id);if(n||(n=b.addServer(d)),b.serverCreateListener.get(d.id)){var N=b.serverCreateListener.get(d.id);N[0](n),N[1](null,n),b.serverCreateListener["delete"](d.id)}b.trigger("serverCreate",n);break;case"CHANNEL_CREATE":var B=b.getChannel("id",d.id);if(!B){var O=b.addChannel(d,d.guild_id),P=b.getServer("id",d.guild_id);P&&P.addChannel(O),b.trigger("channelCreate",O)}break;case"GUILD_MEMBER_ADD":var n=b.getServer("id",d.guild_id);if(n){var Q=b.addUser(d.user);~n.members.indexOf(Q)||n.members.push(Q),b.trigger("serverNewMember",Q,n)}break;case"GUILD_MEMBER_REMOVE":var n=b.getServer("id",d.guild_id);if(n){var Q=b.addUser(d.user);~n.members.indexOf(Q)&&n.members.splice(n.members.indexOf(Q),1),b.trigger("serverRemoveMember",Q,n)}break;case"USER_UPDATE":if(b.user&&d.id===b.user.id){var R=new h(d);b.trigger("userUpdate",R,b.user),~b.userCache.indexOf(b.user)&&(b.userCache[b.userCache.indexOf(b.user)]=R),b.user=R}break;case"PRESENCE_UPDATE":var S=b.getUser("id",d.user.id);if(S){var T=new h(d.user);T.equalsStrict(S)?b.trigger("presence",{user:S,status:d.status,server:b.getServer("id",d.guild_id),gameId:d.game_id}):(b.trigger("userUpdate",S,T),b.userCache[b.userCache.indexOf(S)]=T)}break;default:b.debug("received unknown packet"),b.trigger("unknown",c)}}}},{key:"addUser",value:function(a){return this.getUser("id",a.id)||this.userCache.push(new h(a)),this.getUser("id",a.id)}},{key:"addChannel",value:function(a,b){return this.getChannel("id",a.id)||this.channelCache.push(new j(a,this.getServer("id",b))),this.getChannel("id",a.id)}},{key:"addPMChannel",value:function(a){return this.getPMChannel("id",a.id)||this.pmChannelCache.push(new m(a,this)),this.getPMChannel("id",a.id)}},{key:"addServer",value:function(a){var b=this.getServer("id",a.id);if(!b&&(b=new i(a,this),this.serverCache.push(b),a.channels)){var c=!0,d=!1,e=void 0;try{for(var f,g=a.channels[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;b.channels.push(this.addChannel(h,b.id))}}catch(j){d=!0,e=j}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}}return b}},{key:"getUser",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.userCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"getChannel",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.channelCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return this.getPMChannel(a,b)}},{key:"getPMChannel",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.pmChannelCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"getServer",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.serverCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"trySendConnData",value:function(){if(this.token&&!this.alreadySentData){this.alreadySentData=!0;var a={op:2,d:{token:this.token,v:2,properties:{$os:"discord.js",$browser:"discord.js",$device:"discord.js",$referrer:"",$referring_domain:""}}};this.websocket.send(JSON.stringify(a))}}},{key:"resolveServerID",value:function(a){return a instanceof i?a.id:!isNaN(a)&&a.length&&17===a.length?a:void 0}},{key:"resolveDestination",value:function(a){var b=!1,c=this;return new Promise(function(d,e){if(a instanceof i)b=a.id;else if(a instanceof j)b=a.id;else if(a instanceof k)b=a.channel.id;else if(a instanceof h){var f=!0,g=!1,l=void 0;try{for(var m,n=c.pmChannelCache[Symbol.iterator]();!(f=(m=n.next()).done);f=!0){var o=m.value;if(o.user.equals(a))return void d(o.id)}}catch(p){g=!0,l=p}finally{try{!f&&n["return"]&&n["return"]()}finally{if(g)throw l}}c.startPM(a).then(function(a){console.log(a),d(a.id)})["catch"](e)}else b=a;b&&d(b)})}},{key:"_sendMessage",value:function(a,b,c,d){var e=this;return new Promise(function(f,h){n.post(g.CHANNELS+"/"+a+"/messages").set("authorization",e.token).send({content:b,mentions:d,tts:c}).end(function(a,b){if(a)h(a);else{var c=b.body,d=[];c.mentions=c.mentions||[];var g=!0,i=!1,j=void 0;try{for(var l,m=c.mentions[Symbol.iterator]();!(g=(l=m.next()).done);g=!0){var n=l.value;d.push(e.addUser(n))}}catch(a){i=!0,j=a}finally{try{!g&&m["return"]&&m["return"]()}finally{if(i)throw j}}var o=e.getChannel("id",c.channel_id);if(o){var p=o.addMessage(new k(c,o,d,e.addUser(c.author)));f(p)}}})})}},{key:"_sendFile",value:function(a,b){var c=arguments.length<=2||void 0===arguments[2]?"DEFAULT BECAUSE YOU DIDN'T SPECIFY WHY.png":arguments[2],d=this;return new Promise(function(e,f){n.post(g.CHANNELS+"/"+a+"/messages").set("authorization",d.token).attach("file",b,c).end(function(b,c){if(b)f(b);else{var g=d.getChannel("id",a);if(g){var h=g.addMessage(new k(c.body,g,[],d.user));e(h)}}})})}},{key:"_updateMessage",value:function(a,b){var c=this;return new Promise(function(d,e){n.patch(g.CHANNELS+"/"+a.channel.id+"/messages/"+a.id).set("authorization",c.token).send({content:b,mentions:[]}).end(function(b,c){if(b)e(b);else{var f=new k(c.body,a.channel,a.mentions,a.sender);d(f),a.channel.messages[a.channel.messages.indexOf(a)]=f}})})}},{key:"_deleteMessage",value:function(a){var b=this;return new Promise(function(c,d){n.del(g.CHANNELS+"/"+a.channel.id+"/messages/"+a.id).set("authorization",b.token).end(function(a,b){a?d(a):c()})})}},{key:"checkQueue",value:function(a){var b=this,c=this;this.checkingQueue[a]||!function(){var d=function f(){if(0===c.queue[a].length)return void e();var b=c.queue[a][0];switch(b.action){case"sendMessage":var d=b;c._sendMessage(a,d.content,d.tts,d.mentions).then(function(b){d.then(b),c.queue[a].shift(),f()})["catch"](function(b){d.error(b),c.queue[a].shift(),f()});break;case"sendFile":var g=b;c._sendFile(a,g.attachment,g.attachmentName).then(function(b){g.then(b),c.queue[a].shift(),f()})["catch"](function(b){g.error(b),c.queue[a].shift(),f()});break;case"updateMessage":var h=b;c._updateMessage(h.message,h.content).then(function(b){h.then(b),c.queue[a].shift(),f()})["catch"](function(b){h.error(b),c.queue[a].shift(),f()});break;case"deleteMessage":var i=b;c._deleteMessage(i.message).then(function(b){i.then(b),c.queue[a].shift(),f()})["catch"](function(b){i.error(b),c.queue[a].shift(),f()});break;default:e()}},e=function(){c.checkingQueue[a]=!1};b.checkingQueue[a]=!0,d()}()}},{key:"uptime",get:function(){return this.readyTime?Date.now()-this.readyTime:null}},{key:"ready",get:function(){return 3===this.state}},{key:"servers",get:function(){return this.serverCache}},{key:"channels",get:function(){return this.channelCache}},{key:"users",get:function(){return this.userCache}},{key:"PMChannels",get:function(){return this.pmChannelCache}},{key:"messages",get:function(){var a=[],b=!0,c=!1,d=void 0;try{for(var e,f=this.channelCache[Symbol.iterator]();!(b=(e=f.next()).done);b=!0){var g=e.value;a=a.concat(g.messages)}}catch(h){c=!0,d=h}finally{try{!b&&f["return"]&&f["return"]()}finally{if(c)throw d}}return a}}]),a}();b.exports=r},{"./Endpoints.js":2,"./PMChannel.js":3,"./channel.js":4,"./invite.js":6,"./message.js":7,"./server.js":8,"./user.js":9,fs:10,superagent:11,ws:14}],2:[function(a,b,c){"use strict";c.BASE_DOMAIN="discordapp.com",c.BASE="https://"+c.BASE_DOMAIN,c.WEBSOCKET_HUB="wss://"+c.BASE_DOMAIN+"/hub",c.API=c.BASE+"/api",c.AUTH=c.API+"/auth",c.LOGIN=c.AUTH+"/login",c.LOGOUT=c.AUTH+"/logout",c.USERS=c.API+"/users",c.SERVERS=c.API+"/guilds",c.CHANNELS=c.API+"/channels"},{}],3:[function(a,b,c){"use strict";function d(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}var e=function(){function a(a,b){for(var c=0;c"}},{key:"toString",value:function(){return this.mention()}},{key:"equals",value:function(a){return a.id===this.id}},{key:"equalsStrict",value:function(a){return a.id===this.id&&a.avatar===this.avatar&&a.username===this.username&&a.discriminator===this.discriminator}},{key:"avatarURL",get:function(){return this.avatar?"https://discordapp.com/api/users/"+this.id+"/avatars/"+this.avatar+".jpg":null}}]),a}();b.exports=f},{}],10:[function(a,b,c){},{}],11:[function(a,b,c){function d(){}function e(a){var b={}.toString.call(a);switch(b){case"[object File]":case"[object Blob]":case"[object FormData]":return!0;default:return!1}}function f(a){return a===Object(a)}function g(a){if(!f(a))return a;var b=[];for(var c in a)null!=a[c]&&b.push(encodeURIComponent(c)+"="+encodeURIComponent(a[c]));return b.join("&")}function h(a){for(var b,c,d={},e=a.split("&"),f=0,g=e.length;g>f;++f)c=e[f],b=c.split("="),d[decodeURIComponent(b[0])]=decodeURIComponent(b[1]);return d}function i(a){var b,c,d,e,f=a.split(/\r?\n/),g={};f.pop();for(var h=0,i=f.length;i>h;++h)c=f[h],b=c.indexOf(":"),d=c.slice(0,b).toLowerCase(),e=r(c.slice(b+1)),g[d]=e;return g}function j(a){return a.split(/ *; */).shift()}function k(a){return p(a.split(/ *; */),function(a,b){var c=b.split(/ *= */),d=c.shift(),e=c.shift();return d&&e&&(a[d]=e),a},{})}function l(a,b){b=b||{},this.req=a,this.xhr=this.req.xhr,this.text="HEAD"!=this.req.method&&(""===this.xhr.responseType||"text"===this.xhr.responseType)||"undefined"==typeof this.xhr.responseType?this.xhr.responseText:null,this.statusText=this.req.xhr.statusText,this.setStatusProperties(this.xhr.status),this.header=this.headers=i(this.xhr.getAllResponseHeaders()),this.header["content-type"]=this.xhr.getResponseHeader("content-type"),this.setHeaderProperties(this.header),this.body="HEAD"!=this.req.method?this.parseBody(this.text?this.text:this.xhr.response):null}function m(a,b){var c=this;o.call(this),this._query=this._query||[],this.method=a,this.url=b,this.header={},this._header={},this.on("end",function(){var a=null,b=null;try{b=new l(c)}catch(d){return a=new Error("Parser is unable to parse the response"),a.parse=!0,a.original=d,c.callback(a)}if(c.emit("response",b),a)return c.callback(a,b);if(b.status>=200&&b.status<300)return c.callback(a,b);var e=new Error(b.statusText||"Unsuccessful HTTP response");e.original=a,e.response=b,e.status=b.status,c.callback(e,b)})}function n(a,b){return"function"==typeof b?new m("GET",a).end(b):1==arguments.length?new m("GET",a):new m(a,b)}var o=a("emitter"),p=a("reduce"),q="undefined"==typeof window?this||self:window;n.getXHR=function(){if(!(!q.XMLHttpRequest||q.location&&"file:"==q.location.protocol&&q.ActiveXObject))return new XMLHttpRequest;try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(a){}return!1};var r="".trim?function(a){return a.trim()}:function(a){return a.replace(/(^\s*|\s*$)/g,"")};n.serializeObject=g,n.parseString=h,n.types={html:"text/html",json:"application/json",xml:"application/xml",urlencoded:"application/x-www-form-urlencoded",form:"application/x-www-form-urlencoded","form-data":"application/x-www-form-urlencoded"},n.serialize={"application/x-www-form-urlencoded":g,"application/json":JSON.stringify},n.parse={"application/x-www-form-urlencoded":h,"application/json":JSON.parse},l.prototype.get=function(a){return this.header[a.toLowerCase()]},l.prototype.setHeaderProperties=function(a){var b=this.header["content-type"]||"";this.type=j(b);var c=k(b);for(var d in c)this[d]=c[d]},l.prototype.parseBody=function(a){var b=n.parse[this.type];return b&&a&&(a.length||a instanceof Object)?b(a):null},l.prototype.setStatusProperties=function(a){1223===a&&(a=204);var b=a/100|0;this.status=a,this.statusType=b,this.info=1==b,this.ok=2==b,this.clientError=4==b,this.serverError=5==b,this.error=4==b||5==b?this.toError():!1,this.accepted=202==a,this.noContent=204==a,this.badRequest=400==a,this.unauthorized=401==a,this.notAcceptable=406==a,this.notFound=404==a,this.forbidden=403==a},l.prototype.toError=function(){var a=this.req,b=a.method,c=a.url,d="cannot "+b+" "+c+" ("+this.status+")",e=new Error(d);return e.status=this.status,e.method=b,e.url=c,e},n.Response=l,o(m.prototype),m.prototype.use=function(a){return a(this),this},m.prototype.timeout=function(a){return this._timeout=a,this},m.prototype.clearTimeout=function(){return this._timeout=0,clearTimeout(this._timer),this},m.prototype.abort=function(){return this.aborted?void 0:(this.aborted=!0,
+this.xhr.abort(),this.clearTimeout(),this.emit("abort"),this)},m.prototype.set=function(a,b){if(f(a)){for(var c in a)this.set(c,a[c]);return this}return this._header[a.toLowerCase()]=b,this.header[a]=b,this},m.prototype.unset=function(a){return delete this._header[a.toLowerCase()],delete this.header[a],this},m.prototype.getHeader=function(a){return this._header[a.toLowerCase()]},m.prototype.type=function(a){return this.set("Content-Type",n.types[a]||a),this},m.prototype.accept=function(a){return this.set("Accept",n.types[a]||a),this},m.prototype.auth=function(a,b){var c=btoa(a+":"+b);return this.set("Authorization","Basic "+c),this},m.prototype.query=function(a){return"string"!=typeof a&&(a=g(a)),a&&this._query.push(a),this},m.prototype.field=function(a,b){return this._formData||(this._formData=new q.FormData),this._formData.append(a,b),this},m.prototype.attach=function(a,b,c){return this._formData||(this._formData=new q.FormData),this._formData.append(a,b,c),this},m.prototype.send=function(a){var b=f(a),c=this.getHeader("Content-Type");if(b&&f(this._data))for(var d in a)this._data[d]=a[d];else"string"==typeof a?(c||this.type("form"),c=this.getHeader("Content-Type"),"application/x-www-form-urlencoded"==c?this._data=this._data?this._data+"&"+a:a:this._data=(this._data||"")+a):this._data=a;return!b||e(a)?this:(c||this.type("json"),this)},m.prototype.callback=function(a,b){var c=this._callback;this.clearTimeout(),c(a,b)},m.prototype.crossDomainError=function(){var a=new Error("Origin is not allowed by Access-Control-Allow-Origin");a.crossDomain=!0,this.callback(a)},m.prototype.timeoutError=function(){var a=this._timeout,b=new Error("timeout of "+a+"ms exceeded");b.timeout=a,this.callback(b)},m.prototype.withCredentials=function(){return this._withCredentials=!0,this},m.prototype.end=function(a){var b=this,c=this.xhr=n.getXHR(),f=this._query.join("&"),g=this._timeout,h=this._formData||this._data;this._callback=a||d,c.onreadystatechange=function(){if(4==c.readyState){var a;try{a=c.status}catch(d){a=0}if(0==a){if(b.timedout)return b.timeoutError();if(b.aborted)return;return b.crossDomainError()}b.emit("end")}};var i=function(a){a.total>0&&(a.percent=a.loaded/a.total*100),b.emit("progress",a)};this.hasListeners("progress")&&(c.onprogress=i);try{c.upload&&this.hasListeners("progress")&&(c.upload.onprogress=i)}catch(j){}if(g&&!this._timer&&(this._timer=setTimeout(function(){b.timedout=!0,b.abort()},g)),f&&(f=n.serializeObject(f),this.url+=~this.url.indexOf("?")?"&"+f:"?"+f),c.open(this.method,this.url,!0),this._withCredentials&&(c.withCredentials=!0),"GET"!=this.method&&"HEAD"!=this.method&&"string"!=typeof h&&!e(h)){var k=this.getHeader("Content-Type"),l=n.serialize[k?k.split(";")[0]:""];l&&(h=l(h))}for(var m in this.header)null!=this.header[m]&&c.setRequestHeader(m,this.header[m]);return this.emit("request",this),c.send(h),this},m.prototype.then=function(a,b){return this.end(function(c,d){c?b(c):a(d)})},n.Request=m,n.get=function(a,b,c){var d=n("GET",a);return"function"==typeof b&&(c=b,b=null),b&&d.query(b),c&&d.end(c),d},n.head=function(a,b,c){var d=n("HEAD",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},n.del=function(a,b){var c=n("DELETE",a);return b&&c.end(b),c},n.patch=function(a,b,c){var d=n("PATCH",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},n.post=function(a,b,c){var d=n("POST",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},n.put=function(a,b,c){var d=n("PUT",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},b.exports=n},{emitter:12,reduce:13}],12:[function(a,b,c){function d(a){return a?e(a):void 0}function e(a){for(var b in d.prototype)a[b]=d.prototype[b];return a}b.exports=d,d.prototype.on=d.prototype.addEventListener=function(a,b){return this._callbacks=this._callbacks||{},(this._callbacks[a]=this._callbacks[a]||[]).push(b),this},d.prototype.once=function(a,b){function c(){d.off(a,c),b.apply(this,arguments)}var d=this;return this._callbacks=this._callbacks||{},c.fn=b,this.on(a,c),this},d.prototype.off=d.prototype.removeListener=d.prototype.removeAllListeners=d.prototype.removeEventListener=function(a,b){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var c=this._callbacks[a];if(!c)return this;if(1==arguments.length)return delete this._callbacks[a],this;for(var d,e=0;ed;++d)c[d].apply(this,b)}return this},d.prototype.listeners=function(a){return this._callbacks=this._callbacks||{},this._callbacks[a]||[]},d.prototype.hasListeners=function(a){return!!this.listeners(a).length}},{}],13:[function(a,b,c){b.exports=function(a,b,c){for(var d=0,e=a.length,f=3==arguments.length?c:a[d++];e>d;)f=b.call(null,f,a[d],++d,a);return f}},{}],14:[function(a,b,c){function d(a,b,c){var d;return d=b?new f(a,b):new f(a)}var e=function(){return this}(),f=e.WebSocket||e.MozWebSocket;b.exports=f?d:null,f&&(d.prototype=f.prototype)},{}]},{},[5])(5)});
\ No newline at end of file
diff --git a/web-dist/discord.min.3.4.0.js b/web-dist/discord.min.3.4.0.js
new file mode 100644
index 000000000..9028bea6a
--- /dev/null
+++ b/web-dist/discord.min.3.4.0.js
@@ -0,0 +1,2 @@
+!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.Discord=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g]*>/g)||[])[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;a.push(h.substring(2,h.length-1))}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return a}"function"==typeof c&&(d=c,c=!1),b=e+n(b);var p=o();f.resolveDestination(a).then(k)["catch"](j)});return g}},{key:"createws",value:function(a){if(this.websocket)return!1;var b=this;this.websocket=new n(a),this.websocket.onopen=function(){b.trySendConnData()},this.websocket.onclose=function(){b.trigger("disconnected")},this.websocket.onmessage=function(a){var c=!1,d={};try{c=JSON.parse(a.data),d=c.d}catch(e){return void b.trigger("error",e,a)}switch(c.t){case"READY":b.debug("received ready packet"),b.user=b.addUser(d.user);var f=!0,h=!1,i=void 0;try{for(var k,l=d.guilds[Symbol.iterator]();!(f=(k=l.next()).done);f=!0)var m=k.value,n=b.addServer(m)}catch(e){h=!0,i=e}finally{try{!f&&l["return"]&&l["return"]()}finally{if(h)throw i}}var o=!0,p=!1,q=void 0;try{for(var r,s=d.private_channels[Symbol.iterator]();!(o=(r=s.next()).done);o=!0){var t=r.value;b.addPMChannel(t)}}catch(e){p=!0,q=e}finally{try{!o&&s["return"]&&s["return"]()}finally{if(p)throw q}}b.trigger("ready"),b.readyTime=Date.now(),b.debug("cached "+b.serverCache.length+" servers, "+b.channelCache.length+" channels, "+b.pmChannelCache.length+" PMs and "+b.userCache.length+" users."),b.state=3,setInterval(function(){b.keepAlive.apply(b)},d.heartbeat_interval);break;case"MESSAGE_CREATE":b.debug("received message");var u=[];d.mentions=d.mentions||[];var v=!0,w=!1,x=void 0;try{for(var y,z=d.mentions[Symbol.iterator]();!(v=(y=z.next()).done);v=!0){var A=y.value;u.push(b.addUser(A))}}catch(e){w=!0,x=e}finally{try{!v&&z["return"]&&z["return"]()}finally{if(w)throw x}}var B=b.getChannel("id",d.channel_id);if(B){var C=B.addMessage(new j(d,B,u,b.addUser(d.author)));b.trigger("message",C)}break;case"MESSAGE_DELETE":b.debug("message deleted");var B=b.getChannel("id",d.channel_id),D=B.getMessage("id",d.id);D?(b.trigger("messageDelete",B,D),B.messages.splice(B.messages.indexOf(D),1)):b.trigger("messageDelete",B);break;case"MESSAGE_UPDATE":b.debug("message updated");var B=b.getChannel("id",d.channel_id),E=B.getMessage("id",d.id);if(E){var F={};for(var G in E)F[G]=E[G];for(var G in d)F[G]=d[G];var u=[],H=!0,I=!1,J=void 0;try{for(var K,L=F.mentions[Symbol.iterator]();!(H=(K=L.next()).done);H=!0){var A=K.value;u.push(b.addUser(A))}}catch(e){I=!0,J=e}finally{try{!H&&L["return"]&&L["return"]()}finally{if(I)throw J}}var M=new j(F,B,u,E.author);b.trigger("messageUpdate",M,E),B.messages[B.messages.indexOf(E)]=M}break;case"GUILD_DELETE":var n=b.getServer("id",d.id);n&&(b.serverCache.splice(b.serverCache.indexOf(n),1),b.trigger("serverDelete",n));break;case"CHANNEL_DELETE":var B=b.getChannel("id",d.id);if(B){var n=B.server;n&&n.channels.splice(n.channels.indexOf(B),1),b.trigger("channelDelete",B),b.serverCache.splice(b.serverCache.indexOf(B),1)}break;case"GUILD_CREATE":var n=b.getServer("id",d.id);if(n||(n=b.addServer(d)),b.serverCreateListener[d.id]){var N=b.serverCreateListener[d.id];N[0](n),N[1](null,n),b.serverCreateListener[d.id]=null}b.trigger("serverCreate",n);break;case"CHANNEL_CREATE":var B=b.getChannel("id",d.id);if(!B){var O=b.addChannel(d,d.guild_id),P=b.getServer("id",d.guild_id);P&&P.addChannel(O),b.trigger("channelCreate",O)}break;case"GUILD_MEMBER_ADD":var n=b.getServer("id",d.guild_id);if(n){var Q=b.addUser(d.user);~n.members.indexOf(Q)||n.members.push(Q),b.trigger("serverNewMember",Q,n)}break;case"GUILD_MEMBER_REMOVE":var n=b.getServer("id",d.guild_id);if(n){var Q=b.addUser(d.user);~n.members.indexOf(Q)&&n.members.splice(n.members.indexOf(Q),1),b.trigger("serverRemoveMember",Q,n)}break;case"USER_UPDATE":if(b.user&&d.id===b.user.id){var R=new g(d);b.trigger("userUpdate",R,b.user),~b.userCache.indexOf(b.user)&&(b.userCache[b.userCache.indexOf(b.user)]=R),b.user=R}break;case"PRESENCE_UPDATE":var S=b.getUser("id",d.user.id);if(S){var T=new g(d.user);T.equalsStrict(S)?(S.status=d.status,b.trigger("presence",{user:S,status:d.status,server:b.getServer("id",d.guild_id),gameId:d.game_id})):(b.trigger("userUpdate",S,T),b.userCache[b.userCache.indexOf(S)]=T)}break;default:b.debug("received unknown packet"),b.trigger("unknown",c)}}}},{key:"addUser",value:function(a){return this.getUser("id",a.id)||this.userCache.push(new g(a)),this.getUser("id",a.id)}},{key:"addChannel",value:function(a,b){return this.getChannel("id",a.id)||this.channelCache.push(new i(a,this.getServer("id",b))),this.getChannel("id",a.id)}},{key:"addPMChannel",value:function(a){return this.getPMChannel("id",a.id)||this.pmChannelCache.push(new l(a,this)),this.getPMChannel("id",a.id)}},{key:"addServer",value:function(a){var b=this,c=this.getServer("id",a.id);if(!c&&(c=new h(a,this),this.serverCache.push(c),a.channels)){var d=!0,e=!1,f=void 0;try{for(var g,i=a.channels[Symbol.iterator]();!(d=(g=i.next()).done);d=!0){var j=g.value;c.channels.push(this.addChannel(j,c.id))}}catch(k){e=!0,f=k}finally{try{!d&&i["return"]&&i["return"]()}finally{if(e)throw f}}}var l=!0,m=!1,n=void 0;try{for(var o,p=a.presences[Symbol.iterator]();!(l=(o=p.next()).done);l=!0){var q=o.value;b.getUser("id",q.user.id).status=q.status}}catch(k){m=!0,n=k}finally{try{!l&&p["return"]&&p["return"]()}finally{if(m)throw n}}return c}},{key:"getUser",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.userCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"getChannel",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.channelCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return this.getPMChannel(a,b)}},{key:"getPMChannel",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.pmChannelCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"getServer",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.serverCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"trySendConnData",value:function(){if(this.token&&!this.alreadySentData){this.alreadySentData=!0;var a={op:2,d:{token:this.token,v:2,properties:{$os:"discord.js",$browser:"discord.js",$device:"discord.js",$referrer:"",$referring_domain:""}}};this.websocket.send(JSON.stringify(a))}}},{key:"resolveServerID",value:function(a){return a instanceof h?a.id:!isNaN(a)&&a.length&&17===a.length?a:void 0}},{key:"resolveDestination",value:function(a){var b=!1,c=this;return new Promise(function(d,e){if(a instanceof h)b=a.id;else if(a instanceof i)b=a.id;else if(a instanceof j)b=a.channel.id;else if(a instanceof g){var f=!0,k=!1,l=void 0;try{for(var m,n=c.pmChannelCache[Symbol.iterator]();!(f=(m=n.next()).done);f=!0){var o=m.value;if(o.user.equals(a))return void d(o.id)}}catch(p){k=!0,l=p}finally{try{!f&&n["return"]&&n["return"]()}finally{if(k)throw l}}c.startPM(a).then(function(a){console.log(a),d(a.id)})["catch"](e)}else b=a;b&&d(b)})}},{key:"_sendMessage",value:function(a,b,c,d){var e=this;return new Promise(function(g,h){m.post(f.CHANNELS+"/"+a+"/messages").set("authorization",e.token).send({content:b,mentions:d,tts:c}).end(function(a,b){if(a)h(a);else{var c=b.body,d=[];c.mentions=c.mentions||[];var f=!0,i=!1,k=void 0;try{for(var l,m=c.mentions[Symbol.iterator]();!(f=(l=m.next()).done);f=!0){var n=l.value;d.push(e.addUser(n))}}catch(a){i=!0,k=a}finally{try{!f&&m["return"]&&m["return"]()}finally{if(i)throw k}}var o=e.getChannel("id",c.channel_id);if(o){var p=o.addMessage(new j(c,o,d,e.addUser(c.author)));g(p)}}})})}},{key:"_sendFile",value:function(a,b){var c=arguments.length<=2||void 0===arguments[2]?"DEFAULT BECAUSE YOU DIDN'T SPECIFY WHY.png":arguments[2],d=this;return new Promise(function(e,g){m.post(f.CHANNELS+"/"+a+"/messages").set("authorization",d.token).attach("file",b,c).end(function(b,c){if(b)g(b);else{var f=d.getChannel("id",a);if(f){var h=f.addMessage(new j(c.body,f,[],d.user));e(h)}}})})}},{key:"_updateMessage",value:function(a,b){var c=this;return new Promise(function(d,e){m.patch(f.CHANNELS+"/"+a.channel.id+"/messages/"+a.id).set("authorization",c.token).send({content:b,mentions:[]}).end(function(b,c){if(b)e(b);else{var f=new j(c.body,a.channel,a.mentions,a.sender);d(f),a.channel.messages[a.channel.messages.indexOf(a)]=f}})})}},{key:"_deleteMessage",value:function(a){var b=this;return new Promise(function(c,d){m.del(f.CHANNELS+"/"+a.channel.id+"/messages/"+a.id).set("authorization",b.token).end(function(a,b){a?d(a):c()})})}},{key:"checkQueue",value:function(a){var b=this,c=this;this.checkingQueue[a]||!function(){var d=function f(){if(0===c.queue[a].length)return void e();var b=c.queue[a][0];switch(b.action){case"sendMessage":var d=b;c._sendMessage(a,d.content,d.tts,d.mentions).then(function(b){d.then(b),c.queue[a].shift(),f()})["catch"](function(b){d.error(b),c.queue[a].shift(),f()});break;case"sendFile":var g=b;c._sendFile(a,g.attachment,g.attachmentName).then(function(b){g.then(b),c.queue[a].shift(),f()})["catch"](function(b){g.error(b),c.queue[a].shift(),f()});break;case"updateMessage":var h=b;c._updateMessage(h.message,h.content).then(function(b){h.then(b),c.queue[a].shift(),f()})["catch"](function(b){h.error(b),c.queue[a].shift(),f()});break;case"deleteMessage":var i=b;c._deleteMessage(i.message).then(function(b){i.then(b),c.queue[a].shift(),f()})["catch"](function(b){i.error(b),c.queue[a].shift(),f()});break;default:e()}},e=function(){c.checkingQueue[a]=!1};b.checkingQueue[a]=!0,d()}()}},{key:"getGateway",value:function(){var a=this;return new Promise(function(b,c){m.get(f.API+"/gateway").set("authorization",a.token).end(function(a,d){a?c(a):b(d.body.url)})})}},{key:"uptime",get:function(){return this.readyTime?Date.now()-this.readyTime:null}},{key:"ready",get:function(){return 3===this.state}},{key:"servers",get:function(){return this.serverCache}},{key:"channels",get:function(){return this.channelCache}},{key:"users",get:function(){return this.userCache}},{key:"PMChannels",get:function(){return this.pmChannelCache}},{key:"messages",get:function(){var a=[],b=!0,c=!1,d=void 0;try{for(var e,f=this.channelCache[Symbol.iterator]();!(b=(e=f.next()).done);b=!0){var g=e.value;a=a.concat(g.messages)}}catch(h){c=!0,d=h}finally{try{!b&&f["return"]&&f["return"]()}finally{if(c)throw d}}return a}}]),a}();b.exports=q},{"./Endpoints.js":2,"./PMChannel.js":3,"./channel.js":4,"./invite.js":6,"./message.js":7,"./server.js":8,"./user.js":9,fs:10,superagent:11,ws:14}],2:[function(a,b,c){"use strict";c.BASE_DOMAIN="discordapp.com",c.BASE="https://"+c.BASE_DOMAIN,c.WEBSOCKET_HUB="wss://"+c.BASE_DOMAIN+"/hub",c.API=c.BASE+"/api",c.AUTH=c.API+"/auth",c.LOGIN=c.AUTH+"/login",c.LOGOUT=c.AUTH+"/logout",c.USERS=c.API+"/users",c.SERVERS=c.API+"/guilds",c.CHANNELS=c.API+"/channels"},{}],3:[function(a,b,c){"use strict";function d(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}var e=function(){function a(a,b){for(var c=0;c1e3&&this.messages.splice(0,1),this.getMessage("id",a.id)||this.messages.push(a),this.getMessage("id",a.id)}},{key:"getMessage",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.messages[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"toString",value:function(){return"<#"+this.id+">"}},{key:"client",get:function(){return this.server.client}},{key:"isPrivate",get:function(){return!1}},{key:"users",get:function(){return this.server.members}},{key:"members",get:function(){return this.server.members}}]),a}();b.exports=f},{}],5:[function(a,b,c){"use strict";var d=(a("superagent"),a("./Endpoints.js")),e=a("./Client.js"),f={Endpoints:d,Client:e};b.exports=f},{"./Client.js":1,"./Endpoints.js":2,superagent:11}],6:[function(a,b,c){"use strict";function d(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}var e=function(){function a(a,b){for(var c=0;c"}},{key:"toString",value:function(){return this.mention()}},{key:"equals",value:function(a){return a.id===this.id}},{key:"equalsStrict",value:function(a){return a.id===this.id&&a.avatar===this.avatar&&a.username===this.username&&a.discriminator===this.discriminator}},{key:"avatarURL",get:function(){return this.avatar?"https://discordapp.com/api/users/"+this.id+"/avatars/"+this.avatar+".jpg":null}}]),a}();b.exports=f},{}],10:[function(a,b,c){},{}],11:[function(a,b,c){function d(){}function e(a){var b={}.toString.call(a);switch(b){case"[object File]":case"[object Blob]":case"[object FormData]":return!0;default:return!1}}function f(a){return a===Object(a)}function g(a){if(!f(a))return a;var b=[];for(var c in a)null!=a[c]&&b.push(encodeURIComponent(c)+"="+encodeURIComponent(a[c]));return b.join("&")}function h(a){for(var b,c,d={},e=a.split("&"),f=0,g=e.length;g>f;++f)c=e[f],b=c.split("="),d[decodeURIComponent(b[0])]=decodeURIComponent(b[1]);return d}function i(a){var b,c,d,e,f=a.split(/\r?\n/),g={};f.pop();for(var h=0,i=f.length;i>h;++h)c=f[h],b=c.indexOf(":"),d=c.slice(0,b).toLowerCase(),e=r(c.slice(b+1)),g[d]=e;return g}function j(a){return a.split(/ *; */).shift()}function k(a){return p(a.split(/ *; */),function(a,b){var c=b.split(/ *= */),d=c.shift(),e=c.shift();return d&&e&&(a[d]=e),a},{})}function l(a,b){b=b||{},this.req=a,this.xhr=this.req.xhr,this.text="HEAD"!=this.req.method&&(""===this.xhr.responseType||"text"===this.xhr.responseType)||"undefined"==typeof this.xhr.responseType?this.xhr.responseText:null,this.statusText=this.req.xhr.statusText,this.setStatusProperties(this.xhr.status),this.header=this.headers=i(this.xhr.getAllResponseHeaders()),this.header["content-type"]=this.xhr.getResponseHeader("content-type"),this.setHeaderProperties(this.header),this.body="HEAD"!=this.req.method?this.parseBody(this.text?this.text:this.xhr.response):null}function m(a,b){var c=this;o.call(this),this._query=this._query||[],this.method=a,this.url=b,this.header={},this._header={},this.on("end",function(){var a=null,b=null;try{b=new l(c)}catch(d){return a=new Error("Parser is unable to parse the response"),a.parse=!0,a.original=d,c.callback(a)}if(c.emit("response",b),a)return c.callback(a,b);if(b.status>=200&&b.status<300)return c.callback(a,b);var e=new Error(b.statusText||"Unsuccessful HTTP response");e.original=a,e.response=b,e.status=b.status,c.callback(e,b)})}function n(a,b){return"function"==typeof b?new m("GET",a).end(b):1==arguments.length?new m("GET",a):new m(a,b)}var o=a("emitter"),p=a("reduce"),q="undefined"==typeof window?this||self:window;n.getXHR=function(){if(!(!q.XMLHttpRequest||q.location&&"file:"==q.location.protocol&&q.ActiveXObject))return new XMLHttpRequest;try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(a){}return!1};var r="".trim?function(a){return a.trim()}:function(a){return a.replace(/(^\s*|\s*$)/g,"")};n.serializeObject=g,n.parseString=h,n.types={html:"text/html",json:"application/json",xml:"application/xml",urlencoded:"application/x-www-form-urlencoded",form:"application/x-www-form-urlencoded","form-data":"application/x-www-form-urlencoded"},n.serialize={"application/x-www-form-urlencoded":g,"application/json":JSON.stringify},n.parse={"application/x-www-form-urlencoded":h,"application/json":JSON.parse},l.prototype.get=function(a){return this.header[a.toLowerCase()]},l.prototype.setHeaderProperties=function(a){var b=this.header["content-type"]||"";this.type=j(b);var c=k(b);for(var d in c)this[d]=c[d]},l.prototype.parseBody=function(a){var b=n.parse[this.type];return b&&a&&(a.length||a instanceof Object)?b(a):null},l.prototype.setStatusProperties=function(a){1223===a&&(a=204);var b=a/100|0;this.status=a,this.statusType=b,this.info=1==b,this.ok=2==b,this.clientError=4==b,this.serverError=5==b,this.error=4==b||5==b?this.toError():!1,this.accepted=202==a,this.noContent=204==a,this.badRequest=400==a,
+this.unauthorized=401==a,this.notAcceptable=406==a,this.notFound=404==a,this.forbidden=403==a},l.prototype.toError=function(){var a=this.req,b=a.method,c=a.url,d="cannot "+b+" "+c+" ("+this.status+")",e=new Error(d);return e.status=this.status,e.method=b,e.url=c,e},n.Response=l,o(m.prototype),m.prototype.use=function(a){return a(this),this},m.prototype.timeout=function(a){return this._timeout=a,this},m.prototype.clearTimeout=function(){return this._timeout=0,clearTimeout(this._timer),this},m.prototype.abort=function(){return this.aborted?void 0:(this.aborted=!0,this.xhr.abort(),this.clearTimeout(),this.emit("abort"),this)},m.prototype.set=function(a,b){if(f(a)){for(var c in a)this.set(c,a[c]);return this}return this._header[a.toLowerCase()]=b,this.header[a]=b,this},m.prototype.unset=function(a){return delete this._header[a.toLowerCase()],delete this.header[a],this},m.prototype.getHeader=function(a){return this._header[a.toLowerCase()]},m.prototype.type=function(a){return this.set("Content-Type",n.types[a]||a),this},m.prototype.accept=function(a){return this.set("Accept",n.types[a]||a),this},m.prototype.auth=function(a,b){var c=btoa(a+":"+b);return this.set("Authorization","Basic "+c),this},m.prototype.query=function(a){return"string"!=typeof a&&(a=g(a)),a&&this._query.push(a),this},m.prototype.field=function(a,b){return this._formData||(this._formData=new q.FormData),this._formData.append(a,b),this},m.prototype.attach=function(a,b,c){return this._formData||(this._formData=new q.FormData),this._formData.append(a,b,c),this},m.prototype.send=function(a){var b=f(a),c=this.getHeader("Content-Type");if(b&&f(this._data))for(var d in a)this._data[d]=a[d];else"string"==typeof a?(c||this.type("form"),c=this.getHeader("Content-Type"),"application/x-www-form-urlencoded"==c?this._data=this._data?this._data+"&"+a:a:this._data=(this._data||"")+a):this._data=a;return!b||e(a)?this:(c||this.type("json"),this)},m.prototype.callback=function(a,b){var c=this._callback;this.clearTimeout(),c(a,b)},m.prototype.crossDomainError=function(){var a=new Error("Origin is not allowed by Access-Control-Allow-Origin");a.crossDomain=!0,this.callback(a)},m.prototype.timeoutError=function(){var a=this._timeout,b=new Error("timeout of "+a+"ms exceeded");b.timeout=a,this.callback(b)},m.prototype.withCredentials=function(){return this._withCredentials=!0,this},m.prototype.end=function(a){var b=this,c=this.xhr=n.getXHR(),f=this._query.join("&"),g=this._timeout,h=this._formData||this._data;this._callback=a||d,c.onreadystatechange=function(){if(4==c.readyState){var a;try{a=c.status}catch(d){a=0}if(0==a){if(b.timedout)return b.timeoutError();if(b.aborted)return;return b.crossDomainError()}b.emit("end")}};var i=function(a){a.total>0&&(a.percent=a.loaded/a.total*100),b.emit("progress",a)};this.hasListeners("progress")&&(c.onprogress=i);try{c.upload&&this.hasListeners("progress")&&(c.upload.onprogress=i)}catch(j){}if(g&&!this._timer&&(this._timer=setTimeout(function(){b.timedout=!0,b.abort()},g)),f&&(f=n.serializeObject(f),this.url+=~this.url.indexOf("?")?"&"+f:"?"+f),c.open(this.method,this.url,!0),this._withCredentials&&(c.withCredentials=!0),"GET"!=this.method&&"HEAD"!=this.method&&"string"!=typeof h&&!e(h)){var k=this.getHeader("Content-Type"),l=n.serialize[k?k.split(";")[0]:""];l&&(h=l(h))}for(var m in this.header)null!=this.header[m]&&c.setRequestHeader(m,this.header[m]);return this.emit("request",this),c.send(h),this},m.prototype.then=function(a,b){return this.end(function(c,d){c?b(c):a(d)})},n.Request=m,n.get=function(a,b,c){var d=n("GET",a);return"function"==typeof b&&(c=b,b=null),b&&d.query(b),c&&d.end(c),d},n.head=function(a,b,c){var d=n("HEAD",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},n.del=function(a,b){var c=n("DELETE",a);return b&&c.end(b),c},n.patch=function(a,b,c){var d=n("PATCH",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},n.post=function(a,b,c){var d=n("POST",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},n.put=function(a,b,c){var d=n("PUT",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},b.exports=n},{emitter:12,reduce:13}],12:[function(a,b,c){function d(a){return a?e(a):void 0}function e(a){for(var b in d.prototype)a[b]=d.prototype[b];return a}b.exports=d,d.prototype.on=d.prototype.addEventListener=function(a,b){return this._callbacks=this._callbacks||{},(this._callbacks[a]=this._callbacks[a]||[]).push(b),this},d.prototype.once=function(a,b){function c(){d.off(a,c),b.apply(this,arguments)}var d=this;return this._callbacks=this._callbacks||{},c.fn=b,this.on(a,c),this},d.prototype.off=d.prototype.removeListener=d.prototype.removeAllListeners=d.prototype.removeEventListener=function(a,b){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var c=this._callbacks[a];if(!c)return this;if(1==arguments.length)return delete this._callbacks[a],this;for(var d,e=0;ed;++d)c[d].apply(this,b)}return this},d.prototype.listeners=function(a){return this._callbacks=this._callbacks||{},this._callbacks[a]||[]},d.prototype.hasListeners=function(a){return!!this.listeners(a).length}},{}],13:[function(a,b,c){b.exports=function(a,b,c){for(var d=0,e=a.length,f=3==arguments.length?c:a[d++];e>d;)f=b.call(null,f,a[d],++d,a);return f}},{}],14:[function(a,b,c){function d(a,b,c){var d;return d=b?new f(a,b):new f(a)}var e=function(){return this}(),f=e.WebSocket||e.MozWebSocket;b.exports=f?d:null,f&&(d.prototype=f.prototype)},{}]},{},[5])(5)});
\ No newline at end of file
diff --git a/web-dist/discord.min.3.6.3.js b/web-dist/discord.min.3.6.3.js
new file mode 100644
index 000000000..84ac649e8
--- /dev/null
+++ b/web-dist/discord.min.3.6.3.js
@@ -0,0 +1,2 @@
+!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.Discord=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g]*>/g)||[])[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;a.push(h.substring(2,h.length-1))}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return a}"function"==typeof c&&(d=c,c=!1),b=e+n(b);var p=o();f.resolveDestination(a).then(k)["catch"](j)});return g}},{key:"createws",value:function(a){if(this.websocket)return!1;var b=this;this.websocket=new o(a),this.websocket.onopen=function(){b.trySendConnData()},this.websocket.onclose=function(){b.trigger("disconnected")},this.websocket.onmessage=function(a){var c=!1,d={};try{c=JSON.parse(a.data),d=c.d}catch(e){return void b.trigger("error",e,a)}switch(b.trigger("raw",c),c.t){case"READY":b.debug("received ready packet"),b.user=b.addUser(d.user);var f=!0,h=!1,k=void 0;try{for(var l,m=d.guilds[Symbol.iterator]();!(f=(l=m.next()).done);f=!0)var n=l.value,o=b.addServer(n)}catch(e){h=!0,k=e}finally{try{!f&&m["return"]&&m["return"]()}finally{if(h)throw k}}var p=!0,q=!1,r=void 0;try{for(var s,t=d.private_channels[Symbol.iterator]();!(p=(s=t.next()).done);p=!0){var u=s.value;b.addPMChannel(u)}}catch(e){q=!0,r=e}finally{try{!p&&t["return"]&&t["return"]()}finally{if(q)throw r}}b.trigger("ready"),b.readyTime=Date.now(),b.debug("cached "+b.serverCache.length+" servers, "+b.channelCache.length+" channels, "+b.pmChannelCache.length+" PMs and "+b.userCache.length+" users."),b.state=3,setInterval(function(){b.keepAlive.apply(b)},d.heartbeat_interval);break;case"MESSAGE_CREATE":b.debug("received message");var v=[];d.mentions=d.mentions||[];var w=!0,x=!1,y=void 0;try{for(var z,A=d.mentions[Symbol.iterator]();!(w=(z=A.next()).done);w=!0){var B=z.value;v.push(b.addUser(B))}}catch(e){x=!0,y=e}finally{try{!w&&A["return"]&&A["return"]()}finally{if(x)throw y}}var C=b.getChannel("id",d.channel_id);if(C){var D=C.addMessage(new j(d,C,v,b.addUser(d.author)));b.trigger("message",D)}break;case"MESSAGE_DELETE":b.debug("message deleted");var C=b.getChannel("id",d.channel_id),E=C.getMessage("id",d.id);E?(b.trigger("messageDelete",C,E),C.messages.splice(C.messages.indexOf(E),1)):b.trigger("messageDelete",C);break;case"MESSAGE_UPDATE":b.debug("message updated");var C=b.getChannel("id",d.channel_id),F=C.getMessage("id",d.id);if(F){var G={};for(var H in F)G[H]=F[H];for(var H in d)G[H]=d[H];var v=[],I=!0,J=!1,K=void 0;try{for(var L,M=G.mentions[Symbol.iterator]();!(I=(L=M.next()).done);I=!0){var B=L.value;v.push(b.addUser(B))}}catch(e){J=!0,K=e}finally{try{!I&&M["return"]&&M["return"]()}finally{if(J)throw K}}var N=new j(G,C,v,F.author);b.trigger("messageUpdate",N,F),C.messages[C.messages.indexOf(F)]=N}break;case"GUILD_DELETE":var o=b.getServer("id",d.id);o&&(b.serverCache.splice(b.serverCache.indexOf(o),1),b.trigger("serverDelete",o));break;case"CHANNEL_DELETE":var C=b.getChannel("id",d.id);if(C){var o=C.server;o&&o.channels.splice(o.channels.indexOf(C),1),b.trigger("channelDelete",C),b.serverCache.splice(b.serverCache.indexOf(C),1)}break;case"GUILD_CREATE":var o=b.getServer("id",d.id);if(o||(o=b.addServer(d)),b.serverCreateListener[d.id]){var O=b.serverCreateListener[d.id];O[0](o),O[1](null,o),b.serverCreateListener[d.id]=null}b.trigger("serverCreate",o);break;case"CHANNEL_CREATE":var C=b.getChannel("id",d.id);if(!C){var P=b.addChannel(d,d.guild_id),Q=b.getServer("id",d.guild_id);Q&&Q.addChannel(P),b.trigger("channelCreate",P)}break;case"GUILD_MEMBER_ADD":var o=b.getServer("id",d.guild_id);if(o){var R=b.addUser(d.user);~o.members.indexOf(R)||o.members.push(R),b.trigger("serverNewMember",R,o)}break;case"GUILD_MEMBER_REMOVE":var o=b.getServer("id",d.guild_id);if(o){var R=b.addUser(d.user);~o.members.indexOf(R)&&o.members.splice(o.members.indexOf(R),1),b.trigger("serverRemoveMember",R,o)}break;case"USER_UPDATE":if(b.user&&d.id===b.user.id){var S=new g(d);b.trigger("userUpdate",S,b.user),~b.userCache.indexOf(b.user)&&(b.userCache[b.userCache.indexOf(b.user)]=S),b.user=S}break;case"PRESENCE_UPDATE":var T=b.getUser("id",d.user.id);if(T){var U=new g(d.user);U.equalsStrict(T)?(T.status=d.status,b.trigger("presence",{user:T,status:d.status,server:b.getServer("id",d.guild_id),gameId:d.game_id})):(b.trigger("userUpdate",T,U),b.userCache[b.userCache.indexOf(T)]=U)}break;case"CHANNEL_UPDATE":var V=b.getChannel("id",d.id),W=b.getServer("id",d.guild_id);if(V&&W){var X=new i(d,W);X.messages=V.messages,b.trigger("channelUpdate",V,X),b.channelCache[b.channelCache.indexOf(V)]=X}break;default:b.debug("received unknown packet"),b.trigger("unknown",c)}}}},{key:"addUser",value:function(a){return this.getUser("id",a.id)||this.userCache.push(new g(a)),this.getUser("id",a.id)}},{key:"addChannel",value:function(a,b){return this.getChannel("id",a.id)||this.channelCache.push(new i(a,this.getServer("id",b))),this.getChannel("id",a.id)}},{key:"addPMChannel",value:function(a){return this.getPMChannel("id",a.id)||this.pmChannelCache.push(new l(a,this)),this.getPMChannel("id",a.id)}},{key:"setTopic",value:function(a,b){var c=arguments.length<=2||void 0===arguments[2]?function(a){}:arguments[2],d=this;return new Promise(function(e,g){function h(a){c(a),g(a)}function i(a){var g=d.getChannel("id",a);n.patch(f.CHANNELS+"/"+a).set("authorization",d.token).send({name:g.name,position:0,topic:b}).end(function(a,b){a?h(a):(g.topic=b.body.topic,e(),c())})}d.resolveDestination(a).then(i)["catch"](h)})}},{key:"addServer",value:function(a){var b=this,c=this.getServer("id",a.id);if(a.unavailable)return b.trigger("unavailable",a),void b.debug("Server ID "+a.id+" has been marked unavailable by Discord. It was not cached.");if(!c&&(c=new h(a,this),this.serverCache.push(c),a.channels)){var d=!0,e=!1,f=void 0;try{for(var g,i=a.channels[Symbol.iterator]();!(d=(g=i.next()).done);d=!0){var j=g.value;c.channels.push(this.addChannel(j,c.id))}}catch(k){e=!0,f=k}finally{try{!d&&i["return"]&&i["return"]()}finally{if(e)throw f}}}var l=!0,m=!1,n=void 0;try{for(var o,p=a.presences[Symbol.iterator]();!(l=(o=p.next()).done);l=!0){var q=o.value;b.getUser("id",q.user.id).status=q.status}}catch(k){m=!0,n=k}finally{try{!l&&p["return"]&&p["return"]()}finally{if(m)throw n}}return c}},{key:"getUser",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.userCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"getChannel",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.channelCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return this.getPMChannel(a,b)}},{key:"getPMChannel",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.pmChannelCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"getServer",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.serverCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"trySendConnData",value:function(){if(this.token&&!this.alreadySentData){this.alreadySentData=!0;var a={op:2,d:{token:this.token,v:3,properties:{$os:"discord.js",$browser:"discord.js",$device:"discord.js",$referrer:"",$referring_domain:""}}};this.websocket.send(JSON.stringify(a))}}},{key:"resolveServerID",value:function(a){return a instanceof h?a.id:!isNaN(a)&&a.length&&17===a.length?a:void 0}},{key:"resolveDestination",value:function(a){var b=!1,c=this;return new Promise(function(d,e){if(a instanceof h)b=a.id;else if(a instanceof i)b=a.id;else if(a instanceof j)b=a.channel.id;else if(a instanceof l)b=a.id;else if(a instanceof g){var f=!0,k=!1,m=void 0;try{for(var n,o=c.pmChannelCache[Symbol.iterator]();!(f=(n=o.next()).done);f=!0){var p=n.value;if(p.user.equals(a))return void d(p.id)}}catch(q){k=!0,m=q}finally{try{!f&&o["return"]&&o["return"]()}finally{if(k)throw m}}c.startPM(a).then(function(a){d(a.id)})["catch"](e)}else b=a;b?d(b):e()})}},{key:"_sendMessage",value:function(a,b,c,d){var e=this;return new Promise(function(g,h){n.post(f.CHANNELS+"/"+a+"/messages").set("authorization",e.token).send({content:b,mentions:d,tts:c}).end(function(a,b){if(a)h(a);else{var c=b.body,d=[];c.mentions=c.mentions||[];var f=!0,i=!1,k=void 0;try{for(var l,m=c.mentions[Symbol.iterator]();!(f=(l=m.next()).done);f=!0){var n=l.value;d.push(e.addUser(n))}}catch(a){i=!0,k=a}finally{try{!f&&m["return"]&&m["return"]()}finally{if(i)throw k}}var o=e.getChannel("id",c.channel_id);if(o){var p=o.addMessage(new j(c,o,d,e.addUser(c.author)));g(p)}}})})}},{key:"_sendFile",value:function(a,b){var c=arguments.length<=2||void 0===arguments[2]?"DEFAULT BECAUSE YOU DIDN'T SPECIFY WHY.png":arguments[2],d=this;return new Promise(function(e,g){n.post(f.CHANNELS+"/"+a+"/messages").set("authorization",d.token).attach("file",b,c).end(function(b,c){if(b)g(b);else{var f=d.getChannel("id",a);if(f){var h=f.addMessage(new j(c.body,f,[],d.user));e(h)}}})})}},{key:"_updateMessage",value:function(a,b){var c=this;return new Promise(function(d,e){n.patch(f.CHANNELS+"/"+a.channel.id+"/messages/"+a.id).set("authorization",c.token).send({content:b,mentions:[]}).end(function(b,c){if(b)e(b);else{var f=new j(c.body,a.channel,a.mentions,a.sender);d(f),a.channel.messages[a.channel.messages.indexOf(a)]=f}})})}},{key:"_deleteMessage",value:function(a){var b=this;return new Promise(function(c,d){n.del(f.CHANNELS+"/"+a.channel.id+"/messages/"+a.id).set("authorization",b.token).end(function(a,b){a?d(a):c()})})}},{key:"checkQueue",value:function(a){var b=this,c=this;this.checkingQueue[a]||!function(){var d=function f(){if(0===c.queue[a].length)return void e();var b=c.queue[a][0];switch(b.action){case"sendMessage":var d=b;c._sendMessage(a,d.content,d.tts,d.mentions).then(function(b){d.then(b),c.queue[a].shift(),f()})["catch"](function(b){d.error(b),c.queue[a].shift(),f()});break;case"sendFile":var g=b;c._sendFile(a,g.attachment,g.attachmentName).then(function(b){g.then(b),c.queue[a].shift(),f()})["catch"](function(b){g.error(b),c.queue[a].shift(),f()});break;case"updateMessage":var h=b;c._updateMessage(h.message,h.content).then(function(b){h.then(b),c.queue[a].shift(),f()})["catch"](function(b){h.error(b),c.queue[a].shift(),f()});break;case"deleteMessage":var i=b;c._deleteMessage(i.message).then(function(b){i.then(b),c.queue[a].shift(),f()})["catch"](function(b){i.error(b),c.queue[a].shift(),f()});break;default:e()}},e=function(){c.checkingQueue[a]=!1};b.checkingQueue[a]=!0,d()}()}},{key:"getGateway",value:function(){var a=this;return new Promise(function(b,c){n.get(f.API+"/gateway").set("authorization",a.token).end(function(a,d){a?c(a):b(d.body.url)})})}},{key:"setStatusIdle",value:function(){this.setStatus("idle")}},{key:"setStatusOnline",value:function(){this.setStatus("online")}},{key:"setStatusActive",value:function(){this.setStatusOnline()}},{key:"setStatusHere",value:function(){this.setStatusOnline()}},{key:"setStatusAway",value:function(){this.setStatusIdle()}},{key:"startTyping",value:function(a,b){function c(a){if(!d.typingIntervals[a]){var c=function(){n.post(f.CHANNELS+"/"+a+"/typing").set("authorization",d.token).end()};c();var e=setInterval(c,3e3);d.typingIntervals[a]=e,b&&setTimeout(function(){d.stopTyping(a)},b)}}var d=this;this.resolveDestination(a).then(c)}},{key:"stopTyping",value:function(a){function b(a){c.typingIntervals[a]&&(clearInterval(c.typingIntervals[a]),delete c.typingIntervals[a])}var c=this;this.resolveDestination(a).then(b)}},{key:"setStatus",value:function(a){var b="online"===a?null:Date.now();this.__idleTime=b,this.websocket.send(JSON.stringify({op:3,d:{idle_since:this.__idleTime,game_id:this.__gameId}}))}},{key:"setPlayingGame",value:function(a){if(a instanceof String||"string"==typeof a){var b=a.trim().toUpperCase();a=null;var c=!0,d=!1,e=void 0;try{for(var f,g=m[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h.name.trim().toUpperCase()===b){a=h.id;break}}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}}this.__gameId=a,this.websocket.send(JSON.stringify({op:3,d:{idle_since:this.__idleTime,game_id:this.__gameId}}))}},{key:"playGame",value:function(a){this.setPlayingGame(a)}},{key:"playingGame",value:function(a){this.setPlayingGame(a)}},{key:"uptime",get:function(){return this.readyTime?Date.now()-this.readyTime:null}},{key:"ready",get:function(){return 3===this.state}},{key:"servers",get:function(){return this.serverCache}},{key:"channels",get:function(){return this.channelCache}},{key:"users",get:function(){return this.userCache}},{key:"PMChannels",get:function(){return this.pmChannelCache}},{key:"messages",get:function(){var a=[],b=!0,c=!1,d=void 0;try{for(var e,f=this.channelCache[Symbol.iterator]();!(b=(e=f.next()).done);b=!0){var g=e.value;a=a.concat(g.messages)}}catch(h){c=!0,d=h}finally{try{!b&&f["return"]&&f["return"]()}finally{if(c)throw d}}return a}}]),a}();b.exports=r},{"../ref/gameMap.json":15,"./Endpoints.js":2,"./PMChannel.js":3,"./channel.js":4,"./invite.js":6,"./message.js":7,"./server.js":8,"./user.js":9,fs:10,superagent:11,ws:14}],2:[function(a,b,c){"use strict";c.BASE_DOMAIN="discordapp.com",c.BASE="https://"+c.BASE_DOMAIN,c.WEBSOCKET_HUB="wss://"+c.BASE_DOMAIN+"/hub",c.API=c.BASE+"/api",c.AUTH=c.API+"/auth",c.LOGIN=c.AUTH+"/login",c.LOGOUT=c.AUTH+"/logout",c.USERS=c.API+"/users",c.SERVERS=c.API+"/guilds",c.CHANNELS=c.API+"/channels"},{}],3:[function(a,b,c){"use strict";function d(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}var e=function(){function a(a,b){for(var c=0;c1e3&&this.messages.splice(0,1);var c=!0,d=!1,e=void 0;try{for(var f,g=this.messages[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"isPrivate",get:function(){return!0}}]),a}();b.exports=f},{}],4:[function(a,b,c){"use strict";function d(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}var e=function(){function a(a,b){for(var c=0;c1e3&&this.messages.splice(0,1),this.getMessage("id",a.id)||this.messages.push(a),this.getMessage("id",a.id)}},{key:"getMessage",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.messages[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"toString",value:function(){return"<#"+this.id+">"}},{key:"client",get:function(){return this.server.client}},{key:"isPrivate",get:function(){return!1}},{key:"users",get:function(){return this.server.members}},{key:"members",get:function(){return this.server.members}}]),a}();b.exports=f},{}],5:[function(a,b,c){"use strict";var d=(a("superagent"),a("./Endpoints.js")),e=a("./Client.js"),f={Endpoints:d,Client:e};b.exports=f},{"./Client.js":1,"./Endpoints.js":2,superagent:11}],6:[function(a,b,c){"use strict";function d(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}var e=function(){function a(a,b){for(var c=0;c"}},{key:"toString",value:function(){return this.mention()}},{key:"equals",value:function(a){return a.id===this.id}},{key:"equalsStrict",value:function(a){return a.id===this.id&&a.avatar===this.avatar&&a.username===this.username&&a.discriminator===this.discriminator}},{key:"avatarURL",get:function(){return this.avatar?"https://discordapp.com/api/users/"+this.id+"/avatars/"+this.avatar+".jpg":null}}]),a}();b.exports=f},{}],10:[function(a,b,c){},{}],11:[function(a,b,c){function d(){}function e(a){var b={}.toString.call(a);switch(b){case"[object File]":case"[object Blob]":case"[object FormData]":return!0;default:return!1}}function f(a){return a===Object(a)}function g(a){if(!f(a))return a;var b=[];for(var c in a)null!=a[c]&&b.push(encodeURIComponent(c)+"="+encodeURIComponent(a[c]));return b.join("&")}function h(a){for(var b,c,d={},e=a.split("&"),f=0,g=e.length;g>f;++f)c=e[f],b=c.split("="),d[decodeURIComponent(b[0])]=decodeURIComponent(b[1]);return d}function i(a){var b,c,d,e,f=a.split(/\r?\n/),g={};f.pop();for(var h=0,i=f.length;i>h;++h)c=f[h],b=c.indexOf(":"),d=c.slice(0,b).toLowerCase(),e=r(c.slice(b+1)),g[d]=e;return g}function j(a){return a.split(/ *; */).shift()}function k(a){return p(a.split(/ *; */),function(a,b){var c=b.split(/ *= */),d=c.shift(),e=c.shift();return d&&e&&(a[d]=e),a},{})}function l(a,b){b=b||{},this.req=a,this.xhr=this.req.xhr,this.text="HEAD"!=this.req.method&&(""===this.xhr.responseType||"text"===this.xhr.responseType)||"undefined"==typeof this.xhr.responseType?this.xhr.responseText:null,
+this.statusText=this.req.xhr.statusText,this.setStatusProperties(this.xhr.status),this.header=this.headers=i(this.xhr.getAllResponseHeaders()),this.header["content-type"]=this.xhr.getResponseHeader("content-type"),this.setHeaderProperties(this.header),this.body="HEAD"!=this.req.method?this.parseBody(this.text?this.text:this.xhr.response):null}function m(a,b){var c=this;o.call(this),this._query=this._query||[],this.method=a,this.url=b,this.header={},this._header={},this.on("end",function(){var a=null,b=null;try{b=new l(c)}catch(d){return a=new Error("Parser is unable to parse the response"),a.parse=!0,a.original=d,c.callback(a)}if(c.emit("response",b),a)return c.callback(a,b);if(b.status>=200&&b.status<300)return c.callback(a,b);var e=new Error(b.statusText||"Unsuccessful HTTP response");e.original=a,e.response=b,e.status=b.status,c.callback(e,b)})}function n(a,b){return"function"==typeof b?new m("GET",a).end(b):1==arguments.length?new m("GET",a):new m(a,b)}var o=a("emitter"),p=a("reduce"),q="undefined"==typeof window?this||self:window;n.getXHR=function(){if(!(!q.XMLHttpRequest||q.location&&"file:"==q.location.protocol&&q.ActiveXObject))return new XMLHttpRequest;try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(a){}return!1};var r="".trim?function(a){return a.trim()}:function(a){return a.replace(/(^\s*|\s*$)/g,"")};n.serializeObject=g,n.parseString=h,n.types={html:"text/html",json:"application/json",xml:"application/xml",urlencoded:"application/x-www-form-urlencoded",form:"application/x-www-form-urlencoded","form-data":"application/x-www-form-urlencoded"},n.serialize={"application/x-www-form-urlencoded":g,"application/json":JSON.stringify},n.parse={"application/x-www-form-urlencoded":h,"application/json":JSON.parse},l.prototype.get=function(a){return this.header[a.toLowerCase()]},l.prototype.setHeaderProperties=function(a){var b=this.header["content-type"]||"";this.type=j(b);var c=k(b);for(var d in c)this[d]=c[d]},l.prototype.parseBody=function(a){var b=n.parse[this.type];return b&&a&&(a.length||a instanceof Object)?b(a):null},l.prototype.setStatusProperties=function(a){1223===a&&(a=204);var b=a/100|0;this.status=a,this.statusType=b,this.info=1==b,this.ok=2==b,this.clientError=4==b,this.serverError=5==b,this.error=4==b||5==b?this.toError():!1,this.accepted=202==a,this.noContent=204==a,this.badRequest=400==a,this.unauthorized=401==a,this.notAcceptable=406==a,this.notFound=404==a,this.forbidden=403==a},l.prototype.toError=function(){var a=this.req,b=a.method,c=a.url,d="cannot "+b+" "+c+" ("+this.status+")",e=new Error(d);return e.status=this.status,e.method=b,e.url=c,e},n.Response=l,o(m.prototype),m.prototype.use=function(a){return a(this),this},m.prototype.timeout=function(a){return this._timeout=a,this},m.prototype.clearTimeout=function(){return this._timeout=0,clearTimeout(this._timer),this},m.prototype.abort=function(){return this.aborted?void 0:(this.aborted=!0,this.xhr.abort(),this.clearTimeout(),this.emit("abort"),this)},m.prototype.set=function(a,b){if(f(a)){for(var c in a)this.set(c,a[c]);return this}return this._header[a.toLowerCase()]=b,this.header[a]=b,this},m.prototype.unset=function(a){return delete this._header[a.toLowerCase()],delete this.header[a],this},m.prototype.getHeader=function(a){return this._header[a.toLowerCase()]},m.prototype.type=function(a){return this.set("Content-Type",n.types[a]||a),this},m.prototype.accept=function(a){return this.set("Accept",n.types[a]||a),this},m.prototype.auth=function(a,b){var c=btoa(a+":"+b);return this.set("Authorization","Basic "+c),this},m.prototype.query=function(a){return"string"!=typeof a&&(a=g(a)),a&&this._query.push(a),this},m.prototype.field=function(a,b){return this._formData||(this._formData=new q.FormData),this._formData.append(a,b),this},m.prototype.attach=function(a,b,c){return this._formData||(this._formData=new q.FormData),this._formData.append(a,b,c),this},m.prototype.send=function(a){var b=f(a),c=this.getHeader("Content-Type");if(b&&f(this._data))for(var d in a)this._data[d]=a[d];else"string"==typeof a?(c||this.type("form"),c=this.getHeader("Content-Type"),"application/x-www-form-urlencoded"==c?this._data=this._data?this._data+"&"+a:a:this._data=(this._data||"")+a):this._data=a;return!b||e(a)?this:(c||this.type("json"),this)},m.prototype.callback=function(a,b){var c=this._callback;this.clearTimeout(),c(a,b)},m.prototype.crossDomainError=function(){var a=new Error("Origin is not allowed by Access-Control-Allow-Origin");a.crossDomain=!0,this.callback(a)},m.prototype.timeoutError=function(){var a=this._timeout,b=new Error("timeout of "+a+"ms exceeded");b.timeout=a,this.callback(b)},m.prototype.withCredentials=function(){return this._withCredentials=!0,this},m.prototype.end=function(a){var b=this,c=this.xhr=n.getXHR(),f=this._query.join("&"),g=this._timeout,h=this._formData||this._data;this._callback=a||d,c.onreadystatechange=function(){if(4==c.readyState){var a;try{a=c.status}catch(d){a=0}if(0==a){if(b.timedout)return b.timeoutError();if(b.aborted)return;return b.crossDomainError()}b.emit("end")}};var i=function(a){a.total>0&&(a.percent=a.loaded/a.total*100),b.emit("progress",a)};this.hasListeners("progress")&&(c.onprogress=i);try{c.upload&&this.hasListeners("progress")&&(c.upload.onprogress=i)}catch(j){}if(g&&!this._timer&&(this._timer=setTimeout(function(){b.timedout=!0,b.abort()},g)),f&&(f=n.serializeObject(f),this.url+=~this.url.indexOf("?")?"&"+f:"?"+f),c.open(this.method,this.url,!0),this._withCredentials&&(c.withCredentials=!0),"GET"!=this.method&&"HEAD"!=this.method&&"string"!=typeof h&&!e(h)){var k=this.getHeader("Content-Type"),l=n.serialize[k?k.split(";")[0]:""];l&&(h=l(h))}for(var m in this.header)null!=this.header[m]&&c.setRequestHeader(m,this.header[m]);return this.emit("request",this),c.send(h),this},m.prototype.then=function(a,b){return this.end(function(c,d){c?b(c):a(d)})},n.Request=m,n.get=function(a,b,c){var d=n("GET",a);return"function"==typeof b&&(c=b,b=null),b&&d.query(b),c&&d.end(c),d},n.head=function(a,b,c){var d=n("HEAD",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},n.del=function(a,b){var c=n("DELETE",a);return b&&c.end(b),c},n.patch=function(a,b,c){var d=n("PATCH",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},n.post=function(a,b,c){var d=n("POST",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},n.put=function(a,b,c){var d=n("PUT",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},b.exports=n},{emitter:12,reduce:13}],12:[function(a,b,c){function d(a){return a?e(a):void 0}function e(a){for(var b in d.prototype)a[b]=d.prototype[b];return a}b.exports=d,d.prototype.on=d.prototype.addEventListener=function(a,b){return this._callbacks=this._callbacks||{},(this._callbacks[a]=this._callbacks[a]||[]).push(b),this},d.prototype.once=function(a,b){function c(){d.off(a,c),b.apply(this,arguments)}var d=this;return this._callbacks=this._callbacks||{},c.fn=b,this.on(a,c),this},d.prototype.off=d.prototype.removeListener=d.prototype.removeAllListeners=d.prototype.removeEventListener=function(a,b){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var c=this._callbacks[a];if(!c)return this;if(1==arguments.length)return delete this._callbacks[a],this;for(var d,e=0;ed;++d)c[d].apply(this,b)}return this},d.prototype.listeners=function(a){return this._callbacks=this._callbacks||{},this._callbacks[a]||[]},d.prototype.hasListeners=function(a){return!!this.listeners(a).length}},{}],13:[function(a,b,c){b.exports=function(a,b,c){for(var d=0,e=a.length,f=3==arguments.length?c:a[d++];e>d;)f=b.call(null,f,a[d],++d,a);return f}},{}],14:[function(a,b,c){function d(a,b,c){var d;return d=b?new f(a,b):new f(a)}var e=function(){return this}(),f=e.WebSocket||e.MozWebSocket;b.exports=f?d:null,f&&(d.prototype=f.prototype)},{}],15:[function(a,b,c){b.exports=[{executables:{win32:["pol.exe"]},id:0,name:"FINAL FANTASY XI"},{executables:{win32:["ffxiv.exe","ffxiv_dx11.exe"]},id:1,name:"FINAL FANTASY XIV"},{executables:{win32:["Wow.exe","Wow-64.exe"]},id:3,name:"World of Warcraft"},{executables:{darwin:["LoLLauncher.app"],win32:["LolClient.exe","League of Legends.exe"]},id:4,name:"League of Legends"},{executables:{darwin:["Diablo%20III.app"],win32:["Diablo III.exe"]},id:5,name:"Diablo 3"},{executables:{darwin:["dota_osx.app"],win32:["dota2.exe"]},id:6,name:"DOTA 2"},{executables:{darwin:["Heroes.app"],win32:["Heroes of the Storm.exe","HeroesOfTheStorm_x64.exe","HeroesOfTheStorm.exe"]},id:7,name:"Heroes of the Storm"},{executables:{darwin:["Hearthstone.app"],win32:["Hearthstone.exe"]},id:8,name:"Hearthstone"},{executables:{win32:["csgo.exe"]},id:9,name:"Counter-Strike: Global Offensive"},{executables:{win32:["WorldOfTanks.exe"]},id:10,name:"World of Tanks"},{executables:{darwin:["gw2.app"],win32:["gw2.exe"]},id:11,name:"Guild Wars 2"},{executables:{win32:["dayz.exe"]},id:12,name:"Day Z"},{executables:{darwin:["starcraft%20ii.app"],win32:["starcraft ii.exe","SC2_x64.exe","SC2.exe"]},id:13,name:"Starcraft II"},{executables:{win32:["diablo.exe"]},id:14,name:"Diablo"},{executables:{win32:["diablo ii.exe"]},id:15,name:"Diablo 2"},{executables:{win32:["left4dead.exe"]},id:17,name:"Left 4 Dead"},{executables:{darwin:["minecraft.app"],win32:["minecraft.exe"]},id:18,name:"Minecraft"},{executables:{win32:["smite.exe"]},id:19,name:"Smite"},{executables:{win32:["bf4.exe"]},id:20,name:"Battlefield 4"},{executables:{win32:["AoK HD.exe","empires2.exe"]},id:101,name:"Age of Empire II"},{executables:{win32:["age3y.exe"]},id:102,name:"Age of Empire III"},{executables:{win32:["AlanWake.exe"]},id:104,name:"Alan Wake"},{executables:{win32:["alan_wakes_american_nightmare.exe"]},id:105,name:"Alan Wake's American Nightmare"},{executables:{win32:["AlienBreed2Assault.exe"]},id:106,name:"Alien Breed 2: Assault"},{executables:{win32:["Amnesia.exe"]},id:107,name:"Amnesia: The Dark Descent"},{executables:{win32:["UDK.exe"]},id:108,name:"Antichamber"},{executables:{win32:["ArcheAge.exe"]},id:109,name:"ArcheAge"},{executables:{win32:["arma3.exe"]},id:110,name:"Arma III"},{executables:{win32:["AC3SP.exe"]},id:111,name:"Assassin's Creed 3"},{executables:{win32:["Bastion.exe"]},id:112,name:"Bastion"},{executables:{win32:["BF2.exe"]},id:113,name:"Battlefield 2"},{executables:{win32:["bf3.exe"]},id:114,name:"Battlefield 3"},{executables:{win32:["Besiege.exe"]},id:116,name:"Besiege"},{executables:{win32:["Bioshock.exe"]},id:117,name:"Bioshock"},{executables:{win32:["Bioshock2.exe"]},id:118,name:"BioShock II"},{executables:{win32:["BioShockInfinite.exe"]},id:119,name:"BioShock Infinite"},{executables:{win32:["Borderlands2.exe"]},id:122,name:"Borderlands 2"},{executables:{win32:["braid.exe"]},id:123,name:"Braid"},{executables:{win32:["ShippingPC-StormGame.exe"]},id:124,name:"Bulletstorm"},{executables:{},id:125,name:"Cabal 2"},{executables:{win32:["CabalMain.exe"]},id:126,name:"Cabal Online"},{executables:{win32:["iw4mp.exe","iw4sp.exe"]},id:127,name:"Call of Duty: Modern Warfare 2"},{executables:{win32:["t6sp.exe"]},id:128,name:"Call of Duty: Black Ops"},{executables:{win32:["iw5mp.exe"]},id:129,name:"Call of Duty: Modern Warfare 3"},{executables:{win32:["RelicCOH.exe"]},id:132,name:"Company of Heroes"},{executables:{win32:["Crysis64.exe"]},id:135,name:"Crysis"},{executables:{win32:["Crysis2.exe"]},id:136,name:"Crysis 2"},{executables:{win32:["Crysis3.exe"]},id:137,name:"Crysis 3"},{executables:{win32:["Crysis.exe"]},id:138,name:"Crysis 4 "},{executables:{win32:["DATA.exe"]},id:140,name:"Dark Souls"},{executables:{win32:["DarkSoulsII.exe"]},id:141,name:"Dark Souls II"},{executables:{win32:["dfuw.exe"]},id:142,name:"Darkfall: Unholy Wars"},{executables:{win32:["DCGAME.exe"]},id:144,name:"DC Universe Online"},{executables:{win32:["DeadIslandGame.exe"]},id:145,name:"Dead Island"},{executables:{win32:["deadspace2.exe"]},id:146,name:"Dead Space 2"},{executables:{win32:["LOTDGame.exe"]},id:147,name:"Deadlight"},{executables:{win32:["dxhr.exe"]},id:148,name:"Deus Ex: Human Revolution"},{executables:{win32:["DeviMayCry4.exe"]},id:149,name:"Devil May Cry 4"},{executables:{win32:["DMC-DevilMayCry.exe"]},id:150,name:"DmC Devil May Cry"},{executables:{win32:["dirt2_game.exe"]},id:154,name:"DiRT 2"},{executables:{win32:["dirt3_game.exe"]},id:155,name:"DiRT 3"},{executables:{win32:["dota.exe"]},id:156,name:"DOTA"},{executables:{win32:["DoubleDragon.exe"]},id:158,name:"Double Dragon Neon"},{executables:{win32:["DragonAge2.exe"]},id:159,name:"Dragon Age II"},{executables:{win32:["DragonAgeInquisition.exe"]},id:160,name:"Dragon Age: Inquisition"},{executables:{win32:["daorigins.exe"]},id:161,name:"Dragon Age: Origins"},{executables:{win32:["DBXV.exe"]},id:162,name:"Dragon Ball XenoVerse"},{executables:{win32:["DukeForever.exe"]},id:163,name:"Duke Nukem Forever"},{executables:{darwin:["Dustforce.app"],win32:["dustforce.exe"]},id:164,name:"Dustforce"},{executables:{win32:["EliteDangerous32.exe"]},id:165,name:"Elite: Dangerous"},{executables:{win32:["exefile.exe"]},id:166,name:"Eve Online"},{executables:{win32:["eqgame.exe"]},id:167,name:"EverQuest"},{executables:{win32:["EverQuest2.exe"]},id:168,name:"EverQuest II"},{executables:{},id:169,name:"EverQuest Next"},{executables:{win32:["Engine.exe"]},id:170,name:"F.E.A.R."},{executables:{win32:["FEAR2.exe"]},id:171,name:"F.E.A.R. 2: Project Origin"},{executables:{win32:["fallout3.exe"]},id:172,name:"Fallout 3"},{executables:{win32:["FalloutNV.exe"]},id:174,name:"Fallout: New Vegas"},{executables:{win32:["farcry3.exe"]},id:175,name:"Far Cry 3"},{executables:{win32:["fifa15.exe"]},id:176,name:"FIFA 15"},{executables:{win32:["FTLGame.exe"]},id:180,name:"FTL: Faster Than Light"},{executables:{win32:["GTAIV.exe"]},id:181,name:"Grand Theft Auto 4"},{executables:{win32:["GTA5.exe"]},id:182,name:"Grand Theft Auto 5"},{executables:{win32:["Gw.exe"]},id:183,name:"Guild Wars"},{executables:{win32:["H1Z1.exe"]},id:186,name:"H1Z1"},{executables:{win32:["HL2HL2.exe","hl2.exe"]},id:188,name:"Half Life 2"},{executables:{win32:["HOMEFRONT.exe"]},id:195,name:"Homefront"},{executables:{win32:["invisibleinc.exe"]},id:196,name:"Invisible Inc."},{executables:{win32:["LANoire.exe"]},id:197,name:"L.A. Noire"},{executables:{win32:["Landmark64.exe"]},id:198,name:"Landmark"},{executables:{win32:["left4dead2.exe"]},id:201,name:"Left 4 Dead 2"},{executables:{win32:["lineage.exe"]},id:203,name:"Lineage"},{executables:{win32:["Magicka.exe"]},id:206,name:"Magicka"},{executables:{win32:["MapleStory.exe"]},id:208,name:"MapleStory"},{executables:{},id:209,name:"Mark of the Ninja"},{executables:{win32:["MassEffect.exe"]},id:210,name:"Mass Effect"},{executables:{win32:["MassEffect2.exe"]},id:211,name:"Mass Effect 2"},{executables:{win32:["MassEffect3Demo.exe"]},id:212,name:"Mass Effect 3"},{executables:{win32:["METAL GEAR RISING REVENGEANCE.exe"]},id:214,name:"Metal Gear Rising: Revengeance"},{executables:{win32:["metro2033.exe"]},id:215,name:"Metro 2033"},{executables:{win32:["MetroLL.exe"]},id:216,name:"Metro Last Light"},{executables:{win32:["MK10.exe"]},id:218,name:"Mortal Kombat X"},{executables:{win32:["speed.exe"]},id:219,name:"Need For Speed Most Wanted"},{executables:{},id:220,name:"Neverwinder"},{executables:{darwin:["Outlast.app"],win32:["OLGame.exe"]},id:221,name:"Outlast"},{executables:{win32:["PapersPlease.exe"]},id:222,name:"Papers, Please"},{executables:{win32:["payday_win32_release.exe"]},id:223,name:"PAYDAY"},{executables:{win32:["payday2_win32_release.exe"]},id:224,name:"PAYDAY2"},{executables:{win32:["PillarsOfEternity.exe"]},id:225,name:"Pillars of Eternity"},{executables:{win32:["PA.exe"]},id:226,name:"Planetary Annihilation"},{executables:{win32:["planetside2_x86.exe"]},id:227,name:"Planetside 2"},{executables:{win32:["hl2P.exe"]},id:228,name:"Portal"},{executables:{win32:["portal2.exe"]},id:229,name:"Portal 2"},{executables:{win32:["PrimalCarnageGame.exe"]},id:231,name:"Primal Cargnage"},{executables:{win32:["pCARS.exe"]},id:232,name:"Project Cars"},{executables:{win32:["RaceTheSun.exe"]},id:233,name:"Race The Sun"},{executables:{win32:["Rage.exe"]},id:234,name:"RAGE"},{executables:{win32:["ragexe.exe"]},id:235,name:"Ragnarok Online"},{executables:{win32:["rift.exe"]},id:236,name:"Rift"},{executables:{win32:["Rocksmith2014.exe"]},id:237,name:"Rocksmith 2014"},{executables:{win32:["SwiftKit-RS.exe","JagexLauncher.exe"]},id:238,name:"RuneScape"},{executables:{win32:["Shadowgrounds.exe"]},id:239,name:"Shadowgrounds"},{executables:{win32:["survivor.exe"]},id:240,name:"Shadowgrounds: Survivor"},{executables:{win32:["ShovelKnight.exe"]},id:241,name:"Shovel Knight"},{executables:{win32:["SimCity.exe"]},id:242,name:"SimCity"},{executables:{win32:["SporeApp.exe"]},id:245,name:"Spore"},{executables:{win32:["StarCitizen.exe"]},id:246,name:"Star Citizen"},{executables:{},id:247,name:"Star Trek Online"},{executables:{win32:["battlefront.exe"]},id:248,name:"Star Wars Battlefront"},{executables:{win32:["swtor.exe"]},id:249,name:"Star Wars: The Old Republic"},{executables:{win32:["starbound.exe","starbound_opengl.exe"]},id:250,name:"Starbound"},{executables:{win32:["starcraft.exe"]},id:251,name:"Starcraft"},{executables:{win32:["SSFIV.exe"]},id:253,name:"Ultra Street Fighter IV"},{executables:{win32:["superhexagon.exe"]},id:254,name:"Super Hexagon"},{executables:{win32:["swordandsworcery_pc.exe"]},id:255,name:"Superbrothers: Sword & Sworcery EP"},{executables:{win32:["hl2TF.exe"]},id:256,name:"Team Fortress 2"},{executables:{win32:["TERA.exe"]},id:258,name:"TERA"},{executables:{win32:["Terraria.exe"]},id:259,name:"Terraria"},{executables:{win32:["Bethesda.net_Launcher.exe"]},id:260,name:"The Elder Scrolls Online"},{executables:{win32:["TESV.exe"]},id:261,name:"The Elder Scrolls V: Skyrim"},{executables:{win32:["TheSecretWorld.exe"]},id:262,name:"The Secret World"},{executables:{win32:["TS3.exe","ts3w.exe"]},id:264,name:"The Sims 3"},{executables:{win32:["WALKINGDEAD101.EXE"]},id:265,name:"The Walking Dead"},{executables:{win32:["TheWalkingDead2.exe"]},id:266,name:"The Walking Dead Season Two"},{executables:{win32:["witcher3.exe"]},id:267,name:"The Witcher 3"},{executables:{win32:["Future Soldier.exe"]},id:268,name:"Tom Clancy's Ghost Recon: Future Solider"},{executables:{win32:["TombRaider.exe"]},id:269,name:"Tomb Raider (2013)"},{executables:{win32:["Torchlight.exe"]},id:271,name:"Torchlight"},{executables:{win32:["Torchlight2.exe"]},id:272,name:"Torchlight 2"},{executables:{win32:["Shogun2.exe"]},id:273,name:"Total War: Shogun 2"},{executables:{win32:["Transistor.exe"]},id:274,name:"Transistor"},{executables:{win32:["trine.exe"]},id:275,name:"Trine"},{executables:{win32:["trine2_32bit.exe"]},id:276,name:"Trine 2"},{executables:{win32:["UOKR.exe"]},id:277,name:"Ultima Online"},{executables:{win32:["aces.exe"]},id:279,name:"War Thunder"},{executables:{win32:["Warcraft III.exe","wc3.exe"]},id:281,name:"Warcraft 3: Reign of Chaos"},{executables:{win32:["Warcraft II BNE.exe"]},id:282,name:"Warcraft II"},{executables:{win32:["Warframe.x64.exe","Warframe.exe"]},id:283,name:"Warframe"},{executables:{win32:["watch_dogs.exe"]},id:284,name:"Watch Dogs"},{executables:{win32:["WildStar64.exe"]},id:285,name:"WildStar"},{executables:{win32:["XComGame.exe"]},id:288,name:"XCOM: Enemy Unknown"},{executables:{win32:["DFO.exe","dfo.exe"]},id:289,name:"Dungeon Fighter Online"},{executables:{win32:["aclauncher.exe","acclient.exe"]},id:290,name:"Asheron's Call"},{executables:{win32:["MapleStory2.exe"]},id:291,name:"MapleStory 2"},{executables:{win32:["ksp.exe"]},id:292,name:"Kerbal Space Program"},{executables:{win32:["PINBALL.EXE"]},id:293,name:"3D Pinball: Space Cadet"},{executables:{win32:["dave.exe"]},id:294,name:"Dangerous Dave"},{executables:{win32:["iwbtgbeta(slomo).exe","iwbtgbeta(fs).exe"]},id:295,name:"I Wanna Be The Guy"},{executables:{win32:["MechWarriorOnline.exe "]},id:296,name:"Mech Warrior Online"},{executables:{win32:["dontstarve_steam.exe"]},id:297,name:"Don't Starve"},{executables:{win32:["GalCiv3.exe"]},id:298,name:"Galactic Civilization 3"},{executables:{win32:["Risk of Rain.exe"]},id:299,name:"Risk of Rain"},{executables:{win32:["Binding_of_Isaac.exe","Isaac-ng.exe"]},id:300,name:"The Binding of Isaac"},{executables:{win32:["RustClient.exe"]},id:301,name:"Rust"},{executables:{win32:["Clicker Heroes.exe"]},id:302,name:"Clicker Heroes"},{executables:{win32:["Brawlhalla.exe"]},id:303,name:"Brawlhalla"},{executables:{win32:["TownOfSalem.exe"]},id:304,name:"Town of Salem"},{executables:{win32:["osu!.exe"]},id:305,name:"osu!"},{executables:{win32:["PathOfExileSteam.exe","PathOfExile.exe"]},id:306,name:"Path of Exile"},{executables:{win32:["Dolphin.exe"]},id:307,name:"Dolphin"},{executables:{win32:["RocketLeague.exe"]},id:308,name:"Rocket League"},{executables:{win32:["TJPP.exe"]},id:309,name:"Jackbox Party Pack"},{executables:{win32:["KFGame.exe"]},id:310,name:"Killing Floor 2"},{executables:{win32:["ShooterGame.exe"]},id:311,name:"Ark: Survival Evolved"},{executables:{win32:["LifeIsStrange.exe"]},id:312,name:"Life Is Strange"},{executables:{win32:["Client_tos.exe"]},id:313,name:"Tree of Savior"},{executables:{win32:["olliolli2.exe"]},id:314,name:"OlliOlli2"},{executables:{win32:["cw.exe"]},id:315,name:"Closers Dimension Conflict"},{executables:{win32:["ESSTEAM.exe","elsword.exe","x2.exe"]},id:316,name:"Elsword"},{executables:{win32:["ori.exe"]},id:317,name:"Ori and the Blind Forest"},{executables:{win32:["Skyforge.exe"]},id:318,name:"Skyforge"},{executables:{win32:["projectzomboid64.exe","projectzomboid32.exe"]},id:319,name:"Project Zomboid"},{executables:{win32:["From_The_Depths.exe"]},id:320,name:"The Depths"},{executables:{win32:["TheCrew.exe"]},id:321,name:"The Crew"},{executables:{win32:["MarvelHeroes2015.exe"]},id:322,name:"Marvel Heroes 2015"},{executables:{win32:["timeclickers.exe"]},id:324,name:"Time Clickers"},{executables:{win32:["eurotrucks2.exe"]},id:325,name:"Euro Truck Simulator 2"},{executables:{win32:["FarmingSimulator2015Game.exe"]},id:326,name:"Farming Simulator 15"},{executables:{win32:["strife.exe"]},id:327,name:"Strife"},{executables:{win32:["Awesomenauts.exe"]},id:328,name:"Awesomenauts"},{executables:{win32:["Dofus.exe"]},id:329,name:"Dofus"},{executables:{win32:["Boid.exe"]},id:330,name:"Boid"},{executables:{win32:["adventure-capitalist.exe"]},id:331,name:"AdVenture Capitalist"},{executables:{win32:["OrcsMustDie2.exe"]},id:332,name:"Orcs Must Die! 2"},{executables:{win32:["Mountain.exe"]},id:333,name:"Mountain"},{executables:{win32:["Valkyria.exe"]},id:335,name:"Valkyria Chronicles"},{executables:{win32:["ffxiiiimg.exe"]},id:336,name:"Final Fantasy XIII"},{executables:{win32:["TLR.exe"]},id:337,name:"The Last Remnant"},{executables:{win32:["Cities.exe"]},id:339,name:"Cities Skylines"},{executables:{win32:["worldofwarships.exe","WoWSLauncher.exe"]},id:341,name:"World of Warships"},{executables:{win32:["spacegame-Win64-shipping.exe"]},id:342,name:"Fractured Space"},{executables:{win32:["thespacegame.exe"]},id:343,name:"Ascent - The Space Game"},{executables:{win32:["DuckGame.exe"]},id:344,name:"Duck Game"},{executables:{win32:["PPSSPPWindows.exe"]},id:345,name:"PPSSPP"},{executables:{win32:["MBAA.exe"]},id:346,name:"Melty Blood Actress Again: Current Code"},{executables:{win32:["TheWolfAmongUs.exe"]},id:347,name:"The Wolf Among Us"},{executables:{win32:["SpaceEngineers.exe"]},id:348,name:"Space Engineers"},{executables:{win32:["Borderlands.exe"]},id:349,name:"Borderlands"},{executables:{win32:["100orange.exe"]},id:351,name:"100% Orange Juice"},{executables:{win32:["reflex.exe"]},id:354,name:"Reflex"},{executables:{win32:["pso2.exe"]},id:355,name:"Phantasy Star Online 2"},{executables:{win32:["AssettoCorsa.exe"]},id:356,name:"Assetto Corsa"},{executables:{win32:["iw3mp.exe","iw3sp.exe"]},id:357,name:"Call of Duty 4: Modern Warfare"},{executables:{win32:["WolfOldBlood_x64.exe"]},id:358,name:"Wolfenstein: The Old Blood"},{executables:{win32:["castle.exe"]},id:359,name:"Castle Crashers"},{executables:{win32:["vindictus.exe"]},id:360,name:"Vindictus"},{executables:{win32:["ShooterGame-Win32-Shipping.exe"]},id:361,name:"Dirty Bomb"},{executables:{win32:["BatmanAK.exe"]},id:362,name:"Batman Arkham Knight"},{executables:{win32:["drt.exe"]},id:363,name:"Dirt Rally"},{executables:{win32:["rFactor.exe"]},id:364,name:"rFactor"},{executables:{win32:["clonk.exe"]},id:365,name:"Clonk Rage"},{executables:{win32:["SRHK.exe"]},id:366,name:"Shadowrun: Hong Kong"},{executables:{win32:["Insurgency.exe"]},id:367,name:"Insurgency"},{executables:{win32:["StepMania.exe"]},id:368,name:"Step Mania"},{executables:{win32:["FirefallCLient.exe"]},id:369,name:"Firefall"},{executables:{win32:["mirrorsedge.exe"]},id:370,name:"Mirrors Edge"},{executables:{win32:["MgsGroundZeroes.exe"]},id:371,name:"Metal Gear Solid V: Ground Zeroes"},{executables:{win32:["mgsvtpp.exe"]},id:372,name:"Metal Gear Solid V: The Phantom Pain"},{executables:{win32:["tld.exe"]},id:373,name:"The Long Dark"},{executables:{win32:["TKOM.exe"]},id:374,name:"Take On Mars"},{executables:{win32:["robloxplayerlauncher.exe","Roblox.exe"]},id:375,name:"Roblox"},{executables:{win32:["eu4.exe"]},id:376,name:"Europa Universalis 4"},{executables:{win32:["APB.exe"]},id:377,name:"APB Reloaded"},{executables:{win32:["Robocraft.exe"]},id:378,name:"Robocraft"},{executables:{win32:["Unity.exe"]},id:379,name:"Unity"},{executables:{win32:["Simpsons.exe"]},id:380,name:"The Simpsons: Hit & Run"},{executables:{win32:["Dnlauncher.exe","DragonNest.exe"]},id:381,name:"Dragon Nest"},{executables:{win32:["Trove.exe"]},id:382,name:"Trove"},{executables:{win32:["EndlessLegend.exe"]},id:383,name:"Endless Legend"},{executables:{win32:["TurbineLauncher.exe","dndclient.exe"]},id:384,name:"Dungeons & Dragons Online"},{executables:{win32:["quakelive.exe","quakelive_steam.exe"]},id:385,name:"Quake Live"},{executables:{win32:["7DaysToDie.exe"]},id:386,name:"7DaysToDie"},{executables:{win32:["SpeedRunners.exe"]},id:387,name:"SpeedRunners"},{executables:{win32:["gamemd.exe"]},id:388,name:"Command & Conquer: Red Alert 2"},{executables:{win32:["generals.exe"]},id:389,name:"Command & Conquer Generals: Zero Hour"},{executables:{win32:["Oblivion.exe"]},id:390,name:"The Elder Scrolls 4: Oblivion"},{executables:{win32:["mgsi.exe"]},id:391,name:"Metal Gear Solid"},{executables:{win32:["EoCApp.exe"]},id:392,name:"Divinity - Original Sin"},{executables:{win32:["Torment.exe"]},id:393,name:"Planescape: Torment"},{executables:{win32:["HexPatch.exe"]},id:394,name:"Hex: Shards of Fate"},{executables:{win32:["NS3FB.exe"]},id:395,name:"Naruto Shippuden Ultimate Ninja Storm 3 Full Burst"},{executables:{win32:["NSUNSR.exe"]},id:396,name:"Naruto Shippuden Ultimate Ninja Storm Revolution"},{executables:{win32:["SaintsRowIV.exe"]},id:397,name:"Saints Row IV"},{executables:{win32:["Shadowrun.exe"]},id:398,name:"Shadowrun"},{executables:{win32:["DungeonoftheEndless.exe"]},id:399,name:"Dungeon of the Endless"},{executables:{win32:["Hon.exe"]},id:400,name:"Heroes of Newerth"},{executables:{win32:["mabinogi.exe"]},id:401,name:"Mabinogi"},{executables:{win32:["CoD2MP_s.exe","CoDSP_s.exe"]},id:402,name:"Call of Duty 2:"},{executables:{win32:["CoDWaWmp.exe","CoDWaw.exe"]},id:403,name:"Call of Duty: World at War"},{executables:{win32:["heroes.exe"]},id:404,name:"Mabinogi Heroes (Vindictus) "},{executables:{win32:["KanColleViewer.exe"]},id:405,name:"KanColle "},{executables:{win32:["cyphers.exe"]},id:406,name:"Cyphers"},{executables:{win32:["RelicCoH2.exe"]},id:407,name:"Company of Heroes 2"},{executables:{win32:["MJ.exe"]},id:408,name:"セガNET麻雀MJ"},{executables:{win32:["ge.exe"]},id:409,name:"Granado Espada"},{executables:{win32:["NovaRO.exe"]},id:410,name:"Nova Ragnarok Online"},{executables:{win32:["RivalsofAether.exe"]},id:411,name:"Rivals of Aether"},{executables:{win32:["bfh.exe"]},id:412,name:"Battlefield Hardline"},{executables:{win32:["GrowHome.exe"]},id:413,name:"Grow Home"},{executables:{win32:["patriots.exe"]},id:414,name:"Rise of Nations Extended"},{executables:{win32:["Railroads.exe"]},id:415,name:"Sid Meier's Railroads!"},{executables:{win32:["Empire.exe"]},id:416,name:"Empire: Total War"},{executables:{win32:["Napoleon.exe"]},id:417,name:"Napoleon: Total War"},{executables:{win32:["gta_sa.exe"]},id:418,name:"Grand Theft Auto: San Andreas"},{executables:{win32:["MadMax.exe"]},id:419,name:"Mad Max"},{executables:{win32:["Titanfall.exe"]},id:420,name:"Titanfall"},{executables:{win32:["age2_x1.exe"]},id:421,name:"Age of Empires II: The Conquerors"},{executables:{win32:["Rome2.exe"]},id:422,name:"Total War: ROME 2"},{executables:{win32:["ShadowOfMordor.exe"]},id:423,name:"Middle-earth: Shadow of Mordor"},{executables:{win32:["Subnautica.exe"]},id:424,name:"Subnautica"},{executables:{win32:["anno5.exe"]},id:425,name:"Anno 2070"},{executables:{win32:["carrier.exe"]},id:426,name:"Carrier Command Gaea Mission"},{executables:{win32:["DarksidersPC.exe"]},id:427,name:"Darksiders"},{executables:{win32:["Darksiders2.exe"]},id:428,name:"Darksiders 2"},{executables:{win32:["mudlet.exe"]},id:429,name:"Mudlet"},{executables:{win32:["DunDefLauncher.exe"]},id:430,name:"Dungeon Defenders II"},{executables:{win32:["hng.exe"]},id:431,name:"Heroes and Generals"},{executables:{win32:["WFTOGame.exe"]},id:432,name:"War of the Overworld"},{executables:{win32:["Talisman.exe"]},id:433,name:"Talisman: Digital Edition"},{executables:{win32:["limbo.exe"]},id:434,name:"Limbo"},{executables:{win32:["ibbobb.exe"]},id:435,name:"ibb & obb"},{executables:{win32:["BattleBlockTheater.exe"]},id:436,name:"BattleBlock Theater"},{executables:{win32:["iracinglauncher.exe","iracingsim.exe","iracingsim64.exe"]},id:437,name:"iRacing"},{executables:{win32:["CivilizationV_DX11.exe"]},id:438,name:"Civilization V"}]},{}]},{},[5])(5)});
\ No newline at end of file
diff --git a/web-dist/discord.min.3.7.1.js b/web-dist/discord.min.3.7.1.js
new file mode 100644
index 000000000..84ac649e8
--- /dev/null
+++ b/web-dist/discord.min.3.7.1.js
@@ -0,0 +1,2 @@
+!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.Discord=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g]*>/g)||[])[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;a.push(h.substring(2,h.length-1))}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return a}"function"==typeof c&&(d=c,c=!1),b=e+n(b);var p=o();f.resolveDestination(a).then(k)["catch"](j)});return g}},{key:"createws",value:function(a){if(this.websocket)return!1;var b=this;this.websocket=new o(a),this.websocket.onopen=function(){b.trySendConnData()},this.websocket.onclose=function(){b.trigger("disconnected")},this.websocket.onmessage=function(a){var c=!1,d={};try{c=JSON.parse(a.data),d=c.d}catch(e){return void b.trigger("error",e,a)}switch(b.trigger("raw",c),c.t){case"READY":b.debug("received ready packet"),b.user=b.addUser(d.user);var f=!0,h=!1,k=void 0;try{for(var l,m=d.guilds[Symbol.iterator]();!(f=(l=m.next()).done);f=!0)var n=l.value,o=b.addServer(n)}catch(e){h=!0,k=e}finally{try{!f&&m["return"]&&m["return"]()}finally{if(h)throw k}}var p=!0,q=!1,r=void 0;try{for(var s,t=d.private_channels[Symbol.iterator]();!(p=(s=t.next()).done);p=!0){var u=s.value;b.addPMChannel(u)}}catch(e){q=!0,r=e}finally{try{!p&&t["return"]&&t["return"]()}finally{if(q)throw r}}b.trigger("ready"),b.readyTime=Date.now(),b.debug("cached "+b.serverCache.length+" servers, "+b.channelCache.length+" channels, "+b.pmChannelCache.length+" PMs and "+b.userCache.length+" users."),b.state=3,setInterval(function(){b.keepAlive.apply(b)},d.heartbeat_interval);break;case"MESSAGE_CREATE":b.debug("received message");var v=[];d.mentions=d.mentions||[];var w=!0,x=!1,y=void 0;try{for(var z,A=d.mentions[Symbol.iterator]();!(w=(z=A.next()).done);w=!0){var B=z.value;v.push(b.addUser(B))}}catch(e){x=!0,y=e}finally{try{!w&&A["return"]&&A["return"]()}finally{if(x)throw y}}var C=b.getChannel("id",d.channel_id);if(C){var D=C.addMessage(new j(d,C,v,b.addUser(d.author)));b.trigger("message",D)}break;case"MESSAGE_DELETE":b.debug("message deleted");var C=b.getChannel("id",d.channel_id),E=C.getMessage("id",d.id);E?(b.trigger("messageDelete",C,E),C.messages.splice(C.messages.indexOf(E),1)):b.trigger("messageDelete",C);break;case"MESSAGE_UPDATE":b.debug("message updated");var C=b.getChannel("id",d.channel_id),F=C.getMessage("id",d.id);if(F){var G={};for(var H in F)G[H]=F[H];for(var H in d)G[H]=d[H];var v=[],I=!0,J=!1,K=void 0;try{for(var L,M=G.mentions[Symbol.iterator]();!(I=(L=M.next()).done);I=!0){var B=L.value;v.push(b.addUser(B))}}catch(e){J=!0,K=e}finally{try{!I&&M["return"]&&M["return"]()}finally{if(J)throw K}}var N=new j(G,C,v,F.author);b.trigger("messageUpdate",N,F),C.messages[C.messages.indexOf(F)]=N}break;case"GUILD_DELETE":var o=b.getServer("id",d.id);o&&(b.serverCache.splice(b.serverCache.indexOf(o),1),b.trigger("serverDelete",o));break;case"CHANNEL_DELETE":var C=b.getChannel("id",d.id);if(C){var o=C.server;o&&o.channels.splice(o.channels.indexOf(C),1),b.trigger("channelDelete",C),b.serverCache.splice(b.serverCache.indexOf(C),1)}break;case"GUILD_CREATE":var o=b.getServer("id",d.id);if(o||(o=b.addServer(d)),b.serverCreateListener[d.id]){var O=b.serverCreateListener[d.id];O[0](o),O[1](null,o),b.serverCreateListener[d.id]=null}b.trigger("serverCreate",o);break;case"CHANNEL_CREATE":var C=b.getChannel("id",d.id);if(!C){var P=b.addChannel(d,d.guild_id),Q=b.getServer("id",d.guild_id);Q&&Q.addChannel(P),b.trigger("channelCreate",P)}break;case"GUILD_MEMBER_ADD":var o=b.getServer("id",d.guild_id);if(o){var R=b.addUser(d.user);~o.members.indexOf(R)||o.members.push(R),b.trigger("serverNewMember",R,o)}break;case"GUILD_MEMBER_REMOVE":var o=b.getServer("id",d.guild_id);if(o){var R=b.addUser(d.user);~o.members.indexOf(R)&&o.members.splice(o.members.indexOf(R),1),b.trigger("serverRemoveMember",R,o)}break;case"USER_UPDATE":if(b.user&&d.id===b.user.id){var S=new g(d);b.trigger("userUpdate",S,b.user),~b.userCache.indexOf(b.user)&&(b.userCache[b.userCache.indexOf(b.user)]=S),b.user=S}break;case"PRESENCE_UPDATE":var T=b.getUser("id",d.user.id);if(T){var U=new g(d.user);U.equalsStrict(T)?(T.status=d.status,b.trigger("presence",{user:T,status:d.status,server:b.getServer("id",d.guild_id),gameId:d.game_id})):(b.trigger("userUpdate",T,U),b.userCache[b.userCache.indexOf(T)]=U)}break;case"CHANNEL_UPDATE":var V=b.getChannel("id",d.id),W=b.getServer("id",d.guild_id);if(V&&W){var X=new i(d,W);X.messages=V.messages,b.trigger("channelUpdate",V,X),b.channelCache[b.channelCache.indexOf(V)]=X}break;default:b.debug("received unknown packet"),b.trigger("unknown",c)}}}},{key:"addUser",value:function(a){return this.getUser("id",a.id)||this.userCache.push(new g(a)),this.getUser("id",a.id)}},{key:"addChannel",value:function(a,b){return this.getChannel("id",a.id)||this.channelCache.push(new i(a,this.getServer("id",b))),this.getChannel("id",a.id)}},{key:"addPMChannel",value:function(a){return this.getPMChannel("id",a.id)||this.pmChannelCache.push(new l(a,this)),this.getPMChannel("id",a.id)}},{key:"setTopic",value:function(a,b){var c=arguments.length<=2||void 0===arguments[2]?function(a){}:arguments[2],d=this;return new Promise(function(e,g){function h(a){c(a),g(a)}function i(a){var g=d.getChannel("id",a);n.patch(f.CHANNELS+"/"+a).set("authorization",d.token).send({name:g.name,position:0,topic:b}).end(function(a,b){a?h(a):(g.topic=b.body.topic,e(),c())})}d.resolveDestination(a).then(i)["catch"](h)})}},{key:"addServer",value:function(a){var b=this,c=this.getServer("id",a.id);if(a.unavailable)return b.trigger("unavailable",a),void b.debug("Server ID "+a.id+" has been marked unavailable by Discord. It was not cached.");if(!c&&(c=new h(a,this),this.serverCache.push(c),a.channels)){var d=!0,e=!1,f=void 0;try{for(var g,i=a.channels[Symbol.iterator]();!(d=(g=i.next()).done);d=!0){var j=g.value;c.channels.push(this.addChannel(j,c.id))}}catch(k){e=!0,f=k}finally{try{!d&&i["return"]&&i["return"]()}finally{if(e)throw f}}}var l=!0,m=!1,n=void 0;try{for(var o,p=a.presences[Symbol.iterator]();!(l=(o=p.next()).done);l=!0){var q=o.value;b.getUser("id",q.user.id).status=q.status}}catch(k){m=!0,n=k}finally{try{!l&&p["return"]&&p["return"]()}finally{if(m)throw n}}return c}},{key:"getUser",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.userCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"getChannel",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.channelCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return this.getPMChannel(a,b)}},{key:"getPMChannel",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.pmChannelCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"getServer",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.serverCache[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"trySendConnData",value:function(){if(this.token&&!this.alreadySentData){this.alreadySentData=!0;var a={op:2,d:{token:this.token,v:3,properties:{$os:"discord.js",$browser:"discord.js",$device:"discord.js",$referrer:"",$referring_domain:""}}};this.websocket.send(JSON.stringify(a))}}},{key:"resolveServerID",value:function(a){return a instanceof h?a.id:!isNaN(a)&&a.length&&17===a.length?a:void 0}},{key:"resolveDestination",value:function(a){var b=!1,c=this;return new Promise(function(d,e){if(a instanceof h)b=a.id;else if(a instanceof i)b=a.id;else if(a instanceof j)b=a.channel.id;else if(a instanceof l)b=a.id;else if(a instanceof g){var f=!0,k=!1,m=void 0;try{for(var n,o=c.pmChannelCache[Symbol.iterator]();!(f=(n=o.next()).done);f=!0){var p=n.value;if(p.user.equals(a))return void d(p.id)}}catch(q){k=!0,m=q}finally{try{!f&&o["return"]&&o["return"]()}finally{if(k)throw m}}c.startPM(a).then(function(a){d(a.id)})["catch"](e)}else b=a;b?d(b):e()})}},{key:"_sendMessage",value:function(a,b,c,d){var e=this;return new Promise(function(g,h){n.post(f.CHANNELS+"/"+a+"/messages").set("authorization",e.token).send({content:b,mentions:d,tts:c}).end(function(a,b){if(a)h(a);else{var c=b.body,d=[];c.mentions=c.mentions||[];var f=!0,i=!1,k=void 0;try{for(var l,m=c.mentions[Symbol.iterator]();!(f=(l=m.next()).done);f=!0){var n=l.value;d.push(e.addUser(n))}}catch(a){i=!0,k=a}finally{try{!f&&m["return"]&&m["return"]()}finally{if(i)throw k}}var o=e.getChannel("id",c.channel_id);if(o){var p=o.addMessage(new j(c,o,d,e.addUser(c.author)));g(p)}}})})}},{key:"_sendFile",value:function(a,b){var c=arguments.length<=2||void 0===arguments[2]?"DEFAULT BECAUSE YOU DIDN'T SPECIFY WHY.png":arguments[2],d=this;return new Promise(function(e,g){n.post(f.CHANNELS+"/"+a+"/messages").set("authorization",d.token).attach("file",b,c).end(function(b,c){if(b)g(b);else{var f=d.getChannel("id",a);if(f){var h=f.addMessage(new j(c.body,f,[],d.user));e(h)}}})})}},{key:"_updateMessage",value:function(a,b){var c=this;return new Promise(function(d,e){n.patch(f.CHANNELS+"/"+a.channel.id+"/messages/"+a.id).set("authorization",c.token).send({content:b,mentions:[]}).end(function(b,c){if(b)e(b);else{var f=new j(c.body,a.channel,a.mentions,a.sender);d(f),a.channel.messages[a.channel.messages.indexOf(a)]=f}})})}},{key:"_deleteMessage",value:function(a){var b=this;return new Promise(function(c,d){n.del(f.CHANNELS+"/"+a.channel.id+"/messages/"+a.id).set("authorization",b.token).end(function(a,b){a?d(a):c()})})}},{key:"checkQueue",value:function(a){var b=this,c=this;this.checkingQueue[a]||!function(){var d=function f(){if(0===c.queue[a].length)return void e();var b=c.queue[a][0];switch(b.action){case"sendMessage":var d=b;c._sendMessage(a,d.content,d.tts,d.mentions).then(function(b){d.then(b),c.queue[a].shift(),f()})["catch"](function(b){d.error(b),c.queue[a].shift(),f()});break;case"sendFile":var g=b;c._sendFile(a,g.attachment,g.attachmentName).then(function(b){g.then(b),c.queue[a].shift(),f()})["catch"](function(b){g.error(b),c.queue[a].shift(),f()});break;case"updateMessage":var h=b;c._updateMessage(h.message,h.content).then(function(b){h.then(b),c.queue[a].shift(),f()})["catch"](function(b){h.error(b),c.queue[a].shift(),f()});break;case"deleteMessage":var i=b;c._deleteMessage(i.message).then(function(b){i.then(b),c.queue[a].shift(),f()})["catch"](function(b){i.error(b),c.queue[a].shift(),f()});break;default:e()}},e=function(){c.checkingQueue[a]=!1};b.checkingQueue[a]=!0,d()}()}},{key:"getGateway",value:function(){var a=this;return new Promise(function(b,c){n.get(f.API+"/gateway").set("authorization",a.token).end(function(a,d){a?c(a):b(d.body.url)})})}},{key:"setStatusIdle",value:function(){this.setStatus("idle")}},{key:"setStatusOnline",value:function(){this.setStatus("online")}},{key:"setStatusActive",value:function(){this.setStatusOnline()}},{key:"setStatusHere",value:function(){this.setStatusOnline()}},{key:"setStatusAway",value:function(){this.setStatusIdle()}},{key:"startTyping",value:function(a,b){function c(a){if(!d.typingIntervals[a]){var c=function(){n.post(f.CHANNELS+"/"+a+"/typing").set("authorization",d.token).end()};c();var e=setInterval(c,3e3);d.typingIntervals[a]=e,b&&setTimeout(function(){d.stopTyping(a)},b)}}var d=this;this.resolveDestination(a).then(c)}},{key:"stopTyping",value:function(a){function b(a){c.typingIntervals[a]&&(clearInterval(c.typingIntervals[a]),delete c.typingIntervals[a])}var c=this;this.resolveDestination(a).then(b)}},{key:"setStatus",value:function(a){var b="online"===a?null:Date.now();this.__idleTime=b,this.websocket.send(JSON.stringify({op:3,d:{idle_since:this.__idleTime,game_id:this.__gameId}}))}},{key:"setPlayingGame",value:function(a){if(a instanceof String||"string"==typeof a){var b=a.trim().toUpperCase();a=null;var c=!0,d=!1,e=void 0;try{for(var f,g=m[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h.name.trim().toUpperCase()===b){a=h.id;break}}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}}this.__gameId=a,this.websocket.send(JSON.stringify({op:3,d:{idle_since:this.__idleTime,game_id:this.__gameId}}))}},{key:"playGame",value:function(a){this.setPlayingGame(a)}},{key:"playingGame",value:function(a){this.setPlayingGame(a)}},{key:"uptime",get:function(){return this.readyTime?Date.now()-this.readyTime:null}},{key:"ready",get:function(){return 3===this.state}},{key:"servers",get:function(){return this.serverCache}},{key:"channels",get:function(){return this.channelCache}},{key:"users",get:function(){return this.userCache}},{key:"PMChannels",get:function(){return this.pmChannelCache}},{key:"messages",get:function(){var a=[],b=!0,c=!1,d=void 0;try{for(var e,f=this.channelCache[Symbol.iterator]();!(b=(e=f.next()).done);b=!0){var g=e.value;a=a.concat(g.messages)}}catch(h){c=!0,d=h}finally{try{!b&&f["return"]&&f["return"]()}finally{if(c)throw d}}return a}}]),a}();b.exports=r},{"../ref/gameMap.json":15,"./Endpoints.js":2,"./PMChannel.js":3,"./channel.js":4,"./invite.js":6,"./message.js":7,"./server.js":8,"./user.js":9,fs:10,superagent:11,ws:14}],2:[function(a,b,c){"use strict";c.BASE_DOMAIN="discordapp.com",c.BASE="https://"+c.BASE_DOMAIN,c.WEBSOCKET_HUB="wss://"+c.BASE_DOMAIN+"/hub",c.API=c.BASE+"/api",c.AUTH=c.API+"/auth",c.LOGIN=c.AUTH+"/login",c.LOGOUT=c.AUTH+"/logout",c.USERS=c.API+"/users",c.SERVERS=c.API+"/guilds",c.CHANNELS=c.API+"/channels"},{}],3:[function(a,b,c){"use strict";function d(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}var e=function(){function a(a,b){for(var c=0;c1e3&&this.messages.splice(0,1);var c=!0,d=!1,e=void 0;try{for(var f,g=this.messages[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"isPrivate",get:function(){return!0}}]),a}();b.exports=f},{}],4:[function(a,b,c){"use strict";function d(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}var e=function(){function a(a,b){for(var c=0;c1e3&&this.messages.splice(0,1),this.getMessage("id",a.id)||this.messages.push(a),this.getMessage("id",a.id)}},{key:"getMessage",value:function(a,b){var c=!0,d=!1,e=void 0;try{for(var f,g=this.messages[Symbol.iterator]();!(c=(f=g.next()).done);c=!0){var h=f.value;if(h[a]===b)return h}}catch(i){d=!0,e=i}finally{try{!c&&g["return"]&&g["return"]()}finally{if(d)throw e}}return null}},{key:"toString",value:function(){return"<#"+this.id+">"}},{key:"client",get:function(){return this.server.client}},{key:"isPrivate",get:function(){return!1}},{key:"users",get:function(){return this.server.members}},{key:"members",get:function(){return this.server.members}}]),a}();b.exports=f},{}],5:[function(a,b,c){"use strict";var d=(a("superagent"),a("./Endpoints.js")),e=a("./Client.js"),f={Endpoints:d,Client:e};b.exports=f},{"./Client.js":1,"./Endpoints.js":2,superagent:11}],6:[function(a,b,c){"use strict";function d(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}var e=function(){function a(a,b){for(var c=0;c"}},{key:"toString",value:function(){return this.mention()}},{key:"equals",value:function(a){return a.id===this.id}},{key:"equalsStrict",value:function(a){return a.id===this.id&&a.avatar===this.avatar&&a.username===this.username&&a.discriminator===this.discriminator}},{key:"avatarURL",get:function(){return this.avatar?"https://discordapp.com/api/users/"+this.id+"/avatars/"+this.avatar+".jpg":null}}]),a}();b.exports=f},{}],10:[function(a,b,c){},{}],11:[function(a,b,c){function d(){}function e(a){var b={}.toString.call(a);switch(b){case"[object File]":case"[object Blob]":case"[object FormData]":return!0;default:return!1}}function f(a){return a===Object(a)}function g(a){if(!f(a))return a;var b=[];for(var c in a)null!=a[c]&&b.push(encodeURIComponent(c)+"="+encodeURIComponent(a[c]));return b.join("&")}function h(a){for(var b,c,d={},e=a.split("&"),f=0,g=e.length;g>f;++f)c=e[f],b=c.split("="),d[decodeURIComponent(b[0])]=decodeURIComponent(b[1]);return d}function i(a){var b,c,d,e,f=a.split(/\r?\n/),g={};f.pop();for(var h=0,i=f.length;i>h;++h)c=f[h],b=c.indexOf(":"),d=c.slice(0,b).toLowerCase(),e=r(c.slice(b+1)),g[d]=e;return g}function j(a){return a.split(/ *; */).shift()}function k(a){return p(a.split(/ *; */),function(a,b){var c=b.split(/ *= */),d=c.shift(),e=c.shift();return d&&e&&(a[d]=e),a},{})}function l(a,b){b=b||{},this.req=a,this.xhr=this.req.xhr,this.text="HEAD"!=this.req.method&&(""===this.xhr.responseType||"text"===this.xhr.responseType)||"undefined"==typeof this.xhr.responseType?this.xhr.responseText:null,
+this.statusText=this.req.xhr.statusText,this.setStatusProperties(this.xhr.status),this.header=this.headers=i(this.xhr.getAllResponseHeaders()),this.header["content-type"]=this.xhr.getResponseHeader("content-type"),this.setHeaderProperties(this.header),this.body="HEAD"!=this.req.method?this.parseBody(this.text?this.text:this.xhr.response):null}function m(a,b){var c=this;o.call(this),this._query=this._query||[],this.method=a,this.url=b,this.header={},this._header={},this.on("end",function(){var a=null,b=null;try{b=new l(c)}catch(d){return a=new Error("Parser is unable to parse the response"),a.parse=!0,a.original=d,c.callback(a)}if(c.emit("response",b),a)return c.callback(a,b);if(b.status>=200&&b.status<300)return c.callback(a,b);var e=new Error(b.statusText||"Unsuccessful HTTP response");e.original=a,e.response=b,e.status=b.status,c.callback(e,b)})}function n(a,b){return"function"==typeof b?new m("GET",a).end(b):1==arguments.length?new m("GET",a):new m(a,b)}var o=a("emitter"),p=a("reduce"),q="undefined"==typeof window?this||self:window;n.getXHR=function(){if(!(!q.XMLHttpRequest||q.location&&"file:"==q.location.protocol&&q.ActiveXObject))return new XMLHttpRequest;try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(a){}return!1};var r="".trim?function(a){return a.trim()}:function(a){return a.replace(/(^\s*|\s*$)/g,"")};n.serializeObject=g,n.parseString=h,n.types={html:"text/html",json:"application/json",xml:"application/xml",urlencoded:"application/x-www-form-urlencoded",form:"application/x-www-form-urlencoded","form-data":"application/x-www-form-urlencoded"},n.serialize={"application/x-www-form-urlencoded":g,"application/json":JSON.stringify},n.parse={"application/x-www-form-urlencoded":h,"application/json":JSON.parse},l.prototype.get=function(a){return this.header[a.toLowerCase()]},l.prototype.setHeaderProperties=function(a){var b=this.header["content-type"]||"";this.type=j(b);var c=k(b);for(var d in c)this[d]=c[d]},l.prototype.parseBody=function(a){var b=n.parse[this.type];return b&&a&&(a.length||a instanceof Object)?b(a):null},l.prototype.setStatusProperties=function(a){1223===a&&(a=204);var b=a/100|0;this.status=a,this.statusType=b,this.info=1==b,this.ok=2==b,this.clientError=4==b,this.serverError=5==b,this.error=4==b||5==b?this.toError():!1,this.accepted=202==a,this.noContent=204==a,this.badRequest=400==a,this.unauthorized=401==a,this.notAcceptable=406==a,this.notFound=404==a,this.forbidden=403==a},l.prototype.toError=function(){var a=this.req,b=a.method,c=a.url,d="cannot "+b+" "+c+" ("+this.status+")",e=new Error(d);return e.status=this.status,e.method=b,e.url=c,e},n.Response=l,o(m.prototype),m.prototype.use=function(a){return a(this),this},m.prototype.timeout=function(a){return this._timeout=a,this},m.prototype.clearTimeout=function(){return this._timeout=0,clearTimeout(this._timer),this},m.prototype.abort=function(){return this.aborted?void 0:(this.aborted=!0,this.xhr.abort(),this.clearTimeout(),this.emit("abort"),this)},m.prototype.set=function(a,b){if(f(a)){for(var c in a)this.set(c,a[c]);return this}return this._header[a.toLowerCase()]=b,this.header[a]=b,this},m.prototype.unset=function(a){return delete this._header[a.toLowerCase()],delete this.header[a],this},m.prototype.getHeader=function(a){return this._header[a.toLowerCase()]},m.prototype.type=function(a){return this.set("Content-Type",n.types[a]||a),this},m.prototype.accept=function(a){return this.set("Accept",n.types[a]||a),this},m.prototype.auth=function(a,b){var c=btoa(a+":"+b);return this.set("Authorization","Basic "+c),this},m.prototype.query=function(a){return"string"!=typeof a&&(a=g(a)),a&&this._query.push(a),this},m.prototype.field=function(a,b){return this._formData||(this._formData=new q.FormData),this._formData.append(a,b),this},m.prototype.attach=function(a,b,c){return this._formData||(this._formData=new q.FormData),this._formData.append(a,b,c),this},m.prototype.send=function(a){var b=f(a),c=this.getHeader("Content-Type");if(b&&f(this._data))for(var d in a)this._data[d]=a[d];else"string"==typeof a?(c||this.type("form"),c=this.getHeader("Content-Type"),"application/x-www-form-urlencoded"==c?this._data=this._data?this._data+"&"+a:a:this._data=(this._data||"")+a):this._data=a;return!b||e(a)?this:(c||this.type("json"),this)},m.prototype.callback=function(a,b){var c=this._callback;this.clearTimeout(),c(a,b)},m.prototype.crossDomainError=function(){var a=new Error("Origin is not allowed by Access-Control-Allow-Origin");a.crossDomain=!0,this.callback(a)},m.prototype.timeoutError=function(){var a=this._timeout,b=new Error("timeout of "+a+"ms exceeded");b.timeout=a,this.callback(b)},m.prototype.withCredentials=function(){return this._withCredentials=!0,this},m.prototype.end=function(a){var b=this,c=this.xhr=n.getXHR(),f=this._query.join("&"),g=this._timeout,h=this._formData||this._data;this._callback=a||d,c.onreadystatechange=function(){if(4==c.readyState){var a;try{a=c.status}catch(d){a=0}if(0==a){if(b.timedout)return b.timeoutError();if(b.aborted)return;return b.crossDomainError()}b.emit("end")}};var i=function(a){a.total>0&&(a.percent=a.loaded/a.total*100),b.emit("progress",a)};this.hasListeners("progress")&&(c.onprogress=i);try{c.upload&&this.hasListeners("progress")&&(c.upload.onprogress=i)}catch(j){}if(g&&!this._timer&&(this._timer=setTimeout(function(){b.timedout=!0,b.abort()},g)),f&&(f=n.serializeObject(f),this.url+=~this.url.indexOf("?")?"&"+f:"?"+f),c.open(this.method,this.url,!0),this._withCredentials&&(c.withCredentials=!0),"GET"!=this.method&&"HEAD"!=this.method&&"string"!=typeof h&&!e(h)){var k=this.getHeader("Content-Type"),l=n.serialize[k?k.split(";")[0]:""];l&&(h=l(h))}for(var m in this.header)null!=this.header[m]&&c.setRequestHeader(m,this.header[m]);return this.emit("request",this),c.send(h),this},m.prototype.then=function(a,b){return this.end(function(c,d){c?b(c):a(d)})},n.Request=m,n.get=function(a,b,c){var d=n("GET",a);return"function"==typeof b&&(c=b,b=null),b&&d.query(b),c&&d.end(c),d},n.head=function(a,b,c){var d=n("HEAD",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},n.del=function(a,b){var c=n("DELETE",a);return b&&c.end(b),c},n.patch=function(a,b,c){var d=n("PATCH",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},n.post=function(a,b,c){var d=n("POST",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},n.put=function(a,b,c){var d=n("PUT",a);return"function"==typeof b&&(c=b,b=null),b&&d.send(b),c&&d.end(c),d},b.exports=n},{emitter:12,reduce:13}],12:[function(a,b,c){function d(a){return a?e(a):void 0}function e(a){for(var b in d.prototype)a[b]=d.prototype[b];return a}b.exports=d,d.prototype.on=d.prototype.addEventListener=function(a,b){return this._callbacks=this._callbacks||{},(this._callbacks[a]=this._callbacks[a]||[]).push(b),this},d.prototype.once=function(a,b){function c(){d.off(a,c),b.apply(this,arguments)}var d=this;return this._callbacks=this._callbacks||{},c.fn=b,this.on(a,c),this},d.prototype.off=d.prototype.removeListener=d.prototype.removeAllListeners=d.prototype.removeEventListener=function(a,b){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var c=this._callbacks[a];if(!c)return this;if(1==arguments.length)return delete this._callbacks[a],this;for(var d,e=0;ed;++d)c[d].apply(this,b)}return this},d.prototype.listeners=function(a){return this._callbacks=this._callbacks||{},this._callbacks[a]||[]},d.prototype.hasListeners=function(a){return!!this.listeners(a).length}},{}],13:[function(a,b,c){b.exports=function(a,b,c){for(var d=0,e=a.length,f=3==arguments.length?c:a[d++];e>d;)f=b.call(null,f,a[d],++d,a);return f}},{}],14:[function(a,b,c){function d(a,b,c){var d;return d=b?new f(a,b):new f(a)}var e=function(){return this}(),f=e.WebSocket||e.MozWebSocket;b.exports=f?d:null,f&&(d.prototype=f.prototype)},{}],15:[function(a,b,c){b.exports=[{executables:{win32:["pol.exe"]},id:0,name:"FINAL FANTASY XI"},{executables:{win32:["ffxiv.exe","ffxiv_dx11.exe"]},id:1,name:"FINAL FANTASY XIV"},{executables:{win32:["Wow.exe","Wow-64.exe"]},id:3,name:"World of Warcraft"},{executables:{darwin:["LoLLauncher.app"],win32:["LolClient.exe","League of Legends.exe"]},id:4,name:"League of Legends"},{executables:{darwin:["Diablo%20III.app"],win32:["Diablo III.exe"]},id:5,name:"Diablo 3"},{executables:{darwin:["dota_osx.app"],win32:["dota2.exe"]},id:6,name:"DOTA 2"},{executables:{darwin:["Heroes.app"],win32:["Heroes of the Storm.exe","HeroesOfTheStorm_x64.exe","HeroesOfTheStorm.exe"]},id:7,name:"Heroes of the Storm"},{executables:{darwin:["Hearthstone.app"],win32:["Hearthstone.exe"]},id:8,name:"Hearthstone"},{executables:{win32:["csgo.exe"]},id:9,name:"Counter-Strike: Global Offensive"},{executables:{win32:["WorldOfTanks.exe"]},id:10,name:"World of Tanks"},{executables:{darwin:["gw2.app"],win32:["gw2.exe"]},id:11,name:"Guild Wars 2"},{executables:{win32:["dayz.exe"]},id:12,name:"Day Z"},{executables:{darwin:["starcraft%20ii.app"],win32:["starcraft ii.exe","SC2_x64.exe","SC2.exe"]},id:13,name:"Starcraft II"},{executables:{win32:["diablo.exe"]},id:14,name:"Diablo"},{executables:{win32:["diablo ii.exe"]},id:15,name:"Diablo 2"},{executables:{win32:["left4dead.exe"]},id:17,name:"Left 4 Dead"},{executables:{darwin:["minecraft.app"],win32:["minecraft.exe"]},id:18,name:"Minecraft"},{executables:{win32:["smite.exe"]},id:19,name:"Smite"},{executables:{win32:["bf4.exe"]},id:20,name:"Battlefield 4"},{executables:{win32:["AoK HD.exe","empires2.exe"]},id:101,name:"Age of Empire II"},{executables:{win32:["age3y.exe"]},id:102,name:"Age of Empire III"},{executables:{win32:["AlanWake.exe"]},id:104,name:"Alan Wake"},{executables:{win32:["alan_wakes_american_nightmare.exe"]},id:105,name:"Alan Wake's American Nightmare"},{executables:{win32:["AlienBreed2Assault.exe"]},id:106,name:"Alien Breed 2: Assault"},{executables:{win32:["Amnesia.exe"]},id:107,name:"Amnesia: The Dark Descent"},{executables:{win32:["UDK.exe"]},id:108,name:"Antichamber"},{executables:{win32:["ArcheAge.exe"]},id:109,name:"ArcheAge"},{executables:{win32:["arma3.exe"]},id:110,name:"Arma III"},{executables:{win32:["AC3SP.exe"]},id:111,name:"Assassin's Creed 3"},{executables:{win32:["Bastion.exe"]},id:112,name:"Bastion"},{executables:{win32:["BF2.exe"]},id:113,name:"Battlefield 2"},{executables:{win32:["bf3.exe"]},id:114,name:"Battlefield 3"},{executables:{win32:["Besiege.exe"]},id:116,name:"Besiege"},{executables:{win32:["Bioshock.exe"]},id:117,name:"Bioshock"},{executables:{win32:["Bioshock2.exe"]},id:118,name:"BioShock II"},{executables:{win32:["BioShockInfinite.exe"]},id:119,name:"BioShock Infinite"},{executables:{win32:["Borderlands2.exe"]},id:122,name:"Borderlands 2"},{executables:{win32:["braid.exe"]},id:123,name:"Braid"},{executables:{win32:["ShippingPC-StormGame.exe"]},id:124,name:"Bulletstorm"},{executables:{},id:125,name:"Cabal 2"},{executables:{win32:["CabalMain.exe"]},id:126,name:"Cabal Online"},{executables:{win32:["iw4mp.exe","iw4sp.exe"]},id:127,name:"Call of Duty: Modern Warfare 2"},{executables:{win32:["t6sp.exe"]},id:128,name:"Call of Duty: Black Ops"},{executables:{win32:["iw5mp.exe"]},id:129,name:"Call of Duty: Modern Warfare 3"},{executables:{win32:["RelicCOH.exe"]},id:132,name:"Company of Heroes"},{executables:{win32:["Crysis64.exe"]},id:135,name:"Crysis"},{executables:{win32:["Crysis2.exe"]},id:136,name:"Crysis 2"},{executables:{win32:["Crysis3.exe"]},id:137,name:"Crysis 3"},{executables:{win32:["Crysis.exe"]},id:138,name:"Crysis 4 "},{executables:{win32:["DATA.exe"]},id:140,name:"Dark Souls"},{executables:{win32:["DarkSoulsII.exe"]},id:141,name:"Dark Souls II"},{executables:{win32:["dfuw.exe"]},id:142,name:"Darkfall: Unholy Wars"},{executables:{win32:["DCGAME.exe"]},id:144,name:"DC Universe Online"},{executables:{win32:["DeadIslandGame.exe"]},id:145,name:"Dead Island"},{executables:{win32:["deadspace2.exe"]},id:146,name:"Dead Space 2"},{executables:{win32:["LOTDGame.exe"]},id:147,name:"Deadlight"},{executables:{win32:["dxhr.exe"]},id:148,name:"Deus Ex: Human Revolution"},{executables:{win32:["DeviMayCry4.exe"]},id:149,name:"Devil May Cry 4"},{executables:{win32:["DMC-DevilMayCry.exe"]},id:150,name:"DmC Devil May Cry"},{executables:{win32:["dirt2_game.exe"]},id:154,name:"DiRT 2"},{executables:{win32:["dirt3_game.exe"]},id:155,name:"DiRT 3"},{executables:{win32:["dota.exe"]},id:156,name:"DOTA"},{executables:{win32:["DoubleDragon.exe"]},id:158,name:"Double Dragon Neon"},{executables:{win32:["DragonAge2.exe"]},id:159,name:"Dragon Age II"},{executables:{win32:["DragonAgeInquisition.exe"]},id:160,name:"Dragon Age: Inquisition"},{executables:{win32:["daorigins.exe"]},id:161,name:"Dragon Age: Origins"},{executables:{win32:["DBXV.exe"]},id:162,name:"Dragon Ball XenoVerse"},{executables:{win32:["DukeForever.exe"]},id:163,name:"Duke Nukem Forever"},{executables:{darwin:["Dustforce.app"],win32:["dustforce.exe"]},id:164,name:"Dustforce"},{executables:{win32:["EliteDangerous32.exe"]},id:165,name:"Elite: Dangerous"},{executables:{win32:["exefile.exe"]},id:166,name:"Eve Online"},{executables:{win32:["eqgame.exe"]},id:167,name:"EverQuest"},{executables:{win32:["EverQuest2.exe"]},id:168,name:"EverQuest II"},{executables:{},id:169,name:"EverQuest Next"},{executables:{win32:["Engine.exe"]},id:170,name:"F.E.A.R."},{executables:{win32:["FEAR2.exe"]},id:171,name:"F.E.A.R. 2: Project Origin"},{executables:{win32:["fallout3.exe"]},id:172,name:"Fallout 3"},{executables:{win32:["FalloutNV.exe"]},id:174,name:"Fallout: New Vegas"},{executables:{win32:["farcry3.exe"]},id:175,name:"Far Cry 3"},{executables:{win32:["fifa15.exe"]},id:176,name:"FIFA 15"},{executables:{win32:["FTLGame.exe"]},id:180,name:"FTL: Faster Than Light"},{executables:{win32:["GTAIV.exe"]},id:181,name:"Grand Theft Auto 4"},{executables:{win32:["GTA5.exe"]},id:182,name:"Grand Theft Auto 5"},{executables:{win32:["Gw.exe"]},id:183,name:"Guild Wars"},{executables:{win32:["H1Z1.exe"]},id:186,name:"H1Z1"},{executables:{win32:["HL2HL2.exe","hl2.exe"]},id:188,name:"Half Life 2"},{executables:{win32:["HOMEFRONT.exe"]},id:195,name:"Homefront"},{executables:{win32:["invisibleinc.exe"]},id:196,name:"Invisible Inc."},{executables:{win32:["LANoire.exe"]},id:197,name:"L.A. Noire"},{executables:{win32:["Landmark64.exe"]},id:198,name:"Landmark"},{executables:{win32:["left4dead2.exe"]},id:201,name:"Left 4 Dead 2"},{executables:{win32:["lineage.exe"]},id:203,name:"Lineage"},{executables:{win32:["Magicka.exe"]},id:206,name:"Magicka"},{executables:{win32:["MapleStory.exe"]},id:208,name:"MapleStory"},{executables:{},id:209,name:"Mark of the Ninja"},{executables:{win32:["MassEffect.exe"]},id:210,name:"Mass Effect"},{executables:{win32:["MassEffect2.exe"]},id:211,name:"Mass Effect 2"},{executables:{win32:["MassEffect3Demo.exe"]},id:212,name:"Mass Effect 3"},{executables:{win32:["METAL GEAR RISING REVENGEANCE.exe"]},id:214,name:"Metal Gear Rising: Revengeance"},{executables:{win32:["metro2033.exe"]},id:215,name:"Metro 2033"},{executables:{win32:["MetroLL.exe"]},id:216,name:"Metro Last Light"},{executables:{win32:["MK10.exe"]},id:218,name:"Mortal Kombat X"},{executables:{win32:["speed.exe"]},id:219,name:"Need For Speed Most Wanted"},{executables:{},id:220,name:"Neverwinder"},{executables:{darwin:["Outlast.app"],win32:["OLGame.exe"]},id:221,name:"Outlast"},{executables:{win32:["PapersPlease.exe"]},id:222,name:"Papers, Please"},{executables:{win32:["payday_win32_release.exe"]},id:223,name:"PAYDAY"},{executables:{win32:["payday2_win32_release.exe"]},id:224,name:"PAYDAY2"},{executables:{win32:["PillarsOfEternity.exe"]},id:225,name:"Pillars of Eternity"},{executables:{win32:["PA.exe"]},id:226,name:"Planetary Annihilation"},{executables:{win32:["planetside2_x86.exe"]},id:227,name:"Planetside 2"},{executables:{win32:["hl2P.exe"]},id:228,name:"Portal"},{executables:{win32:["portal2.exe"]},id:229,name:"Portal 2"},{executables:{win32:["PrimalCarnageGame.exe"]},id:231,name:"Primal Cargnage"},{executables:{win32:["pCARS.exe"]},id:232,name:"Project Cars"},{executables:{win32:["RaceTheSun.exe"]},id:233,name:"Race The Sun"},{executables:{win32:["Rage.exe"]},id:234,name:"RAGE"},{executables:{win32:["ragexe.exe"]},id:235,name:"Ragnarok Online"},{executables:{win32:["rift.exe"]},id:236,name:"Rift"},{executables:{win32:["Rocksmith2014.exe"]},id:237,name:"Rocksmith 2014"},{executables:{win32:["SwiftKit-RS.exe","JagexLauncher.exe"]},id:238,name:"RuneScape"},{executables:{win32:["Shadowgrounds.exe"]},id:239,name:"Shadowgrounds"},{executables:{win32:["survivor.exe"]},id:240,name:"Shadowgrounds: Survivor"},{executables:{win32:["ShovelKnight.exe"]},id:241,name:"Shovel Knight"},{executables:{win32:["SimCity.exe"]},id:242,name:"SimCity"},{executables:{win32:["SporeApp.exe"]},id:245,name:"Spore"},{executables:{win32:["StarCitizen.exe"]},id:246,name:"Star Citizen"},{executables:{},id:247,name:"Star Trek Online"},{executables:{win32:["battlefront.exe"]},id:248,name:"Star Wars Battlefront"},{executables:{win32:["swtor.exe"]},id:249,name:"Star Wars: The Old Republic"},{executables:{win32:["starbound.exe","starbound_opengl.exe"]},id:250,name:"Starbound"},{executables:{win32:["starcraft.exe"]},id:251,name:"Starcraft"},{executables:{win32:["SSFIV.exe"]},id:253,name:"Ultra Street Fighter IV"},{executables:{win32:["superhexagon.exe"]},id:254,name:"Super Hexagon"},{executables:{win32:["swordandsworcery_pc.exe"]},id:255,name:"Superbrothers: Sword & Sworcery EP"},{executables:{win32:["hl2TF.exe"]},id:256,name:"Team Fortress 2"},{executables:{win32:["TERA.exe"]},id:258,name:"TERA"},{executables:{win32:["Terraria.exe"]},id:259,name:"Terraria"},{executables:{win32:["Bethesda.net_Launcher.exe"]},id:260,name:"The Elder Scrolls Online"},{executables:{win32:["TESV.exe"]},id:261,name:"The Elder Scrolls V: Skyrim"},{executables:{win32:["TheSecretWorld.exe"]},id:262,name:"The Secret World"},{executables:{win32:["TS3.exe","ts3w.exe"]},id:264,name:"The Sims 3"},{executables:{win32:["WALKINGDEAD101.EXE"]},id:265,name:"The Walking Dead"},{executables:{win32:["TheWalkingDead2.exe"]},id:266,name:"The Walking Dead Season Two"},{executables:{win32:["witcher3.exe"]},id:267,name:"The Witcher 3"},{executables:{win32:["Future Soldier.exe"]},id:268,name:"Tom Clancy's Ghost Recon: Future Solider"},{executables:{win32:["TombRaider.exe"]},id:269,name:"Tomb Raider (2013)"},{executables:{win32:["Torchlight.exe"]},id:271,name:"Torchlight"},{executables:{win32:["Torchlight2.exe"]},id:272,name:"Torchlight 2"},{executables:{win32:["Shogun2.exe"]},id:273,name:"Total War: Shogun 2"},{executables:{win32:["Transistor.exe"]},id:274,name:"Transistor"},{executables:{win32:["trine.exe"]},id:275,name:"Trine"},{executables:{win32:["trine2_32bit.exe"]},id:276,name:"Trine 2"},{executables:{win32:["UOKR.exe"]},id:277,name:"Ultima Online"},{executables:{win32:["aces.exe"]},id:279,name:"War Thunder"},{executables:{win32:["Warcraft III.exe","wc3.exe"]},id:281,name:"Warcraft 3: Reign of Chaos"},{executables:{win32:["Warcraft II BNE.exe"]},id:282,name:"Warcraft II"},{executables:{win32:["Warframe.x64.exe","Warframe.exe"]},id:283,name:"Warframe"},{executables:{win32:["watch_dogs.exe"]},id:284,name:"Watch Dogs"},{executables:{win32:["WildStar64.exe"]},id:285,name:"WildStar"},{executables:{win32:["XComGame.exe"]},id:288,name:"XCOM: Enemy Unknown"},{executables:{win32:["DFO.exe","dfo.exe"]},id:289,name:"Dungeon Fighter Online"},{executables:{win32:["aclauncher.exe","acclient.exe"]},id:290,name:"Asheron's Call"},{executables:{win32:["MapleStory2.exe"]},id:291,name:"MapleStory 2"},{executables:{win32:["ksp.exe"]},id:292,name:"Kerbal Space Program"},{executables:{win32:["PINBALL.EXE"]},id:293,name:"3D Pinball: Space Cadet"},{executables:{win32:["dave.exe"]},id:294,name:"Dangerous Dave"},{executables:{win32:["iwbtgbeta(slomo).exe","iwbtgbeta(fs).exe"]},id:295,name:"I Wanna Be The Guy"},{executables:{win32:["MechWarriorOnline.exe "]},id:296,name:"Mech Warrior Online"},{executables:{win32:["dontstarve_steam.exe"]},id:297,name:"Don't Starve"},{executables:{win32:["GalCiv3.exe"]},id:298,name:"Galactic Civilization 3"},{executables:{win32:["Risk of Rain.exe"]},id:299,name:"Risk of Rain"},{executables:{win32:["Binding_of_Isaac.exe","Isaac-ng.exe"]},id:300,name:"The Binding of Isaac"},{executables:{win32:["RustClient.exe"]},id:301,name:"Rust"},{executables:{win32:["Clicker Heroes.exe"]},id:302,name:"Clicker Heroes"},{executables:{win32:["Brawlhalla.exe"]},id:303,name:"Brawlhalla"},{executables:{win32:["TownOfSalem.exe"]},id:304,name:"Town of Salem"},{executables:{win32:["osu!.exe"]},id:305,name:"osu!"},{executables:{win32:["PathOfExileSteam.exe","PathOfExile.exe"]},id:306,name:"Path of Exile"},{executables:{win32:["Dolphin.exe"]},id:307,name:"Dolphin"},{executables:{win32:["RocketLeague.exe"]},id:308,name:"Rocket League"},{executables:{win32:["TJPP.exe"]},id:309,name:"Jackbox Party Pack"},{executables:{win32:["KFGame.exe"]},id:310,name:"Killing Floor 2"},{executables:{win32:["ShooterGame.exe"]},id:311,name:"Ark: Survival Evolved"},{executables:{win32:["LifeIsStrange.exe"]},id:312,name:"Life Is Strange"},{executables:{win32:["Client_tos.exe"]},id:313,name:"Tree of Savior"},{executables:{win32:["olliolli2.exe"]},id:314,name:"OlliOlli2"},{executables:{win32:["cw.exe"]},id:315,name:"Closers Dimension Conflict"},{executables:{win32:["ESSTEAM.exe","elsword.exe","x2.exe"]},id:316,name:"Elsword"},{executables:{win32:["ori.exe"]},id:317,name:"Ori and the Blind Forest"},{executables:{win32:["Skyforge.exe"]},id:318,name:"Skyforge"},{executables:{win32:["projectzomboid64.exe","projectzomboid32.exe"]},id:319,name:"Project Zomboid"},{executables:{win32:["From_The_Depths.exe"]},id:320,name:"The Depths"},{executables:{win32:["TheCrew.exe"]},id:321,name:"The Crew"},{executables:{win32:["MarvelHeroes2015.exe"]},id:322,name:"Marvel Heroes 2015"},{executables:{win32:["timeclickers.exe"]},id:324,name:"Time Clickers"},{executables:{win32:["eurotrucks2.exe"]},id:325,name:"Euro Truck Simulator 2"},{executables:{win32:["FarmingSimulator2015Game.exe"]},id:326,name:"Farming Simulator 15"},{executables:{win32:["strife.exe"]},id:327,name:"Strife"},{executables:{win32:["Awesomenauts.exe"]},id:328,name:"Awesomenauts"},{executables:{win32:["Dofus.exe"]},id:329,name:"Dofus"},{executables:{win32:["Boid.exe"]},id:330,name:"Boid"},{executables:{win32:["adventure-capitalist.exe"]},id:331,name:"AdVenture Capitalist"},{executables:{win32:["OrcsMustDie2.exe"]},id:332,name:"Orcs Must Die! 2"},{executables:{win32:["Mountain.exe"]},id:333,name:"Mountain"},{executables:{win32:["Valkyria.exe"]},id:335,name:"Valkyria Chronicles"},{executables:{win32:["ffxiiiimg.exe"]},id:336,name:"Final Fantasy XIII"},{executables:{win32:["TLR.exe"]},id:337,name:"The Last Remnant"},{executables:{win32:["Cities.exe"]},id:339,name:"Cities Skylines"},{executables:{win32:["worldofwarships.exe","WoWSLauncher.exe"]},id:341,name:"World of Warships"},{executables:{win32:["spacegame-Win64-shipping.exe"]},id:342,name:"Fractured Space"},{executables:{win32:["thespacegame.exe"]},id:343,name:"Ascent - The Space Game"},{executables:{win32:["DuckGame.exe"]},id:344,name:"Duck Game"},{executables:{win32:["PPSSPPWindows.exe"]},id:345,name:"PPSSPP"},{executables:{win32:["MBAA.exe"]},id:346,name:"Melty Blood Actress Again: Current Code"},{executables:{win32:["TheWolfAmongUs.exe"]},id:347,name:"The Wolf Among Us"},{executables:{win32:["SpaceEngineers.exe"]},id:348,name:"Space Engineers"},{executables:{win32:["Borderlands.exe"]},id:349,name:"Borderlands"},{executables:{win32:["100orange.exe"]},id:351,name:"100% Orange Juice"},{executables:{win32:["reflex.exe"]},id:354,name:"Reflex"},{executables:{win32:["pso2.exe"]},id:355,name:"Phantasy Star Online 2"},{executables:{win32:["AssettoCorsa.exe"]},id:356,name:"Assetto Corsa"},{executables:{win32:["iw3mp.exe","iw3sp.exe"]},id:357,name:"Call of Duty 4: Modern Warfare"},{executables:{win32:["WolfOldBlood_x64.exe"]},id:358,name:"Wolfenstein: The Old Blood"},{executables:{win32:["castle.exe"]},id:359,name:"Castle Crashers"},{executables:{win32:["vindictus.exe"]},id:360,name:"Vindictus"},{executables:{win32:["ShooterGame-Win32-Shipping.exe"]},id:361,name:"Dirty Bomb"},{executables:{win32:["BatmanAK.exe"]},id:362,name:"Batman Arkham Knight"},{executables:{win32:["drt.exe"]},id:363,name:"Dirt Rally"},{executables:{win32:["rFactor.exe"]},id:364,name:"rFactor"},{executables:{win32:["clonk.exe"]},id:365,name:"Clonk Rage"},{executables:{win32:["SRHK.exe"]},id:366,name:"Shadowrun: Hong Kong"},{executables:{win32:["Insurgency.exe"]},id:367,name:"Insurgency"},{executables:{win32:["StepMania.exe"]},id:368,name:"Step Mania"},{executables:{win32:["FirefallCLient.exe"]},id:369,name:"Firefall"},{executables:{win32:["mirrorsedge.exe"]},id:370,name:"Mirrors Edge"},{executables:{win32:["MgsGroundZeroes.exe"]},id:371,name:"Metal Gear Solid V: Ground Zeroes"},{executables:{win32:["mgsvtpp.exe"]},id:372,name:"Metal Gear Solid V: The Phantom Pain"},{executables:{win32:["tld.exe"]},id:373,name:"The Long Dark"},{executables:{win32:["TKOM.exe"]},id:374,name:"Take On Mars"},{executables:{win32:["robloxplayerlauncher.exe","Roblox.exe"]},id:375,name:"Roblox"},{executables:{win32:["eu4.exe"]},id:376,name:"Europa Universalis 4"},{executables:{win32:["APB.exe"]},id:377,name:"APB Reloaded"},{executables:{win32:["Robocraft.exe"]},id:378,name:"Robocraft"},{executables:{win32:["Unity.exe"]},id:379,name:"Unity"},{executables:{win32:["Simpsons.exe"]},id:380,name:"The Simpsons: Hit & Run"},{executables:{win32:["Dnlauncher.exe","DragonNest.exe"]},id:381,name:"Dragon Nest"},{executables:{win32:["Trove.exe"]},id:382,name:"Trove"},{executables:{win32:["EndlessLegend.exe"]},id:383,name:"Endless Legend"},{executables:{win32:["TurbineLauncher.exe","dndclient.exe"]},id:384,name:"Dungeons & Dragons Online"},{executables:{win32:["quakelive.exe","quakelive_steam.exe"]},id:385,name:"Quake Live"},{executables:{win32:["7DaysToDie.exe"]},id:386,name:"7DaysToDie"},{executables:{win32:["SpeedRunners.exe"]},id:387,name:"SpeedRunners"},{executables:{win32:["gamemd.exe"]},id:388,name:"Command & Conquer: Red Alert 2"},{executables:{win32:["generals.exe"]},id:389,name:"Command & Conquer Generals: Zero Hour"},{executables:{win32:["Oblivion.exe"]},id:390,name:"The Elder Scrolls 4: Oblivion"},{executables:{win32:["mgsi.exe"]},id:391,name:"Metal Gear Solid"},{executables:{win32:["EoCApp.exe"]},id:392,name:"Divinity - Original Sin"},{executables:{win32:["Torment.exe"]},id:393,name:"Planescape: Torment"},{executables:{win32:["HexPatch.exe"]},id:394,name:"Hex: Shards of Fate"},{executables:{win32:["NS3FB.exe"]},id:395,name:"Naruto Shippuden Ultimate Ninja Storm 3 Full Burst"},{executables:{win32:["NSUNSR.exe"]},id:396,name:"Naruto Shippuden Ultimate Ninja Storm Revolution"},{executables:{win32:["SaintsRowIV.exe"]},id:397,name:"Saints Row IV"},{executables:{win32:["Shadowrun.exe"]},id:398,name:"Shadowrun"},{executables:{win32:["DungeonoftheEndless.exe"]},id:399,name:"Dungeon of the Endless"},{executables:{win32:["Hon.exe"]},id:400,name:"Heroes of Newerth"},{executables:{win32:["mabinogi.exe"]},id:401,name:"Mabinogi"},{executables:{win32:["CoD2MP_s.exe","CoDSP_s.exe"]},id:402,name:"Call of Duty 2:"},{executables:{win32:["CoDWaWmp.exe","CoDWaw.exe"]},id:403,name:"Call of Duty: World at War"},{executables:{win32:["heroes.exe"]},id:404,name:"Mabinogi Heroes (Vindictus) "},{executables:{win32:["KanColleViewer.exe"]},id:405,name:"KanColle "},{executables:{win32:["cyphers.exe"]},id:406,name:"Cyphers"},{executables:{win32:["RelicCoH2.exe"]},id:407,name:"Company of Heroes 2"},{executables:{win32:["MJ.exe"]},id:408,name:"セガNET麻雀MJ"},{executables:{win32:["ge.exe"]},id:409,name:"Granado Espada"},{executables:{win32:["NovaRO.exe"]},id:410,name:"Nova Ragnarok Online"},{executables:{win32:["RivalsofAether.exe"]},id:411,name:"Rivals of Aether"},{executables:{win32:["bfh.exe"]},id:412,name:"Battlefield Hardline"},{executables:{win32:["GrowHome.exe"]},id:413,name:"Grow Home"},{executables:{win32:["patriots.exe"]},id:414,name:"Rise of Nations Extended"},{executables:{win32:["Railroads.exe"]},id:415,name:"Sid Meier's Railroads!"},{executables:{win32:["Empire.exe"]},id:416,name:"Empire: Total War"},{executables:{win32:["Napoleon.exe"]},id:417,name:"Napoleon: Total War"},{executables:{win32:["gta_sa.exe"]},id:418,name:"Grand Theft Auto: San Andreas"},{executables:{win32:["MadMax.exe"]},id:419,name:"Mad Max"},{executables:{win32:["Titanfall.exe"]},id:420,name:"Titanfall"},{executables:{win32:["age2_x1.exe"]},id:421,name:"Age of Empires II: The Conquerors"},{executables:{win32:["Rome2.exe"]},id:422,name:"Total War: ROME 2"},{executables:{win32:["ShadowOfMordor.exe"]},id:423,name:"Middle-earth: Shadow of Mordor"},{executables:{win32:["Subnautica.exe"]},id:424,name:"Subnautica"},{executables:{win32:["anno5.exe"]},id:425,name:"Anno 2070"},{executables:{win32:["carrier.exe"]},id:426,name:"Carrier Command Gaea Mission"},{executables:{win32:["DarksidersPC.exe"]},id:427,name:"Darksiders"},{executables:{win32:["Darksiders2.exe"]},id:428,name:"Darksiders 2"},{executables:{win32:["mudlet.exe"]},id:429,name:"Mudlet"},{executables:{win32:["DunDefLauncher.exe"]},id:430,name:"Dungeon Defenders II"},{executables:{win32:["hng.exe"]},id:431,name:"Heroes and Generals"},{executables:{win32:["WFTOGame.exe"]},id:432,name:"War of the Overworld"},{executables:{win32:["Talisman.exe"]},id:433,name:"Talisman: Digital Edition"},{executables:{win32:["limbo.exe"]},id:434,name:"Limbo"},{executables:{win32:["ibbobb.exe"]},id:435,name:"ibb & obb"},{executables:{win32:["BattleBlockTheater.exe"]},id:436,name:"BattleBlock Theater"},{executables:{win32:["iracinglauncher.exe","iracingsim.exe","iracingsim64.exe"]},id:437,name:"iRacing"},{executables:{win32:["CivilizationV_DX11.exe"]},id:438,name:"Civilization V"}]},{}]},{},[5])(5)});
\ No newline at end of file