define(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) {
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

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

            module.exports = EventEmitter;

// Backwards-compat with node 0.10.x
            EventEmitter.EventEmitter = EventEmitter;

            EventEmitter.prototype._events = undefined;
            EventEmitter.prototype._maxListeners = undefined;

// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
            EventEmitter.defaultMaxListeners = 10;

// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
            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 there is no 'error' event listener then throw.
                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) {
                        // fast cases
                        case 1:
                            handler.call(this);
                            break;
                        case 2:
                            handler.call(this, arguments[1]);
                            break;
                        case 3:
                            handler.call(this, arguments[1], arguments[2]);
                            break;
                        // slower
                        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 = {};

                // To avoid recursion in the case that type === "newListener"! Before
                // adding it to the listeners, first emit "newListener".
                if (this._events.newListener)
                    this.emit('newListener', type,
                        isFunction(listener.listener) ?
                            listener.listener : listener);

                if (!this._events[type])
                // Optimize the case of one listener. Don't need the extra array object.
                    this._events[type] = listener;
                else if (isObject(this._events[type]))
                // If we've already got an array, just append.
                    this._events[type].push(listener);
                else
                // Adding the second element, need to change to array.
                    this._events[type] = [this._events[type], listener];

                // Check for listener leak
                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') {
                            // not supported in IE 10
                            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;
            };

