text: // Generated by CoffeeScript 1.4.0
  (function() {
    "use strict";
    var UserCommandHandler, exports, _ref,
      __hasProp = {}.hasOwnProperty,
      __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
      __slice = [].slice;
  
    var exports = (_ref = window.chat) != null ? _ref : window.chat = {};
  
    /*
     * Handles user commands, including providing help messages and determining if a
     * command can be run in the current context.
    */
  
  
    UserCommandHandler = (function(_super) {
  
      __extends(UserCommandHandler, _super);
  
      function UserCommandHandler(chat) {
        this.chat = chat;
        this._handlers = {};
        this._init();
        UserCommandHandler.__super__.constructor.apply(this, arguments);
      }
  
      UserCommandHandler.prototype.getCommands = function() {
        return this._handlers;
      };
  
      UserCommandHandler.prototype.getCommand = function(command) {
        return this._handlers[command];
      };
  
      UserCommandHandler.prototype.listenTo = function(emitter) {
        var _this = this;
        return emitter.on('command', function(e) {
          if (_this.canHandle(e.name)) {
            return _this.handle.apply(_this, [e.name, e].concat(__slice.call(e.args)));
          }
        });
      };
  
      UserCommandHandler.prototype.handle = function() {
        var args, command, context, type;
        type = arguments[0], context = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
        if (!this._isValidUserCommand(type)) {
          /*
                 * the command must be a developer command
          */
  
          UserCommandHandler.__super__.handle.apply(this, [type, context].concat(__slice.call(args)));
          return;
        }
        command = this._handlers[type];
        return command.tryToRun.apply(command, [context].concat(__slice.call(args)));
      };
  
      UserCommandHandler.prototype._isValidUserCommand = function(type) {
        return type in this._handlers;
      };
  
      /*
         * Creates all user commands. The "this" parameter in the run() and
         * validateArgs() functions is UserCommand.
         * @this {UserCommand}
      */
  
  
      UserCommandHandler.prototype._init = function() {
        this._addCommand('nick', {
          description: 'sets your nick',
          category: 'common',
          params: ['nick'],
          run: function() {
            var _ref1;
            return this.chat.setNick((_ref1 = this.conn) != null ? _ref1.name : void 0, this.nick);
          }
        });
        this._addCommand('server', {
          description: 'connects to the server, port 6667 is used by default, ' +
              'reconnects to the current server if no server is specified, ' +
              'use \'+\' to enable SSL (i.e. +6667)',
          category: 'common',
          params: ['opt_server', 'opt_port', 'opt_password'],
          requires: ['online'],
          validateArgs: function() {
            var _ref1, _ref2;
            if (!this.port) {
              this.port = 6667;
            }
            if ((_ref1 = this.server) == null) {
              this.server = (_ref2 = this.conn) != null ? _ref2.name : void 0;
            }
            return this.server && !isNaN(this.port);
          },
          run: function() {
            return this.chat.connect(this.server, this.port, this.password);
          }
        });
        this._addCommand('join', {
          description: 'joins the channel with the key if provided, reconnects ' +
              'to the current channel if no channel is specified',
          category: 'common',
          params: ['opt_channel', 'opt_key'],
          requires: ['connection'],
          validateArgs: function() {
            if (this.channel == null) {
              this.channel = this.chan;
            }
            this.channel = this.channel.toLowerCase();
            return true;
          },
          run: function() {
            return this.chat.join(this.conn, this.channel, this.key);
          }
        });
        this._addCommand('part', {
          description: "closes the current window and disconnects from the channel",
          category: 'common',
          params: ['opt_reason...'],
          requires: ['connection', 'channel'],
          run: function() {
            this.chat.disconnectAndRemoveRoom(this.conn.name, this.chan, this.reason);
          }
        });
        this._addCommand('leave', {
           "extends": 'part'
        });
        this._addCommand('close', {
           "extends": 'part'
        });
        this._addCommand('invite', {
           description: "invites the specified nick to the current or specified channel",
           category: 'common',
           params: ['nick...', 'opt_channel'],
           requires: ['connection'],
           usage: '<nick> [channel]',
           run: function() {
               if (!this.channel) {
                   if (this.chan) {
                      this.channel = this.chan;
                   } else {
                      return this.displayMessage('error','you must be in a channel or specify one');
                   }
               }
               if (!this.conn.irc.channels[this.channel]) {
                   // according to spec you can invite users to a channel that you are not a member of if it doesn't exist
                   return this.displayMessage('error', 'you must be in ' + this.channel + ' to invite someone to it');
               }
               this.displayMessage('notice', 'inviting ' + this.nick + ' to join ' + this.channel);
               return this.conn.irc.doCommand('INVITE', this.nick, this.channel);
           }
        });
        this._addCommand('win', {
          description: 'switches windows, only channel windows are selected this way',
          category: 'misc',
          params: ['windowNum'],
          validateArgs: function() {
            this.windowNum = parseInt(this.windowNum);
            return !isNaN(this.windowNum);
          },
          run: function() {
            return this.chat.switchToChannelByIndex(this.windowNum - 1);
          }
        });
        this._addCommand('debug', {
          description: 'prints the last 300-400 logs to the developer console ' +
              'and enables future logging of info and warning messages',
          category: 'misc',
          run: function() {
            window.enableLogging();
            this.displayMessage('notice', 'logging enabled. See developer ' +
                'console for previous logs. Have a bug to report? File an ' +
                'issue at ' + globals.ISSUES_URL);
          }
        });
        this._addCommand('say', {
          description: 'sends text to the current channel',
          category: 'uncommon',
          params: ['text...'],
          requires: ['connection', 'channel', 'connected'],
          run: function() {
            this.conn.irc.doCommand('PRIVMSG', this.chan, this.text);
            return this.displayMessage('privmsg', this.conn.irc.nick, this.text);
          }
        });
        this._addCommand('list', {
          description: 'lists all channels on the server.[',
          category: 'uncommon',
          params: ['opt_channels'],
          requires: ['connection'],
          run: function() {
            return this.conn.irc.doCommand('LIST', this.channels);
          }
        });
        this._addCommand('me', {
          description: 'sends text to the current channel, spoken in the 3rd person',
          category: 'uncommon',
          "extends": 'say',
          validateArgs: function() {
            return this.text = "\u0001ACTION " + this.text + "\u0001";
          }
        });
        this._addCommand('quit', {
          description: 'disconnects from the current server',
          category: 'common',
          params: ['opt_reason...'],
          requires: ['connection'],
          run: function() {
            this.chat.disconnectAndRemoveRoom(this.conn.name, null /* channel */, this.reason);
          }
        });
        this._addCommand('names', {
          description: 'lists nicks in the current channel',
          category: 'uncommon',
          requires: ['connection', 'channel', 'connected'],
          run: function() {
            var k, msg, names, v;
            if (this.win.isPrivate()) {
              msg = "You're in a private conversation with " + this.chan + ".";
            } else {
              names = ((function() {
                var _ref1, _results;
                _ref1 = this.conn.irc.channels[this.chan].names;
                _results = [];
                for (k in _ref1) {
                  v = _ref1[k];
                  _results.push(v);
                }
                return _results;
              }).call(this)).sort();
              msg = "Users in " + this.chan + ": " + (JSON.stringify(names));
            }
            return this.win.message('', msg, 'notice names');
          }
        });
        this._addCommand('clear', {
          description: 'clears messages in the current window or from all windows if all is passed',
          category: 'uncommon',
          params: ["opt_all"],
          validateArgs: function() {
            if (!this.all || this.all === 'all') {
              return true;
            }
          },
          run: function() {
            var index, winList, _i, _ref1, _results;
            if (this.all === 'all') {
              winList = this.chat.winList;
              _results = [];
              for (index = _i = 0, _ref1 = winList.length - 1; 0 <= _ref1 ? _i <= _ref1 : _i >= _ref1; index = 0 <= _ref1 ? ++_i : --_i) {
                _results.push(winList.get(index).clear());
              }
              return _results;
            } else {
              return this.win.clear();
            }
          }
        });
        this._addCommand('help', {
          description: "displays information about a command, lists all commands " + "if no command is specified",
          category: 'misc',
          params: ["opt_command"],
          run: function() {
            var commands;
            this.command = this.chat.userCommands.getCommand(this.command);
            if (this.command) {
              return this.command.displayHelp(this.win);
            } else {
              commands = this.chat.userCommands.getCommands();
              return this.win.messageRenderer.displayHelp(commands);
            }
          }
        });
        this._addCommand('hotkeys', {
          description: "lists keyboard shortcuts",
          category: 'misc',
          run: function() {
            return this.win.messageRenderer.displayHotkeys(this.chat.getKeyboardShortcuts().getMap());
          }
        });
        this._addCommand('raw', {
          description: "sends a raw event to the IRC server, use the -c flag to " + "make the command apply to the current channel",
          category: 'uncommon',
          params: ['command', 'opt_arguments...'],
          usage: '<command> [-c] [arguments...]',
          requires: ['connection'],
          validateArgs: function() {
            return this["arguments"] = this["arguments"] ? this["arguments"].split(' ') : [];
          },
          run: function() {
            var command, _ref1, _ref2;
            command = (_ref1 = chat.customCommandParser).parse.apply(_ref1, [this.chan, this.command].concat(__slice.call(this["arguments"])));
            return (_ref2 = this.conn.irc).send.apply(_ref2, command);
          }
        });
        this._addCommand('quote', {
          "extends": 'raw'
        });
        this._addCommand('install', {
          description: "loads a script by opening a file browser dialog",
          category: 'scripts',
          run: function() {
            var _this = this;
            return script.loader.createScriptFromFileSystem(function(script) {
              return _this.chat.addScript(script);
            });
          }
        });
        this._addCommand('uninstall', {
          description: "uninstalls a script, currently installed scripts can be listed with /scripts",
          params: ['scriptName'],
          usage: '<script name>',
          category: 'scripts',
          run: function() {
            var message, script;
            script = this.chat.scriptHandler.getScriptByName(this.scriptName);
            if (script) {
              this.chat.storage.clearScriptStorage(this.scriptName);
              this.chat.scriptHandler.removeScript(script);
              this.chat.storage.scriptRemoved(script);
              return this.displayMessage('notice', "Script " + this.scriptName + " was successfully uninstalled");
            } else {
              message = "No script by the name '" + this.scriptName + "' was found. " + (this.listInstalledScripts());
              return this.displayMessage('error', message);
            }
          }
        });
        this._addCommand('scripts', {
          description: "displays a list of installed scripts",
          category: 'scripts',
          run: function() {
            return this.displayMessage('notice', this.listInstalledScripts());
          }
        });
        this._addCommand('topic', {
          description: "sets the topic of the current channel, displays the " + "current topic if no topic is specified",
          category: 'uncommon',
          params: ['opt_topic...'],
          requires: ['connection', 'channel'],
          run: function() {
            return this.conn.irc.doCommand('TOPIC', this.chan, this.topic);
          }
        });
        this._addCommand('kick', {
          description: "removes a user from the current channel",
          category: 'uncommon',
          params: ['nick', 'opt_reason...'],
          requires: ['connection', 'channel'],
          run: function() {
            return this.conn.irc.doCommand('KICK', this.chan, this.nick, this.reason);
          }
        });
        this._addCommand('mode', {
          /*
                 * TODO when used with no args, display current modes
          */
  
          description: "sets or gets the modes of a channel or user(s), the " + "current channel is used by default",
          category: 'uncommon',
          params: ['opt_target', 'opt_mode', 'opt_nicks...'],
          usage: "< [channel|nick] | [channel] <mode> [nick1] [nick2] ...>",
          requires: ['connection'],
          validateArgs: function() {
            var _ref1, _ref2;
            if (this.args.length === 0) {
              return true;
            }
            this.nicks = (_ref1 = (_ref2 = this.nicks) != null ? _ref2.split(' ') : void 0) != null ? _ref1 : [];
            if (this.args.length === 1 && !this.isValidMode(this.target)) {
              return true;
            }
            if (this.isValidMode(this.target) && this.target !== this.chan) {
              /*
                         * a target wasn't specified, shift variables over by one
              */
  
              this.nicks.push(this.mode);
              this.mode = this.target;
              this.target = this.chan;
            }
            return this.target && this.isValidMode(this.mode);
          },
          run: function() {
            var _ref1;
            if (this.args.length === 0) {
              if (this.chan) {
                this.conn.irc.doCommand('MODE', this.chan);
              }
              return this.conn.irc.doCommand('MODE', this.conn.irc.nick);
            } else {
              return (_ref1 = this.conn.irc).doCommand.apply(_ref1, ['MODE', this.target, this.mode].concat(__slice.call(this.nicks)));
            }
          }
        });
        this._addCommand('op', {
          description: "gives operator status",
          params: ['nick'],
          "extends": 'mode',
          usage: "<nick>",
          requires: ['connection', 'channel'],
          validateArgs: function() {
            return this.setModeArgs('+o');
          }
        });
        this._addCommand('deop', {
          description: "removes operator status",
          params: ['nick'],
          "extends": 'mode',
          usage: "<nick>",
          requires: ['connection', 'channel'],
          validateArgs: function() {
            return this.setModeArgs('-o');
          }
        });
        this._addCommand('voice', {
          description: "gives voice",
          params: ['nick'],
          "extends": 'mode',
          usage: "<nick>",
          requires: ['connection', 'channel'],
          validateArgs: function() {
            return this.setModeArgs('+v');
          }
        });
        this._addCommand('devoice', {
          description: "removes voice",
          params: ['nick'],
          "extends": 'mode',
          usage: "<nick>",
          requires: ['connection', 'channel'],
          validateArgs: function() {
            return this.setModeArgs('-v');
          }
        });
        this._addCommand('away', {
          description: "sets your status to away, a response is " + "automatically sent when people /msg or WHOIS you",
          category: 'uncommon',
          params: ['opt_response...'],
          requires: ['connection'],
          validateArgs: function() {
            if (!stringHasContent(this.response)) {
              this.response = "I'm currently away from my computer";
            }
            return true;
          },
          run: function() {
            return this.conn.irc.doCommand('AWAY', this.response);
          }
        });
        this._addCommand('back', {
          description: "sets your status to no longer being away",
          category: 'uncommon',
          requires: ['connection'],
          run: function() {
            return this.conn.irc.doCommand('AWAY', this.response);
          }
        });
        this._addCommand('msg', {
          description: "sends a private message",
          category: 'common',
          params: ['nick', 'message...'],
          requires: ['connection'],
          run: function() {
            this.conn.irc.doCommand('PRIVMSG', this.nick, this.message);
            return this.displayDirectMessage();
          }
        });
        this._addCommand('whois', {
          description: "displays information about a nick",
          category: 'uncommon',
          params: ['opt_nick'],
          requires: ['connection'],
          run: function() {
            return this.conn.irc.doCommand('WHOIS', this.nick);
          }
        });
        this._addCommand('swhois', {
          description: "displays detailed information about a nick (by querying user's connecting server)",
          category: 'uncommon',
          params: ['opt_nick'],
          requires: ['connection'],
          run: function() {
            // Same as WHOIS, but send the nick twice.
            return this.conn.irc.doCommand('WHOIS', this.nick, this.nick);
          }
        });
        this._addCommand('whowas', {
          description: "displays recent login information about a nick",
          category: 'uncommon',
          params: ['opt_nick'],
          requires: ['connection'],
          run: function() {
            return this.conn.irc.doCommand('WHOWAS', this.nick);
          }
        });
        this._addCommand('who', {
          description: "displays detailed user list to server window; add 'o' as second option to restrict to IRCOps",
          category: 'uncommon',
          params: ['channel_or_pattern', "opt_o"],
          requires: ['connection'],
          run: function() {
            return this.conn.irc.doCommand('WHO', this.channel_or_pattern, this.o);
          }
        });
        this._addCommand('about', {
          description: "displays information about this IRC client",
          category: 'misc',
          run: function() {
            return this.win.messageRenderer.displayAbout();
          }
        });
        this._addCommand('join-server', {
          description: "use the IRC connection of another device, allowing you " + "to be logged in with the same nick on multiple devices. " + "Connects to the device that called /make-server if no arguments " + "are given",
          category: 'one_identity',
          requires: ['online'],
          params: ['opt_addr', 'opt_port'],
          validateArgs: function() {
            var connectInfo, parsedPort, _ref1;
            parsedPort = parseInt(this.port);
            if ((this.port || this.addr) && !(parsedPort || this.addr)) {
              return false;
            }
            connectInfo = this.chat.storage.serverDevice;
            this.port = parsedPort || (connectInfo != null ? connectInfo.port : void 0);
            if ((_ref1 = this.addr) == null) {
              this.addr = connectInfo != null ? connectInfo.addr : void 0;
            }
            return true;
          },
          run: function() {
            if (this.port && this.addr) {
              if (this.addr === this.chat.remoteConnection.getConnectionInfo().addr) {
                return this.displayMessage('error', "this device is the server and cannot " + "connect to itself. Call /join-server on other devices to " + "have them connect to this device or call /make-server on " + "another device to make it the server");
              } else {
                this.chat.remoteConnectionHandler.isManuallyConnecting();
                return this.chat.remoteConnection.connectToServer({
                  port: this.port,
                  addr: this.addr
                });
              }
            } else {
              return this.displayMessage('error', "No server exists. Use /make-server " + "on the device you wish to become the server.");
            }
          }
        });
        this._addCommand('make-server', {
          description: "makes this device a server to which other devices can " + "connect. Connected devices use the IRC connection of this device",
          category: 'one_identity',
          requires: ['online'],
          run: function() {
            var state,
              _this = this;
            state = this.chat.remoteConnection.getState();
            if (this.chat.remoteConnectionHandler.shouldBeServerDevice()) {
              return this.displayMessage('error', "this device is already acting as a " + "server");
            } else if (!api.listenSupported()) {
              return this.displayMessage('error', "this command cannot be used with your " + "current version of Chrome because it does not support " + "chrome.sockets.tcpServer");
            } else if (state === 'no_addr') {
              return this.displayMessage('error', "this device can not be used as a " + "server at this time because it cannot find its own IP address");
            } else if (state === 'no_port') {
              return this.displayMessage('error', "this device can not be used as a " + "server at this time because no valid port was found");
            } else if (state === 'finding_port') {
              return this.chat.remoteConnection.waitForPort(function() {
                return _this.run;
              });
            } else {
              this.chat.storage.becomeServerDevice(this.chat.remoteConnection.getConnectionInfo());
              return this.chat.remoteConnectionHandler.determineConnection();
            }
          }
        });
        this._addCommand('network-info', {
          description: "displays network information including " + "port, ip address and remote connection status",
          category: 'one_identity',
          run: function() {
            var addr, connectionInfo, numClients, state, _i, _len, _ref1, _results;
            this.displayMessage('breakgroup');
            if (this.chat.remoteConnection.isServer()) {
              numClients = this.chat.remoteConnection.devices.length;
              if (numClients > 0) {
                this.displayMessage('notice', "acting as a server for " + this.chat.remoteConnection.devices.length + " other " + pluralize('device', this.chat.remoteConnection.devices.length));
              } else {
                this.displayMessage('notice', "Acting as a server device. No clients " + "have connected.");
              }
            } else if (this.chat.remoteConnection.isClient()) {
              this.displayMessage('notice', "connected to server device " + this.chat.remoteConnection.serverDevice.addr + " on port " + this.chat.remoteConnection.serverDevice.port);
            } else {
              this.displayMessage('notice', "not connected to any other devices");
            }
            state = this.chat.remoteConnection.getConnectionInfo().getState();
            if (state !== 'found_port') {
              return;
            }
            this.displayMessage('breakgroup');
            connectionInfo = this.chat.remoteConnection.getConnectionInfo();
            this.displayMessageWithStyle('notice', "Port: " + connectionInfo.port, 'no-pretty-format');
            this.displayMessage('breakgroup');
            this.displayMessage('notice', "IP addresses:");
            _ref1 = connectionInfo.possibleAddrs;
            _results = [];
            for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
              addr = _ref1[_i];
              _results.push(this.displayMessageWithStyle('notice', "    " + addr, 'no-pretty-format'));
            }
            return _results;
          }
        });
        this._addCommand('stop-server', {
          description: "stops connecting through another device's IRC " +
              "connection and starts using a new IRC connection (see /join-server)",
          category: 'one_identity',
          requires: ['online'],
          run: function() {
            this.chat.remoteConnectionHandler.useOwnConnection();
            this.displayMessage('notice', "this device is now using its own IRC connection");
          }
        });
        this._addCommand('autostart', {
          description: "sets whether the application will run on startup, " + "toggles if no arguments are given",
          category: 'misc',
          usage: '[ON|OFF]',
          params: ['opt_state'],
          validateArgs: function() {
            if (!this.state) {
              this.enabled = void 0;
              return true;
            }
            this.state = this.state.toLowerCase();
            if (!(this.state === 'on' || this.state === 'off')) {
              return false;
            }
            this.enabled = this.state === 'on';
            return true;
          },
          run: function() {
            var willAutostart;
            willAutostart = this.chat.storage.setAutostart(this.enabled);
            if (willAutostart) {
              return this.displayMessage('notice', "IRCFRHB2 will now automatically " + "run on startup");
            } else {
              return this.displayMessage('notice', "IRCFRHB2 will no longer " + "automatically run on startup");
            }
          }
        });
        this._addCommand('query', {
          description: 'opens a new window for a private conversation with someone',
          category: 'uncommon',
          params: ['nick'],
          requires: ['connection'],
          run: function() {
            var win;
            win = this.chat.createPrivateMessageWindow(this.conn, this.nick);
            return this.chat.switchToWindow(win);
          }
        });
        this._addCommand('kill', {
          description: 'kicks a user from the server',
          category: 'uncommon',
          params: ['nick', 'opt_reason'],
          requires: ['connection'],
          run: function() {
            return this.conn.irc.doCommand('KILL', this.nick, this.reason);
          }
        });
        this._addCommand('version', {
          description: "get the user's IRC version",
          category: 'uncommon',
          params: ['nick'],
          requires: ['connection'],
          run: function() {
            return this.handleCTCPRequest(this.nick, 'VERSION');
          }
        });
        this._addCommand('ignore', {
          description: "stop certain message(s) from being displayed in the " + "current channel, for example '/ignore join part' stops join " + "and part messages from being displayed, a list of ignored " + "messages is displayed if no arguments are given",
          category: 'misc',
          params: ['opt_types...'],
          requires: ['connection'],
          usage: '[<message type 1> <message type 2> ...]',
          run: function() {
            var context, type, typeObject, types, _i, _len;
            context = this.win.getContext();
            if (this.types) {
              types = this.types.split(' ');
              for (_i = 0, _len = types.length; _i < _len; _i++) {
                type = types[_i];
                this.chat.messageHandler.ignoreMessageType(context, type);
              }
              return this.displayMessage('notice', "Messages of type " + ("" + (getReadableList(types)) + " will no longer be displayed in this ") + "room.");
            } else {
              typeObject = this.chat.messageHandler.getIgnoredMessages()[context];
              types = (function() {
                var _results;
                _results = [];
                for (type in typeObject) {
                  _results.push(type);
                }
                return _results;
              })();
              if (types && types.length > 0) {
                return this.displayMessage('notice', "Messages of type " + ("" + (getReadableList(types)) + " are being ignored in this room."));
              } else {
                return this.displayMessage('notice', "There are no messages being ignored " + "in this room.");
              }
            }
          }
        });
        this._addCommand('unignore', {
          description: "stop ignoring certain message(s)",
          "extends": 'ignore',
          usage: '<message type 1> <message type 2> ...',
          run: function() {
            var context, type, types, _i, _len;
            context = this.win.getContext();
            types = this.types.split(' ');
            for (_i = 0, _len = types.length; _i < _len; _i++) {
              type = types[_i];
              this.chat.messageHandler.stopIgnoringMessageType(this.win.getContext(), type);
            }
            return this.displayMessage('notice', ("Messages of type " + (getReadableList(types)) + " ") + "are no longer being ignored.");
          }
        });
        this._addCommand('theme', {
          description: "upload and use a custom CSS file, opens a file browser",
          category: 'misc',
          run: function() {
            var _this = this;
            return loadFromFileSystem(function(content) {
              return webkitRequestFileSystem(TEMPORARY, 50 * 1024, function(fileSystem) {
                return fileSystem.root.getFile('custom_style.css', {
                  create: true
                }, function(fileEntry) {
                  return fileEntry.createWriter(function(writer) {
                    var blob;
                    writer.onwriteend = function() {
                      return $('#main-style').attr('href', fileEntry.toURL());
                    };
                    blob = new Blob([content], {
                      type: 'text/css'
                    });
                    return writer.write(blob);
                  });
                });
              });
            });
          }
        });
        /*
             * Hidden commands.
             * These commands don't display in /help or autocomplete. They're used for
             * scripts and keyboard shortcuts.
        */
  
        this._addCommand('next-server', {
          description: "switches to the next server window",
          category: 'hidden',
          run: function() {
            var nextServer, server, serverIndex, winList, _ref1;
            winList = this.chat.winList;
            server = winList.getServerForWindow(this.win);
            if (!server) {
              return;
            }
            serverIndex = winList.serverIndexOf(server);
            nextServer = (_ref1 = winList.getServerWindow(serverIndex + 1)) != null ? _ref1 : winList.getServerWindow(0);
            return this.chat.switchToWindow(nextServer);
          }
        });
        this._addCommand('next-room', {
          description: "switches to the next window",
          category: 'hidden',
          run: function() {
            var index, nextWin, winList, _ref1;
            winList = this.chat.winList;
            index = winList.indexOf(this.win);
            if (index < 0) {
              return;
            }
            nextWin = (_ref1 = winList.get(index + 1)) != null ? _ref1 : winList.get(0);
            return this.chat.switchToWindow(nextWin);
          }
        });
        this._addCommand('previous-room', {
          description: "switches to the next window",
          category: 'hidden',
          run: function() {
            var index, nextWin, winList, _ref1;
            winList = this.chat.winList;
            index = winList.indexOf(this.win);
            if (index < 0) {
              return;
            }
            nextWin = (_ref1 = winList.get(index - 1)) != null ? _ref1 : winList.get(winList.length - 1);
            return this.chat.switchToWindow(nextWin);
          }
        });
        this._addCommand('reply', {
          description: "begin replying to the user who last mentioned your nick",
          category: 'hidden',
          run: function() {
            var user;
            user = this.chat.getLastUserToMention(this.win.getContext());
            if (!user) {
              return;
            }
            return this.chat.emit('set_input_if_empty', "" + user + ": ");
          }
        });
        this._addCommand('image', {
          description: "embed an image in a message",
          category: 'hidden',
          params: ['src'],
          run: function() {
            var win;
            win = this.win;
            return getEmbedableUrl(this.src, function(url) {
              var img;
              img = $('<img>');
              img.css('max-width', '80%');
              img.attr('src', url)
              img.on('load', function(){
                win.rawMessage('', img[0].outerHTML, 'image-message');
              });
            });
          }
        });
        this._addCommand('suspend-notifications', {
          description: 'suspends notifications temporarily',
          category: 'hidden',
          params: ['suspend'],
          run: function() {
            this.chat.messageHandler.setSuspendNotifications(this.suspend.toLowerCase() == 'on');
          }
        });
      };
  
      UserCommandHandler.prototype._addCommand = function(name, commandDescription) {
        var command, commandToExtend;
        command = new chat.UserCommand(name, commandDescription);
        commandToExtend = this._handlers[commandDescription["extends"]];
        if (commandToExtend) {
          command.describe(commandToExtend.description);
        }
        command.setChat(this.chat);
        return this._handlers[name] = command;
      };
  
      return UserCommandHandler;
  
    })(MessageHandler);
  
    exports.UserCommandHandler = UserCommandHandler;
  
  }).call(this);
  