/*
Code heavily influenced by jayarjo's fork
https://github.com/jayarjo/bunyip/blob/master/lib/browserstack.js
184874
function BrowserStack(config) {
	var workers = [],
		bs = config.browserstack,
		tunnellink = config.tunnellink,
		timeout = bs.timeout || 480, // 8 minutes
		client = browserstack.createClient(bs),
		platforms = /^(all|ios|win|mac|android|opera)$/,
		osMap = {},

	loadBrowsers = function(browsers) {
		browsers.forEach(function(browser, idx){
			client.createWorker(browser, function(err, worker){
				if(err) {
					console.log(err);
					console.log("Whoops! BrowserStack failed to create a worker: %s", err);
				} else {
					console.log("  BrowserStack "+ (browser.browser || browser.device) + " " + browser.version +" worker launched: %s", worker.id);
					workers.push(worker.id);
				}
			});
		});
	},
	availableBrowsers = function(cb) {
		client.getBrowsers(function(err, browsers){
			if(!err) {
				cb(browsers);
			}

			console.log(err);
		});
	},
	killBrowser = function(id, cb) {
		client.terminateWorker(id, function(err, data) {
			if(cb) {
				cb(err, data);
			}
		});
	},
	killBrowsers = function() {
		client.getWorkers(function(err, workers) {
			workers.forEach(function(worker, i) {
				killBrowser(worker.id, function(err, data) {
					console.log("Worker %s successfully killed, it ran for %ss", this, Math.round(data.time));
				}.bind(worker.id));
			});
		});
	},
	getWorkers = function() {
		client.getWorkers(function(err, workers) {
			var running = [],
				queued = [];

			workers.forEach(function(worker, i) {
				if(worker.status === "running") {
					running.push((worker.browser || worker.device) + " - " + worker.version + " ("+worker.id+") ");
				} else if(worker.status === "queue") {
					queued.push((worker.browser || worker.device) + " - " + worker.version + " ("+worker.id+") ");
				}
			});

			console.log("Running:\n\t" + running.join("\n\t"));
			console.log("Queued:\n\t" + queued.join("\n\t"));
		});
	},
	manageBrowsers = function (program) {
		var testURL = "http://"+config.tunnellink,
			timeout = bs.timeout,
			browsers = [],
			file = false;

		if(program.browsers && !platforms.test(program.browsers)) {
			try {
				file = fs.readFileSync(program.browsers,'utf8');
			} catch(e) {}
			
			if(file) {
				// You can pass in a JSON file specifying the browsers
				browsers = JSON.parse(file);
				
				browsers.forEach(function(browser,i) {
					browser.url = testURL;
					browser.timeout = timeout;
				});
			} else {
				var opt = program.browsers.split('|'),
					versions, os, platform, data;

				opt.forEach(function(browser,i) {
					data = browser.split("/");
					platform = data[0].split(":");
					browser = platform[0];
					os = platform[1];
					versions = data[1].split(',');

					versions.forEach(function(ver, i) {
						browsers.push({
							browser: browser,
							device:  browser,
							os: os,
							version: ver,
							url: testURL,
							timeout: timeout
						});
					});
				});
			}
			
			this.loadBrowsers(browsers);
		} else if(platforms.test(program.browsers)) {
			
			if(program.browsers === "all") {
				this.availableBrowsers(function(list){
					list.forEach(function(browser, i) {
						browser.url = testURL;
						browser.timeout = timeout;
					});

					this.loadBrowsers(list);
				});
			} else {
				this.platformBrowsers(program.browsers);
			}
		}
	},
	platformBrowsers = function(os) {
		osMap = {};

		availableBrowsers(function(browsers) {
			browsers.forEach(function(browser, i) {
				if(!osMap[browser.os]) {
					osMap[browser.os] = [];
				}
				osMap[browser.os].push({
					browser: browser.browser || "",
					device: browser.device || "",
					version: browser.version,
					os: browser.os,
					url: "http://" + config.tunnellink,
					timeout: timeout
				});
			});

			loadBrowsers(osMap[os]);
		});
	};

	this.loadBrowsers		= loadBrowsers;
	this.availableBrowsers	= availableBrowsers;
	this.killBrowser		= killBrowser;
	this.killBrowsers		= killBrowsers;
	this.getWorkers			= getWorkers;
	this.manageBrowsers		= manageBrowsers;
	this.platformBrowsers	= platformBrowsers;
}
163893
function compileSourcePreCode() {
    var $version = '##version##';

    var componentRenderers = {};

    function extend(target, source) {
        if (source) {
            Object.keys(source).forEach(function (key) {
                var value = source[key];
                if (typeof value !== 'undefined') {
                    target[key] = value;
                }
            });
        }

        return target;
    }

    function each(array, iterator) {
        if (array && array.length > 0) {
            for (var i = 0, l = array.length; i < l; i++) {
                if (iterator(array[i], i) === false) {
                    break;
                }
            }
        }
    }

    function contains(array, value) {
        var result;
        each(array, function (item) {
            result = item === value;
            return !result;
        });

        return result;
    }

    var HTML_ENTITY = {
        /* jshint ignore:start */
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        /* eslint-disable quotes */
        "'": '&#39;'
        /* eslint-enable quotes */
        /* jshint ignore:end */
    };

    function htmlFilterReplacer(c) {
        return HTML_ENTITY[c];
    }

    function escapeHTML(source) {
        if (source == null) {
            return '';
        }

        if (typeof source === 'string') {
            return source ? source.replace(/[&<>"']/g, htmlFilterReplacer) : '';
        }

        return '' + source;
    }

    function _classFilter(source) {
        if (source instanceof Array) {
            return source.join(' ');
        }

        return source;
    }

    function _styleFilter(source) {
        if (typeof source === 'object') {
            var result = '';
            if (source) {
                Object.keys(source).forEach(function (key) {
                    result += key + ':' + source[key] + ';';
                });
            }

            return result;
        }

        return source;
    }

    function _xclassFilter(source) {
        if (source instanceof Array) {
            source = source.join(' ');
        }

        return source ? ' ' + source : '';
    }

    function _xstyleFilter(source) {
        var result;
        if (typeof source === 'object') {
            result = '';
            if (source) {
                Object.keys(source).forEach(function (key) {
                    result += key + ':' + source[key] + ';';
                });
            }
        }
        else {
            result = source;
        }

        return result ? ';' + result : '';
    }

    function attrFilter(name, value) {
        if (value) {
            return ' ' + name + '="' + value + '"';
        }

        return '';
    }

    function boolAttrFilter(name, value) {
        if (value && value !== 'false' && value !== '0') {
            return ' ' + name;
        }

        return '';
    }

    function callFilter(ctx, name, args) {
        var filter = ctx.proto.filters[name];
        if (typeof filter === 'function') {
            return filter.apply(ctx, args);
        }
    }
}
1064483
function parseCodeChunkToAST(src, options) {
    src = src
    .replace(/@/g, '\uFFDA')
    .replace(/#/g, '\uFFDB')
    ;
    var ast = recast.parse(src);
    return ast;
}
357621
function makeAcyclic(g) {
    var onStack = {};
    var visited = {};

    function dfs(u) {
      if (u in visited) {
        return;
      }
      visited[u] = true;
      onStack[u] = true;
      g.successors(u).forEach(function(v) {
        if (v in onStack) {
          g.addEdge(v, u);
          g.removeEdge(u, v);
        } else {
          dfs(v);
        }
      });
      delete onStack[u];
    }

    g.nodes().forEach(function(u) {
      dfs(u);
    });
  }
545653
function parse(code) {
  var opts = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];

  opts.allowHashBang = true;
  opts.sourceType = "module";
  opts.ecmaVersion = Infinity;
  opts.plugins = {
    jsx: true,
    flow: true
  };
  opts.features = {};

  for (var key in _transformation2["default"].pipeline.transformers) {
    opts.features[key] = true;
  }

  var ast = babylon.parse(code, opts);

  if (opts.onToken) {
    // istanbul ignore next

    var _opts$onToken;

    (_opts$onToken = opts.onToken).push.apply(_opts$onToken, ast.tokens);
  }

  if (opts.onComment) {
    // istanbul ignore next

    var _opts$onComment;

    (_opts$onComment = opts.onComment).push.apply(_opts$onComment, ast.comments);
  }

  return ast.program;
}
221461
function () {
/*Line 138 - 'AtomViewStack.js' */                var element = this.get_element();
/*Line 139 - 'AtomViewStack.js' */                var $element = $(element);
/*Line 140 - 'AtomViewStack.js' */                $element.addClass("atom-view-stack");
/*Line 141 - 'AtomViewStack.js' */                baseType.init.call(this);

/*Line 143 - 'AtomViewStack.js' */                if (!element.parentNode.atomControl) {
/*Line 144 - 'AtomViewStack.js' */                    $element.addClass("atom-view-stack-fill");
/*Line 145 - 'AtomViewStack.js' */                }
/*Line 146 - 'AtomViewStack.js' */                $element.addClass(this._swipeDirection);

/*Line 148 - 'AtomViewStack.js' */                //this.updateUI();
/*Line 149 - 'AtomViewStack.js' */            }
214673
function MatrixStack () {

    // # Gl-Matrix inheritance
    // Create inheritance if not already created.
    // Doing it on first initialisation so that `gl-matrix`
    // is not require just to load W.js on node
    if ( typeof MatrixStack.prototype.glMatrix === 'undefined' ) {
        // Extend gl-matrix as in browser it is global, in node it is a module
        if (typeof module !== 'undefined' && module.exports) {
            // NPM
            W.extend( MatrixStack.prototype, require( 'gl-matrix' ) );
        } else {
            // re-wrap in browser
            W.extend( MatrixStack.prototype, {
                glMatrix : glMatrix,
                mat2 : mat2,
                mat2d : mat2d,
                mat3 : mat3,
                mat4 : mat4,
                quat : quat,
                vec2 : vec2,
                vec3 : vec3,
                vec4 : vec4
            });
        }
    }

    this.stack = [ this.mat4.create() ];
    
}
105289
function prettifyStackTrace(appName, clientConfig, stack) {
	if (!appName || !clientConfig || !Array.isArray(stack)) {
		return;
	}

	var app = mage.core.app.get(appName);
	if (!app) {
		return;
	}

	var responses = app.getResponsesForClientConfig(app.getBestConfig(clientConfig));

	// On the client side, stacktrace.js has turned each entry into "symbol@file:line:col".
	// Now try to source-map our way through it.

	function replacer(match, file, line, col) {
		line = parseInt(line, 10);
		col = parseInt(col, 10);

		for (var i = 0; i < responses.length; i++) {
			var meta = responses[i].meta;
			var sourcemap = meta && meta.sourcemaps && meta.sourcemaps[file];

			if (!sourcemap) {
				continue;
			}

			var smc = new SourceMapConsumer(sourcemap);
			var pos = smc.originalPositionFor({ line: line, column: col });

			if (pos) {
				return pos.name + ' (' + file + ':' + pos.line + ':' + pos.column + ')';
			}
		}

		return match;
	}

	for (var i = 0; i < stack.length; i++) {
		var frame = stack[i];

		if (typeof frame === 'string') {
			// rewrite the stack frame and put it back in the stack

			stack[i] = frame.replace(/^.+?@(.+?):([0-9]+):([0-9]+)$/, replacer);
		}
	}
}
289797
function StackTrace$$getSync(opts) {
            opts = _merge(_options, opts);
            var err = _generateError();
            var stack = _isShapedLikeParsableError(err) ? ErrorStackParser.parse(err) : StackGenerator.backtrace(opts);
            return _filtered(stack, opts.filter);
        }
1046485
function extractStacktrace( e, offset ) {
	offset = offset === undefined ? 4 : offset;

	var stack, include, i;

	if ( e.stack ) {
		stack = e.stack.split( "\n" );
		if ( /^error$/i.test( stack[ 0 ] ) ) {
			stack.shift();
		}
		if ( fileName ) {
			include = [];
			for ( i = offset; i < stack.length; i++ ) {
				if ( stack[ i ].indexOf( fileName ) !== -1 ) {
					break;
				}
				include.push( stack[ i ] );
			}
			if ( include.length ) {
				return include.join( "\n" );
			}
		}
		return stack[ offset ];

	// Support: Safari <=6 only
	} else if ( e.sourceURL ) {

		// exclude useless self-reference for generated Error objects
		if ( /qunit.js$/.test( e.sourceURL ) ) {
			return;
		}

		// for actual exceptions, this is useful
		return e.sourceURL + ":" + e.line;
	}
}
98787
function Fbbot(options)
{
  if (!(this instanceof Fbbot)) return new Fbbot(options);

  /**
   * Custom options per instance
   * @type {object}
   */
  this.options = merge(Fbbot.defaults, options || {});

  /**
   * Store credentials
   * @type {object}
   */
  this.credentials =
  {
    // keep simple naming for internal reference
    token : this.options.pageAccessToken || this.options.token,
    secret: this.options.verifyToken || this.options.secret
  };

  if (!this.credentials.token || !this.credentials.secret)
  {
    throw new Error('Both `token` (pageAccessToken) and `secret` (verifyToken) are required');
  }

  // compose apiUrl
  this.options.apiUrl += this.credentials.token;

  /**
   * expose logger
   * @type {object}
   */
  this.logger = options.logger || bole(options.name || 'fbbot');

  /**
   * middleware storage (per event)
   * @type {object}
   * @private
   */
  this._stack = {};

  /**
   * lock-in public methods
   * wrap `_handler` with agnostic to accommodate different http servers
   * @type {function}
   */
  this.requestHandler = agnostic(this._handler.bind(this));

  // attach lifecycle filters
  inMiddleware(this);
  outMiddleware(this);

  /**
   * create incoming traverse paths
   * @type {Traverse}
   * @private
   */
  this._incoming = new Traverse(inTraverse.steps, {
    entry     : middleware.entryPoint,
    middleware: inTraverse.middleware.bind(this),
    emitter   : inTraverse.emitter.bind(this),
    prefix    : inTraverse.prefix
  });
  // wrap linkParent method
  this._incoming.linkParent = inTraverse.linkParent.bind(null, this._incoming.linkParent);

  /**
   * create outgoing traverse paths
   * @type {Traverse}
   * @private
   */
  this._outgoing = new Traverse(outTraverse.steps, {
    middleware: outTraverse.middleware.bind(this),
    emitter   : outTraverse.emitter.bind(this),
    prefix    : outTraverse.prefix
  });
  // wrap linkParent method
  this._outgoing.linkParent = outTraverse.linkParent.bind(null, this._outgoing.linkParent);
}
991812
function plainHTMLBlocks() {

    const plainBlocks = ['code-example', 'code-tabs'];

    // Create matchers for each block
    const anyBlockMatcher = new RegExp('^' + createOpenMatcher(`(${plainBlocks.join('|')})`));

    const Parser = this.Parser;
    const blockTokenizers = Parser.prototype.blockTokenizers;
    const blockMethods = Parser.prototype.blockMethods;

    blockTokenizers.plainHTMLBlocks = tokenizePlainHTMLBlocks;
    blockMethods.splice(blockMethods.indexOf('html'), 0, 'plainHTMLBlocks');

    function tokenizePlainHTMLBlocks(eat, value, silent) {
      const openMatch = anyBlockMatcher.exec(value);
      if (openMatch) {
        const blockName = openMatch[1];
        try {
          const fullMatch = matchRecursiveRegExp(value, createOpenMatcher(blockName), createCloseMatcher(blockName))[0];
          if (silent || !fullMatch) {
            // either we are not eating (silent) or the match failed
            return !!fullMatch;
          }
          return eat(fullMatch[0])({
            type: 'html',
            value: fullMatch[0]
          });
        } catch(e) {
          this.file.fail('Unmatched plain HTML block tag ' + e.message);
        }
      }
    }
  }
195178
function ErrorStackParser$$parseOpera11(error) {
	            var filtered = _filter(error.stack.split('\n'), function (line) {
	                return !!line.match(FIREFOX_SAFARI_STACK_REGEXP) &&
	                    !line.match(/^Error created at/);
	            }, this);
	
	            return _map(filtered, function (line) {
	                var tokens = line.split('@');
	                var locationParts = this.extractLocation(tokens.pop());
	                var functionCall = (tokens.shift() || '');
	                var functionName = functionCall
	                        .replace(/<anonymous function(: (\w+))?>/, '$2')
	                        .replace(/\([^\)]*\)/g, '') || undefined;
	                var argsRaw;
	                if (functionCall.match(/\(([^\)]*)\)/)) {
	                    argsRaw = functionCall.replace(/^[^\(]+\(([^\)]*)\)$/, '$1');
	                }
	                var args = (argsRaw === undefined || argsRaw === '[arguments not available]') ? undefined : argsRaw.split(',');
	                return new StackFrame(functionName, args, locationParts[0], locationParts[1], locationParts[2], line);
	            }, this);
	        }