// emits a 'removeListener' event iff the listener was removed
            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;

                // not listening for removeListener, no need to emit
                if (!this._events.removeListener) {
                    if (arguments.length === 0)
                        this._events = {};
                    else if (this._events[type])
                        delete this._events[type];
                    return this;
                }

                // emit removeListener for all listeners on all events
                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 {
                    // LIFO order
                    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);
                    }

                    // Add functions that return wrapped values when chaining.
                    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;

                    // Add functions that return unwrapped values when chaining.
                    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;

                    // Some AMD build optimizers like r.js check for condition patterns like the following:
                    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) {
            /*!
             * JSHint, by JSHint Community.
             *
             * This file (and this file only) is licensed under the same slightly modified
             * MIT license that JSLint is. It stops evil-doers everywhere:
             *
             *   Copyright (c) 2002 Douglas Crockford  (www.JSLint.com)
             *
             *   Permission is hereby granted, free of charge, to any person obtaining
             *   a copy of this software and associated documentation files (the "Software"),
             *   to deal in the Software without restriction, including without limitation
             *   the rights to use, copy, modify, merge, publish, distribute, sublicense,
             *   and/or sell copies of the Software, and to permit persons to whom
             *   the Software is furnished to do so, subject to the following conditions:
             *
             *   The above copyright notice and this permission notice shall be included
             *   in all copies or substantial portions of the Software.
             *
             *   The Software shall be used for Good, not Evil.
             *
             *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
             *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
             *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
             *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
             *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
             *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
             *   DEALINGS IN THE SOFTWARE.
             *
             */

            /*jshint quotmark:double */
            /*global console:true */
            /*exported console */

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

// We build the application inside a function so that we produce only a singleton
// variable. That function will be invoked immediately, and its return value is
// the JSHINT function itself.

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

                var api, // Extension API

                    // These are operators that should not be used with the ! operator.
                    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()) {
                        // ES3 FutureReservedWord in an ES5 environment.
                        if (!meta.es5) {
                            return false;
                        }

                        // Some ES5 FutureReservedWord identifiers are active only
                        // within a strict mode environment.
                        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();

                    /**
                     * TODO: Remove in JSHint 3
                     */
                    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";
                        }
                        /**
                         * TODO: Extend this restriction to *all* ES6-specific options.
                         */
                        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);
                    }
                }

                // Produce an error warning.
                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);
                }

                // Tracking of "internal" scripts, like eval containing a static string
                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) {
                                // Ignore trailing comma
                                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) {
                                // Ignore trailing comma
                                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) {
                                // GH988 - numeric options can be disabled by setting them to `false`
                                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") {
                                // `validthis` is valid only within a function scope.

                                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") {
                                /**
                                 * TODO: Extend this restriction to *all* "environmental" options.
                                 */
                                if (!hasParsedCode(state.funct)) {
                                    error("E055", state.tokens.next, "module");
                                }
                            }

                            /**
                             * TODO: Remove in JSHint 3
                             */
                            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");
                                        }
                                    /* falls through */
                                    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) {
                                // ignore for -W..., unignore for +W...
                                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();
                    }
                }

                // We need a peek function. If it has an argument, it peeks that much farther
                // ahead. It is used to distinguish
                //     for ( var i in ...
                // from
                //     for ( var i = ...

                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;
                    }

                    // Peeking past the end of the program should produce the "(end)" token.
                    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;
                }

                // Produce the next token. It looks for programming errors.

                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";
                }

                // This is the heart of JSHINT, the Pratt parser. In addition to parsing, it
                // is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is
                // like .nud except that it is only used on the first token of a statement.
                // Having .fud makes it much easier to define statement-oriented languages like
                // JavaScript. I retained Pratt's nomenclature.

                // .nud  Null denotation
                // .fud  First null denotation
                // .led  Left denotation
                //  lbp  Left binding power
                //  rbp  Right binding power

                // They are elements of the parsing method called Top Down Operator Precedence.

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

                    state.nameStack.push();

                    // if current expression is a let expression
                    if (!initial && state.tokens.next.value === "let" && peek(0).value === "(") {
                        if (!state.inMoz()) {
                            warning("W118", state.tokens.next, "let expressions");
                        }
                        isLetExpr = true;
                        // create a new block scope we use only for the current expression
                        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);
                        }

                        // TODO: use pratt mechanics rather than special casing template tokens
                        while ((rbp < state.tokens.next.lbp || state.tokens.next.type === "(template)") &&
                        !isEndOfExpr()) {
                            isArray = state.tokens.curr.value === "Array";
                            isObject = state.tokens.curr.value === "Object";

                            // #527, new Foo.Array(), Foo.Array(), new Foo.Object(), Foo.Object()
                            // Line breaks in IfStatement heads exist to satisfy the checkJSHint
                            // "Line too long." error.
                            if (left && (left.value || (left.first && left.first.value))) {
                                // If the left.value is not "new", or the left.first.value is a "."
                                // then safely assume that this is not "new Array()" and possibly
                                // not "new Object()"...
                                if (left.value !== "new" ||
                                    (left.first && left.first.value && left.first.value === ".")) {
                                    isArray = false;
                                    // ...In the case of Object, if the left.value and state.tokens.curr.value
                                    // are not equal, then safely assume that this not "new Object()"
                                    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;
                }


                // Functions for conformance of style.

                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())) {
                        // Keywords that cannot follow a comma operator.
                        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;
                                }

                            /* falls through */
                            case ")":
                                error("E024", state.tokens.next, state.tokens.next.value);
                                return false;
                        }
                    }
                    return true;
                }

                // Functional constructors for making the symbols that will be inherited by
                // tokens.

                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);
                                // detect increment/decrement of a const
                                // in the case of a.b, right will be the "." punctuator
                            } 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 = [
                    // E4X extended the `typeof` operator to return "xml" for the XML and
                    // XMLList types it introduced.
                    // Ref: 11.3.2 The typeof Operator
                    // http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-357.pdf
                    "xml",
                    // IE<9 reports "unknown" when the `typeof` operator is applied to an
                    // object existing across a COM+ bridge. In lieu of official documentation
                    // (which does not exist), see:
                    // http://robertnyman.com/2005/12/21/what-is-typeof-unknown/
                    "unknown"
                ];
                typeofValues.es3 = [
                    "undefined", "boolean", "number", "string", "function", "object",
                ];
                typeofValues.es3 = typeofValues.es3.concat(typeofValues.legacy);
                typeofValues.es6 = typeofValues.es3.concat("symbol");

                // Checks whether the 'typeof' operator is used with the correct
                // value. For docs on 'typeof' see:
                // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof
                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;

                    // permit methods to refer to an "eval" key in their own context
                    if (left.type === "this" && state.funct["(context)"] === null) {
                        isGlobal = true;
                    }
                    // permit use of "eval" members of objects
                    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);
                }

                /**
                 * Checks the left hand side of an assignment for issues, returns if ok
                 * @param {token} left - the left hand side of the assignment
                 * @param {token=} assignToken - the token for the assignment, used for reporting
                 * @param {object=} options - optional object
                 * @param {boolean} options.allowDestructuring - whether to allow destructuting binding
                 * @returns {boolean} Whether the left hand side is OK
                 */
                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) {
                        // reassign also calls modify
                        // but we are specific in order to catch function re-assignment
                        // and globals re-assignment
                        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) {
                        // this = suffix e.g. "++" punctuator
                        // left = symbol operated e.g. "a" identifier or "a.b" punctuator
                        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);
                            // detect increment/decrement of a const
                            // in the case of a.b, left will be the "." punctuator
                        } else if (left && left.identifier) {
                            state.funct["(scope)"].block.modify(left.value, left);
                        }

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

                // fnparam means that this identifier is being defined as a function
                // argument (see identifier())
                // prop means that this identifier is that of an object property

                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;
                }

                // fnparam means that this identifier is being defined as a function
                // argument
                // prop means that this identifier is that of an object property
                function identifier(fnparam, prop) {
                    var i = optionalidentifier(fnparam, prop, false);
                    if (i) {
                        return i;
                    }

                    // parameter destructuring with rest operator
                    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);

                        // The token should be consumed after a warning is issued so the parser
                        // can continue as though an identifier were found. The semicolon token
                        // should not be consumed in this way so that the parser interprets it as
                        // a statement delimeter;
                        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 !== ";") {
                        // don't complain about unclosed templates / strings
                        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 this is the last statement in a block that ends on
                            // the same line *and* option lastsemic is on, ignore the warning.
                            // Otherwise, complain about missing semicolon.
                            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;
                    }

                    // Is this a labelled statement?
                    var res = isReserved(t);

                    // We're being more tolerant here: if someone uses
                    // a FutureReservedWord as a label, we warn but proceed
                    // anyway.

                    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;
                    }

                    // Is it a lonely block?

                    if (t.id === "{") {
                        // Is it a switch case block?
                        //
                        //  switch (foo) {
                        //    case bar: { <= here.
                        //      ...
                        //    }
                        //  }
                        var iscase = (state.funct["(verb)"] === "case" && state.tokens.curr.value === ":");
                        block(true, true, false, false, iscase);
                        return;
                    }

                    // Parse the statement.

                    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");
                        }
                    }

                    // Look for the final semicolon.

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


                    // Restore the indentation.

                    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;
                }


                /*
                 * read all directives
                 * recognizes a simple form of asi, but always
                 * warns, if it is used
                 */
                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 === ".") {
                                // string -> [ | . is a valid production
                                break;
                            } else if (!state.option.asi || pn.value === "(") {
                                // string -> ( is not a valid production
                                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);
                        }

                        // there's no directive negation, so always set to true
                        state.directive[directive] = true;

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

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


                /*
                 * Parses a single block. A block is a sequence of statements wrapped in
                 * braces.
                 *
                 * ordinary   - true for everything but function bodies and try blocks.
                 * stmt       - true if block can be a single statement (e.g. in if/for/while).
                 * isfunc     - true if block is a function body
                 * isfatarrow - true if its a body of a fat arrow function
                 * iscase      - true if block is a switch case block
                 */
                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("{");

                        // create a new block scope
                        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 {

                        // check to avoid let declaration not within a block
                        // though is fine inside for loop initializer section
                        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;
                        // test indentation only if statement is in new line
                        a = [statement()];
                        indent -= state.option.indent;

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

                    // Don't clear and let it propagate out if it is "break", "return" or similar in switch case
                    switch (state.funct["(verb)"]) {
                        case "break":
                        case "continue":
                        case "return":
                        case "throw":
                            if (iscase) {
                                break;
                            }

                        /* falls through */
                        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;
                    }
                }

                // Build the syntax table by declaring the syntactic elements of the language.

                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 this identifier is the lone parameter to a shorthand "fat arrow"
                        // function definition, i.e.
                        //
                        //     x => x;
                        //
                        // ...it should not be considered as a variable in the current scope. It
                        // will be added to the scope of the new function when the next token is
                        // parsed, so it can be safely ignored for now.
                        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;
                });

                // ECMAScript parser

                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;

                    // The `delete` operator accepts unresolvable references when not in strict
                    // mode, so the operand may be undefined.
                    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");
                    }

                    // TODO: Allow all AssignmentExpression
                    // once parsing permits.
                    //
                    // How to handle eg. number, boolean when the built-in
                    // prototype of may have an @@iterator definition?
                    //
                    // Number.prototype[Symbol.iterator] = function * () {
                    //   yield this.valueOf();
                    // };
                    //
                    // var a = [ ...1 ];
                    // console.log(a); // [1];
                    //
                    // for (let n of [...10]) {
                    //    console.log(n);
                    // }
                    // // 10
                    //
                    //
                    // Boolean.prototype[Symbol.iterator] = function * () {
                    //   yield this.valueOf();
                    // };
                    //
                    // var a = [ ...true ];
                    // console.log(a); // [true];
                    //
                    // for (let n of [...false]) {
                    //    console.log(n);
                    // }
                    // // false
                    //
                    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);
                    }

                    // The `typeof` operator accepts unresolvable references, so the operand
                    // may be undefined.
                    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);

                                // window.setTimeout/setInterval
                            } 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 the balanced grouping operator is followed by a "fat arrow", the
                    // current token marks the beginning of a "fat arrow" function and parsing
                    // should proceed accordingly.
                    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 =
                                // Used to distinguish from an ExpressionStatement which may not
                                // begin with the `{` and `function` tokens
                                (opening.beginsStmt && (ret.id === "{" || triggerFnExpr || isFunctor(ret))) ||
                                // Used to signal that a function expression is being supplied to
                                // some other operator.
                                (triggerFnExpr &&
                                // For parenthesis wrapping a function expression to be considered
                                // necessary, the grouping operator should be the left-hand-side of
                                // some other operator--either within the parenthesis or directly
                                // following them.
                                (!isEndOfExpr() || state.tokens.prev.id !== "}")) ||
                                // Used to demarcate an arrow function as the left-hand side of some
                                // operator.
                                (isFunctor(ret) && !isEndOfExpr()) ||
                                // Used as the return value of a single-statement arrow function
                                (ret.id === "{" && preceeding.id === "=>") ||
                                // Used to delineate an integer number literal from a dereferencing
                                // punctuator (otherwise interpreted as a decimal point)
                                (ret.type === "(number)" &&
                                checkPunctuator(pn, ".") && /^\d+$/.test(ret.value));
                        }
                    }

                    if (ret) {
                        // The operator may be necessary to override the default binding power of
                        // neighboring operators (whenever there is an operator in use within the
                        // first expression *or* the current group contains multiple expressions)
                        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();

                    // Handle reversed for expressions, used in spidermonkey
                    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()) {
                                    // Maintain compat with old options --- ES5 mode without
                                    // elision=true will warn once per comma
                                    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;
                }

                /**
                 * @param {Object} [options]
                 * @param {token} [options.loneArg] The argument to the function in cases
                 *                                  where it was defined using the
                 *                                  single-argument shorthand.
                 * @param {bool} [options.parsedOpening] Whether the opening parenthesis has
                 *                                       already been parsed.
                 * @returns {{ arity: number, params: Array.<string>}}
                 */
                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++;
                        // are added to the param scope
                        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 {
                                // Skip invalid parameter.
                                while (!checkPunctuators(state.tokens.next, [",", ")"])) advance();
                            }
                        }

                        // It is valid to have a regular argument after a default argument
                        // since undefined can be used for missing parameters. Still warn as it is
                        // a possible code smell.
                        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);
                        }

                        // now we have evaluated the default expression, add the variable to the param scope
                        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;
                }

                /**
                 * Determine if the parser has begun parsing executable code.
                 *
                 * @param {Token} funct - The current "functor" token
                 *
                 * @returns {boolean}
                 */
                function hasParsedCode(funct) {
                    return funct["(global)"] && !funct["(verb)"];
                }

                function doTemplateLiteral(left) {
                    // ASSERT: this.type === "(template)"
                    // jshint validthis: true
                    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 {
                                // skip template start / middle
                                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;
                    }
                }

                /**
                 * @param {Object} [options]
                 * @param {token} [options.name] The identifier belonging to the function (if
                 *                               any)
                 * @param {boolean} [options.statement] The statement that triggered creation
                 *                                      of the current function.
                 * @param {string} [options.type] If specified, either "generator" or "arrow"
                 * @param {token} [options.loneArg] The argument to the function in cases
                 *                                  where it was defined using the
                 *                                  single-argument shorthand
                 * @param {bool} [options.parsedOpening] Whether the opening parenthesis has
                 *                                       already been parsed
                 * @param {token} [options.classExprBinding] Define a function with this
                 *                                           identifier in the new function's
                 *                                           scope, mimicking the bahavior of
                 *                                           class expression names within
                 *                                           the body of member functions.
                 */
                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);

                    // So that the function is available to itself and referencing itself is not
                    // seen as a closure, add the function name to a new scope, but do not
                    // test for unused (unused: false)
                    // it is a new block scope so that params can override it, it can be block scoped
                    // but declarations inside the function don't cause already declared error
                    state.funct["(scope)"].stack("functionouter");
                    var internallyAccessibleName = name || classExprBinding;
                    if (internallyAccessibleName) {
                        state.funct["(scope)"].block.add(internallyAccessibleName,
                            classExprBinding ? "class" : "function", state.tokens.curr, false);
                    }

                    // create the param scope (params added in functionparams)
                    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;

                    // unstack the params scope
                    state.funct["(scope)"].unstack(); // also does usage and label checks

                    // unstack the function outer stack
                    state.funct["(scope)"].unstack();

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

                    if (!ignoreLoopFunc && !state.option.loopfunc && state.funct["(loopage)"]) {
                        // If the function we just parsed accesses any non-local variables
                        // trigger a warning. Otherwise, the function is safe even within
                        // a loop.
                        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;
                }

                // Parse assignments that were found instead of conditionals.
                // For example: if (a = 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");
                            }
                    }
                }

                /**
                 * @param {object} props Collection of property descriptors for a given
                 *                       object.
                 */
                function checkProperties(props) {
                    // Check for lonely setters if in the ES5 mode.
                    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();

                                // ES6 allows for get() {...} and set() {...} method
                                // definition shorthand syntax, so we don't produce an error
                                // if linting ECMAScript 6 code.
                                if (!i && !state.inES6()) {
                                    error("E035");
                                }

                                // We don't want to save this getter unless it's an actual getter
                                // and not an ES6 concise method
                                if (i) {
                                    saveAccessor(nextVal, props, i, state.tokens.curr);
                                }

                                t = state.tokens.next;
                                f = doFunction();
                                p = f["(params)"];

                                // Don't warn about getter/setter pairs if this is an ES6 concise method
                                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 the target was a simple identifier, add it to the list to return
                                    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 {
                            // this id will either be the property name or the property name and the assigning identifier
                            id = identifier();
                            if (checkPunctuator(state.tokens.next, ":")) {
                                advance(":");
                                nextInnerDE();
                            } else if (id) {
                                // in this case we are assigning (not declaring), so check assignment
                                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, "}")) {
                                    // Trailing comma
                                    // ObjectBindingPattern: { BindingPropertyList , }
                                    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) {
                    // used for both let and const statements

                    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);
                            }
                            // don't accept `in` in expression if prefix is used for ForIn/Of loop.
                            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;

                    // If the `implied` option is set, bindings are set differently.
                    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);
                                }
                            }
                            // don't accept `in` in expression if prefix is used for ForIn/Of loop.
                            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) {

                    /*jshint validthis:true */
                    if (!state.inES6()) {
                        warning("W104", state.tokens.curr, "class", "6");
                    }
                    if (isStatement) {
                        // BindingIdentifier
                        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") {
                        // BindingIdentifier(opt)
                        this.name = identifier();
                        this.namedExpr = true;
                    } else {
                        this.name = state.nameStack.infer();
                    }
                    classtail(this);
                    return this;
                }

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

                    state.inClassBody = true;
                    advance("{");
                    // ClassBody(opt)
                    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;

                        // The ES6 grammar for ClassElement includes the `;` token, but it is
                        // defined only as a placeholder to facilitate future language
                        // extensions. In ES6 code, it serves no purpose.
                        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)) {
                            // Non-Computed PropertyName
                            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 --- class properties must be methods
                            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) {
                            // We don't know how to determine if we have duplicate computed property names :(
                            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);

                    // When the if is within a for-in loop, check if the condition
                    // starts with a negation operator
                    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);

                    // When the if is within a for-in loop and the condition has a negative form,
                    // check if the body contains nothing but a continue statement
                    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 {
                            // only advance if we have an identifier so we can continue parsing in the most common error - that no param is given.
                            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:
                                        // You can tell JSHint that you don't use break intentionally by
                                        // adding a comment /* falls through */ on a line just before
                                        // the next `case`.
                                        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:
                                        // Do not display a warning if 'default' is the first statement or if
                                        // there is a special /* falls through */ comment.
                                        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("(");

                    // what kind of for(…) statement it is? for(…of…)? for(…in…)? for(…;…;…)?
                    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 initial token is a BindingPattern, count it as such.
                    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 we're in a for (… in|of …) statement
                    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);
                            // create a new block scope
                            letscope = true;
                            state.funct["(scope)"].stack();
                            state.tokens.curr.fud({prefix: true});
                        } else {
                            // Parse as a var statement, with implied bindings. Ignore errors if an error
                            // was already reported
                            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 = [];
                            }

                            // Push a new for-in-if check onto the stack. The type will be modified
                            // when the loop's body is parsed and a suitable if statement exists.
                            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") ||
                                // Positive if statement is not the only one in loop body
                                check.type === "(positive)" && s.length > 1 ||
                                // Negative if statement but no continue
                                check.type === "(negative)") {
                                    warning("W089", this);
                                }
                            }

                            // Reset the flag in case no if statement was contained in the loop body
                            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");
                                // create a new block scope
                                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(";");

                        // start loopage after the first ; as the next two expressions are executed
                        // on every loop
                        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;

                    }
                    // unstack loop blockscope
                    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 it's a yield within a catch clause inside a generator then that's ok
                        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)") {
                        // ModuleSpecifier :: StringLiteral
                        advance("(string)");
                        return this;
                    }

                    if (state.tokens.next.identifier) {
                        // ImportClause :: ImportedDefaultBinding
                        this.name = identifier();
                        // Import bindings are immutable (see ES6 8.1.1.5.5)
                        state.funct["(scope)"].addlabel(this.name, {
                            type: "const",
                            token: state.tokens.curr
                        });

                        if (state.tokens.next.value === ",") {
                            // ImportClause :: ImportedDefaultBinding , NameSpaceImport
                            // ImportClause :: ImportedDefaultBinding , NamedImports
                            advance(",");
                            // At this point, we intentionally fall through to continue matching
                            // either NameSpaceImport or NamedImports.
                            // Discussion:
                            // https://github.com/jshint/jshint/pull/2144#discussion_r23978406
                        } else {
                            advance("from");
                            advance("(string)");
                            return this;
                        }
                    }

                    if (state.tokens.next.id === "*") {
                        // ImportClause :: NameSpaceImport
                        advance("*");
                        advance("as");
                        if (state.tokens.next.identifier) {
                            this.name = identifier();
                            // Import bindings are immutable (see ES6 8.1.1.5.5)
                            state.funct["(scope)"].addlabel(this.name, {
                                type: "const",
                                token: state.tokens.curr
                            });
                        }
                    } else {
                        // ImportClause :: NamedImports
                        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();
                            }

                            // Import bindings are immutable (see ES6 8.1.1.5.5)
                            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;
                            }
                        }
                    }

                    // FromClause
                    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 === "*") {
                        // ExportDeclaration :: export * FromClause
                        advance("*");
                        advance("from");
                        advance("(string)");
                        return this;
                    }

                    if (state.tokens.next.type === "default") {
                        // ExportDeclaration ::
                        //      export default [lookahead  { function, class }] AssignmentExpression[In] ;
                        //      export default HoistableDeclaration
                        //      export default ClassDeclaration
                        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 === "{") {
                        // ExportDeclaration :: export ExportClause
                        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") {
                            // ExportDeclaration :: export ExportClause FromClause
                            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") {
                        // ExportDeclaration :: export VariableStatement
                        advance("var");
                        state.tokens.curr.fud({inexport: true});
                    } else if (state.tokens.next.id === "let") {
                        // ExportDeclaration :: export VariableStatement
                        advance("let");
                        state.tokens.curr.fud({inexport: true});
                    } else if (state.tokens.next.id === "const") {
                        // ExportDeclaration :: export VariableStatement
                        advance("const");
                        state.tokens.curr.fud({inexport: true});
                    } else if (state.tokens.next.id === "function") {
                        // ExportDeclaration :: export Declaration
                        this.block = true;
                        advance("function");
                        state.syntax["function"].fud({inexport: true});
                    } else if (state.tokens.next.id === "class") {
                        // ExportDeclaration :: export Declaration
                        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;

                // Future Reserved Words

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

                // this function is used to determine whether a squarebracket or a curlybracket
                // expression is a comprehension array, destructuring assignment or a json value.

                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;
                }

                /**
                 * @param {string} accessorType - Either "get" or "set"
                 * @param {object} props - a collection of all properties of the object to
                 *                         which the current accessor is being assigned
                 * @param {object} tkn - the identifier token representing the accessor name
                 * @param {boolean} isClass - whether the accessor is part of an ES6 Class
                 *                            definition
                 * @param {boolean} isStatic - whether the accessor is a static method
                 */
                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;
                }

                /**
                 * Test whether a given token is a punctuator matching one of the specified values
                 * @param {Token} token
                 * @param {Array.<string>} values
                 * @returns {boolean}
                 */
                function checkPunctuators(token, values) {
                    if (token.type === "(punctuator)") {
                        return _.contains(values, token.value);
                    }
                    return false;
                }

                /**
                 * Test whether a given token is a punctuator matching the specified value
                 * @param {Token} token
                 * @param {string} value
                 * @returns {boolean}
                 */
                function checkPunctuator(token, value) {
                    return token.type === "(punctuator)" && token.value === value;
                }

                // Check whether this function has been reached for a destructuring assign with undeclared values
                function destructuringAssignOrJsonValue() {
                    // lookup for the assignment (ECMAScript 6 only)
                    // if it has semicolons, it is a block, so go parse it as a block
                    // or it's not a block, but there are assignments, check for undeclared variables

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

                // array comprehension parsing function
                // parses and defines the three states of the list comprehension in order
                // to avoid defining global variables, but keeping them to the list comprehension scope
                // only. The order of the states are as follows:
                //  * "use" which will be the returned iterative part of the list comprehension
                //  * "define" which will define the variables local to the list comprehension
                //  * "filter" which will help filter out values

                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 it has, change its undef state
                            if (elt.value === v) {
                                elt.undef = false;
                                return v;
                            }
                        }).length;
                        return l !== 0;
                    }

                    function use(v) {
                        var l = _current.variables.filter(function (elt) {
                            // and if it has been defined
                            if (elt.value === v && !elt.undef) {
                                if (elt.unused === true) {
                                    elt.unused = false;
                                }
                                return v;
                            }
                        }).length;
                        // otherwise we warn about it
                        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;
                            }
                            // When we are in "use" state of the list comp, we enqueue that var
                            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;
                                // When we are in "define" state of the list comp,
                            } else if (_current && _current.mode === "define") {
                                // check if the variable has been used previously
                                if (!declare(v)) {
                                    _current.variables.push({
                                        funct: state.funct,
                                        token: state.tokens.curr,
                                        value: v,
                                        undef: false,
                                        unused: true
                                    });
                                }
                                return true;
                                // When we are in the "generate" state of the list comp,
                            } else if (_current && _current.mode === "generate") {
                                state.funct["(scope)"].block.use(v, state.tokens.curr);
                                return true;
                                // When we are in "filter" state,
                            } else if (_current && _current.mode === "filter") {
                                // we check whether current variable has been declared
                                if (use(v)) {
                                    // if not we warn about it
                                    state.funct["(scope)"].block.use(v, state.tokens.curr);
                                }
                                return true;
                            }
                            return false;
                        }
                    };
                };


                // Parse JSON

                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, "\\$&");
                };

                // The actual JSHINT function itself.
                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;
                                // remove from predefined if there
                                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();

                    // Check options
                    for (var name in o) {
                        if (_.has(o, name)) {
                            checkOption(name, state.tokens.curr);
                        }
                    }

                    assume();

                    // combine the passed globals after we've assumed all our options
                    combine(predefined, g || {});

                    //reset values
                    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;
                        }
                    }

                    // Loop over the listed "internals", and check them as well.

                    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;
                };

                // Modules.
                itself.addModule = function (func) {
                    extraModules.push(func);
                };

                itself.addModule(style.register);

                // Data summary.
                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;
            }());

