"no use strict";

!function (window) {
  if (typeof window.window != "undefined" && window.document) return;
  if (window.require && window.define) return;

  if (!window.console) {
    window.console = function () {
      var msgs = Array.prototype.slice.call(arguments, 0);
      postMessage({
        type: "log",
        data: msgs
      });
    };

    window.console.error = window.console.warn = window.console.log = window.console.trace = window.console;
  }

  window.window = window;
  window.ace = window;

  window.onerror = function (message, file, line, col, err) {
    postMessage({
      type: "error",
      data: {
        message: message,
        data: err.data,
        file: file,
        line: line,
        col: col,
        stack: err.stack
      }
    });
  };

  window.normalizeModule = function (parentId, moduleName) {
    // normalize plugin requires
    if (moduleName.indexOf("!") !== -1) {
      var chunks = moduleName.split("!");
      return window.normalizeModule(parentId, chunks[0]) + "!" + window.normalizeModule(parentId, chunks[1]);
    } // normalize relative requires


    if (moduleName.charAt(0) == ".") {
      var base = parentId.split("/").slice(0, -1).join("/");
      moduleName = (base ? base + "/" : "") + moduleName;

      while (moduleName.indexOf(".") !== -1 && previous != moduleName) {
        var previous = moduleName;
        moduleName = moduleName.replace(/^\.\//, "").replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, "");
      }
    }

    return moduleName;
  };

  window.require = function require(parentId, id) {
    if (!id) {
      id = parentId;
      parentId = null;
    }

    if (!id.charAt) throw new Error("worker.js require() accepts only (parentId, id) as arguments");
    id = window.normalizeModule(parentId, id);
    var module = window.require.modules[id];

    if (module) {
      if (!module.initialized) {
        module.initialized = true;
        module.exports = module.factory().exports;
      }

      return module.exports;
    }

    if (!window.require.tlns) return console.log("unable to load " + id);
    var path = resolveModuleId(id, window.require.tlns);
    if (path.slice(-3) != ".js") path += ".js";
    window.require.id = id;
    window.require.modules[id] = {}; // prevent infinite loop on broken modules

    importScripts(path);
    return window.require(parentId, id);
  };

  function resolveModuleId(id, paths) {
    var testPath = id,
        tail = "";

    while (testPath) {
      var alias = paths[testPath];

      if (typeof alias == "string") {
        return alias + tail;
      } else if (alias) {
        return alias.location.replace(/\/*$/, "/") + (tail || alias.main || alias.name);
      } else if (alias === false) {
        return "";
      }

      var i = testPath.lastIndexOf("/");
      if (i === -1) break;
      tail = testPath.substr(i) + tail;
      testPath = testPath.slice(0, i);
    }

    return id;
  }

  window.require.modules = {};
  window.require.tlns = {};

  window.define = function (id, deps, _factory) {
    if (arguments.length == 2) {
      _factory = deps;

      if (typeof id != "string") {
        deps = id;
        id = window.require.id;
      }
    } else if (arguments.length == 1) {
      _factory = id;
      deps = [];
      id = window.require.id;
    }

    if (typeof _factory != "function") {
      window.require.modules[id] = {
        exports: _factory,
        initialized: true
      };
      return;
    }

    if (!deps.length) // If there is no dependencies, we inject "require", "exports" and
      // "module" as dependencies, to provide CommonJS compatibility.
      deps = ["require", "exports", "module"];

    var req = function req(childId) {
      return window.require(id, childId);
    };

    window.require.modules[id] = {
      exports: {},
      factory: function factory() {
        var module = this;

        var returnExports = _factory.apply(this, deps.slice(0, _factory.length).map(function (dep) {
          switch (dep) {
            // Because "require", "exports" and "module" aren't actual
            // dependencies, we must handle them seperately.
            case "require":
              return req;

            case "exports":
              return module.exports;

            case "module":
              return module;
            // But for all other dependencies, we can just go ahead and
            // require them.

            default:
              return req(dep);
          }
        }));

        if (returnExports) module.exports = returnExports;
        return module;
      }
    };
  };

  window.define.amd = {};
  require.tlns = {};

  window.initBaseUrls = function initBaseUrls(topLevelNamespaces) {
    for (var i in topLevelNamespaces) {
      require.tlns[i] = topLevelNamespaces[i];
    }
  };

  window.initSender = function initSender() {
    var EventEmitter = window.require("ace/lib/event_emitter").EventEmitter;

    var oop = window.require("ace/lib/oop");

    var Sender = function Sender() {};

    (function () {
      oop.implement(this, EventEmitter);

      this.callback = function (data, callbackId) {
        postMessage({
          type: "call",
          id: callbackId,
          data: data
        });
      };

      this.emit = function (name, data) {
        postMessage({
          type: "event",
          name: name,
          data: data
        });
      };
    }).call(Sender.prototype);
    return new Sender();
  };

  var main = window.main = null;
  var sender = window.sender = null;

  window.onmessage = function (e) {
    var msg = e.data;

    if (msg.event && sender) {
      sender._signal(msg.event, msg.data);
    } else if (msg.command) {
      if (main[msg.command]) main[msg.command].apply(main, msg.args);else if (window[msg.command]) window[msg.command].apply(window, msg.args);else throw new Error("Unknown command:" + msg.command);
    } else if (msg.init) {
      window.initBaseUrls(msg.tlns);

      require("ace/lib/es5-shim");

      sender = window.sender = window.initSender();

      var clazz = require(msg.module)[msg.classname];

      main = window.main = new clazz(sender);
    }
  };
}(this);
ace.define("ace/lib/oop", [], function (require, exports, module) {
  "use strict";

  exports.inherits = function (ctor, superCtor) {
    ctor.super_ = superCtor;
    ctor.prototype = Object.create(superCtor.prototype, {
      constructor: {
        value: ctor,
        enumerable: false,
        writable: true,
        configurable: true
      }
    });
  };

  exports.mixin = function (obj, mixin) {
    for (var key in mixin) {
      obj[key] = mixin[key];
    }

    return obj;
  };

  exports.implement = function (proto, mixin) {
    exports.mixin(proto, mixin);
  };
});
ace.define("ace/range", [], function (require, exports, module) {
  "use strict";

  var comparePoints = function comparePoints(p1, p2) {
    return p1.row - p2.row || p1.column - p2.column;
  };

  var Range = function Range(startRow, startColumn, endRow, endColumn) {
    this.start = {
      row: startRow,
      column: startColumn
    };
    this.end = {
      row: endRow,
      column: endColumn
    };
  };

  (function () {
    this.isEqual = function (range) {
      return this.start.row === range.start.row && this.end.row === range.end.row && this.start.column === range.start.column && this.end.column === range.end.column;
    };

    this.toString = function () {
      return "Range: [" + this.start.row + "/" + this.start.column + "] -> [" + this.end.row + "/" + this.end.column + "]";
    };

    this.contains = function (row, column) {
      return this.compare(row, column) == 0;
    };

    this.compareRange = function (range) {
      var cmp,
          end = range.end,
          start = range.start;
      cmp = this.compare(end.row, end.column);

      if (cmp == 1) {
        cmp = this.compare(start.row, start.column);

        if (cmp == 1) {
          return 2;
        } else if (cmp == 0) {
          return 1;
        } else {
          return 0;
        }
      } else if (cmp == -1) {
        return -2;
      } else {
        cmp = this.compare(start.row, start.column);

        if (cmp == -1) {
          return -1;
        } else if (cmp == 1) {
          return 42;
        } else {
          return 0;
        }
      }
    };

    this.comparePoint = function (p) {
      return this.compare(p.row, p.column);
    };

    this.containsRange = function (range) {
      return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0;
    };

    this.intersects = function (range) {
      var cmp = this.compareRange(range);
      return cmp == -1 || cmp == 0 || cmp == 1;
    };

    this.isEnd = function (row, column) {
      return this.end.row == row && this.end.column == column;
    };

    this.isStart = function (row, column) {
      return this.start.row == row && this.start.column == column;
    };

    this.setStart = function (row, column) {
      if (typeof row == "object") {
        this.start.column = row.column;
        this.start.row = row.row;
      } else {
        this.start.row = row;
        this.start.column = column;
      }
    };

    this.setEnd = function (row, column) {
      if (typeof row == "object") {
        this.end.column = row.column;
        this.end.row = row.row;
      } else {
        this.end.row = row;
        this.end.column = column;
      }
    };

    this.inside = function (row, column) {
      if (this.compare(row, column) == 0) {
        if (this.isEnd(row, column) || this.isStart(row, column)) {
          return false;
        } else {
          return true;
        }
      }

      return false;
    };

    this.insideStart = function (row, column) {
      if (this.compare(row, column) == 0) {
        if (this.isEnd(row, column)) {
          return false;
        } else {
          return true;
        }
      }

      return false;
    };

    this.insideEnd = function (row, column) {
      if (this.compare(row, column) == 0) {
        if (this.isStart(row, column)) {
          return false;
        } else {
          return true;
        }
      }

      return false;
    };

    this.compare = function (row, column) {
      if (!this.isMultiLine()) {
        if (row === this.start.row) {
          return column < this.start.column ? -1 : column > this.end.column ? 1 : 0;
        }
      }

      if (row < this.start.row) return -1;
      if (row > this.end.row) return 1;
      if (this.start.row === row) return column >= this.start.column ? 0 : -1;
      if (this.end.row === row) return column <= this.end.column ? 0 : 1;
      return 0;
    };

    this.compareStart = function (row, column) {
      if (this.start.row == row && this.start.column == column) {
        return -1;
      } else {
        return this.compare(row, column);
      }
    };

    this.compareEnd = function (row, column) {
      if (this.end.row == row && this.end.column == column) {
        return 1;
      } else {
        return this.compare(row, column);
      }
    };

    this.compareInside = function (row, column) {
      if (this.end.row == row && this.end.column == column) {
        return 1;
      } else if (this.start.row == row && this.start.column == column) {
        return -1;
      } else {
        return this.compare(row, column);
      }
    };

    this.clipRows = function (firstRow, lastRow) {
      if (this.end.row > lastRow) var end = {
        row: lastRow + 1,
        column: 0
      };else if (this.end.row < firstRow) var end = {
        row: firstRow,
        column: 0
      };
      if (this.start.row > lastRow) var start = {
        row: lastRow + 1,
        column: 0
      };else if (this.start.row < firstRow) var start = {
        row: firstRow,
        column: 0
      };
      return Range.fromPoints(start || this.start, end || this.end);
    };

    this.extend = function (row, column) {
      var cmp = this.compare(row, column);
      if (cmp == 0) return this;else if (cmp == -1) var start = {
        row: row,
        column: column
      };else var end = {
        row: row,
        column: column
      };
      return Range.fromPoints(start || this.start, end || this.end);
    };

    this.isEmpty = function () {
      return this.start.row === this.end.row && this.start.column === this.end.column;
    };

    this.isMultiLine = function () {
      return this.start.row !== this.end.row;
    };

    this.clone = function () {
      return Range.fromPoints(this.start, this.end);
    };

    this.collapseRows = function () {
      if (this.end.column == 0) return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row - 1), 0);else return new Range(this.start.row, 0, this.end.row, 0);
    };

    this.toScreenRange = function (session) {
      var screenPosStart = session.documentToScreenPosition(this.start);
      var screenPosEnd = session.documentToScreenPosition(this.end);
      return new Range(screenPosStart.row, screenPosStart.column, screenPosEnd.row, screenPosEnd.column);
    };

    this.moveBy = function (row, column) {
      this.start.row += row;
      this.start.column += column;
      this.end.row += row;
      this.end.column += column;
    };
  }).call(Range.prototype);

  Range.fromPoints = function (start, end) {
    return new Range(start.row, start.column, end.row, end.column);
  };

  Range.comparePoints = comparePoints;

  Range.comparePoints = function (p1, p2) {
    return p1.row - p2.row || p1.column - p2.column;
  };

  exports.Range = Range;
});
ace.define("ace/apply_delta", [], function (require, exports, module) {
  "use strict";

  function throwDeltaError(delta, errorText) {
    console.log("Invalid Delta:", delta);
    throw "Invalid Delta: " + errorText;
  }

  function positionInDocument(docLines, position) {
    return position.row >= 0 && position.row < docLines.length && position.column >= 0 && position.column <= docLines[position.row].length;
  }

  function validateDelta(docLines, delta) {
    if (delta.action != "insert" && delta.action != "remove") throwDeltaError(delta, "delta.action must be 'insert' or 'remove'");
    if (!(delta.lines instanceof Array)) throwDeltaError(delta, "delta.lines must be an Array");
    if (!delta.start || !delta.end) throwDeltaError(delta, "delta.start/end must be an present");
    var start = delta.start;
    if (!positionInDocument(docLines, delta.start)) throwDeltaError(delta, "delta.start must be contained in document");
    var end = delta.end;
    if (delta.action == "remove" && !positionInDocument(docLines, end)) throwDeltaError(delta, "delta.end must contained in document for 'remove' actions");
    var numRangeRows = end.row - start.row;
    var numRangeLastLineChars = end.column - (numRangeRows == 0 ? start.column : 0);
    if (numRangeRows != delta.lines.length - 1 || delta.lines[numRangeRows].length != numRangeLastLineChars) throwDeltaError(delta, "delta.range must match delta lines");
  }

  exports.applyDelta = function (docLines, delta, doNotValidate) {
    var row = delta.start.row;
    var startColumn = delta.start.column;
    var line = docLines[row] || "";

    switch (delta.action) {
      case "insert":
        var lines = delta.lines;

        if (lines.length === 1) {
          docLines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn);
        } else {
          var args = [row, 1].concat(delta.lines);
          docLines.splice.apply(docLines, args);
          docLines[row] = line.substring(0, startColumn) + docLines[row];
          docLines[row + delta.lines.length - 1] += line.substring(startColumn);
        }

        break;

      case "remove":
        var endColumn = delta.end.column;
        var endRow = delta.end.row;

        if (row === endRow) {
          docLines[row] = line.substring(0, startColumn) + line.substring(endColumn);
        } else {
          docLines.splice(row, endRow - row + 1, line.substring(0, startColumn) + docLines[endRow].substring(endColumn));
        }

        break;
    }
  };
});
ace.define("ace/lib/event_emitter", [], function (require, exports, module) {
  "use strict";

  var EventEmitter = {};

  var stopPropagation = function stopPropagation() {
    this.propagationStopped = true;
  };

  var preventDefault = function preventDefault() {
    this.defaultPrevented = true;
  };

  EventEmitter._emit = EventEmitter._dispatchEvent = function (eventName, e) {
    this._eventRegistry || (this._eventRegistry = {});
    this._defaultHandlers || (this._defaultHandlers = {});
    var listeners = this._eventRegistry[eventName] || [];
    var defaultHandler = this._defaultHandlers[eventName];
    if (!listeners.length && !defaultHandler) return;
    if (typeof e != "object" || !e) e = {};
    if (!e.type) e.type = eventName;
    if (!e.stopPropagation) e.stopPropagation = stopPropagation;
    if (!e.preventDefault) e.preventDefault = preventDefault;
    listeners = listeners.slice();

    for (var i = 0; i < listeners.length; i++) {
      listeners[i](e, this);
      if (e.propagationStopped) break;
    }

    if (defaultHandler && !e.defaultPrevented) return defaultHandler(e, this);
  };

  EventEmitter._signal = function (eventName, e) {
    var listeners = (this._eventRegistry || {})[eventName];
    if (!listeners) return;
    listeners = listeners.slice();

    for (var i = 0; i < listeners.length; i++) {
      listeners[i](e, this);
    }
  };

  EventEmitter.once = function (eventName, callback) {
    var _self = this;

    this.on(eventName, function newCallback() {
      _self.off(eventName, newCallback);

      callback.apply(null, arguments);
    });

    if (!callback) {
      return new Promise(function (resolve) {
        callback = resolve;
      });
    }
  };

  EventEmitter.setDefaultHandler = function (eventName, callback) {
    var handlers = this._defaultHandlers;
    if (!handlers) handlers = this._defaultHandlers = {
      _disabled_: {}
    };

    if (handlers[eventName]) {
      var old = handlers[eventName];
      var disabled = handlers._disabled_[eventName];
      if (!disabled) handlers._disabled_[eventName] = disabled = [];
      disabled.push(old);
      var i = disabled.indexOf(callback);
      if (i != -1) disabled.splice(i, 1);
    }

    handlers[eventName] = callback;
  };

  EventEmitter.removeDefaultHandler = function (eventName, callback) {
    var handlers = this._defaultHandlers;
    if (!handlers) return;
    var disabled = handlers._disabled_[eventName];

    if (handlers[eventName] == callback) {
      if (disabled) this.setDefaultHandler(eventName, disabled.pop());
    } else if (disabled) {
      var i = disabled.indexOf(callback);
      if (i != -1) disabled.splice(i, 1);
    }
  };

  EventEmitter.on = EventEmitter.addEventListener = function (eventName, callback, capturing) {
    this._eventRegistry = this._eventRegistry || {};
    var listeners = this._eventRegistry[eventName];
    if (!listeners) listeners = this._eventRegistry[eventName] = [];
    if (listeners.indexOf(callback) == -1) listeners[capturing ? "unshift" : "push"](callback);
    return callback;
  };

  EventEmitter.off = EventEmitter.removeListener = EventEmitter.removeEventListener = function (eventName, callback) {
    this._eventRegistry = this._eventRegistry || {};
    var listeners = this._eventRegistry[eventName];
    if (!listeners) return;
    var index = listeners.indexOf(callback);
    if (index !== -1) listeners.splice(index, 1);
  };

  EventEmitter.removeAllListeners = function (eventName) {
    if (!eventName) this._eventRegistry = this._defaultHandlers = undefined;
    if (this._eventRegistry) this._eventRegistry[eventName] = undefined;
    if (this._defaultHandlers) this._defaultHandlers[eventName] = undefined;
  };

  exports.EventEmitter = EventEmitter;
});
ace.define("ace/anchor", [], function (require, exports, module) {
  "use strict";

  var oop = require("./lib/oop");

  var EventEmitter = require("./lib/event_emitter").EventEmitter;

  var Anchor = exports.Anchor = function (doc, row, column) {
    this.$onChange = this.onChange.bind(this);
    this.attach(doc);
    if (typeof column == "undefined") this.setPosition(row.row, row.column);else this.setPosition(row, column);
  };

  (function () {
    oop.implement(this, EventEmitter);

    this.getPosition = function () {
      return this.$clipPositionToDocument(this.row, this.column);
    };

    this.getDocument = function () {
      return this.document;
    };

    this.$insertRight = false;

    this.onChange = function (delta) {
      if (delta.start.row == delta.end.row && delta.start.row != this.row) return;
      if (delta.start.row > this.row) return;
      var point = $getTransformedPoint(delta, {
        row: this.row,
        column: this.column
      }, this.$insertRight);
      this.setPosition(point.row, point.column, true);
    };

    function $pointsInOrder(point1, point2, equalPointsInOrder) {
      var bColIsAfter = equalPointsInOrder ? point1.column <= point2.column : point1.column < point2.column;
      return point1.row < point2.row || point1.row == point2.row && bColIsAfter;
    }

    function $getTransformedPoint(delta, point, moveIfEqual) {
      var deltaIsInsert = delta.action == "insert";
      var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.end.row - delta.start.row);
      var deltaColShift = (deltaIsInsert ? 1 : -1) * (delta.end.column - delta.start.column);
      var deltaStart = delta.start;
      var deltaEnd = deltaIsInsert ? deltaStart : delta.end; // Collapse insert range.

      if ($pointsInOrder(point, deltaStart, moveIfEqual)) {
        return {
          row: point.row,
          column: point.column
        };
      }

      if ($pointsInOrder(deltaEnd, point, !moveIfEqual)) {
        return {
          row: point.row + deltaRowShift,
          column: point.column + (point.row == deltaEnd.row ? deltaColShift : 0)
        };
      }

      return {
        row: deltaStart.row,
        column: deltaStart.column
      };
    }

    this.setPosition = function (row, column, noClip) {
      var pos;

      if (noClip) {
        pos = {
          row: row,
          column: column
        };
      } else {
        pos = this.$clipPositionToDocument(row, column);
      }

      if (this.row == pos.row && this.column == pos.column) return;
      var old = {
        row: this.row,
        column: this.column
      };
      this.row = pos.row;
      this.column = pos.column;

      this._signal("change", {
        old: old,
        value: pos
      });
    };

    this.detach = function () {
      this.document.off("change", this.$onChange);
    };

    this.attach = function (doc) {
      this.document = doc || this.document;
      this.document.on("change", this.$onChange);
    };

    this.$clipPositionToDocument = function (row, column) {
      var pos = {};

      if (row >= this.document.getLength()) {
        pos.row = Math.max(0, this.document.getLength() - 1);
        pos.column = this.document.getLine(pos.row).length;
      } else if (row < 0) {
        pos.row = 0;
        pos.column = 0;
      } else {
        pos.row = row;
        pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column));
      }

      if (column < 0) pos.column = 0;
      return pos;
    };
  }).call(Anchor.prototype);
});
ace.define("ace/document", [], function (require, exports, module) {
  "use strict";

  var oop = require("./lib/oop");

  var applyDelta = require("./apply_delta").applyDelta;

  var EventEmitter = require("./lib/event_emitter").EventEmitter;

  var Range = require("./range").Range;

  var Anchor = require("./anchor").Anchor;

  var Document = function Document(textOrLines) {
    this.$lines = [""];

    if (textOrLines.length === 0) {
      this.$lines = [""];
    } else if (Array.isArray(textOrLines)) {
      this.insertMergedLines({
        row: 0,
        column: 0
      }, textOrLines);
    } else {
      this.insert({
        row: 0,
        column: 0
      }, textOrLines);
    }
  };

  (function () {
    oop.implement(this, EventEmitter);

    this.setValue = function (text) {
      var len = this.getLength() - 1;
      this.remove(new Range(0, 0, len, this.getLine(len).length));
      this.insert({
        row: 0,
        column: 0
      }, text);
    };

    this.getValue = function () {
      return this.getAllLines().join(this.getNewLineCharacter());
    };

    this.createAnchor = function (row, column) {
      return new Anchor(this, row, column);
    };

    if ("aaa".split(/a/).length === 0) {
      this.$split = function (text) {
        return text.replace(/\r\n|\r/g, "\n").split("\n");
      };
    } else {
      this.$split = function (text) {
        return text.split(/\r\n|\r|\n/);
      };
    }

    this.$detectNewLine = function (text) {
      var match = text.match(/^.*?(\r\n|\r|\n)/m);
      this.$autoNewLine = match ? match[1] : "\n";

      this._signal("changeNewLineMode");
    };

    this.getNewLineCharacter = function () {
      switch (this.$newLineMode) {
        case "windows":
          return "\r\n";

        case "unix":
          return "\n";

        default:
          return this.$autoNewLine || "\n";
      }
    };

    this.$autoNewLine = "";
    this.$newLineMode = "auto";

    this.setNewLineMode = function (newLineMode) {
      if (this.$newLineMode === newLineMode) return;
      this.$newLineMode = newLineMode;

      this._signal("changeNewLineMode");
    };

    this.getNewLineMode = function () {
      return this.$newLineMode;
    };

    this.isNewLine = function (text) {
      return text == "\r\n" || text == "\r" || text == "\n";
    };

    this.getLine = function (row) {
      return this.$lines[row] || "";
    };

    this.getLines = function (firstRow, lastRow) {
      return this.$lines.slice(firstRow, lastRow + 1);
    };

    this.getAllLines = function () {
      return this.getLines(0, this.getLength());
    };

    this.getLength = function () {
      return this.$lines.length;
    };

    this.getTextRange = function (range) {
      return this.getLinesForRange(range).join(this.getNewLineCharacter());
    };

    this.getLinesForRange = function (range) {
      var lines;

      if (range.start.row === range.end.row) {
        lines = [this.getLine(range.start.row).substring(range.start.column, range.end.column)];
      } else {
        lines = this.getLines(range.start.row, range.end.row);
        lines[0] = (lines[0] || "").substring(range.start.column);
        var l = lines.length - 1;
        if (range.end.row - range.start.row == l) lines[l] = lines[l].substring(0, range.end.column);
      }

      return lines;
    };

    this.insertLines = function (row, lines) {
      console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead.");
      return this.insertFullLines(row, lines);
    };

    this.removeLines = function (firstRow, lastRow) {
      console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead.");
      return this.removeFullLines(firstRow, lastRow);
    };

    this.insertNewLine = function (position) {
      console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead.");
      return this.insertMergedLines(position, ["", ""]);
    };

    this.insert = function (position, text) {
      if (this.getLength() <= 1) this.$detectNewLine(text);
      return this.insertMergedLines(position, this.$split(text));
    };

    this.insertInLine = function (position, text) {
      var start = this.clippedPos(position.row, position.column);
      var end = this.pos(position.row, position.column + text.length);
      this.applyDelta({
        start: start,
        end: end,
        action: "insert",
        lines: [text]
      }, true);
      return this.clonePos(end);
    };

    this.clippedPos = function (row, column) {
      var length = this.getLength();

      if (row === undefined) {
        row = length;
      } else if (row < 0) {
        row = 0;
      } else if (row >= length) {
        row = length - 1;
        column = undefined;
      }

      var line = this.getLine(row);
      if (column == undefined) column = line.length;
      column = Math.min(Math.max(column, 0), line.length);
      return {
        row: row,
        column: column
      };
    };

    this.clonePos = function (pos) {
      return {
        row: pos.row,
        column: pos.column
      };
    };

    this.pos = function (row, column) {
      return {
        row: row,
        column: column
      };
    };

    this.$clipPosition = function (position) {
      var length = this.getLength();

      if (position.row >= length) {
        position.row = Math.max(0, length - 1);
        position.column = this.getLine(length - 1).length;
      } else {
        position.row = Math.max(0, position.row);
        position.column = Math.min(Math.max(position.column, 0), this.getLine(position.row).length);
      }

      return position;
    };

    this.insertFullLines = function (row, lines) {
      row = Math.min(Math.max(row, 0), this.getLength());
      var column = 0;

      if (row < this.getLength()) {
        lines = lines.concat([""]);
        column = 0;
      } else {
        lines = [""].concat(lines);
        row--;
        column = this.$lines[row].length;
      }

      this.insertMergedLines({
        row: row,
        column: column
      }, lines);
    };

    this.insertMergedLines = function (position, lines) {
      var start = this.clippedPos(position.row, position.column);
      var end = {
        row: start.row + lines.length - 1,
        column: (lines.length == 1 ? start.column : 0) + lines[lines.length - 1].length
      };
      this.applyDelta({
        start: start,
        end: end,
        action: "insert",
        lines: lines
      });
      return this.clonePos(end);
    };

    this.remove = function (range) {
      var start = this.clippedPos(range.start.row, range.start.column);
      var end = this.clippedPos(range.end.row, range.end.column);
      this.applyDelta({
        start: start,
        end: end,
        action: "remove",
        lines: this.getLinesForRange({
          start: start,
          end: end
        })
      });
      return this.clonePos(start);
    };

    this.removeInLine = function (row, startColumn, endColumn) {
      var start = this.clippedPos(row, startColumn);
      var end = this.clippedPos(row, endColumn);
      this.applyDelta({
        start: start,
        end: end,
        action: "remove",
        lines: this.getLinesForRange({
          start: start,
          end: end
        })
      }, true);
      return this.clonePos(start);
    };

    this.removeFullLines = function (firstRow, lastRow) {
      firstRow = Math.min(Math.max(0, firstRow), this.getLength() - 1);
      lastRow = Math.min(Math.max(0, lastRow), this.getLength() - 1);
      var deleteFirstNewLine = lastRow == this.getLength() - 1 && firstRow > 0;
      var deleteLastNewLine = lastRow < this.getLength() - 1;
      var startRow = deleteFirstNewLine ? firstRow - 1 : firstRow;
      var startCol = deleteFirstNewLine ? this.getLine(startRow).length : 0;
      var endRow = deleteLastNewLine ? lastRow + 1 : lastRow;
      var endCol = deleteLastNewLine ? 0 : this.getLine(endRow).length;
      var range = new Range(startRow, startCol, endRow, endCol);
      var deletedLines = this.$lines.slice(firstRow, lastRow + 1);
      this.applyDelta({
        start: range.start,
        end: range.end,
        action: "remove",
        lines: this.getLinesForRange(range)
      });
      return deletedLines;
    };

    this.removeNewLine = function (row) {
      if (row < this.getLength() - 1 && row >= 0) {
        this.applyDelta({
          start: this.pos(row, this.getLine(row).length),
          end: this.pos(row + 1, 0),
          action: "remove",
          lines: ["", ""]
        });
      }
    };

    this.replace = function (range, text) {
      if (!(range instanceof Range)) range = Range.fromPoints(range.start, range.end);
      if (text.length === 0 && range.isEmpty()) return range.start;
      if (text == this.getTextRange(range)) return range.end;
      this.remove(range);
      var end;

      if (text) {
        end = this.insert(range.start, text);
      } else {
        end = range.start;
      }

      return end;
    };

    this.applyDeltas = function (deltas) {
      for (var i = 0; i < deltas.length; i++) {
        this.applyDelta(deltas[i]);
      }
    };

    this.revertDeltas = function (deltas) {
      for (var i = deltas.length - 1; i >= 0; i--) {
        this.revertDelta(deltas[i]);
      }
    };

    this.applyDelta = function (delta, doNotValidate) {
      var isInsert = delta.action == "insert";

      if (isInsert ? delta.lines.length <= 1 && !delta.lines[0] : !Range.comparePoints(delta.start, delta.end)) {
        return;
      }

      if (isInsert && delta.lines.length > 20000) {
        this.$splitAndapplyLargeDelta(delta, 20000);
      } else {
        applyDelta(this.$lines, delta, doNotValidate);

        this._signal("change", delta);
      }
    };

    this.$safeApplyDelta = function (delta) {
      var docLength = this.$lines.length;

      if (delta.action == "remove" && delta.start.row < docLength && delta.end.row < docLength || delta.action == "insert" && delta.start.row <= docLength) {
        this.applyDelta(delta);
      }
    };

    this.$splitAndapplyLargeDelta = function (delta, MAX) {
      var lines = delta.lines;
      var l = lines.length - MAX + 1;
      var row = delta.start.row;
      var column = delta.start.column;

      for (var from = 0, to = 0; from < l; from = to) {
        to += MAX - 1;
        var chunk = lines.slice(from, to);
        chunk.push("");
        this.applyDelta({
          start: this.pos(row + from, column),
          end: this.pos(row + to, column = 0),
          action: delta.action,
          lines: chunk
        }, true);
      }

      delta.lines = lines.slice(from);
      delta.start.row = row + from;
      delta.start.column = column;
      this.applyDelta(delta, true);
    };

    this.revertDelta = function (delta) {
      this.$safeApplyDelta({
        start: this.clonePos(delta.start),
        end: this.clonePos(delta.end),
        action: delta.action == "insert" ? "remove" : "insert",
        lines: delta.lines.slice()
      });
    };

    this.indexToPosition = function (index, startRow) {
      var lines = this.$lines || this.getAllLines();
      var newlineLength = this.getNewLineCharacter().length;

      for (var i = startRow || 0, l = lines.length; i < l; i++) {
        index -= lines[i].length + newlineLength;
        if (index < 0) return {
          row: i,
          column: index + lines[i].length + newlineLength
        };
      }

      return {
        row: l - 1,
        column: index + lines[l - 1].length + newlineLength
      };
    };

    this.positionToIndex = function (pos, startRow) {
      var lines = this.$lines || this.getAllLines();
      var newlineLength = this.getNewLineCharacter().length;
      var index = 0;
      var row = Math.min(pos.row, lines.length);

      for (var i = startRow || 0; i < row; ++i) {
        index += lines[i].length + newlineLength;
      }

      return index + pos.column;
    };
  }).call(Document.prototype);
  exports.Document = Document;
});
ace.define("ace/lib/lang", [], function (require, exports, module) {
  "use strict";

  exports.last = function (a) {
    return a[a.length - 1];
  };

  exports.stringReverse = function (string) {
    return string.split("").reverse().join("");
  };

  exports.stringRepeat = function (string, count) {
    var result = '';

    while (count > 0) {
      if (count & 1) result += string;
      if (count >>= 1) string += string;
    }

    return result;
  };

  var trimBeginRegexp = /^\s\s*/;
  var trimEndRegexp = /\s\s*$/;

  exports.stringTrimLeft = function (string) {
    return string.replace(trimBeginRegexp, '');
  };

  exports.stringTrimRight = function (string) {
    return string.replace(trimEndRegexp, '');
  };

  exports.copyObject = function (obj) {
    var copy = {};

    for (var key in obj) {
      copy[key] = obj[key];
    }

    return copy;
  };

  exports.copyArray = function (array) {
    var copy = [];

    for (var i = 0, l = array.length; i < l; i++) {
      if (array[i] && typeof array[i] == "object") copy[i] = this.copyObject(array[i]);else copy[i] = array[i];
    }

    return copy;
  };

  exports.deepCopy = function deepCopy(obj) {
    if (typeof obj !== "object" || !obj) return obj;
    var copy;

    if (Array.isArray(obj)) {
      copy = [];

      for (var key = 0; key < obj.length; key++) {
        copy[key] = deepCopy(obj[key]);
      }

      return copy;
    }

    if (Object.prototype.toString.call(obj) !== "[object Object]") return obj;
    copy = {};

    for (var key in obj) {
      copy[key] = deepCopy(obj[key]);
    }

    return copy;
  };

  exports.arrayToMap = function (arr) {
    var map = {};

    for (var i = 0; i < arr.length; i++) {
      map[arr[i]] = 1;
    }

    return map;
  };

  exports.createMap = function (props) {
    var map = Object.create(null);

    for (var i in props) {
      map[i] = props[i];
    }

    return map;
  };

  exports.arrayRemove = function (array, value) {
    for (var i = 0; i <= array.length; i++) {
      if (value === array[i]) {
        array.splice(i, 1);
      }
    }
  };

  exports.escapeRegExp = function (str) {
    return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
  };

  exports.escapeHTML = function (str) {
    return ("" + str).replace(/&/g, "&#38;").replace(/"/g, "&#34;").replace(/'/g, "&#39;").replace(/</g, "&#60;");
  };

  exports.getMatchOffsets = function (string, regExp) {
    var matches = [];
    string.replace(regExp, function (str) {
      matches.push({
        offset: arguments[arguments.length - 2],
        length: str.length
      });
    });
    return matches;
  };

  exports.deferredCall = function (fcn) {
    var timer = null;

    var callback = function callback() {
      timer = null;
      fcn();
    };

    var deferred = function deferred(timeout) {
      deferred.cancel();
      timer = setTimeout(callback, timeout || 0);
      return deferred;
    };

    deferred.schedule = deferred;

    deferred.call = function () {
      this.cancel();
      fcn();
      return deferred;
    };

    deferred.cancel = function () {
      clearTimeout(timer);
      timer = null;
      return deferred;
    };

    deferred.isPending = function () {
      return timer;
    };

    return deferred;
  };

  exports.delayedCall = function (fcn, defaultTimeout) {
    var timer = null;

    var callback = function callback() {
      timer = null;
      fcn();
    };

    var _self = function _self(timeout) {
      if (timer == null) timer = setTimeout(callback, timeout || defaultTimeout);
    };

    _self.delay = function (timeout) {
      timer && clearTimeout(timer);
      timer = setTimeout(callback, timeout || defaultTimeout);
    };

    _self.schedule = _self;

    _self.call = function () {
      this.cancel();
      fcn();
    };

    _self.cancel = function () {
      timer && clearTimeout(timer);
      timer = null;
    };

    _self.isPending = function () {
      return timer;
    };

    return _self;
  };
});
ace.define("ace/worker/mirror", [], function (require, exports, module) {
  "use strict";

  var Range = require("../range").Range;

  var Document = require("../document").Document;

  var lang = require("../lib/lang");

  var Mirror = exports.Mirror = function (sender) {
    this.sender = sender;
    var doc = this.doc = new Document("");
    var deferredUpdate = this.deferredUpdate = lang.delayedCall(this.onUpdate.bind(this));

    var _self = this;

    sender.on("change", function (e) {
      var data = e.data;

      if (data[0].start) {
        doc.applyDeltas(data);
      } else {
        for (var i = 0; i < data.length; i += 2) {
          if (Array.isArray(data[i + 1])) {
            var d = {
              action: "insert",
              start: data[i],
              lines: data[i + 1]
            };
          } else {
            var d = {
              action: "remove",
              start: data[i],
              end: data[i + 1]
            };
          }

          doc.applyDelta(d, true);
        }
      }

      if (_self.$timeout) return deferredUpdate.schedule(_self.$timeout);

      _self.onUpdate();
    });
  };

  (function () {
    this.$timeout = 500;

    this.setTimeout = function (timeout) {
      this.$timeout = timeout;
    };

    this.setValue = function (value) {
      this.doc.setValue(value);
      this.deferredUpdate.schedule(this.$timeout);
    };

    this.getValue = function (callbackId) {
      this.sender.callback(this.doc.getValue(), callbackId);
    };

    this.onUpdate = function () {};

    this.isPending = function () {
      return this.deferredUpdate.isPending();
    };
  }).call(Mirror.prototype);
});
ace.define("ace/mode/lua/luaparse", [], function (require, exports, module) {
  (function (root, name, factory) {
    factory(exports);
  })(this, 'luaparse', function (exports) {
    'use strict';

    exports.version = '0.1.4';
    var input, options, length;
    var defaultOptions = exports.defaultOptions = {
      wait: false,
      comments: true,
      scope: false,
      locations: false,
      ranges: false
    };
    var EOF = 1,
        StringLiteral = 2,
        Keyword = 4,
        Identifier = 8,
        NumericLiteral = 16,
        Punctuator = 32,
        BooleanLiteral = 64,
        NilLiteral = 128,
        VarargLiteral = 256;
    exports.tokenTypes = {
      EOF: EOF,
      StringLiteral: StringLiteral,
      Keyword: Keyword,
      Identifier: Identifier,
      NumericLiteral: NumericLiteral,
      Punctuator: Punctuator,
      BooleanLiteral: BooleanLiteral,
      NilLiteral: NilLiteral,
      VarargLiteral: VarargLiteral
    };
    var errors = exports.errors = {
      unexpected: 'Unexpected %1 \'%2\' near \'%3\'',
      expected: '\'%1\' expected near \'%2\'',
      expectedToken: '%1 expected near \'%2\'',
      unfinishedString: 'unfinished string near \'%1\'',
      malformedNumber: 'malformed number near \'%1\''
    };
    var ast = exports.ast = {
      labelStatement: function labelStatement(label) {
        return {
          type: 'LabelStatement',
          label: label
        };
      },
      breakStatement: function breakStatement() {
        return {
          type: 'BreakStatement'
        };
      },
      gotoStatement: function gotoStatement(label) {
        return {
          type: 'GotoStatement',
          label: label
        };
      },
      returnStatement: function returnStatement(args) {
        return {
          type: 'ReturnStatement',
          'arguments': args
        };
      },
      ifStatement: function ifStatement(clauses) {
        return {
          type: 'IfStatement',
          clauses: clauses
        };
      },
      ifClause: function ifClause(condition, body) {
        return {
          type: 'IfClause',
          condition: condition,
          body: body
        };
      },
      elseifClause: function elseifClause(condition, body) {
        return {
          type: 'ElseifClause',
          condition: condition,
          body: body
        };
      },
      elseClause: function elseClause(body) {
        return {
          type: 'ElseClause',
          body: body
        };
      },
      whileStatement: function whileStatement(condition, body) {
        return {
          type: 'WhileStatement',
          condition: condition,
          body: body
        };
      },
      doStatement: function doStatement(body) {
        return {
          type: 'DoStatement',
          body: body
        };
      },
      repeatStatement: function repeatStatement(condition, body) {
        return {
          type: 'RepeatStatement',
          condition: condition,
          body: body
        };
      },
      localStatement: function localStatement(variables, init) {
        return {
          type: 'LocalStatement',
          variables: variables,
          init: init
        };
      },
      assignmentStatement: function assignmentStatement(variables, init) {
        return {
          type: 'AssignmentStatement',
          variables: variables,
          init: init
        };
      },
      callStatement: function callStatement(expression) {
        return {
          type: 'CallStatement',
          expression: expression
        };
      },
      functionStatement: function functionStatement(identifier, parameters, isLocal, body) {
        return {
          type: 'FunctionDeclaration',
          identifier: identifier,
          isLocal: isLocal,
          parameters: parameters,
          body: body
        };
      },
      forNumericStatement: function forNumericStatement(variable, start, end, step, body) {
        return {
          type: 'ForNumericStatement',
          variable: variable,
          start: start,
          end: end,
          step: step,
          body: body
        };
      },
      forGenericStatement: function forGenericStatement(variables, iterators, body) {
        return {
          type: 'ForGenericStatement',
          variables: variables,
          iterators: iterators,
          body: body
        };
      },
      chunk: function chunk(body) {
        return {
          type: 'Chunk',
          body: body
        };
      },
      identifier: function identifier(name) {
        return {
          type: 'Identifier',
          name: name
        };
      },
      literal: function literal(type, value, raw) {
        type = type === StringLiteral ? 'StringLiteral' : type === NumericLiteral ? 'NumericLiteral' : type === BooleanLiteral ? 'BooleanLiteral' : type === NilLiteral ? 'NilLiteral' : 'VarargLiteral';
        return {
          type: type,
          value: value,
          raw: raw
        };
      },
      tableKey: function tableKey(key, value) {
        return {
          type: 'TableKey',
          key: key,
          value: value
        };
      },
      tableKeyString: function tableKeyString(key, value) {
        return {
          type: 'TableKeyString',
          key: key,
          value: value
        };
      },
      tableValue: function tableValue(value) {
        return {
          type: 'TableValue',
          value: value
        };
      },
      tableConstructorExpression: function tableConstructorExpression(fields) {
        return {
          type: 'TableConstructorExpression',
          fields: fields
        };
      },
      binaryExpression: function binaryExpression(operator, left, right) {
        var type = 'and' === operator || 'or' === operator ? 'LogicalExpression' : 'BinaryExpression';
        return {
          type: type,
          operator: operator,
          left: left,
          right: right
        };
      },
      unaryExpression: function unaryExpression(operator, argument) {
        return {
          type: 'UnaryExpression',
          operator: operator,
          argument: argument
        };
      },
      memberExpression: function memberExpression(base, indexer, identifier) {
        return {
          type: 'MemberExpression',
          indexer: indexer,
          identifier: identifier,
          base: base
        };
      },
      indexExpression: function indexExpression(base, index) {
        return {
          type: 'IndexExpression',
          base: base,
          index: index
        };
      },
      callExpression: function callExpression(base, args) {
        return {
          type: 'CallExpression',
          base: base,
          'arguments': args
        };
      },
      tableCallExpression: function tableCallExpression(base, args) {
        return {
          type: 'TableCallExpression',
          base: base,
          'arguments': args
        };
      },
      stringCallExpression: function stringCallExpression(base, argument) {
        return {
          type: 'StringCallExpression',
          base: base,
          argument: argument
        };
      },
      comment: function comment(value, raw) {
        return {
          type: 'Comment',
          value: value,
          raw: raw
        };
      }
    };

    function finishNode(node) {
      if (trackLocations) {
        var location = locations.pop();
        location.complete();
        if (options.locations) node.loc = location.loc;
        if (options.ranges) node.range = location.range;
      }

      return node;
    }

    var slice = Array.prototype.slice,
        toString = Object.prototype.toString,
        indexOf = function indexOf(array, element) {
      for (var i = 0, length = array.length; i < length; i++) {
        if (array[i] === element) return i;
      }

      return -1;
    };

    function indexOfObject(array, property, element) {
      for (var i = 0, length = array.length; i < length; i++) {
        if (array[i][property] === element) return i;
      }

      return -1;
    }

    function sprintf(format) {
      var args = slice.call(arguments, 1);
      format = format.replace(/%(\d)/g, function (match, index) {
        return '' + args[index - 1] || '';
      });
      return format;
    }

    function extend() {
      var args = slice.call(arguments),
          dest = {},
          src,
          prop;

      for (var i = 0, length = args.length; i < length; i++) {
        src = args[i];

        for (prop in src) {
          if (src.hasOwnProperty(prop)) {
            dest[prop] = src[prop];
          }
        }
      }

      return dest;
    }

    function raise(token) {
      var message = sprintf.apply(null, slice.call(arguments, 1)),
          error,
          col;

      if ('undefined' !== typeof token.line) {
        col = token.range[0] - token.lineStart;
        error = new SyntaxError(sprintf('[%1:%2] %3', token.line, col, message));
        error.line = token.line;
        error.index = token.range[0];
        error.column = col;
      } else {
        col = index - lineStart + 1;
        error = new SyntaxError(sprintf('[%1:%2] %3', line, col, message));
        error.index = index;
        error.line = line;
        error.column = col;
      }

      throw error;
    }

    function raiseUnexpectedToken(type, token) {
      raise(token, errors.expectedToken, type, token.value);
    }

    function unexpected(found, near) {
      if ('undefined' === typeof near) near = lookahead.value;

      if ('undefined' !== typeof found.type) {
        var type;

        switch (found.type) {
          case StringLiteral:
            type = 'string';
            break;

          case Keyword:
            type = 'keyword';
            break;

          case Identifier:
            type = 'identifier';
            break;

          case NumericLiteral:
            type = 'number';
            break;

          case Punctuator:
            type = 'symbol';
            break;

          case BooleanLiteral:
            type = 'boolean';
            break;

          case NilLiteral:
            return raise(found, errors.unexpected, 'symbol', 'nil', near);
        }

        return raise(found, errors.unexpected, type, found.value, near);
      }

      return raise(found, errors.unexpected, 'symbol', found, near);
    }

    var index, token, previousToken, lookahead, comments, tokenStart, line, lineStart;
    exports.lex = lex;

    function lex() {
      skipWhiteSpace();

      while (45 === input.charCodeAt(index) && 45 === input.charCodeAt(index + 1)) {
        scanComment();
        skipWhiteSpace();
      }

      if (index >= length) return {
        type: EOF,
        value: '<eof>',
        line: line,
        lineStart: lineStart,
        range: [index, index]
      };
      var charCode = input.charCodeAt(index),
          next = input.charCodeAt(index + 1);
      tokenStart = index;
      if (isIdentifierStart(charCode)) return scanIdentifierOrKeyword();

      switch (charCode) {
        case 39:
        case 34:
          // '"
          return scanStringLiteral();

        case 48:
        case 49:
        case 50:
        case 51:
        case 52:
        case 53:
        case 54:
        case 55:
        case 56:
        case 57:
          return scanNumericLiteral();

        case 46:
          // .
          if (isDecDigit(next)) return scanNumericLiteral();

          if (46 === next) {
            if (46 === input.charCodeAt(index + 2)) return scanVarargLiteral();
            return scanPunctuator('..');
          }

          return scanPunctuator('.');

        case 61:
          // =
          if (61 === next) return scanPunctuator('==');
          return scanPunctuator('=');

        case 62:
          // >
          if (61 === next) return scanPunctuator('>=');
          return scanPunctuator('>');

        case 60:
          // <
          if (61 === next) return scanPunctuator('<=');
          return scanPunctuator('<');

        case 126:
          // ~
          if (61 === next) return scanPunctuator('~=');
          return scanPunctuator('~');

        case 58:
          // :
          if (58 === next) return scanPunctuator('::');
          return scanPunctuator(':');

        case 91:
          // [
          if (91 === next || 61 === next) return scanLongStringLiteral();
          return scanPunctuator('[');

        case 42:
        case 47:
        case 94:
        case 37:
        case 44:
        case 123:
        case 125:
        case 93:
        case 40:
        case 41:
        case 59:
        case 35:
        case 45:
        case 43:
        case 38:
        case 124:
          return scanPunctuator(input.charAt(index));
      }

      return unexpected(input.charAt(index));
    }

    function skipWhiteSpace() {
      while (index < length) {
        var charCode = input.charCodeAt(index);

        if (isWhiteSpace(charCode)) {
          index++;
        } else if (isLineTerminator(charCode)) {
          line++;
          lineStart = ++index;
        } else {
          break;
        }
      }
    }

    function scanIdentifierOrKeyword() {
      var value, type;

      while (isIdentifierPart(input.charCodeAt(++index))) {
        ;
      }

      value = input.slice(tokenStart, index);

      if (isKeyword(value)) {
        type = Keyword;
      } else if ('true' === value || 'false' === value) {
        type = BooleanLiteral;
        value = 'true' === value;
      } else if ('nil' === value) {
        type = NilLiteral;
        value = null;
      } else {
        type = Identifier;
      }

      return {
        type: type,
        value: value,
        line: line,
        lineStart: lineStart,
        range: [tokenStart, index]
      };
    }

    function scanPunctuator(value) {
      index += value.length;
      return {
        type: Punctuator,
        value: value,
        line: line,
        lineStart: lineStart,
        range: [tokenStart, index]
      };
    }

    function scanVarargLiteral() {
      index += 3;
      return {
        type: VarargLiteral,
        value: '...',
        line: line,
        lineStart: lineStart,
        range: [tokenStart, index]
      };
    }

    function scanStringLiteral() {
      var delimiter = input.charCodeAt(index++),
          stringStart = index,
          string = '',
          charCode;

      while (index < length) {
        charCode = input.charCodeAt(index++);
        if (delimiter === charCode) break;

        if (92 === charCode) {
          // \
          string += input.slice(stringStart, index - 1) + readEscapeSequence();
          stringStart = index;
        } else if (index >= length || isLineTerminator(charCode)) {
          string += input.slice(stringStart, index - 1);
          raise({}, errors.unfinishedString, string + String.fromCharCode(charCode));
        }
      }

      string += input.slice(stringStart, index - 1);
      return {
        type: StringLiteral,
        value: string,
        line: line,
        lineStart: lineStart,
        range: [tokenStart, index]
      };
    }

    function scanLongStringLiteral() {
      var string = readLongString();
      if (false === string) raise(token, errors.expected, '[', token.value);
      return {
        type: StringLiteral,
        value: string,
        line: line,
        lineStart: lineStart,
        range: [tokenStart, index]
      };
    }

    function scanNumericLiteral() {
      var character = input.charAt(index),
          next = input.charAt(index + 1);
      var value = '0' === character && 'xX'.indexOf(next || null) >= 0 ? readHexLiteral() : readDecLiteral();
      return {
        type: NumericLiteral,
        value: value,
        line: line,
        lineStart: lineStart,
        range: [tokenStart, index]
      };
    }

    function readHexLiteral() {
      var fraction = 0 // defaults to 0 as it gets summed
      ,
          binaryExponent = 1 // defaults to 1 as it gets multiplied
      ,
          binarySign = 1 // positive
      ,
          digit,
          fractionStart,
          exponentStart,
          digitStart;
      digitStart = index += 2; // Skip 0x part

      if (!isHexDigit(input.charCodeAt(index))) raise({}, errors.malformedNumber, input.slice(tokenStart, index));

      while (isHexDigit(input.charCodeAt(index))) {
        index++;
      }

      digit = parseInt(input.slice(digitStart, index), 16);

      if ('.' === input.charAt(index)) {
        fractionStart = ++index;

        while (isHexDigit(input.charCodeAt(index))) {
          index++;
        }

        fraction = input.slice(fractionStart, index);
        fraction = fractionStart === index ? 0 : parseInt(fraction, 16) / Math.pow(16, index - fractionStart);
      }

      if ('pP'.indexOf(input.charAt(index) || null) >= 0) {
        index++;
        if ('+-'.indexOf(input.charAt(index) || null) >= 0) binarySign = '+' === input.charAt(index++) ? 1 : -1;
        exponentStart = index;
        if (!isDecDigit(input.charCodeAt(index))) raise({}, errors.malformedNumber, input.slice(tokenStart, index));

        while (isDecDigit(input.charCodeAt(index))) {
          index++;
        }

        binaryExponent = input.slice(exponentStart, index);
        binaryExponent = Math.pow(2, binaryExponent * binarySign);
      }

      return (digit + fraction) * binaryExponent;
    }

    function readDecLiteral() {
      while (isDecDigit(input.charCodeAt(index))) {
        index++;
      }

      if ('.' === input.charAt(index)) {
        index++;

        while (isDecDigit(input.charCodeAt(index))) {
          index++;
        }
      }

      if ('eE'.indexOf(input.charAt(index) || null) >= 0) {
        index++;
        if ('+-'.indexOf(input.charAt(index) || null) >= 0) index++;
        if (!isDecDigit(input.charCodeAt(index))) raise({}, errors.malformedNumber, input.slice(tokenStart, index));

        while (isDecDigit(input.charCodeAt(index))) {
          index++;
        }
      }

      return parseFloat(input.slice(tokenStart, index));
    }

    function readEscapeSequence() {
      var sequenceStart = index;

      switch (input.charAt(index)) {
        case 'n':
          index++;
          return '\n';

        case 'r':
          index++;
          return '\r';

        case 't':
          index++;
          return '\t';

        case 'v':
          index++;
          return '\x0B';

        case 'b':
          index++;
          return '\b';

        case 'f':
          index++;
          return '\f';

        case 'z':
          index++;
          skipWhiteSpace();
          return '';

        case 'x':
          if (isHexDigit(input.charCodeAt(index + 1)) && isHexDigit(input.charCodeAt(index + 2))) {
            index += 3;
            return '\\' + input.slice(sequenceStart, index);
          }

          return '\\' + input.charAt(index++);

        default:
          if (isDecDigit(input.charCodeAt(index))) {
            while (isDecDigit(input.charCodeAt(++index))) {
              ;
            }

            return '\\' + input.slice(sequenceStart, index);
          }

          return input.charAt(index++);
      }
    }

    function scanComment() {
      tokenStart = index;
      index += 2; // --

      var character = input.charAt(index),
          content = '',
          isLong = false,
          commentStart = index,
          lineStartComment = lineStart,
          lineComment = line;

      if ('[' === character) {
        content = readLongString();
        if (false === content) content = character;else isLong = true;
      }

      if (!isLong) {
        while (index < length) {
          if (isLineTerminator(input.charCodeAt(index))) break;
          index++;
        }

        if (options.comments) content = input.slice(commentStart, index);
      }

      if (options.comments) {
        var node = ast.comment(content, input.slice(tokenStart, index));

        if (options.locations) {
          node.loc = {
            start: {
              line: lineComment,
              column: tokenStart - lineStartComment
            },
            end: {
              line: line,
              column: index - lineStart
            }
          };
        }

        if (options.ranges) {
          node.range = [tokenStart, index];
        }

        comments.push(node);
      }
    }

    function readLongString() {
      var level = 0,
          content = '',
          terminator = false,
          character,
          stringStart;
      index++; // [

      while ('=' === input.charAt(index + level)) {
        level++;
      }

      if ('[' !== input.charAt(index + level)) return false;
      index += level + 1;

      if (isLineTerminator(input.charCodeAt(index))) {
        line++;
        lineStart = index++;
      }

      stringStart = index;

      while (index < length) {
        character = input.charAt(index++);

        if (isLineTerminator(character.charCodeAt(0))) {
          line++;
          lineStart = index;
        }

        if (']' === character) {
          terminator = true;

          for (var i = 0; i < level; i++) {
            if ('=' !== input.charAt(index + i)) terminator = false;
          }

          if (']' !== input.charAt(index + level)) terminator = false;
        }

        if (terminator) break;
      }

      content += input.slice(stringStart, index - 1);
      index += level + 1;
      return content;
    }

    function next() {
      previousToken = token;
      token = lookahead;
      lookahead = lex();
    }

    function consume(value) {
      if (value === token.value) {
        next();
        return true;
      }

      return false;
    }

    function expect(value) {
      if (value === token.value) next();else raise(token, errors.expected, value, token.value);
    }

    function isWhiteSpace(charCode) {
      return 9 === charCode || 32 === charCode || 0xB === charCode || 0xC === charCode;
    }

    function isLineTerminator(charCode) {
      return 10 === charCode || 13 === charCode;
    }

    function isDecDigit(charCode) {
      return charCode >= 48 && charCode <= 57;
    }

    function isHexDigit(charCode) {
      return charCode >= 48 && charCode <= 57 || charCode >= 97 && charCode <= 102 || charCode >= 65 && charCode <= 70;
    }

    function isIdentifierStart(charCode) {
      return charCode >= 65 && charCode <= 90 || charCode >= 97 && charCode <= 122 || 95 === charCode;
    }

    function isIdentifierPart(charCode) {
      return charCode >= 65 && charCode <= 90 || charCode >= 97 && charCode <= 122 || 95 === charCode || charCode >= 48 && charCode <= 57;
    }

    function isKeyword(id) {
      switch (id.length) {
        case 2:
          return 'do' === id || 'if' === id || 'in' === id || 'or' === id;

        case 3:
          return 'and' === id || 'end' === id || 'for' === id || 'not' === id;

        case 4:
          return 'else' === id || 'goto' === id || 'then' === id;

        case 5:
          return 'break' === id || 'local' === id || 'until' === id || 'while' === id;

        case 6:
          return 'elseif' === id || 'repeat' === id || 'return' === id;

        case 8:
          return 'function' === id;
      }

      return false;
    }

    function isUnary(token) {
      if (Punctuator === token.type) return '#-~'.indexOf(token.value) >= 0;
      if (Keyword === token.type) return 'not' === token.value;
      return false;
    }

    function isCallExpression(expression) {
      switch (expression.type) {
        case 'CallExpression':
        case 'TableCallExpression':
        case 'StringCallExpression':
          return true;
      }

      return false;
    }

    function isBlockFollow(token) {
      if (EOF === token.type) return true;
      if (Keyword !== token.type) return false;

      switch (token.value) {
        case 'else':
        case 'elseif':
        case 'end':
        case 'until':
          return true;

        default:
          return false;
      }
    }

    var scopes, scopeDepth, globals;

    function createScope() {
      scopes.push(Array.apply(null, scopes[scopeDepth++]));
    }

    function exitScope() {
      scopes.pop();
      scopeDepth--;
    }

    function scopeIdentifierName(name) {
      if (-1 !== indexOf(scopes[scopeDepth], name)) return;
      scopes[scopeDepth].push(name);
    }

    function scopeIdentifier(node) {
      scopeIdentifierName(node.name);
      attachScope(node, true);
    }

    function attachScope(node, isLocal) {
      if (!isLocal && -1 === indexOfObject(globals, 'name', node.name)) globals.push(node);
      node.isLocal = isLocal;
    }

    function scopeHasName(name) {
      return -1 !== indexOf(scopes[scopeDepth], name);
    }

    var locations = [],
        trackLocations;

    function createLocationMarker() {
      return new Marker(token);
    }

    function Marker(token) {
      if (options.locations) {
        this.loc = {
          start: {
            line: token.line,
            column: token.range[0] - token.lineStart
          },
          end: {
            line: 0,
            column: 0
          }
        };
      }

      if (options.ranges) this.range = [token.range[0], 0];
    }

    Marker.prototype.complete = function () {
      if (options.locations) {
        this.loc.end.line = previousToken.line;
        this.loc.end.column = previousToken.range[1] - previousToken.lineStart;
      }

      if (options.ranges) {
        this.range[1] = previousToken.range[1];
      }
    };

    function markLocation() {
      if (trackLocations) locations.push(createLocationMarker());
    }

    function pushLocation(marker) {
      if (trackLocations) locations.push(marker);
    }

    function parseChunk() {
      next();
      markLocation();
      var body = parseBlock();
      if (EOF !== token.type) unexpected(token);
      if (trackLocations && !body.length) previousToken = token;
      return finishNode(ast.chunk(body));
    }

    function parseBlock(terminator) {
      var block = [],
          statement;
      if (options.scope) createScope();

      while (!isBlockFollow(token)) {
        if ('return' === token.value) {
          block.push(parseStatement());
          break;
        }

        statement = parseStatement();
        if (statement) block.push(statement);
      }

      if (options.scope) exitScope();
      return block;
    }

    function parseStatement() {
      markLocation();

      if (Keyword === token.type) {
        switch (token.value) {
          case 'local':
            next();
            return parseLocalStatement();

          case 'if':
            next();
            return parseIfStatement();

          case 'return':
            next();
            return parseReturnStatement();

          case 'function':
            next();
            var name = parseFunctionName();
            return parseFunctionDeclaration(name);

          case 'while':
            next();
            return parseWhileStatement();

          case 'for':
            next();
            return parseForStatement();

          case 'repeat':
            next();
            return parseRepeatStatement();

          case 'break':
            next();
            return parseBreakStatement();

          case 'do':
            next();
            return parseDoStatement();

          case 'goto':
            next();
            return parseGotoStatement();
        }
      }

      if (Punctuator === token.type) {
        if (consume('::')) return parseLabelStatement();
      }

      if (trackLocations) locations.pop();
      if (consume(';')) return;
      return parseAssignmentOrCallStatement();
    }

    function parseLabelStatement() {
      var name = token.value,
          label = parseIdentifier();

      if (options.scope) {
        scopeIdentifierName('::' + name + '::');
        attachScope(label, true);
      }

      expect('::');
      return finishNode(ast.labelStatement(label));
    }

    function parseBreakStatement() {
      return finishNode(ast.breakStatement());
    }

    function parseGotoStatement() {
      var name = token.value,
          label = parseIdentifier();
      if (options.scope) label.isLabel = scopeHasName('::' + name + '::');
      return finishNode(ast.gotoStatement(label));
    }

    function parseDoStatement() {
      var body = parseBlock();
      expect('end');
      return finishNode(ast.doStatement(body));
    }

    function parseWhileStatement() {
      var condition = parseExpectedExpression();
      expect('do');
      var body = parseBlock();
      expect('end');
      return finishNode(ast.whileStatement(condition, body));
    }

    function parseRepeatStatement() {
      var body = parseBlock();
      expect('until');
      var condition = parseExpectedExpression();
      return finishNode(ast.repeatStatement(condition, body));
    }

    function parseReturnStatement() {
      var expressions = [];

      if ('end' !== token.value) {
        var expression = parseExpression();
        if (null != expression) expressions.push(expression);

        while (consume(',')) {
          expression = parseExpectedExpression();
          expressions.push(expression);
        }

        consume(';'); // grammar tells us ; is optional here.
      }

      return finishNode(ast.returnStatement(expressions));
    }

    function parseIfStatement() {
      var clauses = [],
          condition,
          body,
          marker;

      if (trackLocations) {
        marker = locations[locations.length - 1];
        locations.push(marker);
      }

      condition = parseExpectedExpression();
      expect('then');
      body = parseBlock();
      clauses.push(finishNode(ast.ifClause(condition, body)));
      if (trackLocations) marker = createLocationMarker();

      while (consume('elseif')) {
        pushLocation(marker);
        condition = parseExpectedExpression();
        expect('then');
        body = parseBlock();
        clauses.push(finishNode(ast.elseifClause(condition, body)));
        if (trackLocations) marker = createLocationMarker();
      }

      if (consume('else')) {
        if (trackLocations) {
          marker = new Marker(previousToken);
          locations.push(marker);
        }

        body = parseBlock();
        clauses.push(finishNode(ast.elseClause(body)));
      }

      expect('end');
      return finishNode(ast.ifStatement(clauses));
    }

    function parseForStatement() {
      var variable = parseIdentifier(),
          body;
      if (options.scope) scopeIdentifier(variable);

      if (consume('=')) {
        var start = parseExpectedExpression();
        expect(',');
        var end = parseExpectedExpression();
        var step = consume(',') ? parseExpectedExpression() : null;
        expect('do');
        body = parseBlock();
        expect('end');
        return finishNode(ast.forNumericStatement(variable, start, end, step, body));
      } else {
        var variables = [variable];

        while (consume(',')) {
          variable = parseIdentifier();
          if (options.scope) scopeIdentifier(variable);
          variables.push(variable);
        }

        expect('in');
        var iterators = [];

        do {
          var expression = parseExpectedExpression();
          iterators.push(expression);
        } while (consume(','));

        expect('do');
        body = parseBlock();
        expect('end');
        return finishNode(ast.forGenericStatement(variables, iterators, body));
      }
    }

    function parseLocalStatement() {
      var name;

      if (Identifier === token.type) {
        var variables = [],
            init = [];

        do {
          name = parseIdentifier();
          variables.push(name);
        } while (consume(','));

        if (consume('=')) {
          do {
            var expression = parseExpectedExpression();
            init.push(expression);
          } while (consume(','));
        }

        if (options.scope) {
          for (var i = 0, l = variables.length; i < l; i++) {
            scopeIdentifier(variables[i]);
          }
        }

        return finishNode(ast.localStatement(variables, init));
      }

      if (consume('function')) {
        name = parseIdentifier();
        if (options.scope) scopeIdentifier(name);
        return parseFunctionDeclaration(name, true);
      } else {
        raiseUnexpectedToken('<name>', token);
      }
    }

    function parseAssignmentOrCallStatement() {
      var previous = token,
          expression,
          marker;
      if (trackLocations) marker = createLocationMarker();
      expression = parsePrefixExpression();
      if (null == expression) return unexpected(token);

      if (',='.indexOf(token.value) >= 0) {
        var variables = [expression],
            init = [],
            exp;

        while (consume(',')) {
          exp = parsePrefixExpression();
          if (null == exp) raiseUnexpectedToken('<expression>', token);
          variables.push(exp);
        }

        expect('=');

        do {
          exp = parseExpectedExpression();
          init.push(exp);
        } while (consume(','));

        pushLocation(marker);
        return finishNode(ast.assignmentStatement(variables, init));
      }

      if (isCallExpression(expression)) {
        pushLocation(marker);
        return finishNode(ast.callStatement(expression));
      }

      return unexpected(previous);
    }

    function parseIdentifier() {
      markLocation();
      var identifier = token.value;
      if (Identifier !== token.type) raiseUnexpectedToken('<name>', token);
      next();
      return finishNode(ast.identifier(identifier));
    }

    function parseFunctionDeclaration(name, isLocal) {
      var parameters = [];
      expect('(');

      if (!consume(')')) {
        while (true) {
          if (Identifier === token.type) {
            var parameter = parseIdentifier();
            if (options.scope) scopeIdentifier(parameter);
            parameters.push(parameter);
            if (consume(',')) continue;else if (consume(')')) break;
          } else if (VarargLiteral === token.type) {
            parameters.push(parsePrimaryExpression());
            expect(')');
            break;
          } else {
            raiseUnexpectedToken('<name> or \'...\'', token);
          }
        }
      }

      var body = parseBlock();
      expect('end');
      isLocal = isLocal || false;
      return finishNode(ast.functionStatement(name, parameters, isLocal, body));
    }

    function parseFunctionName() {
      var base, name, marker;
      if (trackLocations) marker = createLocationMarker();
      base = parseIdentifier();
      if (options.scope) attachScope(base, false);

      while (consume('.')) {
        pushLocation(marker);
        name = parseIdentifier();
        if (options.scope) attachScope(name, false);
        base = finishNode(ast.memberExpression(base, '.', name));
      }

      if (consume(':')) {
        pushLocation(marker);
        name = parseIdentifier();
        if (options.scope) attachScope(name, false);
        base = finishNode(ast.memberExpression(base, ':', name));
      }

      return base;
    }

    function parseTableConstructor() {
      var fields = [],
          key,
          value;

      while (true) {
        markLocation();

        if (Punctuator === token.type && consume('[')) {
          key = parseExpectedExpression();
          expect(']');
          expect('=');
          value = parseExpectedExpression();
          fields.push(finishNode(ast.tableKey(key, value)));
        } else if (Identifier === token.type) {
          key = parseExpectedExpression();

          if (consume('=')) {
            value = parseExpectedExpression();
            fields.push(finishNode(ast.tableKeyString(key, value)));
          } else {
            fields.push(finishNode(ast.tableValue(key)));
          }
        } else {
          if (null == (value = parseExpression())) {
            locations.pop();
            break;
          }

          fields.push(finishNode(ast.tableValue(value)));
        }

        if (',;'.indexOf(token.value) >= 0) {
          next();
          continue;
        }

        if ('}' === token.value) break;
      }

      expect('}');
      return finishNode(ast.tableConstructorExpression(fields));
    }

    function parseExpression() {
      var expression = parseSubExpression(0);
      return expression;
    }

    function parseExpectedExpression() {
      var expression = parseExpression();
      if (null == expression) raiseUnexpectedToken('<expression>', token);else return expression;
    }

    function binaryPrecedence(operator) {
      var charCode = operator.charCodeAt(0),
          length = operator.length;

      if (1 === length) {
        switch (charCode) {
          case 94:
            return 10;
          // ^

          case 42:
          case 47:
          case 37:
            return 7;
          // * / %

          case 43:
          case 45:
            return 6;
          // + -

          case 60:
          case 62:
            return 3;
          // < >

          case 38:
          case 124:
            return 7;
          // & |
        }
      } else if (2 === length) {
        switch (charCode) {
          case 46:
            return 5;
          // ..

          case 60:
          case 62:
          case 61:
          case 126:
            return 3;
          // <= >= == ~=

          case 111:
            return 1;
          // or
        }
      } else if (97 === charCode && 'and' === operator) return 2;

      return 0;
    }

    function parseSubExpression(minPrecedence) {
      var operator = token.value,
          expression,
          marker;
      if (trackLocations) marker = createLocationMarker();

      if (isUnary(token)) {
        markLocation();
        next();
        var argument = parseSubExpression(8);
        if (argument == null) raiseUnexpectedToken('<expression>', token);
        expression = finishNode(ast.unaryExpression(operator, argument));
      }

      if (null == expression) {
        expression = parsePrimaryExpression();

        if (null == expression) {
          expression = parsePrefixExpression();
        }
      }

      if (null == expression) return null;
      var precedence;

      while (true) {
        operator = token.value;
        precedence = Punctuator === token.type || Keyword === token.type ? binaryPrecedence(operator) : 0;
        if (precedence === 0 || precedence <= minPrecedence) break;
        if ('^' === operator || '..' === operator) precedence--;
        next();
        var right = parseSubExpression(precedence);
        if (null == right) raiseUnexpectedToken('<expression>', token);
        if (trackLocations) locations.push(marker);
        expression = finishNode(ast.binaryExpression(operator, expression, right));
      }

      return expression;
    }

    function parsePrefixExpression() {
      var base, name, marker, isLocal;
      if (trackLocations) marker = createLocationMarker();

      if (Identifier === token.type) {
        name = token.value;
        base = parseIdentifier();
        if (options.scope) attachScope(base, isLocal = scopeHasName(name));
      } else if (consume('(')) {
        base = parseExpectedExpression();
        expect(')');
        if (options.scope) isLocal = base.isLocal;
      } else {
        return null;
      }

      var expression, identifier;

      while (true) {
        if (Punctuator === token.type) {
          switch (token.value) {
            case '[':
              pushLocation(marker);
              next();
              expression = parseExpectedExpression();
              base = finishNode(ast.indexExpression(base, expression));
              expect(']');
              break;

            case '.':
              pushLocation(marker);
              next();
              identifier = parseIdentifier();
              if (options.scope) attachScope(identifier, isLocal);
              base = finishNode(ast.memberExpression(base, '.', identifier));
              break;

            case ':':
              pushLocation(marker);
              next();
              identifier = parseIdentifier();
              if (options.scope) attachScope(identifier, isLocal);
              base = finishNode(ast.memberExpression(base, ':', identifier));
              pushLocation(marker);
              base = parseCallExpression(base);
              break;

            case '(':
            case '{':
              // args
              pushLocation(marker);
              base = parseCallExpression(base);
              break;

            default:
              return base;
          }
        } else if (StringLiteral === token.type) {
          pushLocation(marker);
          base = parseCallExpression(base);
        } else {
          break;
        }
      }

      return base;
    }

    function parseCallExpression(base) {
      if (Punctuator === token.type) {
        switch (token.value) {
          case '(':
            next();
            var expressions = [];
            var expression = parseExpression();
            if (null != expression) expressions.push(expression);

            while (consume(',')) {
              expression = parseExpectedExpression();
              expressions.push(expression);
            }

            expect(')');
            return finishNode(ast.callExpression(base, expressions));

          case '{':
            markLocation();
            next();
            var table = parseTableConstructor();
            return finishNode(ast.tableCallExpression(base, table));
        }
      } else if (StringLiteral === token.type) {
        return finishNode(ast.stringCallExpression(base, parsePrimaryExpression()));
      }

      raiseUnexpectedToken('function arguments', token);
    }

    function parsePrimaryExpression() {
      var literals = StringLiteral | NumericLiteral | BooleanLiteral | NilLiteral | VarargLiteral,
          value = token.value,
          type = token.type,
          marker;
      if (trackLocations) marker = createLocationMarker();

      if (type & literals) {
        pushLocation(marker);
        var raw = input.slice(token.range[0], token.range[1]);
        next();
        return finishNode(ast.literal(type, value, raw));
      } else if (Keyword === type && 'function' === value) {
        pushLocation(marker);
        next();
        return parseFunctionDeclaration(null);
      } else if (consume('{')) {
        pushLocation(marker);
        return parseTableConstructor();
      }
    }

    exports.parse = parse;

    function parse(_input, _options) {
      if ('undefined' === typeof _options && 'object' === typeof _input) {
        _options = _input;
        _input = undefined;
      }

      if (!_options) _options = {};
      input = _input || '';
      options = extend(defaultOptions, _options);
      index = 0;
      line = 1;
      lineStart = 0;
      length = input.length;
      scopes = [[]];
      scopeDepth = 0;
      globals = [];
      locations = [];
      if (options.comments) comments = [];
      if (!options.wait) return end();
      return exports;
    }

    exports.write = write;

    function write(_input) {
      input += String(_input);
      length = input.length;
      return exports;
    }

    exports.end = end;

    function end(_input) {
      if ('undefined' !== typeof _input) write(_input);
      length = input.length;
      trackLocations = options.locations || options.ranges;
      lookahead = lex();
      var chunk = parseChunk();
      if (options.comments) chunk.comments = comments;
      if (options.scope) chunk.globals = globals;
      if (locations.length > 0) throw new Error('Location tracking failed. This is most likely a bug in luaparse');
      return chunk;
    }
  });
});
ace.define("ace/mode/lua_worker", [], function (require, exports, module) {
  "use strict";

  var oop = require("../lib/oop");

  var Mirror = require("../worker/mirror").Mirror;

  var luaparse = require("../mode/lua/luaparse");

  var Worker = exports.Worker = function (sender) {
    Mirror.call(this, sender);
    this.setTimeout(500);
  };

  oop.inherits(Worker, Mirror);
  (function () {
    this.onUpdate = function () {
      var value = this.doc.getValue();
      var errors = [];

      try {
        luaparse.parse(value);
      } catch (e) {
        if (e instanceof SyntaxError) {
          errors.push({
            row: e.line - 1,
            column: e.column,
            text: e.message,
            type: "error"
          });
        }
      }

      this.sender.emit("annotate", errors);
    };
  }).call(Worker.prototype);
});
ace.define("ace/lib/es5-shim", [], function (require, exports, module) {
  function Empty() {}

  if (!Function.prototype.bind) {
    Function.prototype.bind = function bind(that) {
      // .length is 1
      var target = this;

      if (typeof target != "function") {
        throw new TypeError("Function.prototype.bind called on incompatible " + target);
      }

      var args = slice.call(arguments, 1); // for normal call

      var bound = function bound() {
        if (this instanceof bound) {
          var result = target.apply(this, args.concat(slice.call(arguments)));

          if (Object(result) === result) {
            return result;
          }

          return this;
        } else {
          return target.apply(that, args.concat(slice.call(arguments)));
        }
      };

      if (target.prototype) {
        Empty.prototype = target.prototype;
        bound.prototype = new Empty();
        Empty.prototype = null;
      }

      return bound;
    };
  }

  var call = Function.prototype.call;
  var prototypeOfArray = Array.prototype;
  var prototypeOfObject = Object.prototype;
  var slice = prototypeOfArray.slice;

  var _toString = call.bind(prototypeOfObject.toString);

  var owns = call.bind(prototypeOfObject.hasOwnProperty);
  var defineGetter;
  var defineSetter;
  var lookupGetter;
  var lookupSetter;
  var supportsAccessors;

  if (supportsAccessors = owns(prototypeOfObject, "__defineGetter__")) {
    defineGetter = call.bind(prototypeOfObject.__defineGetter__);
    defineSetter = call.bind(prototypeOfObject.__defineSetter__);
    lookupGetter = call.bind(prototypeOfObject.__lookupGetter__);
    lookupSetter = call.bind(prototypeOfObject.__lookupSetter__);
  }

  if ([1, 2].splice(0).length != 2) {
    if (function () {
      // test IE < 9 to splice bug - see issue #138
      function makeArray(l) {
        var a = new Array(l + 2);
        a[0] = a[1] = 0;
        return a;
      }

      var array = [],
          lengthBefore;
      array.splice.apply(array, makeArray(20));
      array.splice.apply(array, makeArray(26));
      lengthBefore = array.length; //46

      array.splice(5, 0, "XXX"); // add one element

      lengthBefore + 1 == array.length;

      if (lengthBefore + 1 == array.length) {
        return true; // has right splice implementation without bugs
      }
    }()) {
      //IE 6/7
      var array_splice = Array.prototype.splice;

      Array.prototype.splice = function (start, deleteCount) {
        if (!arguments.length) {
          return [];
        } else {
          return array_splice.apply(this, [start === void 0 ? 0 : start, deleteCount === void 0 ? this.length - start : deleteCount].concat(slice.call(arguments, 2)));
        }
      };
    } else {
      //IE8
      Array.prototype.splice = function (pos, removeCount) {
        var length = this.length;

        if (pos > 0) {
          if (pos > length) pos = length;
        } else if (pos == void 0) {
          pos = 0;
        } else if (pos < 0) {
          pos = Math.max(length + pos, 0);
        }

        if (!(pos + removeCount < length)) removeCount = length - pos;
        var removed = this.slice(pos, pos + removeCount);
        var insert = slice.call(arguments, 2);
        var add = insert.length;

        if (pos === length) {
          if (add) {
            this.push.apply(this, insert);
          }
        } else {
          var remove = Math.min(removeCount, length - pos);
          var tailOldPos = pos + remove;
          var tailNewPos = tailOldPos + add - remove;
          var tailCount = length - tailOldPos;
          var lengthAfterRemove = length - remove;

          if (tailNewPos < tailOldPos) {
            // case A
            for (var i = 0; i < tailCount; ++i) {
              this[tailNewPos + i] = this[tailOldPos + i];
            }
          } else if (tailNewPos > tailOldPos) {
            // case B
            for (i = tailCount; i--;) {
              this[tailNewPos + i] = this[tailOldPos + i];
            }
          } // else, add == remove (nothing to do)


          if (add && pos === lengthAfterRemove) {
            this.length = lengthAfterRemove; // truncate array

            this.push.apply(this, insert);
          } else {
            this.length = lengthAfterRemove + add; // reserves space

            for (i = 0; i < add; ++i) {
              this[pos + i] = insert[i];
            }
          }
        }

        return removed;
      };
    }
  }

  if (!Array.isArray) {
    Array.isArray = function isArray(obj) {
      return _toString(obj) == "[object Array]";
    };
  }

  var boxedString = Object("a"),
      splitString = boxedString[0] != "a" || !(0 in boxedString);

  if (!Array.prototype.forEach) {
    Array.prototype.forEach = function forEach(fun
    /*, thisp*/
    ) {
      var object = toObject(this),
          self = splitString && _toString(this) == "[object String]" ? this.split("") : object,
          thisp = arguments[1],
          i = -1,
          length = self.length >>> 0;

      if (_toString(fun) != "[object Function]") {
        throw new TypeError(); // TODO message
      }

      while (++i < length) {
        if (i in self) {
          fun.call(thisp, self[i], i, object);
        }
      }
    };
  }

  if (!Array.prototype.map) {
    Array.prototype.map = function map(fun
    /*, thisp*/
    ) {
      var object = toObject(this),
          self = splitString && _toString(this) == "[object String]" ? this.split("") : object,
          length = self.length >>> 0,
          result = Array(length),
          thisp = arguments[1];

      if (_toString(fun) != "[object Function]") {
        throw new TypeError(fun + " is not a function");
      }

      for (var i = 0; i < length; i++) {
        if (i in self) result[i] = fun.call(thisp, self[i], i, object);
      }

      return result;
    };
  }

  if (!Array.prototype.filter) {
    Array.prototype.filter = function filter(fun
    /*, thisp */
    ) {
      var object = toObject(this),
          self = splitString && _toString(this) == "[object String]" ? this.split("") : object,
          length = self.length >>> 0,
          result = [],
          value,
          thisp = arguments[1];

      if (_toString(fun) != "[object Function]") {
        throw new TypeError(fun + " is not a function");
      }

      for (var i = 0; i < length; i++) {
        if (i in self) {
          value = self[i];

          if (fun.call(thisp, value, i, object)) {
            result.push(value);
          }
        }
      }

      return result;
    };
  }

  if (!Array.prototype.every) {
    Array.prototype.every = function every(fun
    /*, thisp */
    ) {
      var object = toObject(this),
          self = splitString && _toString(this) == "[object String]" ? this.split("") : object,
          length = self.length >>> 0,
          thisp = arguments[1];

      if (_toString(fun) != "[object Function]") {
        throw new TypeError(fun + " is not a function");
      }

      for (var i = 0; i < length; i++) {
        if (i in self && !fun.call(thisp, self[i], i, object)) {
          return false;
        }
      }

      return true;
    };
  }

  if (!Array.prototype.some) {
    Array.prototype.some = function some(fun
    /*, thisp */
    ) {
      var object = toObject(this),
          self = splitString && _toString(this) == "[object String]" ? this.split("") : object,
          length = self.length >>> 0,
          thisp = arguments[1];

      if (_toString(fun) != "[object Function]") {
        throw new TypeError(fun + " is not a function");
      }

      for (var i = 0; i < length; i++) {
        if (i in self && fun.call(thisp, self[i], i, object)) {
          return true;
        }
      }

      return false;
    };
  }

  if (!Array.prototype.reduce) {
    Array.prototype.reduce = function reduce(fun
    /*, initial*/
    ) {
      var object = toObject(this),
          self = splitString && _toString(this) == "[object String]" ? this.split("") : object,
          length = self.length >>> 0;

      if (_toString(fun) != "[object Function]") {
        throw new TypeError(fun + " is not a function");
      }

      if (!length && arguments.length == 1) {
        throw new TypeError("reduce of empty array with no initial value");
      }

      var i = 0;
      var result;

      if (arguments.length >= 2) {
        result = arguments[1];
      } else {
        do {
          if (i in self) {
            result = self[i++];
            break;
          }

          if (++i >= length) {
            throw new TypeError("reduce of empty array with no initial value");
          }
        } while (true);
      }

      for (; i < length; i++) {
        if (i in self) {
          result = fun.call(void 0, result, self[i], i, object);
        }
      }

      return result;
    };
  }

  if (!Array.prototype.reduceRight) {
    Array.prototype.reduceRight = function reduceRight(fun
    /*, initial*/
    ) {
      var object = toObject(this),
          self = splitString && _toString(this) == "[object String]" ? this.split("") : object,
          length = self.length >>> 0;

      if (_toString(fun) != "[object Function]") {
        throw new TypeError(fun + " is not a function");
      }

      if (!length && arguments.length == 1) {
        throw new TypeError("reduceRight of empty array with no initial value");
      }

      var result,
          i = length - 1;

      if (arguments.length >= 2) {
        result = arguments[1];
      } else {
        do {
          if (i in self) {
            result = self[i--];
            break;
          }

          if (--i < 0) {
            throw new TypeError("reduceRight of empty array with no initial value");
          }
        } while (true);
      }

      do {
        if (i in this) {
          result = fun.call(void 0, result, self[i], i, object);
        }
      } while (i--);

      return result;
    };
  }

  if (!Array.prototype.indexOf || [0, 1].indexOf(1, 2) != -1) {
    Array.prototype.indexOf = function indexOf(sought
    /*, fromIndex */
    ) {
      var self = splitString && _toString(this) == "[object String]" ? this.split("") : toObject(this),
          length = self.length >>> 0;

      if (!length) {
        return -1;
      }

      var i = 0;

      if (arguments.length > 1) {
        i = toInteger(arguments[1]);
      }

      i = i >= 0 ? i : Math.max(0, length + i);

      for (; i < length; i++) {
        if (i in self && self[i] === sought) {
          return i;
        }
      }

      return -1;
    };
  }

  if (!Array.prototype.lastIndexOf || [0, 1].lastIndexOf(0, -3) != -1) {
    Array.prototype.lastIndexOf = function lastIndexOf(sought
    /*, fromIndex */
    ) {
      var self = splitString && _toString(this) == "[object String]" ? this.split("") : toObject(this),
          length = self.length >>> 0;

      if (!length) {
        return -1;
      }

      var i = length - 1;

      if (arguments.length > 1) {
        i = Math.min(i, toInteger(arguments[1]));
      }

      i = i >= 0 ? i : length - Math.abs(i);

      for (; i >= 0; i--) {
        if (i in self && sought === self[i]) {
          return i;
        }
      }

      return -1;
    };
  }

  if (!Object.getPrototypeOf) {
    Object.getPrototypeOf = function getPrototypeOf(object) {
      return object.__proto__ || (object.constructor ? object.constructor.prototype : prototypeOfObject);
    };
  }

  if (!Object.getOwnPropertyDescriptor) {
    var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " + "non-object: ";

    Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) {
      if (typeof object != "object" && typeof object != "function" || object === null) throw new TypeError(ERR_NON_OBJECT + object);
      if (!owns(object, property)) return;
      var descriptor, getter, setter;
      descriptor = {
        enumerable: true,
        configurable: true
      };

      if (supportsAccessors) {
        var prototype = object.__proto__;
        object.__proto__ = prototypeOfObject;
        var getter = lookupGetter(object, property);
        var setter = lookupSetter(object, property);
        object.__proto__ = prototype;

        if (getter || setter) {
          if (getter) descriptor.get = getter;
          if (setter) descriptor.set = setter;
          return descriptor;
        }
      }

      descriptor.value = object[property];
      return descriptor;
    };
  }

  if (!Object.getOwnPropertyNames) {
    Object.getOwnPropertyNames = function getOwnPropertyNames(object) {
      return Object.keys(object);
    };
  }

  if (!Object.create) {
    var createEmpty;

    if (Object.prototype.__proto__ === null) {
      createEmpty = function createEmpty() {
        return {
          "__proto__": null
        };
      };
    } else {
      createEmpty = function createEmpty() {
        var empty = {};

        for (var i in empty) {
          empty[i] = null;
        }

        empty.constructor = empty.hasOwnProperty = empty.propertyIsEnumerable = empty.isPrototypeOf = empty.toLocaleString = empty.toString = empty.valueOf = empty.__proto__ = null;
        return empty;
      };
    }

    Object.create = function create(prototype, properties) {
      var object;

      if (prototype === null) {
        object = createEmpty();
      } else {
        if (typeof prototype != "object") throw new TypeError("typeof prototype[" + typeof prototype + "] != 'object'");

        var Type = function Type() {};

        Type.prototype = prototype;
        object = new Type();
        object.__proto__ = prototype;
      }

      if (properties !== void 0) Object.defineProperties(object, properties);
      return object;
    };
  }

  function doesDefinePropertyWork(object) {
    try {
      Object.defineProperty(object, "sentinel", {});
      return "sentinel" in object;
    } catch (exception) {}
  }

  if (Object.defineProperty) {
    var definePropertyWorksOnObject = doesDefinePropertyWork({});
    var definePropertyWorksOnDom = typeof document == "undefined" || doesDefinePropertyWork(document.createElement("div"));

    if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) {
      var definePropertyFallback = Object.defineProperty;
    }
  }

  if (!Object.defineProperty || definePropertyFallback) {
    var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: ";
    var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: ";
    var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " + "on this javascript engine";

    Object.defineProperty = function defineProperty(object, property, descriptor) {
      if (typeof object != "object" && typeof object != "function" || object === null) throw new TypeError(ERR_NON_OBJECT_TARGET + object);
      if (typeof descriptor != "object" && typeof descriptor != "function" || descriptor === null) throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor);

      if (definePropertyFallback) {
        try {
          return definePropertyFallback.call(Object, object, property, descriptor);
        } catch (exception) {}
      }

      if (owns(descriptor, "value")) {
        if (supportsAccessors && (lookupGetter(object, property) || lookupSetter(object, property))) {
          var prototype = object.__proto__;
          object.__proto__ = prototypeOfObject;
          delete object[property];
          object[property] = descriptor.value;
          object.__proto__ = prototype;
        } else {
          object[property] = descriptor.value;
        }
      } else {
        if (!supportsAccessors) throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
        if (owns(descriptor, "get")) defineGetter(object, property, descriptor.get);
        if (owns(descriptor, "set")) defineSetter(object, property, descriptor.set);
      }

      return object;
    };
  }

  if (!Object.defineProperties) {
    Object.defineProperties = function defineProperties(object, properties) {
      for (var property in properties) {
        if (owns(properties, property)) Object.defineProperty(object, property, properties[property]);
      }

      return object;
    };
  }

  if (!Object.seal) {
    Object.seal = function seal(object) {
      return object;
    };
  }

  if (!Object.freeze) {
    Object.freeze = function freeze(object) {
      return object;
    };
  }

  try {
    Object.freeze(function () {});
  } catch (exception) {
    Object.freeze = function freeze(freezeObject) {
      return function freeze(object) {
        if (typeof object == "function") {
          return object;
        } else {
          return freezeObject(object);
        }
      };
    }(Object.freeze);
  }

  if (!Object.preventExtensions) {
    Object.preventExtensions = function preventExtensions(object) {
      return object;
    };
  }

  if (!Object.isSealed) {
    Object.isSealed = function isSealed(object) {
      return false;
    };
  }

  if (!Object.isFrozen) {
    Object.isFrozen = function isFrozen(object) {
      return false;
    };
  }

  if (!Object.isExtensible) {
    Object.isExtensible = function isExtensible(object) {
      if (Object(object) === object) {
        throw new TypeError(); // TODO message
      }

      var name = '';

      while (owns(object, name)) {
        name += '?';
      }

      object[name] = true;
      var returnValue = owns(object, name);
      delete object[name];
      return returnValue;
    };
  }

  if (!Object.keys) {
    var hasDontEnumBug = true,
        dontEnums = ["toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "constructor"],
        dontEnumsLength = dontEnums.length;

    for (var key in {
      "toString": null
    }) {
      hasDontEnumBug = false;
    }

    Object.keys = function keys(object) {
      if (typeof object != "object" && typeof object != "function" || object === null) {
        throw new TypeError("Object.keys called on a non-object");
      }

      var keys = [];

      for (var name in object) {
        if (owns(object, name)) {
          keys.push(name);
        }
      }

      if (hasDontEnumBug) {
        for (var i = 0, ii = dontEnumsLength; i < ii; i++) {
          var dontEnum = dontEnums[i];

          if (owns(object, dontEnum)) {
            keys.push(dontEnum);
          }
        }
      }

      return keys;
    };
  }

  if (!Date.now) {
    Date.now = function now() {
      return new Date().getTime();
    };
  }

  var ws = "\t\n\x0B\f\r \xA0\u1680\u2000\u2001\u2002\u2003" + "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" + "\u2029\uFEFF";

  if (!String.prototype.trim) {
    ws = "[" + ws + "]";
    var trimBeginRegexp = new RegExp("^" + ws + ws + "*"),
        trimEndRegexp = new RegExp(ws + ws + "*$");

    String.prototype.trim = function trim() {
      return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, "");
    };
  }

  function toInteger(n) {
    n = +n;

    if (n !== n) {
      // isNaN
      n = 0;
    } else if (n !== 0 && n !== 1 / 0 && n !== -(1 / 0)) {
      n = (n > 0 || -1) * Math.floor(Math.abs(n));
    }

    return n;
  }

  function isPrimitive(input) {
    var type = typeof input;
    return input === null || type === "undefined" || type === "boolean" || type === "number" || type === "string";
  }

  function toPrimitive(input) {
    var val, valueOf, toString;

    if (isPrimitive(input)) {
      return input;
    }

    valueOf = input.valueOf;

    if (typeof valueOf === "function") {
      val = valueOf.call(input);

      if (isPrimitive(val)) {
        return val;
      }
    }

    toString = input.toString;

    if (typeof toString === "function") {
      val = toString.call(input);

      if (isPrimitive(val)) {
        return val;
      }
    }

    throw new TypeError();
  }

  var toObject = function toObject(o) {
    if (o == null) {
      // this matches both null and undefined
      throw new TypeError("can't convert " + o + " to object");
    }

    return Object(o);
  };
});