1175221
function(code, ctx){
    // Wrap code blocks with {}.
    // we only wrap unbuffered code blocks ATM
    // since they are usually flow control
    // Buffer code
    //
    var ast = [];
    if (code.buffer) {
      var val = code.val.trim();
      var tpl = tpl_interp;
      var tplv = {
        VALUE: code.astVal || this.parseExpr(code.val)
      }
      if (code.mustEscape !== false) {
        tpl = tpl_interp_escape;
        tplv.ESCAPE = this.runtime('escape', true);
      }
      push.apply(ast, this.bufferAST(tpl(tplv).expression));
    } else {

      var val = code.val.trim();
      this.codeBuffer += "\n" + val;

      if (code.block) {
        this.codeIndex++;
        var marker = "PUGMARKER"+this.codeIndex;
        this.codeBuffer += "\n{" + marker + "}\n";
        // snaphsot current unbuffered code level
        // this is necessary to accept embedded code blocks
        // - if (true) {
        //   - var a = 1;
        // - }
        // but breaks the "should be reasonably fast" compile test
        // note: we should add a test for this in pug
        var savedCodeBuffer = this.codeBuffer;
        var savedCodeMarker = this.codeMarker;
        var savedCodeIndex = this.codeIndex;

        this.codeBuffer = '_=function*(){';
        this.codeMarker = {};
        this.codeIndex = -1;

        var body = this.visit(code.block, code);

        this.codeBuffer = savedCodeBuffer;
        this.codeMarker = savedCodeMarker;
        this.codeIndex = savedCodeIndex;
       
        this.codeMarker[marker] = body; 
      }

      var idx = ctx.nodes.indexOf(code) + 1;
      if (idx == ctx.nodes.length || ctx.nodes[idx].type != 'Code' || ctx.nodes[idx].buffer) {
        try {
          var src = this.codeBuffer + '}';
          var tpl = babelTemplate(src);
          push.apply(ast, tpl(this.codeMarker).expression.right.body.body);
          this.codeBuffer = '_=function*(){';
          this.codeIndex = -1;
          this.codeMarker = {};
        } catch(e) {
          var codeError = this.codeBuffer.substr(14).trim()
          this.error('Unbuffered code structure could not be parsed; ' + e.message + ' in ' + codeError, codeError, code)
        }
      }

    }
    return ast;
  }