// Make JSHINT a Node module, if possible.
            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) {
            /*
             * Lexical analysis and token construction.
             */

            "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;

// Some of these token types are from JavaScript Parser API
// while others are specific to JSHint parser.
// JS Parser API: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API

            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
            };

// Object that handles postponed lexing verifications that checks the parsed
// environment state.

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

            /*
             * Lexer for JSHint.
             *
             * This object does a char-by-char scan of the provided source code
             * and produces a sequence of tokens.
             *
             *   var lex = new Lexer("var i = 0;");
             *   lex.start();
             *   lex.token(); // returns the next token
             *
             * You have to use the token() method to move the lexer forward
             * but you don't have to use its return value to get tokens. In addition
             * to token() method returning the next token, the Lexer object also
             * emits events.
             *
             *   lex.on("Identifier", function(data) {
             *     if (data.name.indexOf("_") >= 0) {
             *       // Produce a warning.
             *     }
             *   });
             *
             * Note that the token() method returns tokens in a JSLint-compatible
             * format while the event emitter uses a slightly modified version of
             * Mozilla's JavaScript Parser API. Eventually, we will move away from
             * JSLint format.
             */
            function Lexer(source) {
                var lines = source;

                if (typeof lines === "string") {
                    lines = lines
                        .replace(/\r\n/g, "\n")
                        .replace(/\r/g, "\n")
                        .split("\n");
                }

                // If the first line is a shebang (#!), make it a blank and move on.
                // Shebangs are used by Node scripts.

                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 += " ";
                }

                // Blank out non-multi-line-commented lines when ignoring linter errors
                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;
                },

                /*
                 * Return the next i character without actually moving the
                 * char pointer.
                 */
                peek: function (i) {
                    return this.input.charAt(i || 0);
                },

                /*
                 * Move the char pointer forward i times.
                 */
                skip: function (i) {
                    i = i || 1;
                    this.char += i;
                    this.input = this.input.slice(i);
                },

                /*
                 * Subscribe to a token event. The API for this method is similar
                 * Underscore.js i.e. you can subscribe to multiple events with
                 * one call:
                 *
                 *   lex.on("Identifier Number", function(data) {
                 *     // ...
                 *   });
                 */
                on: function (names, listener) {
                    names.split(" ").forEach(function (name) {
                        this.emitter.on(name, listener);
                    }.bind(this));
                },

                /*
                 * Trigger a token event. All arguments will be passed to each
                 * listener.
                 */
                trigger: function () {
                    this.emitter.emit.apply(this.emitter, Array.prototype.slice.call(arguments));
                },

                /*
                 * Postpone a token event. the checking condition is set as
                 * last parameter, and the trigger function is called in a
                 * stored callback. To be later called using the check() function
                 * by the parser. This avoids parser's peek() to give the lexer
                 * a false context.
                 */
                triggerAsync: function (type, args, checks, fn) {
                    checks.push(function () {
                        if (fn()) {
                            this.trigger(type, args);
                        }
                    }.bind(this));
                },

                /*
                 * Extract a punctuator out of the next sequence of characters
                 * or return 'null' if its not possible.
                 *
                 * This method's implementation was heavily influenced by the
                 * scanPunctuator function in the Esprima parser's source code.
                 */
                scanPunctuator: function () {
                    var ch1 = this.peek();
                    var ch2, ch3, ch4;

                    switch (ch1) {
                        // Most common single-character punctuators
                        case ".":
                            if ((/^[0-9]$/).test(this.peek(1))) {
                                return null;
                            }
                            if (this.peek(1) === "." && this.peek(2) === ".") {
                                return {
                                    type: Token.Punctuator,
                                    value: "..."
                                };
                            }
                        /* falls through */
                        case "(":
                        case ")":
                        case ";":
                        case ",":
                        case "[":
                        case "]":
                        case ":":
                        case "~":
                        case "?":
                            return {
                                type: Token.Punctuator,
                                value: ch1
                            };

                        // A block/object opener
                        case "{":
                            this.pushContext(Context.Block);
                            return {
                                type: Token.Punctuator,
                                value: ch1
                            };

                        // A block/object closer
                        case "}":
                            if (this.inContext(Context.Block)) {
                                this.popContext();
                            }
                            return {
                                type: Token.Punctuator,
                                value: ch1
                            };

                        // A pound sign (for Node shebangs)
                        case "#":
                            return {
                                type: Token.Punctuator,
                                value: ch1
                            };

                        // We're at the end of input
                        case "":
                            return null;
                    }

                    // Peek more characters

                    ch2 = this.peek(1);
                    ch3 = this.peek(2);
                    ch4 = this.peek(3);

                    // 4-character punctuator: >>>=

                    if (ch1 === ">" && ch2 === ">" && ch3 === ">" && ch4 === "=") {
                        return {
                            type: Token.Punctuator,
                            value: ">>>="
                        };
                    }

                    // 3-character punctuators: === !== >>> <<= >>=

                    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: ">>="
                        };
                    }

                    // Fat arrow punctuator
                    if (ch1 === "=" && ch2 === ">") {
                        return {
                            type: Token.Punctuator,
                            value: ch1 + ch2
                        };
                    }

                    // 2-character punctuators: <= >= == != ++ -- << >> && ||
                    // += -= *= %= &= |= ^= (but not /=, see below)
                    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
                        };
                    }

                    // Special case: /=.

                    if (ch1 === "/") {
                        if (ch2 === "=") {
                            return {
                                type: Token.Punctuator,
                                value: "/="
                            };
                        }

                        return {
                            type: Token.Punctuator,
                            value: "/"
                        };
                    }

                    return null;
                },

                /*
                 * Extract a comment out of the next sequence of characters and/or
                 * lines or return 'null' if its not possible. Since comments can
                 * span across multiple lines this method has to move the char
                 * pointer.
                 *
                 * In addition to normal JavaScript comments (// and /*) this method
                 * also recognizes JSHint- and JSLint-specific comments such as
                 * /*jshint, /*jslint, /*globals and so on.
                 */
                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;

                    // Create a comment token object and make sure it
                    // has all the data JSHint needs to work with special
                    // comments.

                    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;
                            }

                            // Don't recognize any special comments other than jshint for single-line
                            // comments. This introduced many problems with legit comments.
                            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
                        };
                    }

                    // End of unbegun comment. Raise an error and skip that input.
                    if (ch1 === "*" && ch2 === "/") {
                        this.trigger("error", {
                            code: "E018",
                            line: startLine,
                            character: startChar
                        });

                        this.skip(2);
                        return null;
                    }

                    // Comments must start either with // or /*
                    if (ch1 !== "/" || (ch2 !== "*" && ch2 !== "/")) {
                        return null;
                    }

                    // One-line comment
                    if (ch2 === "/") {
                        this.skip(this.input.length); // Skip to the EOL.
                        return commentToken("//", rest);
                    }

                    var body = "";

                    /* Multi-line comment */
                    if (ch2 === "*") {
                        this.inComment = true;
                        this.skip(2);

                        while (this.peek() !== "*" || this.peek(1) !== "/") {
                            if (this.peek() === "") { // End of Line
                                body += "\n";

                                // If we hit EOF and our comment is still unclosed,
                                // trigger an error and end the comment implicitly.
                                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});
                    }
                },

                /*
                 * Extract a keyword out of the next sequence of characters or
                 * return 'null' if its not possible.
                 */
                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;
                },

                /*
                 * Extract a JavaScript identifier out of the next sequence of
                 * characters or return 'null' if its not possible. In addition,
                 * to Identifier this method can also produce BooleanLiteral
                 * (true/false) and NullLiteral (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 () {
                        /*jshint validthis:true */
                        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 () {
                        /*jshint validthis:true */
                        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 () {
                        /*jshint validthis:true */
                        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
                    };
                },

                /*
                 * Extract a numeric literal out of the next sequence of
                 * characters or return 'null' if its not possible. This method
                 * supports all numeric literals described in section 7.8.3
                 * of the EcmaScript 5 specification.
                 *
                 * This method's implementation was heavily influenced by the
                 * scanNumericLiteral function in the Esprima parser's source code.
                 */
                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");
                    }

                    // Numbers must start either with a decimal digit or a point.

                    if (char !== "." && !isDecimalDigit(char)) {
                        return null;
                    }

                    if (char !== ".") {
                        value = this.peek(index);
                        index += 1;
                        char = this.peek(index);

                        if (value === "0") {
                            // Base-16 numbers.
                            if (char === "x" || char === "X") {
                                isAllowedDigit = isHexDigit;
                                base = 16;

                                index += 1;
                                value += char;
                            }

                            // Base-8 numbers.
                            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;
                            }

                            // Base-2 numbers.
                            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;
                            }

                            // Legacy base-8 numbers.
                            if (isOctalDigit(char)) {
                                isAllowedDigit = isOctalDigit;
                                base = 8;
                                isLegacy = true;
                                bad = false;

                                index += 1;
                                value += char;
                            }

                            // Decimal numbers that start with '0' such as '09' are illegal
                            // but we still parse them and return as malformed.

                            if (!isOctalDigit(char) && isDecimalDigit(char)) {
                                index += 1;
                                value += char;
                            }
                        }

                        while (index < length) {
                            char = this.peek(index);

                            if (isLegacy && isDecimalDigit(char)) {
                                // Numbers like '019' (note the 9) are not valid octals
                                // but we still parse them and mark as malformed.
                                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
                            };
                        }
                    }

                    // Decimal digits.

                    if (char === ".") {
                        value += char;
                        index += 1;

                        while (index < length) {
                            char = this.peek(index);
                            if (!isDecimalDigit(char)) {
                                break;
                            }
                            value += char;
                            index += 1;
                        }
                    }

                    // Exponent part.

                    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)
                    };
                },


                // Assumes previously parsed character was \ (=== '\\') and was not skipped.
                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";

                            // Octal literals fail in strict mode.
                            // Check if the number is between 00 and 07.
                            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};
                },

                /*
                 * Extract a template literal out of the next sequence of characters
                 * and/or lines or return 'null' if its not possible. Since template
                 * literals can span across multiple lines, this method has to move
                 * the char pointer.
                 */
                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)) {
                        // Only lex template strings in ESNext mode.
                        return null;
                    } else if (this.peek() === "`") {
                        // Template must start with a backtick.
                        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() === "}") {
                        // If we're in a template context, and we have a '}', lex a TemplateMiddle.
                        tokenType = Token.TemplateMiddle;
                    } else {
                        // Go lex something else.
                        return null;
                    }

                    while (this.peek() !== "`") {
                        while ((ch = this.peek()) === "") {
                            value += "\n";
                            if (!this.nextLine()) {
                                // Unclosed template literal --- point to the starting "`"
                                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 !== '`') {
                            // Otherwise, append the value and continue.
                            value += ch;
                            this.skip(1);
                        }
                    }

                    // Final value is either NoSubstTemplate or TemplateTail
                    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()
                    };
                },

                /*
                 * Extract a string out of the next sequence of characters and/or
                 * lines or return 'null' if its not possible. Since strings can
                 * span across multiple lines this method has to move the char
                 * pointer.
                 *
                 * This method recognizes pseudo-multiline JavaScript strings:
                 *
                 *   var str = "hello\
                 *   world";
                 */
                scanStringLiteral: function (checks) {
                    /*jshint loopfunc:true */
                    var quote = this.peek();

                    // String must start with a quote.
                    if (quote !== "\"" && quote !== "'") {
                        return null;
                    }

                    // In JSON strings must always use double quotes.
                    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 an EOL is not preceded by a backslash, show a warning
                            // and proceed like it was a legit multi-line string where
                            // author simply forgot to escape the newline symbol.
                            //
                            // Another approach is to implicitly close a string on EOL
                            // but it generates too many false positives.

                            if (!allowNewLine) {
                                this.trigger("warning", {
                                    code: "W112",
                                    line: this.line,
                                    character: this.char
                                });
                            } else {
                                allowNewLine = false;

                                // Otherwise show a warning if multistr option was not set.
                                // For JSON, show warning no matter what.

                                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 we get an EOF inside of an unclosed string, show an
                            // error and implicitly close it at the EOF point.

                            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
                                          // parsing this character.

                            if (char < " ") {
                                // Warn about a control character in a string.
                                this.trigger("warning", {
                                    code: "W113",
                                    line: this.line,
                                    character: this.char,
                                    data: ["<non-printable>"]
                                });
                            }

                            // Special treatment for some escaped characters.
                            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
                    };
                },

                /*
                 * Extract a regular expression out of the next sequence of
                 * characters and/or lines or return 'null' if its not possible.
                 *
                 * This method is platform dependent: it accepts almost any
                 * regular expression values but then tries to compile and run
                 * them using system's RegExp object. This means that there are
                 * rare edge cases where one JavaScript engine complains about
                 * your regular expression while others don't.
                 */
                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 () {
                        // Unexpected control character
                        if (char < " ") {
                            malformed = true;
                            this.trigger("warning", {
                                code: "W048",
                                line: this.line,
                                character: this.char
                            });
                        }

                        // Unexpected escaped character
                        if (char === "<") {
                            malformed = true;
                            this.trigger("warning", {
                                code: "W049",
                                line: this.line,
                                character: this.char,
                                data: [char]
                            });
                        }
                    }.bind(this);

                    // Regular expressions must start with '/'
                    if (!this.prereg || char !== "/") {
                        return null;
                    }

                    index += 1;
                    terminated = false;

                    // Try to get everything in between slashes. A couple of
                    // cases aside (see scanUnexpectedChars) we don't really
                    // care whether the resulting expression is valid or not.
                    // We will check that later using the RegExp object.

                    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;
                    }

                    // A regular expression that was never closed is an
                    // error from which we cannot recover.

                    if (!terminated) {
                        this.trigger("error", {
                            code: "E015",
                            line: this.line,
                            character: this.from
                        });

                        return void this.trigger("fatal", {
                            line: this.line,
                            from: this.from
                        });
                    }

                    // Parse flags (if any).

                    while (index < length) {
                        char = this.peek(index);
                        if (!/[gim]/.test(char)) {
                            break;
                        }
                        flags.push(char);
                        value += char;
                        index += 1;
                    }

                    // Check regular expression for correctness.

                    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
                    };
                },

                /*
                 * Scan for any occurrence of non-breaking spaces. Non-breaking spaces
                 * can be mistakenly typed on OS X with option-space. Non UTF-8 web
                 * pages with non-breaking pages produce syntax errors.
                 */
                scanNonBreakingSpaces: function () {
                    return state.option.nonbsp ?
                        this.input.search(/(\u00A0)/) : -1;
                },

                /*
                 * Scan for characters that get silently deleted by one or more browsers.
                 */
                scanUnsafeChars: function () {
                    return this.input.search(reg.unsafeChars);
                },

                /*
                 * Produce the next raw token or return 'null' if no tokens can be matched.
                 * This method skips over all space characters.
                 */
                next: function (checks) {
                    this.from = this.char;

                    // Move to the next non-space character.
                    var start;
                    if (/\s/.test(this.peek())) {
                        start = this.char;

                        while (/\s/.test(this.peek())) {
                            this.from += 1;
                            this.skip();
                        }
                    }

                    // Methods that work with multi-line structures and move the
                    // character pointer.

                    var match = this.scanComments() ||
                        this.scanStringLiteral(checks) ||
                        this.scanTemplateLiteral(checks);

                    if (match) {
                        return match;
                    }

                    // Methods that don't move the character pointer.

                    match =
                        this.scanRegExp() ||
                        this.scanPunctuator() ||
                        this.scanKeyword() ||
                        this.scanIdentifier() ||
                        this.scanNumericLiteral();

                    if (match) {
                        this.skip(match.tokenLength || match.value.length);
                        return match;
                    }

                    // No token could be matched, give up.

                    return null;
                },

                /*
                 * Switch to the next line and reset all char pointers. Once
                 * switched, this method also checks for other minor warnings.
                 */
                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 we are ignoring linter errors, replace the input with empty string
                    // if it doesn't already at least start or end a multi-line comment
                    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 there is a limit on line length, warn when lines get too
                    // long.

                    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;
                },

                /*
                 * This is simply a synonym for nextLine() method with a friendlier
                 * public name.
                 */
                start: function () {
                    this.nextLine();
                },

                /*
                 * Produce the next token. This function is called by advance() to get
                 * the next token. It returns a token in a JSLint-compatible format.
                 */
                token: function () {
                    /*jshint loopfunc:true */
                    var checks = asyncTrigger();
                    var token;


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

                        if (meta && meta.isFutureReservedWord && state.inES5()) {
                            // ES3 FutureReservedWord in an ES5 environment.
                            if (!meta.es5) {
                                return false;
                            }

                            // Some ES5 FutureReservedWord identifiers are active only
                            // within a strict mode environment.
                            if (meta.strictOnly) {
                                if (!state.option.strict && !state.isStrict()) {
                                    return false;
                                }
                            }

                            if (isProperty) {
                                return false;
                            }
                        }

                        return true;
                    }

                    // Produce a token object.
                    var create = function (type, value, isProperty, token) {
                        /*jshint validthis:true */
                        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 this can't be a reserved keyword, reset the object.
                                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) {
                            // Context of current token
                            obj.context = token.context;
                        }
                        if (token && token.depth) {
                            // Nested template depth
                            obj.depth = token.depth;
                        }
                        if (token && token.isUnclosed) {
                            // Mark token as unclosed string / template literal
                            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) {
                                // Unexpected character.
                                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;
                                });

                            /* falls through */
                            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 = {
                // JSHint options
                E001: "Bad option: '{a}'.",
                E002: "Bad option value.",

                // JSHint input
                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.",

                // Strict mode
                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.",

                // Constants
                E011: "'{a}' has already been declared.",
                E012: "const '{a}' is initialized to 'undefined'.",
                E013: "Attempting to override '{a}' which is a constant.",

                // Regular expressions
                E014: "A regular expression literal can be confused with '/='.",
                E015: "Unclosed regular expression.",
                E016: "Invalid regular expression.",

                // Tokens
                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.",

                // Everything else
                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;
                }
            });

            /**
             * Create a new entry in the stack. Useful for tracking names across
             * expressions.
             */
            NameStack.prototype.push = function () {
                this._stack.push(null);
            };

            /**
             * Discard the most recently-created name on the stack.
             */
            NameStack.prototype.pop = function () {
                this._stack.pop();
            };

            /**
             * Update the most recent name on the top of the stack.
             *
             * @param {object} token The token to consider as the source for the most
             *                       recent name.
             */
            NameStack.prototype.set = function (token) {
                this._stack[this.length - 1] = token;
            };

            /**
             * Generate a string representation of the most recent name.
             *
             * @returns {string}
             */
            NameStack.prototype.infer = function () {
                var nameToken = this._stack[this.length - 1];
                var prefix = "";
                var type;

                // During expected operation, the topmost entry on the stack will only
                // reflect the current function's name when the function is declared without
                // the `function` keyword (i.e. for in-line accessor methods). In other
                // cases, the `function` expression itself will introduce an empty entry on
                // the top of the stack, and this should be ignored.
                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";

// These are the JSHint boolean options.
            exports.bool = {
                enforcing: {

                    /**
                     * This option prohibits the use of bitwise operators such as `^` (XOR),
                     * `|` (OR) and others. Bitwise operators are very rare in JavaScript
                     * programs and quite often `&` is simply a mistyped `&&`.
                     */
                    bitwise: true,

                    /**
                     *
                     * This options prohibits overwriting prototypes of native objects such as
                     * `Array`, `Date` and so on.
                     *
                     *     // jshint freeze:true
                     *     Array.prototype.count = function (value) { return 4; };
                     *     // -> Warning: Extending prototype of native object: 'Array'.
                     */
                    freeze: true,

                    /**
                     * This option allows you to force all variable names to use either
                     * camelCase style or UPPER_CASE with underscores.
                     *
                     * @deprecated JSHint is limiting its scope to issues of code correctness.
                     *             If you would like to enforce rules relating to code style,
                     *             check out [the JSCS
                     *             project](https://github.com/jscs-dev/node-jscs).
                     */
                    camelcase: true,

                    /**
                     * This option requires you to always put curly braces around blocks in
                     * loops and conditionals. JavaScript allows you to omit curly braces when
                     * the block consists of only one statement, for example:
                     *
                     *     while (day)
                     *       shuffle();
                     *
                     * However, in some circumstances, it can lead to bugs (you'd think that
                     * `sleep()` is a part of the loop while in reality it is not):
                     *
                     *     while (day)
                     *       shuffle();
                     *       sleep();
                     */
                    curly: true,

                    /**
                     * This options prohibits the use of `==` and `!=` in favor of `===` and
                     * `!==`. The former try to coerce values before comparing them which can
                     * lead to some unexpected results. The latter don't do any coercion so
                     * they are generally safer. If you would like to learn more about type
                     * coercion in JavaScript, we recommend [Truth, Equality and
                     * JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/)
                     * by Angus Croll.
                     */
                    eqeqeq: true,

                    /**
                     * This option enables warnings about the use of identifiers which are
                     * defined in future versions of JavaScript. Although overwriting them has
                     * no effect in contexts where they are not implemented, this practice can
                     * cause issues when migrating codebases to newer versions of the language.
                     */
                    futurehostile: true,

                    /**
                     * This option suppresses warnings about invalid `typeof` operator values.
                     * This operator has only [a limited set of possible return
                     * values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof).
                     * By default, JSHint warns when you compare its result with an invalid
                     * value which often can be a typo.
                     *
                     *     // 'fuction' instead of 'function'
                     *     if (typeof a == "fuction") { // Invalid typeof value 'fuction'
     *       // ...
     *     }
                     *
                     * Do not use this option unless you're absolutely sure you don't want
                     * these checks.
                     */
                    notypeof: true,

                    /**
                     * This option tells JSHint that your code needs to adhere to ECMAScript 3
                     * specification. Use this option if you need your program to be executable
                     * in older browsers—such as Internet Explorer 6/7/8/9—and other legacy
                     * JavaScript environments.
                     *
                     * @deprecated Use `esversion: 3` instead.
                     */
                    es3: true,

                    /**
                     * This option enables syntax first defined in [the ECMAScript 5.1
                     * specification](http://es5.github.io/). This includes allowing reserved
                     * keywords as object properties.
                     *
                     * @deprecated Use `esversion: 5` instead.
                     */
                    es5: true,

                    /**
                     * This option requires all `for in` loops to filter object's items. The
                     * for in statement allows for looping through the names of all of the
                     * properties of an object including those inherited through the prototype
                     * chain. This behavior can lead to unexpected items in your object so it
                     * is generally safer to always filter inherited properties out as shown in
                     * the example:
                     *
                     *     for (key in obj) {
     *       if (obj.hasOwnProperty(key)) {
     *         // We are sure that obj[key] belongs to the object and was not inherited.
     *       }
     *     }
                     *
                     * For more in-depth understanding of `for in` loops in JavaScript, read
                     * [Exploring JavaScript for-in
                     * loops](http://javascriptweblog.wordpress.com/2011/01/04/exploring-javascript-for-in-loops/)
                     * by Angus Croll.
                     */
                    forin: true,

                    /**
                     * This option suppresses warnings about declaring variables inside of
                     * control
                     * structures while accessing them later from the outside. Even though
                     * JavaScript has only two real scopes—global and function—such practice
                     * leads to confusion among people new to the language and hard-to-debug
                     * bugs. This is why, by default, JSHint warns about variables that are
                     * used outside of their intended scope.
                     *
                     *     function test() {
     *       if (true) {
     *         var x = 0;
     *       }
     *
     *       x += 1; // Default: 'x' used out of scope.
     *                 // No warning when funcscope:true
     *     }
                     */
                    funcscope: true,

                    /**
                     * This option prohibits the use of immediate function invocations without
                     * wrapping them in parentheses. Wrapping parentheses assists readers of
                     * your code in understanding that the expression is the result of a
                     * function, and not the function itself.
                     *
                     * @deprecated JSHint is limiting its scope to issues of code correctness.
                     *             If you would like to enforce rules relating to code style,
                     *             check out [the JSCS
                     *             project](https://github.com/jscs-dev/node-jscs).
                     */
                    immed: true,

                    /**
                     * This option suppresses warnings about the `__iterator__` property. This
                     * property is not supported by all browsers so use it carefully.
                     */
                    iterator: true,

                    /**
                     * This option requires you to capitalize names of constructor functions.
                     * Capitalizing functions that are intended to be used with `new` operator
                     * is just a convention that helps programmers to visually distinguish
                     * constructor functions from other types of functions to help spot
                     * mistakes when using `this`.
                     *
                     * Not doing so won't break your code in any browsers or environments but
                     * it will be a bit harder to figure out—by reading the code—if the
                     * function was supposed to be used with or without new. And this is
                     * important because when the function that was intended to be used with
                     * `new` is used without it, `this` will point to the global object instead
                     * of a new object.
                     *
                     * @deprecated JSHint is limiting its scope to issues of code correctness.
                     *             If you would like to enforce rules relating to code style,
                     *             check out [the JSCS
                     *             project](https://github.com/jscs-dev/node-jscs).
                     */
                    newcap: true,

                    /**
                     * This option prohibits the use of `arguments.caller` and
                     * `arguments.callee`.  Both `.caller` and `.callee` make quite a few
                     * optimizations impossible so they were deprecated in future versions of
                     * JavaScript. In fact, ECMAScript 5 forbids the use of `arguments.callee`
                     * in strict mode.
                     */
                    noarg: true,

                    /**
                     * This option prohibits the use of the comma operator. When misused, the
                     * comma operator can obscure the value of a statement and promote
                     * incorrect code.
                     */
                    nocomma: true,

                    /**
                     * This option warns when you have an empty block in your code. JSLint was
                     * originally warning for all empty blocks and we simply made it optional.
                     * There were no studies reporting that empty blocks in JavaScript break
                     * your code in any way.
                     *
                     * @deprecated JSHint is limiting its scope to issues of code correctness.
                     *             If you would like to enforce rules relating to code style,
                     *             check out [the JSCS
                     *             project](https://github.com/jscs-dev/node-jscs).
                     */
                    noempty: true,

                    /**
                     * This option warns about "non-breaking whitespace" characters. These
                     * characters can be entered with option-space on Mac computers and have a
                     * potential of breaking non-UTF8 web pages.
                     */
                    nonbsp: true,

                    /**
                     * This option prohibits the use of constructor functions for side-effects.
                     * Some people like to call constructor functions without assigning its
                     * result to any variable:
                     *
                     *     new MyConstructor();
                     *
                     * There is no advantage in this approach over simply calling
                     * `MyConstructor` since the object that the operator `new` creates isn't
                     * used anywhere so you should generally avoid constructors like this one.
                     */
                    nonew: true,

                    /**
                     * This option prohibits the use of explicitly undeclared variables. This
                     * option is very useful for spotting leaking and mistyped variables.
                     *
                     *     // jshint undef:true
                     *
                     *     function test() {
     *       var myVar = 'Hello, World';
     *       console.log(myvar); // Oops, typoed here. JSHint with undef will complain
     *     }
                     *
                     * If your variable is defined in another file, you can use the `global`
                     * directive to tell JSHint about it.
                     */
                    undef: true,

                    /**
                     * This option prohibits the use of the grouping operator when it is not
                     * strictly required. Such usage commonly reflects a misunderstanding of
                     * unary operators, for example:
                     *
                     *     // jshint singleGroups: true
                     *
                     *     delete(obj.attr); // Warning: Unnecessary grouping operator.
                     */
                    singleGroups: false,

                    /**
                     * When set to true, the use of VariableStatements are forbidden.
                     * For example:
                     *
                     *     // jshint varstmt: true
                     *
                     *     var a; // Warning: `var` declarations are forbidden. Use `let` or `const` instead.
                     */
                    varstmt: false,

                    /**
                     * This option is a short hand for the most strict JSHint configuration as
                     * available in JSHint version 2.6.3. It enables all enforcing options and
                     * disables all relaxing options that were defined in that release.
                     *
                     * @deprecated The option cannot be maintained without automatically opting
                     *             users in to new features. This can lead to unexpected
                     *             warnings/errors in when upgrading between minor versions of
                     *             JSHint.
                     */
                    enforceall: false
                },
                relaxing: {

                    /**
                     * This option suppresses warnings about missing semicolons. There is a lot
                     * of FUD about semicolon spread by quite a few people in the community.
                     * The common myths are that semicolons are required all the time (they are
                     * not) and that they are unreliable. JavaScript has rules about semicolons
                     * which are followed by *all* browsers so it is up to you to decide
                     * whether you should or should not use semicolons in your code.
                     *
                     * For more information about semicolons in JavaScript read [An Open Letter
                     * to JavaScript Leaders Regarding
                     * Semicolons](http://blog.izs.me/post/2353458699/an-open-letter-to-javascript-leaders-regarding)
                     * by Isaac Schlueter and [JavaScript Semicolon
                     * Insertion](http://inimino.org/~inimino/blog/javascript_semicolons).
                     */
                    asi: true,

                    /**
                     * This option suppresses warnings about multi-line strings. Multi-line
                     * strings can be dangerous in JavaScript because all hell breaks loose if
                     * you accidentally put a whitespace in between the escape character (`\`)
                     * and a new line.
                     *
                     * Note that even though this option allows correct multi-line strings, it
                     * still warns about multi-line strings without escape characters or with
                     * anything in between the escape character and a whitespace.
                     *
                     *     // jshint multistr:true
                     *
                     *     var text = "Hello\
                     *     World"; // All good.
                     *
                     *     text = "Hello
                     *     World"; // Warning, no escape character.
                     *
                     *     text = "Hello\
                     *     World"; // Warning, there is a space after \
                     *
                     * @deprecated JSHint is limiting its scope to issues of code correctness.
                     *             If you would like to enforce rules relating to code style,
                     *             check out [the JSCS
                     *             project](https://github.com/jscs-dev/node-jscs).
                     */
                    multistr: true,

                    /**
                     * This option suppresses warnings about the `debugger` statements in your
                     * code.
                     */
                    debug: true,

                    /**
                     * This option suppresses warnings about the use of assignments in cases
                     * where comparisons are expected. More often than not, code like `if (a =
                     * 10) {}` is a typo. However, it can be useful in cases like this one:
                     *
                     *     for (var i = 0, person; person = people[i]; i++) {}
                     *
                     * You can silence this error on a per-use basis by surrounding the assignment
                     * with parenthesis, such as:
                     *
                     *     for (var i = 0, person; (person = people[i]); i++) {}
                     */
                    boss: true,

                    /**
                     * This option suppresses warnings about the use of `eval`. The use of
                     * `eval` is discouraged because it can make your code vulnerable to
                     * various injection attacks and it makes it hard for JavaScript
                     * interpreter to do certain optimizations.
                     */
                    evil: true,

                    /**
                     * This option suppresses warnings about the use of global strict mode.
                     * Global strict mode can break third-party widgets so it is not
                     * recommended.
                     *
                     * For more info about strict mode see the `strict` option.
                     *
                     * @deprecated Use `strict: "global"`.
                     */
                    globalstrict: true,

                    /**
                     * This option prohibits the use of unary increment and decrement
                     * operators.  Some people think that `++` and `--` reduces the quality of
                     * their coding styles and there are programming languages—such as
                     * Python—that go completely without these operators.
                     */
                    plusplus: true,

                    /**
                     * This option suppresses warnings about the `__proto__` property.
                     */
                    proto: true,

                    /**
                     * This option suppresses warnings about the use of script-targeted
                     * URLs—such as `javascript:...`.
                     */
                    scripturl: true,

                    /**
                     * This option suppresses warnings about using `[]` notation when it can be
                     * expressed in dot notation: `person['name']` vs. `person.name`.
                     *
                     * @deprecated JSHint is limiting its scope to issues of code correctness.
                     *             If you would like to enforce rules relating to code style,
                     *             check out [the JSCS
                     *             project](https://github.com/jscs-dev/node-jscs).
                     */
                    sub: true,

                    /**
                     * This option suppresses warnings about "weird" constructions like
                     * `new function () { ... }` and `new Object;`. Such constructions are
                     * sometimes used to produce singletons in JavaScript:
                     *
                     *     var singleton = new function() {
     *       var privateVar;
     *
     *       this.publicMethod  = function () {}
     *       this.publicMethod2 = function () {}
     *     };
                     */
                    supernew: true,

                    /**
                     * This option suppresses most of the warnings about possibly unsafe line
                     * breakings in your code. It doesn't suppress warnings about comma-first
                     * coding style. To suppress those you have to use `laxcomma` (see below).
                     *
                     * @deprecated JSHint is limiting its scope to issues of code correctness.
                     *             If you would like to enforce rules relating to code style,
                     *             check out [the JSCS
                     *             project](https://github.com/jscs-dev/node-jscs).
                     */
                    laxbreak: true,

                    /**
                     * This option suppresses warnings about comma-first coding style:
                     *
                     *     var obj = {
     *         name: 'Anton'
     *       , handle: 'valueof'
     *       , role: 'SW Engineer'
     *     };
                     *
                     * @deprecated JSHint is limiting its scope to issues of code correctness.
                     *             If you would like to enforce rules relating to code style,
                     *             check out [the JSCS
                     *             project](https://github.com/jscs-dev/node-jscs).
                     */
                    laxcomma: true,

                    /**
                     * This option suppresses warnings about possible strict violations when
                     * the code is running in strict mode and you use `this` in a
                     * non-constructor function. You should use this option—in a function scope
                     * only—when you are positive that your use of `this` is valid in the
                     * strict mode (for example, if you call your function using
                     * `Function.call`).
                     *
                     * **Note:** This option can be used only inside of a function scope.
                     * JSHint will fail with an error if you will try to set this option
                     * globally.
                     */
                    validthis: true,

                    /**
                     * This option suppresses warnings about the use of the `with` statement.
                     * The semantics of the `with` statement can cause confusion among
                     * developers and accidental definition of global variables.
                     *
                     * More info:
                     *
                     * * [with Statement Considered
                     *   Harmful](http://yuiblog.com/blog/2006/04/11/with-statement-considered-harmful/)
                     */
                    withstmt: true,

                    /**
                     * This options tells JSHint that your code uses Mozilla JavaScript
                     * extensions. Unless you develop specifically for the Firefox web browser
                     * you don't need this option.
                     *
                     * More info:
                     *
                     * * [New in JavaScript
                     *   1.7](https://developer.mozilla.org/en-US/docs/JavaScript/New_in_JavaScript/1.7)
                     */
                    moz: true,

                    /**
                     * This option suppresses warnings about generator functions with no
                     * `yield` statement in them.
                     */
                    noyield: true,

                    /**
                     * This option suppresses warnings about `== null` comparisons. Such
                     * comparisons are often useful when you want to check if a variable is
                     * `null` or `undefined`.
                     */
                    eqnull: true,

                    /**
                     * This option suppresses warnings about missing semicolons, but only when
                     * the semicolon is omitted for the last statement in a one-line block:
                     *
                     *     var name = (function() { return 'Anton' }());
                     *
                     * This is a very niche use case that is useful only when you use automatic
                     * JavaScript code generators.
                     */
                    lastsemic: true,

                    /**
                     * This option suppresses warnings about functions inside of loops.
                     * Defining functions inside of loops can lead to bugs such as this one:
                     *
                     *     var nums = [];
                     *
                     *     for (var i = 0; i < 10; i++) {
     *       nums[i] = function (j) {
     *         return i + j;
     *       };
     *     }
                     *
                     *     nums[0](2); // Prints 12 instead of 2
                     *
                     * To fix the code above you need to copy the value of `i`:
                     *
                     *     var nums = [];
                     *
                     *     for (var i = 0; i < 10; i++) {
     *       (function (i) {
     *         nums[i] = function (j) {
     *             return i + j;
     *         };
     *       }(i));
     *     }
                     */
                    loopfunc: true,

                    /**
                     * This option suppresses warnings about the use of expressions where
                     * normally you would expect to see assignments or function calls. Most of
                     * the time, such code is a typo. However, it is not forbidden by the spec
                     * and that's why this warning is optional.
                     */
                    expr: true,

                    /**
                     * This option tells JSHint that your code uses ECMAScript 6 specific
                     * syntax. Note that these features are not finalized yet and not all
                     * browsers implement them.
                     *
                     * More info:
                     *
                     * * [Specification for ECMAScript
                     *   6](http://www.ecma-international.org/ecma-262/6.0/index.html)
                     *
                     * @deprecated Use `esversion: 6` instead.
                     */
                    esnext: true,

                    /**
                     * This option tells JSHint that your code uses ES3 array elision elements,
                     * or empty elements (for example, `[1, , , 4, , , 7]`).
                     */
                    elision: true,
                },

                // Third party globals
                environments: {

                    /**
                     * This option defines globals exposed by the
                     * [MooTools](http://mootools.net/) JavaScript framework.
                     */
                    mootools: true,

                    /**
                     * This option defines globals exposed by
                     * [CouchDB](http://couchdb.apache.org/). CouchDB is a document-oriented
                     * database that can be queried and indexed in a MapReduce fashion using
                     * JavaScript.
                     */
                    couch: true,

                    /**
                     * This option defines globals exposed by [the Jasmine unit testing
                     * framework](https://jasmine.github.io/).
                     */
                    jasmine: true,

                    /**
                     * This option defines globals exposed by the [jQuery](http://jquery.com/)
                     * JavaScript library.
                     */
                    jquery: true,

                    /**
                     * This option defines globals available when your code is running inside
                     * of the Node runtime environment. [Node.js](http://nodejs.org/) is a
                     * server-side JavaScript environment that uses an asynchronous
                     * event-driven model. This option also skips some warnings that make sense
                     * in the browser environments but don't make sense in Node such as
                     * file-level `use strict` pragmas and `console.log` statements.
                     */
                    node: true,

                    /**
                     * This option defines globals exposed by [the QUnit unit testing
                     * framework](http://qunitjs.com/).
                     */
                    qunit: true,

                    /**
                     * This option defines globals available when your code is running inside
                     * of the Rhino runtime environment. [Rhino](http://www.mozilla.org/rhino/)
                     * is an open-source implementation of JavaScript written entirely in Java.
                     */
                    rhino: true,

                    /**
                     * This option defines globals exposed by [the ShellJS
                     * library](http://documentup.com/arturadib/shelljs).
                     */
                    shelljs: true,

                    /**
                     * This option defines globals exposed by the
                     * [Prototype](http://www.prototypejs.org/) JavaScript framework.
                     */
                    prototypejs: true,

                    /**
                     * This option defines globals exposed by the [YUI](http://yuilibrary.com/)
                     * JavaScript framework.
                     */
                    yui: true,

                    /**
                     * This option defines globals exposed by the "BDD" and "TDD" UIs of the
                     * [Mocha unit testing framework](http://mochajs.org/).
                     */
                    mocha: true,

                    /**
                     * This option informs JSHint that the input code describes an ECMAScript 6
                     * module. All module code is interpreted as strict mode code.
                     */
                    module: true,

                    /**
                     * This option defines globals available when your code is running as a
                     * script for the [Windows Script
                     * Host](http://en.wikipedia.org/wiki/Windows_Script_Host).
                     */
                    wsh: true,

                    /**
                     * This option defines globals available when your code is running inside
                     * of a Web Worker. [Web
                     * Workers](https://developer.mozilla.org/en/Using_web_workers) provide a
                     * simple means for web content to run scripts in background threads.
                     */
                    worker: true,

                    /**
                     * This option defines non-standard but widely adopted globals such as
                     * `escape` and `unescape`.
                     */
                    nonstandard: true,

                    /**
                     * This option defines globals exposed by modern browsers: all the way from
                     * good old `document` and `navigator` to the HTML5 `FileReader` and other
                     * new developments in the browser world.
                     *
                     * **Note:** This option doesn't expose variables like `alert` or
                     * `console`. See option `devel` for more information.
                     */
                    browser: true,

                    /**
                     * This option defines globals available when using [the Browserify
                     * tool](http://browserify.org/) to build a project.
                     */
                    browserify: true,

                    /**
                     * This option defines globals that are usually used for logging poor-man's
                     * debugging: `console`, `alert`, etc. It is usually a good idea to not
                     * ship them in production because, for example, `console.log` breaks in
                     * legacy versions of Internet Explorer.
                     */
                    devel: true,

                    /**
                     * This option defines globals exposed by the [Dojo
                     * Toolkit](http://dojotoolkit.org/).
                     */
                    dojo: true,

                    /**
                     * This option defines globals for typed array constructors.
                     *
                     * More info:
                     *
                     * * [JavaScript typed
                     *   arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays)
                     */
                    typed: true,

                    /**
                     * This option defines globals available when your core is running inside
                     * of the PhantomJS runtime environment. [PhantomJS](http://phantomjs.org/)
                     * is a headless WebKit scriptable with a JavaScript API. It has fast and
                     * native support for various web standards: DOM handling, CSS selector,
                     * JSON, Canvas, and SVG.
                     */
                    phantom: true
                },

                // Obsolete options
                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
                                     // should be tolerated
                }
            };

