"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 (childId) {
            return window.require(id, childId);
        };

        window.require.modules[id] = {
            exports: {},
            factory: function () {
                var module = this;
                var returnExports = factory.apply(this, deps.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 () {
        };

        (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);

define("ace/lib/oop", ["require", "exports", "module"], 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);
    };

});

define("ace/range", ["require", "exports", "module"], function (require, exports, module) {
    "use strict";
    var comparePoints = function (p1, p2) {
        return p1.row - p2.row || p1.column - p2.column;
    };
    var Range = function (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;
});

define("ace/apply_delta", ["require", "exports", "module"], 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;
        }
    };
});

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

    var EventEmitter = {};
    var stopPropagation = function () {
        this.propagationStopped = true;
    };
    var preventDefault = function () {
        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;
        callback && this.addEventListener(eventName, function newCallback() {
            _self.removeEventListener(eventName, newCallback);
            callback.apply(null, arguments);
        });
    };


    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) {
            var old = handlers[eventName];
            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 (this._eventRegistry) this._eventRegistry[eventName] = [];
    };

    exports.EventEmitter = EventEmitter;

});

define("ace/anchor", ["require", "exports", "module", "ace/lib/oop", "ace/lib/event_emitter"], 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.removeEventListener("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);

});

define("ace/document", ["require", "exports", "module", "ace/lib/oop", "ace/apply_delta", "ace/lib/event_emitter", "ace/range", "ace/anchor"], 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 (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);
            applyDelta(this.$lines, delta, doNotValidate);
            this._signal("change", delta);
        };

        this.$splitAndapplyLargeDelta = function (delta, MAX) {
            var lines = delta.lines;
            var l = lines.length;
            var row = delta.start.row;
            var column = delta.start.column;
            var from = 0, to = 0;
            do {
                from = to;
                to += MAX - 1;
                var chunk = lines.slice(from, to);
                if (to > l) {
                    delta.lines = chunk;
                    delta.start.row = row + from;
                    delta.start.column = column;
                    break;
                }
                chunk.push("");
                this.applyDelta({
                    start: this.pos(row + from, column),
                    end: this.pos(row + to, column = 0),
                    action: delta.action,
                    lines: chunk
                }, true);
            } while (true);
        };
        this.revertDelta = function (delta) {
            this.applyDelta({
                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: lines[l - 1].length};
        };
        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;
});

define("ace/lib/lang", ["require", "exports", "module"], 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 () {
            timer = null;
            fcn();
        };

        var deferred = function (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 () {
            timer = null;
            fcn();
        };

        var _self = function (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;
    };
});

define("ace/worker/mirror", ["require", "exports", "module", "ace/range", "ace/document", "ace/lib/lang"], 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);

});