558267
async function main({ isFragment, needsHelp, showVersion, useTabs }) {
  /* eslint-disable no-console */
  const stdin = await getStdin()

  if (showVersion) {
    return console.log(version)
  }

  if (needsHelp || !stdin) {
    return console.log(help)
  }

  const pug = html2pug(stdin, { isFragment, useTabs })
  return console.log(pug)

  /* eslint-enable no-console */
}
559224
function breadthFirstSearch(obj, handler) {
  var childrenKey = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'children';
  var reverse = arguments[3];

  var rootChildren = hp.isArray(obj) ? obj : [obj];
  //
  var stack = rootChildren.map(function (v, i) {
    return { item: v, index: i };
  });
  if (reverse) {
    stack.reverse();
  }

  var _loop = function _loop() {
    var _stack$shift = stack.shift(),
        item = _stack$shift.item,
        index = _stack$shift.index,
        parent = _stack$shift.parent;

    var r = handler(item, index, parent);
    if (r === false) {
      // stop
      return {
        v: void 0
      };
    } else if (r === 'skip children') {
      return 'continue';
    } else if (r === 'skip siblings') {
      stack = stack.filter(function (v) {
        return v.parent !== parent;
      });
    }
    if (item.children) {
      var _stack;

      var children = item.children;
      if (reverse) {
        children = children.slice();
        children.reverse();
      }
      var pushStack = children.map(function (v, i) {
        return { item: v, index: i, parent: item };
      });
      (_stack = stack).push.apply(_stack, _toConsumableArray(pushStack));
    }
  };

  while (stack.length) {
    var _ret = _loop();

    switch (_ret) {
      case 'continue':
        continue;

      default:
        if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v;
    }
  }
}
818037
function Slack(opts, debug) {
  if (!(this instanceof Slack)) return new Slack(opts);
  this.opts = opts;
  this.debug = debug;

  /**
   * Do everything.
   */

  this.import = function *() {
    try {
      console.log('Starting import');
      yield this.tokens();
      console.log('Got tokens');
      yield this.login();
      console.log('Logged in');
    } catch (e) {
      console.log('Uh oh! ' + e);
      throw e;
    }
    console.log('Getting emoji page');
    var emojiList = '';
    var aliasList = '';
    for (var i = 0; i < Object.keys(this.opts.emojis).length; i++) {
      var e = this.opts.emojis[i];
      if (e.src) {
        var uploadRes = yield this.upload(e.name, e.src);
        emojiList += ' :' + e.name + ':';
      }
      if (e.aliases) {
        for (var n = 0; n < e.aliases.length; n++) {
          yield this.alias(e.name, e.aliases[n]);
          aliasList += ' :' + e.aliases[n] + ':';
        }
      }
    }
    console.log('Uploaded emojis:' + emojiList);
    console.log('Uploaded emoji aliases:' + aliasList);
    return 'Success';
  };

  /**
   * Get login page (aka credentials).
   */

  this.tokens = function *() {
    var opts = this.opts;
    opts.jar = opts.jar || { _jar: { store: { idx: {} } } };
    var load = {
      url: opts.url + loginFormPath,
      headers: headers,
      jar: opts.jar,
      method: 'GET'
    };
    var res = yield request(load);
    var $ = cheerio.load(res[0].body);
    if (this.debug) write($('title').text(), $.html());
    opts.formData = {
      signin: $('#signin_form input[name="signin"]').attr('value'),
      redir: $('#signin_form input[name="redir"]').attr('value'),
      crumb: $('#signin_form input[name="crumb"]').attr('value'),
      remember: 'on',
      email: opts.email,
      password: opts.password
    };
    if (!opts.formData.signin && !opts.formData.redir && !opts.formData.crumb) throw new Error('Login error: could not get login form for ' + opts.url);
    return this.opts = opts;
  };

  /**
   * Log into Slack and populate cookies.
   */

  this.login = function *() {
    var opts = this.opts;
    var load = {
      url: opts.url + loginFormPath,
      headers: headers,
      jar: opts.jar,
      method: 'POST',
      followAllRedirects: true,
      formData: opts.formData
    };
    var res = yield request(load);
    if(res[0].body.indexOf("Sorry, you entered an incorrect email address or password.") != -1){
      throw new Error('Login error: incorrect username / password');
    }

    if(res[0].body.indexOf("Enter your authentication code") != -1){

      var $ = cheerio.load(res[0].body);

      var inputs = $("form input")

      var formData = {};

      inputs.each(function(i,v){
        formData[v.attribs.name] = v.attribs.value;
      })

      user_2fa_code = yield ask('2FA Code: ', isPassword, 'A password (as defined by this script) needs to have at least one character (not including you).');
      formData["2fa_code"] = user_2fa_code

      delete formData[undefined]
      delete formData['input']

      var load_2fa = {
        url: opts.url + "/",
        headers: headers,
        jar: opts.jar,
        method: 'POST',
        followAllRedirects: true,
        formData: formData
      };
      res = yield request(load_2fa);
    }

    //TODO: it may be necessary in the future to replace this with a user-supplied token
    var match = apiTokenRegex.exec(res[0].body);
    if (!match || !match[1]) {
      throw new Error('Application Error: unable to find api token on login page');
    }
    opts.apiToken = match[1];

    return this.opts = opts;
  };

  /**
   * Upload the emoji.
   */

  this.upload = function *(name, emoji) {
    console.log('Uploading %s with %s', name, emoji);
    return new Promise(function(resolve, reject, notify) {
      var opts = this.opts;
      var r = req({
        url: opts.url + emojiAddEndpoint,
        headers: headers,
        method: 'POST',
        jar: opts.jar,
        followAllRedirects: true
      }, function(err, res, body) {
        if (err || !body) return reject(err);
        resolve(body);
      });
      var form = r.form();
      form.append('name', name);
      form.append('mode', 'data');
      form.append('image', req(emoji));
      form.append('token', opts.apiToken);
    }.bind(this));
  };

  this.alias = function *(name, alias) {
    console.log('Aliasing %s to %s', alias, name);
    return new Promise(function(resolve, reject, notify) {
      var opts = this.opts;
      var r = req({
        url: opts.url + emojiAddEndpoint,
      headers: {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'},
        method: 'POST',
        jar: opts.jar,
        followAllRedirects: true
      }, function(err, res, body) {
        if (err || !body) return reject(err);
        resolve(body);
      });
      var form = r.form();
      form.append('name', alias);
      form.append('mode', 'alias');
      form.append('alias', name);
      form.append('token', opts.apiToken);
    }.bind(this));
  };
}