// These are the JSHint options that can take any value
// (we use this object to detect invalid options)
            exports.val = {

                /**
                 * This option lets you set the maximum length of a line.
                 *
                 * @deprecated JSHint is limiting its scope to issues of code correctness. If
                 *             you would like to enforce rules relating to code style, check
                 *             out [the JSCS project](https://github.com/jscs-dev/node-jscs).
                 */
                maxlen: false,

                /**
                 * This option sets a specific tab width for your code.
                 *
                 * @deprecated JSHint is limiting its scope to issues of code correctness. If
                 *             you would like to enforce rules relating to code style, check
                 *             out [the JSCS project](https://github.com/jscs-dev/node-jscs).
                 */
                indent: false,

                /**
                 * This options allows you to set the maximum amount of warnings JSHint will
                 * produce before giving up. Default is 50.
                 */
                maxerr: false,

                /**
                 * This option allows you to control which variables JSHint considers to be
                 * implicitly defined in the environment. Configure it with an array of
                 * string values. Prefixing a variable name with a hyphen (-) character will
                 * remove that name from the collection of predefined variables.
                 *
                 * JSHint will consider variables declared in this way to be read-only.
                 *
                 * This option cannot be specified in-line; it may only be used via the
                 * JavaScript API or from an external configuration file.
                 */
                predef: false,

                /**
                 * This option can be used to specify a white list of global variables that
                 * are not formally defined in the source code. This is most useful when
                 * combined with the `undef` option in order to suppress warnings for
                 * project-specific global variables.
                 *
                 * Setting an entry to `true` enables reading and writing to that variable.
                 * Setting it to `false` will trigger JSHint to consider that variable
                 * read-only.
                 *
                 * See also the "environment" options: a set of options to be used as short
                 * hand for enabling global variables defined in common JavaScript
                 * environments.
                 *
                 * To configure `globals` within an individual file, see [Inline
                 * Configuration](http://jshint.com/docs/#inline-configuration).
                 */
                globals: false,

                /**
                 * This option enforces the consistency of quotation marks used throughout
                 * your code. It accepts three values: `true` if you don't want to enforce
                 * one particular style but want some consistency, `"single"` if you want to
                 * allow only single quotes and `"double"` if you want to allow only double
                 * quotes.
                 *
                 * @deprecated JSHint is limiting its scope to issues of code correctness. If
                 *             you would like to enforce rules relating to code style, check
                 *             out [the JSCS project](https://github.com/jscs-dev/node-jscs).
                 */
                quotmark: false,

                scope: false,

                /**
                 * This option lets you set the max number of statements allowed per function:
                 *
                 *     // jshint maxstatements:4
                 *
                 *     function main() {
   *       var i = 0;
   *       var j = 0;
   *
   *       // Function declarations count as one statement. Their bodies
   *       // don't get taken into account for the outer function.
   *       function inner() {
   *         var i2 = 1;
   *         var j2 = 1;
   *
   *         return i2 + j2;
   *       }
   *
   *       j = i + j;
   *       return j; // JSHint: Too many statements per function. (5)
   *     }
                 */
                maxstatements: false,

                /**
                 * This option lets you control how nested do you want your blocks to be:
                 *
                 *     // jshint maxdepth:2
                 *
                 *     function main(meaning) {
   *       var day = true;
   *
   *       if (meaning === 42) {
   *         while (day) {
   *           shuffle();
   *
   *           if (tired) { // JSHint: Blocks are nested too deeply (3).
   *               sleep();
   *           }
   *         }
   *       }
   *     }
                 */
                maxdepth: false,

                /**
                 * This option lets you set the max number of formal parameters allowed per
                 * function:
                 *
                 *     // jshint maxparams:3
                 *
                 *     function login(request, onSuccess) {
   *       // ...
   *     }
                 *
                 *     // JSHint: Too many parameters per function (4).
                 *     function logout(request, isManual, whereAmI, onSuccess) {
   *       // ...
   *     }
                 */
                maxparams: false,

                /**
                 * This option lets you control cyclomatic complexity throughout your code.
                 * Cyclomatic complexity measures the number of linearly independent paths
                 * through a program's source code. Read more about [cyclomatic complexity on
                 * Wikipedia](http://en.wikipedia.org/wiki/Cyclomatic_complexity).
                 */
                maxcomplexity: false,

                /**
                 * This option suppresses warnings about variable shadowing i.e. declaring a
                 * variable that had been already declared somewhere in the outer scope.
                 *
                 * - "inner"  - check for variables defined in the same scope only
                 * - "outer"  - check for variables defined in outer scopes as well
                 * - false    - same as inner
                 * - true     - allow variable shadowing
                 */
                shadow: false,

                /**
                 * This option requires the code to run in ECMAScript 5's strict mode.
                 * [Strict mode](https://developer.mozilla.org/en/JavaScript/Strict_mode)
                 * is a way to opt in to a restricted variant of JavaScript. Strict mode
                 * eliminates some JavaScript pitfalls that didn't cause errors by changing
                 * them to produce errors.  It also fixes mistakes that made it difficult
                 * for the JavaScript engines to perform certain optimizations.
                 *
                 * - "func"    - there must be a `"use strict";` directive at function level
                 * - "global"  - there must be a `"use strict";` directive at global level
                 * - "implied" - lint the code as if there is the `"use strict";` directive
                 * - false     - disable warnings about strict mode
                 * - true      - same as `"func"`, but environment options have precedence over
                 *               this (e.g. `node`, `module`, `browserify` and `phantomjs` can
                 *               set `strict: global`)
                 */
                strict: true,

                /**
                 * This option warns when you define and never use your variables. It is very
                 * useful for general code cleanup, especially when used in addition to
                 * `undef`.
                 *
                 *     // jshint unused:true
                 *
                 *     function test(a, b) {
   *       var c, d = 2;
   *
   *       return a + d;
   *     }
                 *
                 *     test(1, 2);
                 *
                 *     // Line 3: 'b' was defined but never used.
                 *     // Line 4: 'c' was defined but never used.
                 *
                 * In addition to that, this option will warn you about unused global
                 * variables declared via the `global` directive.
                 *
                 * This can be set to `vars` to only check for variables, not function
                 * parameters, or `strict` to check all variables and parameters.  The
                 * default (true) behavior is to allow unused parameters that are followed by
                 * a used parameter.
                 */
                unused: true,

                /**
                 * This option prohibits the use of a variable before it was defined.
                 * JavaScript has function scope only and, in addition to that, all variables
                 * are always moved—or hoisted— to the top of the function. This behavior can
                 * lead to some very nasty bugs and that's why it is safer to always use
                 * variable only after they have been explicitly defined.
                 *
                 * Setting this option to "nofunc" will allow function declarations to be
                 * ignored.
                 *
                 * For more in-depth understanding of scoping and hoisting in JavaScript,
                 * read [JavaScript Scoping and
                 * Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting)
                 * by Ben Cherry.
                 */
                latedef: false,

                ignore: false, // start/end ignoring lines of code, bypassing the lexer
                               //   start    - start ignoring lines, including the current line
                               //   end      - stop ignoring lines, starting on the next line
                               //   line     - ignore warnings / errors for just a single line
                               //              (this option does not bypass the lexer)

                ignoreDelimiters: false, // array of start/end delimiters used to ignore
                                         // certain chunks from code

                /**
                 * This option is used to specify the ECMAScript version to which the code
                 * must adhere. It can assume one of the following values:
                 *  - `3` - If you need your program to be executable
                 *    in older browsers—such as Internet Explorer 6/7/8/9—and other legacy
                 *    JavaScript environments
                 *  - `5` - To enable syntax first defined in [the ECMAScript 5.1
                 *    specification](http://www.ecma-international.org/ecma-262/5.1/index.html).
                 *    This includes allowing reserved keywords as object properties.
                 *  - `6` - To tell JSHint that your code uses [ECMAScript
                 *    6](http://www.ecma-international.org/ecma-262/6.0/index.html) specific
                 *    syntax. Note that not all browsers implement them.
                 */
                esversion: 5
            };