define("ace/mode/javascript/jshint", ["require", "exports", "module"], function (require, exports, module) {
    module.exports = (function outer(modules, cache, entry) {
        var previousRequire = typeof require == "function" && require;

        function newRequire(name, jumped) {
            if (!cache[name]) {
                if (!modules[name]) {
                    var currentRequire = typeof require == "function" && require;
                    if (!jumped && currentRequire) return currentRequire(name, true);
                    if (previousRequire) return previousRequire(name, true);
                    var err = new Error('Cannot find module \'' + name + '\'');
                    err.code = 'MODULE_NOT_FOUND';
                    throw err;
                }
                var m = cache[name] = {exports: {}};
                modules[name][0].call(m.exports, function (x) {
                    var id = modules[name][1][x];
                    return newRequire(id ? id : x);
                }, m, m.exports, outer, modules, cache, entry);
            }
            return cache[name].exports;
        }

        for (var i = 0; i < entry.length; i++) newRequire(entry[i]);
        return newRequire(entry[0]);
    })
    ({
        "/node_modules/browserify/node_modules/events/events.js": [function (_dereq_, module, exports) {

            function EventEmitter() {
                this._events = this._events || {};
                this._maxListeners = this._maxListeners || undefined;
            }

            module.exports = EventEmitter;
            EventEmitter.EventEmitter = EventEmitter;

            EventEmitter.prototype._events = undefined;
            EventEmitter.prototype._maxListeners = undefined;
            EventEmitter.defaultMaxListeners = 10;
            EventEmitter.prototype.setMaxListeners = function (n) {
                if (!isNumber(n) || n < 0 || isNaN(n))
                    throw TypeError('n must be a positive number');
                this._maxListeners = n;
                return this;
            };

            EventEmitter.prototype.emit = function (type) {
                var er, handler, len, args, i, listeners;

                if (!this._events)
                    this._events = {};
                if (type === 'error') {
                    if (!this._events.error ||
                        (isObject(this._events.error) && !this._events.error.length)) {
                        er = arguments[1];
                        if (er instanceof Error) {
                            throw er; // Unhandled 'error' event
                        }
                        throw TypeError('Uncaught, unspecified "error" event.');
                    }
                }

                handler = this._events[type];

                if (isUndefined(handler))
                    return false;

                if (isFunction(handler)) {
                    switch (arguments.length) {
                        case 1:
                            handler.call(this);
                            break;
                        case 2:
                            handler.call(this, arguments[1]);
                            break;
                        case 3:
                            handler.call(this, arguments[1], arguments[2]);
                            break;
                        default:
                            len = arguments.length;
                            args = new Array(len - 1);
                            for (i = 1; i < len; i++)
                                args[i - 1] = arguments[i];
                            handler.apply(this, args);
                    }
                } else if (isObject(handler)) {
                    len = arguments.length;
                    args = new Array(len - 1);
                    for (i = 1; i < len; i++)
                        args[i - 1] = arguments[i];

                    listeners = handler.slice();
                    len = listeners.length;
                    for (i = 0; i < len; i++)
                        listeners[i].apply(this, args);
                }

                return true;
            };

            EventEmitter.prototype.addListener = function (type, listener) {
                var m;

                if (!isFunction(listener))
                    throw TypeError('listener must be a function');

                if (!this._events)
                    this._events = {};
                if (this._events.newListener)
                    this.emit('newListener', type,
                        isFunction(listener.listener) ?
                            listener.listener : listener);

                if (!this._events[type])
                    this._events[type] = listener;
                else if (isObject(this._events[type]))
                    this._events[type].push(listener);
                else
                    this._events[type] = [this._events[type], listener];
                if (isObject(this._events[type]) && !this._events[type].warned) {
                    var m;
                    if (!isUndefined(this._maxListeners)) {
                        m = this._maxListeners;
                    } else {
                        m = EventEmitter.defaultMaxListeners;
                    }

                    if (m && m > 0 && this._events[type].length > m) {
                        this._events[type].warned = true;
                        console.error('(node) warning: possible EventEmitter memory ' +
                            'leak detected. %d listeners added. ' +
                            'Use emitter.setMaxListeners() to increase limit.',
                            this._events[type].length);
                        if (typeof console.trace === 'function') {
                            console.trace();
                        }
                    }
                }

                return this;
            };

            EventEmitter.prototype.on = EventEmitter.prototype.addListener;

            EventEmitter.prototype.once = function (type, listener) {
                if (!isFunction(listener))
                    throw TypeError('listener must be a function');

                var fired = false;

                function g() {
                    this.removeListener(type, g);

                    if (!fired) {
                        fired = true;
                        listener.apply(this, arguments);
                    }
                }

                g.listener = listener;
                this.on(type, g);

                return this;
            };
            EventEmitter.prototype.removeListener = function (type, listener) {
                var list, position, length, i;

                if (!isFunction(listener))
                    throw TypeError('listener must be a function');

                if (!this._events || !this._events[type])
                    return this;

                list = this._events[type];
                length = list.length;
                position = -1;

                if (list === listener ||
                    (isFunction(list.listener) && list.listener === listener)) {
                    delete this._events[type];
                    if (this._events.removeListener)
                        this.emit('removeListener', type, listener);

                } else if (isObject(list)) {
                    for (i = length; i-- > 0;) {
                        if (list[i] === listener ||
                            (list[i].listener && list[i].listener === listener)) {
                            position = i;
                            break;
                        }
                    }

                    if (position < 0)
                        return this;

                    if (list.length === 1) {
                        list.length = 0;
                        delete this._events[type];
                    } else {
                        list.splice(position, 1);
                    }

                    if (this._events.removeListener)
                        this.emit('removeListener', type, listener);
                }

                return this;
            };

            EventEmitter.prototype.removeAllListeners = function (type) {
                var key, listeners;

                if (!this._events)
                    return this;
                if (!this._events.removeListener) {
                    if (arguments.length === 0)
                        this._events = {};
                    else if (this._events[type])
                        delete this._events[type];
                    return this;
                }
                if (arguments.length === 0) {
                    for (key in this._events) {
                        if (key === 'removeListener') continue;
                        this.removeAllListeners(key);
                    }
                    this.removeAllListeners('removeListener');
                    this._events = {};
                    return this;
                }

                listeners = this._events[type];

                if (isFunction(listeners)) {
                    this.removeListener(type, listeners);
                } else {
                    while (listeners.length)
                        this.removeListener(type, listeners[listeners.length - 1]);
                }
                delete this._events[type];

                return this;
            };

            EventEmitter.prototype.listeners = function (type) {
                var ret;
                if (!this._events || !this._events[type])
                    ret = [];
                else if (isFunction(this._events[type]))
                    ret = [this._events[type]];
                else
                    ret = this._events[type].slice();
                return ret;
            };

            EventEmitter.listenerCount = function (emitter, type) {
                var ret;
                if (!emitter._events || !emitter._events[type])
                    ret = 0;
                else if (isFunction(emitter._events[type]))
                    ret = 1;
                else
                    ret = emitter._events[type].length;
                return ret;
            };

            function isFunction(arg) {
                return typeof arg === 'function';
            }

            function isNumber(arg) {
                return typeof arg === 'number';
            }

            function isObject(arg) {
                return typeof arg === 'object' && arg !== null;
            }

            function isUndefined(arg) {
                return arg === void 0;
            }

        }, {}],
        "/node_modules/jshint/data/ascii-identifier-data.js": [function (_dereq_, module, exports) {
            var identifierStartTable = [];

            for (var i = 0; i < 128; i++) {
                identifierStartTable[i] =
                    i === 36 ||           // $
                    i >= 65 && i <= 90 || // A-Z
                    i === 95 ||           // _
                    i >= 97 && i <= 122;  // a-z
            }

            var identifierPartTable = [];

            for (var i = 0; i < 128; i++) {
                identifierPartTable[i] =
                    identifierStartTable[i] || // $, _, A-Z, a-z
                    i >= 48 && i <= 57;        // 0-9
            }

            module.exports = {
                asciiIdentifierStartTable: identifierStartTable,
                asciiIdentifierPartTable: identifierPartTable
            };

        }, {}],
        "/node_modules/jshint/lodash.js": [function (_dereq_, module, exports) {
            (function (global) {
                ;(function () {

                    var undefined;

                    var VERSION = '3.7.0';

                    var FUNC_ERROR_TEXT = 'Expected a function';

                    var argsTag = '[object Arguments]',
                        arrayTag = '[object Array]',
                        boolTag = '[object Boolean]',
                        dateTag = '[object Date]',
                        errorTag = '[object Error]',
                        funcTag = '[object Function]',
                        mapTag = '[object Map]',
                        numberTag = '[object Number]',
                        objectTag = '[object Object]',
                        regexpTag = '[object RegExp]',
                        setTag = '[object Set]',
                        stringTag = '[object String]',
                        weakMapTag = '[object WeakMap]';

                    var arrayBufferTag = '[object ArrayBuffer]',
                        float32Tag = '[object Float32Array]',
                        float64Tag = '[object Float64Array]',
                        int8Tag = '[object Int8Array]',
                        int16Tag = '[object Int16Array]',
                        int32Tag = '[object Int32Array]',
                        uint8Tag = '[object Uint8Array]',
                        uint8ClampedTag = '[object Uint8ClampedArray]',
                        uint16Tag = '[object Uint16Array]',
                        uint32Tag = '[object Uint32Array]';

                    var reIsDeepProp = /\.|\[(?:[^[\]]+|(["'])(?:(?!\1)[^\n\\]|\\.)*?)\1\]/,
                        reIsPlainProp = /^\w*$/,
                        rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g;

                    var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g,
                        reHasRegExpChars = RegExp(reRegExpChars.source);

                    var reEscapeChar = /\\(\\)?/g;

                    var reFlags = /\w*$/;

                    var reIsHostCtor = /^\[object .+?Constructor\]$/;

                    var typedArrayTags = {};
                    typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
                        typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
                            typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
                                typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
                                    typedArrayTags[uint32Tag] = true;
                    typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
                        typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
                            typedArrayTags[dateTag] = typedArrayTags[errorTag] =
                                typedArrayTags[funcTag] = typedArrayTags[mapTag] =
                                    typedArrayTags[numberTag] = typedArrayTags[objectTag] =
                                        typedArrayTags[regexpTag] = typedArrayTags[setTag] =
                                            typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;

                    var cloneableTags = {};
                    cloneableTags[argsTag] = cloneableTags[arrayTag] =
                        cloneableTags[arrayBufferTag] = cloneableTags[boolTag] =
                            cloneableTags[dateTag] = cloneableTags[float32Tag] =
                                cloneableTags[float64Tag] = cloneableTags[int8Tag] =
                                    cloneableTags[int16Tag] = cloneableTags[int32Tag] =
                                        cloneableTags[numberTag] = cloneableTags[objectTag] =
                                            cloneableTags[regexpTag] = cloneableTags[stringTag] =
                                                cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
                                                    cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
                    cloneableTags[errorTag] = cloneableTags[funcTag] =
                        cloneableTags[mapTag] = cloneableTags[setTag] =
                            cloneableTags[weakMapTag] = false;

                    var objectTypes = {
                        'function': true,
                        'object': true
                    };

                    var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;

                    var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;

                    var freeGlobal = freeExports && freeModule && typeof global == 'object' && global && global.Object && global;

                    var freeSelf = objectTypes[typeof self] && self && self.Object && self;

                    var freeWindow = objectTypes[typeof window] && window && window.Object && window;

                    var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;

                    var root = freeGlobal || ((freeWindow !== (this && this.window)) && freeWindow) || freeSelf || this;

                    function baseFindIndex(array, predicate, fromRight) {
                        var length = array.length,
                            index = fromRight ? length : -1;

                        while ((fromRight ? index-- : ++index < length)) {
                            if (predicate(array[index], index, array)) {
                                return index;
                            }
                        }
                        return -1;
                    }

                    function baseIndexOf(array, value, fromIndex) {
                        if (value !== value) {
                            return indexOfNaN(array, fromIndex);
                        }
                        var index = fromIndex - 1,
                            length = array.length;

                        while (++index < length) {
                            if (array[index] === value) {
                                return index;
                            }
                        }
                        return -1;
                    }

                    function baseIsFunction(value) {
                        return typeof value == 'function' || false;
                    }

                    function baseToString(value) {
                        if (typeof value == 'string') {
                            return value;
                        }
                        return value == null ? '' : (value + '');
                    }

                    function indexOfNaN(array, fromIndex, fromRight) {
                        var length = array.length,
                            index = fromIndex + (fromRight ? 0 : -1);

                        while ((fromRight ? index-- : ++index < length)) {
                            var other = array[index];
                            if (other !== other) {
                                return index;
                            }
                        }
                        return -1;
                    }

                    function isObjectLike(value) {
                        return !!value && typeof value == 'object';
                    }

                    var arrayProto = Array.prototype,
                        objectProto = Object.prototype;

                    var fnToString = Function.prototype.toString;

                    var hasOwnProperty = objectProto.hasOwnProperty;

                    var objToString = objectProto.toString;

                    var reIsNative = RegExp('^' +
                        escapeRegExp(objToString)
                            .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
                    );

                    var ArrayBuffer = isNative(ArrayBuffer = root.ArrayBuffer) && ArrayBuffer,
                        bufferSlice = isNative(bufferSlice = ArrayBuffer && new ArrayBuffer(0).slice) && bufferSlice,
                        floor = Math.floor,
                        getOwnPropertySymbols = isNative(getOwnPropertySymbols = Object.getOwnPropertySymbols) && getOwnPropertySymbols,
                        getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
                        push = arrayProto.push,
                        preventExtensions = isNative(Object.preventExtensions = Object.preventExtensions) && preventExtensions,
                        propertyIsEnumerable = objectProto.propertyIsEnumerable,
                        Uint8Array = isNative(Uint8Array = root.Uint8Array) && Uint8Array;

                    var Float64Array = (function () {
                        try {
                            var func = isNative(func = root.Float64Array) && func,
                                result = new func(new ArrayBuffer(10), 0, 1) && func;
                        } catch (e) {
                        }
                        return result;
                    }());

                    var nativeAssign = (function () {
                        var object = {'1': 0},
                            func = preventExtensions && isNative(func = Object.assign) && func;

                        try {
                            func(preventExtensions(object), 'xo');
                        } catch (e) {
                        }
                        return !object[1] && func;
                    }());

                    var nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
                        nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys,
                        nativeMax = Math.max,
                        nativeMin = Math.min;

                    var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY;

                    var MAX_ARRAY_LENGTH = Math.pow(2, 32) - 1,
                        MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
                        HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;

                    var FLOAT64_BYTES_PER_ELEMENT = Float64Array ? Float64Array.BYTES_PER_ELEMENT : 0;

                    var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1;

                    function lodash() {
                    }

                    var support = lodash.support = {};

                    (function (x) {
                        var Ctor = function () {
                                this.x = x;
                            },
                            object = {'0': x, 'length': x},
                            props = [];

                        Ctor.prototype = {'valueOf': x, 'y': x};
                        for (var key in new Ctor) {
                            props.push(key);
                        }

                        support.funcDecomp = /\bthis\b/.test(function () {
                            return this;
                        });

                        support.funcNames = typeof Function.name == 'string';

                        try {
                            support.nonEnumArgs = !propertyIsEnumerable.call(arguments, 1);
                        } catch (e) {
                            support.nonEnumArgs = true;
                        }
                    }(1, 0));

                    function arrayCopy(source, array) {
                        var index = -1,
                            length = source.length;

                        array || (array = Array(length));
                        while (++index < length) {
                            array[index] = source[index];
                        }
                        return array;
                    }

                    function arrayEach(array, iteratee) {
                        var index = -1,
                            length = array.length;

                        while (++index < length) {
                            if (iteratee(array[index], index, array) === false) {
                                break;
                            }
                        }
                        return array;
                    }

                    function arrayFilter(array, predicate) {
                        var index = -1,
                            length = array.length,
                            resIndex = -1,
                            result = [];

                        while (++index < length) {
                            var value = array[index];
                            if (predicate(value, index, array)) {
                                result[++resIndex] = value;
                            }
                        }
                        return result;
                    }

                    function arrayMap(array, iteratee) {
                        var index = -1,
                            length = array.length,
                            result = Array(length);

                        while (++index < length) {
                            result[index] = iteratee(array[index], index, array);
                        }
                        return result;
                    }

                    function arrayMax(array) {
                        var index = -1,
                            length = array.length,
                            result = NEGATIVE_INFINITY;

                        while (++index < length) {
                            var value = array[index];
                            if (value > result) {
                                result = value;
                            }
                        }
                        return result;
                    }

                    function arraySome(array, predicate) {
                        var index = -1,
                            length = array.length;

                        while (++index < length) {
                            if (predicate(array[index], index, array)) {
                                return true;
                            }
                        }
                        return false;
                    }

                    function assignWith(object, source, customizer) {
                        var props = keys(source);
                        push.apply(props, getSymbols(source));

                        var index = -1,
                            length = props.length;

                        while (++index < length) {
                            var key = props[index],
                                value = object[key],
                                result = customizer(value, source[key], key, object, source);

                            if ((result === result ? (result !== value) : (value === value)) ||
                                (value === undefined && !(key in object))) {
                                object[key] = result;
                            }
                        }
                        return object;
                    }

                    var baseAssign = nativeAssign || function (object, source) {
                        return source == null
                            ? object
                            : baseCopy(source, getSymbols(source), baseCopy(source, keys(source), object));
                    };

                    function baseCopy(source, props, object) {
                        object || (object = {});

                        var index = -1,
                            length = props.length;

                        while (++index < length) {
                            var key = props[index];
                            object[key] = source[key];
                        }
                        return object;
                    }

                    function baseCallback(func, thisArg, argCount) {
                        var type = typeof func;
                        if (type == 'function') {
                            return thisArg === undefined
                                ? func
                                : bindCallback(func, thisArg, argCount);
                        }
                        if (func == null) {
                            return identity;
                        }
                        if (type == 'object') {
                            return baseMatches(func);
                        }
                        return thisArg === undefined
                            ? property(func)
                            : baseMatchesProperty(func, thisArg);
                    }

                    function baseClone(value, isDeep, customizer, key, object, stackA, stackB) {
                        var result;
                        if (customizer) {
                            result = object ? customizer(value, key, object) : customizer(value);
                        }
                        if (result !== undefined) {
                            return result;
                        }
                        if (!isObject(value)) {
                            return value;
                        }
                        var isArr = isArray(value);
                        if (isArr) {
                            result = initCloneArray(value);
                            if (!isDeep) {
                                return arrayCopy(value, result);
                            }
                        } else {
                            var tag = objToString.call(value),
                                isFunc = tag == funcTag;

                            if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
                                result = initCloneObject(isFunc ? {} : value);
                                if (!isDeep) {
                                    return baseAssign(result, value);
                                }
                            } else {
                                return cloneableTags[tag]
                                    ? initCloneByTag(value, tag, isDeep)
                                    : (object ? value : {});
                            }
                        }
                        stackA || (stackA = []);
                        stackB || (stackB = []);

                        var length = stackA.length;
                        while (length--) {
                            if (stackA[length] == value) {
                                return stackB[length];
                            }
                        }
                        stackA.push(value);
                        stackB.push(result);

                        (isArr ? arrayEach : baseForOwn)(value, function (subValue, key) {
                            result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB);
                        });
                        return result;
                    }

                    var baseEach = createBaseEach(baseForOwn);

                    function baseFilter(collection, predicate) {
                        var result = [];
                        baseEach(collection, function (value, index, collection) {
                            if (predicate(value, index, collection)) {
                                result.push(value);
                            }
                        });
                        return result;
                    }

                    var baseFor = createBaseFor();

                    function baseForIn(object, iteratee) {
                        return baseFor(object, iteratee, keysIn);
                    }

                    function baseForOwn(object, iteratee) {
                        return baseFor(object, iteratee, keys);
                    }

                    function baseGet(object, path, pathKey) {
                        if (object == null) {
                            return;
                        }
                        if (pathKey !== undefined && pathKey in toObject(object)) {
                            path = [pathKey];
                        }
                        var index = -1,
                            length = path.length;

                        while (object != null && ++index < length) {
                            var result = object = object[path[index]];
                        }
                        return result;
                    }

                    function baseIsEqual(value, other, customizer, isLoose, stackA, stackB) {
                        if (value === other) {
                            return value !== 0 || (1 / value == 1 / other);
                        }
                        var valType = typeof value,
                            othType = typeof other;

                        if ((valType != 'function' && valType != 'object' && othType != 'function' && othType != 'object') ||
                            value == null || other == null) {
                            return value !== value && other !== other;
                        }
                        return baseIsEqualDeep(value, other, baseIsEqual, customizer, isLoose, stackA, stackB);
                    }

                    function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
                        var objIsArr = isArray(object),
                            othIsArr = isArray(other),
                            objTag = arrayTag,
                            othTag = arrayTag;

                        if (!objIsArr) {
                            objTag = objToString.call(object);
                            if (objTag == argsTag) {
                                objTag = objectTag;
                            } else if (objTag != objectTag) {
                                objIsArr = isTypedArray(object);
                            }
                        }
                        if (!othIsArr) {
                            othTag = objToString.call(other);
                            if (othTag == argsTag) {
                                othTag = objectTag;
                            } else if (othTag != objectTag) {
                                othIsArr = isTypedArray(other);
                            }
                        }
                        var objIsObj = objTag == objectTag,
                            othIsObj = othTag == objectTag,
                            isSameTag = objTag == othTag;

                        if (isSameTag && !(objIsArr || objIsObj)) {
                            return equalByTag(object, other, objTag);
                        }
                        if (!isLoose) {
                            var valWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
                                othWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');

                            if (valWrapped || othWrapped) {
                                return equalFunc(valWrapped ? object.value() : object, othWrapped ? other.value() : other, customizer, isLoose, stackA, stackB);
                            }
                        }
                        if (!isSameTag) {
                            return false;
                        }
                        stackA || (stackA = []);
                        stackB || (stackB = []);

                        var length = stackA.length;
                        while (length--) {
                            if (stackA[length] == object) {
                                return stackB[length] == other;
                            }
                        }
                        stackA.push(object);
                        stackB.push(other);

                        var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isLoose, stackA, stackB);

                        stackA.pop();
                        stackB.pop();

                        return result;
                    }

                    function baseIsMatch(object, props, values, strictCompareFlags, customizer) {
                        var index = -1,
                            length = props.length,
                            noCustomizer = !customizer;

                        while (++index < length) {
                            if ((noCustomizer && strictCompareFlags[index])
                                ? values[index] !== object[props[index]]
                                : !(props[index] in object)
                            ) {
                                return false;
                            }
                        }
                        index = -1;
                        while (++index < length) {
                            var key = props[index],
                                objValue = object[key],
                                srcValue = values[index];

                            if (noCustomizer && strictCompareFlags[index]) {
                                var result = objValue !== undefined || (key in object);
                            } else {
                                result = customizer ? customizer(objValue, srcValue, key) : undefined;
                                if (result === undefined) {
                                    result = baseIsEqual(srcValue, objValue, customizer, true);
                                }
                            }
                            if (!result) {
                                return false;
                            }
                        }
                        return true;
                    }

                    function baseMatches(source) {
                        var props = keys(source),
                            length = props.length;

                        if (!length) {
                            return constant(true);
                        }
                        if (length == 1) {
                            var key = props[0],
                                value = source[key];

                            if (isStrictComparable(value)) {
                                return function (object) {
                                    if (object == null) {
                                        return false;
                                    }
                                    return object[key] === value && (value !== undefined || (key in toObject(object)));
                                };
                            }
                        }
                        var values = Array(length),
                            strictCompareFlags = Array(length);

                        while (length--) {
                            value = source[props[length]];
                            values[length] = value;
                            strictCompareFlags[length] = isStrictComparable(value);
                        }
                        return function (object) {
                            return object != null && baseIsMatch(toObject(object), props, values, strictCompareFlags);
                        };
                    }

                    function baseMatchesProperty(path, value) {
                        var isArr = isArray(path),
                            isCommon = isKey(path) && isStrictComparable(value),
                            pathKey = (path + '');

                        path = toPath(path);
                        return function (object) {
                            if (object == null) {
                                return false;
                            }
                            var key = pathKey;
                            object = toObject(object);
                            if ((isArr || !isCommon) && !(key in object)) {
                                object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1));
                                if (object == null) {
                                    return false;
                                }
                                key = last(path);
                                object = toObject(object);
                            }
                            return object[key] === value
                                ? (value !== undefined || (key in object))
                                : baseIsEqual(value, object[key], null, true);
                        };
                    }

                    function baseMerge(object, source, customizer, stackA, stackB) {
                        if (!isObject(object)) {
                            return object;
                        }
                        var isSrcArr = isLength(source.length) && (isArray(source) || isTypedArray(source));
                        if (!isSrcArr) {
                            var props = keys(source);
                            push.apply(props, getSymbols(source));
                        }
                        arrayEach(props || source, function (srcValue, key) {
                            if (props) {
                                key = srcValue;
                                srcValue = source[key];
                            }
                            if (isObjectLike(srcValue)) {
                                stackA || (stackA = []);
                                stackB || (stackB = []);
                                baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB);
                            } else {
                                var value = object[key],
                                    result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
                                    isCommon = result === undefined;

                                if (isCommon) {
                                    result = srcValue;
                                }
                                if ((isSrcArr || result !== undefined) &&
                                    (isCommon || (result === result ? (result !== value) : (value === value)))) {
                                    object[key] = result;
                                }
                            }
                        });
                        return object;
                    }

                    function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) {
                        var length = stackA.length,
                            srcValue = source[key];

                        while (length--) {
                            if (stackA[length] == srcValue) {
                                object[key] = stackB[length];
                                return;
                            }
                        }
                        var value = object[key],
                            result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
                            isCommon = result === undefined;

                        if (isCommon) {
                            result = srcValue;
                            if (isLength(srcValue.length) && (isArray(srcValue) || isTypedArray(srcValue))) {
                                result = isArray(value)
                                    ? value
                                    : (getLength(value) ? arrayCopy(value) : []);
                            } else if (isPlainObject(srcValue) || isArguments(srcValue)) {
                                result = isArguments(value)
                                    ? toPlainObject(value)
                                    : (isPlainObject(value) ? value : {});
                            } else {
                                isCommon = false;
                            }
                        }
                        stackA.push(srcValue);
                        stackB.push(result);

                        if (isCommon) {
                            object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB);
                        } else if (result === result ? (result !== value) : (value === value)) {
                            object[key] = result;
                        }
                    }

                    function baseProperty(key) {
                        return function (object) {
                            return object == null ? undefined : object[key];
                        };
                    }

                    function basePropertyDeep(path) {
                        var pathKey = (path + '');
                        path = toPath(path);
                        return function (object) {
                            return baseGet(object, path, pathKey);
                        };
                    }

                    function baseSlice(array, start, end) {
                        var index = -1,
                            length = array.length;

                        start = start == null ? 0 : (+start || 0);
                        if (start < 0) {
                            start = -start > length ? 0 : (length + start);
                        }
                        end = (end === undefined || end > length) ? length : (+end || 0);
                        if (end < 0) {
                            end += length;
                        }
                        length = start > end ? 0 : ((end - start) >>> 0);
                        start >>>= 0;

                        var result = Array(length);
                        while (++index < length) {
                            result[index] = array[index + start];
                        }
                        return result;
                    }

                    function baseSome(collection, predicate) {
                        var result;

                        baseEach(collection, function (value, index, collection) {
                            result = predicate(value, index, collection);
                            return !result;
                        });
                        return !!result;
                    }

                    function baseValues(object, props) {
                        var index = -1,
                            length = props.length,
                            result = Array(length);

                        while (++index < length) {
                            result[index] = object[props[index]];
                        }
                        return result;
                    }

                    function binaryIndex(array, value, retHighest) {
                        var low = 0,
                            high = array ? array.length : low;

                        if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
                            while (low < high) {
                                var mid = (low + high) >>> 1,
                                    computed = array[mid];

                                if (retHighest ? (computed <= value) : (computed < value)) {
                                    low = mid + 1;
                                } else {
                                    high = mid;
                                }
                            }
                            return high;
                        }
                        return binaryIndexBy(array, value, identity, retHighest);
                    }

                    function binaryIndexBy(array, value, iteratee, retHighest) {
                        value = iteratee(value);

                        var low = 0,
                            high = array ? array.length : 0,
                            valIsNaN = value !== value,
                            valIsUndef = value === undefined;

                        while (low < high) {
                            var mid = floor((low + high) / 2),
                                computed = iteratee(array[mid]),
                                isReflexive = computed === computed;

                            if (valIsNaN) {
                                var setLow = isReflexive || retHighest;
                            } else if (valIsUndef) {
                                setLow = isReflexive && (retHighest || computed !== undefined);
                            } else {
                                setLow = retHighest ? (computed <= value) : (computed < value);
                            }
                            if (setLow) {
                                low = mid + 1;
                            } else {
                                high = mid;
                            }
                        }
                        return nativeMin(high, MAX_ARRAY_INDEX);
                    }

                    function bindCallback(func, thisArg, argCount) {
                        if (typeof func != 'function') {
                            return identity;
                        }
                        if (thisArg === undefined) {
                            return func;
                        }
                        switch (argCount) {
                            case 1:
                                return function (value) {
                                    return func.call(thisArg, value);
                                };
                            case 3:
                                return function (value, index, collection) {
                                    return func.call(thisArg, value, index, collection);
                                };
                            case 4:
                                return function (accumulator, value, index, collection) {
                                    return func.call(thisArg, accumulator, value, index, collection);
                                };
                            case 5:
                                return function (value, other, key, object, source) {
                                    return func.call(thisArg, value, other, key, object, source);
                                };
                        }
                        return function () {
                            return func.apply(thisArg, arguments);
                        };
                    }

                    function bufferClone(buffer) {
                        return bufferSlice.call(buffer, 0);
                    }

                    if (!bufferSlice) {
                        bufferClone = !(ArrayBuffer && Uint8Array) ? constant(null) : function (buffer) {
                            var byteLength = buffer.byteLength,
                                floatLength = Float64Array ? floor(byteLength / FLOAT64_BYTES_PER_ELEMENT) : 0,
                                offset = floatLength * FLOAT64_BYTES_PER_ELEMENT,
                                result = new ArrayBuffer(byteLength);

                            if (floatLength) {
                                var view = new Float64Array(result, 0, floatLength);
                                view.set(new Float64Array(buffer, 0, floatLength));
                            }
                            if (byteLength != offset) {
                                view = new Uint8Array(result, offset);
                                view.set(new Uint8Array(buffer, offset));
                            }
                            return result;
                        };
                    }

                    function createAssigner(assigner) {
                        return restParam(function (object, sources) {
                            var index = -1,
                                length = object == null ? 0 : sources.length,
                                customizer = length > 2 && sources[length - 2],
                                guard = length > 2 && sources[2],
                                thisArg = length > 1 && sources[length - 1];

                            if (typeof customizer == 'function') {
                                customizer = bindCallback(customizer, thisArg, 5);
                                length -= 2;
                            } else {
                                customizer = typeof thisArg == 'function' ? thisArg : null;
                                length -= (customizer ? 1 : 0);
                            }
                            if (guard && isIterateeCall(sources[0], sources[1], guard)) {
                                customizer = length < 3 ? null : customizer;
                                length = 1;
                            }
                            while (++index < length) {
                                var source = sources[index];
                                if (source) {
                                    assigner(object, source, customizer);
                                }
                            }
                            return object;
                        });
                    }

                    function createBaseEach(eachFunc, fromRight) {
                        return function (collection, iteratee) {
                            var length = collection ? getLength(collection) : 0;
                            if (!isLength(length)) {
                                return eachFunc(collection, iteratee);
                            }
                            var index = fromRight ? length : -1,
                                iterable = toObject(collection);

                            while ((fromRight ? index-- : ++index < length)) {
                                if (iteratee(iterable[index], index, iterable) === false) {
                                    break;
                                }
                            }
                            return collection;
                        };
                    }

                    function createBaseFor(fromRight) {
                        return function (object, iteratee, keysFunc) {
                            var iterable = toObject(object),
                                props = keysFunc(object),
                                length = props.length,
                                index = fromRight ? length : -1;

                            while ((fromRight ? index-- : ++index < length)) {
                                var key = props[index];
                                if (iteratee(iterable[key], key, iterable) === false) {
                                    break;
                                }
                            }
                            return object;
                        };
                    }

                    function createFindIndex(fromRight) {
                        return function (array, predicate, thisArg) {
                            if (!(array && array.length)) {
                                return -1;
                            }
                            predicate = getCallback(predicate, thisArg, 3);
                            return baseFindIndex(array, predicate, fromRight);
                        };
                    }

                    function createForEach(arrayFunc, eachFunc) {
                        return function (collection, iteratee, thisArg) {
                            return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection))
                                ? arrayFunc(collection, iteratee)
                                : eachFunc(collection, bindCallback(iteratee, thisArg, 3));
                        };
                    }

                    function equalArrays(array, other, equalFunc, customizer, isLoose, stackA, stackB) {
                        var index = -1,
                            arrLength = array.length,
                            othLength = other.length,
                            result = true;

                        if (arrLength != othLength && !(isLoose && othLength > arrLength)) {
                            return false;
                        }
                        while (result && ++index < arrLength) {
                            var arrValue = array[index],
                                othValue = other[index];

                            result = undefined;
                            if (customizer) {
                                result = isLoose
                                    ? customizer(othValue, arrValue, index)
                                    : customizer(arrValue, othValue, index);
                            }
                            if (result === undefined) {
                                if (isLoose) {
                                    var othIndex = othLength;
                                    while (othIndex--) {
                                        othValue = other[othIndex];
                                        result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB);
                                        if (result) {
                                            break;
                                        }
                                    }
                                } else {
                                    result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB);
                                }
                            }
                        }
                        return !!result;
                    }

                    function equalByTag(object, other, tag) {
                        switch (tag) {
                            case boolTag:
                            case dateTag:
                                return +object == +other;

                            case errorTag:
                                return object.name == other.name && object.message == other.message;

                            case numberTag:
                                return (object != +object)
                                    ? other != +other
                                    : (object == 0 ? ((1 / object) == (1 / other)) : object == +other);

                            case regexpTag:
                            case stringTag:
                                return object == (other + '');
                        }
                        return false;
                    }

                    function equalObjects(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
                        var objProps = keys(object),
                            objLength = objProps.length,
                            othProps = keys(other),
                            othLength = othProps.length;

                        if (objLength != othLength && !isLoose) {
                            return false;
                        }
                        var skipCtor = isLoose,
                            index = -1;

                        while (++index < objLength) {
                            var key = objProps[index],
                                result = isLoose ? key in other : hasOwnProperty.call(other, key);

                            if (result) {
                                var objValue = object[key],
                                    othValue = other[key];

                                result = undefined;
                                if (customizer) {
                                    result = isLoose
                                        ? customizer(othValue, objValue, key)
                                        : customizer(objValue, othValue, key);
                                }
                                if (result === undefined) {
                                    result = (objValue && objValue === othValue) || equalFunc(objValue, othValue, customizer, isLoose, stackA, stackB);
                                }
                            }
                            if (!result) {
                                return false;
                            }
                            skipCtor || (skipCtor = key == 'constructor');
                        }
                        if (!skipCtor) {
                            var objCtor = object.constructor,
                                othCtor = other.constructor;

                            if (objCtor != othCtor &&
                                ('constructor' in object && 'constructor' in other) &&
                                !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
                                    typeof othCtor == 'function' && othCtor instanceof othCtor)) {
                                return false;
                            }
                        }
                        return true;
                    }

                    function getCallback(func, thisArg, argCount) {
                        var result = lodash.callback || callback;
                        result = result === callback ? baseCallback : result;
                        return argCount ? result(func, thisArg, argCount) : result;
                    }

                    function getIndexOf(collection, target, fromIndex) {
                        var result = lodash.indexOf || indexOf;
                        result = result === indexOf ? baseIndexOf : result;
                        return collection ? result(collection, target, fromIndex) : result;
                    }

                    var getLength = baseProperty('length');

                    var getSymbols = !getOwnPropertySymbols ? constant([]) : function (object) {
                        return getOwnPropertySymbols(toObject(object));
                    };

                    function initCloneArray(array) {
                        var length = array.length,
                            result = new array.constructor(length);

                        if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
                            result.index = array.index;
                            result.input = array.input;
                        }
                        return result;
                    }

                    function initCloneObject(object) {
                        var Ctor = object.constructor;
                        if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) {
                            Ctor = Object;
                        }
                        return new Ctor;
                    }

                    function initCloneByTag(object, tag, isDeep) {
                        var Ctor = object.constructor;
                        switch (tag) {
                            case arrayBufferTag:
                                return bufferClone(object);

                            case boolTag:
                            case dateTag:
                                return new Ctor(+object);

                            case float32Tag:
                            case float64Tag:
                            case int8Tag:
                            case int16Tag:
                            case int32Tag:
                            case uint8Tag:
                            case uint8ClampedTag:
                            case uint16Tag:
                            case uint32Tag:
                                var buffer = object.buffer;
                                return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length);

                            case numberTag:
                            case stringTag:
                                return new Ctor(object);

                            case regexpTag:
                                var result = new Ctor(object.source, reFlags.exec(object));
                                result.lastIndex = object.lastIndex;
                        }
                        return result;
                    }

                    function isIndex(value, length) {
                        value = +value;
                        length = length == null ? MAX_SAFE_INTEGER : length;
                        return value > -1 && value % 1 == 0 && value < length;
                    }

                    function isIterateeCall(value, index, object) {
                        if (!isObject(object)) {
                            return false;
                        }
                        var type = typeof index;
                        if (type == 'number') {
                            var length = getLength(object),
                                prereq = isLength(length) && isIndex(index, length);
                        } else {
                            prereq = type == 'string' && index in object;
                        }
                        if (prereq) {
                            var other = object[index];
                            return value === value ? (value === other) : (other !== other);
                        }
                        return false;
                    }

                    function isKey(value, object) {
                        var type = typeof value;
                        if ((type == 'string' && reIsPlainProp.test(value)) || type == 'number') {
                            return true;
                        }
                        if (isArray(value)) {
                            return false;
                        }
                        var result = !reIsDeepProp.test(value);
                        return result || (object != null && value in toObject(object));
                    }

                    function isLength(value) {
                        return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
                    }

                    function isStrictComparable(value) {
                        return value === value && (value === 0 ? ((1 / value) > 0) : !isObject(value));
                    }

                    function shimIsPlainObject(value) {
                        var Ctor,
                            support = lodash.support;

                        if (!(isObjectLike(value) && objToString.call(value) == objectTag) ||
                            (!hasOwnProperty.call(value, 'constructor') &&
                                (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) {
                            return false;
                        }
                        var result;
                        baseForIn(value, function (subValue, key) {
                            result = key;
                        });
                        return result === undefined || hasOwnProperty.call(value, result);
                    }

                    function shimKeys(object) {
                        var props = keysIn(object),
                            propsLength = props.length,
                            length = propsLength && object.length,
                            support = lodash.support;

                        var allowIndexes = length && isLength(length) &&
                            (isArray(object) || (support.nonEnumArgs && isArguments(object)));

                        var index = -1,
                            result = [];

                        while (++index < propsLength) {
                            var key = props[index];
                            if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
                                result.push(key);
                            }
                        }
                        return result;
                    }

                    function toObject(value) {
                        return isObject(value) ? value : Object(value);
                    }

                    function toPath(value) {
                        if (isArray(value)) {
                            return value;
                        }
                        var result = [];
                        baseToString(value).replace(rePropName, function (match, number, quote, string) {
                            result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
                        });
                        return result;
                    }

                    var findLastIndex = createFindIndex(true);

                    function indexOf(array, value, fromIndex) {
                        var length = array ? array.length : 0;
                        if (!length) {
                            return -1;
                        }
                        if (typeof fromIndex == 'number') {
                            fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : fromIndex;
                        } else if (fromIndex) {
                            var index = binaryIndex(array, value),
                                other = array[index];

                            if (value === value ? (value === other) : (other !== other)) {
                                return index;
                            }
                            return -1;
                        }
                        return baseIndexOf(array, value, fromIndex || 0);
                    }

                    function last(array) {
                        var length = array ? array.length : 0;
                        return length ? array[length - 1] : undefined;
                    }

                    function slice(array, start, end) {
                        var length = array ? array.length : 0;
                        if (!length) {
                            return [];
                        }
                        if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
                            start = 0;
                            end = length;
                        }
                        return baseSlice(array, start, end);
                    }

                    function unzip(array) {
                        var index = -1,
                            length = (array && array.length && arrayMax(arrayMap(array, getLength))) >>> 0,
                            result = Array(length);

                        while (++index < length) {
                            result[index] = arrayMap(array, baseProperty(index));
                        }
                        return result;
                    }

                    var zip = restParam(unzip);

                    var forEach = createForEach(arrayEach, baseEach);

                    function includes(collection, target, fromIndex, guard) {
                        var length = collection ? getLength(collection) : 0;
                        if (!isLength(length)) {
                            collection = values(collection);
                            length = collection.length;
                        }
                        if (!length) {
                            return false;
                        }
                        if (typeof fromIndex != 'number' || (guard && isIterateeCall(target, fromIndex, guard))) {
                            fromIndex = 0;
                        } else {
                            fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0);
                        }
                        return (typeof collection == 'string' || !isArray(collection) && isString(collection))
                            ? (fromIndex < length && collection.indexOf(target, fromIndex) > -1)
                            : (getIndexOf(collection, target, fromIndex) > -1);
                    }

                    function reject(collection, predicate, thisArg) {
                        var func = isArray(collection) ? arrayFilter : baseFilter;
                        predicate = getCallback(predicate, thisArg, 3);
                        return func(collection, function (value, index, collection) {
                            return !predicate(value, index, collection);
                        });
                    }

                    function some(collection, predicate, thisArg) {
                        var func = isArray(collection) ? arraySome : baseSome;
                        if (thisArg && isIterateeCall(collection, predicate, thisArg)) {
                            predicate = null;
                        }
                        if (typeof predicate != 'function' || thisArg !== undefined) {
                            predicate = getCallback(predicate, thisArg, 3);
                        }
                        return func(collection, predicate);
                    }

                    function restParam(func, start) {
                        if (typeof func != 'function') {
                            throw new TypeError(FUNC_ERROR_TEXT);
                        }
                        start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0);
                        return function () {
                            var args = arguments,
                                index = -1,
                                length = nativeMax(args.length - start, 0),
                                rest = Array(length);

                            while (++index < length) {
                                rest[index] = args[start + index];
                            }
                            switch (start) {
                                case 0:
                                    return func.call(this, rest);
                                case 1:
                                    return func.call(this, args[0], rest);
                                case 2:
                                    return func.call(this, args[0], args[1], rest);
                            }
                            var otherArgs = Array(start + 1);
                            index = -1;
                            while (++index < start) {
                                otherArgs[index] = args[index];
                            }
                            otherArgs[start] = rest;
                            return func.apply(this, otherArgs);
                        };
                    }

                    function clone(value, isDeep, customizer, thisArg) {
                        if (isDeep && typeof isDeep != 'boolean' && isIterateeCall(value, isDeep, customizer)) {
                            isDeep = false;
                        } else if (typeof isDeep == 'function') {
                            thisArg = customizer;
                            customizer = isDeep;
                            isDeep = false;
                        }
                        customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1);
                        return baseClone(value, isDeep, customizer);
                    }

                    function isArguments(value) {
                        var length = isObjectLike(value) ? value.length : undefined;
                        return isLength(length) && objToString.call(value) == argsTag;
                    }

                    var isArray = nativeIsArray || function (value) {
                        return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag;
                    };

                    function isEmpty(value) {
                        if (value == null) {
                            return true;
                        }
                        var length = getLength(value);
                        if (isLength(length) && (isArray(value) || isString(value) || isArguments(value) ||
                            (isObjectLike(value) && isFunction(value.splice)))) {
                            return !length;
                        }
                        return !keys(value).length;
                    }

                    var isFunction = !(baseIsFunction(/x/) || (Uint8Array && !baseIsFunction(Uint8Array))) ? baseIsFunction : function (value) {
                        return objToString.call(value) == funcTag;
                    };

                    function isObject(value) {
                        var type = typeof value;
                        return type == 'function' || (!!value && type == 'object');
                    }

                    function isNative(value) {
                        if (value == null) {
                            return false;
                        }
                        if (objToString.call(value) == funcTag) {
                            return reIsNative.test(fnToString.call(value));
                        }
                        return isObjectLike(value) && reIsHostCtor.test(value);
                    }

                    function isNumber(value) {
                        return typeof value == 'number' || (isObjectLike(value) && objToString.call(value) == numberTag);
                    }

                    var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function (value) {
                        if (!(value && objToString.call(value) == objectTag)) {
                            return false;
                        }
                        var valueOf = value.valueOf,
                            objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);

                        return objProto
                            ? (value == objProto || getPrototypeOf(value) == objProto)
                            : shimIsPlainObject(value);
                    };

                    function isString(value) {
                        return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag);
                    }

                    function isTypedArray(value) {
                        return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)];
                    }

                    function toPlainObject(value) {
                        return baseCopy(value, keysIn(value));
                    }

                    var assign = createAssigner(function (object, source, customizer) {
                        return customizer
                            ? assignWith(object, source, customizer)
                            : baseAssign(object, source);
                    });

                    function has(object, path) {
                        if (object == null) {
                            return false;
                        }
                        var result = hasOwnProperty.call(object, path);
                        if (!result && !isKey(path)) {
                            path = toPath(path);
                            object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1));
                            path = last(path);
                            result = object != null && hasOwnProperty.call(object, path);
                        }
                        return result;
                    }

                    var keys = !nativeKeys ? shimKeys : function (object) {
                        if (object) {
                            var Ctor = object.constructor,
                                length = object.length;
                        }
                        if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
                            (typeof object != 'function' && isLength(length))) {
                            return shimKeys(object);
                        }
                        return isObject(object) ? nativeKeys(object) : [];
                    };

                    function keysIn(object) {
                        if (object == null) {
                            return [];
                        }
                        if (!isObject(object)) {
                            object = Object(object);
                        }
                        var length = object.length;
                        length = (length && isLength(length) &&
                            (isArray(object) || (support.nonEnumArgs && isArguments(object))) && length) || 0;

                        var Ctor = object.constructor,
                            index = -1,
                            isProto = typeof Ctor == 'function' && Ctor.prototype === object,
                            result = Array(length),
                            skipIndexes = length > 0;

                        while (++index < length) {
                            result[index] = (index + '');
                        }
                        for (var key in object) {
                            if (!(skipIndexes && isIndex(key, length)) &&
                                !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
                                result.push(key);
                            }
                        }
                        return result;
                    }

                    var merge = createAssigner(baseMerge);

                    function values(object) {
                        return baseValues(object, keys(object));
                    }

                    function escapeRegExp(string) {
                        string = baseToString(string);
                        return (string && reHasRegExpChars.test(string))
                            ? string.replace(reRegExpChars, '\\$&')
                            : string;
                    }

                    function callback(func, thisArg, guard) {
                        if (guard && isIterateeCall(func, thisArg, guard)) {
                            thisArg = null;
                        }
                        return baseCallback(func, thisArg);
                    }

                    function constant(value) {
                        return function () {
                            return value;
                        };
                    }

                    function identity(value) {
                        return value;
                    }

                    function property(path) {
                        return isKey(path) ? baseProperty(path) : basePropertyDeep(path);
                    }

                    lodash.assign = assign;
                    lodash.callback = callback;
                    lodash.constant = constant;
                    lodash.forEach = forEach;
                    lodash.keys = keys;
                    lodash.keysIn = keysIn;
                    lodash.merge = merge;
                    lodash.property = property;
                    lodash.reject = reject;
                    lodash.restParam = restParam;
                    lodash.slice = slice;
                    lodash.toPlainObject = toPlainObject;
                    lodash.unzip = unzip;
                    lodash.values = values;
                    lodash.zip = zip;

                    lodash.each = forEach;
                    lodash.extend = assign;
                    lodash.iteratee = callback;
                    lodash.clone = clone;
                    lodash.escapeRegExp = escapeRegExp;
                    lodash.findLastIndex = findLastIndex;
                    lodash.has = has;
                    lodash.identity = identity;
                    lodash.includes = includes;
                    lodash.indexOf = indexOf;
                    lodash.isArguments = isArguments;
                    lodash.isArray = isArray;
                    lodash.isEmpty = isEmpty;
                    lodash.isFunction = isFunction;
                    lodash.isNative = isNative;
                    lodash.isNumber = isNumber;
                    lodash.isObject = isObject;
                    lodash.isPlainObject = isPlainObject;
                    lodash.isString = isString;
                    lodash.isTypedArray = isTypedArray;
                    lodash.last = last;
                    lodash.some = some;

                    lodash.any = some;
                    lodash.contains = includes;
                    lodash.include = includes;

                    lodash.VERSION = VERSION;
                    if (freeExports && freeModule) {
                        if (moduleExports) {
                            (freeModule.exports = lodash)._ = lodash;
                        } else {
                            freeExports._ = lodash;
                        }
                    } else {
                        root._ = lodash;
                    }
                }.call(this));

            }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
        }, {}],
        "/node_modules/jshint/src/jshint.js": [function (_dereq_, module, exports) {

            var _ = _dereq_("../lodash");
            var events = _dereq_("events");
            var vars = _dereq_("./vars.js");
            var messages = _dereq_("./messages.js");
            var Lexer = _dereq_("./lex.js").Lexer;
            var reg = _dereq_("./reg.js");
            var state = _dereq_("./state.js").state;
            var style = _dereq_("./style.js");
            var options = _dereq_("./options.js");
            var scopeManager = _dereq_("./scope-manager.js");

            var JSHINT = (function () {
                "use strict";

                var api, // Extension API
                    bang = {
                        "<": true,
                        "<=": true,
                        "==": true,
                        "===": true,
                        "!==": true,
                        "!=": true,
                        ">": true,
                        ">=": true,
                        "+": true,
                        "-": true,
                        "*": true,
                        "/": true,
                        "%": true
                    },

                    declared, // Globals that were declared using /*global ... */ syntax.

                    functionicity = [
                        "closure", "exception", "global", "label",
                        "outer", "unused", "var"
                    ],

                    functions, // All of the functions

                    inblock,
                    indent,
                    lookahead,
                    lex,
                    member,
                    membersOnly,
                    predefined,    // Global variables defined by option

                    stack,
                    urls,

                    extraModules = [],
                    emitter = new events.EventEmitter();

                function checkOption(name, t) {
                    name = name.trim();

                    if (/^[+-]W\d{3}$/g.test(name)) {
                        return true;
                    }

                    if (options.validNames.indexOf(name) === -1) {
                        if (t.type !== "jslint" && !_.has(options.removed, name)) {
                            error("E001", t, name);
                            return false;
                        }
                    }

                    return true;
                }

                function isString(obj) {
                    return Object.prototype.toString.call(obj) === "[object String]";
                }

                function isIdentifier(tkn, value) {
                    if (!tkn)
                        return false;

                    if (!tkn.identifier || tkn.value !== value)
                        return false;

                    return true;
                }

                function isReserved(token) {
                    if (!token.reserved) {
                        return false;
                    }
                    var meta = token.meta;

                    if (meta && meta.isFutureReservedWord && state.inES5()) {
                        if (!meta.es5) {
                            return false;
                        }
                        if (meta.strictOnly) {
                            if (!state.option.strict && !state.isStrict()) {
                                return false;
                            }
                        }

                        if (token.isProperty) {
                            return false;
                        }
                    }

                    return true;
                }

                function supplant(str, data) {
                    return str.replace(/\{([^{}]*)\}/g, function (a, b) {
                        var r = data[b];
                        return typeof r === "string" || typeof r === "number" ? r : a;
                    });
                }

                function combine(dest, src) {
                    Object.keys(src).forEach(function (name) {
                        if (_.has(JSHINT.blacklist, name)) return;
                        dest[name] = src[name];
                    });
                }

                function processenforceall() {
                    if (state.option.enforceall) {
                        for (var enforceopt in options.bool.enforcing) {
                            if (state.option[enforceopt] === undefined &&
                                !options.noenforceall[enforceopt]) {
                                state.option[enforceopt] = true;
                            }
                        }
                        for (var relaxopt in options.bool.relaxing) {
                            if (state.option[relaxopt] === undefined) {
                                state.option[relaxopt] = false;
                            }
                        }
                    }
                }

                function assume() {
                    processenforceall();
                    if (!state.option.esversion && !state.option.moz) {
                        if (state.option.es3) {
                            state.option.esversion = 3;
                        } else if (state.option.esnext) {
                            state.option.esversion = 6;
                        } else {
                            state.option.esversion = 5;
                        }
                    }

                    if (state.inES5()) {
                        combine(predefined, vars.ecmaIdentifiers[5]);
                    }

                    if (state.inES6()) {
                        combine(predefined, vars.ecmaIdentifiers[6]);
                    }

                    if (state.option.module) {
                        if (state.option.strict === true) {
                            state.option.strict = "global";
                        }
                        if (!state.inES6()) {
                            warning("W134", state.tokens.next, "module", 6);
                        }
                    }

                    if (state.option.couch) {
                        combine(predefined, vars.couch);
                    }

                    if (state.option.qunit) {
                        combine(predefined, vars.qunit);
                    }

                    if (state.option.rhino) {
                        combine(predefined, vars.rhino);
                    }

                    if (state.option.shelljs) {
                        combine(predefined, vars.shelljs);
                        combine(predefined, vars.node);
                    }
                    if (state.option.typed) {
                        combine(predefined, vars.typed);
                    }

                    if (state.option.phantom) {
                        combine(predefined, vars.phantom);
                        if (state.option.strict === true) {
                            state.option.strict = "global";
                        }
                    }

                    if (state.option.prototypejs) {
                        combine(predefined, vars.prototypejs);
                    }

                    if (state.option.node) {
                        combine(predefined, vars.node);
                        combine(predefined, vars.typed);
                        if (state.option.strict === true) {
                            state.option.strict = "global";
                        }
                    }

                    if (state.option.devel) {
                        combine(predefined, vars.devel);
                    }

                    if (state.option.dojo) {
                        combine(predefined, vars.dojo);
                    }

                    if (state.option.browser) {
                        combine(predefined, vars.browser);
                        combine(predefined, vars.typed);
                    }

                    if (state.option.browserify) {
                        combine(predefined, vars.browser);
                        combine(predefined, vars.typed);
                        combine(predefined, vars.browserify);
                        if (state.option.strict === true) {
                            state.option.strict = "global";
                        }
                    }

                    if (state.option.nonstandard) {
                        combine(predefined, vars.nonstandard);
                    }

                    if (state.option.jasmine) {
                        combine(predefined, vars.jasmine);
                    }

                    if (state.option.jquery) {
                        combine(predefined, vars.jquery);
                    }

                    if (state.option.mootools) {
                        combine(predefined, vars.mootools);
                    }

                    if (state.option.worker) {
                        combine(predefined, vars.worker);
                    }

                    if (state.option.wsh) {
                        combine(predefined, vars.wsh);
                    }

                    if (state.option.globalstrict && state.option.strict !== false) {
                        state.option.strict = "global";
                    }

                    if (state.option.yui) {
                        combine(predefined, vars.yui);
                    }

                    if (state.option.mocha) {
                        combine(predefined, vars.mocha);
                    }
                }

                function quit(code, line, chr) {
                    var percentage = Math.floor((line / state.lines.length) * 100);
                    var message = messages.errors[code].desc;

                    throw {
                        name: "JSHintError",
                        line: line,
                        character: chr,
                        message: message + " (" + percentage + "% scanned).",
                        raw: message,
                        code: code
                    };
                }

                function removeIgnoredMessages() {
                    var ignored = state.ignoredLines;

                    if (_.isEmpty(ignored)) return;
                    JSHINT.errors = _.reject(JSHINT.errors, function (err) {
                        return ignored[err.line]
                    });
                }

                function warning(code, t, a, b, c, d) {
                    var ch, l, w, msg;

                    if (/^W\d{3}$/.test(code)) {
                        if (state.ignored[code])
                            return;

                        msg = messages.warnings[code];
                    } else if (/E\d{3}/.test(code)) {
                        msg = messages.errors[code];
                    } else if (/I\d{3}/.test(code)) {
                        msg = messages.info[code];
                    }

                    t = t || state.tokens.next || {};
                    if (t.id === "(end)") {  // `~
                        t = state.tokens.curr;
                    }

                    l = t.line || 0;
                    ch = t.from || 0;

                    w = {
                        id: "(error)",
                        raw: msg.desc,
                        code: msg.code,
                        evidence: state.lines[l - 1] || "",
                        line: l,
                        character: ch,
                        scope: JSHINT.scope,
                        a: a,
                        b: b,
                        c: c,
                        d: d
                    };

                    w.reason = supplant(msg.desc, w);
                    JSHINT.errors.push(w);

                    removeIgnoredMessages();

                    if (JSHINT.errors.length >= state.option.maxerr)
                        quit("E043", l, ch);

                    return w;
                }

                function warningAt(m, l, ch, a, b, c, d) {
                    return warning(m, {
                        line: l,
                        from: ch
                    }, a, b, c, d);
                }

                function error(m, t, a, b, c, d) {
                    warning(m, t, a, b, c, d);
                }

                function errorAt(m, l, ch, a, b, c, d) {
                    return error(m, {
                        line: l,
                        from: ch
                    }, a, b, c, d);
                }

                function addInternalSrc(elem, src) {
                    var i;
                    i = {
                        id: "(internal)",
                        elem: elem,
                        value: src
                    };
                    JSHINT.internals.push(i);
                    return i;
                }

                function doOption() {
                    var nt = state.tokens.next;
                    var body = nt.body.match(/(-\s+)?[^\s,:]+(?:\s*:\s*(-\s+)?[^\s,]+)?/g) || [];

                    var predef = {};
                    if (nt.type === "globals") {
                        body.forEach(function (g, idx) {
                            g = g.split(":");
                            var key = (g[0] || "").trim();
                            var val = (g[1] || "").trim();

                            if (key === "-" || !key.length) {
                                if (idx > 0 && idx === body.length - 1) {
                                    return;
                                }
                                error("E002", nt);
                                return;
                            }

                            if (key.charAt(0) === "-") {
                                key = key.slice(1);
                                val = false;

                                JSHINT.blacklist[key] = key;
                                delete predefined[key];
                            } else {
                                predef[key] = (val === "true");
                            }
                        });

                        combine(predefined, predef);

                        for (var key in predef) {
                            if (_.has(predef, key)) {
                                declared[key] = nt;
                            }
                        }
                    }

                    if (nt.type === "exported") {
                        body.forEach(function (e, idx) {
                            if (!e.length) {
                                if (idx > 0 && idx === body.length - 1) {
                                    return;
                                }
                                error("E002", nt);
                                return;
                            }

                            state.funct["(scope)"].addExported(e);
                        });
                    }

                    if (nt.type === "members") {
                        membersOnly = membersOnly || {};

                        body.forEach(function (m) {
                            var ch1 = m.charAt(0);
                            var ch2 = m.charAt(m.length - 1);

                            if (ch1 === ch2 && (ch1 === "\"" || ch1 === "'")) {
                                m = m
                                    .substr(1, m.length - 2)
                                    .replace("\\\"", "\"");
                            }

                            membersOnly[m] = false;
                        });
                    }

                    var numvals = [
                        "maxstatements",
                        "maxparams",
                        "maxdepth",
                        "maxcomplexity",
                        "maxerr",
                        "maxlen",
                        "indent"
                    ];

                    if (nt.type === "jshint" || nt.type === "jslint") {
                        body.forEach(function (g) {
                            g = g.split(":");
                            var key = (g[0] || "").trim();
                            var val = (g[1] || "").trim();

                            if (!checkOption(key, nt)) {
                                return;
                            }

                            if (numvals.indexOf(key) >= 0) {
                                if (val !== "false") {
                                    val = +val;

                                    if (typeof val !== "number" || !isFinite(val) || val <= 0 || Math.floor(val) !== val) {
                                        error("E032", nt, g[1].trim());
                                        return;
                                    }

                                    state.option[key] = val;
                                } else {
                                    state.option[key] = key === "indent" ? 4 : false;
                                }

                                return;
                            }

                            if (key === "validthis") {

                                if (state.funct["(global)"])
                                    return void error("E009");

                                if (val !== "true" && val !== "false")
                                    return void error("E002", nt);

                                state.option.validthis = (val === "true");
                                return;
                            }

                            if (key === "quotmark") {
                                switch (val) {
                                    case "true":
                                    case "false":
                                        state.option.quotmark = (val === "true");
                                        break;
                                    case "double":
                                    case "single":
                                        state.option.quotmark = val;
                                        break;
                                    default:
                                        error("E002", nt);
                                }
                                return;
                            }

                            if (key === "shadow") {
                                switch (val) {
                                    case "true":
                                        state.option.shadow = true;
                                        break;
                                    case "outer":
                                        state.option.shadow = "outer";
                                        break;
                                    case "false":
                                    case "inner":
                                        state.option.shadow = "inner";
                                        break;
                                    default:
                                        error("E002", nt);
                                }
                                return;
                            }

                            if (key === "unused") {
                                switch (val) {
                                    case "true":
                                        state.option.unused = true;
                                        break;
                                    case "false":
                                        state.option.unused = false;
                                        break;
                                    case "vars":
                                    case "strict":
                                        state.option.unused = val;
                                        break;
                                    default:
                                        error("E002", nt);
                                }
                                return;
                            }

                            if (key === "latedef") {
                                switch (val) {
                                    case "true":
                                        state.option.latedef = true;
                                        break;
                                    case "false":
                                        state.option.latedef = false;
                                        break;
                                    case "nofunc":
                                        state.option.latedef = "nofunc";
                                        break;
                                    default:
                                        error("E002", nt);
                                }
                                return;
                            }

                            if (key === "ignore") {
                                switch (val) {
                                    case "line":
                                        state.ignoredLines[nt.line] = true;
                                        removeIgnoredMessages();
                                        break;
                                    default:
                                        error("E002", nt);
                                }
                                return;
                            }

                            if (key === "strict") {
                                switch (val) {
                                    case "true":
                                        state.option.strict = true;
                                        break;
                                    case "false":
                                        state.option.strict = false;
                                        break;
                                    case "func":
                                    case "global":
                                    case "implied":
                                        state.option.strict = val;
                                        break;
                                    default:
                                        error("E002", nt);
                                }
                                return;
                            }

                            if (key === "module") {
                                if (!hasParsedCode(state.funct)) {
                                    error("E055", state.tokens.next, "module");
                                }
                            }
                            var esversions = {
                                es3: 3,
                                es5: 5,
                                esnext: 6
                            };
                            if (_.has(esversions, key)) {
                                switch (val) {
                                    case "true":
                                        state.option.moz = false;
                                        state.option.esversion = esversions[key];
                                        break;
                                    case "false":
                                        if (!state.option.moz) {
                                            state.option.esversion = 5;
                                        }
                                        break;
                                    default:
                                        error("E002", nt);
                                }
                                return;
                            }

                            if (key === "esversion") {
                                switch (val) {
                                    case "5":
                                        if (state.inES5(true)) {
                                            warning("I003");
                                        }
                                    case "3":
                                    case "6":
                                        state.option.moz = false;
                                        state.option.esversion = +val;
                                        break;
                                    case "2015":
                                        state.option.moz = false;
                                        state.option.esversion = 6;
                                        break;
                                    default:
                                        error("E002", nt);
                                }
                                if (!hasParsedCode(state.funct)) {
                                    error("E055", state.tokens.next, "esversion");
                                }
                                return;
                            }

                            var match = /^([+-])(W\d{3})$/g.exec(key);
                            if (match) {
                                state.ignored[match[2]] = (match[1] === "-");
                                return;
                            }

                            var tn;
                            if (val === "true" || val === "false") {
                                if (nt.type === "jslint") {
                                    tn = options.renamed[key] || key;
                                    state.option[tn] = (val === "true");

                                    if (options.inverted[tn] !== undefined) {
                                        state.option[tn] = !state.option[tn];
                                    }
                                } else {
                                    state.option[key] = (val === "true");
                                }

                                if (key === "newcap") {
                                    state.option["(explicitNewcap)"] = true;
                                }
                                return;
                            }

                            error("E002", nt);
                        });

                        assume();
                    }
                }

                function peek(p) {
                    var i = p || 0, j = lookahead.length, t;

                    if (i < j) {
                        return lookahead[i];
                    }

                    while (j <= i) {
                        t = lookahead[j];
                        if (!t) {
                            t = lookahead[j] = lex.token();
                        }
                        j += 1;
                    }
                    if (!t && state.tokens.next.id === "(end)") {
                        return state.tokens.next;
                    }

                    return t;
                }

                function peekIgnoreEOL() {
                    var i = 0;
                    var t;
                    do {
                        t = peek(i++);
                    } while (t.id === "(endline)");
                    return t;
                }

                function advance(id, t) {

                    switch (state.tokens.curr.id) {
                        case "(number)":
                            if (state.tokens.next.id === ".") {
                                warning("W005", state.tokens.curr);
                            }
                            break;
                        case "-":
                            if (state.tokens.next.id === "-" || state.tokens.next.id === "--") {
                                warning("W006");
                            }
                            break;
                        case "+":
                            if (state.tokens.next.id === "+" || state.tokens.next.id === "++") {
                                warning("W007");
                            }
                            break;
                    }

                    if (id && state.tokens.next.id !== id) {
                        if (t) {
                            if (state.tokens.next.id === "(end)") {
                                error("E019", t, t.id);
                            } else {
                                error("E020", state.tokens.next, id, t.id, t.line, state.tokens.next.value);
                            }
                        } else if (state.tokens.next.type !== "(identifier)" || state.tokens.next.value !== id) {
                            warning("W116", state.tokens.next, id, state.tokens.next.value);
                        }
                    }

                    state.tokens.prev = state.tokens.curr;
                    state.tokens.curr = state.tokens.next;
                    for (; ;) {
                        state.tokens.next = lookahead.shift() || lex.token();

                        if (!state.tokens.next) { // No more tokens left, give up
                            quit("E041", state.tokens.curr.line);
                        }

                        if (state.tokens.next.id === "(end)" || state.tokens.next.id === "(error)") {
                            return;
                        }

                        if (state.tokens.next.check) {
                            state.tokens.next.check();
                        }

                        if (state.tokens.next.isSpecial) {
                            if (state.tokens.next.type === "falls through") {
                                state.tokens.curr.caseFallsThrough = true;
                            } else {
                                doOption();
                            }
                        } else {
                            if (state.tokens.next.id !== "(endline)") {
                                break;
                            }
                        }
                    }
                }

                function isInfix(token) {
                    return token.infix || (!token.identifier && !token.template && !!token.led);
                }

                function isEndOfExpr() {
                    var curr = state.tokens.curr;
                    var next = state.tokens.next;
                    if (next.id === ";" || next.id === "}" || next.id === ":") {
                        return true;
                    }
                    if (isInfix(next) === isInfix(curr) || (curr.id === "yield" && state.inMoz())) {
                        return curr.line !== startLine(next);
                    }
                    return false;
                }

                function isBeginOfExpr(prev) {
                    return !prev.left && prev.arity !== "unary";
                }

                function expression(rbp, initial) {
                    var left, isArray = false, isObject = false, isLetExpr = false;

                    state.nameStack.push();
                    if (!initial && state.tokens.next.value === "let" && peek(0).value === "(") {
                        if (!state.inMoz()) {
                            warning("W118", state.tokens.next, "let expressions");
                        }
                        isLetExpr = true;
                        state.funct["(scope)"].stack();
                        advance("let");
                        advance("(");
                        state.tokens.prev.fud();
                        advance(")");
                    }

                    if (state.tokens.next.id === "(end)")
                        error("E006", state.tokens.curr);

                    var isDangerous =
                        state.option.asi &&
                        state.tokens.prev.line !== startLine(state.tokens.curr) &&
                        _.contains(["]", ")"], state.tokens.prev.id) &&
                        _.contains(["[", "("], state.tokens.curr.id);

                    if (isDangerous)
                        warning("W014", state.tokens.curr, state.tokens.curr.id);

                    advance();

                    if (initial) {
                        state.funct["(verb)"] = state.tokens.curr.value;
                        state.tokens.curr.beginsStmt = true;
                    }

                    if (initial === true && state.tokens.curr.fud) {
                        left = state.tokens.curr.fud();
                    } else {
                        if (state.tokens.curr.nud) {
                            left = state.tokens.curr.nud();
                        } else {
                            error("E030", state.tokens.curr, state.tokens.curr.id);
                        }
                        while ((rbp < state.tokens.next.lbp || state.tokens.next.type === "(template)") &&
                        !isEndOfExpr()) {
                            isArray = state.tokens.curr.value === "Array";
                            isObject = state.tokens.curr.value === "Object";
                            if (left && (left.value || (left.first && left.first.value))) {
                                if (left.value !== "new" ||
                                    (left.first && left.first.value && left.first.value === ".")) {
                                    isArray = false;
                                    if (left.value !== state.tokens.curr.value) {
                                        isObject = false;
                                    }
                                }
                            }

                            advance();

                            if (isArray && state.tokens.curr.id === "(" && state.tokens.next.id === ")") {
                                warning("W009", state.tokens.curr);
                            }

                            if (isObject && state.tokens.curr.id === "(" && state.tokens.next.id === ")") {
                                warning("W010", state.tokens.curr);
                            }

                            if (left && state.tokens.curr.led) {
                                left = state.tokens.curr.led(left);
                            } else {
                                error("E033", state.tokens.curr, state.tokens.curr.id);
                            }
                        }
                    }
                    if (isLetExpr) {
                        state.funct["(scope)"].unstack();
                    }

                    state.nameStack.pop();

                    return left;
                }

                function startLine(token) {
                    return token.startLine || token.line;
                }

                function nobreaknonadjacent(left, right) {
                    left = left || state.tokens.curr;
                    right = right || state.tokens.next;
                    if (!state.option.laxbreak && left.line !== startLine(right)) {
                        warning("W014", right, right.value);
                    }
                }

                function nolinebreak(t) {
                    t = t || state.tokens.curr;
                    if (t.line !== startLine(state.tokens.next)) {
                        warning("E022", t, t.value);
                    }
                }

                function nobreakcomma(left, right) {
                    if (left.line !== startLine(right)) {
                        if (!state.option.laxcomma) {
                            if (comma.first) {
                                warning("I001");
                                comma.first = false;
                            }
                            warning("W014", left, right.value);
                        }
                    }
                }

                function comma(opts) {
                    opts = opts || {};

                    if (!opts.peek) {
                        nobreakcomma(state.tokens.curr, state.tokens.next);
                        advance(",");
                    } else {
                        nobreakcomma(state.tokens.prev, state.tokens.curr);
                    }

                    if (state.tokens.next.identifier && !(opts.property && state.inES5())) {
                        switch (state.tokens.next.value) {
                            case "break":
                            case "case":
                            case "catch":
                            case "continue":
                            case "default":
                            case "do":
                            case "else":
                            case "finally":
                            case "for":
                            case "if":
                            case "in":
                            case "instanceof":
                            case "return":
                            case "switch":
                            case "throw":
                            case "try":
                            case "var":
                            case "let":
                            case "while":
                            case "with":
                                error("E024", state.tokens.next, state.tokens.next.value);
                                return false;
                        }
                    }

                    if (state.tokens.next.type === "(punctuator)") {
                        switch (state.tokens.next.value) {
                            case "}":
                            case "]":
                            case ",":
                                if (opts.allowTrailing) {
                                    return true;
                                }
                            case ")":
                                error("E024", state.tokens.next, state.tokens.next.value);
                                return false;
                        }
                    }
                    return true;
                }

                function symbol(s, p) {
                    var x = state.syntax[s];
                    if (!x || typeof x !== "object") {
                        state.syntax[s] = x = {
                            id: s,
                            lbp: p,
                            value: s
                        };
                    }
                    return x;
                }

                function delim(s) {
                    var x = symbol(s, 0);
                    x.delim = true;
                    return x;
                }

                function stmt(s, f) {
                    var x = delim(s);
                    x.identifier = x.reserved = true;
                    x.fud = f;
                    return x;
                }

                function blockstmt(s, f) {
                    var x = stmt(s, f);
                    x.block = true;
                    return x;
                }

                function reserveName(x) {
                    var c = x.id.charAt(0);
                    if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z")) {
                        x.identifier = x.reserved = true;
                    }
                    return x;
                }

                function prefix(s, f) {
                    var x = symbol(s, 150);
                    reserveName(x);

                    x.nud = (typeof f === "function") ? f : function () {
                        this.arity = "unary";
                        this.right = expression(150);

                        if (this.id === "++" || this.id === "--") {
                            if (state.option.plusplus) {
                                warning("W016", this, this.id);
                            } else if (this.right && (!this.right.identifier || isReserved(this.right)) &&
                                this.right.id !== "." && this.right.id !== "[") {
                                warning("W017", this);
                            }

                            if (this.right && this.right.isMetaProperty) {
                                error("E031", this);
                            } else if (this.right && this.right.identifier) {
                                state.funct["(scope)"].block.modify(this.right.value, this);
                            }
                        }

                        return this;
                    };

                    return x;
                }

                function type(s, f) {
                    var x = delim(s);
                    x.type = s;
                    x.nud = f;
                    return x;
                }

                function reserve(name, func) {
                    var x = type(name, func);
                    x.identifier = true;
                    x.reserved = true;
                    return x;
                }

                function FutureReservedWord(name, meta) {
                    var x = type(name, (meta && meta.nud) || function () {
                        return this;
                    });

                    meta = meta || {};
                    meta.isFutureReservedWord = true;

                    x.value = name;
                    x.identifier = true;
                    x.reserved = true;
                    x.meta = meta;

                    return x;
                }

                function reservevar(s, v) {
                    return reserve(s, function () {
                        if (typeof v === "function") {
                            v(this);
                        }
                        return this;
                    });
                }

                function infix(s, f, p, w) {
                    var x = symbol(s, p);
                    reserveName(x);
                    x.infix = true;
                    x.led = function (left) {
                        if (!w) {
                            nobreaknonadjacent(state.tokens.prev, state.tokens.curr);
                        }
                        if ((s === "in" || s === "instanceof") && left.id === "!") {
                            warning("W018", left, "!");
                        }
                        if (typeof f === "function") {
                            return f(left, this);
                        } else {
                            this.left = left;
                            this.right = expression(p);
                            return this;
                        }
                    };
                    return x;
                }

                function application(s) {
                    var x = symbol(s, 42);

                    x.led = function (left) {
                        nobreaknonadjacent(state.tokens.prev, state.tokens.curr);

                        this.left = left;
                        this.right = doFunction({type: "arrow", loneArg: left});
                        return this;
                    };
                    return x;
                }

                function relation(s, f) {
                    var x = symbol(s, 100);

                    x.led = function (left) {
                        nobreaknonadjacent(state.tokens.prev, state.tokens.curr);
                        this.left = left;
                        var right = this.right = expression(100);

                        if (isIdentifier(left, "NaN") || isIdentifier(right, "NaN")) {
                            warning("W019", this);
                        } else if (f) {
                            f.apply(this, [left, right]);
                        }

                        if (!left || !right) {
                            quit("E041", state.tokens.curr.line);
                        }

                        if (left.id === "!") {
                            warning("W018", left, "!");
                        }

                        if (right.id === "!") {
                            warning("W018", right, "!");
                        }

                        return this;
                    };
                    return x;
                }

                function isPoorRelation(node) {
                    return node &&
                        ((node.type === "(number)" && +node.value === 0) ||
                            (node.type === "(string)" && node.value === "") ||
                            (node.type === "null" && !state.option.eqnull) ||
                            node.type === "true" ||
                            node.type === "false" ||
                            node.type === "undefined");
                }

                var typeofValues = {};
                typeofValues.legacy = [
                    "xml",
                    "unknown"
                ];
                typeofValues.es3 = [
                    "undefined", "boolean", "number", "string", "function", "object",
                ];
                typeofValues.es3 = typeofValues.es3.concat(typeofValues.legacy);
                typeofValues.es6 = typeofValues.es3.concat("symbol");

                function isTypoTypeof(left, right, state) {
                    var values;

                    if (state.option.notypeof)
                        return false;

                    if (!left || !right)
                        return false;

                    values = state.inES6() ? typeofValues.es6 : typeofValues.es3;

                    if (right.type === "(identifier)" && right.value === "typeof" && left.type === "(string)")
                        return !_.contains(values, left.value);

                    return false;
                }

                function isGlobalEval(left, state) {
                    var isGlobal = false;
                    if (left.type === "this" && state.funct["(context)"] === null) {
                        isGlobal = true;
                    } else if (left.type === "(identifier)") {
                        if (state.option.node && left.value === "global") {
                            isGlobal = true;
                        } else if (state.option.browser && (left.value === "window" || left.value === "document")) {
                            isGlobal = true;
                        }
                    }

                    return isGlobal;
                }

                function findNativePrototype(left) {
                    var natives = [
                        "Array", "ArrayBuffer", "Boolean", "Collator", "DataView", "Date",
                        "DateTimeFormat", "Error", "EvalError", "Float32Array", "Float64Array",
                        "Function", "Infinity", "Intl", "Int16Array", "Int32Array", "Int8Array",
                        "Iterator", "Number", "NumberFormat", "Object", "RangeError",
                        "ReferenceError", "RegExp", "StopIteration", "String", "SyntaxError",
                        "TypeError", "Uint16Array", "Uint32Array", "Uint8Array", "Uint8ClampedArray",
                        "URIError"
                    ];

                    function walkPrototype(obj) {
                        if (typeof obj !== "object") return;
                        return obj.right === "prototype" ? obj : walkPrototype(obj.left);
                    }

                    function walkNative(obj) {
                        while (!obj.identifier && typeof obj.left === "object")
                            obj = obj.left;

                        if (obj.identifier && natives.indexOf(obj.value) >= 0)
                            return obj.value;
                    }

                    var prototype = walkPrototype(left);
                    if (prototype) return walkNative(prototype);
                }

                function checkLeftSideAssign(left, assignToken, options) {

                    var allowDestructuring = options && options.allowDestructuring;

                    assignToken = assignToken || left;

                    if (state.option.freeze) {
                        var nativeObject = findNativePrototype(left);
                        if (nativeObject)
                            warning("W121", left, nativeObject);
                    }

                    if (left.identifier && !left.isMetaProperty) {
                        state.funct["(scope)"].block.reassign(left.value, left);
                    }

                    if (left.id === ".") {
                        if (!left.left || left.left.value === "arguments" && !state.isStrict()) {
                            warning("E031", assignToken);
                        }

                        state.nameStack.set(state.tokens.prev);
                        return true;
                    } else if (left.id === "{" || left.id === "[") {
                        if (allowDestructuring && state.tokens.curr.left.destructAssign) {
                            state.tokens.curr.left.destructAssign.forEach(function (t) {
                                if (t.id) {
                                    state.funct["(scope)"].block.modify(t.id, t.token);
                                }
                            });
                        } else {
                            if (left.id === "{" || !left.left) {
                                warning("E031", assignToken);
                            } else if (left.left.value === "arguments" && !state.isStrict()) {
                                warning("E031", assignToken);
                            }
                        }

                        if (left.id === "[") {
                            state.nameStack.set(left.right);
                        }

                        return true;
                    } else if (left.isMetaProperty) {
                        error("E031", assignToken);
                        return true;
                    } else if (left.identifier && !isReserved(left)) {
                        if (state.funct["(scope)"].labeltype(left.value) === "exception") {
                            warning("W022", left);
                        }
                        state.nameStack.set(left);
                        return true;
                    }

                    if (left === state.syntax["function"]) {
                        warning("W023", state.tokens.curr);
                    }

                    return false;
                }

                function assignop(s, f, p) {
                    var x = infix(s, typeof f === "function" ? f : function (left, that) {
                        that.left = left;

                        if (left && checkLeftSideAssign(left, that, {allowDestructuring: true})) {
                            that.right = expression(10);
                            return that;
                        }

                        error("E031", that);
                    }, p);

                    x.exps = true;
                    x.assign = true;
                    return x;
                }


                function bitwise(s, f, p) {
                    var x = symbol(s, p);
                    reserveName(x);
                    x.led = (typeof f === "function") ? f : function (left) {
                        if (state.option.bitwise) {
                            warning("W016", this, this.id);
                        }
                        this.left = left;
                        this.right = expression(p);
                        return this;
                    };
                    return x;
                }

                function bitwiseassignop(s) {
                    return assignop(s, function (left, that) {
                        if (state.option.bitwise) {
                            warning("W016", that, that.id);
                        }

                        if (left && checkLeftSideAssign(left, that)) {
                            that.right = expression(10);
                            return that;
                        }
                        error("E031", that);
                    }, 20);
                }

                function suffix(s) {
                    var x = symbol(s, 150);

                    x.led = function (left) {
                        if (state.option.plusplus) {
                            warning("W016", this, this.id);
                        } else if ((!left.identifier || isReserved(left)) && left.id !== "." && left.id !== "[") {
                            warning("W017", this);
                        }

                        if (left.isMetaProperty) {
                            error("E031", this);
                        } else if (left && left.identifier) {
                            state.funct["(scope)"].block.modify(left.value, left);
                        }

                        this.left = left;
                        return this;
                    };
                    return x;
                }

                function optionalidentifier(fnparam, prop, preserve) {
                    if (!state.tokens.next.identifier) {
                        return;
                    }

                    if (!preserve) {
                        advance();
                    }

                    var curr = state.tokens.curr;
                    var val = state.tokens.curr.value;

                    if (!isReserved(curr)) {
                        return val;
                    }

                    if (prop) {
                        if (state.inES5()) {
                            return val;
                        }
                    }

                    if (fnparam && val === "undefined") {
                        return val;
                    }

                    warning("W024", state.tokens.curr, state.tokens.curr.id);
                    return val;
                }

                function identifier(fnparam, prop) {
                    var i = optionalidentifier(fnparam, prop, false);
                    if (i) {
                        return i;
                    }
                    if (state.tokens.next.value === "...") {
                        if (!state.inES6(true)) {
                            warning("W119", state.tokens.next, "spread/rest operator", "6");
                        }
                        advance();

                        if (checkPunctuator(state.tokens.next, "...")) {
                            warning("E024", state.tokens.next, "...");
                            while (checkPunctuator(state.tokens.next, "...")) {
                                advance();
                            }
                        }

                        if (!state.tokens.next.identifier) {
                            warning("E024", state.tokens.curr, "...");
                            return;
                        }

                        return identifier(fnparam, prop);
                    } else {
                        error("E030", state.tokens.next, state.tokens.next.value);
                        if (state.tokens.next.id !== ";") {
                            advance();
                        }
                    }
                }


                function reachable(controlToken) {
                    var i = 0, t;
                    if (state.tokens.next.id !== ";" || controlToken.inBracelessBlock) {
                        return;
                    }
                    for (; ;) {
                        do {
                            t = peek(i);
                            i += 1;
                        } while (t.id !== "(end)" && t.id === "(comment)");

                        if (t.reach) {
                            return;
                        }
                        if (t.id !== "(endline)") {
                            if (t.id === "function") {
                                if (state.option.latedef === true) {
                                    warning("W026", t);
                                }
                                break;
                            }

                            warning("W027", t, t.value, controlToken.value);
                            break;
                        }
                    }
                }

                function parseFinalSemicolon() {
                    if (state.tokens.next.id !== ";") {
                        if (state.tokens.next.isUnclosed) return advance();

                        var sameLine = startLine(state.tokens.next) === state.tokens.curr.line &&
                            state.tokens.next.id !== "(end)";
                        var blockEnd = checkPunctuator(state.tokens.next, "}");

                        if (sameLine && !blockEnd) {
                            errorAt("E058", state.tokens.curr.line, state.tokens.curr.character);
                        } else if (!state.option.asi) {
                            if ((blockEnd && !state.option.lastsemic) || !sameLine) {
                                warningAt("W033", state.tokens.curr.line, state.tokens.curr.character);
                            }
                        }
                    } else {
                        advance(";");
                    }
                }

                function statement() {
                    var i = indent, r, t = state.tokens.next, hasOwnScope = false;

                    if (t.id === ";") {
                        advance(";");
                        return;
                    }
                    var res = isReserved(t);

                    if (res && t.meta && t.meta.isFutureReservedWord && peek().id === ":") {
                        warning("W024", t, t.id);
                        res = false;
                    }

                    if (t.identifier && !res && peek().id === ":") {
                        advance();
                        advance(":");

                        hasOwnScope = true;
                        state.funct["(scope)"].stack();
                        state.funct["(scope)"].block.addBreakLabel(t.value, {token: state.tokens.curr});

                        if (!state.tokens.next.labelled && state.tokens.next.value !== "{") {
                            warning("W028", state.tokens.next, t.value, state.tokens.next.value);
                        }

                        state.tokens.next.label = t.value;
                        t = state.tokens.next;
                    }

                    if (t.id === "{") {
                        var iscase = (state.funct["(verb)"] === "case" && state.tokens.curr.value === ":");
                        block(true, true, false, false, iscase);
                        return;
                    }

                    r = expression(0, true);

                    if (r && !(r.identifier && r.value === "function") &&
                        !(r.type === "(punctuator)" && r.left &&
                            r.left.identifier && r.left.value === "function")) {
                        if (!state.isStrict() &&
                            state.option.strict === "global") {
                            warning("E007");
                        }
                    }

                    if (!t.block) {
                        if (!state.option.expr && (!r || !r.exps)) {
                            warning("W030", state.tokens.curr);
                        } else if (state.option.nonew && r && r.left && r.id === "(" && r.left.id === "new") {
                            warning("W031", t);
                        }
                        parseFinalSemicolon();
                    }

                    indent = i;
                    if (hasOwnScope) {
                        state.funct["(scope)"].unstack();
                    }
                    return r;
                }


                function statements() {
                    var a = [], p;

                    while (!state.tokens.next.reach && state.tokens.next.id !== "(end)") {
                        if (state.tokens.next.id === ";") {
                            p = peek();

                            if (!p || (p.id !== "(" && p.id !== "[")) {
                                warning("W032");
                            }

                            advance(";");
                        } else {
                            a.push(statement());
                        }
                    }
                    return a;
                }

                function directives() {
                    var i, p, pn;

                    while (state.tokens.next.id === "(string)") {
                        p = peek(0);
                        if (p.id === "(endline)") {
                            i = 1;
                            do {
                                pn = peek(i++);
                            } while (pn.id === "(endline)");
                            if (pn.id === ";") {
                                p = pn;
                            } else if (pn.value === "[" || pn.value === ".") {
                                break;
                            } else if (!state.option.asi || pn.value === "(") {
                                warning("W033", state.tokens.next);
                            }
                        } else if (p.id === "." || p.id === "[") {
                            break;
                        } else if (p.id !== ";") {
                            warning("W033", p);
                        }

                        advance();
                        var directive = state.tokens.curr.value;
                        if (state.directive[directive] ||
                            (directive === "use strict" && state.option.strict === "implied")) {
                            warning("W034", state.tokens.curr, directive);
                        }
                        state.directive[directive] = true;

                        if (p.id === ";") {
                            advance(";");
                        }
                    }

                    if (state.isStrict()) {
                        if (!state.option["(explicitNewcap)"]) {
                            state.option.newcap = true;
                        }
                        state.option.undef = true;
                    }
                }

                function block(ordinary, stmt, isfunc, isfatarrow, iscase) {
                    var a,
                        b = inblock,
                        old_indent = indent,
                        m,
                        t,
                        line,
                        d;

                    inblock = ordinary;

                    t = state.tokens.next;

                    var metrics = state.funct["(metrics)"];
                    metrics.nestedBlockDepth += 1;
                    metrics.verifyMaxNestedBlockDepthPerFunction();

                    if (state.tokens.next.id === "{") {
                        advance("{");
                        state.funct["(scope)"].stack();

                        line = state.tokens.curr.line;
                        if (state.tokens.next.id !== "}") {
                            indent += state.option.indent;
                            while (!ordinary && state.tokens.next.from > indent) {
                                indent += state.option.indent;
                            }

                            if (isfunc) {
                                m = {};
                                for (d in state.directive) {
                                    if (_.has(state.directive, d)) {
                                        m[d] = state.directive[d];
                                    }
                                }
                                directives();

                                if (state.option.strict && state.funct["(context)"]["(global)"]) {
                                    if (!m["use strict"] && !state.isStrict()) {
                                        warning("E007");
                                    }
                                }
                            }

                            a = statements();

                            metrics.statementCount += a.length;

                            indent -= state.option.indent;
                        }

                        advance("}", t);

                        if (isfunc) {
                            state.funct["(scope)"].validateParams();
                            if (m) {
                                state.directive = m;
                            }
                        }

                        state.funct["(scope)"].unstack();

                        indent = old_indent;
                    } else if (!ordinary) {
                        if (isfunc) {
                            state.funct["(scope)"].stack();

                            m = {};
                            if (stmt && !isfatarrow && !state.inMoz()) {
                                error("W118", state.tokens.curr, "function closure expressions");
                            }

                            if (!stmt) {
                                for (d in state.directive) {
                                    if (_.has(state.directive, d)) {
                                        m[d] = state.directive[d];
                                    }
                                }
                            }
                            expression(10);

                            if (state.option.strict && state.funct["(context)"]["(global)"]) {
                                if (!m["use strict"] && !state.isStrict()) {
                                    warning("E007");
                                }
                            }

                            state.funct["(scope)"].unstack();
                        } else {
                            error("E021", state.tokens.next, "{", state.tokens.next.value);
                        }
                    } else {
                        state.funct["(noblockscopedvar)"] = state.tokens.next.id !== "for";
                        state.funct["(scope)"].stack();

                        if (!stmt || state.option.curly) {
                            warning("W116", state.tokens.next, "{", state.tokens.next.value);
                        }

                        state.tokens.next.inBracelessBlock = true;
                        indent += state.option.indent;
                        a = [statement()];
                        indent -= state.option.indent;

                        state.funct["(scope)"].unstack();
                        delete state.funct["(noblockscopedvar)"];
                    }
                    switch (state.funct["(verb)"]) {
                        case "break":
                        case "continue":
                        case "return":
                        case "throw":
                            if (iscase) {
                                break;
                            }
                        default:
                            state.funct["(verb)"] = null;
                    }

                    inblock = b;
                    if (ordinary && state.option.noempty && (!a || a.length === 0)) {
                        warning("W035", state.tokens.prev);
                    }
                    metrics.nestedBlockDepth -= 1;
                    return a;
                }


                function countMember(m) {
                    if (membersOnly && typeof membersOnly[m] !== "boolean") {
                        warning("W036", state.tokens.curr, m);
                    }
                    if (typeof member[m] === "number") {
                        member[m] += 1;
                    } else {
                        member[m] = 1;
                    }
                }

                type("(number)", function () {
                    return this;
                });

                type("(string)", function () {
                    return this;
                });

                state.syntax["(identifier)"] = {
                    type: "(identifier)",
                    lbp: 0,
                    identifier: true,

                    nud: function () {
                        var v = this.value;
                        if (state.tokens.next.id === "=>") {
                            return this;
                        }

                        if (!state.funct["(comparray)"].check(v)) {
                            state.funct["(scope)"].block.use(v, state.tokens.curr);
                        }
                        return this;
                    },

                    led: function () {
                        error("E033", state.tokens.next, state.tokens.next.value);
                    }
                };

                var baseTemplateSyntax = {
                    lbp: 0,
                    identifier: false,
                    template: true,
                };
                state.syntax["(template)"] = _.extend({
                    type: "(template)",
                    nud: doTemplateLiteral,
                    led: doTemplateLiteral,
                    noSubst: false
                }, baseTemplateSyntax);

                state.syntax["(template middle)"] = _.extend({
                    type: "(template middle)",
                    middle: true,
                    noSubst: false
                }, baseTemplateSyntax);

                state.syntax["(template tail)"] = _.extend({
                    type: "(template tail)",
                    tail: true,
                    noSubst: false
                }, baseTemplateSyntax);

                state.syntax["(no subst template)"] = _.extend({
                    type: "(template)",
                    nud: doTemplateLiteral,
                    led: doTemplateLiteral,
                    noSubst: true,
                    tail: true // mark as tail, since it's always the last component
                }, baseTemplateSyntax);

                type("(regexp)", function () {
                    return this;
                });

                delim("(endline)");
                delim("(begin)");
                delim("(end)").reach = true;
                delim("(error)").reach = true;
                delim("}").reach = true;
                delim(")");
                delim("]");
                delim("\"").reach = true;
                delim("'").reach = true;
                delim(";");
                delim(":").reach = true;
                delim("#");

                reserve("else");
                reserve("case").reach = true;
                reserve("catch");
                reserve("default").reach = true;
                reserve("finally");
                reservevar("arguments", function (x) {
                    if (state.isStrict() && state.funct["(global)"]) {
                        warning("E008", x);
                    }
                });
                reservevar("eval");
                reservevar("false");
                reservevar("Infinity");
                reservevar("null");
                reservevar("this", function (x) {
                    if (state.isStrict() && !isMethod() &&
                        !state.option.validthis && ((state.funct["(statement)"] &&
                            state.funct["(name)"].charAt(0) > "Z") || state.funct["(global)"])) {
                        warning("W040", x);
                    }
                });
                reservevar("true");
                reservevar("undefined");

                assignop("=", "assign", 20);
                assignop("+=", "assignadd", 20);
                assignop("-=", "assignsub", 20);
                assignop("*=", "assignmult", 20);
                assignop("/=", "assigndiv", 20).nud = function () {
                    error("E014");
                };
                assignop("%=", "assignmod", 20);

                bitwiseassignop("&=");
                bitwiseassignop("|=");
                bitwiseassignop("^=");
                bitwiseassignop("<<=");
                bitwiseassignop(">>=");
                bitwiseassignop(">>>=");
                infix(",", function (left, that) {
                    var expr;
                    that.exprs = [left];

                    if (state.option.nocomma) {
                        warning("W127");
                    }

                    if (!comma({peek: true})) {
                        return that;
                    }
                    while (true) {
                        if (!(expr = expression(10))) {
                            break;
                        }
                        that.exprs.push(expr);
                        if (state.tokens.next.value !== "," || !comma()) {
                            break;
                        }
                    }
                    return that;
                }, 10, true);

                infix("?", function (left, that) {
                    increaseComplexityCount();
                    that.left = left;
                    that.right = expression(10);
                    advance(":");
                    that["else"] = expression(10);
                    return that;
                }, 30);

                var orPrecendence = 40;
                infix("||", function (left, that) {
                    increaseComplexityCount();
                    that.left = left;
                    that.right = expression(orPrecendence);
                    return that;
                }, orPrecendence);
                infix("&&", "and", 50);
                bitwise("|", "bitor", 70);
                bitwise("^", "bitxor", 80);
                bitwise("&", "bitand", 90);
                relation("==", function (left, right) {
                    var eqnull = state.option.eqnull &&
                        ((left && left.value) === "null" || (right && right.value) === "null");

                    switch (true) {
                        case !eqnull && state.option.eqeqeq:
                            this.from = this.character;
                            warning("W116", this, "===", "==");
                            break;
                        case isPoorRelation(left):
                            warning("W041", this, "===", left.value);
                            break;
                        case isPoorRelation(right):
                            warning("W041", this, "===", right.value);
                            break;
                        case isTypoTypeof(right, left, state):
                            warning("W122", this, right.value);
                            break;
                        case isTypoTypeof(left, right, state):
                            warning("W122", this, left.value);
                            break;
                    }

                    return this;
                });
                relation("===", function (left, right) {
                    if (isTypoTypeof(right, left, state)) {
                        warning("W122", this, right.value);
                    } else if (isTypoTypeof(left, right, state)) {
                        warning("W122", this, left.value);
                    }
                    return this;
                });
                relation("!=", function (left, right) {
                    var eqnull = state.option.eqnull &&
                        ((left && left.value) === "null" || (right && right.value) === "null");

                    if (!eqnull && state.option.eqeqeq) {
                        this.from = this.character;
                        warning("W116", this, "!==", "!=");
                    } else if (isPoorRelation(left)) {
                        warning("W041", this, "!==", left.value);
                    } else if (isPoorRelation(right)) {
                        warning("W041", this, "!==", right.value);
                    } else if (isTypoTypeof(right, left, state)) {
                        warning("W122", this, right.value);
                    } else if (isTypoTypeof(left, right, state)) {
                        warning("W122", this, left.value);
                    }
                    return this;
                });
                relation("!==", function (left, right) {
                    if (isTypoTypeof(right, left, state)) {
                        warning("W122", this, right.value);
                    } else if (isTypoTypeof(left, right, state)) {
                        warning("W122", this, left.value);
                    }
                    return this;
                });
                relation("<");
                relation(">");
                relation("<=");
                relation(">=");
                bitwise("<<", "shiftleft", 120);
                bitwise(">>", "shiftright", 120);
                bitwise(">>>", "shiftrightunsigned", 120);
                infix("in", "in", 120);
                infix("instanceof", "instanceof", 120);
                infix("+", function (left, that) {
                    var right;
                    that.left = left;
                    that.right = right = expression(130);

                    if (left && right && left.id === "(string)" && right.id === "(string)") {
                        left.value += right.value;
                        left.character = right.character;
                        if (!state.option.scripturl && reg.javascriptURL.test(left.value)) {
                            warning("W050", left);
                        }
                        return left;
                    }

                    return that;
                }, 130);
                prefix("+", "num");
                prefix("+++", function () {
                    warning("W007");
                    this.arity = "unary";
                    this.right = expression(150);
                    return this;
                });
                infix("+++", function (left) {
                    warning("W007");
                    this.left = left;
                    this.right = expression(130);
                    return this;
                }, 130);
                infix("-", "sub", 130);
                prefix("-", "neg");
                prefix("---", function () {
                    warning("W006");
                    this.arity = "unary";
                    this.right = expression(150);
                    return this;
                });
                infix("---", function (left) {
                    warning("W006");
                    this.left = left;
                    this.right = expression(130);
                    return this;
                }, 130);
                infix("*", "mult", 140);
                infix("/", "div", 140);
                infix("%", "mod", 140);

                suffix("++");
                prefix("++", "preinc");
                state.syntax["++"].exps = true;

                suffix("--");
                prefix("--", "predec");
                state.syntax["--"].exps = true;
                prefix("delete", function () {
                    var p = expression(10);
                    if (!p) {
                        return this;
                    }

                    if (p.id !== "." && p.id !== "[") {
                        warning("W051");
                    }
                    this.first = p;
                    if (p.identifier && !state.isStrict()) {
                        p.forgiveUndef = true;
                    }
                    return this;
                }).exps = true;

                prefix("~", function () {
                    if (state.option.bitwise) {
                        warning("W016", this, "~");
                    }
                    this.arity = "unary";
                    this.right = expression(150);
                    return this;
                });

                prefix("...", function () {
                    if (!state.inES6(true)) {
                        warning("W119", this, "spread/rest operator", "6");
                    }
                    if (!state.tokens.next.identifier &&
                        state.tokens.next.type !== "(string)" &&
                        !checkPunctuators(state.tokens.next, ["[", "("])) {

                        error("E030", state.tokens.next, state.tokens.next.value);
                    }
                    expression(150);
                    return this;
                });

                prefix("!", function () {
                    this.arity = "unary";
                    this.right = expression(150);

                    if (!this.right) { // '!' followed by nothing? Give up.
                        quit("E041", this.line || 0);
                    }

                    if (bang[this.right.id] === true) {
                        warning("W018", this, "!");
                    }
                    return this;
                });

                prefix("typeof", (function () {
                    var p = expression(150);
                    this.first = this.right = p;

                    if (!p) { // 'typeof' followed by nothing? Give up.
                        quit("E041", this.line || 0, this.character || 0);
                    }
                    if (p.identifier) {
                        p.forgiveUndef = true;
                    }
                    return this;
                }));
                prefix("new", function () {
                    var mp = metaProperty("target", function () {
                        if (!state.inES6(true)) {
                            warning("W119", state.tokens.prev, "new.target", "6");
                        }
                        var inFunction, c = state.funct;
                        while (c) {
                            inFunction = !c["(global)"];
                            if (!c["(arrow)"]) {
                                break;
                            }
                            c = c["(context)"];
                        }
                        if (!inFunction) {
                            warning("W136", state.tokens.prev, "new.target");
                        }
                    });
                    if (mp) {
                        return mp;
                    }

                    var c = expression(155), i;
                    if (c && c.id !== "function") {
                        if (c.identifier) {
                            c["new"] = true;
                            switch (c.value) {
                                case "Number":
                                case "String":
                                case "Boolean":
                                case "Math":
                                case "JSON":
                                    warning("W053", state.tokens.prev, c.value);
                                    break;
                                case "Symbol":
                                    if (state.inES6()) {
                                        warning("W053", state.tokens.prev, c.value);
                                    }
                                    break;
                                case "Function":
                                    if (!state.option.evil) {
                                        warning("W054");
                                    }
                                    break;
                                case "Date":
                                case "RegExp":
                                case "this":
                                    break;
                                default:
                                    if (c.id !== "function") {
                                        i = c.value.substr(0, 1);
                                        if (state.option.newcap && (i < "A" || i > "Z") &&
                                            !state.funct["(scope)"].isPredefined(c.value)) {
                                            warning("W055", state.tokens.curr);
                                        }
                                    }
                            }
                        } else {
                            if (c.id !== "." && c.id !== "[" && c.id !== "(") {
                                warning("W056", state.tokens.curr);
                            }
                        }
                    } else {
                        if (!state.option.supernew)
                            warning("W057", this);
                    }
                    if (state.tokens.next.id !== "(" && !state.option.supernew) {
                        warning("W058", state.tokens.curr, state.tokens.curr.value);
                    }
                    this.first = this.right = c;
                    return this;
                });
                state.syntax["new"].exps = true;

                prefix("void").exps = true;

                infix(".", function (left, that) {
                    var m = identifier(false, true);

                    if (typeof m === "string") {
                        countMember(m);
                    }

                    that.left = left;
                    that.right = m;

                    if (m && m === "hasOwnProperty" && state.tokens.next.value === "=") {
                        warning("W001");
                    }

                    if (left && left.value === "arguments" && (m === "callee" || m === "caller")) {
                        if (state.option.noarg)
                            warning("W059", left, m);
                        else if (state.isStrict())
                            error("E008");
                    } else if (!state.option.evil && left && left.value === "document" &&
                        (m === "write" || m === "writeln")) {
                        warning("W060", left);
                    }

                    if (!state.option.evil && (m === "eval" || m === "execScript")) {
                        if (isGlobalEval(left, state)) {
                            warning("W061");
                        }
                    }

                    return that;
                }, 160, true);

                infix("(", function (left, that) {
                    if (state.option.immed && left && !left.immed && left.id === "function") {
                        warning("W062");
                    }

                    var n = 0;
                    var p = [];

                    if (left) {
                        if (left.type === "(identifier)") {
                            if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) {
                                if ("Array Number String Boolean Date Object Error Symbol".indexOf(left.value) === -1) {
                                    if (left.value === "Math") {
                                        warning("W063", left);
                                    } else if (state.option.newcap) {
                                        warning("W064", left);
                                    }
                                }
                            }
                        }
                    }

                    if (state.tokens.next.id !== ")") {
                        for (; ;) {
                            p[p.length] = expression(10);
                            n += 1;
                            if (state.tokens.next.id !== ",") {
                                break;
                            }
                            comma();
                        }
                    }

                    advance(")");

                    if (typeof left === "object") {
                        if (!state.inES5() && left.value === "parseInt" && n === 1) {
                            warning("W065", state.tokens.curr);
                        }
                        if (!state.option.evil) {
                            if (left.value === "eval" || left.value === "Function" ||
                                left.value === "execScript") {
                                warning("W061", left);

                                if (p[0] && [0].id === "(string)") {
                                    addInternalSrc(left, p[0].value);
                                }
                            } else if (p[0] && p[0].id === "(string)" &&
                                (left.value === "setTimeout" ||
                                    left.value === "setInterval")) {
                                warning("W066", left);
                                addInternalSrc(left, p[0].value);
                            } else if (p[0] && p[0].id === "(string)" &&
                                left.value === "." &&
                                left.left.value === "window" &&
                                (left.right === "setTimeout" ||
                                    left.right === "setInterval")) {
                                warning("W066", left);
                                addInternalSrc(left, p[0].value);
                            }
                        }
                        if (!left.identifier && left.id !== "." && left.id !== "[" && left.id !== "=>" &&
                            left.id !== "(" && left.id !== "&&" && left.id !== "||" && left.id !== "?" &&
                            !(state.inES6() && left["(name)"])) {
                            warning("W067", that);
                        }
                    }

                    that.left = left;
                    return that;
                }, 155, true).exps = true;

                prefix("(", function () {
                    var pn = state.tokens.next, pn1, i = -1;
                    var ret, triggerFnExpr, first, last;
                    var parens = 1;
                    var opening = state.tokens.curr;
                    var preceeding = state.tokens.prev;
                    var isNecessary = !state.option.singleGroups;

                    do {
                        if (pn.value === "(") {
                            parens += 1;
                        } else if (pn.value === ")") {
                            parens -= 1;
                        }

                        i += 1;
                        pn1 = pn;
                        pn = peek(i);
                    } while (!(parens === 0 && pn1.value === ")") && pn.value !== ";" && pn.type !== "(end)");

                    if (state.tokens.next.id === "function") {
                        triggerFnExpr = state.tokens.next.immed = true;
                    }
                    if (pn.value === "=>") {
                        return doFunction({type: "arrow", parsedOpening: true});
                    }

                    var exprs = [];

                    if (state.tokens.next.id !== ")") {
                        for (; ;) {
                            exprs.push(expression(10));

                            if (state.tokens.next.id !== ",") {
                                break;
                            }

                            if (state.option.nocomma) {
                                warning("W127");
                            }

                            comma();
                        }
                    }

                    advance(")", this);
                    if (state.option.immed && exprs[0] && exprs[0].id === "function") {
                        if (state.tokens.next.id !== "(" &&
                            state.tokens.next.id !== "." && state.tokens.next.id !== "[") {
                            warning("W068", this);
                        }
                    }

                    if (!exprs.length) {
                        return;
                    }
                    if (exprs.length > 1) {
                        ret = Object.create(state.syntax[","]);
                        ret.exprs = exprs;

                        first = exprs[0];
                        last = exprs[exprs.length - 1];

                        if (!isNecessary) {
                            isNecessary = preceeding.assign || preceeding.delim;
                        }
                    } else {
                        ret = first = last = exprs[0];

                        if (!isNecessary) {
                            isNecessary =
                                (opening.beginsStmt && (ret.id === "{" || triggerFnExpr || isFunctor(ret))) ||
                                (triggerFnExpr &&
                                    (!isEndOfExpr() || state.tokens.prev.id !== "}")) ||
                                (isFunctor(ret) && !isEndOfExpr()) ||
                                (ret.id === "{" && preceeding.id === "=>") ||
                                (ret.type === "(number)" &&
                                    checkPunctuator(pn, ".") && /^\d+$/.test(ret.value));
                        }
                    }

                    if (ret) {
                        if (!isNecessary && (first.left || first.right || ret.exprs)) {
                            isNecessary =
                                (!isBeginOfExpr(preceeding) && first.lbp <= preceeding.lbp) ||
                                (!isEndOfExpr() && last.lbp < state.tokens.next.lbp);
                        }

                        if (!isNecessary) {
                            warning("W126", opening);
                        }

                        ret.paren = true;
                    }

                    return ret;
                });

                application("=>");

                infix("[", function (left, that) {
                    var e = expression(10), s;
                    if (e && e.type === "(string)") {
                        if (!state.option.evil && (e.value === "eval" || e.value === "execScript")) {
                            if (isGlobalEval(left, state)) {
                                warning("W061");
                            }
                        }

                        countMember(e.value);
                        if (!state.option.sub && reg.identifier.test(e.value)) {
                            s = state.syntax[e.value];
                            if (!s || !isReserved(s)) {
                                warning("W069", state.tokens.prev, e.value);
                            }
                        }
                    }
                    advance("]", that);

                    if (e && e.value === "hasOwnProperty" && state.tokens.next.value === "=") {
                        warning("W001");
                    }

                    that.left = left;
                    that.right = e;
                    return that;
                }, 160, true);

                function comprehensiveArrayExpression() {
                    var res = {};
                    res.exps = true;
                    state.funct["(comparray)"].stack();
                    var reversed = false;
                    if (state.tokens.next.value !== "for") {
                        reversed = true;
                        if (!state.inMoz()) {
                            warning("W116", state.tokens.next, "for", state.tokens.next.value);
                        }
                        state.funct["(comparray)"].setState("use");
                        res.right = expression(10);
                    }

                    advance("for");
                    if (state.tokens.next.value === "each") {
                        advance("each");
                        if (!state.inMoz()) {
                            warning("W118", state.tokens.curr, "for each");
                        }
                    }
                    advance("(");
                    state.funct["(comparray)"].setState("define");
                    res.left = expression(130);
                    if (_.contains(["in", "of"], state.tokens.next.value)) {
                        advance();
                    } else {
                        error("E045", state.tokens.curr);
                    }
                    state.funct["(comparray)"].setState("generate");
                    expression(10);

                    advance(")");
                    if (state.tokens.next.value === "if") {
                        advance("if");
                        advance("(");
                        state.funct["(comparray)"].setState("filter");
                        res.filter = expression(10);
                        advance(")");
                    }

                    if (!reversed) {
                        state.funct["(comparray)"].setState("use");
                        res.right = expression(10);
                    }

                    advance("]");
                    state.funct["(comparray)"].unstack();
                    return res;
                }

                prefix("[", function () {
                    var blocktype = lookupBlockType();
                    if (blocktype.isCompArray) {
                        if (!state.option.esnext && !state.inMoz()) {
                            warning("W118", state.tokens.curr, "array comprehension");
                        }
                        return comprehensiveArrayExpression();
                    } else if (blocktype.isDestAssign) {
                        this.destructAssign = destructuringPattern({openingParsed: true, assignment: true});
                        return this;
                    }
                    var b = state.tokens.curr.line !== startLine(state.tokens.next);
                    this.first = [];
                    if (b) {
                        indent += state.option.indent;
                        if (state.tokens.next.from === indent + state.option.indent) {
                            indent += state.option.indent;
                        }
                    }
                    while (state.tokens.next.id !== "(end)") {
                        while (state.tokens.next.id === ",") {
                            if (!state.option.elision) {
                                if (!state.inES5()) {
                                    warning("W070");
                                } else {
                                    warning("W128");
                                    do {
                                        advance(",");
                                    } while (state.tokens.next.id === ",");
                                    continue;
                                }
                            }
                            advance(",");
                        }

                        if (state.tokens.next.id === "]") {
                            break;
                        }

                        this.first.push(expression(10));
                        if (state.tokens.next.id === ",") {
                            comma({allowTrailing: true});
                            if (state.tokens.next.id === "]" && !state.inES5()) {
                                warning("W070", state.tokens.curr);
                                break;
                            }
                        } else {
                            break;
                        }
                    }
                    if (b) {
                        indent -= state.option.indent;
                    }
                    advance("]", this);
                    return this;
                });


                function isMethod() {
                    return state.funct["(statement)"] && state.funct["(statement)"].type === "class" ||
                        state.funct["(context)"] && state.funct["(context)"]["(verb)"] === "class";
                }


                function isPropertyName(token) {
                    return token.identifier || token.id === "(string)" || token.id === "(number)";
                }


                function propertyName(preserveOrToken) {
                    var id;
                    var preserve = true;
                    if (typeof preserveOrToken === "object") {
                        id = preserveOrToken;
                    } else {
                        preserve = preserveOrToken;
                        id = optionalidentifier(false, true, preserve);
                    }

                    if (!id) {
                        if (state.tokens.next.id === "(string)") {
                            id = state.tokens.next.value;
                            if (!preserve) {
                                advance();
                            }
                        } else if (state.tokens.next.id === "(number)") {
                            id = state.tokens.next.value.toString();
                            if (!preserve) {
                                advance();
                            }
                        }
                    } else if (typeof id === "object") {
                        if (id.id === "(string)" || id.id === "(identifier)") id = id.value;
                        else if (id.id === "(number)") id = id.value.toString();
                    }

                    if (id === "hasOwnProperty") {
                        warning("W001");
                    }

                    return id;
                }

                function functionparams(options) {
                    var next;
                    var paramsIds = [];
                    var ident;
                    var tokens = [];
                    var t;
                    var pastDefault = false;
                    var pastRest = false;
                    var arity = 0;
                    var loneArg = options && options.loneArg;

                    if (loneArg && loneArg.identifier === true) {
                        state.funct["(scope)"].addParam(loneArg.value, loneArg);
                        return {arity: 1, params: [loneArg.value]};
                    }

                    next = state.tokens.next;

                    if (!options || !options.parsedOpening) {
                        advance("(");
                    }

                    if (state.tokens.next.id === ")") {
                        advance(")");
                        return;
                    }

                    function addParam(addParamArgs) {
                        state.funct["(scope)"].addParam.apply(state.funct["(scope)"], addParamArgs);
                    }

                    for (; ;) {
                        arity++;
                        var currentParams = [];

                        if (_.contains(["{", "["], state.tokens.next.id)) {
                            tokens = destructuringPattern();
                            for (t in tokens) {
                                t = tokens[t];
                                if (t.id) {
                                    paramsIds.push(t.id);
                                    currentParams.push([t.id, t.token]);
                                }
                            }
                        } else {
                            if (checkPunctuator(state.tokens.next, "...")) pastRest = true;
                            ident = identifier(true);
                            if (ident) {
                                paramsIds.push(ident);
                                currentParams.push([ident, state.tokens.curr]);
                            } else {
                                while (!checkPunctuators(state.tokens.next, [",", ")"])) advance();
                            }
                        }
                        if (pastDefault) {
                            if (state.tokens.next.id !== "=") {
                                error("W138", state.tokens.current);
                            }
                        }
                        if (state.tokens.next.id === "=") {
                            if (!state.inES6()) {
                                warning("W119", state.tokens.next, "default parameters", "6");
                            }
                            advance("=");
                            pastDefault = true;
                            expression(10);
                        }
                        currentParams.forEach(addParam);

                        if (state.tokens.next.id === ",") {
                            if (pastRest) {
                                warning("W131", state.tokens.next);
                            }
                            comma();
                        } else {
                            advance(")", next);
                            return {arity: arity, params: paramsIds};
                        }
                    }
                }

                function functor(name, token, overwrites) {
                    var funct = {
                        "(name)": name,
                        "(breakage)": 0,
                        "(loopage)": 0,
                        "(tokens)": {},
                        "(properties)": {},

                        "(catch)": false,
                        "(global)": false,

                        "(line)": null,
                        "(character)": null,
                        "(metrics)": null,
                        "(statement)": null,
                        "(context)": null,
                        "(scope)": null,
                        "(comparray)": null,
                        "(generator)": null,
                        "(arrow)": null,
                        "(params)": null
                    };

                    if (token) {
                        _.extend(funct, {
                            "(line)": token.line,
                            "(character)": token.character,
                            "(metrics)": createMetrics(token)
                        });
                    }

                    _.extend(funct, overwrites);

                    if (funct["(context)"]) {
                        funct["(scope)"] = funct["(context)"]["(scope)"];
                        funct["(comparray)"] = funct["(context)"]["(comparray)"];
                    }

                    return funct;
                }

                function isFunctor(token) {
                    return "(scope)" in token;
                }

                function hasParsedCode(funct) {
                    return funct["(global)"] && !funct["(verb)"];
                }

                function doTemplateLiteral(left) {
                    var ctx = this.context;
                    var noSubst = this.noSubst;
                    var depth = this.depth;

                    if (!noSubst) {
                        while (!end()) {
                            if (!state.tokens.next.template || state.tokens.next.depth > depth) {
                                expression(0); // should probably have different rbp?
                            } else {
                                advance();
                            }
                        }
                    }

                    return {
                        id: "(template)",
                        type: "(template)",
                        tag: left
                    };

                    function end() {
                        if (state.tokens.curr.template && state.tokens.curr.tail &&
                            state.tokens.curr.context === ctx) return true;
                        var complete = (state.tokens.next.template && state.tokens.next.tail &&
                            state.tokens.next.context === ctx);
                        if (complete) advance();
                        return complete || state.tokens.next.isUnclosed;
                    }
                }

                function doFunction(options) {
                    var f, token, name, statement, classExprBinding, isGenerator, isArrow, ignoreLoopFunc;
                    var oldOption = state.option;
                    var oldIgnored = state.ignored;

                    if (options) {
                        name = options.name;
                        statement = options.statement;
                        classExprBinding = options.classExprBinding;
                        isGenerator = options.type === "generator";
                        isArrow = options.type === "arrow";
                        ignoreLoopFunc = options.ignoreLoopFunc;
                    }

                    state.option = Object.create(state.option);
                    state.ignored = Object.create(state.ignored);

                    state.funct = functor(name || state.nameStack.infer(), state.tokens.next, {
                        "(statement)": statement,
                        "(context)": state.funct,
                        "(arrow)": isArrow,
                        "(generator)": isGenerator
                    });

                    f = state.funct;
                    token = state.tokens.curr;
                    token.funct = state.funct;

                    functions.push(state.funct);
                    state.funct["(scope)"].stack("functionouter");
                    var internallyAccessibleName = name || classExprBinding;
                    if (internallyAccessibleName) {
                        state.funct["(scope)"].block.add(internallyAccessibleName,
                            classExprBinding ? "class" : "function", state.tokens.curr, false);
                    }
                    state.funct["(scope)"].stack("functionparams");

                    var paramsInfo = functionparams(options);

                    if (paramsInfo) {
                        state.funct["(params)"] = paramsInfo.params;
                        state.funct["(metrics)"].arity = paramsInfo.arity;
                        state.funct["(metrics)"].verifyMaxParametersPerFunction();
                    } else {
                        state.funct["(metrics)"].arity = 0;
                    }

                    if (isArrow) {
                        if (!state.inES6(true)) {
                            warning("W119", state.tokens.curr, "arrow function syntax (=>)", "6");
                        }

                        if (!options.loneArg) {
                            advance("=>");
                        }
                    }

                    block(false, true, true, isArrow);

                    if (!state.option.noyield && isGenerator &&
                        state.funct["(generator)"] !== "yielded") {
                        warning("W124", state.tokens.curr);
                    }

                    state.funct["(metrics)"].verifyMaxStatementsPerFunction();
                    state.funct["(metrics)"].verifyMaxComplexityPerFunction();
                    state.funct["(unusedOption)"] = state.option.unused;
                    state.option = oldOption;
                    state.ignored = oldIgnored;
                    state.funct["(last)"] = state.tokens.curr.line;
                    state.funct["(lastcharacter)"] = state.tokens.curr.character;
                    state.funct["(scope)"].unstack(); // also does usage and label checks
                    state.funct["(scope)"].unstack();

                    state.funct = state.funct["(context)"];

                    if (!ignoreLoopFunc && !state.option.loopfunc && state.funct["(loopage)"]) {
                        if (f["(isCapturing)"]) {
                            warning("W083", token);
                        }
                    }

                    return f;
                }

                function createMetrics(functionStartToken) {
                    return {
                        statementCount: 0,
                        nestedBlockDepth: -1,
                        ComplexityCount: 1,
                        arity: 0,

                        verifyMaxStatementsPerFunction: function () {
                            if (state.option.maxstatements &&
                                this.statementCount > state.option.maxstatements) {
                                warning("W071", functionStartToken, this.statementCount);
                            }
                        },

                        verifyMaxParametersPerFunction: function () {
                            if (_.isNumber(state.option.maxparams) &&
                                this.arity > state.option.maxparams) {
                                warning("W072", functionStartToken, this.arity);
                            }
                        },

                        verifyMaxNestedBlockDepthPerFunction: function () {
                            if (state.option.maxdepth &&
                                this.nestedBlockDepth > 0 &&
                                this.nestedBlockDepth === state.option.maxdepth + 1) {
                                warning("W073", null, this.nestedBlockDepth);
                            }
                        },

                        verifyMaxComplexityPerFunction: function () {
                            var max = state.option.maxcomplexity;
                            var cc = this.ComplexityCount;
                            if (max && cc > max) {
                                warning("W074", functionStartToken, cc);
                            }
                        }
                    };
                }

                function increaseComplexityCount() {
                    state.funct["(metrics)"].ComplexityCount += 1;
                }

                function checkCondAssignment(expr) {
                    var id, paren;
                    if (expr) {
                        id = expr.id;
                        paren = expr.paren;
                        if (id === "," && (expr = expr.exprs[expr.exprs.length - 1])) {
                            id = expr.id;
                            paren = paren || expr.paren;
                        }
                    }
                    switch (id) {
                        case "=":
                        case "+=":
                        case "-=":
                        case "*=":
                        case "%=":
                        case "&=":
                        case "|=":
                        case "^=":
                        case "/=":
                            if (!paren && !state.option.boss) {
                                warning("W084");
                            }
                    }
                }

                function checkProperties(props) {
                    if (state.inES5()) {
                        for (var name in props) {
                            if (props[name] && props[name].setterToken && !props[name].getterToken) {
                                warning("W078", props[name].setterToken);
                            }
                        }
                    }
                }

                function metaProperty(name, c) {
                    if (checkPunctuator(state.tokens.next, ".")) {
                        var left = state.tokens.curr.id;
                        advance(".");
                        var id = identifier();
                        state.tokens.curr.isMetaProperty = true;
                        if (name !== id) {
                            error("E057", state.tokens.prev, left, id);
                        } else {
                            c();
                        }
                        return state.tokens.curr;
                    }
                }

                (function (x) {
                    x.nud = function () {
                        var b, f, i, p, t, isGeneratorMethod = false, nextVal;
                        var props = Object.create(null); // All properties, including accessors

                        b = state.tokens.curr.line !== startLine(state.tokens.next);
                        if (b) {
                            indent += state.option.indent;
                            if (state.tokens.next.from === indent + state.option.indent) {
                                indent += state.option.indent;
                            }
                        }

                        var blocktype = lookupBlockType();
                        if (blocktype.isDestAssign) {
                            this.destructAssign = destructuringPattern({openingParsed: true, assignment: true});
                            return this;
                        }

                        for (; ;) {
                            if (state.tokens.next.id === "}") {
                                break;
                            }

                            nextVal = state.tokens.next.value;
                            if (state.tokens.next.identifier &&
                                (peekIgnoreEOL().id === "," || peekIgnoreEOL().id === "}")) {
                                if (!state.inES6()) {
                                    warning("W104", state.tokens.next, "object short notation", "6");
                                }
                                i = propertyName(true);
                                saveProperty(props, i, state.tokens.next);

                                expression(10);

                            } else if (peek().id !== ":" && (nextVal === "get" || nextVal === "set")) {
                                advance(nextVal);

                                if (!state.inES5()) {
                                    error("E034");
                                }

                                i = propertyName();
                                if (!i && !state.inES6()) {
                                    error("E035");
                                }
                                if (i) {
                                    saveAccessor(nextVal, props, i, state.tokens.curr);
                                }

                                t = state.tokens.next;
                                f = doFunction();
                                p = f["(params)"];
                                if (nextVal === "get" && i && p) {
                                    warning("W076", t, p[0], i);
                                } else if (nextVal === "set" && i && (!p || p.length !== 1)) {
                                    warning("W077", t, i);
                                }
                            } else {
                                if (state.tokens.next.value === "*" && state.tokens.next.type === "(punctuator)") {
                                    if (!state.inES6()) {
                                        warning("W104", state.tokens.next, "generator functions", "6");
                                    }
                                    advance("*");
                                    isGeneratorMethod = true;
                                } else {
                                    isGeneratorMethod = false;
                                }

                                if (state.tokens.next.id === "[") {
                                    i = computedPropertyName();
                                    state.nameStack.set(i);
                                } else {
                                    state.nameStack.set(state.tokens.next);
                                    i = propertyName();
                                    saveProperty(props, i, state.tokens.next);

                                    if (typeof i !== "string") {
                                        break;
                                    }
                                }

                                if (state.tokens.next.value === "(") {
                                    if (!state.inES6()) {
                                        warning("W104", state.tokens.curr, "concise methods", "6");
                                    }
                                    doFunction({type: isGeneratorMethod ? "generator" : null});
                                } else {
                                    advance(":");
                                    expression(10);
                                }
                            }

                            countMember(i);

                            if (state.tokens.next.id === ",") {
                                comma({allowTrailing: true, property: true});
                                if (state.tokens.next.id === ",") {
                                    warning("W070", state.tokens.curr);
                                } else if (state.tokens.next.id === "}" && !state.inES5()) {
                                    warning("W070", state.tokens.curr);
                                }
                            } else {
                                break;
                            }
                        }
                        if (b) {
                            indent -= state.option.indent;
                        }
                        advance("}", this);

                        checkProperties(props);

                        return this;
                    };
                    x.fud = function () {
                        error("E036", state.tokens.curr);
                    };
                }(delim("{")));

                function destructuringPattern(options) {
                    var isAssignment = options && options.assignment;

                    if (!state.inES6()) {
                        warning("W104", state.tokens.curr,
                            isAssignment ? "destructuring assignment" : "destructuring binding", "6");
                    }

                    return destructuringPatternRecursive(options);
                }

                function destructuringPatternRecursive(options) {
                    var ids;
                    var identifiers = [];
                    var openingParsed = options && options.openingParsed;
                    var isAssignment = options && options.assignment;
                    var recursiveOptions = isAssignment ? {assignment: isAssignment} : null;
                    var firstToken = openingParsed ? state.tokens.curr : state.tokens.next;

                    var nextInnerDE = function () {
                        var ident;
                        if (checkPunctuators(state.tokens.next, ["[", "{"])) {
                            ids = destructuringPatternRecursive(recursiveOptions);
                            for (var id in ids) {
                                id = ids[id];
                                identifiers.push({id: id.id, token: id.token});
                            }
                        } else if (checkPunctuator(state.tokens.next, ",")) {
                            identifiers.push({id: null, token: state.tokens.curr});
                        } else if (checkPunctuator(state.tokens.next, "(")) {
                            advance("(");
                            nextInnerDE();
                            advance(")");
                        } else {
                            var is_rest = checkPunctuator(state.tokens.next, "...");

                            if (isAssignment) {
                                var identifierToken = is_rest ? peek(0) : state.tokens.next;
                                if (!identifierToken.identifier) {
                                    warning("E030", identifierToken, identifierToken.value);
                                }
                                var assignTarget = expression(155);
                                if (assignTarget) {
                                    checkLeftSideAssign(assignTarget);
                                    if (assignTarget.identifier) {
                                        ident = assignTarget.value;
                                    }
                                }
                            } else {
                                ident = identifier();
                            }
                            if (ident) {
                                identifiers.push({id: ident, token: state.tokens.curr});
                            }
                            return is_rest;
                        }
                        return false;
                    };
                    var assignmentProperty = function () {
                        var id;
                        if (checkPunctuator(state.tokens.next, "[")) {
                            advance("[");
                            expression(10);
                            advance("]");
                            advance(":");
                            nextInnerDE();
                        } else if (state.tokens.next.id === "(string)" ||
                            state.tokens.next.id === "(number)") {
                            advance();
                            advance(":");
                            nextInnerDE();
                        } else {
                            id = identifier();
                            if (checkPunctuator(state.tokens.next, ":")) {
                                advance(":");
                                nextInnerDE();
                            } else if (id) {
                                if (isAssignment) {
                                    checkLeftSideAssign(state.tokens.curr);
                                }
                                identifiers.push({id: id, token: state.tokens.curr});
                            }
                        }
                    };
                    if (checkPunctuator(firstToken, "[")) {
                        if (!openingParsed) {
                            advance("[");
                        }
                        if (checkPunctuator(state.tokens.next, "]")) {
                            warning("W137", state.tokens.curr);
                        }
                        var element_after_rest = false;
                        while (!checkPunctuator(state.tokens.next, "]")) {
                            if (nextInnerDE() && !element_after_rest &&
                                checkPunctuator(state.tokens.next, ",")) {
                                warning("W130", state.tokens.next);
                                element_after_rest = true;
                            }
                            if (checkPunctuator(state.tokens.next, "=")) {
                                if (checkPunctuator(state.tokens.prev, "...")) {
                                    advance("]");
                                } else {
                                    advance("=");
                                }
                                if (state.tokens.next.id === "undefined") {
                                    warning("W080", state.tokens.prev, state.tokens.prev.value);
                                }
                                expression(10);
                            }
                            if (!checkPunctuator(state.tokens.next, "]")) {
                                advance(",");
                            }
                        }
                        advance("]");
                    } else if (checkPunctuator(firstToken, "{")) {

                        if (!openingParsed) {
                            advance("{");
                        }
                        if (checkPunctuator(state.tokens.next, "}")) {
                            warning("W137", state.tokens.curr);
                        }
                        while (!checkPunctuator(state.tokens.next, "}")) {
                            assignmentProperty();
                            if (checkPunctuator(state.tokens.next, "=")) {
                                advance("=");
                                if (state.tokens.next.id === "undefined") {
                                    warning("W080", state.tokens.prev, state.tokens.prev.value);
                                }
                                expression(10);
                            }
                            if (!checkPunctuator(state.tokens.next, "}")) {
                                advance(",");
                                if (checkPunctuator(state.tokens.next, "}")) {
                                    break;
                                }
                            }
                        }
                        advance("}");
                    }
                    return identifiers;
                }

                function destructuringPatternMatch(tokens, value) {
                    var first = value.first;

                    if (!first)
                        return;

                    _.zip(tokens, Array.isArray(first) ? first : [first]).forEach(function (val) {
                        var token = val[0];
                        var value = val[1];

                        if (token && value)
                            token.first = value;
                        else if (token && token.first && !value)
                            warning("W080", token.first, token.first.value);
                    });
                }

                function blockVariableStatement(type, statement, context) {

                    var prefix = context && context.prefix;
                    var inexport = context && context.inexport;
                    var isLet = type === "let";
                    var isConst = type === "const";
                    var tokens, lone, value, letblock;

                    if (!state.inES6()) {
                        warning("W104", state.tokens.curr, type, "6");
                    }

                    if (isLet && state.tokens.next.value === "(") {
                        if (!state.inMoz()) {
                            warning("W118", state.tokens.next, "let block");
                        }
                        advance("(");
                        state.funct["(scope)"].stack();
                        letblock = true;
                    } else if (state.funct["(noblockscopedvar)"]) {
                        error("E048", state.tokens.curr, isConst ? "Const" : "Let");
                    }

                    statement.first = [];
                    for (; ;) {
                        var names = [];
                        if (_.contains(["{", "["], state.tokens.next.value)) {
                            tokens = destructuringPattern();
                            lone = false;
                        } else {
                            tokens = [{id: identifier(), token: state.tokens.curr}];
                            lone = true;
                        }

                        if (!prefix && isConst && state.tokens.next.id !== "=") {
                            warning("E012", state.tokens.curr, state.tokens.curr.value);
                        }

                        for (var t in tokens) {
                            if (tokens.hasOwnProperty(t)) {
                                t = tokens[t];
                                if (state.funct["(scope)"].block.isGlobal()) {
                                    if (predefined[t.id] === false) {
                                        warning("W079", t.token, t.id);
                                    }
                                }
                                if (t.id && !state.funct["(noblockscopedvar)"]) {
                                    state.funct["(scope)"].addlabel(t.id, {
                                        type: type,
                                        token: t.token
                                    });
                                    names.push(t.token);

                                    if (lone && inexport) {
                                        state.funct["(scope)"].setExported(t.token.value, t.token);
                                    }
                                }
                            }
                        }

                        if (state.tokens.next.id === "=") {
                            advance("=");
                            if (!prefix && state.tokens.next.id === "undefined") {
                                warning("W080", state.tokens.prev, state.tokens.prev.value);
                            }
                            if (!prefix && peek(0).id === "=" && state.tokens.next.identifier) {
                                warning("W120", state.tokens.next, state.tokens.next.value);
                            }
                            value = expression(prefix ? 120 : 10);
                            if (lone) {
                                tokens[0].first = value;
                            } else {
                                destructuringPatternMatch(names, value);
                            }
                        }

                        statement.first = statement.first.concat(names);

                        if (state.tokens.next.id !== ",") {
                            break;
                        }
                        comma();
                    }
                    if (letblock) {
                        advance(")");
                        block(true, true);
                        statement.block = true;
                        state.funct["(scope)"].unstack();
                    }

                    return statement;
                }

                var conststatement = stmt("const", function (context) {
                    return blockVariableStatement("const", this, context);
                });
                conststatement.exps = true;

                var letstatement = stmt("let", function (context) {
                    return blockVariableStatement("let", this, context);
                });
                letstatement.exps = true;

                var varstatement = stmt("var", function (context) {
                    var prefix = context && context.prefix;
                    var inexport = context && context.inexport;
                    var tokens, lone, value;
                    var implied = context && context.implied;
                    var report = !(context && context.ignore);

                    this.first = [];
                    for (; ;) {
                        var names = [];
                        if (_.contains(["{", "["], state.tokens.next.value)) {
                            tokens = destructuringPattern();
                            lone = false;
                        } else {
                            tokens = [{id: identifier(), token: state.tokens.curr}];
                            lone = true;
                        }

                        if (!(prefix && implied) && report && state.option.varstmt) {
                            warning("W132", this);
                        }

                        this.first = this.first.concat(names);

                        for (var t in tokens) {
                            if (tokens.hasOwnProperty(t)) {
                                t = tokens[t];
                                if (!implied && state.funct["(global)"]) {
                                    if (predefined[t.id] === false) {
                                        warning("W079", t.token, t.id);
                                    } else if (state.option.futurehostile === false) {
                                        if ((!state.inES5() && vars.ecmaIdentifiers[5][t.id] === false) ||
                                            (!state.inES6() && vars.ecmaIdentifiers[6][t.id] === false)) {
                                            warning("W129", t.token, t.id);
                                        }
                                    }
                                }
                                if (t.id) {
                                    if (implied === "for") {

                                        if (!state.funct["(scope)"].has(t.id)) {
                                            if (report) warning("W088", t.token, t.id);
                                        }
                                        state.funct["(scope)"].block.use(t.id, t.token);
                                    } else {
                                        state.funct["(scope)"].addlabel(t.id, {
                                            type: "var",
                                            token: t.token
                                        });

                                        if (lone && inexport) {
                                            state.funct["(scope)"].setExported(t.id, t.token);
                                        }
                                    }
                                    names.push(t.token);
                                }
                            }
                        }

                        if (state.tokens.next.id === "=") {
                            state.nameStack.set(state.tokens.curr);

                            advance("=");
                            if (!prefix && report && !state.funct["(loopage)"] &&
                                state.tokens.next.id === "undefined") {
                                warning("W080", state.tokens.prev, state.tokens.prev.value);
                            }
                            if (peek(0).id === "=" && state.tokens.next.identifier) {
                                if (!prefix && report &&
                                    !state.funct["(params)"] ||
                                    state.funct["(params)"].indexOf(state.tokens.next.value) === -1) {
                                    warning("W120", state.tokens.next, state.tokens.next.value);
                                }
                            }
                            value = expression(prefix ? 120 : 10);
                            if (lone) {
                                tokens[0].first = value;
                            } else {
                                destructuringPatternMatch(names, value);
                            }
                        }

                        if (state.tokens.next.id !== ",") {
                            break;
                        }
                        comma();
                    }

                    return this;
                });
                varstatement.exps = true;

                blockstmt("class", function () {
                    return classdef.call(this, true);
                });

                function classdef(isStatement) {
                    if (!state.inES6()) {
                        warning("W104", state.tokens.curr, "class", "6");
                    }
                    if (isStatement) {
                        this.name = identifier();

                        state.funct["(scope)"].addlabel(this.name, {
                            type: "class",
                            token: state.tokens.curr
                        });
                    } else if (state.tokens.next.identifier && state.tokens.next.value !== "extends") {
                        this.name = identifier();
                        this.namedExpr = true;
                    } else {
                        this.name = state.nameStack.infer();
                    }
                    classtail(this);
                    return this;
                }

                function classtail(c) {
                    var wasInClassBody = state.inClassBody;
                    if (state.tokens.next.value === "extends") {
                        advance("extends");
                        c.heritage = expression(10);
                    }

                    state.inClassBody = true;
                    advance("{");
                    c.body = classbody(c);
                    advance("}");
                    state.inClassBody = wasInClassBody;
                }

                function classbody(c) {
                    var name;
                    var isStatic;
                    var isGenerator;
                    var getset;
                    var props = Object.create(null);
                    var staticProps = Object.create(null);
                    var computed;
                    for (var i = 0; state.tokens.next.id !== "}"; ++i) {
                        name = state.tokens.next;
                        isStatic = false;
                        isGenerator = false;
                        getset = null;
                        if (name.id === ";") {
                            warning("W032");
                            advance(";");
                            continue;
                        }

                        if (name.id === "*") {
                            isGenerator = true;
                            advance("*");
                            name = state.tokens.next;
                        }
                        if (name.id === "[") {
                            name = computedPropertyName();
                            computed = true;
                        } else if (isPropertyName(name)) {
                            advance();
                            computed = false;
                            if (name.identifier && name.value === "static") {
                                if (checkPunctuator(state.tokens.next, "*")) {
                                    isGenerator = true;
                                    advance("*");
                                }
                                if (isPropertyName(state.tokens.next) || state.tokens.next.id === "[") {
                                    computed = state.tokens.next.id === "[";
                                    isStatic = true;
                                    name = state.tokens.next;
                                    if (state.tokens.next.id === "[") {
                                        name = computedPropertyName();
                                    } else advance();
                                }
                            }

                            if (name.identifier && (name.value === "get" || name.value === "set")) {
                                if (isPropertyName(state.tokens.next) || state.tokens.next.id === "[") {
                                    computed = state.tokens.next.id === "[";
                                    getset = name;
                                    name = state.tokens.next;
                                    if (state.tokens.next.id === "[") {
                                        name = computedPropertyName();
                                    } else advance();
                                }
                            }
                        } else {
                            warning("W052", state.tokens.next, state.tokens.next.value || state.tokens.next.type);
                            advance();
                            continue;
                        }

                        if (!checkPunctuator(state.tokens.next, "(")) {
                            error("E054", state.tokens.next, state.tokens.next.value);
                            while (state.tokens.next.id !== "}" &&
                            !checkPunctuator(state.tokens.next, "(")) {
                                advance();
                            }
                            if (state.tokens.next.value !== "(") {
                                doFunction({statement: c});
                            }
                        }

                        if (!computed) {
                            if (getset) {
                                saveAccessor(
                                    getset.value, isStatic ? staticProps : props, name.value, name, true, isStatic);
                            } else {
                                if (name.value === "constructor") {
                                    state.nameStack.set(c);
                                } else {
                                    state.nameStack.set(name);
                                }
                                saveProperty(isStatic ? staticProps : props, name.value, name, true, isStatic);
                            }
                        }

                        if (getset && name.value === "constructor") {
                            var propDesc = getset.value === "get" ? "class getter method" : "class setter method";
                            error("E049", name, propDesc, "constructor");
                        } else if (name.value === "prototype") {
                            error("E049", name, "class method", "prototype");
                        }

                        propertyName(name);

                        doFunction({
                            statement: c,
                            type: isGenerator ? "generator" : null,
                            classExprBinding: c.namedExpr ? c.name : null
                        });
                    }

                    checkProperties(props);
                }

                blockstmt("function", function (context) {
                    var inexport = context && context.inexport;
                    var generator = false;
                    if (state.tokens.next.value === "*") {
                        advance("*");
                        if (state.inES6({strict: true})) {
                            generator = true;
                        } else {
                            warning("W119", state.tokens.curr, "function*", "6");
                        }
                    }
                    if (inblock) {
                        warning("W082", state.tokens.curr);
                    }
                    var i = optionalidentifier();

                    state.funct["(scope)"].addlabel(i, {
                        type: "function",
                        token: state.tokens.curr
                    });

                    if (i === undefined) {
                        warning("W025");
                    } else if (inexport) {
                        state.funct["(scope)"].setExported(i, state.tokens.prev);
                    }

                    doFunction({
                        name: i,
                        statement: this,
                        type: generator ? "generator" : null,
                        ignoreLoopFunc: inblock // a declaration may already have warned
                    });
                    if (state.tokens.next.id === "(" && state.tokens.next.line === state.tokens.curr.line) {
                        error("E039");
                    }
                    return this;
                });

                prefix("function", function () {
                    var generator = false;

                    if (state.tokens.next.value === "*") {
                        if (!state.inES6()) {
                            warning("W119", state.tokens.curr, "function*", "6");
                        }
                        advance("*");
                        generator = true;
                    }

                    var i = optionalidentifier();
                    doFunction({name: i, type: generator ? "generator" : null});
                    return this;
                });

                blockstmt("if", function () {
                    var t = state.tokens.next;
                    increaseComplexityCount();
                    state.condition = true;
                    advance("(");
                    var expr = expression(0);
                    checkCondAssignment(expr);
                    var forinifcheck = null;
                    if (state.option.forin && state.forinifcheckneeded) {
                        state.forinifcheckneeded = false; // We only need to analyze the first if inside the loop
                        forinifcheck = state.forinifchecks[state.forinifchecks.length - 1];
                        if (expr.type === "(punctuator)" && expr.value === "!") {
                            forinifcheck.type = "(negative)";
                        } else {
                            forinifcheck.type = "(positive)";
                        }
                    }

                    advance(")", t);
                    state.condition = false;
                    var s = block(true, true);
                    if (forinifcheck && forinifcheck.type === "(negative)") {
                        if (s && s[0] && s[0].type === "(identifier)" && s[0].value === "continue") {
                            forinifcheck.type = "(negative-with-continue)";
                        }
                    }

                    if (state.tokens.next.id === "else") {
                        advance("else");
                        if (state.tokens.next.id === "if" || state.tokens.next.id === "switch") {
                            statement();
                        } else {
                            block(true, true);
                        }
                    }
                    return this;
                });

                blockstmt("try", function () {
                    var b;

                    function doCatch() {
                        advance("catch");
                        advance("(");

                        state.funct["(scope)"].stack("catchparams");

                        if (checkPunctuators(state.tokens.next, ["[", "{"])) {
                            var tokens = destructuringPattern();
                            _.each(tokens, function (token) {
                                if (token.id) {
                                    state.funct["(scope)"].addParam(token.id, token, "exception");
                                }
                            });
                        } else if (state.tokens.next.type !== "(identifier)") {
                            warning("E030", state.tokens.next, state.tokens.next.value);
                        } else {
                            state.funct["(scope)"].addParam(identifier(), state.tokens.curr, "exception");
                        }

                        if (state.tokens.next.value === "if") {
                            if (!state.inMoz()) {
                                warning("W118", state.tokens.curr, "catch filter");
                            }
                            advance("if");
                            expression(0);
                        }

                        advance(")");

                        block(false);

                        state.funct["(scope)"].unstack();
                    }

                    block(true);

                    while (state.tokens.next.id === "catch") {
                        increaseComplexityCount();
                        if (b && (!state.inMoz())) {
                            warning("W118", state.tokens.next, "multiple catch blocks");
                        }
                        doCatch();
                        b = true;
                    }

                    if (state.tokens.next.id === "finally") {
                        advance("finally");
                        block(true);
                        return;
                    }

                    if (!b) {
                        error("E021", state.tokens.next, "catch", state.tokens.next.value);
                    }

                    return this;
                });

                blockstmt("while", function () {
                    var t = state.tokens.next;
                    state.funct["(breakage)"] += 1;
                    state.funct["(loopage)"] += 1;
                    increaseComplexityCount();
                    advance("(");
                    checkCondAssignment(expression(0));
                    advance(")", t);
                    block(true, true);
                    state.funct["(breakage)"] -= 1;
                    state.funct["(loopage)"] -= 1;
                    return this;
                }).labelled = true;

                blockstmt("with", function () {
                    var t = state.tokens.next;
                    if (state.isStrict()) {
                        error("E010", state.tokens.curr);
                    } else if (!state.option.withstmt) {
                        warning("W085", state.tokens.curr);
                    }

                    advance("(");
                    expression(0);
                    advance(")", t);
                    block(true, true);

                    return this;
                });

                blockstmt("switch", function () {
                    var t = state.tokens.next;
                    var g = false;
                    var noindent = false;

                    state.funct["(breakage)"] += 1;
                    advance("(");
                    checkCondAssignment(expression(0));
                    advance(")", t);
                    t = state.tokens.next;
                    advance("{");

                    if (state.tokens.next.from === indent)
                        noindent = true;

                    if (!noindent)
                        indent += state.option.indent;

                    this.cases = [];

                    for (; ;) {
                        switch (state.tokens.next.id) {
                            case "case":
                                switch (state.funct["(verb)"]) {
                                    case "yield":
                                    case "break":
                                    case "case":
                                    case "continue":
                                    case "return":
                                    case "switch":
                                    case "throw":
                                        break;
                                    default:
                                        if (!state.tokens.curr.caseFallsThrough) {
                                            warning("W086", state.tokens.curr, "case");
                                        }
                                }

                                advance("case");
                                this.cases.push(expression(0));
                                increaseComplexityCount();
                                g = true;
                                advance(":");
                                state.funct["(verb)"] = "case";
                                break;
                            case "default":
                                switch (state.funct["(verb)"]) {
                                    case "yield":
                                    case "break":
                                    case "continue":
                                    case "return":
                                    case "throw":
                                        break;
                                    default:
                                        if (this.cases.length) {
                                            if (!state.tokens.curr.caseFallsThrough) {
                                                warning("W086", state.tokens.curr, "default");
                                            }
                                        }
                                }

                                advance("default");
                                g = true;
                                advance(":");
                                break;
                            case "}":
                                if (!noindent)
                                    indent -= state.option.indent;

                                advance("}", t);
                                state.funct["(breakage)"] -= 1;
                                state.funct["(verb)"] = undefined;
                                return;
                            case "(end)":
                                error("E023", state.tokens.next, "}");
                                return;
                            default:
                                indent += state.option.indent;
                                if (g) {
                                    switch (state.tokens.curr.id) {
                                        case ",":
                                            error("E040");
                                            return;
                                        case ":":
                                            g = false;
                                            statements();
                                            break;
                                        default:
                                            error("E025", state.tokens.curr);
                                            return;
                                    }
                                } else {
                                    if (state.tokens.curr.id === ":") {
                                        advance(":");
                                        error("E024", state.tokens.curr, ":");
                                        statements();
                                    } else {
                                        error("E021", state.tokens.next, "case", state.tokens.next.value);
                                        return;
                                    }
                                }
                                indent -= state.option.indent;
                        }
                    }
                    return this;
                }).labelled = true;

                stmt("debugger", function () {
                    if (!state.option.debug) {
                        warning("W087", this);
                    }
                    return this;
                }).exps = true;

                (function () {
                    var x = stmt("do", function () {
                        state.funct["(breakage)"] += 1;
                        state.funct["(loopage)"] += 1;
                        increaseComplexityCount();

                        this.first = block(true, true);
                        advance("while");
                        var t = state.tokens.next;
                        advance("(");
                        checkCondAssignment(expression(0));
                        advance(")", t);
                        state.funct["(breakage)"] -= 1;
                        state.funct["(loopage)"] -= 1;
                        return this;
                    });
                    x.labelled = true;
                    x.exps = true;
                }());

                blockstmt("for", function () {
                    var s, t = state.tokens.next;
                    var letscope = false;
                    var foreachtok = null;

                    if (t.value === "each") {
                        foreachtok = t;
                        advance("each");
                        if (!state.inMoz()) {
                            warning("W118", state.tokens.curr, "for each");
                        }
                    }

                    increaseComplexityCount();
                    advance("(");
                    var nextop; // contains the token of the "in" or "of" operator
                    var i = 0;
                    var inof = ["in", "of"];
                    var level = 0; // BindingPattern "level" --- level 0 === no BindingPattern
                    var comma; // First comma punctuator at level 0
                    var initializer; // First initializer at level 0
                    if (checkPunctuators(state.tokens.next, ["{", "["])) ++level;
                    do {
                        nextop = peek(i);
                        ++i;
                        if (checkPunctuators(nextop, ["{", "["])) ++level;
                        else if (checkPunctuators(nextop, ["}", "]"])) --level;
                        if (level < 0) break;
                        if (level === 0) {
                            if (!comma && checkPunctuator(nextop, ",")) comma = nextop;
                            else if (!initializer && checkPunctuator(nextop, "=")) initializer = nextop;
                        }
                    } while (level > 0 || !_.contains(inof, nextop.value) && nextop.value !== ";" &&
                    nextop.type !== "(end)"); // Is this a JSCS bug? This looks really weird.
                    if (_.contains(inof, nextop.value)) {
                        if (!state.inES6() && nextop.value === "of") {
                            warning("W104", nextop, "for of", "6");
                        }

                        var ok = !(initializer || comma);
                        if (initializer) {
                            error("W133", comma, nextop.value, "initializer is forbidden");
                        }

                        if (comma) {
                            error("W133", comma, nextop.value, "more than one ForBinding");
                        }

                        if (state.tokens.next.id === "var") {
                            advance("var");
                            state.tokens.curr.fud({prefix: true});
                        } else if (state.tokens.next.id === "let" || state.tokens.next.id === "const") {
                            advance(state.tokens.next.id);
                            letscope = true;
                            state.funct["(scope)"].stack();
                            state.tokens.curr.fud({prefix: true});
                        } else {
                            Object.create(varstatement).fud({prefix: true, implied: "for", ignore: !ok});
                        }
                        advance(nextop.value);
                        expression(20);
                        advance(")", t);

                        if (nextop.value === "in" && state.option.forin) {
                            state.forinifcheckneeded = true;

                            if (state.forinifchecks === undefined) {
                                state.forinifchecks = [];
                            }
                            state.forinifchecks.push({
                                type: "(none)"
                            });
                        }

                        state.funct["(breakage)"] += 1;
                        state.funct["(loopage)"] += 1;

                        s = block(true, true);

                        if (nextop.value === "in" && state.option.forin) {
                            if (state.forinifchecks && state.forinifchecks.length > 0) {
                                var check = state.forinifchecks.pop();

                                if (// No if statement or not the first statement in loop body
                                    s && s.length > 0 && (typeof s[0] !== "object" || s[0].value !== "if") ||
                                    check.type === "(positive)" && s.length > 1 ||
                                    check.type === "(negative)") {
                                    warning("W089", this);
                                }
                            }
                            state.forinifcheckneeded = false;
                        }

                        state.funct["(breakage)"] -= 1;
                        state.funct["(loopage)"] -= 1;
                    } else {
                        if (foreachtok) {
                            error("E045", foreachtok);
                        }
                        if (state.tokens.next.id !== ";") {
                            if (state.tokens.next.id === "var") {
                                advance("var");
                                state.tokens.curr.fud();
                            } else if (state.tokens.next.id === "let") {
                                advance("let");
                                letscope = true;
                                state.funct["(scope)"].stack();
                                state.tokens.curr.fud();
                            } else {
                                for (; ;) {
                                    expression(0, "for");
                                    if (state.tokens.next.id !== ",") {
                                        break;
                                    }
                                    comma();
                                }
                            }
                        }
                        nolinebreak(state.tokens.curr);
                        advance(";");
                        state.funct["(loopage)"] += 1;
                        if (state.tokens.next.id !== ";") {
                            checkCondAssignment(expression(0));
                        }
                        nolinebreak(state.tokens.curr);
                        advance(";");
                        if (state.tokens.next.id === ";") {
                            error("E021", state.tokens.next, ")", ";");
                        }
                        if (state.tokens.next.id !== ")") {
                            for (; ;) {
                                expression(0, "for");
                                if (state.tokens.next.id !== ",") {
                                    break;
                                }
                                comma();
                            }
                        }
                        advance(")", t);
                        state.funct["(breakage)"] += 1;
                        block(true, true);
                        state.funct["(breakage)"] -= 1;
                        state.funct["(loopage)"] -= 1;

                    }
                    if (letscope) {
                        state.funct["(scope)"].unstack();
                    }
                    return this;
                }).labelled = true;


                stmt("break", function () {
                    var v = state.tokens.next.value;

                    if (!state.option.asi)
                        nolinebreak(this);

                    if (state.tokens.next.id !== ";" && !state.tokens.next.reach &&
                        state.tokens.curr.line === startLine(state.tokens.next)) {
                        if (!state.funct["(scope)"].funct.hasBreakLabel(v)) {
                            warning("W090", state.tokens.next, v);
                        }
                        this.first = state.tokens.next;
                        advance();
                    } else {
                        if (state.funct["(breakage)"] === 0)
                            warning("W052", state.tokens.next, this.value);
                    }

                    reachable(this);

                    return this;
                }).exps = true;


                stmt("continue", function () {
                    var v = state.tokens.next.value;

                    if (state.funct["(breakage)"] === 0)
                        warning("W052", state.tokens.next, this.value);
                    if (!state.funct["(loopage)"])
                        warning("W052", state.tokens.next, this.value);

                    if (!state.option.asi)
                        nolinebreak(this);

                    if (state.tokens.next.id !== ";" && !state.tokens.next.reach) {
                        if (state.tokens.curr.line === startLine(state.tokens.next)) {
                            if (!state.funct["(scope)"].funct.hasBreakLabel(v)) {
                                warning("W090", state.tokens.next, v);
                            }
                            this.first = state.tokens.next;
                            advance();
                        }
                    }

                    reachable(this);

                    return this;
                }).exps = true;


                stmt("return", function () {
                    if (this.line === startLine(state.tokens.next)) {
                        if (state.tokens.next.id !== ";" && !state.tokens.next.reach) {
                            this.first = expression(0);

                            if (this.first &&
                                this.first.type === "(punctuator)" && this.first.value === "=" &&
                                !this.first.paren && !state.option.boss) {
                                warningAt("W093", this.first.line, this.first.character);
                            }
                        }
                    } else {
                        if (state.tokens.next.type === "(punctuator)" &&
                            ["[", "{", "+", "-"].indexOf(state.tokens.next.value) > -1) {
                            nolinebreak(this); // always warn (Line breaking error)
                        }
                    }

                    reachable(this);

                    return this;
                }).exps = true;

                (function (x) {
                    x.exps = true;
                    x.lbp = 25;
                }(prefix("yield", function () {
                    var prev = state.tokens.prev;
                    if (state.inES6(true) && !state.funct["(generator)"]) {
                        if (!("(catch)" === state.funct["(name)"] && state.funct["(context)"]["(generator)"])) {
                            error("E046", state.tokens.curr, "yield");
                        }
                    } else if (!state.inES6()) {
                        warning("W104", state.tokens.curr, "yield", "6");
                    }
                    state.funct["(generator)"] = "yielded";
                    var delegatingYield = false;

                    if (state.tokens.next.value === "*") {
                        delegatingYield = true;
                        advance("*");
                    }

                    if (this.line === startLine(state.tokens.next) || !state.inMoz()) {
                        if (delegatingYield ||
                            (state.tokens.next.id !== ";" && !state.option.asi &&
                                !state.tokens.next.reach && state.tokens.next.nud)) {

                            nobreaknonadjacent(state.tokens.curr, state.tokens.next);
                            this.first = expression(10);

                            if (this.first.type === "(punctuator)" && this.first.value === "=" &&
                                !this.first.paren && !state.option.boss) {
                                warningAt("W093", this.first.line, this.first.character);
                            }
                        }

                        if (state.inMoz() && state.tokens.next.id !== ")" &&
                            (prev.lbp > 30 || (!prev.assign && !isEndOfExpr()) || prev.id === "yield")) {
                            error("E050", this);
                        }
                    } else if (!state.option.asi) {
                        nolinebreak(this); // always warn (Line breaking error)
                    }
                    return this;
                })));


                stmt("throw", function () {
                    nolinebreak(this);
                    this.first = expression(20);

                    reachable(this);

                    return this;
                }).exps = true;

                stmt("import", function () {
                    if (!state.inES6()) {
                        warning("W119", state.tokens.curr, "import", "6");
                    }

                    if (state.tokens.next.type === "(string)") {
                        advance("(string)");
                        return this;
                    }

                    if (state.tokens.next.identifier) {
                        this.name = identifier();
                        state.funct["(scope)"].addlabel(this.name, {
                            type: "const",
                            token: state.tokens.curr
                        });

                        if (state.tokens.next.value === ",") {
                            advance(",");
                        } else {
                            advance("from");
                            advance("(string)");
                            return this;
                        }
                    }

                    if (state.tokens.next.id === "*") {
                        advance("*");
                        advance("as");
                        if (state.tokens.next.identifier) {
                            this.name = identifier();
                            state.funct["(scope)"].addlabel(this.name, {
                                type: "const",
                                token: state.tokens.curr
                            });
                        }
                    } else {
                        advance("{");
                        for (; ;) {
                            if (state.tokens.next.value === "}") {
                                advance("}");
                                break;
                            }
                            var importName;
                            if (state.tokens.next.type === "default") {
                                importName = "default";
                                advance("default");
                            } else {
                                importName = identifier();
                            }
                            if (state.tokens.next.value === "as") {
                                advance("as");
                                importName = identifier();
                            }
                            state.funct["(scope)"].addlabel(importName, {
                                type: "const",
                                token: state.tokens.curr
                            });

                            if (state.tokens.next.value === ",") {
                                advance(",");
                            } else if (state.tokens.next.value === "}") {
                                advance("}");
                                break;
                            } else {
                                error("E024", state.tokens.next, state.tokens.next.value);
                                break;
                            }
                        }
                    }
                    advance("from");
                    advance("(string)");
                    return this;
                }).exps = true;

                stmt("export", function () {
                    var ok = true;
                    var token;
                    var identifier;

                    if (!state.inES6()) {
                        warning("W119", state.tokens.curr, "export", "6");
                        ok = false;
                    }

                    if (!state.funct["(scope)"].block.isGlobal()) {
                        error("E053", state.tokens.curr);
                        ok = false;
                    }

                    if (state.tokens.next.value === "*") {
                        advance("*");
                        advance("from");
                        advance("(string)");
                        return this;
                    }

                    if (state.tokens.next.type === "default") {
                        state.nameStack.set(state.tokens.next);
                        advance("default");
                        var exportType = state.tokens.next.id;
                        if (exportType === "function" || exportType === "class") {
                            this.block = true;
                        }

                        token = peek();

                        expression(10);

                        identifier = token.value;

                        if (this.block) {
                            state.funct["(scope)"].addlabel(identifier, {
                                type: exportType,
                                token: token
                            });

                            state.funct["(scope)"].setExported(identifier, token);
                        }

                        return this;
                    }

                    if (state.tokens.next.value === "{") {
                        advance("{");
                        var exportedTokens = [];
                        for (; ;) {
                            if (!state.tokens.next.identifier) {
                                error("E030", state.tokens.next, state.tokens.next.value);
                            }
                            advance();

                            exportedTokens.push(state.tokens.curr);

                            if (state.tokens.next.value === "as") {
                                advance("as");
                                if (!state.tokens.next.identifier) {
                                    error("E030", state.tokens.next, state.tokens.next.value);
                                }
                                advance();
                            }

                            if (state.tokens.next.value === ",") {
                                advance(",");
                            } else if (state.tokens.next.value === "}") {
                                advance("}");
                                break;
                            } else {
                                error("E024", state.tokens.next, state.tokens.next.value);
                                break;
                            }
                        }
                        if (state.tokens.next.value === "from") {
                            advance("from");
                            advance("(string)");
                        } else if (ok) {
                            exportedTokens.forEach(function (token) {
                                state.funct["(scope)"].setExported(token.value, token);
                            });
                        }
                        return this;
                    }

                    if (state.tokens.next.id === "var") {
                        advance("var");
                        state.tokens.curr.fud({inexport: true});
                    } else if (state.tokens.next.id === "let") {
                        advance("let");
                        state.tokens.curr.fud({inexport: true});
                    } else if (state.tokens.next.id === "const") {
                        advance("const");
                        state.tokens.curr.fud({inexport: true});
                    } else if (state.tokens.next.id === "function") {
                        this.block = true;
                        advance("function");
                        state.syntax["function"].fud({inexport: true});
                    } else if (state.tokens.next.id === "class") {
                        this.block = true;
                        advance("class");
                        var classNameToken = state.tokens.next;
                        state.syntax["class"].fud();
                        state.funct["(scope)"].setExported(classNameToken.value, classNameToken);
                    } else {
                        error("E024", state.tokens.next, state.tokens.next.value);
                    }

                    return this;
                }).exps = true;

                FutureReservedWord("abstract");
                FutureReservedWord("boolean");
                FutureReservedWord("byte");
                FutureReservedWord("char");
                FutureReservedWord("class", {es5: true, nud: classdef});
                FutureReservedWord("double");
                FutureReservedWord("enum", {es5: true});
                FutureReservedWord("export", {es5: true});
                FutureReservedWord("extends", {es5: true});
                FutureReservedWord("final");
                FutureReservedWord("float");
                FutureReservedWord("goto");
                FutureReservedWord("implements", {es5: true, strictOnly: true});
                FutureReservedWord("import", {es5: true});
                FutureReservedWord("int");
                FutureReservedWord("interface", {es5: true, strictOnly: true});
                FutureReservedWord("long");
                FutureReservedWord("native");
                FutureReservedWord("package", {es5: true, strictOnly: true});
                FutureReservedWord("private", {es5: true, strictOnly: true});
                FutureReservedWord("protected", {es5: true, strictOnly: true});
                FutureReservedWord("public", {es5: true, strictOnly: true});
                FutureReservedWord("short");
                FutureReservedWord("static", {es5: true, strictOnly: true});
                FutureReservedWord("super", {es5: true});
                FutureReservedWord("synchronized");
                FutureReservedWord("transient");
                FutureReservedWord("volatile");

                var lookupBlockType = function () {
                    var pn, pn1, prev;
                    var i = -1;
                    var bracketStack = 0;
                    var ret = {};
                    if (checkPunctuators(state.tokens.curr, ["[", "{"])) {
                        bracketStack += 1;
                    }
                    do {
                        prev = i === -1 ? state.tokens.curr : pn;
                        pn = i === -1 ? state.tokens.next : peek(i);
                        pn1 = peek(i + 1);
                        i = i + 1;
                        if (checkPunctuators(pn, ["[", "{"])) {
                            bracketStack += 1;
                        } else if (checkPunctuators(pn, ["]", "}"])) {
                            bracketStack -= 1;
                        }
                        if (bracketStack === 1 && pn.identifier && pn.value === "for" &&
                            !checkPunctuator(prev, ".")) {
                            ret.isCompArray = true;
                            ret.notJson = true;
                            break;
                        }
                        if (bracketStack === 0 && checkPunctuators(pn, ["}", "]"])) {
                            if (pn1.value === "=") {
                                ret.isDestAssign = true;
                                ret.notJson = true;
                                break;
                            } else if (pn1.value === ".") {
                                ret.notJson = true;
                                break;
                            }
                        }
                        if (checkPunctuator(pn, ";")) {
                            ret.isBlock = true;
                            ret.notJson = true;
                        }
                    } while (bracketStack > 0 && pn.id !== "(end)");
                    return ret;
                };

                function saveProperty(props, name, tkn, isClass, isStatic) {
                    var msg = ["key", "class method", "static class method"];
                    msg = msg[(isClass || false) + (isStatic || false)];
                    if (tkn.identifier) {
                        name = tkn.value;
                    }

                    if (props[name] && name !== "__proto__") {
                        warning("W075", state.tokens.next, msg, name);
                    } else {
                        props[name] = Object.create(null);
                    }

                    props[name].basic = true;
                    props[name].basictkn = tkn;
                }

                function saveAccessor(accessorType, props, name, tkn, isClass, isStatic) {
                    var flagName = accessorType === "get" ? "getterToken" : "setterToken";
                    var msg = "";

                    if (isClass) {
                        if (isStatic) {
                            msg += "static ";
                        }
                        msg += accessorType + "ter method";
                    } else {
                        msg = "key";
                    }

                    state.tokens.curr.accessorType = accessorType;
                    state.nameStack.set(tkn);

                    if (props[name]) {
                        if ((props[name].basic || props[name][flagName]) && name !== "__proto__") {
                            warning("W075", state.tokens.next, msg, name);
                        }
                    } else {
                        props[name] = Object.create(null);
                    }

                    props[name][flagName] = tkn;
                }

                function computedPropertyName() {
                    advance("[");
                    if (!state.inES6()) {
                        warning("W119", state.tokens.curr, "computed property names", "6");
                    }
                    var value = expression(10);
                    advance("]");
                    return value;
                }

                function checkPunctuators(token, values) {
                    if (token.type === "(punctuator)") {
                        return _.contains(values, token.value);
                    }
                    return false;
                }

                function checkPunctuator(token, value) {
                    return token.type === "(punctuator)" && token.value === value;
                }

                function destructuringAssignOrJsonValue() {

                    var block = lookupBlockType();
                    if (block.notJson) {
                        if (!state.inES6() && block.isDestAssign) {
                            warning("W104", state.tokens.curr, "destructuring assignment", "6");
                        }
                        statements();
                    } else {
                        state.option.laxbreak = true;
                        state.jsonMode = true;
                        jsonValue();
                    }
                }

                var arrayComprehension = function () {
                    var CompArray = function () {
                        this.mode = "use";
                        this.variables = [];
                    };
                    var _carrays = [];
                    var _current;

                    function declare(v) {
                        var l = _current.variables.filter(function (elt) {
                            if (elt.value === v) {
                                elt.undef = false;
                                return v;
                            }
                        }).length;
                        return l !== 0;
                    }

                    function use(v) {
                        var l = _current.variables.filter(function (elt) {
                            if (elt.value === v && !elt.undef) {
                                if (elt.unused === true) {
                                    elt.unused = false;
                                }
                                return v;
                            }
                        }).length;
                        return (l === 0);
                    }

                    return {
                        stack: function () {
                            _current = new CompArray();
                            _carrays.push(_current);
                        },
                        unstack: function () {
                            _current.variables.filter(function (v) {
                                if (v.unused)
                                    warning("W098", v.token, v.raw_text || v.value);
                                if (v.undef)
                                    state.funct["(scope)"].block.use(v.value, v.token);
                            });
                            _carrays.splice(-1, 1);
                            _current = _carrays[_carrays.length - 1];
                        },
                        setState: function (s) {
                            if (_.contains(["use", "define", "generate", "filter"], s))
                                _current.mode = s;
                        },
                        check: function (v) {
                            if (!_current) {
                                return;
                            }
                            if (_current && _current.mode === "use") {
                                if (use(v)) {
                                    _current.variables.push({
                                        funct: state.funct,
                                        token: state.tokens.curr,
                                        value: v,
                                        undef: true,
                                        unused: false
                                    });
                                }
                                return true;
                            } else if (_current && _current.mode === "define") {
                                if (!declare(v)) {
                                    _current.variables.push({
                                        funct: state.funct,
                                        token: state.tokens.curr,
                                        value: v,
                                        undef: false,
                                        unused: true
                                    });
                                }
                                return true;
                            } else if (_current && _current.mode === "generate") {
                                state.funct["(scope)"].block.use(v, state.tokens.curr);
                                return true;
                            } else if (_current && _current.mode === "filter") {
                                if (use(v)) {
                                    state.funct["(scope)"].block.use(v, state.tokens.curr);
                                }
                                return true;
                            }
                            return false;
                        }
                    };
                };

                function jsonValue() {
                    function jsonObject() {
                        var o = {}, t = state.tokens.next;
                        advance("{");
                        if (state.tokens.next.id !== "}") {
                            for (; ;) {
                                if (state.tokens.next.id === "(end)") {
                                    error("E026", state.tokens.next, t.line);
                                } else if (state.tokens.next.id === "}") {
                                    warning("W094", state.tokens.curr);
                                    break;
                                } else if (state.tokens.next.id === ",") {
                                    error("E028", state.tokens.next);
                                } else if (state.tokens.next.id !== "(string)") {
                                    warning("W095", state.tokens.next, state.tokens.next.value);
                                }
                                if (o[state.tokens.next.value] === true) {
                                    warning("W075", state.tokens.next, "key", state.tokens.next.value);
                                } else if ((state.tokens.next.value === "__proto__" &&
                                    !state.option.proto) || (state.tokens.next.value === "__iterator__" &&
                                    !state.option.iterator)) {
                                    warning("W096", state.tokens.next, state.tokens.next.value);
                                } else {
                                    o[state.tokens.next.value] = true;
                                }
                                advance();
                                advance(":");
                                jsonValue();
                                if (state.tokens.next.id !== ",") {
                                    break;
                                }
                                advance(",");
                            }
                        }
                        advance("}");
                    }

                    function jsonArray() {
                        var t = state.tokens.next;
                        advance("[");
                        if (state.tokens.next.id !== "]") {
                            for (; ;) {
                                if (state.tokens.next.id === "(end)") {
                                    error("E027", state.tokens.next, t.line);
                                } else if (state.tokens.next.id === "]") {
                                    warning("W094", state.tokens.curr);
                                    break;
                                } else if (state.tokens.next.id === ",") {
                                    error("E028", state.tokens.next);
                                }
                                jsonValue();
                                if (state.tokens.next.id !== ",") {
                                    break;
                                }
                                advance(",");
                            }
                        }
                        advance("]");
                    }

                    switch (state.tokens.next.id) {
                        case "{":
                            jsonObject();
                            break;
                        case "[":
                            jsonArray();
                            break;
                        case "true":
                        case "false":
                        case "null":
                        case "(number)":
                        case "(string)":
                            advance();
                            break;
                        case "-":
                            advance("-");
                            advance("(number)");
                            break;
                        default:
                            error("E003", state.tokens.next);
                    }
                }

                var escapeRegex = function (str) {
                    return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
                };
                var itself = function (s, o, g) {
                    var i, k, x, reIgnoreStr, reIgnore;
                    var optionKeys;
                    var newOptionObj = {};
                    var newIgnoredObj = {};

                    o = _.clone(o);
                    state.reset();

                    if (o && o.scope) {
                        JSHINT.scope = o.scope;
                    } else {
                        JSHINT.errors = [];
                        JSHINT.undefs = [];
                        JSHINT.internals = [];
                        JSHINT.blacklist = {};
                        JSHINT.scope = "(main)";
                    }

                    predefined = Object.create(null);
                    combine(predefined, vars.ecmaIdentifiers[3]);
                    combine(predefined, vars.reservedVars);

                    combine(predefined, g || {});

                    declared = Object.create(null);
                    var exported = Object.create(null); // Variables that live outside the current file

                    function each(obj, cb) {
                        if (!obj)
                            return;

                        if (!Array.isArray(obj) && typeof obj === "object")
                            obj = Object.keys(obj);

                        obj.forEach(cb);
                    }

                    if (o) {
                        each(o.predef || null, function (item) {
                            var slice, prop;

                            if (item[0] === "-") {
                                slice = item.slice(1);
                                JSHINT.blacklist[slice] = slice;
                                delete predefined[slice];
                            } else {
                                prop = Object.getOwnPropertyDescriptor(o.predef, item);
                                predefined[item] = prop ? prop.value : false;
                            }
                        });

                        each(o.exported || null, function (item) {
                            exported[item] = true;
                        });

                        delete o.predef;
                        delete o.exported;

                        optionKeys = Object.keys(o);
                        for (x = 0; x < optionKeys.length; x++) {
                            if (/^-W\d{3}$/g.test(optionKeys[x])) {
                                newIgnoredObj[optionKeys[x].slice(1)] = true;
                            } else {
                                var optionKey = optionKeys[x];
                                newOptionObj[optionKey] = o[optionKey];
                                if ((optionKey === "esversion" && o[optionKey] === 5) ||
                                    (optionKey === "es5" && o[optionKey])) {
                                    warning("I003");
                                }

                                if (optionKeys[x] === "newcap" && o[optionKey] === false)
                                    newOptionObj["(explicitNewcap)"] = true;
                            }
                        }
                    }

                    state.option = newOptionObj;
                    state.ignored = newIgnoredObj;

                    state.option.indent = state.option.indent || 4;
                    state.option.maxerr = state.option.maxerr || 50;

                    indent = 1;

                    var scopeManagerInst = scopeManager(state, predefined, exported, declared);
                    scopeManagerInst.on("warning", function (ev) {
                        warning.apply(null, [ev.code, ev.token].concat(ev.data));
                    });

                    scopeManagerInst.on("error", function (ev) {
                        error.apply(null, [ev.code, ev.token].concat(ev.data));
                    });

                    state.funct = functor("(global)", null, {
                        "(global)": true,
                        "(scope)": scopeManagerInst,
                        "(comparray)": arrayComprehension(),
                        "(metrics)": createMetrics(state.tokens.next)
                    });

                    functions = [state.funct];
                    urls = [];
                    stack = null;
                    member = {};
                    membersOnly = null;
                    inblock = false;
                    lookahead = [];

                    if (!isString(s) && !Array.isArray(s)) {
                        errorAt("E004", 0);
                        return false;
                    }

                    api = {
                        get isJSON() {
                            return state.jsonMode;
                        },

                        getOption: function (name) {
                            return state.option[name] || null;
                        },

                        getCache: function (name) {
                            return state.cache[name];
                        },

                        setCache: function (name, value) {
                            state.cache[name] = value;
                        },

                        warn: function (code, data) {
                            warningAt.apply(null, [code, data.line, data.char].concat(data.data));
                        },

                        on: function (names, listener) {
                            names.split(" ").forEach(function (name) {
                                emitter.on(name, listener);
                            }.bind(this));
                        }
                    };

                    emitter.removeAllListeners();
                    (extraModules || []).forEach(function (func) {
                        func(api);
                    });

                    state.tokens.prev = state.tokens.curr = state.tokens.next = state.syntax["(begin)"];

                    if (o && o.ignoreDelimiters) {

                        if (!Array.isArray(o.ignoreDelimiters)) {
                            o.ignoreDelimiters = [o.ignoreDelimiters];
                        }

                        o.ignoreDelimiters.forEach(function (delimiterPair) {
                            if (!delimiterPair.start || !delimiterPair.end)
                                return;

                            reIgnoreStr = escapeRegex(delimiterPair.start) +
                                "[\\s\\S]*?" +
                                escapeRegex(delimiterPair.end);

                            reIgnore = new RegExp(reIgnoreStr, "ig");

                            s = s.replace(reIgnore, function (match) {
                                return match.replace(/./g, " ");
                            });
                        });
                    }

                    lex = new Lexer(s);

                    lex.on("warning", function (ev) {
                        warningAt.apply(null, [ev.code, ev.line, ev.character].concat(ev.data));
                    });

                    lex.on("error", function (ev) {
                        errorAt.apply(null, [ev.code, ev.line, ev.character].concat(ev.data));
                    });

                    lex.on("fatal", function (ev) {
                        quit("E041", ev.line, ev.from);
                    });

                    lex.on("Identifier", function (ev) {
                        emitter.emit("Identifier", ev);
                    });

                    lex.on("String", function (ev) {
                        emitter.emit("String", ev);
                    });

                    lex.on("Number", function (ev) {
                        emitter.emit("Number", ev);
                    });

                    lex.start();
                    for (var name in o) {
                        if (_.has(o, name)) {
                            checkOption(name, state.tokens.curr);
                        }
                    }

                    assume();
                    combine(predefined, g || {});
                    comma.first = true;

                    try {
                        advance();
                        switch (state.tokens.next.id) {
                            case "{":
                            case "[":
                                destructuringAssignOrJsonValue();
                                break;
                            default:
                                directives();

                                if (state.directive["use strict"]) {
                                    if (state.option.strict !== "global") {
                                        warning("W097", state.tokens.prev);
                                    }
                                }

                                statements();
                        }

                        if (state.tokens.next.id !== "(end)") {
                            quit("E041", state.tokens.curr.line);
                        }

                        state.funct["(scope)"].unstack();

                    } catch (err) {
                        if (err && err.name === "JSHintError") {
                            var nt = state.tokens.next || {};
                            JSHINT.errors.push({
                                scope: "(main)",
                                raw: err.raw,
                                code: err.code,
                                reason: err.message,
                                line: err.line || nt.line,
                                character: err.character || nt.from
                            }, null);
                        } else {
                            throw err;
                        }
                    }

                    if (JSHINT.scope === "(main)") {
                        o = o || {};

                        for (i = 0; i < JSHINT.internals.length; i += 1) {
                            k = JSHINT.internals[i];
                            o.scope = k.elem;
                            itself(k.value, o, g);
                        }
                    }

                    return JSHINT.errors.length === 0;
                };
                itself.addModule = function (func) {
                    extraModules.push(func);
                };

                itself.addModule(style.register);
                itself.data = function () {
                    var data = {
                        functions: [],
                        options: state.option
                    };

                    var fu, f, i, j, n, globals;

                    if (itself.errors.length) {
                        data.errors = itself.errors;
                    }

                    if (state.jsonMode) {
                        data.json = true;
                    }

                    var impliedGlobals = state.funct["(scope)"].getImpliedGlobals();
                    if (impliedGlobals.length > 0) {
                        data.implieds = impliedGlobals;
                    }

                    if (urls.length > 0) {
                        data.urls = urls;
                    }

                    globals = state.funct["(scope)"].getUsedOrDefinedGlobals();
                    if (globals.length > 0) {
                        data.globals = globals;
                    }

                    for (i = 1; i < functions.length; i += 1) {
                        f = functions[i];
                        fu = {};

                        for (j = 0; j < functionicity.length; j += 1) {
                            fu[functionicity[j]] = [];
                        }

                        for (j = 0; j < functionicity.length; j += 1) {
                            if (fu[functionicity[j]].length === 0) {
                                delete fu[functionicity[j]];
                            }
                        }

                        fu.name = f["(name)"];
                        fu.param = f["(params)"];
                        fu.line = f["(line)"];
                        fu.character = f["(character)"];
                        fu.last = f["(last)"];
                        fu.lastcharacter = f["(lastcharacter)"];

                        fu.metrics = {
                            complexity: f["(metrics)"].ComplexityCount,
                            parameters: f["(metrics)"].arity,
                            statements: f["(metrics)"].statementCount
                        };

                        data.functions.push(fu);
                    }

                    var unuseds = state.funct["(scope)"].getUnuseds();
                    if (unuseds.length > 0) {
                        data.unused = unuseds;
                    }

                    for (n in member) {
                        if (typeof member[n] === "number") {
                            data.member = member;
                            break;
                        }
                    }

                    return data;
                };

                itself.jshint = itself;

                return itself;
            }());
            if (typeof exports === "object" && exports) {
                exports.JSHINT = JSHINT;
            }

        }, {
            "../lodash": "/node_modules/jshint/lodash.js",
            "./lex.js": "/node_modules/jshint/src/lex.js",
            "./messages.js": "/node_modules/jshint/src/messages.js",
            "./options.js": "/node_modules/jshint/src/options.js",
            "./reg.js": "/node_modules/jshint/src/reg.js",
            "./scope-manager.js": "/node_modules/jshint/src/scope-manager.js",
            "./state.js": "/node_modules/jshint/src/state.js",
            "./style.js": "/node_modules/jshint/src/style.js",
            "./vars.js": "/node_modules/jshint/src/vars.js",
            "events": "/node_modules/browserify/node_modules/events/events.js"
        }],
        "/node_modules/jshint/src/lex.js": [function (_dereq_, module, exports) {

            "use strict";

            var _ = _dereq_("../lodash");
            var events = _dereq_("events");
            var reg = _dereq_("./reg.js");
            var state = _dereq_("./state.js").state;

            var unicodeData = _dereq_("../data/ascii-identifier-data.js");
            var asciiIdentifierStartTable = unicodeData.asciiIdentifierStartTable;
            var asciiIdentifierPartTable = unicodeData.asciiIdentifierPartTable;

            var Token = {
                Identifier: 1,
                Punctuator: 2,
                NumericLiteral: 3,
                StringLiteral: 4,
                Comment: 5,
                Keyword: 6,
                NullLiteral: 7,
                BooleanLiteral: 8,
                RegExp: 9,
                TemplateHead: 10,
                TemplateMiddle: 11,
                TemplateTail: 12,
                NoSubstTemplate: 13
            };

            var Context = {
                Block: 1,
                Template: 2
            };

            function asyncTrigger() {
                var _checks = [];

                return {
                    push: function (fn) {
                        _checks.push(fn);
                    },

                    check: function () {
                        for (var check = 0; check < _checks.length; ++check) {
                            _checks[check]();
                        }

                        _checks.splice(0, _checks.length);
                    }
                };
            }

            function Lexer(source) {
                var lines = source;

                if (typeof lines === "string") {
                    lines = lines
                        .replace(/\r\n/g, "\n")
                        .replace(/\r/g, "\n")
                        .split("\n");
                }

                if (lines[0] && lines[0].substr(0, 2) === "#!") {
                    if (lines[0].indexOf("node") !== -1) {
                        state.option.node = true;
                    }
                    lines[0] = "";
                }

                this.emitter = new events.EventEmitter();
                this.source = source;
                this.setLines(lines);
                this.prereg = true;

                this.line = 0;
                this.char = 1;
                this.from = 1;
                this.input = "";
                this.inComment = false;
                this.context = [];
                this.templateStarts = [];

                for (var i = 0; i < state.option.indent; i += 1) {
                    state.tab += " ";
                }
                this.ignoreLinterErrors = false;
            }

            Lexer.prototype = {
                _lines: [],

                inContext: function (ctxType) {
                    return this.context.length > 0 && this.context[this.context.length - 1].type === ctxType;
                },

                pushContext: function (ctxType) {
                    this.context.push({type: ctxType});
                },

                popContext: function () {
                    return this.context.pop();
                },

                isContext: function (context) {
                    return this.context.length > 0 && this.context[this.context.length - 1] === context;
                },

                currentContext: function () {
                    return this.context.length > 0 && this.context[this.context.length - 1];
                },

                getLines: function () {
                    this._lines = state.lines;
                    return this._lines;
                },

                setLines: function (val) {
                    this._lines = val;
                    state.lines = this._lines;
                },
                peek: function (i) {
                    return this.input.charAt(i || 0);
                },
                skip: function (i) {
                    i = i || 1;
                    this.char += i;
                    this.input = this.input.slice(i);
                },
                on: function (names, listener) {
                    names.split(" ").forEach(function (name) {
                        this.emitter.on(name, listener);
                    }.bind(this));
                },
                trigger: function () {
                    this.emitter.emit.apply(this.emitter, Array.prototype.slice.call(arguments));
                },
                triggerAsync: function (type, args, checks, fn) {
                    checks.push(function () {
                        if (fn()) {
                            this.trigger(type, args);
                        }
                    }.bind(this));
                },
                scanPunctuator: function () {
                    var ch1 = this.peek();
                    var ch2, ch3, ch4;

                    switch (ch1) {
                        case ".":
                            if ((/^[0-9]$/).test(this.peek(1))) {
                                return null;
                            }
                            if (this.peek(1) === "." && this.peek(2) === ".") {
                                return {
                                    type: Token.Punctuator,
                                    value: "..."
                                };
                            }
                        case "(":
                        case ")":
                        case ";":
                        case ",":
                        case "[":
                        case "]":
                        case ":":
                        case "~":
                        case "?":
                            return {
                                type: Token.Punctuator,
                                value: ch1
                            };
                        case "{":
                            this.pushContext(Context.Block);
                            return {
                                type: Token.Punctuator,
                                value: ch1
                            };
                        case "}":
                            if (this.inContext(Context.Block)) {
                                this.popContext();
                            }
                            return {
                                type: Token.Punctuator,
                                value: ch1
                            };
                        case "#":
                            return {
                                type: Token.Punctuator,
                                value: ch1
                            };
                        case "":
                            return null;
                    }

                    ch2 = this.peek(1);
                    ch3 = this.peek(2);
                    ch4 = this.peek(3);

                    if (ch1 === ">" && ch2 === ">" && ch3 === ">" && ch4 === "=") {
                        return {
                            type: Token.Punctuator,
                            value: ">>>="
                        };
                    }

                    if (ch1 === "=" && ch2 === "=" && ch3 === "=") {
                        return {
                            type: Token.Punctuator,
                            value: "==="
                        };
                    }

                    if (ch1 === "!" && ch2 === "=" && ch3 === "=") {
                        return {
                            type: Token.Punctuator,
                            value: "!=="
                        };
                    }

                    if (ch1 === ">" && ch2 === ">" && ch3 === ">") {
                        return {
                            type: Token.Punctuator,
                            value: ">>>"
                        };
                    }

                    if (ch1 === "<" && ch2 === "<" && ch3 === "=") {
                        return {
                            type: Token.Punctuator,
                            value: "<<="
                        };
                    }

                    if (ch1 === ">" && ch2 === ">" && ch3 === "=") {
                        return {
                            type: Token.Punctuator,
                            value: ">>="
                        };
                    }
                    if (ch1 === "=" && ch2 === ">") {
                        return {
                            type: Token.Punctuator,
                            value: ch1 + ch2
                        };
                    }
                    if (ch1 === ch2 && ("+-<>&|".indexOf(ch1) >= 0)) {
                        return {
                            type: Token.Punctuator,
                            value: ch1 + ch2
                        };
                    }

                    if ("<>=!+-*%&|^".indexOf(ch1) >= 0) {
                        if (ch2 === "=") {
                            return {
                                type: Token.Punctuator,
                                value: ch1 + ch2
                            };
                        }

                        return {
                            type: Token.Punctuator,
                            value: ch1
                        };
                    }

                    if (ch1 === "/") {
                        if (ch2 === "=") {
                            return {
                                type: Token.Punctuator,
                                value: "/="
                            };
                        }

                        return {
                            type: Token.Punctuator,
                            value: "/"
                        };
                    }

                    return null;
                },
                scanComments: function () {
                    var ch1 = this.peek();
                    var ch2 = this.peek(1);
                    var rest = this.input.substr(2);
                    var startLine = this.line;
                    var startChar = this.char;
                    var self = this;

                    function commentToken(label, body, opt) {
                        var special = ["jshint", "jslint", "members", "member", "globals", "global", "exported"];
                        var isSpecial = false;
                        var value = label + body;
                        var commentType = "plain";
                        opt = opt || {};

                        if (opt.isMultiline) {
                            value += "*/";
                        }

                        body = body.replace(/\n/g, " ");

                        if (label === "/*" && reg.fallsThrough.test(body)) {
                            isSpecial = true;
                            commentType = "falls through";
                        }

                        special.forEach(function (str) {
                            if (isSpecial) {
                                return;
                            }
                            if (label === "//" && str !== "jshint") {
                                return;
                            }

                            if (body.charAt(str.length) === " " && body.substr(0, str.length) === str) {
                                isSpecial = true;
                                label = label + str;
                                body = body.substr(str.length);
                            }

                            if (!isSpecial && body.charAt(0) === " " && body.charAt(str.length + 1) === " " &&
                                body.substr(1, str.length) === str) {
                                isSpecial = true;
                                label = label + " " + str;
                                body = body.substr(str.length + 1);
                            }

                            if (!isSpecial) {
                                return;
                            }

                            switch (str) {
                                case "member":
                                    commentType = "members";
                                    break;
                                case "global":
                                    commentType = "globals";
                                    break;
                                default:
                                    var options = body.split(":").map(function (v) {
                                        return v.replace(/^\s+/, "").replace(/\s+$/, "");
                                    });

                                    if (options.length === 2) {
                                        switch (options[0]) {
                                            case "ignore":
                                                switch (options[1]) {
                                                    case "start":
                                                        self.ignoringLinterErrors = true;
                                                        isSpecial = false;
                                                        break;
                                                    case "end":
                                                        self.ignoringLinterErrors = false;
                                                        isSpecial = false;
                                                        break;
                                                }
                                        }
                                    }

                                    commentType = str;
                            }
                        });

                        return {
                            type: Token.Comment,
                            commentType: commentType,
                            value: value,
                            body: body,
                            isSpecial: isSpecial,
                            isMultiline: opt.isMultiline || false,
                            isMalformed: opt.isMalformed || false
                        };
                    }

                    if (ch1 === "*" && ch2 === "/") {
                        this.trigger("error", {
                            code: "E018",
                            line: startLine,
                            character: startChar
                        });

                        this.skip(2);
                        return null;
                    }
                    if (ch1 !== "/" || (ch2 !== "*" && ch2 !== "/")) {
                        return null;
                    }
                    if (ch2 === "/") {
                        this.skip(this.input.length); // Skip to the EOL.
                        return commentToken("//", rest);
                    }

                    var body = "";
                    if (ch2 === "*") {
                        this.inComment = true;
                        this.skip(2);

                        while (this.peek() !== "*" || this.peek(1) !== "/") {
                            if (this.peek() === "") { // End of Line
                                body += "\n";
                                if (!this.nextLine()) {
                                    this.trigger("error", {
                                        code: "E017",
                                        line: startLine,
                                        character: startChar
                                    });

                                    this.inComment = false;
                                    return commentToken("/*", body, {
                                        isMultiline: true,
                                        isMalformed: true
                                    });
                                }
                            } else {
                                body += this.peek();
                                this.skip();
                            }
                        }

                        this.skip(2);
                        this.inComment = false;
                        return commentToken("/*", body, {isMultiline: true});
                    }
                },
                scanKeyword: function () {
                    var result = /^[a-zA-Z_$][a-zA-Z0-9_$]*/.exec(this.input);
                    var keywords = [
                        "if", "in", "do", "var", "for", "new",
                        "try", "let", "this", "else", "case",
                        "void", "with", "enum", "while", "break",
                        "catch", "throw", "const", "yield", "class",
                        "super", "return", "typeof", "delete",
                        "switch", "export", "import", "default",
                        "finally", "extends", "function", "continue",
                        "debugger", "instanceof"
                    ];

                    if (result && keywords.indexOf(result[0]) >= 0) {
                        return {
                            type: Token.Keyword,
                            value: result[0]
                        };
                    }

                    return null;
                },
                scanIdentifier: function () {
                    var id = "";
                    var index = 0;
                    var type, char;

                    function isNonAsciiIdentifierStart(code) {
                        return code > 256;
                    }

                    function isNonAsciiIdentifierPart(code) {
                        return code > 256;
                    }

                    function isHexDigit(str) {
                        return (/^[0-9a-fA-F]$/).test(str);
                    }

                    var readUnicodeEscapeSequence = function () {
                        index += 1;

                        if (this.peek(index) !== "u") {
                            return null;
                        }

                        var ch1 = this.peek(index + 1);
                        var ch2 = this.peek(index + 2);
                        var ch3 = this.peek(index + 3);
                        var ch4 = this.peek(index + 4);
                        var code;

                        if (isHexDigit(ch1) && isHexDigit(ch2) && isHexDigit(ch3) && isHexDigit(ch4)) {
                            code = parseInt(ch1 + ch2 + ch3 + ch4, 16);

                            if (asciiIdentifierPartTable[code] || isNonAsciiIdentifierPart(code)) {
                                index += 5;
                                return "\\u" + ch1 + ch2 + ch3 + ch4;
                            }

                            return null;
                        }

                        return null;
                    }.bind(this);

                    var getIdentifierStart = function () {
                        var chr = this.peek(index);
                        var code = chr.charCodeAt(0);

                        if (code === 92) {
                            return readUnicodeEscapeSequence();
                        }

                        if (code < 128) {
                            if (asciiIdentifierStartTable[code]) {
                                index += 1;
                                return chr;
                            }

                            return null;
                        }

                        if (isNonAsciiIdentifierStart(code)) {
                            index += 1;
                            return chr;
                        }

                        return null;
                    }.bind(this);

                    var getIdentifierPart = function () {
                        var chr = this.peek(index);
                        var code = chr.charCodeAt(0);

                        if (code === 92) {
                            return readUnicodeEscapeSequence();
                        }

                        if (code < 128) {
                            if (asciiIdentifierPartTable[code]) {
                                index += 1;
                                return chr;
                            }

                            return null;
                        }

                        if (isNonAsciiIdentifierPart(code)) {
                            index += 1;
                            return chr;
                        }

                        return null;
                    }.bind(this);

                    function removeEscapeSequences(id) {
                        return id.replace(/\\u([0-9a-fA-F]{4})/g, function (m0, codepoint) {
                            return String.fromCharCode(parseInt(codepoint, 16));
                        });
                    }

                    char = getIdentifierStart();
                    if (char === null) {
                        return null;
                    }

                    id = char;
                    for (; ;) {
                        char = getIdentifierPart();

                        if (char === null) {
                            break;
                        }

                        id += char;
                    }

                    switch (id) {
                        case "true":
                        case "false":
                            type = Token.BooleanLiteral;
                            break;
                        case "null":
                            type = Token.NullLiteral;
                            break;
                        default:
                            type = Token.Identifier;
                    }

                    return {
                        type: type,
                        value: removeEscapeSequences(id),
                        text: id,
                        tokenLength: id.length
                    };
                },
                scanNumericLiteral: function () {
                    var index = 0;
                    var value = "";
                    var length = this.input.length;
                    var char = this.peek(index);
                    var bad;
                    var isAllowedDigit = isDecimalDigit;
                    var base = 10;
                    var isLegacy = false;

                    function isDecimalDigit(str) {
                        return (/^[0-9]$/).test(str);
                    }

                    function isOctalDigit(str) {
                        return (/^[0-7]$/).test(str);
                    }

                    function isBinaryDigit(str) {
                        return (/^[01]$/).test(str);
                    }

                    function isHexDigit(str) {
                        return (/^[0-9a-fA-F]$/).test(str);
                    }

                    function isIdentifierStart(ch) {
                        return (ch === "$") || (ch === "_") || (ch === "\\") ||
                            (ch >= "a" && ch <= "z") || (ch >= "A" && ch <= "Z");
                    }

                    if (char !== "." && !isDecimalDigit(char)) {
                        return null;
                    }

                    if (char !== ".") {
                        value = this.peek(index);
                        index += 1;
                        char = this.peek(index);

                        if (value === "0") {
                            if (char === "x" || char === "X") {
                                isAllowedDigit = isHexDigit;
                                base = 16;

                                index += 1;
                                value += char;
                            }
                            if (char === "o" || char === "O") {
                                isAllowedDigit = isOctalDigit;
                                base = 8;

                                if (!state.inES6(true)) {
                                    this.trigger("warning", {
                                        code: "W119",
                                        line: this.line,
                                        character: this.char,
                                        data: ["Octal integer literal", "6"]
                                    });
                                }

                                index += 1;
                                value += char;
                            }
                            if (char === "b" || char === "B") {
                                isAllowedDigit = isBinaryDigit;
                                base = 2;

                                if (!state.inES6(true)) {
                                    this.trigger("warning", {
                                        code: "W119",
                                        line: this.line,
                                        character: this.char,
                                        data: ["Binary integer literal", "6"]
                                    });
                                }

                                index += 1;
                                value += char;
                            }
                            if (isOctalDigit(char)) {
                                isAllowedDigit = isOctalDigit;
                                base = 8;
                                isLegacy = true;
                                bad = false;

                                index += 1;
                                value += char;
                            }

                            if (!isOctalDigit(char) && isDecimalDigit(char)) {
                                index += 1;
                                value += char;
                            }
                        }

                        while (index < length) {
                            char = this.peek(index);

                            if (isLegacy && isDecimalDigit(char)) {
                                bad = true;
                            } else if (!isAllowedDigit(char)) {
                                break;
                            }
                            value += char;
                            index += 1;
                        }

                        if (isAllowedDigit !== isDecimalDigit) {
                            if (!isLegacy && value.length <= 2) { // 0x
                                return {
                                    type: Token.NumericLiteral,
                                    value: value,
                                    isMalformed: true
                                };
                            }

                            if (index < length) {
                                char = this.peek(index);
                                if (isIdentifierStart(char)) {
                                    return null;
                                }
                            }

                            return {
                                type: Token.NumericLiteral,
                                value: value,
                                base: base,
                                isLegacy: isLegacy,
                                isMalformed: false
                            };
                        }
                    }

                    if (char === ".") {
                        value += char;
                        index += 1;

                        while (index < length) {
                            char = this.peek(index);
                            if (!isDecimalDigit(char)) {
                                break;
                            }
                            value += char;
                            index += 1;
                        }
                    }

                    if (char === "e" || char === "E") {
                        value += char;
                        index += 1;
                        char = this.peek(index);

                        if (char === "+" || char === "-") {
                            value += this.peek(index);
                            index += 1;
                        }

                        char = this.peek(index);
                        if (isDecimalDigit(char)) {
                            value += char;
                            index += 1;

                            while (index < length) {
                                char = this.peek(index);
                                if (!isDecimalDigit(char)) {
                                    break;
                                }
                                value += char;
                                index += 1;
                            }
                        } else {
                            return null;
                        }
                    }

                    if (index < length) {
                        char = this.peek(index);
                        if (isIdentifierStart(char)) {
                            return null;
                        }
                    }

                    return {
                        type: Token.NumericLiteral,
                        value: value,
                        base: base,
                        isMalformed: !isFinite(value)
                    };
                },
                scanEscapeSequence: function (checks) {
                    var allowNewLine = false;
                    var jump = 1;
                    this.skip();
                    var char = this.peek();

                    switch (char) {
                        case "'":
                            this.triggerAsync("warning", {
                                code: "W114",
                                line: this.line,
                                character: this.char,
                                data: ["\\'"]
                            }, checks, function () {
                                return state.jsonMode;
                            });
                            break;
                        case "b":
                            char = "\\b";
                            break;
                        case "f":
                            char = "\\f";
                            break;
                        case "n":
                            char = "\\n";
                            break;
                        case "r":
                            char = "\\r";
                            break;
                        case "t":
                            char = "\\t";
                            break;
                        case "0":
                            char = "\\0";
                            var n = parseInt(this.peek(1), 10);
                            this.triggerAsync("warning", {
                                    code: "W115",
                                    line: this.line,
                                    character: this.char
                                }, checks,
                                function () {
                                    return n >= 0 && n <= 7 && state.isStrict();
                                });
                            break;
                        case "u":
                            var hexCode = this.input.substr(1, 4);
                            var code = parseInt(hexCode, 16);
                            if (isNaN(code)) {
                                this.trigger("warning", {
                                    code: "W052",
                                    line: this.line,
                                    character: this.char,
                                    data: ["u" + hexCode]
                                });
                            }
                            char = String.fromCharCode(code);
                            jump = 5;
                            break;
                        case "v":
                            this.triggerAsync("warning", {
                                code: "W114",
                                line: this.line,
                                character: this.char,
                                data: ["\\v"]
                            }, checks, function () {
                                return state.jsonMode;
                            });

                            char = "\v";
                            break;
                        case "x":
                            var x = parseInt(this.input.substr(1, 2), 16);

                            this.triggerAsync("warning", {
                                code: "W114",
                                line: this.line,
                                character: this.char,
                                data: ["\\x-"]
                            }, checks, function () {
                                return state.jsonMode;
                            });

                            char = String.fromCharCode(x);
                            jump = 3;
                            break;
                        case "\\":
                            char = "\\\\";
                            break;
                        case "\"":
                            char = "\\\"";
                            break;
                        case "/":
                            break;
                        case "":
                            allowNewLine = true;
                            char = "";
                            break;
                    }

                    return {char: char, jump: jump, allowNewLine: allowNewLine};
                },
                scanTemplateLiteral: function (checks) {
                    var tokenType;
                    var value = "";
                    var ch;
                    var startLine = this.line;
                    var startChar = this.char;
                    var depth = this.templateStarts.length;

                    if (!state.inES6(true)) {
                        return null;
                    } else if (this.peek() === "`") {
                        tokenType = Token.TemplateHead;
                        this.templateStarts.push({line: this.line, char: this.char});
                        depth = this.templateStarts.length;
                        this.skip(1);
                        this.pushContext(Context.Template);
                    } else if (this.inContext(Context.Template) && this.peek() === "}") {
                        tokenType = Token.TemplateMiddle;
                    } else {
                        return null;
                    }

                    while (this.peek() !== "`") {
                        while ((ch = this.peek()) === "") {
                            value += "\n";
                            if (!this.nextLine()) {
                                var startPos = this.templateStarts.pop();
                                this.trigger("error", {
                                    code: "E052",
                                    line: startPos.line,
                                    character: startPos.char
                                });
                                return {
                                    type: tokenType,
                                    value: value,
                                    startLine: startLine,
                                    startChar: startChar,
                                    isUnclosed: true,
                                    depth: depth,
                                    context: this.popContext()
                                };
                            }
                        }

                        if (ch === '$' && this.peek(1) === '{') {
                            value += '${';
                            this.skip(2);
                            return {
                                type: tokenType,
                                value: value,
                                startLine: startLine,
                                startChar: startChar,
                                isUnclosed: false,
                                depth: depth,
                                context: this.currentContext()
                            };
                        } else if (ch === '\\') {
                            var escape = this.scanEscapeSequence(checks);
                            value += escape.char;
                            this.skip(escape.jump);
                        } else if (ch !== '`') {
                            value += ch;
                            this.skip(1);
                        }
                    }
                    tokenType = tokenType === Token.TemplateHead ? Token.NoSubstTemplate : Token.TemplateTail;
                    this.skip(1);
                    this.templateStarts.pop();

                    return {
                        type: tokenType,
                        value: value,
                        startLine: startLine,
                        startChar: startChar,
                        isUnclosed: false,
                        depth: depth,
                        context: this.popContext()
                    };
                },
                scanStringLiteral: function (checks) {
                    var quote = this.peek();
                    if (quote !== "\"" && quote !== "'") {
                        return null;
                    }
                    this.triggerAsync("warning", {
                        code: "W108",
                        line: this.line,
                        character: this.char // +1?
                    }, checks, function () {
                        return state.jsonMode && quote !== "\"";
                    });

                    var value = "";
                    var startLine = this.line;
                    var startChar = this.char;
                    var allowNewLine = false;

                    this.skip();

                    while (this.peek() !== quote) {
                        if (this.peek() === "") { // End Of Line

                            if (!allowNewLine) {
                                this.trigger("warning", {
                                    code: "W112",
                                    line: this.line,
                                    character: this.char
                                });
                            } else {
                                allowNewLine = false;

                                this.triggerAsync("warning", {
                                    code: "W043",
                                    line: this.line,
                                    character: this.char
                                }, checks, function () {
                                    return !state.option.multistr;
                                });

                                this.triggerAsync("warning", {
                                    code: "W042",
                                    line: this.line,
                                    character: this.char
                                }, checks, function () {
                                    return state.jsonMode && state.option.multistr;
                                });
                            }

                            if (!this.nextLine()) {
                                this.trigger("error", {
                                    code: "E029",
                                    line: startLine,
                                    character: startChar
                                });

                                return {
                                    type: Token.StringLiteral,
                                    value: value,
                                    startLine: startLine,
                                    startChar: startChar,
                                    isUnclosed: true,
                                    quote: quote
                                };
                            }

                        } else { // Any character other than End Of Line

                            allowNewLine = false;
                            var char = this.peek();
                            var jump = 1; // A length of a jump, after we're done

                            if (char < " ") {
                                this.trigger("warning", {
                                    code: "W113",
                                    line: this.line,
                                    character: this.char,
                                    data: ["<non-printable>"]
                                });
                            }
                            if (char === "\\") {
                                var parsed = this.scanEscapeSequence(checks);
                                char = parsed.char;
                                jump = parsed.jump;
                                allowNewLine = parsed.allowNewLine;
                            }

                            value += char;
                            this.skip(jump);
                        }
                    }

                    this.skip();
                    return {
                        type: Token.StringLiteral,
                        value: value,
                        startLine: startLine,
                        startChar: startChar,
                        isUnclosed: false,
                        quote: quote
                    };
                },
                scanRegExp: function () {
                    var index = 0;
                    var length = this.input.length;
                    var char = this.peek();
                    var value = char;
                    var body = "";
                    var flags = [];
                    var malformed = false;
                    var isCharSet = false;
                    var terminated;

                    var scanUnexpectedChars = function () {
                        if (char < " ") {
                            malformed = true;
                            this.trigger("warning", {
                                code: "W048",
                                line: this.line,
                                character: this.char
                            });
                        }
                        if (char === "<") {
                            malformed = true;
                            this.trigger("warning", {
                                code: "W049",
                                line: this.line,
                                character: this.char,
                                data: [char]
                            });
                        }
                    }.bind(this);
                    if (!this.prereg || char !== "/") {
                        return null;
                    }

                    index += 1;
                    terminated = false;

                    while (index < length) {
                        char = this.peek(index);
                        value += char;
                        body += char;

                        if (isCharSet) {
                            if (char === "]") {
                                if (this.peek(index - 1) !== "\\" || this.peek(index - 2) === "\\") {
                                    isCharSet = false;
                                }
                            }

                            if (char === "\\") {
                                index += 1;
                                char = this.peek(index);
                                body += char;
                                value += char;

                                scanUnexpectedChars();
                            }

                            index += 1;
                            continue;
                        }

                        if (char === "\\") {
                            index += 1;
                            char = this.peek(index);
                            body += char;
                            value += char;

                            scanUnexpectedChars();

                            if (char === "/") {
                                index += 1;
                                continue;
                            }

                            if (char === "[") {
                                index += 1;
                                continue;
                            }
                        }

                        if (char === "[") {
                            isCharSet = true;
                            index += 1;
                            continue;
                        }

                        if (char === "/") {
                            body = body.substr(0, body.length - 1);
                            terminated = true;
                            index += 1;
                            break;
                        }

                        index += 1;
                    }

                    if (!terminated) {
                        this.trigger("error", {
                            code: "E015",
                            line: this.line,
                            character: this.from
                        });

                        return void this.trigger("fatal", {
                            line: this.line,
                            from: this.from
                        });
                    }

                    while (index < length) {
                        char = this.peek(index);
                        if (!/[gim]/.test(char)) {
                            break;
                        }
                        flags.push(char);
                        value += char;
                        index += 1;
                    }

                    try {
                        new RegExp(body, flags.join(""));
                    } catch (err) {
                        malformed = true;
                        this.trigger("error", {
                            code: "E016",
                            line: this.line,
                            character: this.char,
                            data: [err.message] // Platform dependent!
                        });
                    }

                    return {
                        type: Token.RegExp,
                        value: value,
                        flags: flags,
                        isMalformed: malformed
                    };
                },
                scanNonBreakingSpaces: function () {
                    return state.option.nonbsp ?
                        this.input.search(/(\u00A0)/) : -1;
                },
                scanUnsafeChars: function () {
                    return this.input.search(reg.unsafeChars);
                },
                next: function (checks) {
                    this.from = this.char;
                    var start;
                    if (/\s/.test(this.peek())) {
                        start = this.char;

                        while (/\s/.test(this.peek())) {
                            this.from += 1;
                            this.skip();
                        }
                    }

                    var match = this.scanComments() ||
                        this.scanStringLiteral(checks) ||
                        this.scanTemplateLiteral(checks);

                    if (match) {
                        return match;
                    }

                    match =
                        this.scanRegExp() ||
                        this.scanPunctuator() ||
                        this.scanKeyword() ||
                        this.scanIdentifier() ||
                        this.scanNumericLiteral();

                    if (match) {
                        this.skip(match.tokenLength || match.value.length);
                        return match;
                    }

                    return null;
                },
                nextLine: function () {
                    var char;

                    if (this.line >= this.getLines().length) {
                        return false;
                    }

                    this.input = this.getLines()[this.line];
                    this.line += 1;
                    this.char = 1;
                    this.from = 1;

                    var inputTrimmed = this.input.trim();

                    var startsWith = function () {
                        return _.some(arguments, function (prefix) {
                            return inputTrimmed.indexOf(prefix) === 0;
                        });
                    };

                    var endsWith = function () {
                        return _.some(arguments, function (suffix) {
                            return inputTrimmed.indexOf(suffix, inputTrimmed.length - suffix.length) !== -1;
                        });
                    };
                    if (this.ignoringLinterErrors === true) {
                        if (!startsWith("/*", "//") && !(this.inComment && endsWith("*/"))) {
                            this.input = "";
                        }
                    }

                    char = this.scanNonBreakingSpaces();
                    if (char >= 0) {
                        this.trigger("warning", {code: "W125", line: this.line, character: char + 1});
                    }

                    this.input = this.input.replace(/\t/g, state.tab);
                    char = this.scanUnsafeChars();

                    if (char >= 0) {
                        this.trigger("warning", {code: "W100", line: this.line, character: char});
                    }

                    if (!this.ignoringLinterErrors && state.option.maxlen &&
                        state.option.maxlen < this.input.length) {
                        var inComment = this.inComment ||
                            startsWith.call(inputTrimmed, "//") ||
                            startsWith.call(inputTrimmed, "/*");

                        var shouldTriggerError = !inComment || !reg.maxlenException.test(inputTrimmed);

                        if (shouldTriggerError) {
                            this.trigger("warning", {code: "W101", line: this.line, character: this.input.length});
                        }
                    }

                    return true;
                },
                start: function () {
                    this.nextLine();
                },
                token: function () {
                    var checks = asyncTrigger();
                    var token;


                    function isReserved(token, isProperty) {
                        if (!token.reserved) {
                            return false;
                        }
                        var meta = token.meta;

                        if (meta && meta.isFutureReservedWord && state.inES5()) {
                            if (!meta.es5) {
                                return false;
                            }
                            if (meta.strictOnly) {
                                if (!state.option.strict && !state.isStrict()) {
                                    return false;
                                }
                            }

                            if (isProperty) {
                                return false;
                            }
                        }

                        return true;
                    }

                    var create = function (type, value, isProperty, token) {
                        var obj;

                        if (type !== "(endline)" && type !== "(end)") {
                            this.prereg = false;
                        }

                        if (type === "(punctuator)") {
                            switch (value) {
                                case ".":
                                case ")":
                                case "~":
                                case "#":
                                case "]":
                                case "++":
                                case "--":
                                    this.prereg = false;
                                    break;
                                default:
                                    this.prereg = true;
                            }

                            obj = Object.create(state.syntax[value] || state.syntax["(error)"]);
                        }

                        if (type === "(identifier)") {
                            if (value === "return" || value === "case" || value === "typeof") {
                                this.prereg = true;
                            }

                            if (_.has(state.syntax, value)) {
                                obj = Object.create(state.syntax[value] || state.syntax["(error)"]);
                                if (!isReserved(obj, isProperty && type === "(identifier)")) {
                                    obj = null;
                                }
                            }
                        }

                        if (!obj) {
                            obj = Object.create(state.syntax[type]);
                        }

                        obj.identifier = (type === "(identifier)");
                        obj.type = obj.type || type;
                        obj.value = value;
                        obj.line = this.line;
                        obj.character = this.char;
                        obj.from = this.from;
                        if (obj.identifier && token) obj.raw_text = token.text || token.value;
                        if (token && token.startLine && token.startLine !== this.line) {
                            obj.startLine = token.startLine;
                        }
                        if (token && token.context) {
                            obj.context = token.context;
                        }
                        if (token && token.depth) {
                            obj.depth = token.depth;
                        }
                        if (token && token.isUnclosed) {
                            obj.isUnclosed = token.isUnclosed;
                        }

                        if (isProperty && obj.identifier) {
                            obj.isProperty = isProperty;
                        }

                        obj.check = checks.check;

                        return obj;
                    }.bind(this);

                    for (; ;) {
                        if (!this.input.length) {
                            if (this.nextLine()) {
                                return create("(endline)", "");
                            }

                            if (this.exhausted) {
                                return null;
                            }

                            this.exhausted = true;
                            return create("(end)", "");
                        }

                        token = this.next(checks);

                        if (!token) {
                            if (this.input.length) {
                                this.trigger("error", {
                                    code: "E024",
                                    line: this.line,
                                    character: this.char,
                                    data: [this.peek()]
                                });

                                this.input = "";
                            }

                            continue;
                        }

                        switch (token.type) {
                            case Token.StringLiteral:
                                this.triggerAsync("String", {
                                    line: this.line,
                                    char: this.char,
                                    from: this.from,
                                    startLine: token.startLine,
                                    startChar: token.startChar,
                                    value: token.value,
                                    quote: token.quote
                                }, checks, function () {
                                    return true;
                                });

                                return create("(string)", token.value, null, token);

                            case Token.TemplateHead:
                                this.trigger("TemplateHead", {
                                    line: this.line,
                                    char: this.char,
                                    from: this.from,
                                    startLine: token.startLine,
                                    startChar: token.startChar,
                                    value: token.value
                                });
                                return create("(template)", token.value, null, token);

                            case Token.TemplateMiddle:
                                this.trigger("TemplateMiddle", {
                                    line: this.line,
                                    char: this.char,
                                    from: this.from,
                                    startLine: token.startLine,
                                    startChar: token.startChar,
                                    value: token.value
                                });
                                return create("(template middle)", token.value, null, token);

                            case Token.TemplateTail:
                                this.trigger("TemplateTail", {
                                    line: this.line,
                                    char: this.char,
                                    from: this.from,
                                    startLine: token.startLine,
                                    startChar: token.startChar,
                                    value: token.value
                                });
                                return create("(template tail)", token.value, null, token);

                            case Token.NoSubstTemplate:
                                this.trigger("NoSubstTemplate", {
                                    line: this.line,
                                    char: this.char,
                                    from: this.from,
                                    startLine: token.startLine,
                                    startChar: token.startChar,
                                    value: token.value
                                });
                                return create("(no subst template)", token.value, null, token);

                            case Token.Identifier:
                                this.triggerAsync("Identifier", {
                                    line: this.line,
                                    char: this.char,
                                    from: this.form,
                                    name: token.value,
                                    raw_name: token.text,
                                    isProperty: state.tokens.curr.id === "."
                                }, checks, function () {
                                    return true;
                                });
                            case Token.Keyword:
                            case Token.NullLiteral:
                            case Token.BooleanLiteral:
                                return create("(identifier)", token.value, state.tokens.curr.id === ".", token);

                            case Token.NumericLiteral:
                                if (token.isMalformed) {
                                    this.trigger("warning", {
                                        code: "W045",
                                        line: this.line,
                                        character: this.char,
                                        data: [token.value]
                                    });
                                }

                                this.triggerAsync("warning", {
                                    code: "W114",
                                    line: this.line,
                                    character: this.char,
                                    data: ["0x-"]
                                }, checks, function () {
                                    return token.base === 16 && state.jsonMode;
                                });

                                this.triggerAsync("warning", {
                                    code: "W115",
                                    line: this.line,
                                    character: this.char
                                }, checks, function () {
                                    return state.isStrict() && token.base === 8 && token.isLegacy;
                                });

                                this.trigger("Number", {
                                    line: this.line,
                                    char: this.char,
                                    from: this.from,
                                    value: token.value,
                                    base: token.base,
                                    isMalformed: token.malformed
                                });

                                return create("(number)", token.value);

                            case Token.RegExp:
                                return create("(regexp)", token.value);

                            case Token.Comment:
                                state.tokens.curr.comment = true;

                                if (token.isSpecial) {
                                    return {
                                        id: '(comment)',
                                        value: token.value,
                                        body: token.body,
                                        type: token.commentType,
                                        isSpecial: token.isSpecial,
                                        line: this.line,
                                        character: this.char,
                                        from: this.from
                                    };
                                }

                                break;

                            case "":
                                break;

                            default:
                                return create("(punctuator)", token.value);
                        }
                    }
                }
            };

            exports.Lexer = Lexer;
            exports.Context = Context;

        }, {
            "../data/ascii-identifier-data.js": "/node_modules/jshint/data/ascii-identifier-data.js",
            "../lodash": "/node_modules/jshint/lodash.js",
            "./reg.js": "/node_modules/jshint/src/reg.js",
            "./state.js": "/node_modules/jshint/src/state.js",
            "events": "/node_modules/browserify/node_modules/events/events.js"
        }],
        "/node_modules/jshint/src/messages.js": [function (_dereq_, module, exports) {
            "use strict";

            var _ = _dereq_("../lodash");

            var errors = {
                E001: "Bad option: '{a}'.",
                E002: "Bad option value.",
                E003: "Expected a JSON value.",
                E004: "Input is neither a string nor an array of strings.",
                E005: "Input is empty.",
                E006: "Unexpected early end of program.",
                E007: "Missing \"use strict\" statement.",
                E008: "Strict violation.",
                E009: "Option 'validthis' can't be used in a global scope.",
                E010: "'with' is not allowed in strict mode.",
                E011: "'{a}' has already been declared.",
                E012: "const '{a}' is initialized to 'undefined'.",
                E013: "Attempting to override '{a}' which is a constant.",
                E014: "A regular expression literal can be confused with '/='.",
                E015: "Unclosed regular expression.",
                E016: "Invalid regular expression.",
                E017: "Unclosed comment.",
                E018: "Unbegun comment.",
                E019: "Unmatched '{a}'.",
                E020: "Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.",
                E021: "Expected '{a}' and instead saw '{b}'.",
                E022: "Line breaking error '{a}'.",
                E023: "Missing '{a}'.",
                E024: "Unexpected '{a}'.",
                E025: "Missing ':' on a case clause.",
                E026: "Missing '}' to match '{' from line {a}.",
                E027: "Missing ']' to match '[' from line {a}.",
                E028: "Illegal comma.",
                E029: "Unclosed string.",
                E030: "Expected an identifier and instead saw '{a}'.",
                E031: "Bad assignment.", // FIXME: Rephrase
                E032: "Expected a small integer or 'false' and instead saw '{a}'.",
                E033: "Expected an operator and instead saw '{a}'.",
                E034: "get/set are ES5 features.",
                E035: "Missing property name.",
                E036: "Expected to see a statement and instead saw a block.",
                E037: null,
                E038: null,
                E039: "Function declarations are not invocable. Wrap the whole function invocation in parens.",
                E040: "Each value should have its own case label.",
                E041: "Unrecoverable syntax error.",
                E042: "Stopping.",
                E043: "Too many errors.",
                E044: null,
                E045: "Invalid for each loop.",
                E046: "A yield statement shall be within a generator function (with syntax: `function*`)",
                E047: null,
                E048: "{a} declaration not directly within block.",
                E049: "A {a} cannot be named '{b}'.",
                E050: "Mozilla requires the yield expression to be parenthesized here.",
                E051: null,
                E052: "Unclosed template literal.",
                E053: "Export declaration must be in global scope.",
                E054: "Class properties must be methods. Expected '(' but instead saw '{a}'.",
                E055: "The '{a}' option cannot be set after any executable code.",
                E056: "'{a}' was used before it was declared, which is illegal for '{b}' variables.",
                E057: "Invalid meta property: '{a}.{b}'.",
                E058: "Missing semicolon."
            };

            var warnings = {
                W001: "'hasOwnProperty' is a really bad name.",
                W002: "Value of '{a}' may be overwritten in IE 8 and earlier.",
                W003: "'{a}' was used before it was defined.",
                W004: "'{a}' is already defined.",
                W005: "A dot following a number can be confused with a decimal point.",
                W006: "Confusing minuses.",
                W007: "Confusing plusses.",
                W008: "A leading decimal point can be confused with a dot: '{a}'.",
                W009: "The array literal notation [] is preferable.",
                W010: "The object literal notation {} is preferable.",
                W011: null,
                W012: null,
                W013: null,
                W014: "Bad line breaking before '{a}'.",
                W015: null,
                W016: "Unexpected use of '{a}'.",
                W017: "Bad operand.",
                W018: "Confusing use of '{a}'.",
                W019: "Use the isNaN function to compare with NaN.",
                W020: "Read only.",
                W021: "Reassignment of '{a}', which is is a {b}. " +
                    "Use 'var' or 'let' to declare bindings that may change.",
                W022: "Do not assign to the exception parameter.",
                W023: "Expected an identifier in an assignment and instead saw a function invocation.",
                W024: "Expected an identifier and instead saw '{a}' (a reserved word).",
                W025: "Missing name in function declaration.",
                W026: "Inner functions should be listed at the top of the outer function.",
                W027: "Unreachable '{a}' after '{b}'.",
                W028: "Label '{a}' on {b} statement.",
                W030: "Expected an assignment or function call and instead saw an expression.",
                W031: "Do not use 'new' for side effects.",
                W032: "Unnecessary semicolon.",
                W033: "Missing semicolon.",
                W034: "Unnecessary directive \"{a}\".",
                W035: "Empty block.",
                W036: "Unexpected /*member '{a}'.",
                W037: "'{a}' is a statement label.",
                W038: "'{a}' used out of scope.",
                W039: "'{a}' is not allowed.",
                W040: "Possible strict violation.",
                W041: "Use '{a}' to compare with '{b}'.",
                W042: "Avoid EOL escaping.",
                W043: "Bad escaping of EOL. Use option multistr if needed.",
                W044: "Bad or unnecessary escaping.", /* TODO(caitp): remove W044 */
                W045: "Bad number '{a}'.",
                W046: "Don't use extra leading zeros '{a}'.",
                W047: "A trailing decimal point can be confused with a dot: '{a}'.",
                W048: "Unexpected control character in regular expression.",
                W049: "Unexpected escaped character '{a}' in regular expression.",
                W050: "JavaScript URL.",
                W051: "Variables should not be deleted.",
                W052: "Unexpected '{a}'.",
                W053: "Do not use {a} as a constructor.",
                W054: "The Function constructor is a form of eval.",
                W055: "A constructor name should start with an uppercase letter.",
                W056: "Bad constructor.",
                W057: "Weird construction. Is 'new' necessary?",
                W058: "Missing '()' invoking a constructor.",
                W059: "Avoid arguments.{a}.",
                W060: "document.write can be a form of eval.",
                W061: "eval can be harmful.",
                W062: "Wrap an immediate function invocation in parens " +
                    "to assist the reader in understanding that the expression " +
                    "is the result of a function, and not the function itself.",
                W063: "Math is not a function.",
                W064: "Missing 'new' prefix when invoking a constructor.",
                W065: "Missing radix parameter.",
                W066: "Implied eval. Consider passing a function instead of a string.",
                W067: "Bad invocation.",
                W068: "Wrapping non-IIFE function literals in parens is unnecessary.",
                W069: "['{a}'] is better written in dot notation.",
                W070: "Extra comma. (it breaks older versions of IE)",
                W071: "This function has too many statements. ({a})",
                W072: "This function has too many parameters. ({a})",
                W073: "Blocks are nested too deeply. ({a})",
                W074: "This function's cyclomatic complexity is too high. ({a})",
                W075: "Duplicate {a} '{b}'.",
                W076: "Unexpected parameter '{a}' in get {b} function.",
                W077: "Expected a single parameter in set {a} function.",
                W078: "Setter is defined without getter.",
                W079: "Redefinition of '{a}'.",
                W080: "It's not necessary to initialize '{a}' to 'undefined'.",
                W081: null,
                W082: "Function declarations should not be placed in blocks. " +
                    "Use a function expression or move the statement to the top of " +
                    "the outer function.",
                W083: "Don't make functions within a loop.",
                W084: "Assignment in conditional expression",
                W085: "Don't use 'with'.",
                W086: "Expected a 'break' statement before '{a}'.",
                W087: "Forgotten 'debugger' statement?",
                W088: "Creating global 'for' variable. Should be 'for (var {a} ...'.",
                W089: "The body of a for in should be wrapped in an if statement to filter " +
                    "unwanted properties from the prototype.",
                W090: "'{a}' is not a statement label.",
                W091: null,
                W093: "Did you mean to return a conditional instead of an assignment?",
                W094: "Unexpected comma.",
                W095: "Expected a string and instead saw {a}.",
                W096: "The '{a}' key may produce unexpected results.",
                W097: "Use the function form of \"use strict\".",
                W098: "'{a}' is defined but never used.",
                W099: null,
                W100: "This character may get silently deleted by one or more browsers.",
                W101: "Line is too long.",
                W102: null,
                W103: "The '{a}' property is deprecated.",
                W104: "'{a}' is available in ES{b} (use 'esversion: {b}') or Mozilla JS extensions (use moz).",
                W105: "Unexpected {a} in '{b}'.",
                W106: "Identifier '{a}' is not in camel case.",
                W107: "Script URL.",
                W108: "Strings must use doublequote.",
                W109: "Strings must use singlequote.",
                W110: "Mixed double and single quotes.",
                W112: "Unclosed string.",
                W113: "Control character in string: {a}.",
                W114: "Avoid {a}.",
                W115: "Octal literals are not allowed in strict mode.",
                W116: "Expected '{a}' and instead saw '{b}'.",
                W117: "'{a}' is not defined.",
                W118: "'{a}' is only available in Mozilla JavaScript extensions (use moz option).",
                W119: "'{a}' is only available in ES{b} (use 'esversion: {b}').",
                W120: "You might be leaking a variable ({a}) here.",
                W121: "Extending prototype of native object: '{a}'.",
                W122: "Invalid typeof value '{a}'",
                W123: "'{a}' is already defined in outer scope.",
                W124: "A generator function shall contain a yield statement.",
                W125: "This line contains non-breaking spaces: http://jshint.com/doc/options/#nonbsp",
                W126: "Unnecessary grouping operator.",
                W127: "Unexpected use of a comma operator.",
                W128: "Empty array elements require elision=true.",
                W129: "'{a}' is defined in a future version of JavaScript. Use a " +
                    "different variable name to avoid migration issues.",
                W130: "Invalid element after rest element.",
                W131: "Invalid parameter after rest parameter.",
                W132: "`var` declarations are forbidden. Use `let` or `const` instead.",
                W133: "Invalid for-{a} loop left-hand-side: {b}.",
                W134: "The '{a}' option is only available when linting ECMAScript {b} code.",
                W135: "{a} may not be supported by non-browser environments.",
                W136: "'{a}' must be in function scope.",
                W137: "Empty destructuring.",
                W138: "Regular parameters should not come after default parameters."
            };

            var info = {
                I001: "Comma warnings can be turned off with 'laxcomma'.",
                I002: null,
                I003: "ES5 option is now set per default"
            };

            exports.errors = {};
            exports.warnings = {};
            exports.info = {};

            _.each(errors, function (desc, code) {
                exports.errors[code] = {code: code, desc: desc};
            });

            _.each(warnings, function (desc, code) {
                exports.warnings[code] = {code: code, desc: desc};
            });

            _.each(info, function (desc, code) {
                exports.info[code] = {code: code, desc: desc};
            });

        }, {"../lodash": "/node_modules/jshint/lodash.js"}],
        "/node_modules/jshint/src/name-stack.js": [function (_dereq_, module, exports) {
            "use strict";

            function NameStack() {
                this._stack = [];
            }

            Object.defineProperty(NameStack.prototype, "length", {
                get: function () {
                    return this._stack.length;
                }
            });
            NameStack.prototype.push = function () {
                this._stack.push(null);
            };
            NameStack.prototype.pop = function () {
                this._stack.pop();
            };
            NameStack.prototype.set = function (token) {
                this._stack[this.length - 1] = token;
            };
            NameStack.prototype.infer = function () {
                var nameToken = this._stack[this.length - 1];
                var prefix = "";
                var type;
                if (!nameToken || nameToken.type === "class") {
                    nameToken = this._stack[this.length - 2];
                }

                if (!nameToken) {
                    return "(empty)";
                }

                type = nameToken.type;

                if (type !== "(string)" && type !== "(number)" && type !== "(identifier)" && type !== "default") {
                    return "(expression)";
                }

                if (nameToken.accessorType) {
                    prefix = nameToken.accessorType + " ";
                }

                return prefix + nameToken.value;
            };

            module.exports = NameStack;

        }, {}],
        "/node_modules/jshint/src/options.js": [function (_dereq_, module, exports) {
            "use strict";
            exports.bool = {
                enforcing: {
                    bitwise: true,
                    freeze: true,
                    camelcase: true,
                    curly: true,
                    eqeqeq: true,
                    futurehostile: true,
                    notypeof: true,
                    es3: true,
                    es5: true,
                    forin: true,
                    funcscope: true,
                    immed: true,
                    iterator: true,
                    newcap: true,
                    noarg: true,
                    nocomma: true,
                    noempty: true,
                    nonbsp: true,
                    nonew: true,
                    undef: true,
                    singleGroups: false,
                    varstmt: false,
                    enforceall: false
                },
                relaxing: {
                    asi: true,
                    multistr: true,
                    debug: true,
                    boss: true,
                    evil: true,
                    globalstrict: true,
                    plusplus: true,
                    proto: true,
                    scripturl: true,
                    sub: true,
                    supernew: true,
                    laxbreak: true,
                    laxcomma: true,
                    validthis: true,
                    withstmt: true,
                    moz: true,
                    noyield: true,
                    eqnull: true,
                    lastsemic: true,
                    loopfunc: true,
                    expr: true,
                    esnext: true,
                    elision: true,
                },
                environments: {
                    mootools: true,
                    couch: true,
                    jasmine: true,
                    jquery: true,
                    node: true,
                    qunit: true,
                    rhino: true,
                    shelljs: true,
                    prototypejs: true,
                    yui: true,
                    mocha: true,
                    module: true,
                    wsh: true,
                    worker: true,
                    nonstandard: true,
                    browser: true,
                    browserify: true,
                    devel: true,
                    dojo: true,
                    typed: true,
                    phantom: true
                },
                obsolete: {
                    onecase: true, // if one case switch statements should be allowed
                    regexp: true, // if the . should not be allowed in regexp literals
                    regexdash: true  // if unescaped first/last dash (-) inside brackets
                }
            };
            exports.val = {
                maxlen: false,
                indent: false,
                maxerr: false,
                predef: false,
                globals: false,
                quotmark: false,

                scope: false,
                maxstatements: false,
                maxdepth: false,
                maxparams: false,
                maxcomplexity: false,
                shadow: false,
                strict: true,
                unused: true,
                latedef: false,

                ignore: false, // start/end ignoring lines of code, bypassing the lexer

                ignoreDelimiters: false, // array of start/end delimiters used to ignore
                esversion: 5
            };
            exports.inverted = {
                bitwise: true,
                forin: true,
                newcap: true,
                plusplus: true,
                regexp: true,
                undef: true,
                eqeqeq: true,
                strict: true
            };

            exports.validNames = Object.keys(exports.val)
                .concat(Object.keys(exports.bool.relaxing))
                .concat(Object.keys(exports.bool.enforcing))
                .concat(Object.keys(exports.bool.obsolete))
                .concat(Object.keys(exports.bool.environments));
            exports.renamed = {
                eqeq: "eqeqeq",
                windows: "wsh",
                sloppy: "strict"
            };

            exports.removed = {
                nomen: true,
                onevar: true,
                passfail: true,
                white: true,
                gcl: true,
                smarttabs: true,
                trailing: true
            };
            exports.noenforceall = {
                varstmt: true,
                strict: true
            };

        }, {}],
        "/node_modules/jshint/src/reg.js": [function (_dereq_, module, exports) {

            "use strict";
            exports.unsafeString =
                /@cc|<\/?|script|\]\s*\]|<\s*!|&lt/i;
            exports.unsafeChars =
                /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
            exports.needEsc =
                /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;

            exports.needEscGlobal =
                /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
            exports.starSlash = /\*\//;
            exports.identifier = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/;
            exports.javascriptURL = /^(?:javascript|jscript|ecmascript|vbscript|livescript)\s*:/i;
            exports.fallsThrough = /^\s*falls?\sthrough\s*$/;
            exports.maxlenException = /^(?:(?:\/\/|\/\*|\*) ?)?[^ ]+$/;

        }, {}],
        "/node_modules/jshint/src/scope-manager.js": [function (_dereq_, module, exports) {
            "use strict";

            var _ = _dereq_("../lodash");
            var events = _dereq_("events");
            var marker = {};
            var scopeManager = function (state, predefined, exported, declared) {

                var _current;
                var _scopeStack = [];

                function _newScope(type) {
                    _current = {
                        "(labels)": Object.create(null),
                        "(usages)": Object.create(null),
                        "(breakLabels)": Object.create(null),
                        "(parent)": _current,
                        "(type)": type,
                        "(params)": (type === "functionparams" || type === "catchparams") ? [] : null
                    };
                    _scopeStack.push(_current);
                }

                _newScope("global");
                _current["(predefined)"] = predefined;

                var _currentFunctBody = _current; // this is the block after the params = function

                var usedPredefinedAndGlobals = Object.create(null);
                var impliedGlobals = Object.create(null);
                var unuseds = [];
                var emitter = new events.EventEmitter();

                function warning(code, token) {
                    emitter.emit("warning", {
                        code: code,
                        token: token,
                        data: _.slice(arguments, 2)
                    });
                }

                function error(code, token) {
                    emitter.emit("warning", {
                        code: code,
                        token: token,
                        data: _.slice(arguments, 2)
                    });
                }

                function _setupUsages(labelName) {
                    if (!_current["(usages)"][labelName]) {
                        _current["(usages)"][labelName] = {
                            "(modified)": [],
                            "(reassigned)": [],
                            "(tokens)": []
                        };
                    }
                }

                var _getUnusedOption = function (unused_opt) {
                    if (unused_opt === undefined) {
                        unused_opt = state.option.unused;
                    }

                    if (unused_opt === true) {
                        unused_opt = "last-param";
                    }

                    return unused_opt;
                };

                var _warnUnused = function (name, tkn, type, unused_opt) {
                    var line = tkn.line;
                    var chr = tkn.from;
                    var raw_name = tkn.raw_text || name;

                    unused_opt = _getUnusedOption(unused_opt);

                    var warnable_types = {
                        "vars": ["var"],
                        "last-param": ["var", "param"],
                        "strict": ["var", "param", "last-param"]
                    };

                    if (unused_opt) {
                        if (warnable_types[unused_opt] && warnable_types[unused_opt].indexOf(type) !== -1) {
                            warning("W098", {line: line, from: chr}, raw_name);
                        }
                    }
                    if (unused_opt || type === "var") {
                        unuseds.push({
                            name: name,
                            line: line,
                            character: chr
                        });
                    }
                };

                function _checkForUnused() {
                    if (_current["(type)"] === "functionparams") {
                        _checkParams();
                        return;
                    }
                    var curentLabels = _current["(labels)"];
                    for (var labelName in curentLabels) {
                        if (curentLabels[labelName]) {
                            if (curentLabels[labelName]["(type)"] !== "exception" &&
                                curentLabels[labelName]["(unused)"]) {
                                _warnUnused(labelName, curentLabels[labelName]["(token)"], "var");
                            }
                        }
                    }
                }

                function _checkParams() {
                    var params = _current["(params)"];

                    if (!params) {
                        return;
                    }

                    var param = params.pop();
                    var unused_opt;

                    while (param) {
                        var label = _current["(labels)"][param];

                        unused_opt = _getUnusedOption(state.funct["(unusedOption)"]);
                        if (param === "undefined")
                            return;

                        if (label["(unused)"]) {
                            _warnUnused(param, label["(token)"], "param", state.funct["(unusedOption)"]);
                        } else if (unused_opt === "last-param") {
                            return;
                        }

                        param = params.pop();
                    }
                }

                function _getLabel(labelName) {
                    for (var i = _scopeStack.length - 1; i >= 0; --i) {
                        var scopeLabels = _scopeStack[i]["(labels)"];
                        if (scopeLabels[labelName]) {
                            return scopeLabels;
                        }
                    }
                }

                function usedSoFarInCurrentFunction(labelName) {
                    for (var i = _scopeStack.length - 1; i >= 0; i--) {
                        var current = _scopeStack[i];
                        if (current["(usages)"][labelName]) {
                            return current["(usages)"][labelName];
                        }
                        if (current === _currentFunctBody) {
                            break;
                        }
                    }
                    return false;
                }

                function _checkOuterShadow(labelName, token) {
                    if (state.option.shadow !== "outer") {
                        return;
                    }

                    var isGlobal = _currentFunctBody["(type)"] === "global",
                        isNewFunction = _current["(type)"] === "functionparams";

                    var outsideCurrentFunction = !isGlobal;
                    for (var i = 0; i < _scopeStack.length; i++) {
                        var stackItem = _scopeStack[i];

                        if (!isNewFunction && _scopeStack[i + 1] === _currentFunctBody) {
                            outsideCurrentFunction = false;
                        }
                        if (outsideCurrentFunction && stackItem["(labels)"][labelName]) {
                            warning("W123", token, labelName);
                        }
                        if (stackItem["(breakLabels)"][labelName]) {
                            warning("W123", token, labelName);
                        }
                    }
                }

                function _latedefWarning(type, labelName, token) {
                    if (state.option.latedef) {
                        if ((state.option.latedef === true && type === "function") ||
                            type !== "function") {
                            warning("W003", token, labelName);
                        }
                    }
                }

                var scopeManagerInst = {

                    on: function (names, listener) {
                        names.split(" ").forEach(function (name) {
                            emitter.on(name, listener);
                        });
                    },

                    isPredefined: function (labelName) {
                        return !this.has(labelName) && _.has(_scopeStack[0]["(predefined)"], labelName);
                    },
                    stack: function (type) {
                        var previousScope = _current;
                        _newScope(type);

                        if (!type && previousScope["(type)"] === "functionparams") {

                            _current["(isFuncBody)"] = true;
                            _current["(context)"] = _currentFunctBody;
                            _currentFunctBody = _current;
                        }
                    },

                    unstack: function () {
                        var subScope = _scopeStack.length > 1 ? _scopeStack[_scopeStack.length - 2] : null;
                        var isUnstackingFunctionBody = _current === _currentFunctBody,
                            isUnstackingFunctionParams = _current["(type)"] === "functionparams",
                            isUnstackingFunctionOuter = _current["(type)"] === "functionouter";

                        var i, j;
                        var currentUsages = _current["(usages)"];
                        var currentLabels = _current["(labels)"];
                        var usedLabelNameList = Object.keys(currentUsages);

                        if (currentUsages.__proto__ && usedLabelNameList.indexOf("__proto__") === -1) {
                            usedLabelNameList.push("__proto__");
                        }

                        for (i = 0; i < usedLabelNameList.length; i++) {
                            var usedLabelName = usedLabelNameList[i];

                            var usage = currentUsages[usedLabelName];
                            var usedLabel = currentLabels[usedLabelName];
                            if (usedLabel) {
                                var usedLabelType = usedLabel["(type)"];

                                if (usedLabel["(useOutsideOfScope)"] && !state.option.funcscope) {
                                    var usedTokens = usage["(tokens)"];
                                    if (usedTokens) {
                                        for (j = 0; j < usedTokens.length; j++) {
                                            if (usedLabel["(function)"] === usedTokens[j]["(function)"]) {
                                                error("W038", usedTokens[j], usedLabelName);
                                            }
                                        }
                                    }
                                }
                                _current["(labels)"][usedLabelName]["(unused)"] = false;
                                if (usedLabelType === "const" && usage["(modified)"]) {
                                    for (j = 0; j < usage["(modified)"].length; j++) {
                                        error("E013", usage["(modified)"][j], usedLabelName);
                                    }
                                }
                                if ((usedLabelType === "function" || usedLabelType === "class") &&
                                    usage["(reassigned)"]) {
                                    for (j = 0; j < usage["(reassigned)"].length; j++) {
                                        error("W021", usage["(reassigned)"][j], usedLabelName, usedLabelType);
                                    }
                                }
                                continue;
                            }

                            if (isUnstackingFunctionOuter) {
                                state.funct["(isCapturing)"] = true;
                            }

                            if (subScope) {
                                if (!subScope["(usages)"][usedLabelName]) {
                                    subScope["(usages)"][usedLabelName] = usage;
                                    if (isUnstackingFunctionBody) {
                                        subScope["(usages)"][usedLabelName]["(onlyUsedSubFunction)"] = true;
                                    }
                                } else {
                                    var subScopeUsage = subScope["(usages)"][usedLabelName];
                                    subScopeUsage["(modified)"] = subScopeUsage["(modified)"].concat(usage["(modified)"]);
                                    subScopeUsage["(tokens)"] = subScopeUsage["(tokens)"].concat(usage["(tokens)"]);
                                    subScopeUsage["(reassigned)"] =
                                        subScopeUsage["(reassigned)"].concat(usage["(reassigned)"]);
                                    subScopeUsage["(onlyUsedSubFunction)"] = false;
                                }
                            } else {
                                if (typeof _current["(predefined)"][usedLabelName] === "boolean") {
                                    delete declared[usedLabelName];
                                    usedPredefinedAndGlobals[usedLabelName] = marker;
                                    if (_current["(predefined)"][usedLabelName] === false && usage["(reassigned)"]) {
                                        for (j = 0; j < usage["(reassigned)"].length; j++) {
                                            warning("W020", usage["(reassigned)"][j]);
                                        }
                                    }
                                } else {
                                    if (usage["(tokens)"]) {
                                        for (j = 0; j < usage["(tokens)"].length; j++) {
                                            var undefinedToken = usage["(tokens)"][j];
                                            if (!undefinedToken.forgiveUndef) {
                                                if (state.option.undef && !undefinedToken.ignoreUndef) {
                                                    warning("W117", undefinedToken, usedLabelName);
                                                }
                                                if (impliedGlobals[usedLabelName]) {
                                                    impliedGlobals[usedLabelName].line.push(undefinedToken.line);
                                                } else {
                                                    impliedGlobals[usedLabelName] = {
                                                        name: usedLabelName,
                                                        line: [undefinedToken.line]
                                                    };
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        if (!subScope) {
                            Object.keys(declared)
                                .forEach(function (labelNotUsed) {
                                    _warnUnused(labelNotUsed, declared[labelNotUsed], "var");
                                });
                        }
                        if (subScope && !isUnstackingFunctionBody &&
                            !isUnstackingFunctionParams && !isUnstackingFunctionOuter) {
                            var labelNames = Object.keys(currentLabels);
                            for (i = 0; i < labelNames.length; i++) {

                                var defLabelName = labelNames[i];
                                if (!currentLabels[defLabelName]["(blockscoped)"] &&
                                    currentLabels[defLabelName]["(type)"] !== "exception" &&
                                    !this.funct.has(defLabelName, {excludeCurrent: true})) {
                                    subScope["(labels)"][defLabelName] = currentLabels[defLabelName];
                                    if (_currentFunctBody["(type)"] !== "global") {
                                        subScope["(labels)"][defLabelName]["(useOutsideOfScope)"] = true;
                                    }
                                    delete currentLabels[defLabelName];
                                }
                            }
                        }

                        _checkForUnused();

                        _scopeStack.pop();
                        if (isUnstackingFunctionBody) {
                            _currentFunctBody = _scopeStack[_.findLastIndex(_scopeStack, function (scope) {
                                return scope["(isFuncBody)"] || scope["(type)"] === "global";
                            })];
                        }

                        _current = subScope;
                    },
                    addParam: function (labelName, token, type) {
                        type = type || "param";

                        if (type === "exception") {
                            var previouslyDefinedLabelType = this.funct.labeltype(labelName);
                            if (previouslyDefinedLabelType && previouslyDefinedLabelType !== "exception") {
                                if (!state.option.node) {
                                    warning("W002", state.tokens.next, labelName);
                                }
                            }
                        }
                        if (_.has(_current["(labels)"], labelName)) {
                            _current["(labels)"][labelName].duplicated = true;
                        } else {
                            _checkOuterShadow(labelName, token, type);

                            _current["(labels)"][labelName] = {
                                "(type)": type,
                                "(token)": token,
                                "(unused)": true
                            };

                            _current["(params)"].push(labelName);
                        }

                        if (_.has(_current["(usages)"], labelName)) {
                            var usage = _current["(usages)"][labelName];
                            if (usage["(onlyUsedSubFunction)"]) {
                                _latedefWarning(type, labelName, token);
                            } else {
                                warning("E056", token, labelName, type);
                            }
                        }
                    },

                    validateParams: function () {
                        if (_currentFunctBody["(type)"] === "global") {
                            return;
                        }

                        var isStrict = state.isStrict();
                        var currentFunctParamScope = _currentFunctBody["(parent)"];

                        if (!currentFunctParamScope["(params)"]) {
                            return;
                        }

                        currentFunctParamScope["(params)"].forEach(function (labelName) {
                            var label = currentFunctParamScope["(labels)"][labelName];

                            if (label && label.duplicated) {
                                if (isStrict) {
                                    warning("E011", label["(token)"], labelName);
                                } else if (state.option.shadow !== true) {
                                    warning("W004", label["(token)"], labelName);
                                }
                            }
                        });
                    },

                    getUsedOrDefinedGlobals: function () {
                        var list = Object.keys(usedPredefinedAndGlobals);
                        if (usedPredefinedAndGlobals.__proto__ === marker &&
                            list.indexOf("__proto__") === -1) {
                            list.push("__proto__");
                        }

                        return list;
                    },
                    getImpliedGlobals: function () {
                        var values = _.values(impliedGlobals);
                        var hasProto = false;
                        if (impliedGlobals.__proto__) {
                            hasProto = values.some(function (value) {
                                return value.name === "__proto__";
                            });

                            if (!hasProto) {
                                values.push(impliedGlobals.__proto__);
                            }
                        }

                        return values;
                    },
                    getUnuseds: function () {
                        return unuseds;
                    },

                    has: function (labelName) {
                        return Boolean(_getLabel(labelName));
                    },

                    labeltype: function (labelName) {
                        var scopeLabels = _getLabel(labelName);
                        if (scopeLabels) {
                            return scopeLabels[labelName]["(type)"];
                        }
                        return null;
                    },
                    addExported: function (labelName) {
                        var globalLabels = _scopeStack[0]["(labels)"];
                        if (_.has(declared, labelName)) {
                            delete declared[labelName];
                        } else if (_.has(globalLabels, labelName)) {
                            globalLabels[labelName]["(unused)"] = false;
                        } else {
                            for (var i = 1; i < _scopeStack.length; i++) {
                                var scope = _scopeStack[i];
                                if (!scope["(type)"]) {
                                    if (_.has(scope["(labels)"], labelName) &&
                                        !scope["(labels)"][labelName]["(blockscoped)"]) {
                                        scope["(labels)"][labelName]["(unused)"] = false;
                                        return;
                                    }
                                } else {
                                    break;
                                }
                            }
                            exported[labelName] = true;
                        }
                    },
                    setExported: function (labelName, token) {
                        this.block.use(labelName, token);
                    },
                    addlabel: function (labelName, opts) {

                        var type = opts.type;
                        var token = opts.token;
                        var isblockscoped = type === "let" || type === "const" || type === "class";
                        var isexported = (isblockscoped ? _current : _currentFunctBody)["(type)"] === "global" &&
                            _.has(exported, labelName);
                        _checkOuterShadow(labelName, token, type);
                        if (isblockscoped) {

                            var declaredInCurrentScope = _current["(labels)"][labelName];
                            if (!declaredInCurrentScope && _current === _currentFunctBody &&
                                _current["(type)"] !== "global") {
                                declaredInCurrentScope = !!_currentFunctBody["(parent)"]["(labels)"][labelName];
                            }
                            if (!declaredInCurrentScope && _current["(usages)"][labelName]) {
                                var usage = _current["(usages)"][labelName];
                                if (usage["(onlyUsedSubFunction)"]) {
                                    _latedefWarning(type, labelName, token);
                                } else {
                                    warning("E056", token, labelName, type);
                                }
                            }
                            if (declaredInCurrentScope) {
                                warning("E011", token, labelName);
                            } else if (state.option.shadow === "outer") {
                                if (scopeManagerInst.funct.has(labelName)) {
                                    warning("W004", token, labelName);
                                }
                            }

                            scopeManagerInst.block.add(labelName, type, token, !isexported);

                        } else {

                            var declaredInCurrentFunctionScope = scopeManagerInst.funct.has(labelName);
                            if (!declaredInCurrentFunctionScope && usedSoFarInCurrentFunction(labelName)) {
                                _latedefWarning(type, labelName, token);
                            }
                            if (scopeManagerInst.funct.has(labelName, {onlyBlockscoped: true})) {
                                warning("E011", token, labelName);
                            } else if (state.option.shadow !== true) {
                                if (declaredInCurrentFunctionScope && labelName !== "__proto__") {
                                    if (_currentFunctBody["(type)"] !== "global") {
                                        warning("W004", token, labelName);
                                    }
                                }
                            }

                            scopeManagerInst.funct.add(labelName, type, token, !isexported);

                            if (_currentFunctBody["(type)"] === "global") {
                                usedPredefinedAndGlobals[labelName] = marker;
                            }
                        }
                    },

                    funct: {
                        labeltype: function (labelName, options) {
                            var onlyBlockscoped = options && options.onlyBlockscoped;
                            var excludeParams = options && options.excludeParams;
                            var currentScopeIndex = _scopeStack.length - (options && options.excludeCurrent ? 2 : 1);
                            for (var i = currentScopeIndex; i >= 0; i--) {
                                var current = _scopeStack[i];
                                if (current["(labels)"][labelName] &&
                                    (!onlyBlockscoped || current["(labels)"][labelName]["(blockscoped)"])) {
                                    return current["(labels)"][labelName]["(type)"];
                                }
                                var scopeCheck = excludeParams ? _scopeStack[i - 1] : current;
                                if (scopeCheck && scopeCheck["(type)"] === "functionparams") {
                                    return null;
                                }
                            }
                            return null;
                        },
                        hasBreakLabel: function (labelName) {
                            for (var i = _scopeStack.length - 1; i >= 0; i--) {
                                var current = _scopeStack[i];

                                if (current["(breakLabels)"][labelName]) {
                                    return true;
                                }
                                if (current["(type)"] === "functionparams") {
                                    return false;
                                }
                            }
                            return false;
                        },
                        has: function (labelName, options) {
                            return Boolean(this.labeltype(labelName, options));
                        },
                        add: function (labelName, type, tok, unused) {
                            _current["(labels)"][labelName] = {
                                "(type)": type,
                                "(token)": tok,
                                "(blockscoped)": false,
                                "(function)": _currentFunctBody,
                                "(unused)": unused
                            };
                        }
                    },

                    block: {
                        isGlobal: function () {
                            return _current["(type)"] === "global";
                        },

                        use: function (labelName, token) {
                            var paramScope = _currentFunctBody["(parent)"];
                            if (paramScope && paramScope["(labels)"][labelName] &&
                                paramScope["(labels)"][labelName]["(type)"] === "param") {
                                if (!scopeManagerInst.funct.has(labelName,
                                    {excludeParams: true, onlyBlockscoped: true})) {
                                    paramScope["(labels)"][labelName]["(unused)"] = false;
                                }
                            }

                            if (token && (state.ignored.W117 || state.option.undef === false)) {
                                token.ignoreUndef = true;
                            }

                            _setupUsages(labelName);

                            if (token) {
                                token["(function)"] = _currentFunctBody;
                                _current["(usages)"][labelName]["(tokens)"].push(token);
                            }
                        },

                        reassign: function (labelName, token) {

                            this.modify(labelName, token);

                            _current["(usages)"][labelName]["(reassigned)"].push(token);
                        },

                        modify: function (labelName, token) {

                            _setupUsages(labelName);

                            _current["(usages)"][labelName]["(modified)"].push(token);
                        },
                        add: function (labelName, type, tok, unused) {
                            _current["(labels)"][labelName] = {
                                "(type)": type,
                                "(token)": tok,
                                "(blockscoped)": true,
                                "(unused)": unused
                            };
                        },

                        addBreakLabel: function (labelName, opts) {
                            var token = opts.token;
                            if (scopeManagerInst.funct.hasBreakLabel(labelName)) {
                                warning("E011", token, labelName);
                            } else if (state.option.shadow === "outer") {
                                if (scopeManagerInst.funct.has(labelName)) {
                                    warning("W004", token, labelName);
                                } else {
                                    _checkOuterShadow(labelName, token);
                                }
                            }
                            _current["(breakLabels)"][labelName] = token;
                        }
                    }
                };
                return scopeManagerInst;
            };

            module.exports = scopeManager;

        }, {
            "../lodash": "/node_modules/jshint/lodash.js",
            "events": "/node_modules/browserify/node_modules/events/events.js"
        }],
        "/node_modules/jshint/src/state.js": [function (_dereq_, module, exports) {
            "use strict";
            var NameStack = _dereq_("./name-stack.js");

            var state = {
                syntax: {},
                isStrict: function () {
                    return this.directive["use strict"] || this.inClassBody ||
                        this.option.module || this.option.strict === "implied";
                },

                inMoz: function () {
                    return this.option.moz;
                },
                inES6: function () {
                    return this.option.moz || this.option.esversion >= 6;
                },
                inES5: function (strict) {
                    if (strict) {
                        return (!this.option.esversion || this.option.esversion === 5) && !this.option.moz;
                    }
                    return !this.option.esversion || this.option.esversion >= 5 || this.option.moz;
                },


                reset: function () {
                    this.tokens = {
                        prev: null,
                        next: null,
                        curr: null
                    };

                    this.option = {};
                    this.funct = null;
                    this.ignored = {};
                    this.directive = {};
                    this.jsonMode = false;
                    this.jsonWarnings = [];
                    this.lines = [];
                    this.tab = "";
                    this.cache = {}; // Node.JS doesn't have Map. Sniff.
                    this.ignoredLines = {};
                    this.forinifcheckneeded = false;
                    this.nameStack = new NameStack();
                    this.inClassBody = false;
                }
            };

            exports.state = state;

        }, {"./name-stack.js": "/node_modules/jshint/src/name-stack.js"}],
        "/node_modules/jshint/src/style.js": [function (_dereq_, module, exports) {
            "use strict";

            exports.register = function (linter) {

                linter.on("Identifier", function style_scanProto(data) {
                    if (linter.getOption("proto")) {
                        return;
                    }

                    if (data.name === "__proto__") {
                        linter.warn("W103", {
                            line: data.line,
                            char: data.char,
                            data: [data.name, "6"]
                        });
                    }
                });

                linter.on("Identifier", function style_scanIterator(data) {
                    if (linter.getOption("iterator")) {
                        return;
                    }

                    if (data.name === "__iterator__") {
                        linter.warn("W103", {
                            line: data.line,
                            char: data.char,
                            data: [data.name]
                        });
                    }
                });

                linter.on("Identifier", function style_scanCamelCase(data) {
                    if (!linter.getOption("camelcase")) {
                        return;
                    }

                    if (data.name.replace(/^_+|_+$/g, "").indexOf("_") > -1 && !data.name.match(/^[A-Z0-9_]*$/)) {
                        linter.warn("W106", {
                            line: data.line,
                            char: data.from,
                            data: [data.name]
                        });
                    }
                });

                linter.on("String", function style_scanQuotes(data) {
                    var quotmark = linter.getOption("quotmark");
                    var code;

                    if (!quotmark) {
                        return;
                    }

                    if (quotmark === "single" && data.quote !== "'") {
                        code = "W109";
                    }

                    if (quotmark === "double" && data.quote !== "\"") {
                        code = "W108";
                    }

                    if (quotmark === true) {
                        if (!linter.getCache("quotmark")) {
                            linter.setCache("quotmark", data.quote);
                        }

                        if (linter.getCache("quotmark") !== data.quote) {
                            code = "W110";
                        }
                    }

                    if (code) {
                        linter.warn(code, {
                            line: data.line,
                            char: data.char,
                        });
                    }
                });

                linter.on("Number", function style_scanNumbers(data) {
                    if (data.value.charAt(0) === ".") {
                        linter.warn("W008", {
                            line: data.line,
                            char: data.char,
                            data: [data.value]
                        });
                    }

                    if (data.value.substr(data.value.length - 1) === ".") {
                        linter.warn("W047", {
                            line: data.line,
                            char: data.char,
                            data: [data.value]
                        });
                    }

                    if (/^00+/.test(data.value)) {
                        linter.warn("W046", {
                            line: data.line,
                            char: data.char,
                            data: [data.value]
                        });
                    }
                });

                linter.on("String", function style_scanJavaScriptURLs(data) {
                    var re = /^(?:javascript|jscript|ecmascript|vbscript|livescript)\s*:/i;

                    if (linter.getOption("scripturl")) {
                        return;
                    }

                    if (re.test(data.value)) {
                        linter.warn("W107", {
                            line: data.line,
                            char: data.char
                        });
                    }
                });
            };

        }, {}],
        "/node_modules/jshint/src/vars.js": [function (_dereq_, module, exports) {

            "use strict";

            exports.reservedVars = {
                arguments: false,
                NaN: false
            };

            exports.ecmaIdentifiers = {
                3: {
                    Array: false,
                    Boolean: false,
                    Date: false,
                    decodeURI: false,
                    decodeURIComponent: false,
                    encodeURI: false,
                    encodeURIComponent: false,
                    Error: false,
                    "eval": false,
                    EvalError: false,
                    Function: false,
                    hasOwnProperty: false,
                    isFinite: false,
                    isNaN: false,
                    Math: false,
                    Number: false,
                    Object: false,
                    parseInt: false,
                    parseFloat: false,
                    RangeError: false,
                    ReferenceError: false,
                    RegExp: false,
                    String: false,
                    SyntaxError: false,
                    TypeError: false,
                    URIError: false
                },
                5: {
                    JSON: false
                },
                6: {
                    Map: false,
                    Promise: false,
                    Proxy: false,
                    Reflect: false,
                    Set: false,
                    Symbol: false,
                    WeakMap: false,
                    WeakSet: false
                }
            };

            exports.browser = {
                Audio: false,
                Blob: false,
                addEventListener: false,
                applicationCache: false,
                atob: false,
                blur: false,
                btoa: false,
                cancelAnimationFrame: false,
                CanvasGradient: false,
                CanvasPattern: false,
                CanvasRenderingContext2D: false,
                CSS: false,
                clearInterval: false,
                clearTimeout: false,
                close: false,
                closed: false,
                Comment: false,
                CustomEvent: false,
                DOMParser: false,
                defaultStatus: false,
                Document: false,
                document: false,
                DocumentFragment: false,
                Element: false,
                ElementTimeControl: false,
                Event: false,
                event: false,
                fetch: false,
                FileReader: false,
                FormData: false,
                focus: false,
                frames: false,
                getComputedStyle: false,
                HTMLElement: false,
                HTMLAnchorElement: false,
                HTMLBaseElement: false,
                HTMLBlockquoteElement: false,
                HTMLBodyElement: false,
                HTMLBRElement: false,
                HTMLButtonElement: false,
                HTMLCanvasElement: false,
                HTMLCollection: false,
                HTMLDirectoryElement: false,
                HTMLDivElement: false,
                HTMLDListElement: false,
                HTMLFieldSetElement: false,
                HTMLFontElement: false,
                HTMLFormElement: false,
                HTMLFrameElement: false,
                HTMLFrameSetElement: false,
                HTMLHeadElement: false,
                HTMLHeadingElement: false,
                HTMLHRElement: false,
                HTMLHtmlElement: false,
                HTMLIFrameElement: false,
                HTMLImageElement: false,
                HTMLInputElement: false,
                HTMLIsIndexElement: false,
                HTMLLabelElement: false,
                HTMLLayerElement: false,
                HTMLLegendElement: false,
                HTMLLIElement: false,
                HTMLLinkElement: false,
                HTMLMapElement: false,
                HTMLMenuElement: false,
                HTMLMetaElement: false,
                HTMLModElement: false,
                HTMLObjectElement: false,
                HTMLOListElement: false,
                HTMLOptGroupElement: false,
                HTMLOptionElement: false,
                HTMLParagraphElement: false,
                HTMLParamElement: false,
                HTMLPreElement: false,
                HTMLQuoteElement: false,
                HTMLScriptElement: false,
                HTMLSelectElement: false,
                HTMLStyleElement: false,
                HTMLTableCaptionElement: false,
                HTMLTableCellElement: false,
                HTMLTableColElement: false,
                HTMLTableElement: false,
                HTMLTableRowElement: false,
                HTMLTableSectionElement: false,
                HTMLTemplateElement: false,
                HTMLTextAreaElement: false,
                HTMLTitleElement: false,
                HTMLUListElement: false,
                HTMLVideoElement: false,
                history: false,
                Image: false,
                Intl: false,
                length: false,
                localStorage: false,
                location: false,
                matchMedia: false,
                MessageChannel: false,
                MessageEvent: false,
                MessagePort: false,
                MouseEvent: false,
                moveBy: false,
                moveTo: false,
                MutationObserver: false,
                name: false,
                Node: false,
                NodeFilter: false,
                NodeList: false,
                Notification: false,
                navigator: false,
                onbeforeunload: true,
                onblur: true,
                onerror: true,
                onfocus: true,
                onload: true,
                onresize: true,
                onunload: true,
                open: false,
                openDatabase: false,
                opener: false,
                Option: false,
                parent: false,
                performance: false,
                print: false,
                Range: false,
                requestAnimationFrame: false,
                removeEventListener: false,
                resizeBy: false,
                resizeTo: false,
                screen: false,
                scroll: false,
                scrollBy: false,
                scrollTo: false,
                sessionStorage: false,
                setInterval: false,
                setTimeout: false,
                SharedWorker: false,
                status: false,
                SVGAElement: false,
                SVGAltGlyphDefElement: false,
                SVGAltGlyphElement: false,
                SVGAltGlyphItemElement: false,
                SVGAngle: false,
                SVGAnimateColorElement: false,
                SVGAnimateElement: false,
                SVGAnimateMotionElement: false,
                SVGAnimateTransformElement: false,
                SVGAnimatedAngle: false,
                SVGAnimatedBoolean: false,
                SVGAnimatedEnumeration: false,
                SVGAnimatedInteger: false,
                SVGAnimatedLength: false,
                SVGAnimatedLengthList: false,
                SVGAnimatedNumber: false,
                SVGAnimatedNumberList: false,
                SVGAnimatedPathData: false,
                SVGAnimatedPoints: false,
                SVGAnimatedPreserveAspectRatio: false,
                SVGAnimatedRect: false,
                SVGAnimatedString: false,
                SVGAnimatedTransformList: false,
                SVGAnimationElement: false,
                SVGCSSRule: false,
                SVGCircleElement: false,
                SVGClipPathElement: false,
                SVGColor: false,
                SVGColorProfileElement: false,
                SVGColorProfileRule: false,
                SVGComponentTransferFunctionElement: false,
                SVGCursorElement: false,
                SVGDefsElement: false,
                SVGDescElement: false,
                SVGDocument: false,
                SVGElement: false,
                SVGElementInstance: false,
                SVGElementInstanceList: false,
                SVGEllipseElement: false,
                SVGExternalResourcesRequired: false,
                SVGFEBlendElement: false,
                SVGFEColorMatrixElement: false,
                SVGFEComponentTransferElement: false,
                SVGFECompositeElement: false,
                SVGFEConvolveMatrixElement: false,
                SVGFEDiffuseLightingElement: false,
                SVGFEDisplacementMapElement: false,
                SVGFEDistantLightElement: false,
                SVGFEFloodElement: false,
                SVGFEFuncAElement: false,
                SVGFEFuncBElement: false,
                SVGFEFuncGElement: false,
                SVGFEFuncRElement: false,
                SVGFEGaussianBlurElement: false,
                SVGFEImageElement: false,
                SVGFEMergeElement: false,
                SVGFEMergeNodeElement: false,
                SVGFEMorphologyElement: false,
                SVGFEOffsetElement: false,
                SVGFEPointLightElement: false,
                SVGFESpecularLightingElement: false,
                SVGFESpotLightElement: false,
                SVGFETileElement: false,
                SVGFETurbulenceElement: false,
                SVGFilterElement: false,
                SVGFilterPrimitiveStandardAttributes: false,
                SVGFitToViewBox: false,
                SVGFontElement: false,
                SVGFontFaceElement: false,
                SVGFontFaceFormatElement: false,
                SVGFontFaceNameElement: false,
                SVGFontFaceSrcElement: false,
                SVGFontFaceUriElement: false,
                SVGForeignObjectElement: false,
                SVGGElement: false,
                SVGGlyphElement: false,
                SVGGlyphRefElement: false,
                SVGGradientElement: false,
                SVGHKernElement: false,
                SVGICCColor: false,
                SVGImageElement: false,
                SVGLangSpace: false,
                SVGLength: false,
                SVGLengthList: false,
                SVGLineElement: false,
                SVGLinearGradientElement: false,
                SVGLocatable: false,
                SVGMPathElement: false,
                SVGMarkerElement: false,
                SVGMaskElement: false,
                SVGMatrix: false,
                SVGMetadataElement: false,
                SVGMissingGlyphElement: false,
                SVGNumber: false,
                SVGNumberList: false,
                SVGPaint: false,
                SVGPathElement: false,
                SVGPathSeg: false,
                SVGPathSegArcAbs: false,
                SVGPathSegArcRel: false,
                SVGPathSegClosePath: false,
                SVGPathSegCurvetoCubicAbs: false,
                SVGPathSegCurvetoCubicRel: false,
                SVGPathSegCurvetoCubicSmoothAbs: false,
                SVGPathSegCurvetoCubicSmoothRel: false,
                SVGPathSegCurvetoQuadraticAbs: false,
                SVGPathSegCurvetoQuadraticRel: false,
                SVGPathSegCurvetoQuadraticSmoothAbs: false,
                SVGPathSegCurvetoQuadraticSmoothRel: false,
                SVGPathSegLinetoAbs: false,
                SVGPathSegLinetoHorizontalAbs: false,
                SVGPathSegLinetoHorizontalRel: false,
                SVGPathSegLinetoRel: false,
                SVGPathSegLinetoVerticalAbs: false,
                SVGPathSegLinetoVerticalRel: false,
                SVGPathSegList: false,
                SVGPathSegMovetoAbs: false,
                SVGPathSegMovetoRel: false,
                SVGPatternElement: false,
                SVGPoint: false,
                SVGPointList: false,
                SVGPolygonElement: false,
                SVGPolylineElement: false,
                SVGPreserveAspectRatio: false,
                SVGRadialGradientElement: false,
                SVGRect: false,
                SVGRectElement: false,
                SVGRenderingIntent: false,
                SVGSVGElement: false,
                SVGScriptElement: false,
                SVGSetElement: false,
                SVGStopElement: false,
                SVGStringList: false,
                SVGStylable: false,
                SVGStyleElement: false,
                SVGSwitchElement: false,
                SVGSymbolElement: false,
                SVGTRefElement: false,
                SVGTSpanElement: false,
                SVGTests: false,
                SVGTextContentElement: false,
                SVGTextElement: false,
                SVGTextPathElement: false,
                SVGTextPositioningElement: false,
                SVGTitleElement: false,
                SVGTransform: false,
                SVGTransformList: false,
                SVGTransformable: false,
                SVGURIReference: false,
                SVGUnitTypes: false,
                SVGUseElement: false,
                SVGVKernElement: false,
                SVGViewElement: false,
                SVGViewSpec: false,
                SVGZoomAndPan: false,
                Text: false,
                TextDecoder: false,
                TextEncoder: false,
                TimeEvent: false,
                top: false,
                URL: false,
                WebGLActiveInfo: false,
                WebGLBuffer: false,
                WebGLContextEvent: false,
                WebGLFramebuffer: false,
                WebGLProgram: false,
                WebGLRenderbuffer: false,
                WebGLRenderingContext: false,
                WebGLShader: false,
                WebGLShaderPrecisionFormat: false,
                WebGLTexture: false,
                WebGLUniformLocation: false,
                WebSocket: false,
                window: false,
                Window: false,
                Worker: false,
                XDomainRequest: false,
                XMLHttpRequest: false,
                XMLSerializer: false,
                XPathEvaluator: false,
                XPathException: false,
                XPathExpression: false,
                XPathNamespace: false,
                XPathNSResolver: false,
                XPathResult: false
            };

            exports.devel = {
                alert: false,
                confirm: false,
                console: false,
                Debug: false,
                opera: false,
                prompt: false
            };

            exports.worker = {
                importScripts: true,
                postMessage: true,
                self: true,
                FileReaderSync: true
            };
            exports.nonstandard = {
                escape: false,
                unescape: false
            };

            exports.couch = {
                "require": false,
                respond: false,
                getRow: false,
                emit: false,
                send: false,
                start: false,
                sum: false,
                log: false,
                exports: false,
                module: false,
                provides: false
            };

            exports.node = {
                __filename: false,
                __dirname: false,
                GLOBAL: false,
                global: false,
                module: false,
                require: false,

                Buffer: true,
                console: true,
                exports: true,
                process: true,
                setTimeout: true,
                clearTimeout: true,
                setInterval: true,
                clearInterval: true,
                setImmediate: true, // v0.9.1+
                clearImmediate: true  // v0.9.1+
            };

            exports.browserify = {
                __filename: false,
                __dirname: false,
                global: false,
                module: false,
                require: false,
                Buffer: true,
                exports: true,
                process: true
            };

            exports.phantom = {
                phantom: true,
                require: true,
                WebPage: true,
                console: true, // in examples, but undocumented
                exports: true  // v1.7+
            };

            exports.qunit = {
                asyncTest: false,
                deepEqual: false,
                equal: false,
                expect: false,
                module: false,
                notDeepEqual: false,
                notEqual: false,
                notPropEqual: false,
                notStrictEqual: false,
                ok: false,
                propEqual: false,
                QUnit: false,
                raises: false,
                start: false,
                stop: false,
                strictEqual: false,
                test: false,
                "throws": false
            };

            exports.rhino = {
                defineClass: false,
                deserialize: false,
                gc: false,
                help: false,
                importClass: false,
                importPackage: false,
                "java": false,
                load: false,
                loadClass: false,
                Packages: false,
                print: false,
                quit: false,
                readFile: false,
                readUrl: false,
                runCommand: false,
                seal: false,
                serialize: false,
                spawn: false,
                sync: false,
                toint32: false,
                version: false
            };

            exports.shelljs = {
                target: false,
                echo: false,
                exit: false,
                cd: false,
                pwd: false,
                ls: false,
                find: false,
                cp: false,
                rm: false,
                mv: false,
                mkdir: false,
                test: false,
                cat: false,
                sed: false,
                grep: false,
                which: false,
                dirs: false,
                pushd: false,
                popd: false,
                env: false,
                exec: false,
                chmod: false,
                config: false,
                error: false,
                tempdir: false
            };

            exports.typed = {
                ArrayBuffer: false,
                ArrayBufferView: false,
                DataView: false,
                Float32Array: false,
                Float64Array: false,
                Int16Array: false,
                Int32Array: false,
                Int8Array: false,
                Uint16Array: false,
                Uint32Array: false,
                Uint8Array: false,
                Uint8ClampedArray: false
            };

            exports.wsh = {
                ActiveXObject: true,
                Enumerator: true,
                GetObject: true,
                ScriptEngine: true,
                ScriptEngineBuildVersion: true,
                ScriptEngineMajorVersion: true,
                ScriptEngineMinorVersion: true,
                VBArray: true,
                WSH: true,
                WScript: true,
                XDomainRequest: true
            };

            exports.dojo = {
                dojo: false,
                dijit: false,
                dojox: false,
                define: false,
                "require": false
            };

            exports.jquery = {
                "$": false,
                jQuery: false
            };

            exports.mootools = {
                "$": false,
                "$$": false,
                Asset: false,
                Browser: false,
                Chain: false,
                Class: false,
                Color: false,
                Cookie: false,
                Core: false,
                Document: false,
                DomReady: false,
                DOMEvent: false,
                DOMReady: false,
                Drag: false,
                Element: false,
                Elements: false,
                Event: false,
                Events: false,
                Fx: false,
                Group: false,
                Hash: false,
                HtmlTable: false,
                IFrame: false,
                IframeShim: false,
                InputValidator: false,
                instanceOf: false,
                Keyboard: false,
                Locale: false,
                Mask: false,
                MooTools: false,
                Native: false,
                Options: false,
                OverText: false,
                Request: false,
                Scroller: false,
                Slick: false,
                Slider: false,
                Sortables: false,
                Spinner: false,
                Swiff: false,
                Tips: false,
                Type: false,
                typeOf: false,
                URI: false,
                Window: false
            };

            exports.prototypejs = {
                "$": false,
                "$$": false,
                "$A": false,
                "$F": false,
                "$H": false,
                "$R": false,
                "$break": false,
                "$continue": false,
                "$w": false,
                Abstract: false,
                Ajax: false,
                Class: false,
                Enumerable: false,
                Element: false,
                Event: false,
                Field: false,
                Form: false,
                Hash: false,
                Insertion: false,
                ObjectRange: false,
                PeriodicalExecuter: false,
                Position: false,
                Prototype: false,
                Selector: false,
                Template: false,
                Toggle: false,
                Try: false,
                Autocompleter: false,
                Builder: false,
                Control: false,
                Draggable: false,
                Draggables: false,
                Droppables: false,
                Effect: false,
                Sortable: false,
                SortableObserver: false,
                Sound: false,
                Scriptaculous: false
            };

            exports.yui = {
                YUI: false,
                Y: false,
                YUI_config: false
            };

            exports.mocha = {
                mocha: false,
                describe: false,
                xdescribe: false,
                it: false,
                xit: false,
                context: false,
                xcontext: false,
                before: false,
                after: false,
                beforeEach: false,
                afterEach: false,
                suite: false,
                test: false,
                setup: false,
                teardown: false,
                suiteSetup: false,
                suiteTeardown: false
            };

            exports.jasmine = {
                jasmine: false,
                describe: false,
                xdescribe: false,
                it: false,
                xit: false,
                beforeEach: false,
                afterEach: false,
                setFixtures: false,
                loadFixtures: false,
                spyOn: false,
                expect: false,
                runs: false,
                waitsFor: false,
                waits: false,
                beforeAll: false,
                afterAll: false,
                fail: false,
                fdescribe: false,
                fit: false,
                pending: false
            };

        }, {}]
    }, {}, ["/node_modules/jshint/src/jshint.js"]);

});

define("ace/mode/javascript_worker", ["require", "exports", "module", "ace/lib/oop", "ace/worker/mirror", "ace/mode/javascript/jshint"], function (require, exports, module) {
    "use strict";

    var oop = require("../lib/oop");
    var Mirror = require("../worker/mirror").Mirror;
    var lint = require("./javascript/jshint").JSHINT;

    function startRegex(arr) {
        return RegExp("^(" + arr.join("|") + ")");
    }

    var disabledWarningsRe = startRegex([
        "Bad for in variable '(.+)'.",
        'Missing "use strict"'
    ]);
    var errorsRe = startRegex([
        "Unexpected",
        "Expected ",
        "Confusing (plus|minus)",
        "\\{a\\} unterminated regular expression",
        "Unclosed ",
        "Unmatched ",
        "Unbegun comment",
        "Bad invocation",
        "Missing space after",
        "Missing operator at"
    ]);
    var infoRe = startRegex([
        "Expected an assignment",
        "Bad escapement of EOL",
        "Unexpected comma",
        "Unexpected space",
        "Missing radix parameter.",
        "A leading decimal point can",
        "\\['{a}'\\] is better written in dot notation.",
        "'{a}' used out of scope"
    ]);

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

    oop.inherits(JavaScriptWorker, Mirror);

    (function () {
        this.setOptions = function (options) {
            this.options = options || {
                esnext: true,
                moz: true,
                devel: true,
                browser: true,
                node: true,
                laxcomma: true,
                laxbreak: true,
                lastsemic: true,
                onevar: false,
                passfail: false,
                maxerr: 100,
                expr: true,
                multistr: true,
                globalstrict: true
            };
            this.doc.getValue() && this.deferredUpdate.schedule(100);
        };

        this.changeOptions = function (newOptions) {
            oop.mixin(this.options, newOptions);
            this.doc.getValue() && this.deferredUpdate.schedule(100);
        };

        this.isValidJS = function (str) {
            try {
                eval("throw 0;" + str);
            } catch (e) {
                if (e === 0)
                    return true;
            }
            return false;
        };

        this.onUpdate = function () {
            var value = this.doc.getValue();
            value = value.replace(/^#!.*\n/, "\n");
            if (!value)
                return this.sender.emit("annotate", []);

            var errors = [];
            var maxErrorLevel = this.isValidJS(value) ? "warning" : "error";
            lint(value, this.options, this.options.globals);
            var results = lint.errors;

            var errorAdded = false;
            for (var i = 0; i < results.length; i++) {
                var error = results[i];
                if (!error)
                    continue;
                var raw = error.raw;
                var type = "warning";

                if (raw == "Missing semicolon.") {
                    var str = error.evidence.substr(error.character);
                    str = str.charAt(str.search(/\S/));
                    if (maxErrorLevel == "error" && str && /[\w\d{(['"]/.test(str)) {
                        error.reason = 'Missing ";" before statement';
                        type = "error";
                    } else {
                        type = "info";
                    }
                } else if (disabledWarningsRe.test(raw)) {
                    continue;
                } else if (infoRe.test(raw)) {
                    type = "info";
                } else if (errorsRe.test(raw)) {
                    errorAdded = true;
                    type = maxErrorLevel;
                } else if (raw == "'{a}' is not defined.") {
                    type = "warning";
                } else if (raw == "'{a}' is defined but never used.") {
                    type = "info";
                }

                errors.push({
                    row: error.line - 1,
                    column: error.character - 1,
                    text: error.reason,
                    type: type,
                    raw: raw
                });

                if (errorAdded) {
                }
            }

            this.sender.emit("annotate", errors);
        };

    }).call(JavaScriptWorker.prototype);

});

define("ace/lib/es5-shim", ["require", "exports", "module"], 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 () {

                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 () {
                return {"__proto__": null};
            };
        } else {
            createEmpty = function () {
                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.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 = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
        "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
        "\u2029\uFEFF";
    if (!String.prototype.trim || ws.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 (o) {
        if (o == null) { // this matches both null and undefined
            throw new TypeError("can't convert " + o + " to object");
        }
        return Object(o);
    };

});
