// Generated by CoffeeScript 1.3.3
(function() {
  var ARGUMENT, COMMAND, Command, DUMMY, DefaultHandlers, HEADER, OPTION, OPTION_BOOL, OPTION_DESC, OPTION_DESC_DEFAULT, OPTION_DESC_TAG, OPTION_LONG, OPTION_METAVARS, OPTION_SHORT, Option, SUBSUBSUB, Syntax, TEXT, USAGE, Usage, UsageSection, alignment, cleanUpMetaVarName, cleanUpNameForUsingAsVarName, createError, formatMetaVar, formatUsageString, indent, parse, separator, width, wordwrap, wrapText,
    __slice = [].slice;

  wordwrap = require('wordwrap');

  USAGE = /^Usage:/;

  HEADER = /^[^-].*:$/;

  OPTION = /^\s+-/;

  COMMAND = /^\s+([\w.-]+)(?:\s{2,}(.*))?$/;

  TEXT = /^\S/;

  ARGUMENT = /^\s+(?:[A-Z._-][A-Z0-9._-]+|<[^\s>]+>)(?:\s\s|$)/;

  OPTION_DESC = /^(.*?)\s{2,}(.*)$/;

  OPTION_METAVARS = /^([^\s,]+(?:,\s*\S+)?)((?:\s(?:[A-Z._-][A-Z0-9._-]+|<[^\s>]+>))*)$/;

  OPTION_SHORT = /^(-\S)(?:,\s*(.*))?$/;

  OPTION_LONG = /^(--\S+)$/;

  OPTION_BOOL = /^--\[no-\](.*)$/;

  OPTION_DESC_TAG = /^(.*)\#(\w+)(?:\(([^()]*)\))?\s*$/;

  DUMMY = /\#/;

  OPTION_DESC_DEFAULT = /\((?:default:|default\s+is|defaults\s+to)\s+([^()]+)\)/i;

  SUBSUBSUB = ['command', 'subcommand', 'subsubcommand', 'subsubsubcommand'];

  createError = function(message) {
    var e;
    e = new Error(message);
    e.isCommandLineError = true;
    return e;
  };

  DefaultHandlers = {
    auto: function(value) {
      if (typeof value !== 'string') {
        return value;
      }
      if (!isNaN(Number(value))) {
        return Number(value);
      }
      return value;
    },
    string: function(value) {
      return value;
    },
    int: function(value) {
      if (typeof value !== 'string') {
        return value;
      }
      if (isNaN(parseInt(value, 10))) {
        throw createError("Integer value required: " + value);
      }
      return parseInt(value, 10);
    },
    flag: function(value, options, optionName, tagValue) {
      var _ref, _ref1;
      if (!(value != null)) {
        return true;
      }
      if (typeof value !== 'string') {
        return value;
      }
      if ((_ref = value.toLowerCase()) === '0' || _ref === 'false' || _ref === 'no' || _ref === 'off') {
        return false;
      }
      if ((_ref1 = value.toLowerCase()) === '' || _ref1 === '1' || _ref1 === 'true' || _ref1 === 'yes' || _ref1 === 'on') {
        return true;
      }
      throw new Error("Invalid flag value " + (JSON.stringify(value)) + " for option " + optionName);
    }
  };

  alignment = 24;

  indent = "  ";

  separator = "  ";

  width = 100;

  wrapText = require('wordwrap')(width);

  formatUsageString = function(left, right) {
    var actualAlignment, descriptionWidth, firstLine, otherLines, overhead, padding, wrappedLineIndent, _ref;
    overhead = indent.length + separator.length;
    if (left.length < alignment - overhead) {
      padding = new Array(alignment - overhead - left.length + 1).join(' ');
    } else {
      padding = '';
    }
    actualAlignment = overhead + left.length + padding.length;
    descriptionWidth = width - actualAlignment;
    wrappedLineIndent = new Array(actualAlignment + 1).join(' ');
    _ref = wordwrap(descriptionWidth)(right).trim().split('\n'), firstLine = _ref[0], otherLines = 2 <= _ref.length ? __slice.call(_ref, 1) : [];
    right = [firstLine].concat(otherLines.map(function(line) {
      return wrappedLineIndent + line;
    })).join("\n");
    if (otherLines.length) {
      right += "\n";
    }
    return "  " + left + padding + "  " + right;
  };

  cleanUpMetaVarName = function(name) {
    var $;
    if ($ = name.match(/^<(.*)>$/)) {
      return $[1];
    } else {
      return name;
    }
  };

  formatMetaVar = function(metavar) {
    if (metavar === metavar.toUpperCase()) {
      return metavar;
    } else {
      return "<" + metavar + ">";
    }
  };

  cleanUpNameForUsingAsVarName = function(name, isOption) {
    if (!isOption) {
      if (name === name.toUpperCase()) {
        name = name.toLowerCase();
      }
    }
    return name;
  };

  Option = (function() {

    function Option(shortOpt, longOpt, desc, tagPairs, metavars, defaultValue) {
      var $, name, tag, value, _i, _len, _ref;
      this.shortOpt = shortOpt;
      this.longOpt = longOpt;
      this.desc = desc;
      this.metavars = metavars;
      this.defaultValue = defaultValue;
      if (this.longOpt || this.shortOpt) {
        this.name = this.longOpt && this.longOpt.slice(2) || this.shortOpt.slice(1);
      } else if (this.metavars.length) {
        this.name = this.metavars[0];
        if ($ = this.name.match(/^\[(.*)\]$/)) {
          this.name = $[1];
        }
        this.name = cleanUpMetaVarName(this.name);
      }
      this.metavars = (function() {
        var _i, _len, _ref, _results;
        _ref = this.metavars;
        _results = [];
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          name = _ref[_i];
          _results.push(cleanUpMetaVarName(name));
        }
        return _results;
      }).call(this);
      this["var"] = cleanUpNameForUsingAsVarName(this.name, this.longOpt || this.shortOpt);
      this.tags = {};
      this.tagsOrder = [];
      for (_i = 0, _len = tagPairs.length; _i < _len; _i++) {
        _ref = tagPairs[_i], tag = _ref[0], value = _ref[1];
        this.tags[tag] = value;
        this.tagsOrder.push(tag);
        switch (tag) {
          case 'default':
            this.defaultValue = value;
            break;
          case 'var':
            this["var"] = value;
        }
      }
      this.func = null;
    }

    Option.prototype.leftUsageComponent = function() {
      var longOpt, mv, string;
      longOpt = this.longOpt;
      if (longOpt && this.tags.acceptsno) {
        longOpt = "--[no-]" + longOpt.slice(2);
      }
      string = (function() {
        switch (false) {
          case !(this.shortOpt && longOpt):
            return "" + this.shortOpt + ", " + longOpt;
          case !this.shortOpt:
            return this.shortOpt;
          case !this.longOpt:
            return "    " + longOpt;
          default:
            return '';
        }
      }).call(this);
      if (this.metavars) {
        string = string + (string && ' ' || '') + ((function() {
          var _i, _len, _ref, _results;
          _ref = this.metavars;
          _results = [];
          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            mv = _ref[_i];
            _results.push(formatMetaVar(mv));
          }
          return _results;
        }).call(this)).join(' ');
      }
      return string;
    };

    Option.prototype.toUsageString = function() {
      return formatUsageString(this.leftUsageComponent(), this.desc);
    };

    Option.prototype.coerce = function(value, options, syntax) {
      var any, handler, newValue, tag, _i, _len, _ref;
      any = false;
      _ref = this.tagsOrder;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        tag = _ref[_i];
        if (handler = syntax.handlers[tag] || DefaultHandlers[tag]) {
          newValue = handler(value, options, this.leftUsageComponent(), this.tags[tag]);
          if (typeof newValue !== void 0) {
            value = newValue;
          }
          any = true;
        }
      }
      if (!any) {
        value = DefaultHandlers.auto(value, options, syntax, this.leftUsageComponent());
      }
      return value;
    };

    return Option;

  })();

  Command = (function() {

    function Command(name, desc, syntax) {
      this.name = name;
      this.desc = desc;
      this.syntax = syntax;
      this.func = null;
      this.desc || (this.desc = this.syntax.usage.firstPreambleLine());
    }

    Command.prototype.leftUsageComponent = function() {
      return this.name;
    };

    Command.prototype.toUsageString = function() {
      return formatUsageString(this.leftUsageComponent(), this.desc);
    };

    return Command;

  })();

  UsageSection = (function() {

    function UsageSection(type, header) {
      this.type = type;
      this.header = header;
      this.lines = [];
    }

    UsageSection.prototype.toUsageString = function() {
      var line;
      return (this.header ? "" + this.header + "\n" : '') + ((function() {
        var _i, _len, _ref, _results;
        _ref = this.lines;
        _results = [];
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          line = _ref[_i];
          _results.push("" + line + "\n");
        }
        return _results;
      }).call(this)).join('');
    };

    return UsageSection;

  })();

  Usage = (function() {

    function Usage() {
      this.sections = [];
      this.lastSection = null;
      this.implicitHeaders = {
        preamble: "",
        text: "",
        options: "Options:",
        "arguments": "Arguments:",
        commands: "Commands:"
      };
      this.startSectionType('preamble');
    }

    Usage.prototype.startSection = function(type, header) {
      this.lastSection = new UsageSection(type, header);
      return this.sections.push(this.lastSection);
    };

    Usage.prototype.endSection = function() {
      return this.lastSection = null;
    };

    Usage.prototype.startSectionType = function(type) {
      var _ref, _ref1;
      if (((_ref = this.lastSection) != null ? _ref.type : void 0) === type) {
        return;
      }
      if (this.lastSection && (type === '*')) {
        return;
      }
      if (((_ref1 = this.lastSection) != null ? _ref1.type : void 0) === '*') {
        return this.lastSection.type = type;
      } else {
        return this.startSection(type, this.implicitHeaders[type]);
      }
    };

    Usage.prototype.add = function(sectionType, line) {
      if ((sectionType === 'text') && (this.sections.length === 1) && (this.sections[0].lines.length === 0)) {
        sectionType = 'preamble';
      }
      this.startSectionType(sectionType);
      return this.lastSection.lines.push(line);
    };

    Usage.prototype.filtered = function() {
      var result, section;
      result = new Usage();
      result.sections = (function() {
        var _i, _len, _ref, _ref1, _results;
        _ref = this.sections;
        _results = [];
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          section = _ref[_i];
          if (!((_ref1 = section.type) === 'preamble' || _ref1 === 'commands')) {
            _results.push(section);
          }
        }
        return _results;
      }).call(this);
      return result;
    };

    Usage.prototype.firstPreambleLine = function() {
      return this.sections[0].lines[0] || '';
    };

    Usage.prototype.toUsageString = function() {
      var s, section, usageStrings;
      usageStrings = (function() {
        var _i, _len, _ref, _results;
        _ref = this.sections;
        _results = [];
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          section = _ref[_i];
          _results.push(section.toUsageString());
        }
        return _results;
      }).call(this);
      return ((function() {
        var _i, _len, _results;
        _results = [];
        for (_i = 0, _len = usageStrings.length; _i < _len; _i++) {
          s = usageStrings[_i];
          if (s) {
            _results.push(s);
          }
        }
        return _results;
      })()).join("\n");
    };

    Usage.toUsageString = function(usages) {
      var s, usage, usageStrings;
      usageStrings = (function() {
        var _i, _len, _results;
        _results = [];
        for (_i = 0, _len = usages.length; _i < _len; _i++) {
          usage = usages[_i];
          _results.push(usage.toUsageString());
        }
        return _results;
      })();
      return ((function() {
        var _i, _len, _results;
        _results = [];
        for (_i = 0, _len = usageStrings.length; _i < _len; _i++) {
          s = usageStrings[_i];
          if (s) {
            _results.push(s);
          }
        }
        return _results;
      })()).join("\n");
    };

    return Usage;

  })();

  Syntax = (function() {

    function Syntax(handlers, specs, parent, parentContext) {
      this.handlers = handlers;
      if (specs == null) {
        specs = [];
      }
      this.parent = parent != null ? parent : null;
      this.parentContext = parentContext != null ? parentContext : '';
      this.usage = new Usage();
      this.options = [];
      this["arguments"] = [];
      this.commands = {};
      this.commandsOrder = [];
      if (this.parent) {
        this.parentContexts = [this.parentContext].concat(this.parent.parentContexts);
      } else {
        this.parentContexts = [];
      }
      this.nestingLevel = (this.parent ? this.parent.nestingLevel + 1 : 0);
      this.shortOptions = {};
      this.longOptions = {};
      if (specs) {
        this.add(specs);
      }
    }

    Syntax.prototype.add = function(specs, options) {
      var $, command, desc, func, gotArray, gotFunction, name, option, spec, subspecs, subsyntax, _;
      if (options == null) {
        options = {};
      }
      if (typeof specs !== 'object') {
        specs = [specs];
      }
      specs = specs.slice(0);
      gotArray = function() {
        return (typeof specs[0] === 'object') && (specs[0] instanceof Array);
      };
      gotFunction = function() {
        return typeof specs[0] === 'function';
      };
      while (spec = specs.shift()) {
        if (typeof spec !== 'string') {
          throw new Error("Expected string spec, found " + (typeof spec));
        }
        if (spec.match(HEADER)) {
          this.usage.startSection('*', spec);
        } else if (spec.match(USAGE)) {
          this.usage.add('usage', "" + spec);
        } else if (spec.match(OPTION)) {
          this.options.push((option = Option.parse(spec.trim())));
          if (option.shortOpt) {
            this.shortOptions[option.shortOpt.slice(1)] = option;
          }
          if (option.longOpt) {
            this.longOptions[option.longOpt.slice(2)] = option;
          }
          if (gotFunction()) {
            option.func = specs.shift();
          }
          this.usage.add('options', option.toUsageString());
        } else if (!gotArray() && spec.match(ARGUMENT)) {
          this["arguments"].push((option = Option.parse(spec.trim())));
          if (gotFunction()) {
            option.func = specs.shift();
          }
          this.usage.add('arguments', option.toUsageString());
        } else if ($ = spec.match(COMMAND)) {
          _ = $[0], name = $[1], desc = $[2];
          desc = (desc || '').trim();
          func = gotFunction() ? specs.shift() : null;
          if (gotArray()) {
            subspecs = specs.shift();
          } else if ((subspecs = typeof options.loadCommandSyntax === "function" ? options.loadCommandSyntax(this.parentContexts.concat([name]).join(' ')) : void 0)) {

          } else {
            throw new Error("Array must follow a command spec: " + (JSON.stringify(spec)));
          }
          subsyntax = new Syntax(this.handlers, [], this, name);
          subsyntax.add(subspecs, options);
          command = new Command(name, desc, subsyntax);
          command.func = func;
          this.commands[name] = command;
          this.commandsOrder.push(name);
          this.usage.add('commands', command.toUsageString());
        } else if (spec.trim() === '') {
          this.usage.endSection();
        } else if (spec.match(TEXT)) {
          this.usage.add('text', "\n" + wrapText(spec.trim()));
        } else {
          throw new Error("String spec invalid: " + (JSON.stringify(spec)));
        }
      }
      return this;
    };

    Syntax.prototype.filteredUsages = function() {
      var _ref;
      return [this.usage.filtered()].concat(((_ref = this.parent) != null ? _ref.filteredUsages() : void 0) || []);
    };

    Syntax.prototype.toUsageString = function() {
      var _ref;
      return Usage.toUsageString([this.usage].concat(((_ref = this.parent) != null ? _ref.filteredUsages() : void 0) || []));
    };

    Syntax.prototype.parse = function(argv, options) {
      var $, allArguments, arg, assignValue, c, command, commands, executeHook, func, funcs, index, key, name, option, positional, processOption, remainder, result, subarg, syntax, value, _, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _ref, _ref1,
        _this = this;
      argv = argv.slice(0);
      result = {};
      positional = [];
      funcs = [];
      commands = [];
      syntax = this;
      executeHook = function(option, value) {
        var newValue;
        if (option.func) {
          if (option.tags.delayfunc) {
            funcs.push([option.func, option, value]);
          } else {
            newValue = option.func(value, result, syntax, option);
            if (newValue != null) {
              value = newValue;
            }
          }
        }
        return value;
      };
      processOption = function(result, arg, option, value) {
        var index, metavar, subvalue, _i, _len, _ref;
        switch (option.metavars.length) {
          case 0:
            value = true;
            break;
          case 1:
            if (value == null) {
              value = argv.shift();
            }
            if (typeof value === 'undefined') {
              throw createError("Option " + arg + " requires an argument: " + (option.leftUsageComponent()));
            }
            break;
          default:
            value = [];
            _ref = option.metavars;
            for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) {
              metavar = _ref[index];
              value.push((subvalue = argv.shift()));
              if (typeof subvalue === 'undefined') {
                throw createError("Option " + arg + " requires " + option.metavars.length + " arguments: " + (option.leftUsageComponent()));
              }
            }
        }
        return option.coerce(value, result, syntax);
      };
      assignValue = function(result, option, value) {
        if (option.tags.list) {
          if (!result.hasOwnProperty(option["var"])) {
            result[option["var"]] = [];
          }
          if (value != null) {
            return result[option["var"]].push(value);
          }
        } else {
          return result[option["var"]] = value;
        }
      };
      while (arg = argv.shift()) {
        if (arg === '--') {
          while (arg = argv.shift()) {
            positional.push(arg);
          }
        } else if (arg === '-') {
          positional.push(arg);
        } else if (arg.match(/^--no-/) && (option = syntax.lookupLongOption(arg.slice(5), result)) && option.tags.flag) {
          assignValue(result, option, false);
        } else if ($ = arg.match(/^--([^=]+)(?:=(.*))?$/)) {
          _ = $[0], name = $[1], value = $[2];
          if (option = syntax.lookupLongOption(name, result)) {
            value = processOption(result, arg, option, value);
            value = executeHook(option, value);
            assignValue(result, option, value);
          } else {
            throw createError("Unknown long option: " + arg);
          }
        } else if (arg.match(/^-/)) {
          remainder = arg.slice(1);
          while (remainder) {
            subarg = remainder[0];
            remainder = remainder.slice(1);
            if (option = syntax.lookupShortOption(subarg, result)) {
              if (remainder && option.metavars.length > 0) {
                value = remainder;
                remainder = '';
              } else {
                value = void 0;
              }
              value = processOption(result, arg, option, value);
              value = executeHook(option, value);
              assignValue(result, option, value);
            } else {
              if (arg === ("-" + subarg)) {
                throw createError("Unknown short option " + arg);
              } else {
                throw createError("Unknown short option -" + subarg + " in " + arg);
              }
            }
          }
        } else if ((positional.length === 0) && (command = syntax.lookupCommand(arg, result))) {
          commands.push(command);
          if (key = options.commandKeys[syntax.nestingLevel]) {
            result[key] = arg;
          }
          if (key = options.compoundCommandKey) {
            result[key] = ((function() {
              var _i, _len, _results;
              _results = [];
              for (_i = 0, _len = commands.length; _i < _len; _i++) {
                c = commands[_i];
                _results.push(c.name);
              }
              return _results;
            })()).join(' ');
          }
          syntax = command.syntax;
        } else {
          positional.push(arg);
        }
      }
      if (syntax.commandsOrder.length > 0) {
        if (positional.length === 0) {
          throw createError("No " + SUBSUBSUB[syntax.nestingLevel] + " specified");
        } else {
          throw createError("Unknown " + SUBSUBSUB[syntax.nestingLevel] + " '" + positional[0] + "'");
        }
      }
      _ref = syntax.allOptions();
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        option = _ref[_i];
        if (!result.hasOwnProperty(option["var"])) {
          if (option.tags.required) {
            throw createError("Missing required option: " + (option.leftUsageComponent()));
          }
          if ((option.defaultValue != null) || option.tags.fancydefault || option.tags.list) {
            if (option.defaultValue != null) {
              value = option.coerce(option.defaultValue, result, syntax);
            } else {
              value = null;
            }
            value = executeHook(option, value);
            assignValue(result, option, value);
          }
        }
      }
      allArguments = syntax.allArguments();
      for (index = _j = 0, _len1 = positional.length; _j < _len1; index = ++_j) {
        arg = positional[index];
        if (option = allArguments[index]) {
          value = option.coerce(arg, result, syntax);
          value = executeHook(option, value);
          positional[index] = value;
          if (option["var"]) {
            assignValue(result, option, value);
          }
        }
      }
      for (index = _k = 0, _len2 = allArguments.length; _k < _len2; index = ++_k) {
        option = allArguments[index];
        if (index >= positional.length) {
          if (option.tags.required) {
            throw createError("Missing required argument \#" + (index + 1) + ": " + (option.leftUsageComponent()));
          }
          if ((option.defaultValue != null) || option.tags.fancydefault) {
            if (option.defaultValue != null) {
              value = option.coerce(option.defaultValue, result, syntax);
            } else {
              value = null;
            }
            value = executeHook(option, value);
            if (option["var"]) {
              assignValue(result, option, value);
            }
            if (index === positional.length) {
              positional.push(value);
            } else if (!option["var"] && !option.func) {
              throw new Error("Cannot apply default value to argument \#" + (index + 1) + " (" + (option.leftUsageComponent()) + ") because no #var is specified, no func is provided and previous arguments don't have default values");
            }
          }
        }
      }
      result.argv = positional;
      for (_l = 0, _len3 = funcs.length; _l < _len3; _l++) {
        _ref1 = funcs[_l], func = _ref1[0], option = _ref1[1], value = _ref1[2];
        func(value, result, syntax, option);
      }
      for (_m = 0, _len4 = commands.length; _m < _len4; _m++) {
        command = commands[_m];
        if (typeof command.func === "function") {
          command.func(result);
        }
      }
      return result;
    };

    Syntax.prototype.lookupLongOption = function(name, result) {
      var option, _base;
      if (!this.longOptions.hasOwnProperty(name)) {
        if (this.parent && (option = this.parent.lookupLongOption(name, result))) {
          return option;
        }
        if (typeof (_base = this.handlers).resolveLongOption === "function") {
          _base.resolveLongOption(name, result, this);
        }
      }
      if (this.longOptions.hasOwnProperty(name)) {
        return this.longOptions[name];
      } else {
        return null;
      }
    };

    Syntax.prototype.lookupShortOption = function(name, result) {
      var option, _base;
      if (!this.shortOptions.hasOwnProperty(name)) {
        if (this.parent && (option = this.parent.lookupShortOption(name, result))) {
          return option;
        }
        if (typeof (_base = this.handlers).resolveShortOption === "function") {
          _base.resolveShortOption(name, result, this);
        }
      }
      if (this.shortOptions.hasOwnProperty(name)) {
        return this.shortOptions[name];
      } else {
        return null;
      }
    };

    Syntax.prototype.lookupCommand = function(name, result) {
      var command, _base;
      if (!this.commands.hasOwnProperty(name)) {
        if (this.parent && (command = this.parent.lookupCommand(name, result))) {
          return command;
        }
        if (typeof (_base = this.handlers).resolveCommand === "function") {
          _base.resolveCommand(name, result, this);
        }
      }
      if (this.commands.hasOwnProperty(name)) {
        return this.commands[name];
      } else {
        return null;
      }
    };

    Syntax.prototype.allOptions = function() {
      var _ref;
      return (((_ref = this.parent) != null ? _ref.allOptions() : void 0) || []).concat(this.options);
    };

    Syntax.prototype.allArguments = function() {
      var _ref;
      return (((_ref = this.parent) != null ? _ref.allArguments() : void 0) || []).concat(this["arguments"]);
    };

    Syntax.prototype.allCommands = function() {
      return this.commandsOrder;
    };

    return Syntax;

  })();

  Option.parse = function(spec) {
    var $, defaultValue, desc, isOption, longOpt, metavars, options, shortOpt, tag, tags, value, _, _ref, _ref1, _ref2, _ref3, _ref4;
    isOption = (' ' + spec).match(OPTION);
    _ref = spec.match(OPTION_DESC) || [void 0, spec, ""], _ = _ref[0], options = _ref[1], desc = _ref[2];
    if (isOption) {
      _ref1 = options.match(OPTION_METAVARS) || [void 0, options, ""], _ = _ref1[0], options = _ref1[1], metavars = _ref1[2];
      _ref2 = options.match(OPTION_SHORT) || [void 0, "", options], _ = _ref2[0], shortOpt = _ref2[1], options = _ref2[2];
      _ref3 = (options || '').match(OPTION_LONG) || [void 0, "", options], _ = _ref3[0], longOpt = _ref3[1], options = _ref3[2];
    } else {
      _ref4 = [options, ""], metavars = _ref4[0], options = _ref4[1];
    }
    metavars = metavars && metavars.trim() && metavars.trim().split(/\s+/) || [];
    tags = ((function() {
      var _results;
      _results = [];
      while ($ = desc.match(OPTION_DESC_TAG)) {
        _results.push(((_ = $[0], desc = $[1], tag = $[2], value = $[3], $), [tag, value != null ? value : true]));
      }
      return _results;
    })());
    tags.reverse();
    if (longOpt && longOpt.match(OPTION_BOOL)) {
      tags.push(['acceptsno', true]);
      longOpt = longOpt.replace('--[no-]', '--');
    }
    if (isOption && metavars.length === 0) {
      tags.push(['flag', true]);
    }
    if ($ = desc.match(OPTION_DESC_DEFAULT)) {
      defaultValue = $[1];
      if (defaultValue.match(/\s/)) {
        defaultValue = void 0;
        tags.push(['fancydefault', true]);
      }
    }
    if (options) {
      throw new Error("Invalid option spec format (cannot parse " + (JSON.stringify(options)) + "): " + (JSON.stringify(spec)));
    }
    if (isOption && !(shortOpt || longOpt)) {
      throw new Error("Invalid option spec format !(shortOpt || longOpt): " + (JSON.stringify(spec)));
    }
    return new Option(shortOpt || null, longOpt || null, desc.trim(), tags, metavars, defaultValue);
  };

  parse = function(specs, options) {
    var syntax, _ref, _ref1, _ref2, _ref3, _ref4;
    if (options == null) {
      options = {};
    }
    if ((_ref = options.handlers) == null) {
      options.handlers = {};
    }
    if ((_ref1 = options.argv) == null) {
      options.argv = process.argv.slice(2);
    }
    if ((_ref2 = options.error) == null) {
      options.error = function(e) {
        process.stderr.write("" + (e.message.trim()) + ". Run with --help for help.\n");
        return process.exit(10);
      };
    }
    if ((_ref3 = options.help) == null) {
      options.help = function(text) {
        process.stdout.write(text.trim() + "\n");
        return process.exit(0);
      };
    }
    if ((_ref4 = options.commandKeys) == null) {
      options.commandKeys = ['command', 'subcommand', 'subsubcommand', 'subsubsubcommand'];
    }
    options.compoundCommandKey = null;
    syntax = new Syntax(options.handlers);
    syntax.add(specs, options);
    if (!syntax.longOptions.help) {
      syntax.add([
        "  -h, --help  Display this usage information", function(v, o, syntax) {
          return options.help(syntax.toUsageString());
        }
      ]);
    }
    try {
      return syntax.parse(options.argv, options);
    } catch (e) {
      if (e.isCommandLineError) {
        return options.error(e);
      } else {
        throw e;
      }
    }
  };

  module.exports = parse;

  module.exports.parseOptionSpec = Option.parse;

  module.exports.Syntax = Syntax;

}).call(this);