// These are JSHint boolean options which are shared with JSLint
// where the definition in JSHint is opposite JSLint
            exports.inverted = {
                bitwise: true,
                forin: true,
                newcap: true,
                plusplus: true,
                regexp: true,
                undef: true,

                // Inverted and renamed, use JSHint name here
                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));

// These are JSHint boolean options which are shared with JSLint
// where the name has been changed but the effect is unchanged
            exports.renamed = {
                eqeq: "eqeqeq",
                windows: "wsh",
                sloppy: "strict"
            };

            exports.removed = {
                nomen: true,
                onevar: true,
                passfail: true,
                white: true,
                gcl: true,
                smarttabs: true,
                trailing: true
            };

// Add options here which should not be automatically enforced by
// `enforceall`.
            exports.noenforceall = {
                varstmt: true,
                strict: true
            };

        }, {}],
        "/node_modules/jshint/src/reg.js": [function (_dereq_, module, exports) {
            /*
             * Regular expressions. Some of these are stupidly long.
             */

            /*jshint maxlen:1000 */

            "use strict";

// Unsafe comment or string (ax)
            exports.unsafeString =
                /@cc|<\/?|script|\]\s*\]|<\s*!|&lt/i;

// Unsafe characters that are silently deleted by one or more browsers (cx)
            exports.unsafeChars =
                /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;

// Characters in strings that need escaping (nx and nxg)
            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;

// Star slash (lx)
            exports.starSlash = /\*\//;

// Identifier (ix)
            exports.identifier = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/;

// JavaScript URL (jx)
            exports.javascriptURL = /^(?:javascript|jscript|ecmascript|vbscript|livescript)\s*:/i;

// Catches /* falls through */ comments (ft)
            exports.fallsThrough = /^\s*falls?\sthrough\s*$/;

// very conservative rule (eg: only one space between the start of the comment and the first character)
// to relax the maxlen option
            exports.maxlenException = /^(?:(?:\/\/|\/\*|\*) ?)?[^ ]+$/;

        }, {}],
        "/node_modules/jshint/src/scope-manager.js": [function (_dereq_, module, exports) {
            "use strict";

            var _ = _dereq_("../lodash");
            var events = _dereq_("events");

// Used to denote membership in lookup tables (a primitive value such as `true`
// would be silently rejected for the property name "__proto__" in some
// environments)
            var marker = {};

            /**
             * Creates a scope manager that handles variables and labels, storing usages
             * and resolving when variables are used and undefined
             */
            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);
                        }
                    }

                    // inconsistent - see gh-1894
                    if (unused_opt || type === "var") {
                        unuseds.push({
                            name: name,
                            line: line,
                            character: chr
                        });
                    }
                };

                /**
                 * Checks the current scope for unused identifiers
                 */
                function _checkForUnused() {
                    // function params are handled specially
                    // assume that parameters are the only thing declared in the param scope
                    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");
                            }
                        }
                    }
                }

                /**
                 * Checks the current scope for unused parameters
                 * Must be called in a function parameter scope
                 */
                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)"]);

                        // 'undefined' is a special case for (function(window, undefined) { ... })();
                        // patterns.
                        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();
                    }
                }

                /**
                 * Finds the relevant label's scope, searching from nearest outwards
                 * @returns {Object} the scope the label was found in
                 */
                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) {
                    // used so far in this whole function and any sub functions
                    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) {

                    // only check if shadow is outer
                    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 either latedef is strict and this is a function
                        //    or this is not a function
                        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);
                    },

                    /**
                     * Tell the manager we are entering a new block of code
                     * @param {string} [type] - The type of the block. Valid values are
                     *                          "functionparams", "catchparams" and
                     *                          "functionouter"
                     */
                    stack: function (type) {
                        var previousScope = _current;
                        _newScope(type);

                        if (!type && previousScope["(type)"] === "functionparams") {

                            _current["(isFuncBody)"] = true;
                            _current["(context)"] = _currentFunctBody;
                            _currentFunctBody = _current;
                        }
                    },

                    unstack: function () {
                        // jshint proto: true
                        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++) {
                                            // Keep the consistency of https://github.com/jshint/jshint/issues/2409
                                            if (usedLabel["(function)"] === usedTokens[j]["(function)"]) {
                                                error("W038", usedTokens[j], usedLabelName);
                                            }
                                        }
                                    }
                                }

                                // mark the label used
                                _current["(labels)"][usedLabelName]["(unused)"] = false;

                                // check for modifying a const
                                if (usedLabelType === "const" && usage["(modified)"]) {
                                    for (j = 0; j < usage["(modified)"].length; j++) {
                                        error("E013", usage["(modified)"][j], usedLabelName);
                                    }
                                }

                                // check for re-assigning a function declaration
                                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) {
                                // not exiting the global scope, so copy the usage down in case its an out of scope usage
                                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 {
                                // this is exiting global scope, so we finalise everything here - we are at the end of the file
                                if (typeof _current["(predefined)"][usedLabelName] === "boolean") {

                                    // remove the declared token, so we know it is used
                                    delete declared[usedLabelName];

                                    // note it as used so it can be reported
                                    usedPredefinedAndGlobals[usedLabelName] = marker;

                                    // check for re-assigning a read-only (set to false) predefined
                                    if (_current["(predefined)"][usedLabelName] === false && usage["(reassigned)"]) {
                                        for (j = 0; j < usage["(reassigned)"].length; j++) {
                                            warning("W020", usage["(reassigned)"][j]);
                                        }
                                    }
                                }
                                else {
                                    // label usage is not predefined and we have not found a declaration
                                    // so report as undeclared
                                    if (usage["(tokens)"]) {
                                        for (j = 0; j < usage["(tokens)"].length; j++) {
                                            var undefinedToken = usage["(tokens)"][j];
                                            // if its not a forgiven undefined (e.g. typof x)
                                            if (!undefinedToken.forgiveUndef) {
                                                // if undef is on and undef was on when the token was defined
                                                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 exiting the global scope, we can warn about declared globals that haven't been used yet
                        if (!subScope) {
                            Object.keys(declared)
                                .forEach(function (labelNotUsed) {
                                    _warnUnused(labelNotUsed, declared[labelNotUsed], "var");
                                });
                        }

                        // if we have a sub scope we can copy too and we are still within the function boundary
                        if (subScope && !isUnstackingFunctionBody &&
                            !isUnstackingFunctionParams && !isUnstackingFunctionOuter) {
                            var labelNames = Object.keys(currentLabels);
                            for (i = 0; i < labelNames.length; i++) {

                                var defLabelName = labelNames[i];

                                // if its function scoped and
                                // not already defined (caught with shadow, shouldn't also trigger out of scope)
                                if (!currentLabels[defLabelName]["(blockscoped)"] &&
                                    currentLabels[defLabelName]["(type)"] !== "exception" &&
                                    !this.funct.has(defLabelName, {excludeCurrent: true})) {
                                    subScope["(labels)"][defLabelName] = currentLabels[defLabelName];
                                    // we do not warn about out of scope usages in the global scope
                                    if (_currentFunctBody["(type)"] !== "global") {
                                        subScope["(labels)"][defLabelName]["(useOutsideOfScope)"] = true;
                                    }
                                    delete currentLabels[defLabelName];
                                }
                            }
                        }

                        _checkForUnused();

                        _scopeStack.pop();
                        if (isUnstackingFunctionBody) {
                            _currentFunctBody = _scopeStack[_.findLastIndex(_scopeStack, function (scope) {
                                // if function or if global (which is at the bottom so it will only return true if we call back)
                                return scope["(isFuncBody)"] || scope["(type)"] === "global";
                            })];
                        }

                        _current = subScope;
                    },

                    /**
                     * Add a param to the current scope
                     * @param {string} labelName
                     * @param {Token} token
                     * @param {string} [type="param"] param type
                     */
                    addParam: function (labelName, token, type) {
                        type = type || "param";

                        if (type === "exception") {
                            // if defined in the current function
                            var previouslyDefinedLabelType = this.funct.labeltype(labelName);
                            if (previouslyDefinedLabelType && previouslyDefinedLabelType !== "exception") {
                                // and has not been used yet in the current function scope
                                if (!state.option.node) {
                                    warning("W002", state.tokens.next, labelName);
                                }
                            }
                        }

                        // The variable was declared in the current scope
                        if (_.has(_current["(labels)"], labelName)) {
                            _current["(labels)"][labelName].duplicated = true;

                            // The variable was declared in an outer scope
                        } else {
                            // if this scope has the variable defined, it's a re-definition error
                            _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 its in a sub function it is not necessarily an error, just latedef
                            if (usage["(onlyUsedSubFunction)"]) {
                                _latedefWarning(type, labelName, token);
                            } else {
                                // this is a clear illegal usage for block scoped variables
                                warning("E056", token, labelName, type);
                            }
                        }
                    },

                    validateParams: function () {
                        // This method only concerns errors for function parameters
                        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 () {
                        // jshint proto: true
                        var list = Object.keys(usedPredefinedAndGlobals);

                        // If `__proto__` is used as a global variable name, its entry in the
                        // lookup table may not be enumerated by `Object.keys` (depending on the
                        // environment).
                        if (usedPredefinedAndGlobals.__proto__ === marker &&
                            list.indexOf("__proto__") === -1) {
                            list.push("__proto__");
                        }

                        return list;
                    },

                    /**
                     * Gets an array of implied globals
                     * @returns {Array.<{ name: string, line: Array.<number>}>}
                     */
                    getImpliedGlobals: function () {
                        // jshint proto: true
                        var values = _.values(impliedGlobals);
                        var hasProto = false;

                        // If `__proto__` is an implied global variable, its entry in the lookup
                        // table may not be enumerated by `_.values` (depending on the
                        // environment).
                        if (impliedGlobals.__proto__) {
                            hasProto = values.some(function (value) {
                                return value.name === "__proto__";
                            });

                            if (!hasProto) {
                                values.push(impliedGlobals.__proto__);
                            }
                        }

                        return values;
                    },

                    /**
                     * Returns a list of unused variables
                     * @returns {Array}
                     */
                    getUnuseds: function () {
                        return unuseds;
                    },

                    has: function (labelName) {
                        return Boolean(_getLabel(labelName));
                    },

                    labeltype: function (labelName) {
                        // returns a labels type or null if not present
                        var scopeLabels = _getLabel(labelName);
                        if (scopeLabels) {
                            return scopeLabels[labelName]["(type)"];
                        }
                        return null;
                    },

                    /**
                     * for the exported options, indicating a variable is used outside the file
                     */
                    addExported: function (labelName) {
                        var globalLabels = _scopeStack[0]["(labels)"];
                        if (_.has(declared, labelName)) {
                            // remove the declared token, so we know it is used
                            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)` is not defined, it is a block scope
                                if (!scope["(type)"]) {
                                    if (_.has(scope["(labels)"], labelName) &&
                                        !scope["(labels)"][labelName]["(blockscoped)"]) {
                                        scope["(labels)"][labelName]["(unused)"] = false;
                                        return;
                                    }
                                } else {
                                    break;
                                }
                            }
                            exported[labelName] = true;
                        }
                    },

                    /**
                     * Mark an indentifier as es6 module exported
                     */
                    setExported: function (labelName, token) {
                        this.block.use(labelName, token);
                    },

                    /**
                     * adds an indentifier to the relevant current scope and creates warnings/errors as necessary
                     * @param {string} labelName
                     * @param {Object} opts
                     * @param {String} opts.type - the type of the label e.g. "param", "var", "let, "const", "function"
                     * @param {Token} opts.token - the token pointing at the declaration
                     */
                    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);

                        // outer shadow check (inner is only on non-block scoped)
                        _checkOuterShadow(labelName, token, type);

                        // if is block scoped (let or const)
                        if (isblockscoped) {

                            var declaredInCurrentScope = _current["(labels)"][labelName];
                            // for block scoped variables, params are seen in the current scope as the root function
                            // scope, so check these too.
                            if (!declaredInCurrentScope && _current === _currentFunctBody &&
                                _current["(type)"] !== "global") {
                                declaredInCurrentScope = !!_currentFunctBody["(parent)"]["(labels)"][labelName];
                            }

                            // if its not already defined (which is an error, so ignore) and is used in TDZ
                            if (!declaredInCurrentScope && _current["(usages)"][labelName]) {
                                var usage = _current["(usages)"][labelName];
                                // if its in a sub function it is not necessarily an error, just latedef
                                if (usage["(onlyUsedSubFunction)"]) {
                                    _latedefWarning(type, labelName, token);
                                } else {
                                    // this is a clear illegal usage for block scoped variables
                                    warning("E056", token, labelName, type);
                                }
                            }

                            // if this scope has the variable defined, its a re-definition error
                            if (declaredInCurrentScope) {
                                warning("E011", token, labelName);
                            }
                            else if (state.option.shadow === "outer") {

                                // if shadow is outer, for block scope we want to detect any shadowing within this function
                                if (scopeManagerInst.funct.has(labelName)) {
                                    warning("W004", token, labelName);
                                }
                            }

                            scopeManagerInst.block.add(labelName, type, token, !isexported);

                        } else {

                            var declaredInCurrentFunctionScope = scopeManagerInst.funct.has(labelName);

                            // check for late definition, ignore if already declared
                            if (!declaredInCurrentFunctionScope && usedSoFarInCurrentFunction(labelName)) {
                                _latedefWarning(type, labelName, token);
                            }

                            // defining with a var or a function when a block scope variable of the same name
                            // is in scope is an error
                            if (scopeManagerInst.funct.has(labelName, {onlyBlockscoped: true})) {
                                warning("E011", token, labelName);
                            } else if (state.option.shadow !== true) {
                                // now since we didn't get any block scope variables, test for var/function
                                // shadowing
                                if (declaredInCurrentFunctionScope && labelName !== "__proto__") {

                                    // see https://github.com/jshint/jshint/issues/2400
                                    if (_currentFunctBody["(type)"] !== "global") {
                                        warning("W004", token, labelName);
                                    }
                                }
                            }

                            scopeManagerInst.funct.add(labelName, type, token, !isexported);

                            if (_currentFunctBody["(type)"] === "global") {
                                usedPredefinedAndGlobals[labelName] = marker;
                            }
                        }
                    },

                    funct: {
                        /**
                         * Returns the label type given certain options
                         * @param labelName
                         * @param {Object=} options
                         * @param {Boolean=} options.onlyBlockscoped - only include block scoped labels
                         * @param {Boolean=} options.excludeParams - exclude the param scope
                         * @param {Boolean=} options.excludeCurrent - exclude the current scope
                         * @returns {String}
                         */
                        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;
                        },
                        /**
                         * Returns if a break label exists in the function scope
                         * @param {string} labelName
                         * @returns {boolean}
                         */
                        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;
                        },
                        /**
                         * Returns if the label is in the current function scope
                         * See scopeManager.funct.labelType for options
                         */
                        has: function (labelName, options) {
                            return Boolean(this.labeltype(labelName, options));
                        },

                        /**
                         * Adds a new function scoped variable
                         * see block.add for block scoped
                         */
                        add: function (labelName, type, tok, unused) {
                            _current["(labels)"][labelName] = {
                                "(type)": type,
                                "(token)": tok,
                                "(blockscoped)": false,
                                "(function)": _currentFunctBody,
                                "(unused)": unused
                            };
                        }
                    },

                    block: {

                        /**
                         * is the current block global?
                         * @returns Boolean
                         */
                        isGlobal: function () {
                            return _current["(type)"] === "global";
                        },

                        use: function (labelName, token) {

                            // if resolves to current function params, then do not store usage just resolve
                            // this is because function(a) { var a; a = a; } will resolve to the param, not
                            // to the unset var
                            // first check the param is used
                            var paramScope = _currentFunctBody["(parent)"];
                            if (paramScope && paramScope["(labels)"][labelName] &&
                                paramScope["(labels)"][labelName]["(type)"] === "param") {

                                // then check its not declared by a block scope variable
                                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);
                        },

                        /**
                         * Adds a new variable
                         */
                        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: {},

                /**
                 * Determine if the code currently being linted is strict mode code.
                 *
                 * @returns {boolean}
                 */
                isStrict: function () {
                    return this.directive["use strict"] || this.inClassBody ||
                        this.option.module || this.option.strict === "implied";
                },

                // Assumption: chronologically ES3 < ES5 < ES6 < Moz

                inMoz: function () {
                    return this.option.moz;
                },

                /**
                 * @param {boolean} strict - When `true`, only consider ES6 when in
                 *                           "esversion: 6" code and *not* in "moz".
                 */
                inES6: function () {
                    return this.option.moz || this.option.esversion >= 6;
                },

                /**
                 * @param {boolean} strict - When `true`, return `true` only when
                 *                           esversion is exactly 5
                 */
                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) {
                // Check for properties named __proto__. This special property was
                // deprecated and then re-introduced for ES6.

                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"]
                        });
                    }
                });

                // Check for properties named __iterator__. This is a special property
                // available only in browsers with JavaScript 1.7 implementation, but
                // it is deprecated for ES6

                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]
                        });
                    }
                });

                // Check that all identifiers are using camelCase notation.
                // Exceptions: names like MY_VAR and _myVar.

                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]
                        });
                    }
                });

                // Enforce consistency in style of quoting.

                linter.on("String", function style_scanQuotes(data) {
                    var quotmark = linter.getOption("quotmark");
                    var code;

                    if (!quotmark) {
                        return;
                    }

                    // If quotmark is set to 'single' warn about all double-quotes.

                    if (quotmark === "single" && data.quote !== "'") {
                        code = "W109";
                    }

                    // If quotmark is set to 'double' warn about all single-quotes.

                    if (quotmark === "double" && data.quote !== "\"") {
                        code = "W108";
                    }

                    // If quotmark is set to true, remember the first quotation style
                    // and then warn about all others.

                    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) === ".") {
                        // Warn about a leading decimal point.
                        linter.warn("W008", {
                            line: data.line,
                            char: data.char,
                            data: [data.value]
                        });
                    }

                    if (data.value.substr(data.value.length - 1) === ".") {
                        // Warn about a trailing decimal point.
                        linter.warn("W047", {
                            line: data.line,
                            char: data.char,
                            data: [data.value]
                        });
                    }

                    if (/^00+/.test(data.value)) {
                        // Multiple leading zeroes.
                        linter.warn("W046", {
                            line: data.line,
                            char: data.char,
                            data: [data.value]
                        });
                    }
                });

                // Warn about script URLs.

                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) {
// jshint -W001

            "use strict";

// Identifiers provided by the ECMAScript standard.

            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
                }
            };

// Global variables commonly provided by a web browser environment.

            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
            };

// Widely adopted global names that are not part of ECMAScript standard
            exports.nonstandard = {
                escape: false,
                unescape: false
            };

// Globals provided by popular JavaScript environments.

            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,

                // These globals are writeable because Node allows the following
                // usage pattern: var Buffer = require("buffer").Buffer;

                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
            };

// Globals provided by popular JavaScript libraries.

            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 = {
                // Global (for config etc.)
                mocha: false,
                // BDD
                describe: false,
                xdescribe: false,
                it: false,
                xit: false,
                context: false,
                xcontext: false,
                before: false,
                after: false,
                beforeEach: false,
                afterEach: false,
                // TDD
                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,
                // Jasmine 1.3
                runs: false,
                waitsFor: false,
                waits: false,
                // Jasmine 2.1
                beforeAll: false,
                afterAll: false,
                fail: false,
                fdescribe: false,
                fit: false,
                pending: false
            };

        }, {}]
    }, {}, ["/node_modules/jshint/src/jshint.js"]);

});