le(name, config) {
    if (config != null) {
        var locale,
            tmpLocale,
            parentConfig = baseConfig;

        if (locales[name] != null && locales[name].parentLocale != null) {
            // Update existing child locale in-place to avoid memory-leaks
            locales[name].set(mergeConfigs(locales[name]._config, config));
        } else {
            // MERGE
            tmpLocale = loadLocale(name);
            if (tmpLocale != null) {
                parentConfig = tmpLocale._config;
            }
            config = mergeConfigs(parentConfig, config);
            if (tmpLocale == null) {
                // updateLocale is called for creating a new locale
                // Set abbr so it will have a name (getters return
                // undefined otherwise).
                config.abbr = name;
            }
            locale = new Locale(config);
            locale.parentLocale = locales[name];
            locales[name] = locale;
        }

        // backwards compat for now: also set the locale
        getSetGlobalLocale(name);
    } else {
        // pass null for config to unupdate, useful for tests
        if (locales[name] != null) {
            if (locales[name].parentLocale != null) {
                locales[name] = locales[name].parentLocale;
                if (name === getSetGlobalLocale()) {
                    getSetGlobalLocale(name);
                }
            } else if (locales[name] != null) {
                delete locales[name];
            }
        }
    }
    return locales[name];
}

// returns locale data
function getLocale(key) {
    var locale;

    if (key && key._locale && key._locale._abbr) {
        key = key._locale._abbr;
    }

    if (!key) {
        return globalLocale;
    }

    if (!isArray(key)) {
        //short-circuit everything else
        locale = loadLocale(key);
        if (locale) {
            return locale;
        }
        key = [key];
    }

    return chooseLocale(key);
}

function listLocales() {
    return keys(locales);
}

function checkOverflow(m) {
    var overflow,
        a = m._a;

    if (a && getParsingFlags(m).overflow === -2) {
        overflow =
            a[MONTH] < 0 || a[MONTH] > 11
                ? MONTH
                : a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH])
                  ? DATE
                  : a[HOUR] < 0 ||
                      a[HOUR] > 24 ||
                      (a[HOUR] === 24 &&
                          (a[MINUTE] !== 0 ||
                              a[SECOND] !== 0 ||
                              a[MILLISECOND] !== 0))
                    ? HOUR
                    : a[MINUTE] < 0 || a[MINUTE] > 59
                      ? MINUTE
                      : a[SECOND] < 0 || a[SECOND] > 59
                        ? SECOND
                        : a[MILLISECOND] < 0 || a[MILLISECOND] > 999
                          ? MILLISECOND
                          : -1;

        if (
            getParsingFlags(m)._overflowDayOfYear &&
            (overflow < YEAR || overflow > DATE)
        ) {
            overflow = DATE;
        }
        if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
            overflow = WEEK;
        }
        if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
            overflow = WEEKDAY;
        }

        getParsingFlags(m).overflow = overflow;
    }

    return m;
}

// iso 8601 regex
// 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
var extendedIsoRegex =
        /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,
    basicIsoRegex =
        /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,
    tzRegex = /Z|[+-]\d\d(?::?\d\d)?/,
    isoDates = [
        ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
        ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
        ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
        ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
        ['YYYY-DDD', /\d{4}-\d{3}/],
        ['YYYY-MM', /\d{4}-\d\d/, false],
        ['YYYYYYMMDD', /[+-]\d{10}/],
        ['YYYYMMDD', /\d{8}/],
        ['GGGG[W]WWE', /\d{4}W\d{3}/],
        ['GGGG[W]WW', /\d{4}W\d{2}/, false],
        ['YYYYDDD', /\d{7}/],
        ['YYYYMM', /\d{6}/, false],
        ['YYYY', /\d{4}/, false],
    ],
    // iso time formats and regexes
    isoTimes = [
        ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
        ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
        ['HH:mm:ss', /\d\d:\d\d:\d\d/],
        ['HH:mm', /\d\d:\d\d/],
        ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
        ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
        ['HHmmss', /\d\d\d\d\d\d/],
        ['HHmm', /\d\d\d\d/],
        ['HH', /\d\d/],
    ],
    aspNetJsonRegex = /^\/?Date\((-?\d+)/i,
    // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
    rfc2822 =
        /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/,
    obsOffsets = {
        UT: 0,
        GMT: 0,
        EDT: -4 * 60,
        EST: -5 * 60,
        CDT: -5 * 60,
        CST: -6 * 60,
        MDT: -6 * 60,
        MST: -7 * 60,
        PDT: -7 * 60,
        PST: -8 * 60,
    };

// date from iso format
function configFromISO(config) {
    var i,
        l,
        string = config._i,
        match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
        allowTime,
        dateFormat,
        timeFormat,
        tzFormat,
        isoDatesLen = isoDates.length,
        isoTimesLen = isoTimes.length;

    if (match) {
        getParsingFlags(config).iso = true;
        for (i = 0, l = isoDatesLen; i < l; i++) {
            if (isoDates[i][1].exec(match[1])) {
                dateFormat = isoDates[i][0];
                allowTime = isoDates[i][2] !== false;
                break;
            }
        }
        if (dateFormat == null) {
            config._isValid = false;
            return;
        }
        if (match[3]) {
            for (i = 0, l = isoTimesLen; i < l; i++) {
                if (isoTimes[i][1].exec(match[3])) {
                    // match[2] should be 'T' or space
                    timeFormat = (match[2] || ' ') + isoTimes[i][0];
                    break;
                }
            }
            if (timeFormat == null) {
                config._isValid = false;
                return;
            }
        }
        if (!allowTime && timeFormat != null) {
            config._isValid = false;
            return;
        }
        if (match[4]) {
            if (tzRegex.exec(match[4])) {
                tzFormat = 'Z';
            } else {
                config._isValid = false;
                return;
            }
        }
        config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
        configFromStringAndFormat(config);
    } else {
        config._isValid = false;
    }
}

function extractFromRFC2822Strings(
    yearStr,
    monthStr,
    dayStr,
    hourStr,
    minuteStr,
    secondStr
) {
    var result = [
        untruncateYear(yearStr),
        defaultLocaleMonthsShort.indexOf(monthStr),
        parseInt(dayStr, 10),
        parseInt(hourStr, 10),
        parseInt(minuteStr, 10),
    ];

    if (secondStr) {
        result.push(parseInt(secondStr, 10));
    }

    return result;
}

function untruncateYear(yearStr) {
    var year = parseInt(yearStr, 10);
    if (year <= 49) {
        return 2000 + year;
    } else if (year <= 999) {
        return 1900 + year;
    }
    return year;
}

function preprocessRFC2822(s) {
    // Remove comments and folding whitespace and replace multiple-spaces with a single space
    return s
        .replace(/\([^()]*\)|[\n\t]/g, ' ')
        .replace(/(\s\s+)/g, ' ')
        .replace(/^\s\s*/, '')
        .replace(/\s\s*$/, '');
}

function checkWeekday(weekdayStr, parsedInput, config) {
    if (weekdayStr) {
        // TODO: Replace the vanilla JS Date object with an independent day-of-week check.
        var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
            weekdayActual = new Date(
                parsedInput[0],
                parsedInput[1],
                parsedInput[2]
            ).getDay();
        if (weekdayProvided !== weekdayActual) {
            getParsingFlags(config).weekdayMismatch = true;
            config._isValid = false;
            return false;
        }
    }
    return true;
}

function calculateOffset(obsOffset, militaryOffset, numOffset) {
    if (obsOffset) {
        return obsOffsets[obsOffset];
    } else if (militaryOffset) {
        // the only allowed military tz is Z
        return 0;
    } else {
        var hm = parseInt(numOffset, 10),
            m = hm % 100,
            h = (hm - m) / 100;
        return h * 60 + m;
    }
}

// date and time from ref 2822 format
function configFromRFC2822(config) {
    var match = rfc2822.exec(preprocessRFC2822(config._i)),
        parsedArray;
    if (match) {
        parsedArray = extractFromRFC2822Strings(
            match[4],
            match[3],
            match[2],
            match[5],
            match[6],
            match[7]
        );
        if (!checkWeekday(match[1], parsedArray, config)) {
            return;
        }

        config._a = parsedArray;
        config._tzm = calculateOffset(match[8], match[9], match[10]);

        config._d = createUTCDate.apply(null, config._a);
        config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);

        getParsingFlags(config).rfc2822 = true;
    } else {
        config._isValid = false;
    }
}

// date from 1) ASP.NET, 2) ISO, 3) RFC 2822 formats, or 4) optional fallback if parsing isn't strict
function configFromString(config) {
    var matched = aspNetJsonRegex.exec(config._i);
    if (matched !== null) {
        config._d = new Date(+matched[1]);
        return;
    }

    configFromISO(config);
    if (config._isValid === false) {
        delete config._isValid;
    } else {
        return;
    }

    configFromRFC2822(config);
    if (config._isValid === false) {
        delete config._isValid;
    } else {
        return;
    }

    if (config._strict) {
        config._isValid = false;
    } else {
        // Final attempt, use Input Fallback
        hooks.createFromInputFallback(config);
    }
}

hooks.createFromInputFallback = deprecate(
    'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' +
        'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' +
        'discouraged. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.',
    function (config) {
        config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
    }
);

// Pick the first defined of two or three arguments.
function defaults(a, b, c) {
    if (a != null) {
        return a;
    }
    if (b != null) {
        return b;
    }
    return c;
}

function currentDateArray(config) {
    // hooks is actually the exported moment object
    var nowValue = new Date(hooks.now());
    if (config._useUTC) {
        return [
            nowValue.getUTCFullYear(),
            nowValue.getUTCMonth(),
            nowValue.getUTCDate(),
        ];
    }
    return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
}

// convert an array to a date.
// the array should mirror the parameters below
// note: all values past the year are optional and will default to the lowest possible value.
// [year, month, day , hour, minute, second, millisecond]
function configFromArray(config) {
    var i,
        date,
        input = [],
        currentDate,
        expectedWeekday,
        yearToUse;

    if (config._d) {
        return;
    }

    currentDate = currentDateArray(config);

    //compute day of the year from weeks and weekdays
    if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
        dayOfYearFromWeekInfo(config);
    }

    //if the day of the year is set, figure out what it is
    if (config._dayOfYear != null) {
        yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);

        if (
            config._dayOfYear > daysInYear(yearToUse) ||
            config._dayOfYear === 0
        ) {
            getParsingFlags(config)._overflowDayOfYear = true;
        }

        date = createUTCDate(yearToUse, 0, config._dayOfYear);
        config._a[MONTH] = date.getUTCMonth();
        config._a[DATE] = date.getUTCDate();
    }

    // Default to current date.
    // * if no year, month, day of month are given, default to today
    // * if day of month is given, default month and year
    // * if month is given, default only year
    // * if year is given, don't default anything
    for (i = 0; i < 3 && config._a[i] == null; ++i) {
        config._a[i] = input[i] = currentDate[i];
    }

    // Zero out whatever was not defaulted, including time
    for (; i < 7; i++) {
        config._a[i] = input[i] =
            config._a[i] == null ? (i === 2 ? 1 : 0) : config._a[i];
    }

    // Check for 24:00:00.000
    if (
        config._a[HOUR] === 24 &&
        config._a[MINUTE] === 0 &&
        config._a[SECOND] === 0 &&
        config._a[MILLISECOND] === 0
    ) {
        config._nextDay = true;
        config._a[HOUR] = 0;
    }

    config._d = (config._useUTC ? createUTCDate : createDate).apply(
        null,
        input
    );
    expectedWeekday = config._useUTC
        ? config._d.getUTCDay()
        : config._d.getDay();

    // Apply timezone offset from input. The actual utcOffset can be changed
    // with parseZone.
    if (config._tzm != null) {
        config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
    }

    if (config._nextDay) {
        config._a[HOUR] = 24;
    }

    // check for mismatching day of week
    if (
        config._w &&
        typeof config._w.d !== 'undefined' &&
        config._w.d !== expectedWeekday
    ) {
        getParsingFlags(config).weekdayMismatch = true;
    }
}

function dayOfYearFromWeekInfo(config) {
    var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow, curWeek;

    w = config._w;
    if (w.GG != null || w.W != null || w.E != null) {
        dow = 1;
        doy = 4;

        // TODO: We need to take the current isoWeekYear, but that depends on
        // how we interpret now (local, utc, fixed offset). So create
        // a now version of current config (take local/utc/offset flags, and
        // create now).
        weekYear = defaults(
            w.GG,
            config._a[YEAR],
            weekOfYear(createLocal(), 1, 4).year
        );
        week = defaults(w.W, 1);
        weekday = defaults(w.E, 1);
        if (weekday < 1 || weekday > 7) {
            weekdayOverflow = true;
        }
    } else {
        dow = config._locale._week.dow;
        doy = config._locale._week.doy;

        curWeek = weekOfYear(createLocal(), dow, doy);

        weekYear = defaults(w.gg, config._a[YEAR], curWeek.year);

        // Default to current week.
        week = defaults(w.w, curWeek.week);

        if (w.d != null) {
            // weekday -- low day numbers are considered next week
            weekday = w.d;
            if (weekday < 0 || weekday > 6) {
                weekdayOverflow = true;
            }
        } else if (w.e != null) {
            // local weekday -- counting starts from beginning of week
            weekday = w.e + dow;
            if (w.e < 0 || w.e > 6) {
                weekdayOverflow = true;
            }
        } else {
            // default to beginning of week
            weekday = dow;
        }
    }
    if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
        getParsingFlags(config)._overflowWeeks = true;
    } else if (weekdayOverflow != null) {
        getParsingFlags(config)._overflowWeekday = true;
    } else {
        temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
        config._a[YEAR] = temp.year;
        config._dayOfYear = temp.dayOfYear;
    }
}

// constant that refers to the ISO standard
hooks.ISO_8601 = function () {};

// constant that refers to the RFC 2822 form
hooks.RFC_2822 = function () {};

// date from string and format string
function configFromStringAndFormat(config) {
    // TODO: Move this to another part of the creation flow to prevent circular deps
    if (config._f === hooks.ISO_8601) {
        configFromISO(config);
        return;
    }
    if (config._f === hooks.RFC_2822) {
        configFromRFC2822(config);
        return;
    }
    config._a = [];
    getParsingFlags(config).empty = true;

    // This array is used to make a Date, either with `new Date` or `Date.UTC`
    var string = '' + config._i,
        i,
        parsedInput,
        tokens,
        token,
        skipped,
        stringLength = string.length,
        totalParsedInputLength = 0,
        era,
        tokenLen;

    tokens =
        expandFormat(config._f, config._locale).match(formattingTokens) || [];
    tokenLen = tokens.length;
    for (i = 0; i < tokenLen; i++) {
        token = tokens[i];
        parsedInput = (string.match(getParseRegexForToken(token, config)) ||
            [])[0];
        if (parsedInput) {
            skipped = string.substr(0, string.indexOf(parsedInput));
            if (skipped.length > 0) {
                getParsingFlags(config).unusedInput.push(skipped);
            }
            string = string.slice(
                string.indexOf(parsedInput) + parsedInput.length
            );
            totalParsedInputLength += parsedInput.length;
        }
        // don't parse if it's not a known token
        if (formatTokenFunctions[token]) {
            if (parsedInput) {
                getParsingFlags(config).empty = false;
            } else {
                getParsingFlags(config).unusedTokens.push(token);
            }
            addTimeToArrayFromToken(token, parsedInput, config);
        } else if (config._strict && !parsedInput) {
            getParsingFlags(config).unusedTokens.push(token);
        }
    }

    // add remaining unparsed input length to the string
    getParsingFlags(config).charsLeftOver =
        stringLength - totalParsedInputLength;
    if (string.length > 0) {
        getParsingFlags(config).unusedInput.push(string);
    }

    // clear _12h flag if hour is <= 12
    if (
        config._a[HOUR] <= 12 &&
        getParsingFlags(config).bigHour === true &&
        config._a[HOUR] > 0
    ) {
        getParsingFlags(config).bigHour = undefined;
    }

    getParsingFlags(config).parsedDateParts = config._a.slice(0);
    getParsingFlags(config).meridiem = config._meridiem;
    // handle meridiem
    config._a[HOUR] = meridiemFixWrap(
        config._locale,
        config._a[HOUR],
        config._meridiem
    );

    // handle era
    era = getParsingFlags(config).era;
    if (era !== null) {
        config._a[YEAR] = config._locale.erasConvertYear(era, config._a[YEAR]);
    }

    configFromArray(config);
    checkOverflow(config);
}

function meridiemFixWrap(locale, hour, meridiem) {
    var isPm;

    if (meridiem == null) {
        // nothing to do
        return hour;
    }
    if (locale.meridiemHour != null) {
        return locale.meridiemHour(hour, meridiem);
    } else if (locale.isPM != null) {
        // Fallback
        isPm = locale.isPM(meridiem);
        if (isPm && hour < 12) {
            hour += 12;
        }
        if (!isPm && hour === 12) {
            hour = 0;
        }
        return hour;
    } else {
        // this is not supposed to happen
        return hour;
    }
}

// date from string and array of format strings
function configFromStringAndArray(config) {
    var tempConfig,
        bestMoment,
        scoreToBeat,
        i,
        currentScore,
        validFormatFound,
        bestFormatIsValid = false,
        configfLen = config._f.length;

    if (configfLen === 0) {
        getParsingFlags(config).invalidFormat = true;
        config._d = new Date(NaN);
        return;
    }

    for (i = 0; i < configfLen; i++) {
        currentScore = 0;
        validFormatFound = false;
        tempConfig = copyConfig({}, config);
        if (config._useUTC != null) {
            tempConfig._useUTC = config._useUTC;
        }
        tempConfig._f = config._f[i];
        configFromStringAndFormat(tempConfig);

        if (isValid(tempConfig)) {
            validFormatFound = true;
        }

        // if there is any input that was not parsed add a penalty for that format
        currentScore += getParsingFlags(tempConfig).charsLeftOver;

        //or tokens
        currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;

        getParsingFlags(tempConfig).score = currentScore;

        if (!bestFormatIsValid) {
            if (
                scoreToBeat == null ||
                currentScore < scoreToBeat ||
                validFormatFound
            ) {
                scoreToBeat = currentScore;
                bestMoment = tempConfig;
                if (validFormatFound) {
                    bestFormatIsValid = true;
                }
            }
        } else {
            if (currentScore < scoreToBeat) {
                scoreToBeat = currentScore;
                bestMoment = tempConfig;
            }
        }
    }

    extend(config, bestMoment || tempConfig);
}

function configFromObject(config) {
    if (config._d) {
        return;
    }

    var i = normalizeObjectUnits(config._i),
        dayOrDate = i.day === undefined ? i.date : i.day;
    config._a = map(
        [i.year, i.month, dayOrDate, i.hour, i.minute, i.second, i.millisecond],
        function (obj) {
            return obj && parseInt(obj, 10);
        }
    );

    configFromArray(config);
}

function createFromConfig(config) {
    var res = new Moment(checkOverflow(prepareConfig(config)));
    if (res._nextDay) {
        // Adding is smart enough around DST
        res.add(1, 'd');
        res._nextDay = undefined;
    }

    return res;
}

function prepareConfig(config) {
    var input = config._i,
        format = config._f;

    config._locale = config._locale || getLocale(config._l);

    if (input === null || (format === undefined && input === '')) {
        return createInvalid({ nullInput: true });
    }

    if (typeof input === 'string') {
        config._i = input = config._locale.preparse(input);
    }

    if (isMoment(input)) {
        return new Moment(checkOverflow(input));
    } else if (isDate(input)) {
        config._d = input;
    } else if (isArray(format)) {
        configFromStringAndArray(config);
    } else if (format) {
        configFromStringAndFormat(config);
    } else {
        configFromInput(config);
    }

    if (!isValid(config)) {
        config._d = null;
    }

    return config;
}

function configFromInput(config) {
    var input = config._i;
    if (isUndefined(input)) {
        config._d = new Date(hooks.now());
    } else if (isDate(input)) {
        config._d = new Date(input.valueOf());
    } else if (typeof input === 'string') {
        configFromString(config);
    } else if (isArray(input)) {
        config._a = map(input.slice(0), function (obj) {
            return parseInt(obj, 10);
        });
        configFromArray(config);
    } else if (isObject(input)) {
        configFromObject(config);
    } else if (isNumber(input)) {
        // from milliseconds
        config._d = new Date(input);
    } else {
        hooks.createFromInputFallback(config);
    }
}

function createLocalOrUTC(input, format, locale, strict, isUTC) {
    var c = {};

    if (format === true || format === false) {
        strict = format;
        format = undefined;
    }

    if (locale === true || locale === false) {
        strict = locale;
        locale = undefined;
    }

    if (
        (isObject(input) && isObjectEmpty(input)) ||
        (isArray(input) && input.length === 0)
    ) {
        input = undefined;
    }
    // object construction must be done this way.
    // https://github.com/moment/moment/issues/1423
    c._isAMomentObject = true;
    c._useUTC = c._isUTC = isUTC;
    c._l = locale;
    c._i = input;
    c._f = format;
    c._strict = strict;

    return createFromConfig(c);
}

function createLocal(input, format, locale, strict) {
    return createLocalOrUTC(input, format, locale, strict, false);
}

var prototypeMin = deprecate(
        'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',
        function () {
            var other = createLocal.apply(null, arguments);
            if (this.isValid() && other.isValid()) {
                return other < this ? this : other;
            } else {
                return createInvalid();
            }
        }
    ),
    prototypeMax = deprecate(
        'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',
        function () {
            var other = createLocal.apply(null, arguments);
            if (this.isValid() && other.isValid()) {
                return other > this ? this : other;
            } else {
                return createInvalid();
            }
        }
    );

// Pick a moment m from moments so that m[fn](other) is true for all
// other. This relies on the function fn to be transitive.
//
// moments should either be an array of moment objects or an array, whose
// first element is an array of moment objects.
function pickBy(fn, moments) {
    var res, i;
    if (moments.length === 1 && isArray(moments[0])) {
        moments = moments[0];
    }
    if (!moments.length) {
        return createLocal();
    }
    res = moments[0];
    for (i = 1; i < moments.length; ++i) {
        if (!moments[i].isValid() || moments[i][fn](res)) {
            res = moments[i];
        }
    }
    return res;
}

// TODO: Use [].sort instead?
function min() {
    var args = [].slice.call(arguments, 0);

    return pickBy('isBefore', args);
}

function max() {
    var args = [].slice.call(arguments, 0);

    return pickBy('isAfter', args);
}

var now = function () {
    return Date.now ? Date.now() : +new Date();
};

var ordering = [
    'year',
    'quarter',
    'month',
    'week',
    'day',
    'hour',
    'minute',
    'second',
    'millisecond',
];

function isDurationValid(m) {
    var key,
        unitHasDecimal = false,
        i,
        orderLen = ordering.length;
    for (key in m) {
        if (
            hasOwnProp(m, key) &&
            !(
                indexOf.call(ordering, key) !== -1 &&
                (m[key] == null || !isNaN(m[key]))
            )
        ) {
            return false;
        }
    }

    for (i = 0; i < orderLen; ++i) {
        if (m[ordering[i]]) {
            if (unitHasDecimal) {
                return false; // only allow non-integers for smallest unit
            }
            if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
                unitHasDecimal = true;
            }
        }
    }

    return true;
}

function isValid$1() {
    return this._isValid;
}

function createInvalid$1() {
    return createDuration(NaN);
}

function Duration(duration) {
    var normalizedInput = normalizeObjectUnits(duration),
        years = normalizedInput.year || 0,
        quarters = normalizedInput.quarter || 0,
        months = normalizedInput.month || 0,
        weeks = normalizedInput.week || normalizedInput.isoWeek || 0,
        days = normalizedInput.day || 0,
        hours = normalizedInput.hour || 0,
        minutes = normalizedInput.minute || 0,
        seconds = normalizedInput.second || 0,
        milliseconds = normalizedInput.millisecond || 0;

    this._isValid = isDurationValid(normalizedInput);

    // representation for dateAddRemove
    this._milliseconds =
        +milliseconds +
        seconds * 1e3 + // 1000
        minutes * 6e4 + // 1000 * 60
        hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
    // Because of dateAddRemove treats 24 hours as different from a
    // day when working around DST, we need to store them separately
    this._days = +days + weeks * 7;
    // It is impossible to translate months into days without knowing
    // which months you are are talking about, so we have to store
    // it separately.
    this._months = +months + quarters * 3 + years * 12;

    this._data = {};

    this._locale = getLocale();

    this._bubble();
}

function isDuration(obj) {
    return obj instanceof Duration;
}

function absRound(number) {
    if (number < 0) {
        return Math.round(-1 * number) * -1;
    } else {
        return Math.round(number);
    }
}

// compare two arrays, return the number of differences
function compareArrays(array1, array2, dontConvert) {
    var len = Math.min(array1.length, array2.length),
        lengthDiff = Math.abs(array1.length - array2.length),
        diffs = 0,
        i;
    for (i = 0; i < len; i++) {
        if (
            (dontConvert && array1[i] !== array2[i]) ||
            (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))
        ) {
            diffs++;
        }
    }
    return diffs + lengthDiff;
}

// FORMATTING

function offset(token, separator) {
    addFormatToken(token, 0, 0, function () {
        var offset = this.utcOffset(),
            sign = '+';
        if (offset < 0) {
            offset = -offset;
            sign = '-';
        }
        return (
            sign +
            zeroFill(~~(offset / 60), 2) +
            separator +
            zeroFill(~~offset % 60, 2)
        );
    });
}

offset('Z', ':');
offset('ZZ', '');

// PARSING

addRegexToken('Z', matchShortOffset);
addRegexToken('ZZ', matchShortOffset);
addParseToken(['Z', 'ZZ'], function (input, array, config) {
    config._useUTC = true;
    config._tzm = offsetFromString(matchShortOffset, input);
});

// HELPERS

// timezone chunker
// '+10:00' > ['10',  '00']
// '-1530'  > ['-15', '30']
var chunkOffset = /([\+\-]|\d\d)/gi;

function offsetFromString(matcher, string) {
    var matches = (string || '').match(matcher),
        chunk,
        parts,
        minutes;

    if (matches === null) {
        return null;
    }

    chunk = matches[matches.length - 1] || [];
    parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
    minutes = +(parts[1] * 60) + toInt(parts[2]);

    return minutes === 0 ? 0 : parts[0] === '+' ? minutes : -minutes;
}

// Return a moment from input, that is local/utc/zone equivalent to model.
function cloneWithOffset(input, model) {
    var res, diff;
    if (model._isUTC) {
        res = model.clone();
        diff =
            (isMoment(input) || isDate(input)
                ? input.valueOf()
                : createLocal(input).valueOf()) - res.valueOf();
        // Use low-level api, because this fn is low-level api.
        res._d.setTime(res._d.valueOf() + diff);
        hooks.updateOffset(res, false);
        return res;
    } else {
        return createLocal(input).local();
    }
}

function getDateOffset(m) {
    // On Firefox.24 Date#getTimezoneOffset returns a floating point.
    // https://github.com/moment/moment/pull/1871
    return -Math.round(m._d.getTimezoneOffset());
}

// HOOKS

// This function will be called whenever a moment is mutated.
// It is intended to keep the offset in sync with the timezone.
hooks.updateOffset = function () {};

// MOMENTS

// keepLocalTime = true means only change the timezone, without
// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
// +0200, so we adjust the time as needed, to be valid.
//
// Keeping the time actually adds/subtracts (one hour)
// from the actual represented time. That is why we call updateOffset
// a second time. In case it wants us to change the offset again
// _changeInProgress == true case, then we have to adjust, because
// there is no such time in the given timezone.
function getSetOffset(input, keepLocalTime, keepMinutes) {
    var offset = this._offset || 0,
        localAdjust;
    if (!this.isValid()) {
        return input != null ? this : NaN;
    }
    if (input != null) {
        if (typeof input === 'string') {
            input = offsetFromString(matchShortOffset, input);
            if (input === null) {
                return this;
            }
        } else if (Math.abs(input) < 16 && !keepMinutes) {
            input = input * 60;
        }
        if (!this._isUTC && keepLocalTime) {
            localAdjust = getDateOffset(this);
        }
        this._offset = input;
        this._isUTC = true;
        if (localAdjust != null) {
            this.add(localAdjust, 'm');
        }
        if (offset !== input) {
            if (!keepLocalTime || this._changeInProgress) {
                addSubtract(
                    this,
                    createDuration(input - offset, 'm'),
                    1,
                    false
                );
            } else if (!this._changeInProgress) {
                this._changeInProgress = true;
                hooks.updateOffset(this, true);
                this._changeInProgress = null;
            }
        }
        return this;
    } else {
        return this._isUTC ? offset : getDateOffset(this);
    }
}

function getSetZone(input, keepLocalTime) {
    if (input != null) {
        if (typeof input !== 'string') {
            input = -input;
        }

        this.utcOffset(input, keepLocalTime);

        return this;
    } else {
        return -this.utcOffset();
    }
}

function setOffsetToUTC(keepLocalTime) {
    return this.utcOffset(0, keepLocalTime);
}

function setOffsetToLocal(keepLocalTime) {
    if (this._isUTC) {
        this.utcOffset(0, keepLocalTime);
        this._isUTC = false;

        if (keepLocalTime) {
            this.subtract(getDateOffset(this), 'm');
        }
    }
    return this;
}

function setOffsetToParsedOffset() {
    if (this._tzm != null) {
        this.utcOffset(this._tzm, false, true);
    } else if (typeof this._i === 'string') {
        var tZone = offsetFromString(matchOffset, this._i);
        if (tZone != null) {
            this.utcOffset(tZone);
        } else {
            this.utcOffset(0, true);
        }
    }
    return this;
}

function hasAlignedHourOffset(input) {
    if (!this.isValid()) {
        return false;
    }
    input = input ? createLocal(input).utcOffset() : 0;

    return (this.utcOffset() - input) % 60 === 0;
}

function isDaylightSavingTime() {
    return (
        this.utcOffset() > this.clone().month(0).utcOffset() ||
        this.utcOffset() > this.clone().month(5).utcOffset()
    );
}

function isDaylightSavingTimeShifted() {
    if (!isUndefined(this._isDSTShifted)) {
        return this._isDSTShifted;
    }

    var c = {},
        other;

    copyConfig(c, this);
    c = prepareConfig(c);

    if (c._a) {
        other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
        this._isDSTShifted =
            this.isValid() && compareArrays(c._a, other.toArray()) > 0;
    } else {
        this._isDSTShifted = false;
    }

    return this._isDSTShifted;
}

function isLocal() {
    return this.isValid() ? !this._isUTC : false;
}

function isUtcOffset() {
    return this.isValid() ? this._isUTC : false;
}

function isUtc() {
    return this.isValid() ? this._isUTC && this._offset === 0 : false;
}

// ASP.NET json date format regex
var aspNetRegex = /^(-|\+)?(?:(\d*)[. ])?(\d+):(\d+)(?::(\d+)(\.\d*)?)?$/,
    // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
    // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
    // and further modified to allow for strings containing both week and day
    isoRegex =
        /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;

function createDuration(input, key) {
    var duration = input,
        // matching against regexp is expensive, do it on demand
        match = null,
        sign,
        ret,
        diffRes;

    if (isDuration(input)) {
        duration = {
            ms: input._milliseconds,
            d: input._days,
            M: input._months,
        };
    } else if (isNumber(input) || !isNaN(+input)) {
        duration = {};
        if (key) {
            duration[key] = +input;
        } else {
            duration.milliseconds = +input;
        }
    } else if ((match = aspNetRegex.exec(input))) {
        sign = match[1] === '-' ? -1 : 1;
        duration = {
            y: 0,
            d: toInt(match[DATE]) * sign,
            h: toInt(match[HOUR]) * sign,
            m: toInt(match[MINUTE]) * sign,
            s: toInt(match[SECOND]) * sign,
            ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign, // the millisecond decimal point is included in the match
        };
    } else if ((match = isoRegex.exec(input))) {
        sign = match[1] === '-' ? -1 : 1;
        duration = {
            y: parseIso(match[2], sign),
            M: parseIso(match[3], sign),
            w: parseIso(match[4], sign),
            d: parseIso(match[5], sign),
            h: parseIso(match[6], sign),
            m: parseIso(match[7], sign),
            s: parseIso(match[8], sign),
        };
    } else if (duration == null) {
        // checks for null or undefined
        duration = {};
    } else if (
        typeof duration === 'object' &&
        ('from' in duration || 'to' in duration)
    ) {
        diffRes = momentsDifference(
            createLocal(duration.from),
            createLocal(duration.to)
        );

        duration = {};
        duration.ms = diffRes.milliseconds;
        duration.M = diffRes.months;
    }

    ret = new Duration(duration);

    if (isDuration(input) && hasOwnProp(input, '_locale')) {
        ret._locale = input._locale;
    }

    if (isDuration(input) && hasOwnProp(input, '_isValid')) {
        ret._isValid = input._isValid;
    }

    return ret;
}

createDuration.fn = Duration.prototype;
createDuration.invalid = createInvalid$1;

function parseIso(inp, sign) {
    // We'd normally use ~~inp for this, but unfortunately it also
    // converts floats to ints.
    // inp may be undefined, so careful calling replace on it.
    var res = inp && parseFloat(inp.replace(',', '.'));
    // apply sign while we're at it
    return (isNaN(res) ? 0 : res) * sign;
}

function positiveMomentsDifference(base, other) {
    var res = {};

    res.months =
        other.month() - base.month() + (other.year() - base.year()) * 12;
    if (base.clone().add(res.months, 'M').isAfter(other)) {
        --res.months;
    }

    res.milliseconds = +other - +base.clone().add(res.months, 'M');

    return res;
}

function momentsDifference(base, other) {
    var res;
    if (!(base.isValid() && other.isValid())) {
        return { milliseconds: 0, months: 0 };
    }

    other = cloneWithOffset(other, base);
    if (base.isBefore(other)) {
        res = positiveMomentsDifference(base, other);
    } else {
        res = positiveMomentsDifference(other, base);
        res.milliseconds = -res.milliseconds;
        res.months = -res.months;
    }

    return res;
}

// TODO: remove 'name' arg after deprecation is removed
function createAdder(direction, name) {
    return function (val, period) {
        var dur, tmp;
        //invert the arguments, but complain about it
        if (period !== null && !isNaN(+period)) {
            deprecateSimple(
                name,
                'moment().' +
                    name +
                    '(period, number) is deprecated. Please use moment().' +
                    name +
                    '(number, period). ' +
                    'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.'
            );
            tmp = val;
            val = period;
            period = tmp;
        }

        dur = createDuration(val, period);
        addSubtract(this, dur, direction);
        return this;
    };
}

function addSubtract(mom, duration, isAdding, updateOffset) {
    var milliseconds = duration._milliseconds,
        days = absRound(duration._days),
        months = absRound(duration._months);

    if (!mom.isValid()) {
        // No op
        return;
    }

    updateOffset = updateOffset == null ? true : updateOffset;

    if (months) {
        setMonth(mom, get(mom, 'Month') + months * isAdding);
    }
    if (days) {
        set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
    }
    if (milliseconds) {
        mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
    }
    if (updateOffset) {
        hooks.updateOffset(mom, days || months);
    }
}

var add = createAdder(1, 'add'),
    subtract = createAdder(-1, 'subtract');

function isString(input) {
    return typeof input === 'string' || input instanceof String;
}

// type MomentInput = Moment | Date | string | number | (number | string)[] | MomentInputObject | void; // null | undefined
function isMomentInput(input) {
    return (
        isMoment(input) ||
        isDate(input) ||
        isString(input) ||
        isNumber(input) ||
        isNumberOrStringArray(input) ||
        isMomentInputObject(input) ||
        input === null ||
        input === undefined
    );
}

function isMomentInputObject(input) {
    var objectTest = isObject(input) && !isObjectEmpty(input),
        propertyTest = false,
        properties = [
            'years',
            'year',
            'y',
            'months',
            'month',
            'M',
            'days',
            'day',
            'd',
            'dates',
            'date',
            'D',
            'hours',
            'hour',
            'h',
            'minutes',
            'minute',
            'm',
            'seconds',
            'second',
            's',
            'milliseconds',
            'millisecond',
            'ms',
        ],
        i,
        property,
        propertyLen = properties.length;

    for (i = 0; i < propertyLen; i += 1) {
        property = properties[i];
        propertyTest = propertyTest || hasOwnProp(input, property);
    }

    return objectTest && propertyTest;
}

function isNumberOrStringArray(input) {
    var arrayTest = isArray(input),
        dataTypeTest = false;
    if (arrayTest) {
        dataTypeTest =
            input.filter(function (item) {
                return !isNumber(item) && isString(input);
            }).length === 0;
    }
    return arrayTest && dataTypeTest;
}

function isCalendarSpec(input) {
    var objectTest = isObject(input) && !isObjectEmpty(input),
        propertyTest = false,
        properties = [
            'sameDay',
            'nextDay',
            'lastDay',
            'nextWeek',
            'lastWeek',
            'sameElse',
        ],
        i,
        property;

    for (i = 0; i < properties.length; i += 1) {
        property = properties[i];
        propertyTest = propertyTest || hasOwnProp(input, property);
    }

    return objectTest && propertyTest;
}

function getCalendarFormat(myMoment, now) {
    var diff = myMoment.diff(now, 'days', true);
    return diff < -6
        ? 'sameElse'
        : diff < -1
          ? 'lastWeek'
          : diff < 0
            ? 'lastDay'
            : diff < 1
              ? 'sameDay'
              : diff < 2
                ? 'nextDay'
                : diff < 7
                  ? 'nextWeek'
                  : 'sameElse';
}

function calendar$1(time, formats) {
    // Support for single parameter, formats only overload to the calendar function
    if (arguments.length === 1) {
        if (!arguments[0]) {
            time = undefined;
            formats = undefined;
        } else if (isMomentInput(arguments[0])) {
            time = arguments[0];
            formats = undefined;
        } else if (isCalendarSpec(arguments[0])) {
            formats = arguments[0];
            time = undefined;
        }
    }
    // We want to compare the start of today, vs this.
    // Getting start-of-today depends on whether we're local/utc/offset or not.
    var now = time || createLocal(),
        sod = cloneWithOffset(now, this).startOf('day'),
        format = hooks.calendarFormat(this, sod) || 'sameElse',
        output =
            formats &&
            (isFunction(formats[format])
                ? formats[format].call(this, now)
                : formats[format]);

    return this.format(
        output || this.localeData().calendar(format, this, createLocal(now))
    );
}

function clone() {
    return new Moment(this);
}

function isAfter(input, units) {
    var localInput = isMoment(input) ? input : createLocal(input);
    if (!(this.isValid() && localInput.isValid())) {
        return false;
    }
    units = normalizeUnits(units) || 'millisecond';
    if (units === 'millisecond') {
        return this.valueOf() > localInput.valueOf();
    } else {
        return localInput.valueOf() < this.clone().startOf(units).valueOf();
    }
}

function isBefore(input, units) {
    var localInput = isMoment(input) ? input : createLocal(input);
    if (!(this.isValid() && localInput.isValid())) {
        return false;
    }
    units = normalizeUnits(units) || 'millisecond';
    if (units === 'millisecond') {
        return this.valueOf() < localInput.valueOf();
    } else {
        return this.clone().endOf(units).valueOf() < localInput.valueOf();
    }
}

function isBetween(from, to, units, inclusivity) {
    var localFrom = isMoment(from) ? from : createLocal(from),
        localTo = isMoment(to) ? to : createLocal(to);
    if (!(this.isValid() && localFrom.isValid() && localTo.isValid())) {
        return false;
    }
    inclusivity = inclusivity || '()';
    return (
        (inclusivity[0] === '('
            ? this.isAfter(localFrom, units)
            : !this.isBefore(localFrom, units)) &&
        (inclusivity[1] === ')'
            ? this.isBefore(localTo, units)
            : !this.isAfter(localTo, units))
    );
}

function isSame(input, units) {
    var localInput = isMoment(input) ? input : createLocal(input),
        inputMs;
    if (!(this.isValid() && localInput.isValid())) {
        return false;
    }
    units = normalizeUnits(units) || 'millisecond';
    if (units === 'millisecond') {
        return this.valueOf() === localInput.valueOf();
    } else {
        inputMs = localInput.valueOf();
        return (
            this.clone().startOf(units).valueOf() <= inputMs &&
            inputMs <= this.clone().endOf(units).valueOf()
        );
    }
}

function isSameOrAfter(input, units) {
    return this.isSame(input, units) || this.isAfter(input, units);
}

function isSameOrBefore(input, units) {
    return this.isSame(input, units) || this.isBefore(input, units);
}

function diff(input, units, asFloat) {
    var that, zoneDelta, output;

    if (!this.isValid()) {
        return NaN;
    }

    that = cloneWithOffset(input, this);

    if (!that.isValid()) {
        return NaN;
    }

    zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;

    units = normalizeUnits(units);

    switch (units) {
        case 'year':
            output = monthDiff(this, that) / 12;
            break;
        case 'month':
            output = monthDiff(this, that);
            break;
        case 'quarter':
            output = monthDiff(this, that) / 3;
            break;
        case 'second':
            output = (this - that) / 1e3;
            break; // 1000
        case 'minute':
            output = (this - that) / 6e4;
            break; // 1000 * 60
        case 'hour':
            output = (this - that) / 36e5;
            break; // 1000 * 60 * 60
        case 'day':
            output = (this - that - zoneDelta) / 864e5;
            break; // 1000 * 60 * 60 * 24, negate dst
        case 'week':
            output = (this - that - zoneDelta) / 6048e5;
            break; // 1000 * 60 * 60 * 24 * 7, negate dst
        default:
            output = this - that;
    }

    return asFloat ? output : absFloor(output);
}

function monthDiff(a, b) {
    if (a.date() < b.date()) {
        // end-of-month calculations work correct when the start month has more
        // days than the end month.
        return -monthDiff(b, a);
    }
    // difference in months
    var wholeMonthDiff = (b.year() - a.year()) * 12 + (b.month() - a.month()),
        // b is in (anchor - 1 month, anchor + 1 month)
        anchor = a.clone().add(wholeMonthDiff, 'months'),
        anchor2,
        adjust;

    if (b - anchor < 0) {
        anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
        // linear across the month
        adjust = (b - anchor) / (anchor - anchor2);
    } else {
        anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
        // linear across the month
        adjust = (b - anchor) / (anchor2 - anchor);
    }

    //check for negative zero, return zero if negative zero
    return -(wholeMonthDiff + adjust) || 0;
}

hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';

function toString() {
    return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
}

function toISOString(keepOffset) {
    if (!this.isValid()) {
        return null;
    }
    var utc = keepOffset !== true,
        m = utc ? this.clone().utc() : this;
    if (m.year() < 0 || m.year() > 9999) {
        return formatMoment(
            m,
            utc
                ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'
                : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ'
        );
    }
    if (isFunction(Date.prototype.toISOString)) {
        // native implementation is ~50x faster, use it when we can
        if (utc) {
            return this.toDate().toISOString();
        } else {
            return new Date(this.valueOf() + this.utcOffset() * 60 * 1000)
                .toISOString()
                .replace('Z', formatMoment(m, 'Z'));
        }
    }
    return formatMoment(
        m,
        utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ'
    );
}

/**
 * Return a human readable representation of a moment that can
 * also be evaluated to get a new moment which is the same
 *
 * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
 */
function inspect() {
    if (!this.isValid()) {
        return 'moment.invalid(/* ' + this._i + ' */)';
    }
    var func = 'moment',
        zone = '',
        prefix,
        year,
        datetime,
        suffix;
    if (!this.isLocal()) {
        func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
        zone = 'Z';
    }
    prefix = '[' + func + '("]';
    year = 0 <= this.year() && this.year() <= 9999 ? 'YYYY' : 'YYYYYY';
    datetime = '-MM-DD[T]HH:mm:ss.SSS';
    suffix = zone + '[")]';

    return this.format(prefix + year + datetime + suffix);
}

function format(inputString) {
    if (!inputString) {
        inputString = this.isUtc()
            ? hooks.defaultFormatUtc
            : hooks.defaultFormat;
    }
    var output = formatMoment(this, inputString);
    return this.localeData().postformat(output);
}

function from(time, withoutSuffix) {
    if (
        this.isValid() &&
        ((isMoment(time) && time.isValid()) || createLocal(time).isValid())
    ) {
        return createDuration({ to: this, from: time })
            .locale(this.locale())
            .humanize(!withoutSuffix);
    } else {
        return this.localeData().invalidDate();
    }
}

function fromNow(withoutSuffix) {
    return this.from(createLocal(), withoutSuffix);
}

function to(time, withoutSuffix) {
    if (
        this.isValid() &&
        ((isMoment(time) && time.isValid()) || createLocal(time).isValid())
    ) {
        return createDuration({ from: this, to: time })
            .locale(this.locale())
            .humanize(!withoutSuffix);
    } else {
        return this.localeData().invalidDate();
    }
}

function toNow(withoutSuffix) {
    return this.to(createLocal(), withoutSuffix);
}

// If passed a locale key, it will set the locale for this
// instance.  Otherwise, it will return the locale configuration
// variables for this instance.
function locale(key) {
    var newLocaleData;

    if (key === undefined) {
        return this._locale._abbr;
    } else {
        newLocaleData = getLocale(key);
        if (newLocaleData != null) {
            this._locale = newLocaleData;
        }
        return this;
    }
}

var lang = deprecate(
    'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
    function (key) {
        if (key === undefined) {
            return this.localeData();
        } else {
            return this.locale(key);
        }
    }
);

function localeData() {
    return this._locale;
}

var MS_PER_SECOND = 1000,
    MS_PER_MINUTE = 60 * MS_PER_SECOND,
    MS_PER_HOUR = 60 * MS_PER_MINUTE,
    MS_PER_400_YEARS = (365 * 400 + 97) * 24 * MS_PER_HOUR;

// actual modulo - handles negative numbers (for dates before 1970):
function mod$1(dividend, divisor) {
    return ((dividend % divisor) + divisor) % divisor;
}

function localStartOfDate(y, m, d) {
    // the date constructor remaps years 0-99 to 1900-1999
    if (y < 100 && y >= 0) {
        // preserve leap years using a full 400 year cycle, then reset
        return new Date(y + 400, m, d) - MS_PER_400_YEARS;
    } else {
        return new Date(y, m, d).valueOf();
    }
}

function utcStartOfDate(y, m, d) {
    // Date.UTC remaps years 0-99 to 1900-1999
    if (y < 100 && y >= 0) {
        // preserve leap years using a full 400 year cycle, then reset
        return Date.UTC(y + 400, m, d) - MS_PER_400_YEARS;
    } else {
        return Date.UTC(y, m, d);
    }
}

function startOf(units) {
    var time, startOfDate;
    units = normalizeUnits(units);
    if (units === undefined || units === 'millisecond' || !this.isValid()) {
        return this;
    }

    startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;

    switch (units) {
        case 'year':
            time = startOfDate(this.year(), 0, 1);
            break;
        case 'quarter':
            time = startOfDate(
                this.year(),
                this.month() - (this.month() % 3),
                1
            );
            break;
        case 'month':
            time = startOfDate(this.year(), this.month(), 1);
            break;
        case 'week':
            time = startOfDate(
                this.year(),
                this.month(),
                this.date() - this.weekday()
            );
            break;
        case 'isoWeek':
            time = startOfDate(
                this.year(),
                this.month(),
                this.date() - (this.isoWeekday() - 1)
            );
            break;
        case 'day':
        case 'date':
            time = startOfDate(this.year(), this.month(), this.date());
            break;
        case 'hour':
            time = this._d.valueOf();
            time -= mod$1(
                time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE),
                MS_PER_HOUR
            );
            break;
        case 'minute':
            time = this._d.valueOf();
            time -= mod$1(time, MS_PER_MINUTE);
            break;
        case 'second':
            time = this._d.valueOf();
            time -= mod$1(time, MS_PER_SECOND);
            break;
    }

    this._d.setTime(time);
    hooks.updateOffset(this, true);
    return this;
}

function endOf(units) {
    var time, startOfDate;
    units = normalizeUnits(units);
    if (units === undefined || units === 'millisecond' || !this.isValid()) {
        return this;
    }

    startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;

    switch (units) {
        case 'year':
            time = startOfDate(this.year() + 1, 0, 1) - 1;
            break;
        case 'quarter':
            time =
                startOfDate(
                    this.year(),
                    this.month() - (this.month() % 3) + 3,
                    1
                ) - 1;
            break;
        case 'month':
            time = startOfDate(this.year(), this.month() + 1, 1) - 1;
            break;
        case 'week':
            time =
                startOfDate(
                    this.year(),
                    this.month(),
                    this.date() - this.weekday() + 7
                ) - 1;
            break;
        case 'isoWeek':
            time =
                startOfDate(
                    this.year(),
                    this.month(),
                    this.date() - (this.isoWeekday() - 1) + 7
                ) - 1;
            break;
        case 'day':
        case 'date':
            time = startOfDate(this.year(), this.month(), this.date() + 1) - 1;
            break;
        case 'hour':
            time = this._d.valueOf();
            time +=
                MS_PER_HOUR -
                mod$1(
                    time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE),
                    MS_PER_HOUR
                ) -
                1;
            break;
        case 'minute':
            time = this._d.valueOf();
            time += MS_PER_MINUTE - mod$1(time, MS_PER_MINUTE) - 1;
            break;
        case 'second':
            time = this._d.valueOf();
            time += MS_PER_SECOND - mod$1(time, MS_PER_SECOND) - 1;
            break;
    }

    this._d.setTime(time);
    hooks.updateOffset(this, true);
    return this;
}

function valueOf() {
    return this._d.valueOf() - (this._offset || 0) * 60000;
}

function unix() {
    return Math.floor(this.valueOf() / 1000);
}

function toDate() {
    return new Date(this.valueOf());
}

function toArray() {
    var m = this;
    return [
        m.year(),
        m.month(),
        m.date(),
        m.hour(),
        m.minute(),
        m.second(),
        m.millisecond(),
    ];
}

function toObject() {
    var m = this;
    return {
        years: m.year(),
        months: m.month(),
        date: m.date(),
        hours: m.hours(),
        minutes: m.minutes(),
        seconds: m.seconds(),
        milliseconds: m.milliseconds(),
    };
}

function toJSON() {
    // new Date(NaN).toJSON() === null
    return this.isValid() ? this.toISOString() : null;
}

function isValid$2() {
    return isValid(this);
}

function parsingFlags() {
    return extend({}, getParsingFlags(this));
}

function invalidAt() {
    return getParsingFlags(this).overflow;
}

function creationData() {
    return {
        input: this._i,
        format: this._f,
        locale: this._locale,
        isUTC: this._isUTC,
        strict: this._strict,
    };
}

addFormatToken('N', 0, 0, 'eraAbbr');
addFormatToken('NN', 0, 0, 'eraAbbr');
addFormatToken('NNN', 0, 0, 'eraAbbr');
addFormatToken('NNNN', 0, 0, 'eraName');
addFormatToken('NNNNN', 0, 0, 'eraNarrow');

addFormatToken('y', ['y', 1], 'yo', 'eraYear');
addFormatToken('y', ['yy', 2], 0, 'eraYear');
addFormatToken('y', ['yyy', 3], 0, 'eraYear');
addFormatToken('y', ['yyyy', 4], 0, 'eraYear');

addRegexToken('N', matchEraAbbr);
addRegexToken('NN', matchEraAbbr);
addRegexToken('NNN', matchEraAbbr);
addRegexToken('NNNN', matchEraName);
addRegexToken('NNNNN', matchEraNarrow);

addParseToken(
    ['N', 'NN', 'NNN', 'NNNN', 'NNNNN'],
    function (input, array, config, token) {
        var era = config._locale.erasParse(input, token, config._strict);
        if (era) {
            getParsingFlags(config).era = era;
        } else {
            getParsingFlags(config).invalidEra = input;
        }
    }
);

addRegexToken('y', matchUnsigned);
addRegexToken('yy', matchUnsigned);
addRegexToken('yyy', matchUnsigned);
addRegexToken('yyyy', matchUnsigned);
addRegexToken('yo', matchEraYearOrdinal);

addParseToken(['y', 'yy', 'yyy', 'yyyy'], YEAR);
addParseToken(['yo'], function (input, array, config, token) {
    var match;
    if (config._locale._eraYearOrdinalRegex) {
        match = input.match(config._locale._eraYearOrdinalRegex);
    }

    if (config._locale.eraYearOrdinalParse) {
        array[YEAR] = config._locale.eraYearOrdinalParse(input, match);
    } else {
        array[YEAR] = parseInt(input, 10);
    }
});

function localeEras(m, format) {
    var i,
        l,
        date,
        eras = this._eras || getLocale('en')._eras;
    for (i = 0, l = eras.length; i < l; ++i) {
        switch (typeof eras[i].since) {
            case 'string':
                // truncate time
                date = hooks(eras[i].since).startOf('day');
                eras[i].since = date.valueOf();
                break;
        }

        switch (typeof eras[i].until) {
            case 'undefined':
                eras[i].until = +Infinity;
                break;
            case 'string':
                // truncate time
                date = hooks(eras[i].until).startOf('day').valueOf();
                eras[i].until = date.valueOf();
                break;
        }
    }
    return eras;
}

function localeErasParse(eraName, format, strict) {
    var i,
        l,
        eras = this.eras(),
        name,
        abbr,
        narrow;
    eraName = eraName.toUpperCase();

    for (i = 0, l = eras.length; i < l; ++i) {
        name = eras[i].name.toUpperCase();
        abbr = eras[i].abbr.toUpperCase();
        narrow = eras[i].narrow.toUpperCase();

        if (strict) {
            switch (format) {
                case 'N':
                case 'NN':
                case 'NNN':
                    if (abbr === eraName) {
                        return eras[i];
                    }
                    break;

                case 'NNNN':
                    if (name === eraName) {
                        return eras[i];
                    }
                    break;

                case 'NNNNN':
                    if (narrow === eraName) {
                        return eras[i];
                    }
                    break;
            }
        } else if ([name, abbr, narrow].indexOf(eraName) >= 0) {
            return eras[i];
        }
    }
}

function localeErasConvertYear(era, year) {
    var dir = era.since <= era.until ? +1 : -1;
    if (year === undefined) {
        return hooks(era.since).year();
    } else {
        return hooks(era.since).year() + (year - era.offset) * dir;
    }
}

function getEraName() {
    var i,
        l,
        val,
        eras = this.localeData().eras();
    for (i = 0, l = eras.length; i < l; ++i) {
        // truncate time
        val = this.clone().startOf('day').valueOf();

        if (eras[i].since <= val && val <= eras[i].until) {
            return eras[i].name;
        }
        if (eras[i].until <= val && val <= eras[i].since) {
            return eras[i].name;
        }
    }

    return '';
}

function getEraNarrow() {
    var i,
        l,
        val,
        eras = this.localeData().eras();
    for (i = 0, l = eras.length; i < l; ++i) {
        // truncate time
        val = this.clone().startOf('day').valueOf();

        if (eras[i].since <= val && val <= eras[i].until) {
            return eras[i].narrow;
        }
        if (eras[i].until <= val && val <= eras[i].since) {
            return eras[i].narrow;
        }
    }

    return '';
}

function getEraAbbr() {
    var i,
        l,
        val,
        eras = this.localeData().eras();
    for (i = 0, l = eras.length; i < l; ++i) {
        // truncate time
        val = this.clone().startOf('day').valueOf();

        if (eras[i].since <= val && val <= eras[i].until) {
            return eras[i].abbr;
        }
        if (eras[i].until <= val && val <= eras[i].since) {
            return eras[i].abbr;
        }
    }

    return '';
}

function getEraYear() {
    var i,
        l,
        dir,
        val,
        eras = this.localeData().eras();
    for (i = 0, l = eras.length; i < l; ++i) {
        dir = eras[i].since <= eras[i].until ? +1 : -1;

        // truncate time
        val = this.clone().startOf('day').valueOf();

        if (
            (eras[i].since <= val && val <= eras[i].until) ||
            (eras[i].until <= val && val <= eras[i].since)
        ) {
            return (
                (this.year() - hooks(eras[i].since).year()) * dir +
                eras[i].offset
            );
        }
    }

    return this.year();
}

function erasNameRegex(isStrict) {
    if (!hasOwnProp(this, '_erasNameRegex')) {
        computeErasParse.call(this);
    }
    return isStrict ? this._erasNameRegex : this._erasRegex;
}

function erasAbbrRegex(isStrict) {
    if (!hasOwnProp(this, '_erasAbbrRegex')) {
        computeErasParse.call(this);
    }
    return isStrict ? this._erasAbbrRegex : this._erasRegex;
}

function erasNarrowRegex(isStrict) {
    if (!hasOwnProp(this, '_erasNarrowRegex')) {
        computeErasParse.call(this);
    }
    return isStrict ? this._erasNarrowRegex : this._erasRegex;
}

function matchEraAbbr(isStrict, locale) {
    return locale.erasAbbrRegex(isStrict);
}

function matchEraName(isStrict, locale) {
    return locale.erasNameRegex(isStrict);
}

function matchEraNarrow(isStrict, locale) {
    return locale.erasNarrowRegex(isStrict);
}

function matchEraYearOrdinal(isStrict, locale) {
    return locale._eraYearOrdinalRegex || matchUnsigned;
}

function computeErasParse() {
    var abbrPieces = [],
        namePieces = [],
        narrowPieces = [],
        mixedPieces = [],
        i,
        l,
        erasName,
        erasAbbr,
        erasNarrow,
        eras = this.eras();

    for (i = 0, l = eras.length; i < l; ++i) {
        erasName = regexEscape(eras[i].name);
        erasAbbr = regexEscape(eras[i].abbr);
        erasNarrow = regexEscape(eras[i].narrow);

        namePieces.push(erasName);
        abbrPieces.push(erasAbbr);
        narrowPieces.push(erasNarrow);
        mixedPieces.push(erasName);
        mixedPieces.push(erasAbbr);
        mixedPieces.push(erasNarrow);
    }

    this._erasRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
    this._erasNameRegex = new RegExp('^(' + namePieces.join('|') + ')', 'i');
    this._erasAbbrRegex = new RegExp('^(' + abbrPieces.join('|') + ')', 'i');
    this._erasNarrowRegex = new RegExp(
        '^(' + narrowPieces.join('|') + ')',
        'i'
    );
}

// FORMATTING

addFormatToken(0, ['gg', 2], 0, function () {
    return this.weekYear() % 100;
});

addFormatToken(0, ['GG', 2], 0, function () {
    return this.isoWeekYear() % 100;
});

function addWeekYearFormatToken(token, getter) {
    addFormatToken(0, [token, token.length], 0, getter);
}

addWeekYearFormatToken('gggg', 'weekYear');
addWeekYearFormatToken('ggggg', 'weekYear');
addWeekYearFormatToken('GGGG', 'isoWeekYear');
addWeekYearFormatToken('GGGGG', 'isoWeekYear');

// ALIASES

// PARSING

addRegexToken('G', matchSigned);
addRegexToken('g', matchSigned);
addRegexToken('GG', match1to2, match2);
addRegexToken('gg', match1to2, match2);
addRegexToken('GGGG', match1to4, match4);
addRegexToken('gggg', match1to4, match4);
addRegexToken('GGGGG', match1to6, match6);
addRegexToken('ggggg', match1to6, match6);

addWeekParseToken(
    ['gggg', 'ggggg', 'GGGG', 'GGGGG'],
    function (input, week, config, token) {
        week[token.substr(0, 2)] = toInt(input);
    }
);

addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
    week[token] = hooks.parseTwoDigitYear(input);
});

// MOMENTS

function getSetWeekYear(input) {
    return getSetWeekYearHelper.call(
        this,
        input,
        this.week(),
        this.weekday() + this.localeData()._week.dow,
        this.localeData()._week.dow,
        this.localeData()._week.doy
    );
}

function getSetISOWeekYear(input) {
    return getSetWeekYearHelper.call(
        this,
        input,
        this.isoWeek(),
        this.isoWeekday(),
        1,
        4
    );
}

function getISOWeeksInYear() {
    return weeksInYear(this.year(), 1, 4);
}

function getISOWeeksInISOWeekYear() {
    return weeksInYear(this.isoWeekYear(), 1, 4);
}

function getWeeksInYear() {
    var weekInfo = this.localeData()._week;
    return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
}

function getWeeksInWeekYear() {
    var weekInfo = this.localeData()._week;
    return weeksInYear(this.weekYear(), weekInfo.dow, weekInfo.doy);
}

function getSetWeekYearHelper(input, week, weekday, dow, doy) {
    var weeksTarget;
    if (input == null) {
        return weekOfYear(this, dow, doy).year;
    } else {
        weeksTarget = weeksInYear(input, dow, doy);
        if (week > weeksTarget) {
            week = weeksTarget;
        }
        return setWeekAll.call(this, input, week, weekday, dow, doy);
    }
}

function setWeekAll(weekYear, week, weekday, dow, doy) {
    var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
        date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);

    this.year(date.getUTCFullYear());
    this.month(date.getUTCMonth());
    this.date(date.getUTCDate());
    return this;
}

// FORMATTING

addFormatToken('Q', 0, 'Qo', 'quarter');

// PARSING

addRegexToken('Q', match1);
addParseToken('Q', function (input, array) {
    array[MONTH] = (toInt(input) - 1) * 3;
});

// MOMENTS

function getSetQuarter(input) {
    return input == null
        ? Math.ceil((this.month() + 1) / 3)
        : this.month((input - 1) * 3 + (this.month() % 3));
}

// FORMATTING

addFormatToken('D', ['DD', 2], 'Do', 'date');

// PARSING

addRegexToken('D', match1to2, match1to2NoLeadingZero);
addRegexToken('DD', match1to2, match2);
addRegexToken('Do', function (isStrict, locale) {
    // TODO: Remove "ordinalParse" fallback in next major release.
    return isStrict
        ? locale._dayOfMonthOrdinalParse || locale._ordinalParse
        : locale._dayOfMonthOrdinalParseLenient;
});

addParseToken(['D', 'DD'], DATE);
addParseToken('Do', function (input, array) {
    array[DATE] = toInt(input.match(match1to2)[0]);
});

// MOMENTS

var getSetDayOfMonth = makeGetSet('Date', true);

// FORMATTING

addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');

// PARSING

addRegexToken('DDD', match1to3);
addRegexToken('DDDD', match3);
addParseToken(['DDD', 'DDDD'], function (input, array, config) {
    config._dayOfYear = toInt(input);
});

// HELPERS

// MOMENTS

function getSetDayOfYear(input) {
    var dayOfYear =
        Math.round(
            (this.clone().startOf('day') - this.clone().startOf('year')) / 864e5
        ) + 1;
    return input == null ? dayOfYear : this.add(input - dayOfYear, 'd');
}

// FORMATTING

addFormatToken('m', ['mm', 2], 0, 'minute');

// PARSING

addRegexToken('m', match1to2, match1to2HasZero);
addRegexToken('mm', match1to2, match2);
addParseToken(['m', 'mm'], MINUTE);

// MOMENTS

var getSetMinute = makeGetSet('Minutes', false);

// FORMATTING

addFormatToken('s', ['ss', 2], 0, 'second');

// PARSING

addRegexToken('s', match1to2, match1to2HasZero);
addRegexToken('ss', match1to2, match2);
addParseToken(['s', 'ss'], SECOND);

// MOMENTS

var getSetSecond = makeGetSet('Seconds', false);

// FORMATTING

addFormatToken('S', 0, 0, function () {
    return ~~(this.millisecond() / 100);
});

addFormatToken(0, ['SS', 2], 0, function () {
    return ~~(this.millisecond() / 10);
});

addFormatToken(0, ['SSS', 3], 0, 'millisecond');
addFormatToken(0, ['SSSS', 4], 0, function () {
    return this.millisecond() * 10;
});
addFormatToken(0, ['SSSSS', 5], 0, function () {
    return this.millisecond() * 100;
});
addFormatToken(0, ['SSSSSS', 6], 0, function () {
    return this.millisecond() * 1000;
});
addFormatToken(0, ['SSSSSSS', 7], 0, function () {
    return this.millisecond() * 10000;
});
addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
    return this.millisecond() * 100000;
});
addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
    return this.millisecond() * 1000000;
});

// PARSING

addRegexToken('S', match1to3, match1);
addRegexToken('SS', match1to3, match2);
addRegexToken('SSS', match1to3, match3);

var token, getSetMillisecond;
for (token = 'SSSS'; token.length <= 9; token += 'S') {
    addRegexToken(token, matchUnsigned);
}

function parseMs(input, array) {
    array[MILLISECOND] = toInt(('0.' + input) * 1000);
}

for (token = 'S'; token.length <= 9; token += 'S') {
    addParseToken(token, parseMs);
}

getSetMillisecond = makeGetSet('Milliseconds', false);

// FORMATTING

addFormatToken('z', 0, 0, 'zoneAbbr');
addFormatToken('zz', 0, 0, 'zoneName');

// MOMENTS

function getZoneAbbr() {
    return this._isUTC ? 'UTC' : '';
}

function getZoneName() {
    return this._isUTC ? 'Coordinated Universal Time' : '';
}

var proto = Moment.prototype;

proto.add = add;
proto.calendar = calendar$1;
proto.clone = clone;
proto.diff = diff;
proto.endOf = endOf;
proto.format = format;
proto.from = from;
proto.fromNow = fromNow;
proto.to = to;
proto.toNow = toNow;
proto.get = stringGet;
proto.invalidAt = invalidAt;
proto.isAfter = isAfter;
proto.isBefore = isBefore;
proto.isBetween = isBetween;
proto.isSame = isSame;
proto.isSameOrAfter = isSameOrAfter;
proto.isSameOrBefore = isSameOrBefore;
proto.isValid = isValid$2;
proto.lang = lang;
proto.locale = locale;
proto.localeData = localeData;
proto.max = prototypeMax;
proto.min = prototypeMin;
proto.parsingFlags = parsingFlags;
proto.set = stringSet;
proto.startOf = startOf;
proto.subtract = subtract;
proto.toArray = toArray;
proto.toObject = toObject;
proto.toDate = toDate;
proto.toISOString = toISOString;
proto.inspect = inspect;
if (typeof Symbol !== 'undefined' && Symbol.for != null) {
    proto[Symbol.for('nodejs.util.inspect.custom')] = function () {
        return 'Moment<' + this.format() + '>';
    };
}
proto.toJSON = toJSON;
proto.toString = toString;
proto.unix = unix;
proto.valueOf = valueOf;
proto.creationData = creationData;
proto.eraName = getEraName;
proto.eraNarrow = getEraNarrow;
proto.eraAbbr = getEraAbbr;
proto.eraYear = getEraYear;
proto.year = getSetYear;
proto.isLeapYear = getIsLeapYear;
proto.weekYear = getSetWeekYear;
proto.isoWeekYear = getSetISOWeekYear;
proto.quarter = proto.quarters = getSetQuarter;
proto.month = getSetMonth;
proto.daysInMonth = getDaysInMonth;
proto.week = proto.weeks = getSetWeek;
proto.isoWeek = proto.isoWeeks = getSetISOWeek;
proto.weeksInYear = getWeeksInYear;
proto.weeksInWeekYear = getWeeksInWeekYear;
proto.isoWeeksInYear = getISOWeeksInYear;
proto.isoWeeksInISOWeekYear = getISOWeeksInISOWeekYear;
proto.date = getSetDayOfMonth;
proto.day = proto.days = getSetDayOfWeek;
proto.weekday = getSetLocaleDayOfWeek;
proto.isoWeekday = getSetISODayOfWeek;
proto.dayOfYear = getSetDayOfYear;
proto.hour = proto.hours = getSetHour;
proto.minute = proto.minutes = getSetMinute;
proto.second = proto.seconds = getSetSecond;
proto.millisecond = proto.milliseconds = getSetMillisecond;
proto.utcOffset = getSetOffset;
proto.utc = setOffsetToUTC;
proto.local = setOffsetToLocal;
proto.parseZone = setOffsetToParsedOffset;
proto.hasAlignedHourOffset = hasAlignedHourOffset;
proto.isDST = isDaylightSavingTime;
proto.isLocal = isLocal;
proto.isUtcOffset = isUtcOffset;
proto.isUtc = isUtc;
proto.isUTC = isUtc;
proto.zoneAbbr = getZoneAbbr;
proto.zoneName = getZoneName;
proto.dates = deprecate(
    'dates accessor is deprecated. Use date instead.',
    getSetDayOfMonth
);
proto.months = deprecate(
    'months accessor is deprecated. Use month instead',
    getSetMonth
);
proto.years = deprecate(
    'years accessor is deprecated. Use year instead',
    getSetYear
);
proto.zone = deprecate(
    'moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/',
    getSetZone
);
proto.isDSTShifted = deprecate(
    'isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information',
    isDaylightSavingTimeShifted
);

function createUnix(input) {
    return createLocal(input * 1000);
}

function createInZone() {
    return createLocal.apply(null, arguments).parseZone();
}

function preParsePostFormat(string) {
    return string;
}

var proto$1 = Locale.prototype;

proto$1.calendar = calendar;
proto$1.longDateFormat = longDateFormat;
proto$1.invalidDate = invalidDate;
proto$1.ordinal = ordinal;
proto$1.preparse = preParsePostFormat;
proto$1.postformat = preParsePostFormat;
proto$1.relativeTime = relativeTime;
proto$1.pastFuture = pastFuture;
proto$1.set = set;
proto$1.eras = localeEras;
proto$1.erasParse = localeErasParse;
proto$1.erasConvertYear = localeErasConvertYear;
proto$1.erasAbbrRegex = erasAbbrRegex;
proto$1.erasNameRegex = erasNameRegex;
proto$1.erasNarrowRegex = erasNarrowRegex;

proto$1.months = localeMonths;
proto$1.monthsShort = localeMonthsShort;
proto$1.monthsParse = localeMonthsParse;
proto$1.monthsRegex = monthsRegex;
proto$1.monthsShortRegex = monthsShortRegex;
proto$1.week = localeWeek;
proto$1.firstDayOfYear = localeFirstDayOfYear;
proto$1.firstDayOfWeek = localeFirstDayOfWeek;

proto$1.weekdays = localeWeekdays;
proto$1.weekdaysMin = localeWeekdaysMin;
proto$1.weekdaysShort = localeWeekdaysShort;
proto$1.weekdaysParse = localeWeekdaysParse;

proto$1.weekdaysRegex = weekdaysRegex;
proto$1.weekdaysShortRegex = weekdaysShortRegex;
proto$1.weekdaysMinRegex = weekdaysMinRegex;

proto$1.isPM = localeIsPM;
proto$1.meridiem = localeMeridiem;

function get$1(format, index, field, setter) {
    var locale = getLocale(),
        utc = createUTC().set(setter, index);
    return locale[field](utc, format);
}

function listMonthsImpl(format, index, field) {
    if (isNumber(format)) {
        index = format;
        format = undefined;
    }

    format = format || '';

    if (index != null) {
        return get$1(format, index, field, 'month');
    }

    var i,
        out = [];
    for (i = 0; i < 12; i++) {
        out[i] = get$1(format, i, field, 'month');
    }
    return out;
}

// ()
// (5)
// (fmt, 5)
// (fmt)
// (true)
// (true, 5)
// (true, fmt, 5)
// (true, fmt)
function listWeekdaysImpl(localeSorted, format, index, field) {
    if (typeof localeSorted === 'boolean') {
        if (isNumber(format)) {
            index = format;
            format = undefined;
        }

        format = format || '';
    } else {
        format = localeSorted;
        index = format;
        localeSorted = false;

        if (isNumber(format)) {
            index = format;
            format = undefined;
        }

        format = format || '';
    }

    var locale = getLocale(),
        shift = localeSorted ? locale._week.dow : 0,
        i,
        out = [];

    if (index != null) {
        return get$1(format, (index + shift) % 7, field, 'day');
    }

    for (i = 0; i < 7; i++) {
        out[i] = get$1(format, (i + shift) % 7, field, 'day');
    }
    return out;
}

function listMonths(format, index) {
    return listMonthsImpl(format, index, 'months');
}

function listMonthsShort(format, index) {
    return listMonthsImpl(format, index, 'monthsShort');
}

function listWeekdays(localeSorted, format, index) {
    return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
}

function listWeekdaysShort(localeSorted, format, index) {
    return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
}

function listWeekdaysMin(localeSorted, format, index) {
    return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
}

getSetGlobalLocale('en', {
    eras: [
        {
            since: '0001-01-01',
            until: +Infinity,
            offset: 1,
            name: 'Anno Domini',
            narrow: 'AD',
            abbr: 'AD',
        },
        {
            since: '0000-12-31',
            until: -Infinity,
            offset: 1,
            name: 'Before Christ',
            narrow: 'BC',
            abbr: 'BC',
        },
    ],
    dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
    ordinal: function (number) {
        var b = number % 10,
            output =
                toInt((number % 100) / 10) === 1
                    ? 'th'
                    : b === 1
                      ? 'st'
                      : b === 2
                        ? 'nd'
                        : b === 3
                          ? 'rd'
                          : 'th';
        return number + output;
    },
});

// Side effect imports

hooks.lang = deprecate(
    'moment.lang is deprecated. Use moment.locale instead.',
    getSetGlobalLocale
);
hooks.langData = deprecate(
    'moment.langData is deprecated. Use moment.localeData instead.',
    getLocale
);

var mathAbs = Math.abs;

function abs() {
    var data = this._data;

    this._milliseconds = mathAbs(this._milliseconds);
    this._days = mathAbs(this._days);
    this._months = mathAbs(this._months);

    data.milliseconds = mathAbs(data.milliseconds);
    data.seconds = mathAbs(data.seconds);
    data.minutes = mathAbs(data.minutes);
    data.hours = mathAbs(data.hours);
    data.months = mathAbs(data.months);
    data.years = mathAbs(data.years);

    return this;
}

function addSubtract$1(duration, input, value, direction) {
    var other = createDuration(input, value);

    duration._milliseconds += direction * other._milliseconds;
    duration._days += direction * other._days;
    duration._months += direction * other._months;

    return duration._bubble();
}

// supports only 2.0-style add(1, 's') or add(duration)
function add$1(input, value) {
    return addSubtract$1(this, input, value, 1);
}

// supports only 2.0-style subtract(1, 's') or subtract(duration)
function subtract$1(input, value) {
    return addSubtract$1(this, input, value, -1);
}

function absCeil(number) {
    if (number < 0) {
        return Math.floor(number);
    } else {
        return Math.ceil(number);
    }
}

function bubble() {
    var milliseconds = this._milliseconds,
        days = this._days,
        months = this._months,
        data = this._data,
        seconds,
        minutes,
        hours,
        years,
        monthsFromDays;

    // if we have a mix of positive and negative values, bubble down first
    // check: https://github.com/moment/moment/issues/2166
    if (
        !(
            (milliseconds >= 0 && days >= 0 && months >= 0) ||
            (milliseconds <= 0 && days <= 0 && months <= 0)
        )
    ) {
        milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
        days = 0;
        months = 0;
    }

    // The following code bubbles up values, see the tests for
    // examples of what that means.
    data.milliseconds = milliseconds % 1000;

    seconds = absFloor(milliseconds / 1000);
    data.seconds = seconds % 60;

    minutes = absFloor(seconds / 60);
    data.minutes = minutes % 60;

    hours = absFloor(minutes / 60);
    data.hours = hours % 24;

    days += absFloor(hours / 24);

    // convert days to months
    monthsFromDays = absFloor(daysToMonths(days));
    months += monthsFromDays;
    days -= absCeil(monthsToDays(monthsFromDays));

    // 12 months -> 1 year
    years = absFloor(months / 12);
    months %= 12;

    data.days = days;
    data.months = months;
    data.years = years;

    return this;
}

function daysToMonths(days) {
    // 400 years have 146097 days (taking into account leap year rules)
    // 400 years have 12 months === 4800
    return (days * 4800) / 146097;
}

function monthsToDays(months) {
    // the reverse of daysToMonths
    return (months * 146097) / 4800;
}

function as(units) {
    if (!this.isValid()) {
        return NaN;
    }
    var days,
        months,
        milliseconds = this._milliseconds;

    units = normalizeUnits(units);

    if (units === 'month' || units === 'quarter' || units === 'year') {
        days = this._days + milliseconds / 864e5;
        months = this._months + daysToMonths(days);
        switch (units) {
            case 'month':
                return months;
            case 'quarter':
                return months / 3;
            case 'year':
                return months / 12;
        }
    } else {
        // handle milliseconds separately because of floating point math errors (issue #1867)
        days = this._days + Math.round(monthsToDays(this._months));
        switch (units) {
            case 'week':
                return days / 7 + milliseconds / 6048e5;
            case 'day':
                return days + milliseconds / 864e5;
            case 'hour':
                return days * 24 + milliseconds / 36e5;
            case 'minute':
                return days * 1440 + milliseconds / 6e4;
            case 'second':
                return days * 86400 + milliseconds / 1000;
            // Math.floor prevents floating point math errors here
            case 'millisecond':
                return Math.floor(days * 864e5) + milliseconds;
            default:
                throw new Error('Unknown unit ' + units);
        }
    }
}

function makeAs(alias) {
    return function () {
        return this.as(alias);
    };
}

var asMilliseconds = makeAs('ms'),
    asSeconds = makeAs('s'),
    asMinutes = makeAs('m'),
    asHours = makeAs('h'),
    asDays = makeAs('d'),
    asWeeks = makeAs('w'),
    asMonths = makeAs('M'),
    asQuarters = makeAs('Q'),
    asYears = makeAs('y'),
    valueOf$1 = asMilliseconds;

function clone$1() {
    return createDuration(this);
}

function get$2(units) {
    units = normalizeUnits(units);
    return this.isValid() ? this[units + 's']() : NaN;
}

function makeGetter(name) {
    return function () {
        return this.isValid() ? this._data[name] : NaN;
    };
}

var milliseconds = makeGetter('milliseconds'),
    seconds = makeGetter('seconds'),
    minutes = makeGetter('minutes'),
    hours = makeGetter('hours'),
    days = makeGetter('days'),
    months = makeGetter('months'),
    years = makeGetter('years');

function weeks() {
    return absFloor(this.days() / 7);
}

var round = Math.round,
    thresholds = {
        ss: 44, // a few seconds to seconds
        s: 45, // seconds to minute
        m: 45, // minutes to hour
        h: 22, // hours to day
        d: 26, // days to month/week
        w: null, // weeks to month
        M: 11, // months to year
    };

// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
    return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
}

function relativeTime$1(posNegDuration, withoutSuffix, thresholds, locale) {
    var duration = createDuration(posNegDuration).abs(),
        seconds = round(duration.as('s')),
        minutes = round(duration.as('m')),
        hours = round(duration.as('h')),
        days = round(duration.as('d')),
        months = round(duration.as('M')),
        weeks = round(duration.as('w')),
        years = round(duration.as('y')),
        a =
            (seconds <= thresholds.ss && ['s', seconds]) ||
            (seconds < thresholds.s && ['ss', seconds]) ||
            (minutes <= 1 && ['m']) ||
            (minutes < thresholds.m && ['mm', minutes]) ||
            (hours <= 1 && ['h']) ||
            (hours < thresholds.h && ['hh', hours]) ||
            (days <= 1 && ['d']) ||
            (days < thresholds.d && ['dd', days]);

    if (thresholds.w != null) {
        a =
            a ||
            (weeks <= 1 && ['w']) ||
            (weeks < thresholds.w && ['ww', weeks]);
    }
    a = a ||
        (months <= 1 && ['M']) ||
        (months < thresholds.M && ['MM', months]) ||
        (years <= 1 && ['y']) || ['yy', years];

    a[2] = withoutSuffix;
    a[3] = +posNegDuration > 0;
    a[4] = locale;
    return substituteTimeAgo.apply(null, a);
}

// This function allows you to set the rounding function for relative time strings
function getSetRelativeTimeRounding(roundingFunction) {
    if (roundingFunction === undefined) {
        return round;
    }
    if (typeof roundingFunction === 'function') {
        round = roundingFunction;
        return true;
    }
    return false;
}

// This function allows you to set a threshold for relative time strings
function getSetRelativeTimeThreshold(threshold, limit) {
    if (thresholds[threshold] === undefined) {
        return false;
    }
    if (limit === undefined) {
        return thresholds[threshold];
    }
    thresholds[threshold] = limit;
    if (threshold === 's') {
        thresholds.ss = limit - 1;
    }
    return true;
}

function humanize(argWithSuffix, argThresholds) {
    if (!this.isValid()) {
        return this.localeData().invalidDate();
    }

    var withSuffix = false,
        th = thresholds,
        locale,
        output;

    if (typeof argWithSuffix === 'object') {
        argThresholds = argWithSuffix;
        argWithSuffix = false;
    }
    if (typeof argWithSuffix === 'boolean') {
        withSuffix = argWithSuffix;
    }
    if (typeof argThresholds === 'object') {
        th = Object.assign({}, thresholds, argThresholds);
        if (argThresholds.s != null && argThresholds.ss == null) {
            th.ss = argThresholds.s - 1;
        }
    }

    locale = this.localeData();
    output = relativeTime$1(this, !withSuffix, th, locale);

    if (withSuffix) {
        output = locale.pastFuture(+this, output);
    }

    return locale.postformat(output);
}

var abs$1 = Math.abs;

function sign(x) {
    return (x > 0) - (x < 0) || +x;
}

function toISOString$1() {
    // for ISO strings we do not use the normal bubbling rules:
    //  * milliseconds bubble up until they become hours
    //  * days do not bubble at all
    //  * months bubble up until they become years
    // This is because there is no context-free conversion between hours and days
    // (think of clock changes)
    // and also not between days and months (28-31 days per month)
    if (!this.isValid()) {
        return this.localeData().invalidDate();
    }

    var seconds = abs$1(this._milliseconds) / 1000,
        days = abs$1(this._days),
        months = abs$1(this._months),
        minutes,
        hours,
        years,
        s,
        total = this.asSeconds(),
        totalSign,
        ymSign,
        daysSign,
        hmsSign;

    if (!total) {
        // this is the same as C#'s (Noda) and python (isodate)...
        // but not other JS (goog.date)
        return 'P0D';
    }

    // 3600 seconds -> 60 minutes -> 1 hour
    minutes = absFloor(seconds / 60);
    hours = absFloor(minutes / 60);
    seconds %= 60;
    minutes %= 60;

    // 12 months -> 1 year
    years = absFloor(months / 12);
    months %= 12;

    // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
    s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';

    totalSign = total < 0 ? '-' : '';
    ymSign = sign(this._months) !== sign(total) ? '-' : '';
    daysSign = sign(this._days) !== sign(total) ? '-' : '';
    hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';

    return (
        totalSign +
        'P' +
        (years ? ymSign + years + 'Y' : '') +
        (months ? ymSign + months + 'M' : '') +
        (days ? daysSign + days + 'D' : '') +
        (hours || minutes || seconds ? 'T' : '') +
        (hours ? hmsSign + hours + 'H' : '') +
        (minutes ? hmsSign + minutes + 'M' : '') +
        (seconds ? hmsSign + s + 'S' : '')
    );
}

var proto$2 = Duration.prototype;

proto$2.isValid = isValid$1;
proto$2.abs = abs;
proto$2.add = add$1;
proto$2.subtract = subtract$1;
proto$2.as = as;
proto$2.asMilliseconds = asMilliseconds;
proto$2.asSeconds = asSeconds;
proto$2.asMinutes = asMinutes;
proto$2.asHours = asHours;
proto$2.asDays = asDays;
proto$2.asWeeks = asWeeks;
proto$2.asMonths = asMonths;
proto$2.asQuarters = asQuarters;
proto$2.asYears = asYears;
proto$2.valueOf = valueOf$1;
proto$2._bubble = bubble;
proto$2.clone = clone$1;
proto$2.get = get$2;
proto$2.milliseconds = milliseconds;
proto$2.seconds = seconds;
proto$2.minutes = minutes;
proto$2.hours = hours;
proto$2.days = days;
proto$2.weeks = weeks;
proto$2.months = months;
proto$2.years = years;
proto$2.humanize = humanize;
proto$2.toISOString = toISOString$1;
proto$2.toString = toISOString$1;
proto$2.toJSON = toISOString$1;
proto$2.locale = locale;
proto$2.localeData = localeData;

proto$2.toIsoString = deprecate(
    'toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)',
    toISOString$1
);
proto$2.lang = lang;

// FORMATTING

addFormatToken('X', 0, 0, 'unix');
addFormatToken('x', 0, 0, 'valueOf');

// PARSING

addRegexToken('x', matchSigned);
addRegexToken('X', matchTimestamp);
addParseToken('X', function (input, array, config) {
    config._d = new Date(parseFloat(input) * 1000);
});
addParseToken('x', function (input, array, config) {
    config._d = new Date(toInt(input));
});

//! moment.js

hooks.version = '2.30.1';

setHookCallback(createLocal);

hooks.fn = proto;
hooks.min = min;
hooks.max = max;
hooks.now = now;
hooks.utc = createUTC;
hooks.unix = createUnix;
hooks.months = listMonths;
hooks.isDate = isDate;
hooks.locale = getSetGlobalLocale;
hooks.invalid = createInvalid;
hooks.duration = createDuration;
hooks.isMoment = isMoment;
hooks.weekdays = listWeekdays;
hooks.parseZone = createInZone;
hooks.localeData = getLocale;
hooks.isDuration = isDuration;
hooks.monthsShort = listMonthsShort;
hooks.weekdaysMin = listWeekdaysMin;
hooks.defineLocale = defineLocale;
hooks.updateLocale = updateLocale;
hooks.locales = listLocales;
hooks.weekdaysShort = listWeekdaysShort;
hooks.normalizeUnits = normalizeUnits;
hooks.relativeTimeRounding = getSetRelativeTimeRounding;
hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
hooks.calendarFormat = getCalendarFormat;
hooks.prototype = proto;

// currently HTML5 input type only supports 24-hour formats
hooks.HTML5_FMT = {
    DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm', // <input type="datetime-local" />
    DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss', // <input type="datetime-local" step="1" />
    DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS', // <input type="datetime-local" step="0.001" />
    DATE: 'YYYY-MM-DD', // <input type="date" />
    TIME: 'HH:mm', // <input type="time" />
    TIME_SECONDS: 'HH:mm:ss', // <input type="time" step="1" />
    TIME_MS: 'HH:mm:ss.SSS', // <input type="time" step="0.001" />
    WEEK: 'GGGG-[W]WW', // <input type="week" />
    MONTH: 'YYYY-MM', // <input type="month" />
};

export default hooks;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          /*
 * xpath.js
 *
 * An XPath 1.0 library for JavaScript.
 *
 * Cameron McCormack <cam (at) mcc.id.au>
 *
 * This work is licensed under the MIT License.
 *
 * Revision 20: April 26, 2011
 *   Fixed a typo resulting in FIRST_ORDERED_NODE_TYPE results being wrong,
 *   thanks to <shi_a009 (at) hotmail.com>.
 *
 * Revision 19: November 29, 2005
 *   Nodesets now store their nodes in a height balanced tree, increasing
 *   performance for the common case of selecting nodes in document order,
 *   thanks to Sébastien Cramatte <contact (at) zeninteractif.com>.
 *   AVL tree code adapted from Raimund Neumann <rnova (at) gmx.net>.
 *
 * Revision 18: October 27, 2005
 *   DOM 3 XPath support.  Caveats:
 *     - namespace prefixes aren't resolved in XPathEvaluator.createExpression,
 *       but in XPathExpression.evaluate.
 *     - XPathResult.invalidIteratorState is not implemented.
 *
 * Revision 17: October 25, 2005
 *   Some core XPath function fixes and a patch to avoid crashing certain
 *   versions of MSXML in PathExpr.prototype.getOwnerElement, thanks to
 *   Sébastien Cramatte <contact (at) zeninteractif.com>.
 *
 * Revision 16: September 22, 2005
 *   Workarounds for some IE 5.5 deficiencies.
 *   Fixed problem with prefix node tests on attribute nodes.
 *
 * Revision 15: May 21, 2005
 *   Fixed problem with QName node tests on elements with an xmlns="...".
 *
 * Revision 14: May 19, 2005
 *   Fixed QName node tests on attribute node regression.
 *
 * Revision 13: May 3, 2005
 *   Node tests are case insensitive now if working in an HTML DOM.
 *
 * Revision 12: April 26, 2005
 *   Updated licence.  Slight code changes to enable use of Dean
 *   Edwards' script compression, http://dean.edwards.name/packer/ .
 *
 * Revision 11: April 23, 2005
 *   Fixed bug with 'and' and 'or' operators, fix thanks to
 *   Sandy McArthur <sandy (at) mcarthur.org>.
 *
 * Revision 10: April 15, 2005
 *   Added support for a virtual root node, supposedly helpful for
 *   implementing XForms.  Fixed problem with QName node tests and
 *   the parent axis.
 *
 * Revision 9: March 17, 2005
 *   Namespace resolver tweaked so using the document node as the context
 *   for namespace lookups is equivalent to using the document element.
 *
 * Revision 8: February 13, 2005
 *   Handle implicit declaration of 'xmlns' namespace prefix.
 *   Fixed bug when comparing nodesets.
 *   Instance data can now be associated with a FunctionResolver, and
 *     workaround for MSXML not supporting 'localName' and 'getElementById',
 *     thanks to Grant Gongaware.
 *   Fix a few problems when the context node is the root node.
 *
 * Revision 7: February 11, 2005
 *   Default namespace resolver fix from Grant Gongaware
 *   <grant (at) gongaware.com>.
 *
 * Revision 6: February 10, 2005
 *   Fixed bug in 'number' function.
 *
 * Revision 5: February 9, 2005
 *   Fixed bug where text nodes not getting converted to string values.
 *
 * Revision 4: January 21, 2005
 *   Bug in 'name' function, fix thanks to Bill Edney.
 *   Fixed incorrect processing of namespace nodes.
 *   Fixed NamespaceResolver to resolve 'xml' namespace.
 *   Implemented union '|' operator.
 *
 * Revision 3: January 14, 2005
 *   Fixed bug with nodeset comparisons, bug lexing < and >.
 *
 * Revision 2: October 26, 2004
 *   QName node test namespace handling fixed.  Few other bug fixes.
 *
 * Revision 1: August 13, 2004
 *   Bug fixes from William J. Edney <bedney (at) technicalpursuit.com>.
 *   Added minimal licence.
 *
 * Initial version: June 14, 2004
 */

// non-node wrapper
var xpath = (typeof exports === 'undefined') ? {} : exports;

(function (exports) {
    "use strict";

    // functional helpers
    function curry(func) {
        var slice = Array.prototype.slice,
            totalargs = func.length,
            partial = function (args, fn) {
                return function () {
                    return fn.apply(this, args.concat(slice.call(arguments)));
                }
            },
            fn = function () {
                var args = slice.call(arguments);
                return (args.length < totalargs) ?
                    partial(args, fn) :
                    func.apply(this, slice.apply(arguments, [0, totalargs]));
            };
        return fn;
    }

    var forEach = function (f, xs) {
        for (var i = 0; i < xs.length; i += 1) {
            f(xs[i], i, xs);
        }
    };

    var reduce = function (f, seed, xs) {
        var acc = seed;

        forEach(function (x, i) { acc = f(acc, x, i); }, xs);

        return acc;
    };

    var map = function (f, xs) {
        var mapped = new Array(xs.length);

        forEach(function (x, i) { mapped[i] = f(x); }, xs);

        return mapped;
    };

    var filter = function (f, xs) {
        var filtered = [];

        forEach(function (x, i) { if (f(x, i)) { filtered.push(x); } }, xs);

        return filtered;
    };

    var includes = function (values, value) {
        for (var i = 0; i < values.length; i += 1) {
            if (values[i] === value) {
                return true;
            }
        }

        return false;
    };

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

    function toString(x) { return x.toString(); }
    var join = function (s, xs) { return xs.join(s); };
    var wrap = function (pref, suf, str) { return pref + str + suf; };

    var prototypeConcat = Array.prototype.concat;

    // .apply() fails above a certain number of arguments - https://github.com/goto100/xpath/pull/98
    var MAX_ARGUMENT_LENGTH = 32767;

    function flatten(arr) {
        var result = [];

        for (var start = 0; start < arr.length; start += MAX_ARGUMENT_LENGTH) {
            var chunk = arr.slice(start, start + MAX_ARGUMENT_LENGTH);
            
            result = prototypeConcat.apply(result, chunk);
        }
        
        return result;
    }

    function assign(target, varArgs) { // .length of function is 2
        var to = Object(target);

        for (var index = 1; index < arguments.length; index++) {
            var nextSource = arguments[index];

            if (nextSource != null) { // Skip over if undefined or null
                for (var nextKey in nextSource) {
                    // Avoid bugs when hasOwnProperty is shadowed
                    if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
                        to[nextKey] = nextSource[nextKey];
                    }
                }
            }
        }

        return to;
    }

    var NodeTypes = {
        ELEMENT_NODE: 1,
        ATTRIBUTE_NODE: 2,
        TEXT_NODE: 3,
        CDATA_SECTION_NODE: 4,
        PROCESSING_INSTRUCTION_NODE: 7,
        COMMENT_NODE: 8,
        DOCUMENT_NODE: 9,
        DOCUMENT_TYPE_NODE: 10,
        DOCUMENT_FRAGMENT_NODE: 11,
    };

    // XPathParser ///////////////////////////////////////////////////////////////

    XPathParser.prototype = new Object();
    XPathParser.prototype.constructor = XPathParser;
    XPathParser.superclass = Object.prototype;

    function XPathParser() {
        this.init();
    }

    XPathParser.prototype.init = function () {
        this.reduceActions = [];

        this.reduceActions[3] = function (rhs) {
            return new OrOperation(rhs[0], rhs[2]);
        };
        this.reduceActions[5] = function (rhs) {
            return new AndOperation(rhs[0], rhs[2]);
        };
        this.reduceActions[7] = function (rhs) {
            return new EqualsOperation(rhs[0], rhs[2]);
        };
        this.reduceActions[8] = function (rhs) {
            return new NotEqualOperation(rhs[0], rhs[2]);
        };
        this.reduceActions[10] = function (rhs) {
            return new LessThanOperation(rhs[0], rhs[2]);
        };
        this.reduceActions[11] = function (rhs) {
            return new GreaterThanOperation(rhs[0], rhs[2]);
        };
        this.reduceActions[12] = function (rhs) {
            return new LessThanOrEqualOperation(rhs[0], rhs[2]);
        };
        this.reduceActions[13] = function (rhs) {
            return new GreaterThanOrEqualOperation(rhs[0], rhs[2]);
        };
        this.reduceActions[15] = function (rhs) {
            return new PlusOperation(rhs[0], rhs[2]);
        };
        this.reduceActions[16] = function (rhs) {
            return new MinusOperation(rhs[0], rhs[2]);
        };
        this.reduceActions[18] = function (rhs) {
            return new MultiplyOperation(rhs[0], rhs[2]);
        };
        this.reduceActions[19] = function (rhs) {
            return new DivOperation(rhs[0], rhs[2]);
        };
        this.reduceActions[20] = function (rhs) {
            return new ModOperation(rhs[0], rhs[2]);
        };
        this.reduceActions[22] = function (rhs) {
            return new UnaryMinusOperation(rhs[1]);
        };
        this.reduceActions[24] = function (rhs) {
            return new BarOperation(rhs[0], rhs[2]);
        };
        this.reduceActions[25] = function (rhs) {
            return new PathExpr(undefined, undefined, rhs[0]);
        };
        this.reduceActions[27] = function (rhs) {
            rhs[0].locationPath = rhs[2];
            return rhs[0];
        };
        this.reduceActions[28] = function (rhs) {
            rhs[0].locationPath = rhs[2];
            rhs[0].locationPath.steps.unshift(new Step(Step.DESCENDANTORSELF, NodeTest.nodeTest, []));
            return rhs[0];
        };
        this.reduceActions[29] = function (rhs) {
            return new PathExpr(rhs[0], [], undefined);
        };
        this.reduceActions[30] = function (rhs) {
            if (Utilities.instance_of(rhs[0], PathExpr)) {
                if (rhs[0].filterPredicates == undefined) {
                    rhs[0].filterPredicates = [];
                }
                rhs[0].filterPredicates.push(rhs[1]);
                return rhs[0];
            } else {
                return new PathExpr(rhs[0], [rhs[1]], undefined);
            }
        };
        this.reduceActions[32] = function (rhs) {
            return rhs[1];
        };
        this.reduceActions[33] = function (rhs) {
            return new XString(rhs[0]);
        };
        this.reduceActions[34] = function (rhs) {
            return new XNumber(rhs[0]);
        };
        this.reduceActions[36] = function (rhs) {
            return new FunctionCall(rhs[0], []);
        };
        this.reduceActions[37] = function (rhs) {
            return new FunctionCall(rhs[0], rhs[2]);
        };
        this.reduceActions[38] = function (rhs) {
            return [rhs[0]];
        };
        this.reduceActions[39] = function (rhs) {
            rhs[2].unshift(rhs[0]);
            return rhs[2];
        };
        this.reduceActions[43] = function (rhs) {
            return new LocationPath(true, []);
        };
        this.reduceActions[44] = function (rhs) {
            rhs[1].absolute = true;
            return rhs[1];
        };
        this.reduceActions[46] = function (rhs) {
            return new LocationPath(false, [rhs[0]]);
        };
        this.reduceActions[47] = function (rhs) {
            rhs[0].steps.push(rhs[2]);
            return rhs[0];
        };
        this.reduceActions[49] = function (rhs) {
            return new Step(rhs[0], rhs[1], []);
        };
        this.reduceActions[50] = function (rhs) {
            return new Step(Step.CHILD, rhs[0], []);
        };
        this.reduceActions[51] = function (rhs) {
            return new Step(rhs[0], rhs[1], rhs[2]);
        };
        this.reduceActions[52] = function (rhs) {
            return new Step(Step.CHILD, rhs[0], rhs[1]);
        };
        this.reduceActions[54] = function (rhs) {
            return [rhs[0]];
        };
        this.reduceActions[55] = function (rhs) {
            rhs[1].unshift(rhs[0]);
            return rhs[1];
        };
        this.reduceActions[56] = function (rhs) {
            if (rhs[0] == "ancestor") {
                return Step.ANCESTOR;
            } else if (rhs[0] == "ancestor-or-self") {
                return Step.ANCESTORORSELF;
            } else if (rhs[0] == "attribute") {
                return Step.ATTRIBUTE;
            } else if (rhs[0] == "child") {
                return Step.CHILD;
            } else if (rhs[0] == "descendant") {
                return Step.DESCENDANT;
            } else if (rhs[0] == "descendant-or-self") {
                return Step.DESCENDANTORSELF;
            } else if (rhs[0] == "following") {
                return Step.FOLLOWING;
            } else if (rhs[0] == "following-sibling") {
                return Step.FOLLOWINGSIBLING;
            } else if (rhs[0] == "namespace") {
                return Step.NAMESPACE;
            } else if (rhs[0] == "parent") {
                return Step.PARENT;
            } else if (rhs[0] == "preceding") {
                return Step.PRECEDING;
            } else if (rhs[0] == "preceding-sibling") {
                return Step.PRECEDINGSIBLING;
            } else if (rhs[0] == "self") {
                return Step.SELF;
            }
            return -1;
        };
        this.reduceActions[57] = function (rhs) {
            return Step.ATTRIBUTE;
        };
        this.reduceActions[59] = function (rhs) {
            if (rhs[0] == "comment") {
                return NodeTest.commentTest;
            } else if (rhs[0] == "text") {
                return NodeTest.textTest;
            } else if (rhs[0] == "processing-instruction") {
                return NodeTest.anyPiTest;
            } else if (rhs[0] == "node") {
                return NodeTest.nodeTest;
            }
            return new NodeTest(-1, undefined);
        };
        this.reduceActions[60] = function (rhs) {
            return new NodeTest.PITest(rhs[2]);
        };
        this.reduceActions[61] = function (rhs) {
            return rhs[1];
        };
        this.reduceActions[63] = function (rhs) {
            rhs[1].absolute = true;
            rhs[1].steps.unshift(new Step(Step.DESCENDANTORSELF, NodeTest.nodeTest, []));
            return rhs[1];
        };
        this.reduceActions[64] = function (rhs) {
            rhs[0].steps.push(new Step(Step.DESCENDANTORSELF, NodeTest.nodeTest, []));
            rhs[0].steps.push(rhs[2]);
            return rhs[0];
        };
        this.reduceActions[65] = function (rhs) {
            return new Step(Step.SELF, NodeTest.nodeTest, []);
        };
        this.reduceActions[66] = function (rhs) {
            return new Step(Step.PARENT, NodeTest.nodeTest, []);
        };
        this.reduceActions[67] = function (rhs) {
            return new VariableReference(rhs[1]);
        };
        this.reduceActions[68] = function (rhs) {
            return NodeTest.nameTestAny;
        };
        this.reduceActions[69] = function (rhs) {
            return new NodeTest.NameTestPrefixAny(rhs[0].split(':')[0]);
        };
        this.reduceActions[70] = function (rhs) {
            return new NodeTest.NameTestQName(rhs[0]);
        };
    };

    XPathParser.actionTable = [
        " s s        sssssssss    s ss  s  ss",
        "                 s                  ",
        "r  rrrrrrrrr         rrrrrrr rr  r  ",
        "                rrrrr               ",
        " s s        sssssssss    s ss  s  ss",
        "rs  rrrrrrrr s  sssssrrrrrr  rrs rs ",
        " s s        sssssssss    s ss  s  ss",
        "                            s       ",
        "                            s       ",
        "r  rrrrrrrrr         rrrrrrr rr rr  ",
        "r  rrrrrrrrr         rrrrrrr rr rr  ",
        "r  rrrrrrrrr         rrrrrrr rr rr  ",
        "r  rrrrrrrrr         rrrrrrr rr rr  ",
        "r  rrrrrrrrr         rrrrrrr rr rr  ",
        "  s                                 ",
        "                            s       ",
        " s           s  sssss          s  s ",
        "r  rrrrrrrrr         rrrrrrr rr  r  ",
        "a                                   ",
        "r       s                    rr  r  ",
        "r      sr                    rr  r  ",
        "r   s  rr            s       rr  r  ",
        "r   rssrr            rss     rr  r  ",
        "r   rrrrr            rrrss   rr  r  ",
        "r   rrrrrsss         rrrrr   rr  r  ",
        "r   rrrrrrrr         rrrrr   rr  r  ",
        "r   rrrrrrrr         rrrrrs  rr  r  ",
        "r   rrrrrrrr         rrrrrr  rr  r  ",
        "r   rrrrrrrr         rrrrrr  rr  r  ",
        "r  srrrrrrrr         rrrrrrs rr sr  ",
        "r  srrrrrrrr         rrrrrrs rr  r  ",
        "r  rrrrrrrrr         rrrrrrr rr rr  ",
        "r  rrrrrrrrr         rrrrrrr rr rr  ",
        "r  rrrrrrrrr         rrrrrrr rr rr  ",
        "r   rrrrrrrr         rrrrrr  rr  r  ",
        "r   rrrrrrrr         rrrrrr  rr  r  ",
        "r  rrrrrrrrr         rrrrrrr rr  r  ",
        "r  rrrrrrrrr         rrrrrrr rr  r  ",
        "                sssss               ",
        "r  rrrrrrrrr         rrrrrrr rr sr  ",
        "r  rrrrrrrrr         rrrrrrr rr  r  ",
        "r  rrrrrrrrr         rrrrrrr rr rr  ",
        "r  rrrrrrrrr         rrrrrrr rr rr  ",
        "                             s      ",
        "r  srrrrrrrr         rrrrrrs rr  r  ",
        "r   rrrrrrrr         rrrrr   rr  r  ",
        "              s                     ",
        "                             s      ",
        "                rrrrr               ",
        " s s        sssssssss    s sss s  ss",
        "r  srrrrrrrr         rrrrrrs rr  r  ",
        " s s        sssssssss    s ss  s  ss",
        " s s        sssssssss    s ss  s  ss",
        " s s        sssssssss    s ss  s  ss",
        " s s        sssssssss    s ss  s  ss",
        " s s        sssssssss    s ss  s  ss",
        " s s        sssssssss    s ss  s  ss",
        " s s        sssssssss    s ss  s  ss",
        " s s        sssssssss    s ss  s  ss",
        " s s        sssssssss    s ss  s  ss",
        " s s        sssssssss    s ss  s  ss",
        " s s        sssssssss    s ss  s  ss",
        " s s        sssssssss    s ss  s  ss",
        " s s        sssssssss    s ss  s  ss",
        " s s        sssssssss      ss  s  ss",
        " s s        sssssssss    s ss  s  ss",
        " s           s  sssss          s  s ",
        " s           s  sssss          s  s ",
        "r  rrrrrrrrr         rrrrrrr rr rr  ",
        " s           s  sssss          s  s ",
        " s           s  sssss          s  s ",
        "r  rrrrrrrrr         rrrrrrr rr sr  ",
        "r  rrrrrrrrr         rrrrrrr rr sr  ",
        "r  rrrrrrrrr         rrrrrrr rr  r  ",
        "r  rrrrrrrrr         rrrrrrr rr rr  ",
        "                             s      ",
        "r  rrrrrrrrr         rrrrrrr rr rr  ",
        "r  rrrrrrrrr         rrrrrrr rr rr  ",
        "                             rr     ",
        "                             s      ",
        "                             rs     ",
        "r      sr                    rr  r  ",
        "r   s  rr            s       rr  r  ",
        "r   rssrr            rss     rr  r  ",
        "r   rssrr            rss     rr  r  ",
        "r   rrrrr            rrrss   rr  r  ",
        "r   rrrrr            rrrss   rr  r  ",
        "r   rrrrr            rrrss   rr  r  ",
        "r   rrrrr            rrrss   rr  r  ",
        "r   rrrrrsss         rrrrr   rr  r  ",
        "r   rrrrrsss         rrrrr   rr  r  ",
        "r   rrrrrrrr         rrrrr   rr  r  ",
        "r   rrrrrrrr         rrrrr   rr  r  ",
        "r   rrrrrrrr         rrrrr   rr  r  ",
        "r   rrrrrrrr         rrrrrr  rr  r  ",
        "                                 r  ",
        "                                 s  ",
        "r  srrrrrrrr         rrrrrrs rr  r  ",
        "r  srrrrrrrr         rrrrrrs rr  r  ",
        "r  rrrrrrrrr         rrrrrrr rr  r  ",
        "r  rrrrrrrrr         rrrrrrr rr  r  ",
        "r  rrrrrrrrr         rrrrrrr rr  r  ",
        "r  rrrrrrrrr         rrrrrrr rr  r  ",
        "r  rrrrrrrrr         rrrrrrr rr rr  ",
        "r  rrrrrrrrr         rrrrrrr rr rr  ",
        " s s        sssssssss    s ss  s  ss",
        "r  rrrrrrrrr         rrrrrrr rr rr  ",
        "                             r      "
    ];

    XPathParser.actionTableNumber = [
        " 1 0        /.-,+*)('    & %$  #  \"!",
        "                 J                  ",
        "a  aaaaaaaaa         aaaaaaa aa  a  ",
        "                YYYYY               ",
        " 1 0        /.-,+*)('    & %$  #  \"!",
        "K1  KKKKKKKK .  +*)('KKKKKK  KK# K\" ",
        " 1 0        /.-,+*)('    & %$  #  \"!",
        "                            N       ",
        "                            O       ",
        "e  eeeeeeeee         eeeeeee ee ee  ",
        "f  fffffffff         fffffff ff ff  ",
        "d  ddddddddd         ddddddd dd dd  ",
        "B  BBBBBBBBB         BBBBBBB BB BB  ",
        "A  AAAAAAAAA         AAAAAAA AA AA  ",
        "  P                                 ",
        "                            Q       ",
        " 1           .  +*)('          #  \" ",
        "b  bbbbbbbbb         bbbbbbb bb  b  ",
        "                                    ",
        "!       S                    !!  !  ",
        "\"      T\"                    \"\"  \"  ",
        "$   V  $$            U       $$  $  ",
        "&   &ZY&&            &XW     &&  &  ",
        ")   )))))            )))\\[   ))  )  ",
        ".   ....._^]         .....   ..  .  ",
        "1   11111111         11111   11  1  ",
        "5   55555555         55555`  55  5  ",
        "7   77777777         777777  77  7  ",
        "9   99999999         999999  99  9  ",
        ":  c::::::::         ::::::b :: a:  ",
        "I  fIIIIIIII         IIIIIIe II  I  ",
        "=  =========         ======= == ==  ",
        "?  ?????????         ??????? ?? ??  ",
        "C  CCCCCCCCC         CCCCCCC CC CC  ",
        "J   JJJJJJJJ         JJJJJJ  JJ  J  ",
        "M   MMMMMMMM         MMMMMM  MM  M  ",
        "N  NNNNNNNNN         NNNNNNN NN  N  ",
        "P  PPPPPPPPP         PPPPPPP PP  P  ",
        "                +*)('               ",
        "R  RRRRRRRRR         RRRRRRR RR aR  ",
        "U  UUUUUUUUU         UUUUUUU UU  U  ",
        "Z  ZZZZZZZZZ         ZZZZZZZ ZZ ZZ  ",
        "c  ccccccccc         ccccccc cc cc  ",
        "                             j      ",
        "L  fLLLLLLLL         LLLLLLe LL  L  ",
        "6   66666666         66666   66  6  ",
        "              k                     ",
        "                             l      ",
        "                XXXXX               ",
        " 1 0        /.-,+*)('    & %$m #  \"!",
        "_  f________         ______e __  _  ",
        " 1 0        /.-,+*)('    & %$  #  \"!",
        " 1 0        /.-,+*)('    & %$  #  \"!",
        " 1 0        /.-,+*)('    & %$  #  \"!",
        " 1 0        /.-,+*)('    & %$  #  \"!",
        " 1 0        /.-,+*)('    & %$  #  \"!",
        " 1 0        /.-,+*)('    & %$  #  \"!",
        " 1 0        /.-,+*)('    & %$  #  \"!",
        " 1 0        /.-,+*)('    & %$  #  \"!",
        " 1 0        /.-,+*)('    & %$  #  \"!",
        " 1 0        /.-,+*)('    & %$  #  \"!",
        " 1 0        /.-,+*)('    & %$  #  \"!",
        " 1 0        /.-,+*)('    & %$  #  \"!",
        " 1 0        /.-,+*)('    & %$  #  \"!",
        " 1 0        /.-,+*)('      %$  #  \"!",
        " 1 0        /.-,+*)('    & %$  #  \"!",
        " 1           .  +*)('          #  \" ",
        " 1           .  +*)('          #  \" ",
        ">  >>>>>>>>>         >>>>>>> >> >>  ",
        " 1           .  +*)('          #  \" ",
        " 1           .  +*)('          #  \" ",
        "Q  QQQQQQQQQ         QQQQQQQ QQ aQ  ",
        "V  VVVVVVVVV         VVVVVVV VV aV  ",
        "T  TTTTTTTTT         TTTTTTT TT  T  ",
        "@  @@@@@@@@@         @@@@@@@ @@ @@  ",
        "                             \x87      ",
        "[  [[[[[[[[[         [[[[[[[ [[ [[  ",
        "D  DDDDDDDDD         DDDDDDD DD DD  ",
        "                             HH     ",
        "                             \x88      ",
        "                             F\x89     ",
        "#      T#                    ##  #  ",
        "%   V  %%            U       %%  %  ",
        "'   'ZY''            'XW     ''  '  ",
        "(   (ZY((            (XW     ((  (  ",
        "+   +++++            +++\\[   ++  +  ",
        "*   *****            ***\\[   **  *  ",
        "-   -----            ---\\[   --  -  ",
        ",   ,,,,,            ,,,\\[   ,,  ,  ",
        "0   00000_^]         00000   00  0  ",
        "/   /////_^]         /////   //  /  ",
        "2   22222222         22222   22  2  ",
        "3   33333333         33333   33  3  ",
        "4   44444444         44444   44  4  ",
        "8   88888888         888888  88  8  ",
        "                                 ^  ",
        "                                 \x8a  ",
        ";  f;;;;;;;;         ;;;;;;e ;;  ;  ",
        "<  f<<<<<<<<         <<<<<<e <<  <  ",
        "O  OOOOOOOOO         OOOOOOO OO  O  ",
        "`  `````````         ``````` ``  `  ",
        "S  SSSSSSSSS         SSSSSSS SS  S  ",
        "W  WWWWWWWWW         WWWWWWW WW  W  ",
        "\\  \\\\\\\\\\\\\\\\\\         \\\\\\\\\\\\\\ \\\\ \\\\  ",
        "E  EEEEEEEEE         EEEEEEE EE EE  ",
        " 1 0        /.-,+*)('    & %$  #  \"!",
        "]  ]]]]]]]]]         ]]]]]]] ]] ]]  ",
        "                             G      "
    ];

    XPathParser.gotoTable = [
        "3456789:;<=>?@ AB  CDEFGH IJ ",
        "                             ",
        "                             ",
        "                             ",
        "L456789:;<=>?@ AB  CDEFGH IJ ",
        "            M        EFGH IJ ",
        "       N;<=>?@ AB  CDEFGH IJ ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "            S        EFGH IJ ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "              e              ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                        h  J ",
        "              i          j   ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "o456789:;<=>?@ ABpqCDEFGH IJ ",
        "                             ",
        "  r6789:;<=>?@ AB  CDEFGH IJ ",
        "   s789:;<=>?@ AB  CDEFGH IJ ",
        "    t89:;<=>?@ AB  CDEFGH IJ ",
        "    u89:;<=>?@ AB  CDEFGH IJ ",
        "     v9:;<=>?@ AB  CDEFGH IJ ",
        "     w9:;<=>?@ AB  CDEFGH IJ ",
        "     x9:;<=>?@ AB  CDEFGH IJ ",
        "     y9:;<=>?@ AB  CDEFGH IJ ",
        "      z:;<=>?@ AB  CDEFGH IJ ",
        "      {:;<=>?@ AB  CDEFGH IJ ",
        "       |;<=>?@ AB  CDEFGH IJ ",
        "       };<=>?@ AB  CDEFGH IJ ",
        "       ~;<=>?@ AB  CDEFGH IJ ",
        "         \x7f=>?@ AB  CDEFGH IJ ",
        "\x80456789:;<=>?@ AB  CDEFGH IJ\x81",
        "            \x82        EFGH IJ ",
        "            \x83        EFGH IJ ",
        "                             ",
        "                     \x84 GH IJ ",
        "                     \x85 GH IJ ",
        "              i          \x86   ",
        "              i          \x87   ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "                             ",
        "o456789:;<=>?@ AB\x8cqCDEFGH IJ ",
        "                             ",
        "                             "
    ];

    XPathParser.productions = [
        [1, 1, 2],
        [2, 1, 3],
        [3, 1, 4],
        [3, 3, 3, -9, 4],
        [4, 1, 5],
        [4, 3, 4, -8, 5],
        [5, 1, 6],
        [5, 3, 5, -22, 6],
        [5, 3, 5, -5, 6],
        [6, 1, 7],
        [6, 3, 6, -23, 7],
        [6, 3, 6, -24, 7],
        [6, 3, 6, -6, 7],
        [6, 3, 6, -7, 7],
        [7, 1, 8],
        [7, 3, 7, -25, 8],
        [7, 3, 7, -26, 8],
        [8, 1, 9],
        [8, 3, 8, -12, 9],
        [8, 3, 8, -11, 9],
        [8, 3, 8, -10, 9],
        [9, 1, 10],
        [9, 2, -26, 9],
        [10, 1, 11],
        [10, 3, 10, -27, 11],
        [11, 1, 12],
        [11, 1, 13],
        [11, 3, 13, -28, 14],
        [11, 3, 13, -4, 14],
        [13, 1, 15],
        [13, 2, 13, 16],
        [15, 1, 17],
        [15, 3, -29, 2, -30],
        [15, 1, -15],
        [15, 1, -16],
        [15, 1, 18],
        [18, 3, -13, -29, -30],
        [18, 4, -13, -29, 19, -30],
        [19, 1, 20],
        [19, 3, 20, -31, 19],
        [20, 1, 2],
        [12, 1, 14],
        [12, 1, 21],
        [21, 1, -28],
        [21, 2, -28, 14],
        [21, 1, 22],
        [14, 1, 23],
        [14, 3, 14, -28, 23],
        [14, 1, 24],
        [23, 2, 25, 26],
        [23, 1, 26],
        [23, 3, 25, 26, 27],
        [23, 2, 26, 27],
        [23, 1, 28],
        [27, 1, 16],
        [27, 2, 16, 27],
        [25, 2, -14, -3],
        [25, 1, -32],
        [26, 1, 29],
        [26, 3, -20, -29, -30],
        [26, 4, -21, -29, -15, -30],
        [16, 3, -33, 30, -34],
        [30, 1, 2],
        [22, 2, -4, 14],
        [24, 3, 14, -4, 23],
        [28, 1, -35],
        [28, 1, -2],
        [17, 2, -36, -18],
        [29, 1, -17],
        [29, 1, -19],
        [29, 1, -18]
    ];

    XPathParser.DOUBLEDOT = 2;
    XPathParser.DOUBLECOLON = 3;
    XPathParser.DOUBLESLASH = 4;
    XPathParser.NOTEQUAL = 5;
    XPathParser.LESSTHANOREQUAL = 6;
    XPathParser.GREATERTHANOREQUAL = 7;
    XPathParser.AND = 8;
    XPathParser.OR = 9;
    XPathParser.MOD = 10;
    XPathParser.DIV = 11;
    XPathParser.MULTIPLYOPERATOR = 12;
    XPathParser.FUNCTIONNAME = 13;
    XPathParser.AXISNAME = 14;
    XPathParser.LITERAL = 15;
    XPathParser.NUMBER = 16;
    XPathParser.ASTERISKNAMETEST = 17;
    XPathParser.QNAME = 18;
    XPathParser.NCNAMECOLONASTERISK = 19;
    XPathParser.NODETYPE = 20;
    XPathParser.PROCESSINGINSTRUCTIONWITHLITERAL = 21;
    XPathParser.EQUALS = 22;
    XPathParser.LESSTHAN = 23;
    XPathParser.GREATERTHAN = 24;
    XPathParser.PLUS = 25;
    XPathParser.MINUS = 26;
    XPathParser.BAR = 27;
    XPathParser.SLASH = 28;
    XPathParser.LEFTPARENTHESIS = 29;
    XPathParser.RIGHTPARENTHESIS = 30;
    XPathParser.COMMA = 31;
    XPathParser.AT = 32;
    XPathParser.LEFTBRACKET = 33;
    XPathParser.RIGHTBRACKET = 34;
    XPathParser.DOT = 35;
    XPathParser.DOLLAR = 36;

    XPathParser.prototype.tokenize = function (s1) {
        var types = [];
        var values = [];
        var s = s1 + '\0';

        var pos = 0;
        var c = s.charAt(pos++);
        while (1) {
            while (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
                c = s.charAt(pos++);
            }
            if (c == '\0' || pos >= s.length) {
                break;
            }

            if (c == '(') {
                types.push(XPathParser.LEFTPARENTHESIS);
                values.push(c);
                c = s.charAt(pos++);
                continue;
            }
            if (c == ')') {
                types.push(XPathParser.RIGHTPARENTHESIS);
                values.push(c);
                c = s.charAt(pos++);
                continue;
            }
            if (c == '[') {
                types.push(XPathParser.LEFTBRACKET);
                values.push(c);
                c = s.charAt(pos++);
                continue;
            }
            if (c == ']') {
                types.push(XPathParser.RIGHTBRACKET);
                values.push(c);
                c = s.charAt(pos++);
                continue;
            }
            if (c == '@') {
                types.push(XPathParser.AT);
                values.push(c);
                c = s.charAt(pos++);
                continue;
            }
            if (c == ',') {
                types.push(XPathParser.COMMA);
                values.push(c);
                c = s.charAt(pos++);
                continue;
            }
            if (c == '|') {
                types.push(XPathParser.BAR);
                values.push(c);
                c = s.charAt(pos++);
                continue;
            }
            if (c == '+') {
                types.push(XPathParser.PLUS);
                values.push(c);
                c = s.charAt(pos++);
                continue;
            }
            if (c == '-') {
                types.push(XPathParser.MINUS);
                values.push(c);
                c = s.charAt(pos++);
                continue;
            }
            if (c == '=') {
                types.push(XPathParser.EQUALS);
                values.push(c);
                c = s.charAt(pos++);
                continue;
            }
            if (c == '$') {
                types.push(XPathParser.DOLLAR);
                values.push(c);
                c = s.charAt(pos++);
                continue;
            }

            if (c == '.') {
                c = s.charAt(pos++);
                if (c == '.') {
                    types.push(XPathParser.DOUBLEDOT);
                    values.push("..");
                    c = s.charAt(pos++);
                    continue;
                }
                if (c >= '0' && c <= '9') {
                    var number = "." + c;
                    c = s.charAt(pos++);
                    while (c >= '0' && c <= '9') {
                        number += c;
                        c = s.charAt(pos++);
                    }
                    types.push(XPathParser.NUMBER);
                    values.push(number);
                    continue;
                }
                types.push(XPathParser.DOT);
                values.push('.');
                continue;
            }

            if (c == '\'' || c == '"') {
                var delimiter = c;
                var literal = "";
                while (pos < s.length && (c = s.charAt(pos)) !== delimiter) {
                    literal += c;
                    pos += 1;
                }
                if (c !== delimiter) {
                    throw XPathException.fromMessage("Unterminated string literal: " + delimiter + literal);
                }
                pos += 1;
                types.push(XPathParser.LITERAL);
                values.push(literal);
                c = s.charAt(pos++);
                continue;
            }

            if (c >= '0' && c <= '9') {
                var number = c;
                c = s.charAt(pos++);
                while (c >= '0' && c <= '9') {
                    number += c;
                    c = s.charAt(pos++);
                }
                if (c == '.') {
                    if (s.charAt(pos) >= '0' && s.charAt(pos) <= '9') {
                        number += c;
                        number += s.charAt(pos++);
                        c = s.charAt(pos++);
                        while (c >= '0' && c <= '9') {
                            number += c;
                            c = s.charAt(pos++);
                        }
                    }
                }
                types.push(XPathParser.NUMBER);
                values.push(number);
                continue;
            }

            if (c == '*') {
                if (types.length > 0) {
                    var last = types[types.length - 1];
                    if (last != XPathParser.AT
                        && last != XPathParser.DOUBLECOLON
                        && last != XPathParser.LEFTPARENTHESIS
                        && last != XPathParser.LEFTBRACKET
                        && last != XPathParser.AND
                        && last != XPathParser.OR
                        && last != XPathParser.MOD
                        && last != XPathParser.DIV
                        && last != XPathParser.MULTIPLYOPERATOR
                        && last != XPathParser.SLASH
                        && last != XPathParser.DOUBLESLASH
                        && last != XPathParser.BAR
                        && last != XPathParser.PLUS
                        && last != XPathParser.MINUS
                        && last != XPathParser.EQUALS
                        && last != XPathParser.NOTEQUAL
                        && last != XPathParser.LESSTHAN
                        && last != XPathParser.LESSTHANOREQUAL
                        && last != XPathParser.GREATERTHAN
                        && last != XPathParser.GREATERTHANOREQUAL) {
                        types.push(XPathParser.MULTIPLYOPERATOR);
                        values.push(c);
                        c = s.charAt(pos++);
                        continue;
                    }
                }
                types.push(XPathParser.ASTERISKNAMETEST);
                values.push(c);
                c = s.charAt(pos++);
                continue;
            }

            if (c == ':') {
                if (s.charAt(pos) == ':') {
                    types.push(XPathParser.DOUBLECOLON);
                    values.push("::");
                    pos++;
                    c = s.charAt(pos++);
                    continue;
                }
            }

            if (c == '/') {
                c = s.charAt(pos++);
                if (c == '/') {
                    types.push(XPathParser.DOUBLESLASH);
                    values.push("//");
                    c = s.charAt(pos++);
                    continue;
                }
                types.push(XPathParser.SLASH);
                values.push('/');
                continue;
            }

            if (c == '!') {
                if (s.charAt(pos) == '=') {
                    types.push(XPathParser.NOTEQUAL);
                    values.push("!=");
                    pos++;
                    c = s.charAt(pos++);
                    continue;
                }
            }

            if (c == '<') {
                if (s.charAt(pos) == '=') {
                    types.push(XPathParser.LESSTHANOREQUAL);
                    values.push("<=");
                    pos++;
                    c = s.charAt(pos++);
                    continue;
                }
                types.push(XPathParser.LESSTHAN);
                values.push('<');
                c = s.charAt(pos++);
                continue;
            }

            if (c == '>') {
                if (s.charAt(pos) == '=') {
                    types.push(XPathParser.GREATERTHANOREQUAL);
                    values.push(">=");
                    pos++;
                    c = s.charAt(pos++);
                    continue;
                }
                types.push(XPathParser.GREATERTHAN);
                values.push('>');
                c = s.charAt(pos++);
                continue;
            }

            if (c == '_' || Utilities.isLetter(c.charCodeAt(0))) {
                var name = c;
                c = s.charAt(pos++);
                while (Utilities.isNCNameChar(c.charCodeAt(0))) {
                    name += c;
                    c = s.charAt(pos++);
                }
                if (types.length > 0) {
                    var last = types[types.length - 1];
                    if (last != XPathParser.AT
                        && last != XPathParser.DOUBLECOLON
                        && last != XPathParser.LEFTPARENTHESIS
                        && last != XPathParser.LEFTBRACKET
                        && last != XPathParser.AND
                        && last != XPathParser.OR
                        && last != XPathParser.MOD
                        && last != XPathParser.DIV
                        && last != XPathParser.MULTIPLYOPERATOR
                        && last != XPathParser.SLASH
                        && last != XPathParser.DOUBLESLASH
                        && last != XPathParser.BAR
                        && last != XPathParser.PLUS
                        && last != XPathParser.MINUS
                        && last != XPathParser.EQUALS
                        && last != XPathParser.NOTEQUAL
                        && last != XPathParser.LESSTHAN
                        && last != XPathParser.LESSTHANOREQUAL
                        && last != XPathParser.GREATERTHAN
                        && last != XPathParser.GREATERTHANOREQUAL) {
                        if (name == "and") {
                            types.push(XPathParser.AND);
                            values.push(name);
                            continue;
                        }
                        if (name == "or") {
                            types.push(XPathParser.OR);
                            values.push(name);
                            continue;
                        }
                        if (name == "mod") {
                            types.push(XPathParser.MOD);
                            values.push(name);
                            continue;
                        }
                        if (name == "div") {
                            types.push(XPathParser.DIV);
                            values.push(name);
                            continue;
                        }
                    }
                }
                if (c == ':') {
                    if (s.charAt(pos) == '*') {
                        types.push(XPathParser.NCNAMECOLONASTERISK);
                        values.push(name + ":*");
                        pos++;
                        c = s.charAt(pos++);
                        continue;
                    }
                    if (s.charAt(pos) == '_' || Utilities.isLetter(s.charCodeAt(pos))) {
                        name += ':';
                        c = s.charAt(pos++);
                        while (Utilities.isNCNameChar(c.charCodeAt(0))) {
                            name += c;
                            c = s.charAt(pos++);
                        }
                        if (c == '(') {
                            types.push(XPathParser.FUNCTIONNAME);
                            values.push(name);
                            continue;
                        }
                        types.push(XPathParser.QNAME);
                        values.push(name);
                        continue;
                    }
                    if (s.charAt(pos) == ':') {
                        types.push(XPathParser.AXISNAME);
                        values.push(name);
                        continue;
                    }
                }
                if (c == '(') {
                    if (name == "comment" || name == "text" || name == "node") {
                        types.push(XPathParser.NODETYPE);
                        values.push(name);
                        continue;
                    }
                    if (name == "processing-instruction") {
                        if (s.charAt(pos) == ')') {
                            types.push(XPathParser.NODETYPE);
                        } else {
                            types.push(XPathParser.PROCESSINGINSTRUCTIONWITHLITERAL);
                        }
                        values.push(name);
                        continue;
                    }
                    types.push(XPathParser.FUNCTIONNAME);
                    values.push(name);
                    continue;
                }
                types.push(XPathParser.QNAME);
                values.push(name);
                continue;
            }

            throw new Error("Unexpected character " + c);
        }
        types.push(1);
        values.push("[EOF]");
        return [types, values];
    };

    XPathParser.SHIFT = 's';
    XPathParser.REDUCE = 'r';
    XPathParser.ACCEPT = 'a';

    XPathParser.prototype.parse = function (s) {
        var types;
        var values;
        var res = this.tokenize(s);
        if (res == undefined) {
            return undefined;
        }
        types = res[0];
        values = res[1];
        var tokenPos = 0;
        var state = [];
        var tokenType = [];
        var tokenValue = [];
        var s;
        var a;
        var t;

        state.push(0);
        tokenType.push(1);
        tokenValue.push("_S");

        a = types[tokenPos];
        t = values[tokenPos++];
        while (1) {
            s = state[state.length - 1];
            switch (XPathParser.actionTable[s].charAt(a - 1)) {
                case XPathParser.SHIFT:
                    tokenType.push(-a);
                    tokenValue.push(t);
                    state.push(XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32);
                    a = types[tokenPos];
                    t = values[tokenPos++];
                    break;
                case XPathParser.REDUCE:
                    var num = XPathParser.productions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32][1];
                    var rhs = [];
                    for (var i = 0; i < num; i++) {
                        tokenType.pop();
                        rhs.unshift(tokenValue.pop());
                        state.pop();
                    }
                    var s_ = state[state.length - 1];
                    tokenType.push(XPathParser.productions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32][0]);
                    if (this.reduceActions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32] == undefined) {
                        tokenValue.push(rhs[0]);
                    } else {
                        tokenValue.push(this.reduceActions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32](rhs));
                    }
                    state.push(XPathParser.gotoTable[s_].charCodeAt(XPathParser.productions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32][0] - 2) - 33);
                    break;
                case XPathParser.ACCEPT:
                    return new XPath(tokenValue.pop());
                default:
                    throw new Error("XPath parse error");
            }
        }
    };

    // XPath /////////////////////////////////////////////////////////////////////

    XPath.prototype = new Object();
    XPath.prototype.constructor = XPath;
    XPath.superclass = Object.prototype;

    function XPath(e) {
        this.expression = e;
    }

    XPath.prototype.toString = function () {
        return this.expression.toString();
    };

    function setIfUnset(obj, prop, value) {
        if (!(prop in obj)) {
            obj[prop] = value;
        }
    }

    XPath.prototype.evaluate = function (c) {
        c.contextNode = c.expressionContextNode;
        c.contextSize = 1;
        c.contextPosition = 1;

        // [2017-11-25] Removed usage of .implementation.hasFeature() since it does
        //              not reliably detect HTML DOMs (always returns false in xmldom and true in browsers)
        if (c.isHtml) {
            setIfUnset(c, 'caseInsensitive', true);
            setIfUnset(c, 'allowAnyNamespaceForNoPrefix', true);
        }

        setIfUnset(c, 'caseInsensitive', false);

        return this.expression.evaluate(c);
    };

    XPath.XML_NAMESPACE_URI = "http://www.w3.org/XML/1998/namespace";
    XPath.XMLNS_NAMESPACE_URI = "http://www.w3.org/2000/xmlns/";

    // Expression ////////////////////////////////////////////////////////////////

    Expression.prototype = new Object();
    Expression.prototype.constructor = Expression;
    Expression.superclass = Object.prototype;

    function Expression() {
    }

    Expression.prototype.init = function () {
    };

    Expression.prototype.toString = function () {
        return "<Expression>";
    };

    Expression.prototype.evaluate = function (c) {
        throw new Error("Could not evaluate expression.");
    };

    // UnaryOperation ////////////////////////////////////////////////////////////

    UnaryOperation.prototype = new Expression();
    UnaryOperation.prototype.constructor = UnaryOperation;
    UnaryOperation.superclass = Expression.prototype;

    function UnaryOperation(rhs) {
        if (arguments.length > 0) {
            this.init(rhs);
        }
    }

    UnaryOperation.prototype.init = function (rhs) {
        this.rhs = rhs;
    };

    // UnaryMinusOperation ///////////////////////////////////////////////////////

    UnaryMinusOperation.prototype = new UnaryOperation();
    UnaryMinusOperation.prototype.constructor = UnaryMinusOperation;
    UnaryMinusOperation.superclass = UnaryOperation.prototype;

    function UnaryMinusOperation(rhs) {
        if (arguments.length > 0) {
            this.init(rhs);
        }
    }

    UnaryMinusOperation.prototype.init = function (rhs) {
        UnaryMinusOperation.superclass.init.call(this, rhs);
    };

    UnaryMinusOperation.prototype.evaluate = function (c) {
        return this.rhs.evaluate(c).number().negate();
    };

    UnaryMinusOperation.prototype.toString = function () {
        return "-" + this.rhs.toString();
    };

    // BinaryOperation ///////////////////////////////////////////////////////////

    BinaryOperation.prototype = new Expression();
    BinaryOperation.prototype.constructor = BinaryOperation;
    BinaryOperation.superclass = Expression.prototype;

    function BinaryOperation(lhs, rhs) {
        if (arguments.length > 0) {
            this.init(lhs, rhs);
        }
    }

    BinaryOperation.prototype.init = function (lhs, rhs) {
        this.lhs = lhs;
        this.rhs = rhs;
    };

    // OrOperation ///////////////////////////////////////////////////////////////

    OrOperation.prototype = new BinaryOperation();
    OrOperation.prototype.constructor = OrOperation;
    OrOperation.superclass = BinaryOperation.prototype;

    function OrOperation(lhs, rhs) {
        if (arguments.length > 0) {
            this.init(lhs, rhs);
        }
    }

    OrOperation.prototype.init = function (lhs, rhs) {
        OrOperation.superclass.init.call(this, lhs, rhs);
    };

    OrOperation.prototype.toString = function () {
        return "(" + this.lhs.toString() + " or " + this.rhs.toString() + ")";
    };

    OrOperation.prototype.evaluate = function (c) {
        var b = this.lhs.evaluate(c).bool();
        if (b.booleanValue()) {
            return b;
        }
        return this.rhs.evaluate(c).bool();
    };

    // AndOperation //////////////////////////////////////////////////////////////

    AndOperation.prototype = new BinaryOperation();
    AndOperation.prototype.constructor = AndOperation;
    AndOperation.superclass = BinaryOperation.prototype;

    function AndOperation(lhs, rhs) {
        if (arguments.length > 0) {
            this.init(lhs, rhs);
        }
    }

    AndOperation.prototype.init = function (lhs, rhs) {
        AndOperation.superclass.init.call(this, lhs, rhs);
    };

    AndOperation.prototype.toString = function () {
        return "(" + this.lhs.toString() + " and " + this.rhs.toString() + ")";
    };

    AndOperation.prototype.evaluate = function (c) {
        var b = this.lhs.evaluate(c).bool();
        if (!b.booleanValue()) {
            return b;
        }
        return this.rhs.evaluate(c).bool();
    };

    // EqualsOperation ///////////////////////////////////////////////////////////

    EqualsOperation.prototype = new BinaryOperation();
    EqualsOperation.prototype.constructor = EqualsOperation;
    EqualsOperation.superclass = BinaryOperation.prototype;

    function EqualsOperation(lhs, rhs) {
        if (arguments.length > 0) {
            this.init(lhs, rhs);
        }
    }

    EqualsOperation.prototype.init = function (lhs, rhs) {
        EqualsOperation.superclass.init.call(this, lhs, rhs);
    };

    EqualsOperation.prototype.toString = function () {
        return "(" + this.lhs.toString() + " = " + this.rhs.toString() + ")";
    };

    EqualsOperation.prototype.evaluate = function (c) {
        return this.lhs.evaluate(c).equals(this.rhs.evaluate(c));
    };

    // NotEqualOperation /////////////////////////////////////////////////////////

    NotEqualOperation.prototype = new BinaryOperation();
    NotEqualOperation.prototype.constructor = NotEqualOperation;
    NotEqualOperation.superclass = BinaryOperation.prototype;

    function NotEqualOperation(lhs, rhs) {
        if (arguments.length > 0) {
            this.init(lhs, rhs);
        }
    }

    NotEqualOperation.prototype.init = function (lhs, rhs) {
        NotEqualOperation.superclass.init.call(this, lhs, rhs);
    };

    NotEqualOperation.prototype.toString = function () {
        return "(" + this.lhs.toString() + " != " + this.rhs.toString() + ")";
    };

    NotEqualOperation.prototype.evaluate = function (c) {
        return this.lhs.evaluate(c).notequal(this.rhs.evaluate(c));
    };

    // LessThanOperation /////////////////////////////////////////////////////////

    LessThanOperation.prototype = new BinaryOperation();
    LessThanOperation.prototype.constructor = LessThanOperation;
    LessThanOperation.superclass = BinaryOperation.prototype;

    function LessThanOperation(lhs, rhs) {
        if (arguments.length > 0) {
            this.init(lhs, rhs);
        }
    }

    LessThanOperation.prototype.init = function (lhs, rhs) {
        LessThanOperation.superclass.init.call(this, lhs, rhs);
    };

    LessThanOperation.prototype.evaluate = function (c) {
        return this.lhs.evaluate(c).lessthan(this.rhs.evaluate(c));
    };

    LessThanOperation.prototype.toString = function () {
        return "(" + this.lhs.toString() + " < " + this.rhs.toString() + ")";
    };

    // GreaterThanOperation //////////////////////////////////////////////////////

    GreaterThanOperation.prototype = new BinaryOperation();
    GreaterThanOperation.prototype.constructor = GreaterThanOperation;
    GreaterThanOperation.superclass = BinaryOperation.prototype;

    function GreaterThanOperation(lhs, rhs) {
        if (arguments.length > 0) {
            this.init(lhs, rhs);
        }
    }

    GreaterThanOperation.prototype.init = function (lhs, rhs) {
        GreaterThanOperation.superclass.init.call(this, lhs, rhs);
    };

    GreaterThanOperation.prototype.evaluate = function (c) {
        return this.lhs.evaluate(c).greaterthan(this.rhs.evaluate(c));
    };

    GreaterThanOperation.prototype.toString = function () {
        return "(" + this.lhs.toString() + " > " + this.rhs.toString() + ")";
    };

    // LessThanOrEqualOperation //////////////////////////////////////////////////

    LessThanOrEqualOperation.prototype = new BinaryOperation();
    LessThanOrEqualOperation.prototype.constructor = LessThanOrEqualOperation;
    LessThanOrEqualOperation.superclass = BinaryOperation.prototype;

    function LessThanOrEqualOperation(lhs, rhs) {
        if (arguments.length > 0) {
            this.init(lhs, rhs);
        }
    }

    LessThanOrEqualOperation.prototype.init = function (lhs, rhs) {
        LessThanOrEqualOperation.superclass.init.call(this, lhs, rhs);
    };

    LessThanOrEqualOperation.prototype.evaluate = function (c) {
        return this.lhs.evaluate(c).lessthanorequal(this.rhs.evaluate(c));
    };

    LessThanOrEqualOperation.prototype.toString = function () {
        return "(" + this.lhs.toString() + " <= " + this.rhs.toString() + ")";
    };

    // GreaterThanOrEqualOperation ///////////////////////////////////////////////

    GreaterThanOrEqualOperation.prototype = new BinaryOperation();
    GreaterThanOrEqualOperation.prototype.constructor = GreaterThanOrEqualOperation;
    GreaterThanOrEqualOperation.superclass = BinaryOperation.prototype;

    function GreaterThanOrEqualOperation(lhs, rhs) {
        if (arguments.length > 0) {
            this.init(lhs, rhs);
        }
    }

    GreaterThanOrEqualOperation.prototype.init = function (lhs, rhs) {
        GreaterThanOrEqualOperation.superclass.init.call(this, lhs, rhs);
    };

    GreaterThanOrEqualOperation.prototype.evaluate = function (c) {
        return this.lhs.evaluate(c).greaterthanorequal(this.rhs.evaluate(c));
    };

    GreaterThanOrEqualOperation.prototype.toString = function () {
        return "(" + this.lhs.toString() + " >= " + this.rhs.toString() + ")";
    };

    // PlusOperation /////////////////////////////////////////////////////////////

    PlusOperation.prototype = new BinaryOperation();
    PlusOperation.prototype.constructor = PlusOperation;
    PlusOperation.superclass = BinaryOperation.prototype;

    function PlusOperation(lhs, rhs) {
        if (arguments.length > 0) {
            this.init(lhs, rhs);
        }
    }

    PlusOperation.prototype.init = function (lhs, rhs) {
        PlusOperation.superclass.init.call(this, lhs, rhs);
    };

    PlusOperation.prototype.evaluate = function (c) {
        return this.lhs.evaluate(c).number().plus(this.rhs.evaluate(c).number());
    };

    PlusOperation.prototype.toString = function () {
        return "(" + this.lhs.toString() + " + " + this.rhs.toString() + ")";
    };

    // MinusOperation ////////////////////////////////////////////////////////////

    MinusOperation.prototype = new BinaryOperation();
    MinusOperation.prototype.constructor = MinusOperation;
    MinusOperation.superclass = BinaryOperation.prototype;

    function MinusOperation(lhs, rhs) {
        if (arguments.length > 0) {
            this.init(lhs, rhs);
        }
    }

    MinusOperation.prototype.init = function (lhs, rhs) {
        MinusOperation.superclass.init.call(this, lhs, rhs);
    };

    MinusOperation.prototype.evaluate = function (c) {
        return this.lhs.evaluate(c).number().minus(this.rhs.evaluate(c).number());
    };

    MinusOperation.prototype.toString = function () {
        return "(" + this.lhs.toString() + " - " + this.rhs.toString() + ")";
    };

    // MultiplyOperation /////////////////////////////////////////////////////////

    MultiplyOperation.prototype = new BinaryOperation();
    MultiplyOperation.prototype.constructor = MultiplyOperation;
    MultiplyOperation.superclass = BinaryOperation.prototype;

    function MultiplyOperation(lhs, rhs) {
        if (arguments.length > 0) {
            this.init(lhs, rhs);
        }
    }

    MultiplyOperation.prototype.init = function (lhs, rhs) {
        MultiplyOperation.superclass.init.call(this, lhs, rhs);
    };

    MultiplyOperation.prototype.evaluate = function (c) {
        return this.lhs.evaluate(c).number().multiply(this.rhs.evaluate(c).number());
    };

    MultiplyOperation.prototype.toString = function () {
        return "(" + this.lhs.toString() + " * " + this.rhs.toString() + ")";
    };

    // DivOperation //////////////////////////////////////////////////////////////

    DivOperation.prototype = new BinaryOperation();
    DivOperation.prototype.constructor = DivOperation;
    DivOperation.superclass = BinaryOperation.prototype;

    function DivOperation(lhs, rhs) {
        if (arguments.length > 0) {
            this.init(lhs, rhs);
        }
    }

    DivOperation.prototype.init = function (lhs, rhs) {
        DivOperation.superclass.init.call(this, lhs, rhs);
    };

    DivOperation.prototype.evaluate = function (c) {
        return this.lhs.evaluate(c).number().div(this.rhs.evaluate(c).number());
    };

    DivOperation.prototype.toString = function () {
        return "(" + this.lhs.toString() + " div " + this.rhs.toString() + ")";
    };

    // ModOperation //////////////////////////////////////////////////////////////

    ModOperation.prototype = new BinaryOperation();
    ModOperation.prototype.constructor = ModOperation;
    ModOperation.superclass = BinaryOperation.prototype;

    function ModOperation(lhs, rhs) {
        if (arguments.length > 0) {
            this.init(lhs, rhs);
        }
    }

    ModOperation.prototype.init = function (lhs, rhs) {
        ModOperation.superclass.init.call(this, lhs, rhs);
    };

    ModOperation.prototype.evaluate = function (c) {
        return this.lhs.evaluate(c).number().mod(this.rhs.evaluate(c).number());
    };

    ModOperation.prototype.toString = function () {
        return "(" + this.lhs.toString() + " mod " + this.rhs.toString() + ")";
    };

    // BarOperation //////////////////////////////////////////////////////////////

    BarOperation.prototype = new BinaryOperation();
    BarOperation.prototype.constructor = BarOperation;
    BarOperation.superclass = BinaryOperation.prototype;

    function BarOperation(lhs, rhs) {
        if (arguments.length > 0) {
            this.init(lhs, rhs);
        }
    }

    BarOperation.prototype.init = function (lhs, rhs) {
        BarOperation.superclass.init.call(this, lhs, rhs);
    };

    BarOperation.prototype.evaluate = function (c) {
        return this.lhs.evaluate(c).nodeset().union(this.rhs.evaluate(c).nodeset());
    };

    BarOperation.prototype.toString = function () {
        return map(toString, [this.lhs, this.rhs]).join(' | ');
    };

    // PathExpr //////////////////////////////////////////////////////////////////

    PathExpr.prototype = new Expression();
    PathExpr.prototype.constructor = PathExpr;
    PathExpr.superclass = Expression.prototype;

    function PathExpr(filter, filterPreds, locpath) {
        if (arguments.length > 0) {
            this.init(filter, filterPreds, locpath);
        }
    }

    PathExpr.prototype.init = function (filter, filterPreds, locpath) {
        PathExpr.superclass.init.call(this);
        this.filter = filter;
        this.filterPredicates = filterPreds;
        this.locationPath = locpath;
    };

    /**
     * Returns the topmost node of the tree containing node
     */
    function findRoot(node) {
        while (node && node.parentNode) {
            node = node.parentNode;
        }

        return node;
    }

    PathExpr.applyPredicates = function (predicates, c, nodes) {
        if (predicates.length === 0) {
            return nodes;
        }

        var ctx = c.extend({});

        return reduce(
            function (inNodes, pred) {
                ctx.contextSize = inNodes.length;

                return filter(
                    function (node, i) {
                        ctx.contextNode = node;
                        ctx.contextPosition = i + 1;

                        return PathExpr.predicateMatches(pred, ctx);
                    },
                    inNodes
                );
            },
            nodes,
            predicates
        );
    };

    PathExpr.getRoot = function (xpc, nodes) {
        var firstNode = nodes[0];

        if (firstNode.nodeType === NodeTypes.DOCUMENT_NODE) {
            return firstNode;
        }

        if (xpc.virtualRoot) {
            return xpc.virtualRoot;
        }

        var ownerDoc = firstNode.ownerDocument;

        if (ownerDoc) {
            return ownerDoc;
        }

        // IE 5.5 doesn't have ownerDocument?
        var n = firstNode;
        while (n.parentNode != null) {
            n = n.parentNode;
        }
        return n;
    }

    PathExpr.applyStep = function (step, xpc, node) {
        var self = this;
        var newNodes = [];
        xpc.contextNode = node;

        switch (step.axis) {
            case Step.ANCESTOR:
                // look at all the ancestor nodes
                if (xpc.contextNode === xpc.virtualRoot) {
                    break;
                }
                var m;
                if (xpc.contextNode.nodeType == NodeTypes.ATTRIBUTE_NODE) {
                    m = PathExpr.getOwnerElement(xpc.contextNode);
                } else {
                    m = xpc.contextNode.parentNode;
                }
                while (m != null) {
                    if (step.nodeTest.matches(m, xpc)) {
                        newNodes.push(m);
                    }
                    if (m === xpc.virtualRoot) {
                        break;
                    }
                    m = m.parentNode;
                }
                break;

            case Step.ANCESTORORSELF:
                // look at all the ancestor nodes and the current node
                for (var m = xpc.contextNode; m != null; m = m.nodeType == NodeTypes.ATTRIBUTE_NODE ? PathExpr.getOwnerElement(m) : m.parentNode) {
                    if (step.nodeTest.matches(m, xpc)) {
                        newNodes.push(m);
                    }
                    if (m === xpc.virtualRoot) {
                        break;
                    }
                }
                break;

            case Step.ATTRIBUTE:
                // look at the attributes
                var nnm = xpc.contextNode.attributes;
                if (nnm != null) {
                    for (var k = 0; k < nnm.length; k++) {
                        var m = nnm.item(k);
                        if (step.nodeTest.matches(m, xpc)) {
                            newNodes.push(m);
                        }
                    }
                }
                break;

            case Step.CHILD:
                // look at all child elements
                for (var m = xpc.contextNode.firstChild; m != null; m = m.nextSibling) {
                    if (step.nodeTest.matches(m, xpc)) {
                        newNodes.push(m);
                    }
                }
                break;

            case Step.DESCENDANT:
                // look at all descendant nodes
                var st = [xpc.contextNode.firstChild];
                while (st.length > 0) {
                    for (var m = st.pop(); m != null;) {
                        if (step.nodeTest.matches(m, xpc)) {
                            newNodes.push(m);
                        }
                        if (m.firstChild != null) {
                            st.push(m.nextSibling);
                            m = m.firstChild;
                        } else {
                            m = m.nextSibling;
                        }
                    }
                }
                break;

            case Step.DESCENDANTORSELF:
                // look at self
                if (step.nodeTest.matches(xpc.contextNode, xpc)) {
                    newNodes.push(xpc.contextNode);
                }
                // look at all descendant nodes
                var st = [xpc.contextNode.firstChild];
                while (st.length > 0) {
                    for (var m = st.pop(); m != null;) {
                        if (step.nodeTest.matches(m, xpc)) {
                            newNodes.push(m);
                        }
                        if (m.firstChild != null) {
                            st.push(m.nextSibling);
                            m = m.firstChild;
                        } else {
                            m = m.nextSibling;
                        }
                    }
                }
                break;

            case Step.FOLLOWING:
                if (xpc.contextNode === xpc.virtualRoot) {
                    break;
                }
                var st = [];
                if (xpc.contextNode.firstChild != null) {
                    st.unshift(xpc.contextNode.firstChild);
                } else {
                    st.unshift(xpc.contextNode.nextSibling);
                }
                for (var m = xpc.contextNode.parentNode; m != null && m.nodeType != NodeTypes.DOCUMENT_NODE && m !== xpc.virtualRoot; m = m.parentNode) {
                    st.unshift(m.nextSibling);
                }
                do {
                    for (var m = st.pop(); m != null;) {
                        if (step.nodeTest.matches(m, xpc)) {
                            newNodes.push(m);
                        }
                        if (m.firstChild != null) {
                            st.push(m.nextSibling);
                            m = m.firstChild;
                        } else {
                            m = m.nextSibling;
                        }
                    }
                } while (st.length > 0);
                break;

            case Step.FOLLOWINGSIBLING:
                if (xpc.contextNode === xpc.virtualRoot) {
                    break;
                }
                for (var m = xpc.contextNode.nextSibling; m != null; m = m.nextSibling) {
                    if (step.nodeTest.matches(m, xpc)) {
                        newNodes.push(m);
                    }
                }
                break;

            case Step.NAMESPACE:
                var n = {};
                if (xpc.contextNode.nodeType == NodeTypes.ELEMENT_NODE) {
                    n["xml"] = XPath.XML_NAMESPACE_URI;
                    n["xmlns"] = XPath.XMLNS_NAMESPACE_URI;
                    for (var m = xpc.contextNode; m != null && m.nodeType == NodeTypes.ELEMENT_NODE; m = m.parentNode) {
                        for (var k = 0; k < m.attributes.length; k++) {
                            var attr = m.attributes.item(k);
                            var nm = String(attr.name);
                            if (nm == "xmlns") {
                                if (n[""] == undefined) {
                                    n[""] = attr.value;
                                }
                            } else if (nm.length > 6 && nm.substring(0, 6) == "xmlns:") {
                                var pre = nm.substring(6, nm.length);
                                if (n[pre] == undefined) {
                                    n[pre] = attr.value;
                                }
                            }
                        }
                    }
                    for (var pre in n) {
                        var nsn = new XPathNamespace(pre, n[pre], xpc.contextNode);
                        if (step.nodeTest.matches(nsn, xpc)) {
                            newNodes.push(nsn);
                        }
                    }
                }
                break;

            case Step.PARENT:
                m = null;
                if (xpc.contextNode !== xpc.virtualRoot) {
                    if (xpc.contextNode.nodeType == NodeTypes.ATTRIBUTE_NODE) {
                        m = PathExpr.getOwnerElement(xpc.contextNode);
                    } else {
                        m = xpc.contextNode.parentNode;
                    }
                }
                if (m != null && step.nodeTest.matches(m, xpc)) {
                    newNodes.push(m);
                }
                break;

            case Step.PRECEDING:
                var st;
                if (xpc.virtualRoot != null) {
                    st = [xpc.virtualRoot];
                } else {
                    // cannot rely on .ownerDocument because the node may be in a document fragment
                    st = [findRoot(xpc.contextNode)];
                }
                outer: while (st.length > 0) {
                    for (var m = st.pop(); m != null;) {
                        if (m == xpc.contextNode) {
                            break outer;
                        }
                        if (step.nodeTest.matches(m, xpc)) {
                            newNodes.unshift(m);
                        }
                        if (m.firstChild != null) {
                            st.push(m.nextSibling);
                            m = m.firstChild;
                        } else {
                            m = m.nextSibling;
                        }
                    }
                }
                break;

            case Step.PRECEDINGSIBLING:
                if (xpc.contextNode === xpc.virtualRoot) {
                    break;
                }
                for (var m = xpc.contextNode.previousSibling; m != null; m = m.previousSibling) {
                    if (step.nodeTest.matches(m, xpc)) {
                        newNodes.push(m);
                    }
                }
                break;

            case Step.SELF:
                if (step.nodeTest.matches(xpc.contextNode, xpc)) {
                    newNodes.push(xpc.contextNode);
                }
                break;

            default:
        }

        return newNodes;
    };

    function applyStepWithPredicates(step, xpc, node) {
        return PathExpr.applyPredicates(
            step.predicates,
            xpc,
            PathExpr.applyStep(step, xpc, node)
        );
    }

    function applyStepToNodes(context, nodes, step) {
        return flatten(
            map(
                applyStepWithPredicates.bind(null, step, context),
                nodes
            )
        );
    }

    PathExpr.applySteps = function (steps, xpc, nodes) {
        return reduce(
            applyStepToNodes.bind(null, xpc),
            nodes,
            steps
        );
    }

    PathExpr.prototype.applyFilter = function (c, xpc) {
        if (!this.filter) {
            return { nodes: [c.contextNode] };
        }

        var ns = this.filter.evaluate(c);

        if (!Utilities.instance_of(ns, XNodeSet)) {
            if (this.filterPredicates != null && this.filterPredicates.length > 0 || this.locationPath != null) {
                throw new Error("Path expression filter must evaluate to a nodeset if predicates or location path are used");
            }

            return { nonNodes: ns };
        }

        return {
            nodes: PathExpr.applyPredicates(this.filterPredicates || [], xpc, ns.toUnsortedArray())
        };
    };

    PathExpr.applyLocationPath = function (locationPath, xpc, nodes) {
        if (!locationPath) {
            return nodes;
        }

        var startNodes = locationPath.absolute ? [PathExpr.getRoot(xpc, nodes)] : nodes;

        return PathExpr.applySteps(locationPath.steps, xpc, startNodes);
    };

    PathExpr.prototype.evaluate = function (c) {
        var xpc = assign(new XPathContext(), c);

        var filterResult = this.applyFilter(c, xpc);

        if ('nonNodes' in filterResult) {
            return filterResult.nonNodes;
        }

        var ns = new XNodeSet();
        ns.addArray(PathExpr.applyLocationPath(this.locationPath, xpc, filterResult.nodes));
        return ns;
    };

    PathExpr.predicateMatches = function (pred, c) {
        var res = pred.evaluate(c);

        return Utilities.instance_of(res, XNumber)
            ? c.contextPosition === res.numberValue()
            : res.booleanValue();
    };

    PathExpr.predicateString = function (predicate) {
        return wrap('[', ']', predicate.toString());
    }

    PathExpr.predicatesString = function (predicates) {
        return join(
            '',
            map(PathExpr.predicateString, predicates)
        );
    }

    PathExpr.prototype.toString = function () {
        if (this.filter != undefined) {
            var filterStr = toString(this.filter);

            if (Utilities.instance_of(this.filter, XString)) {
                return wrap("'", "'", filterStr);
            }
            if (this.filterPredicates != undefined && this.filterPredicates.length) {
                return wrap('(', ')', filterStr) +
                    PathExpr.predicatesString(this.filterPredicates);
            }
            if (this.locationPath != undefined) {
                return filterStr +
                    (this.locationPath.absolute ? '' : '/') +
                    toString(this.locationPath);
            }

            return filterStr;
        }

        return toString(this.locationPath);
    };

    PathExpr.getOwnerElement = function (n) {
        // DOM 2 has ownerElement
        if (n.ownerElement) {
            return n.ownerElement;
        }
        // DOM 1 Internet Explorer can use selectSingleNode (ironically)
        try {
            if (n.selectSingleNode) {
                return n.selectSingleNode("..");
            }
        } catch (e) {
        }
        // Other DOM 1 implementations must use this egregious search
        var doc = n.nodeType == NodeTypes.DOCUMENT_NODE
            ? n
            : n.ownerDocument;
        var elts = doc.getElementsByTagName("*");
        for (var i = 0; i < elts.length; i++) {
            var elt = elts.item(i);
            var nnm = elt.attributes;
            for (var j = 0; j < nnm.length; j++) {
                var an = nnm.item(j);
                if (an === n) {
                    return elt;
                }
            }
        }
        return null;
    };

    // LocationPath //////////////////////////////////////////////////////////////

    LocationPath.prototype = new Object();
    LocationPath.prototype.constructor = LocationPath;
    LocationPath.superclass = Object.prototype;

    function LocationPath(abs, steps) {
        if (arguments.length > 0) {
            this.init(abs, steps);
        }
    }

    LocationPath.prototype.init = function (abs, steps) {
        this.absolute = abs;
        this.steps = steps;
    };

    LocationPath.prototype.toString = function () {
        return (
            (this.absolute ? '/' : '') +
            map(toString, this.steps).join('/')
        );
    };

    // Step //////////////////////////////////////////////////////////////////////

    Step.prototype = new Object();
    Step.prototype.constructor = Step;
    Step.superclass = Object.prototype;

    function Step(axis, nodetest, preds) {
        if (arguments.length > 0) {
            this.init(axis, nodetest, preds);
        }
    }

    Step.prototype.init = function (axis, nodetest, preds) {
        this.axis = axis;
        this.nodeTest = nodetest;
        this.predicates = preds;
    };

    Step.prototype.toString = function () {
        return Step.STEPNAMES[this.axis] +
            "::" +
            this.nodeTest.toString() +
            PathExpr.predicatesString(this.predicates);
    };


    Step.ANCESTOR = 0;
    Step.ANCESTORORSELF = 1;
    Step.ATTRIBUTE = 2;
    Step.CHILD = 3;
    Step.DESCENDANT = 4;
    Step.DESCENDANTORSELF = 5;
    Step.FOLLOWING = 6;
    Step.FOLLOWINGSIBLING = 7;
    Step.NAMESPACE = 8;
    Step.PARENT = 9;
    Step.PRECEDING = 10;
    Step.PRECEDINGSIBLING = 11;
    Step.SELF = 12;

    Step.STEPNAMES = reduce(function (acc, x) { return acc[x[0]] = x[1], acc; }, {}, [
        [Step.ANCESTOR, 'ancestor'],
        [Step.ANCESTORORSELF, 'ancestor-or-self'],
        [Step.ATTRIBUTE, 'attribute'],
        [Step.CHILD, 'child'],
        [Step.DESCENDANT, 'descendant'],
        [Step.DESCENDANTORSELF, 'descendant-or-self'],
        [Step.FOLLOWING, 'following'],
        [Step.FOLLOWINGSIBLING, 'following-sibling'],
        [Step.NAMESPACE, 'namespace'],
        [Step.PARENT, 'parent'],
        [Step.PRECEDING, 'preceding'],
        [Step.PRECEDINGSIBLING, 'preceding-sibling'],
        [Step.SELF, 'self']
    ]);

    // NodeTest //////////////////////////////////////////////////////////////////

    NodeTest.prototype = new Object();
    NodeTest.prototype.constructor = NodeTest;
    NodeTest.superclass = Object.prototype;

    function NodeTest(type, value) {
        if (arguments.length > 0) {
            this.init(type, value);
        }
    }

    NodeTest.prototype.init = function (type, value) {
        this.type = type;
        this.value = value;
    };

    NodeTest.prototype.toString = function () {
        return "<unknown nodetest type>";
    };

    NodeTest.prototype.matches = function (n, xpc) {
        console.warn('unknown node test type');
    };

    NodeTest.NAMETESTANY = 0;
    NodeTest.NAMETESTPREFIXANY = 1;
    NodeTest.NAMETESTQNAME = 2;
    NodeTest.COMMENT = 3;
    NodeTest.TEXT = 4;
    NodeTest.PI = 5;
    NodeTest.NODE = 6;

    NodeTest.isNodeType = function (types) {
        return function (node) {
            return includes(types, node.nodeType);
        };
    };

    NodeTest.makeNodeTestType = function (type, members, ctor) {
        var newType = ctor || function () { };

        newType.prototype = new NodeTest(type);
        newType.prototype.constructor = newType;

        assign(newType.prototype, members);

        return newType;
    };
    // create invariant node test for certain node types
    NodeTest.makeNodeTypeTest = function (type, nodeTypes, stringVal) {
        return new (NodeTest.makeNodeTestType(type, {
            matches: NodeTest.isNodeType(nodeTypes),
            toString: always(stringVal)
        }))();
    };

    NodeTest.hasPrefix = function (node) {
        return node.prefix || (node.nodeName || node.tagName).indexOf(':') !== -1;
    };

    NodeTest.isElementOrAttribute = NodeTest.isNodeType([1, 2]);
    NodeTest.nameSpaceMatches = function (prefix, xpc, n) {
        var nNamespace = (n.namespaceURI || '');

        if (!prefix) {
            return !nNamespace || (xpc.allowAnyNamespaceForNoPrefix && !NodeTest.hasPrefix(n));
        }

        var ns = xpc.namespaceResolver.getNamespace(prefix, xpc.expressionContextNode);

        if (ns == null) {
            throw new Error("Cannot resolve QName " + prefix);
        }

        return ns === nNamespace;
    };
    NodeTest.localNameMatches = function (localName, xpc, n) {
        var nLocalName = (n.localName || n.nodeName);

        return xpc.caseInsensitive
            ? localName.toLowerCase() === nLocalName.toLowerCase()
            : localName === nLocalName;
    };

    NodeTest.NameTestPrefixAny = NodeTest.makeNodeTestType(
        NodeTest.NAMETESTPREFIXANY,
        {
            matches: function (n, xpc) {
                return NodeTest.isElementOrAttribute(n) &&
                    NodeTest.nameSpaceMatches(this.prefix, xpc, n);
            },
            toString: function () {
                return this.prefix + ":*";
            }
        },
        function NameTestPrefixAny(prefix) { this.prefix = prefix; }
    );

    NodeTest.NameTestQName = NodeTest.makeNodeTestType(
        NodeTest.NAMETESTQNAME,
        {
            matches: function (n, xpc) {
                return NodeTest.isNodeType(
                    [
                        NodeTypes.ELEMENT_NODE,
                        NodeTypes.ATTRIBUTE_NODE,
                        XPathNamespace.XPATH_NAMESPACE_NODE,
                    ]
                )(n) &&
                    NodeTest.nameSpaceMatches(this.prefix, xpc, n) &&
                    NodeTest.localNameMatches(this.localName, xpc, n);
            },
            toString: function () {
                return this.name;
            }
        },
        function NameTestQName(name) {
            var nameParts = name.split(':');

            this.name = name;
            this.prefix = nameParts.length > 1 ? nameParts[0] : null;
            this.localName = nameParts[nameParts.length > 1 ? 1 : 0];
        }
    );

    NodeTest.PITest = NodeTest.makeNodeTestType(NodeTest.PI, {
        matches: function (n, xpc) {
            return NodeTest.isNodeType(
                [NodeTypes.PROCESSING_INSTRUCTION_NODE]
            )(n) &&
                (n.target || n.nodeName) === this.name;
        },
        toString: function () {
            return wrap('processing-instruction("', '")', this.name);
        }
    }, function (name) { this.name = name; })

    // singletons

    // elements, attributes, namespaces
    NodeTest.nameTestAny = NodeTest.makeNodeTypeTest(
        NodeTest.NAMETESTANY,
        [
            NodeTypes.ELEMENT_NODE,
            NodeTypes.ATTRIBUTE_NODE,
            XPathNamespace.XPATH_NAMESPACE_NODE,
        ],
        '*'
    );
    // text, cdata
    NodeTest.textTest = NodeTest.makeNodeTypeTest(
        NodeTest.TEXT,
        [
            NodeTypes.TEXT_NODE,
            NodeTypes.CDATA_SECTION_NODE,
        ],
        'text()'
    );
    NodeTest.commentTest = NodeTest.makeNodeTypeTest(
        NodeTest.COMMENT,
        [NodeTypes.COMMENT_NODE],
        'comment()'
    );
    // elements, attributes, text, cdata, PIs, comments, document nodes
    NodeTest.nodeTest = NodeTest.makeNodeTypeTest(
        NodeTest.NODE,
        [
            NodeTypes.ELEMENT_NODE,
            NodeTypes.ATTRIBUTE_NODE, 
            NodeTypes.TEXT_NODE, 
            NodeTypes.CDATA_SECTION_NODE,
            NodeTypes.PROCESSING_INSTRUCTION_NODE,
            NodeTypes.COMMENT_NODE,
            NodeTypes.DOCUMENT_NODE,
        ],
        'node()'
    );
    NodeTest.anyPiTest = NodeTest.makeNodeTypeTest(
        NodeTest.PI,
        [NodeTypes.PROCESSING_INSTRUCTION_NODE],
        'processing-instruction()'
    );

    // VariableReference /////////////////////////////////////////////////////////

    VariableReference.prototype = new Expression();
    VariableReference.prototype.constructor = VariableReference;
    VariableReference.superclass = Expression.prototype;

    function VariableReference(v) {
        if (arguments.length > 0) {
            this.init(v);
        }
    }

    VariableReference.prototype.init = function (v) {
        this.variable = v;
    };

    VariableReference.prototype.toString = function () {
        return "$" + this.variable;
    };

    VariableReference.prototype.evaluate = function (c) {
        var parts = Utilities.resolveQName(this.variable, c.namespaceResolver, c.contextNode, false);

        if (parts[0] == null) {
            throw new Error("Cannot resolve QName " + fn);
        }
        var result = c.variableResolver.getVariable(parts[1], parts[0]);
        if (!result) {
            throw XPathException.fromMessage("Undeclared variable: " + this.toString());
        }
        return result;
    };

    // FunctionCall //////////////////////////////////////////////////////////////

    FunctionCall.prototype = new Expression();
    FunctionCall.prototype.constructor = FunctionCall;
    FunctionCall.superclass = Expression.prototype;

    function FunctionCall(fn, args) {
        if (arguments.length > 0) {
            this.init(fn, args);
        }
    }

    FunctionCall.prototype.init = function (fn, args) {
        this.functionName = fn;
        this.arguments = args;
    };

    FunctionCall.prototype.toString = function () {
        var s = this.functionName + "(";
        for (var i = 0; i < this.arguments.length; i++) {
            if (i > 0) {
                s += ", ";
            }
            s += this.arguments[i].toString();
        }
        return s + ")";
    };

    FunctionCall.prototype.evaluate = function (c) {
        var f = FunctionResolver.getFunctionFromContext(this.functionName, c);

        if (!f) {
            throw new Error("Unknown function " + this.functionName);
        }

        var a = [c].concat(this.arguments);
        return f.apply(c.functionResolver.thisArg, a);
    };

    // Operators /////////////////////////////////////////////////////////////////

    var Operators = new Object();

    Operators.equals = function (l, r) {
        return l.equals(r);
    };

    Operators.notequal = function (l, r) {
        return l.notequal(r);
    };

    Operators.lessthan = function (l, r) {
        return l.lessthan(r);
    };

    Operators.greaterthan = function (l, r) {
        return l.greaterthan(r);
    };

    Operators.lessthanorequal = function (l, r) {
        return l.lessthanorequal(r);
    };

    Operators.greaterthanorequal = function (l, r) {
        return l.greaterthanorequal(r);
    };

    // XString ///////////////////////////////////////////////////////////////////

    XString.prototype = new Expression();
    XString.prototype.constructor = XString;
    XString.superclass = Expression.prototype;

    function XString(s) {
        if (arguments.length > 0) {
            this.init(s);
        }
    }

    XString.prototype.init = function (s) {
        this.str = String(s);
    };

    XString.prototype.toString = function () {
        return this.str;
    };

    XString.prototype.evaluate = function (c) {
        return this;
    };

    XString.prototype.string = function () {
        return this;
    };

    XString.prototype.number = function () {
        return new XNumber(this.str);
    };

    XString.prototype.bool = function () {
        return new XBoolean(this.str);
    };

    XString.prototype.nodeset = function () {
        throw new Error("Cannot convert string to nodeset");
    };

    XString.prototype.stringValue = function () {
        return this.str;
    };

    XString.prototype.numberValue = function () {
        return this.number().numberValue();
    };

    XString.prototype.booleanValue = function () {
        return this.bool().booleanValue();
    };

    XString.prototype.equals = function (r) {
        if (Utilities.instance_of(r, XBoolean)) {
            return this.bool().equals(r);
        }
        if (Utilities.instance_of(r, XNumber)) {
            return this.number().equals(r);
        }
        if (Utilities.instance_of(r, XNodeSet)) {
            return r.compareWithString(this, Operators.equals);
        }
        return new XBoolean(this.str == r.str);
    };

    XString.prototype.notequal = function (r) {
        if (Utilities.instance_of(r, XBoolean)) {
            return this.bool().notequal(r);
        }
        if (Utilities.instance_of(r, XNumber)) {
            return this.number().notequal(r);
        }
        if (Utilities.instance_of(r, XNodeSet)) {
            return r.compareWithString(this, Operators.notequal);
        }
        return new XBoolean(this.str != r.str);
    };

    XString.prototype.lessthan = function (r) {
        return this.number().lessthan(r);
    };

    XString.prototype.greaterthan = function (r) {
        return this.number().greaterthan(r);
    };

    XString.prototype.lessthanorequal = function (r) {
        return this.number().lessthanorequal(r);
    };

    XString.prototype.greaterthanorequal = function (r) {
        return this.number().greaterthanorequal(r);
    };

    // XNumber ///////////////////////////////////////////////////////////////////

    XNumber.prototype = new Expression();
    XNumber.prototype.constructor = XNumber;
    XNumber.superclass = Expression.prototype;

    function XNumber(n) {
        if (arguments.length > 0) {
            this.init(n);
        }
    }

    XNumber.prototype.init = function (n) {
        this.num = typeof n === "string" ? this.parse(n) : Number(n);
    };

    XNumber.prototype.numberFormat = /^\s*-?[0-9]*\.?[0-9]+\s*$/;

    XNumber.prototype.parse = function (s) {
        // XPath representation of numbers is more restrictive than what Number() or parseFloat() allow
        return this.numberFormat.test(s) ? parseFloat(s) : Number.NaN;
    };

    function padSmallNumber(numberStr) {
        var parts = numberStr.split('e-');
        var base = parts[0].replace('.', '');
        var exponent = Number(parts[1]);

        for (var i = 0; i < exponent - 1; i += 1) {
            base = '0' + base;
        }

        return '0.' + base;
    }

    function padLargeNumber(numberStr) {
        var parts = numberStr.split('e');
        var base = parts[0].replace('.', '');
        var exponent = Number(parts[1]);
        var zerosToAppend = exponent + 1 - base.length;

        for (var i = 0; i < zerosToAppend; i += 1) {
            base += '0';
        }

        return base;
    }

    XNumber.prototype.toString = function () {
        var strValue = this.num.toString();

        if (strValue.indexOf('e-') !== -1) {
            return padSmallNumber(strValue);
        }

        if (strValue.indexOf('e') !== -1) {
            return padLargeNumber(strValue);
        }

        return strValue;
    };

    XNumber.prototype.evaluate = function (c) {
        return this;
    };

    XNumber.prototype.string = function () {


        return new XString(this.toString());
    };

    XNumber.prototype.number = function () {
        return this;
    };

    XNumber.prototype.bool = function () {
        return new XBoolean(this.num);
    };

    XNumber.prototype.nodeset = function () {
        throw new Error("Cannot convert number to nodeset");
    };

    XNumber.prototype.stringValue = function () {
        return this.string().stringValue();
    };

    XNumber.prototype.numberValue = function () {
        return this.num;
    };

    XNumber.prototype.booleanValue = function () {
        return this.bool().booleanValue();
    };

    XNumber.prototype.negate = function () {
        return new XNumber(-this.num);
    };

    XNumber.prototype.equals = function (r) {
        if (Utilities.instance_of(r, XBoolean)) {
            return this.bool().equals(r);
        }
        if (Utilities.instance_of(r, XString)) {
            return this.equals(r.number());
        }
        if (Utilities.instance_of(r, XNodeSet)) {
            return r.compareWithNumber(this, Operators.equals);
        }
        return new XBoolean(this.num == r.num);
    };

    XNumber.prototype.notequal = function (r) {
        if (Utilities.instance_of(r, XBoolean)) {
            return this.bool().notequal(r);
        }
        if (Utilities.instance_of(r, XString)) {
            return this.notequal(r.number());
        }
        if (Utilities.instance_of(r, XNodeSet)) {
            return r.compareWithNumber(this, Operators.notequal);
        }
        return new XBoolean(this.num != r.num);
    };

    XNumber.prototype.lessthan = function (r) {
        if (Utilities.instance_of(r, XNodeSet)) {
            return r.compareWithNumber(this, Operators.greaterthan);
        }
        if (Utilities.instance_of(r, XBoolean) || Utilities.instance_of(r, XString)) {
            return this.lessthan(r.number());
        }
        return new XBoolean(this.num < r.num);
    };

    XNumber.prototype.greaterthan = function (r) {
        if (Utilities.instance_of(r, XNodeSet)) {
            return r.compareWithNumber(this, Operators.lessthan);
        }
        if (Utilities.instance_of(r, XBoolean) || Utilities.instance_of(r, XString)) {
            return this.greaterthan(r.number());
        }
        return new XBoolean(this.num > r.num);
    };

    XNumber.prototype.lessthanorequal = function (r) {
        if (Utilities.instance_of(r, XNodeSet)) {
            return r.compareWithNumber(this, Operators.greaterthanorequal);
        }
        if (Utilities.instance_of(r, XBoolean) || Utilities.instance_of(r, XString)) {
            return this.lessthanorequal(r.number());
        }
        return new XBoolean(this.num <= r.num);
    };

    XNumber.prototype.greaterthanorequal = function (r) {
        if (Utilities.instance_of(r, XNodeSet)) {
            return r.compareWithNumber(this, Operators.lessthanorequal);
        }
        if (Utilities.instance_of(r, XBoolean) || Utilities.instance_of(r, XString)) {
            return this.greaterthanorequal(r.number());
        }
        return new XBoolean(this.num >= r.num);
    };

    XNumber.prototype.plus = function (r) {
        return new XNumber(this.num + r.num);
    };

    XNumber.prototype.minus = function (r) {
        return new XNumber(this.num - r.num);
    };

    XNumber.prototype.multiply = function (r) {
        return new XNumber(this.num * r.num);
    };

    XNumber.prototype.div = function (r) {
        return new XNumber(this.num / r.num);
    };

    XNumber.prototype.mod = function (r) {
        return new XNumber(this.num % r.num);
    };

    // XBoolean //////////////////////////////////////////////////////////////////

    XBoolean.prototype = new Expression();
    XBoolean.prototype.constructor = XBoolean;
    XBoolean.superclass = Expression.prototype;

    function XBoolean(b) {
        if (arguments.length > 0) {
            this.init(b);
        }
    }

    XBoolean.prototype.init = function (b) {
        this.b = Boolean(b);
    };

    XBoolean.prototype.toString = function () {
        return this.b.toString();
    };

    XBoolean.prototype.evaluate = function (c) {
        return this;
    };

    XBoolean.prototype.string = function () {
        return new XString(this.b);
    };

    XBoolean.prototype.number = function () {
        return new XNumber(this.b);
    };

    XBoolean.prototype.bool = function () {
        return this;
    };

    XBoolean.prototype.nodeset = function () {
        throw new Error("Cannot convert boolean to nodeset");
    };

    XBoolean.prototype.stringValue = function () {
        return this.string().stringValue();
    };

    XBoolean.prototype.numberValue = function () {
        return this.number().numberValue();
    };

    XBoolean.prototype.booleanValue = function () {
        return this.b;
    };

    XBoolean.prototype.not = function () {
        return new XBoolean(!this.b);
    };

    XBoolean.prototype.equals = function (r) {
        if (Utilities.instance_of(r, XString) || Utilities.instance_of(r, XNumber)) {
            return this.equals(r.bool());
        }
        if (Utilities.instance_of(r, XNodeSet)) {
            return r.compareWithBoolean(this, Operators.equals);
        }
        return new XBoolean(this.b == r.b);
    };

    XBoolean.prototype.notequal = function (r) {
        if (Utilities.instance_of(r, XString) || Utilities.instance_of(r, XNumber)) {
            return this.notequal(r.bool());
        }
        if (Utilities.instance_of(r, XNodeSet)) {
            return r.compareWithBoolean(this, Operators.notequal);
        }
        return new XBoolean(this.b != r.b);
    };

    XBoolean.prototype.lessthan = function (r) {
        return this.number().lessthan(r);
    };

    XBoolean.prototype.greaterthan = function (r) {
        return this.number().greaterthan(r);
    };

    XBoolean.prototype.lessthanorequal = function (r) {
        return this.number().lessthanorequal(r);
    };

    XBoolean.prototype.greaterthanorequal = function (r) {
        return this.number().greaterthanorequal(r);
    };

    XBoolean.true_ = new XBoolean(true);
    XBoolean.false_ = new XBoolean(false);

    // AVLTree ///////////////////////////////////////////////////////////////////

    AVLTree.prototype = new Object();
    AVLTree.prototype.constructor = AVLTree;
    AVLTree.superclass = Object.prototype;

    function AVLTree(n) {
        this.init(n);
    }

    AVLTree.prototype.init = function (n) {
        this.left = null;
        this.right = null;
        this.node = n;
        this.depth = 1;
    };

    AVLTree.prototype.balance = function () {
        var ldepth = this.left == null ? 0 : this.left.depth;
        var rdepth = this.right == null ? 0 : this.right.depth;

        if (ldepth > rdepth + 1) {
            // LR or LL rotation
            var lldepth = this.left.left == null ? 0 : this.left.left.depth;
            var lrdepth = this.left.right == null ? 0 : this.left.right.depth;

            if (lldepth < lrdepth) {
                // LR rotation consists of a RR rotation of the left child
                this.left.rotateRR();
                // plus a LL rotation of this node, which happens anyway
            }
            this.rotateLL();
        } else if (ldepth + 1 < rdepth) {
            // RR or RL rorarion
            var rrdepth = this.right.right == null ? 0 : this.right.right.depth;
            var rldepth = this.right.left == null ? 0 : this.right.left.depth;

            if (rldepth > rrdepth) {
                // RR rotation consists of a LL rotation of the right child
                this.right.rotateLL();
                // plus a RR rotation of this node, which happens anyway
            }
            this.rotateRR();
        }
    };

    AVLTree.prototype.rotateLL = function () {
        // the left side is too long => rotate from the left (_not_ leftwards)
        var nodeBefore = this.node;
        var rightBefore = this.right;
        this.node = this.left.node;
        this.right = this.left;
        this.left = this.left.left;
        this.right.left = this.right.right;
        this.right.right = rightBefore;
        this.right.node = nodeBefore;
        this.right.updateInNewLocation();
        this.updateInNewLocation();
    };

    AVLTree.prototype.rotateRR = function () {
        // the right side is too long => rotate from the right (_not_ rightwards)
        var nodeBefore = this.node;
        var leftBefore = this.left;
        this.node = this.right.node;
        this.left = this.right;
        this.right = this.right.right;
        this.left.right = this.left.left;
        this.left.left = leftBefore;
        this.left.node = nodeBefore;
        this.left.updateInNewLocation();
        this.updateInNewLocation();
    };

    AVLTree.prototype.updateInNewLocation = function () {
        this.getDepthFromChildren();
    };

    AVLTree.prototype.getDepthFromChildren = function () {
        this.depth = this.node == null ? 0 : 1;
        if (this.left != null) {
            this.depth = this.left.depth + 1;
        }
        if (this.right != null && this.depth <= this.right.depth) {
            this.depth = this.right.depth + 1;
        }
    };

    function nodeOrder(n1, n2) {
        if (n1 === n2) {
            return 0;
        }

        if (n1.compareDocumentPosition) {
            var cpos = n1.compareDocumentPosition(n2);

            if (cpos & 0x01) {
                // not in the same document; return an arbitrary result (is there a better way to do this)
                return 1;
            }
            if (cpos & 0x0A) {
                // n2 precedes or contains n1
                return 1;
            }
            if (cpos & 0x14) {
                // n2 follows or is contained by n1
                return -1;
            }

            return 0;
        }

        var d1 = 0,
            d2 = 0;
        for (var m1 = n1; m1 != null; m1 = m1.parentNode || m1.ownerElement) {
            d1++;
        }
        for (var m2 = n2; m2 != null; m2 = m2.parentNode || m2.ownerElement) {
            d2++;
        }

        // step up to same depth
        if (d1 > d2) {
            while (d1 > d2) {
                n1 = n1.parentNode || n1.ownerElement;
                d1--;
            }
            if (n1 === n2) {
                return 1;
            }
        } else if (d2 > d1) {
            while (d2 > d1) {
                n2 = n2.parentNode || n2.ownerElement;
                d2--;
            }
            if (n1 === n2) {
                return -1;
            }
        }

        var n1Par = n1.parentNode || n1.ownerElement,
            n2Par = n2.parentNode || n2.ownerElement;

        // find common parent
        while (n1Par !== n2Par) {
            n1 = n1Par;
            n2 = n2Par;
            n1Par = n1.parentNode || n1.ownerElement;
            n2Par = n2.parentNode || n2.ownerElement;
        }

        var n1isAttr = Utilities.isAttribute(n1);
        var n2isAttr = Utilities.isAttribute(n2);

        if (n1isAttr && !n2isAttr) {
            return -1;
        }
        if (!n1isAttr && n2isAttr) {
            return 1;
        }

        if (n1Par) {
            var cn = n1isAttr ? n1Par.attributes : n1Par.childNodes,
                len = cn.length;
            for (var i = 0; i < len; i += 1) {
                var n = cn[i];
                if (n === n1) {
                    return -1;
                }
                if (n === n2) {
                    return 1;
                }
            }
        }

        throw new Error('Unexpected: could not determine node order');
    }

    AVLTree.prototype.add = function (n) {
        if (n === this.node) {
            return false;
        }

        var o = nodeOrder(n, this.node);

        var ret = false;
        if (o == -1) {
            if (this.left == null) {
                this.left = new AVLTree(n);
                ret = true;
            } else {
                ret = this.left.add(n);
                if (ret) {
                    this.balance();
                }
            }
        } else if (o == 1) {
            if (this.right == null) {
                this.right = new AVLTree(n);
                ret = true;
            } else {
                ret = this.right.add(n);
                if (ret) {
                    this.balance();
                }
            }
        }

        if (ret) {
            this.getDepthFromChildren();
        }
        return ret;
    };

    // XNodeSet //////////////////////////////////////////////////////////////////

    XNodeSet.prototype = new Expression();
    XNodeSet.prototype.constructor = XNodeSet;
    XNodeSet.superclass = Expression.prototype;

    function XNodeSet() {
        this.init();
    }

    XNodeSet.prototype.init = function () {
        this.tree = null;
        this.nodes = [];
        this.size = 0;
    };

    XNodeSet.prototype.toString = function () {
        var p = this.first();
        if (p == null) {
            return "";
        }
        return this.stringForNode(p);
    };

    XNodeSet.prototype.evaluate = function (c) {
        return this;
    };

    XNodeSet.prototype.string = function () {
        return new XString(this.toString());
    };

    XNodeSet.prototype.stringValue = function () {
        return this.toString();
    };

    XNodeSet.prototype.number = function () {
        return new XNumber(this.string());
    };

    XNodeSet.prototype.numberValue = function () {
        return Number(this.string());
    };

    XNodeSet.prototype.bool = function () {
        return new XBoolean(this.booleanValue());
    };

    XNodeSet.prototype.booleanValue = function () {
        return !!this.size;
    };

    XNodeSet.prototype.nodeset = function () {
        return this;
    };

    XNodeSet.prototype.stringForNode = function (n) {
        if (n.nodeType == NodeTypes.DOCUMENT_NODE ||
            n.nodeType == NodeTypes.ELEMENT_NODE ||
            n.nodeType === NodeTypes.DOCUMENT_FRAGMENT_NODE) {
            return this.stringForContainerNode(n);
        }
        if (n.nodeType === NodeTypes.ATTRIBUTE_NODE) {
            return n.value || n.nodeValue;
        }
        if (n.isNamespaceNode) {
            return n.namespace;
        }
        return n.nodeValue;
    };

    XNodeSet.prototype.stringForContainerNode = function (n) {
        var s = "";
        for (var n2 = n.firstChild; n2 != null; n2 = n2.nextSibling) {
            var nt = n2.nodeType;
            //  Element,    Text,       CDATA,      Document,   Document Fragment
            if (nt === 1 || nt === 3 || nt === 4 || nt === 9 || nt === 11) {
                s += this.stringForNode(n2);
            }
        }
        return s;
    };

    XNodeSet.prototype.buildTree = function () {
        if (!this.tree && this.nodes.length) {
            this.tree = new AVLTree(this.nodes[0]);
            for (var i = 1; i < this.nodes.length; i += 1) {
                this.tree.add(this.nodes[i]);
            }
        }

        return this.tree;
    };

    XNodeSet.prototype.first = function () {
        var p = this.buildTree();
        if (p == null) {
            return null;
        }
        while (p.left != null) {
            p = p.left;
        }
        return p.node;
    };

    XNodeSet.prototype.add = function (n) {
        for (var i = 0; i < this.nodes.length; i += 1) {
            if (n === this.nodes[i]) {
                return;
            }
        }

        this.tree = null;
        this.nodes.push(n);
        this.size += 1;
    };

    XNodeSet.prototype.addArray = function (ns) {
        var self = this;

        forEach(function (x) { self.add(x); }, ns);
    };

    /**
     * Returns an array of the node set's contents in document order
     */
    XNodeSet.prototype.toArray = function () {
        var a = [];
        this.toArrayRec(this.buildTree(), a);
        return a;
    };

    XNodeSet.prototype.toArrayRec = function (t, a) {
        if (t != null) {
            this.toArrayRec(t.left, a);
            a.push(t.node);
            this.toArrayRec(t.right, a);
        }
    };

    /**
     * Returns an array of the node set's contents in arbitrary order
     */
    XNodeSet.prototype.toUnsortedArray = function () {
        return this.nodes.slice();
    };

    XNodeSet.prototype.compareWithString = function (r, o) {
        var a = this.toUnsortedArray();
        for (var i = 0; i < a.length; i++) {
            var n = a[i];
            var l = new XString(this.stringForNode(n));
            var res = o(l, r);
            if (res.booleanValue()) {
                return res;
            }
        }
        return new XBoolean(false);
    };

    XNodeSet.prototype.compareWithNumber = function (r, o) {
        var a = this.toUnsortedArray();
        for (var i = 0; i < a.length; i++) {
            var n = a[i];
            var l = new XNumber(this.stringForNode(n));
            var res = o(l, r);
            if (res.booleanValue()) {
                return res;
            }
        }
        return new XBoolean(false);
    };

    XNodeSet.prototype.compareWithBoolean = function (r, o) {
        return o(this.bool(), r);
    };

    XNodeSet.prototype.compareWithNodeSet = function (r, o) {
        var arr = this.toUnsortedArray();
        var oInvert = function (lop, rop) { return o(rop, lop); };

        for (var i = 0; i < arr.length; i++) {
            var l = new XString(this.stringForNode(arr[i]));

            var res = r.compareWithString(l, oInvert);
            if (res.booleanValue()) {
                return res;
            }
        }

        return new XBoolean(false);
    };

    XNodeSet.compareWith = curry(function (o, r) {
        if (Utilities.instance_of(r, XString)) {
            return this.compareWithString(r, o);
        }
        if (Utilities.instance_of(r, XNumber)) {
            return this.compareWithNumber(r, o);
        }
        if (Utilities.instance_of(r, XBoolean)) {
            return this.compareWithBoolean(r, o);
        }
        return this.compareWithNodeSet(r, o);
    });

    XNodeSet.prototype.equals = XNodeSet.compareWith(Operators.equals);
    XNodeSet.prototype.notequal = XNodeSet.compareWith(Operators.notequal);
    XNodeSet.prototype.lessthan = XNodeSet.compareWith(Operators.lessthan);
    XNodeSet.prototype.greaterthan = XNodeSet.compareWith(Operators.greaterthan);
    XNodeSet.prototype.lessthanorequal = XNodeSet.compareWith(Operators.lessthanorequal);
    XNodeSet.prototype.greaterthanorequal = XNodeSet.compareWith(Operators.greaterthanorequal);

    XNodeSet.prototype.union = function (r) {
        var ns = new XNodeSet();
        ns.addArray(this.toUnsortedArray());
        ns.addArray(r.toUnsortedArray());
        return ns;
    };

    // XPathNamespace ////////////////////////////////////////////////////////////

    XPathNamespace.prototype = new Object();
    XPathNamespace.prototype.constructor = XPathNamespace;
    XPathNamespace.superclass = Object.prototype;

    function XPathNamespace(pre, ns, p) {
        this.isXPathNamespace = true;
        this.ownerDocument = p.ownerDocument;
        this.nodeName = "#namespace";
        this.prefix = pre;
        this.localName = pre;
        this.namespaceURI = ns;
        this.nodeValue = ns;
        this.ownerElement = p;
        this.nodeType = XPathNamespace.XPATH_NAMESPACE_NODE;
    }

    XPathNamespace.prototype.toString = function () {
        return "{ \"" + this.prefix + "\", \"" + this.namespaceURI + "\" }";
    };

    // XPathContext //////////////////////////////////////////////////////////////

    XPathContext.prototype = new Object();
    XPathContext.prototype.constructor = XPathContext;
    XPathContext.superclass = Object.prototype;

    function XPathContext(vr, nr, fr) {
        this.variableResolver = vr != null ? vr : new VariableResolver();
        this.namespaceResolver = nr != null ? nr : new NamespaceResolver();
        this.functionResolver = fr != null ? fr : new FunctionResolver();
    }

    XPathContext.prototype.extend = function (newProps) {
        return assign(new XPathContext(), this, newProps);
    };

    // VariableResolver //////////////////////////////////////////////////////////

    VariableResolver.prototype = new Object();
    VariableResolver.prototype.constructor = VariableResolver;
    VariableResolver.superclass = Object.prototype;

    function VariableResolver() {
    }

    VariableResolver.prototype.getVariable = function (ln, ns) {
        return null;
    };

    // FunctionResolver //////////////////////////////////////////////////////////

    FunctionResolver.prototype = new Object();
    FunctionResolver.prototype.constructor = FunctionResolver;
    FunctionResolver.superclass = Object.prototype;

    function FunctionResolver(thisArg) {
        this.thisArg = thisArg != null ? thisArg : Functions;
        this.functions = new Object();
        this.addStandardFunctions();
    }

    FunctionResolver.prototype.addStandardFunctions = function () {
        this.functions["{}last"] = Functions.last;
        this.functions["{}position"] = Functions.position;
        this.functions["{}count"] = Functions.count;
        this.functions["{}id"] = Functions.id;
        this.functions["{}local-name"] = Functions.localName;
        this.functions["{}namespace-uri"] = Functions.namespaceURI;
        this.functions["{}name"] = Functions.name;
        this.functions["{}string"] = Functions.string;
        this.functions["{}concat"] = Functions.concat;
        this.functions["{}starts-with"] = Functions.startsWith;
        this.functions["{}contains"] = Functions.contains;
        this.functions["{}substring-before"] = Functions.substringBefore;
        this.functions["{}substring-after"] = Functions.substringAfter;
        this.functions["{}substring"] = Functions.substring;
        this.functions["{}string-length"] = Functions.stringLength;
        this.functions["{}normalize-space"] = Functions.normalizeSpace;
        this.functions["{}translate"] = Functions.translate;
        this.functions["{}boolean"] = Functions.boolean_;
        this.functions["{}not"] = Functions.not;
        this.functions["{}true"] = Functions.true_;
        this.functions["{}false"] = Functions.false_;
        this.functions["{}lang"] = Functions.lang;
        this.functions["{}number"] = Functions.number;
        this.functions["{}sum"] = Functions.sum;
        this.functions["{}floor"] = Functions.floor;
        this.functions["{}ceiling"] = Functions.ceiling;
        this.functions["{}round"] = Functions.round;
    };

    FunctionResolver.prototype.addFunction = function (ns, ln, f) {
        this.functions["{" + ns + "}" + ln] = f;
    };

    FunctionResolver.getFunctionFromContext = function (qName, context) {
        var parts = Utilities.resolveQName(qName, context.namespaceResolver, context.contextNode, false);

        if (parts[0] === null) {
            throw new Error("Cannot resolve QName " + name);
        }

        return context.functionResolver.getFunction(parts[1], parts[0]);
    };

    FunctionResolver.prototype.getFunction = function (localName, namespace) {
        return this.functions["{" + namespace + "}" + localName];
    };

    // NamespaceResolver /////////////////////////////////////////////////////////

    NamespaceResolver.prototype = new Object();
    NamespaceResolver.prototype.constructor = NamespaceResolver;
    NamespaceResolver.superclass = Object.prototype;

    function NamespaceResolver() {
    }

    NamespaceResolver.prototype.getNamespace = function (prefix, n) {
        if (prefix == "xml") {
            return XPath.XML_NAMESPACE_URI;
        } else if (prefix == "xmlns") {
            return XPath.XMLNS_NAMESPACE_URI;
        }
        if (n.nodeType == NodeTypes.DOCUMENT_NODE) {
            n = n.documentElement;
        } else if (n.nodeType == NodeTypes.ATTRIBUTE_NODE) {
            n = PathExpr.getOwnerElement(n);
        } else if (n.nodeType != NodeTypes.ELEMENT_NODE) {
            n = n.parentNode;
        }
        while (n != null && n.nodeType == NodeTypes.ELEMENT_NODE) {
            var nnm = n.attributes;
            for (var i = 0; i < nnm.length; i++) {
                var a = nnm.item(i);
                var aname = a.name || a.nodeName;
                if ((aname === "xmlns" && prefix === "")
                    || aname === "xmlns:" + prefix) {
                    return String(a.value || a.nodeValue);
                }
            }
            n = n.parentNode;
        }
        return null;
    };

    // Functions /////////////////////////////////////////////////////////////////

    var Functions = new Object();

    Functions.last = function (c) {
        if (arguments.length != 1) {
            throw new Error("Function last expects ()");
        }

        return new XNumber(c.contextSize);
    };

    Functions.position = function (c) {
        if (arguments.length != 1) {
            throw new Error("Function position expects ()");
        }

        return new XNumber(c.contextPosition);
    };

    Functions.count = function () {
        var c = arguments[0];
        var ns;
        if (arguments.length != 2 || !Utilities.instance_of(ns = arguments[1].evaluate(c), XNodeSet)) {
            throw new Error("Function count expects (node-set)");
        }
        return new XNumber(ns.size);
    };

    Functions.id = function () {
        var c = arguments[0];
        var id;
        if (arguments.length != 2) {
            throw new Error("Function id expects (object)");
        }
        id = arguments[1].evaluate(c);
        if (Utilities.instance_of(id, XNodeSet)) {
            id = id.toArray().join(" ");
        } else {
            id = id.stringValue();
        }
        var ids = id.split(/[\x0d\x0a\x09\x20]+/);
        var count = 0;
        var ns = new XNodeSet();
        var doc = c.contextNode.nodeType == NodeTypes.DOCUMENT_NODE
            ? c.contextNode
            : c.contextNode.ownerDocument;
        for (var i = 0; i < ids.length; i++) {
            var n;
            if (doc.getElementById) {
                n = doc.getElementById(ids[i]);
            } else {
                n = Utilities.getElementById(doc, ids[i]);
            }
            if (n != null) {
                ns.add(n);
                count++;
            }
        }
        return ns;
    };

    Functions.localName = function (c, eNode) {
        var n;

        if (arguments.length == 1) {
            n = c.contextNode;
        } else if (arguments.length == 2) {
            n = eNode.evaluate(c).first();
        } else {
            throw new Error("Function local-name expects (node-set?)");
        }

        if (n == null) {
            return new XString("");
        }

        return new XString(
            n.localName ||     //  standard elements and attributes
            n.baseName ||     //  IE
            n.target ||     //  processing instructions
            n.nodeName ||     //  DOM1 elements
            ""                 //  fallback
        );
    };

    Functions.namespaceURI = function () {
        var c = arguments[0];
        var n;
        if (arguments.length == 1) {
            n = c.contextNode;
        } else if (arguments.length == 2) {
            n = arguments[1].evaluate(c).first();
        } else {
            throw new Error("Function namespace-uri expects (node-set?)");
        }
        if (n == null) {
            return new XString("");
        }
        return new XString(n.namespaceURI);
    };

    Functions.name = function () {
        var c = arguments[0];
        var n;
        if (arguments.length == 1) {
            n = c.contextNode;
        } else if (arguments.length == 2) {
            n = arguments[1].evaluate(c).first();
        } else {
            throw new Error("Function name expects (node-set?)");
        }
        if (n == null) {
            return new XString("");
        }
        if (n.nodeType == NodeTypes.ELEMENT_NODE) {
            return new XString(n.nodeName);
        } else if (n.nodeType == NodeTypes.ATTRIBUTE_NODE) {
            return new XString(n.name || n.nodeName);
        } else if (n.nodeType === NodeTypes.PROCESSING_INSTRUCTION_NODE) {
            return new XString(n.target || n.nodeName);
        } else if (n.localName == null) {
            return new XString("");
        } else {
            return new XString(n.localName);
        }
    };

    Functions.string = function () {
        var c = arguments[0];
        if (arguments.length == 1) {
            return new XString(XNodeSet.prototype.stringForNode(c.contextNode));
        } else if (arguments.length == 2) {
            return arguments[1].evaluate(c).string();
        }
        throw new Error("Function string expects (object?)");
    };

    Functions.concat = function (c) {
        if (arguments.length < 3) {
            throw new Error("Function concat expects (string, string[, string]*)");
        }
        var s = "";
        for (var i = 1; i < arguments.length; i++) {
            s += arguments[i].evaluate(c).stringValue();
        }
        return new XString(s);
    };

    Functions.startsWith = function () {
        var c = arguments[0];
        if (arguments.length != 3) {
            throw new Error("Function startsWith expects (string, string)");
        }
        var s1 = arguments[1].evaluate(c).stringValue();
        var s2 = arguments[2].evaluate(c).stringValue();
        return new XBoolean(s1.substring(0, s2.length) == s2);
    };

    Functions.contains = function () {
        var c = arguments[0];
        if (arguments.length != 3) {
            throw new Error("Function contains expects (string, string)");
        }
        var s1 = arguments[1].evaluate(c).stringValue();
        var s2 = arguments[2].evaluate(c).stringValue();
        return new XBoolean(s1.indexOf(s2) !== -1);
    };

    Functions.substringBefore = function () {
        var c = arguments[0];
        if (arguments.length != 3) {
            throw new Error("Function substring-before expects (string, string)");
        }
        var s1 = arguments[1].evaluate(c).stringValue();
        var s2 = arguments[2].evaluate(c).stringValue();
        return new XString(s1.substring(0, s1.indexOf(s2)));
    };

    Functions.substringAfter = function () {
        var c = arguments[0];
        if (arguments.length != 3) {
            throw new Error("Function substring-after expects (string, string)");
        }
        var s1 = arguments[1].evaluate(c).stringValue();
        var s2 = arguments[2].evaluate(c).stringValue();
        if (s2.length == 0) {
            return new XString(s1);
        }
        var i = s1.indexOf(s2);
        if (i == -1) {
            return new XString("");
        }
        return new XString(s1.substring(i + s2.length));
    };

    Functions.substring = function () {
        var c = arguments[0];
        if (!(arguments.length == 3 || arguments.length == 4)) {
            throw new Error("Function substring expects (string, number, number?)");
        }
        var s = arguments[1].evaluate(c).stringValue();
        var n1 = Math.round(arguments[2].evaluate(c).numberValue()) - 1;
        var n2 = arguments.length == 4 ? n1 + Math.round(arguments[3].evaluate(c).numberValue()) : undefined;
        return new XString(s.substring(n1, n2));
    };

    Functions.stringLength = function () {
        var c = arguments[0];
        var s;
        if (arguments.length == 1) {
            s = XNodeSet.prototype.stringForNode(c.contextNode);
        } else if (arguments.length == 2) {
            s = arguments[1].evaluate(c).stringValue();
        } else {
            throw new Error("Function string-length expects (string?)");
        }
        return new XNumber(s.length);
    };

    Functions.normalizeSpace = function () {
        var c = arguments[0];
        var s;
        if (arguments.length == 1) {
            s = XNodeSet.prototype.stringForNode(c.contextNode);
        } else if (arguments.length == 2) {
            s = arguments[1].evaluate(c).stringValue();
        } else {
            throw new Error("Function normalize-space expects (string?)");
        }
        var i = 0;
        var j = s.length - 1;
        while (Utilities.isSpace(s.charCodeAt(j))) {
            j--;
        }
        var t = "";
        while (i <= j && Utilities.isSpace(s.charCodeAt(i))) {
            i++;
        }
        while (i <= j) {
            if (Utilities.isSpace(s.charCodeAt(i))) {
                t += " ";
                while (i <= j && Utilities.isSpace(s.charCodeAt(i))) {
                    i++;
                }
            } else {
                t += s.charAt(i);
                i++;
            }
        }
        return new XString(t);
    };

    Functions.translate = function (c, eValue, eFrom, eTo) {
        if (arguments.length != 4) {
            throw new Error("Function translate expects (string, string, string)");
        }

        var value = eValue.evaluate(c).stringValue();
        var from = eFrom.evaluate(c).stringValue();
        var to = eTo.evaluate(c).stringValue();

        var cMap = reduce(function (acc, ch, i) {
            if (!(ch in acc)) {
                acc[ch] = i > to.length ? '' : to[i];
            }
            return acc;
        }, {}, from);

        var t = join(
            '',
            map(function (ch) {
                return ch in cMap ? cMap[ch] : ch;
            }, value)
        );

        return new XString(t);
    };

    Functions.boolean_ = function () {
        var c = arguments[0];
        if (arguments.length != 2) {
            throw new Error("Function boolean expects (object)");
        }
        return arguments[1].evaluate(c).bool();
    };

    Functions.not = function (c, eValue) {
        if (arguments.length != 2) {
            throw new Error("Function not expects (object)");
        }
        return eValue.evaluate(c).bool().not();
    };

    Functions.true_ = function () {
        if (arguments.length != 1) {
            throw new Error("Function true expects ()");
        }
        return XBoolean.true_;
    };

    Functions.false_ = function () {
        if (arguments.length != 1) {
            throw new Error("Function false expects ()");
        }
        return XBoolean.false_;
    };

    Functions.lang = function () {
        var c = arguments[0];
        if (arguments.length != 2) {
            throw new Error("Function lang expects (string)");
        }
        var lang;
        for (var n = c.contextNode; n != null && n.nodeType != NodeTypes.DOCUMENT_NODE; n = n.parentNode) {
            var a = n.getAttributeNS(XPath.XML_NAMESPACE_URI, "lang");
            if (a != null) {
                lang = String(a);
                break;
            }
        }
        if (lang == null) {
            return XBoolean.false_;
        }
        var s = arguments[1].evaluate(c).stringValue();
        return new XBoolean(lang.substring(0, s.length) == s
            && (lang.length == s.length || lang.charAt(s.length) == '-'));
    };

    Functions.number = function () {
        var c = arguments[0];
        if (!(arguments.length == 1 || arguments.length == 2)) {
            throw new Error("Function number expects (object?)");
        }
        if (arguments.length == 1) {
            return new XNumber(XNodeSet.prototype.stringForNode(c.contextNode));
        }
        return arguments[1].evaluate(c).number();
    };

    Functions.sum = function () {
        var c = arguments[0];
        var ns;
        if (arguments.length != 2 || !Utilities.instance_of((ns = arguments[1].evaluate(c)), XNodeSet)) {
            throw new Error("Function sum expects (node-set)");
        }
        ns = ns.toUnsortedArray();
        var n = 0;
        for (var i = 0; i < ns.length; i++) {
            n += new XNumber(XNodeSet.prototype.stringForNode(ns[i])).numberValue();
        }
        return new XNumber(n);
    };

    Functions.floor = function () {
        var c = arguments[0];
        if (arguments.length != 2) {
            throw new Error("Function floor expects (number)");
        }
        return new XNumber(Math.floor(arguments[1].evaluate(c).numberValue()));
    };

    Functions.ceiling = function () {
        var c = arguments[0];
        if (arguments.length != 2) {
            throw new Error("Function ceiling expects (number)");
        }
        return new XNumber(Math.ceil(arguments[1].evaluate(c).numberValue()));
    };

    Functions.round = function () {
        var c = arguments[0];
        if (arguments.length != 2) {
            throw new Error("Function round expects (number)");
        }
        return new XNumber(Math.round(arguments[1].evaluate(c).numberValue()));
    };

    // Utilities /////////////////////////////////////////////////////////////////

    var Utilities = new Object();

    Utilities.isAttribute = function (val) {
        return val && (val.nodeType === NodeTypes.ATTRIBUTE_NODE || val.ownerElement);
    }

    Utilities.splitQName = function (qn) {
        var i = qn.indexOf(":");
        if (i == -1) {
            return [null, qn];
        }
        return [qn.substring(0, i), qn.substring(i + 1)];
    };

    Utilities.resolveQName = function (qn, nr, n, useDefault) {
        var parts = Utilities.splitQName(qn);
        if (parts[0] != null) {
            parts[0] = nr.getNamespace(parts[0], n);
        } else {
            if (useDefault) {
                parts[0] = nr.getNamespace("", n);
                if (parts[0] == null) {
                    parts[0] = "";
                }
            } else {
                parts[0] = "";
            }
        }
        return parts;
    };

    Utilities.isSpace = function (c) {
        return c == 0x9 || c == 0xd || c == 0xa || c == 0x20;
    };

    Utilities.isLetter = function (c) {
        return c >= 0x0041 && c <= 0x005A ||
            c >= 0x0061 && c <= 0x007A ||
            c >= 0x00C0 && c <= 0x00D6 ||
            c >= 0x00D8 && c <= 0x00F6 ||
            c >= 0x00F8 && c <= 0x00FF ||
            c >= 0x0100 && c <= 0x0131 ||
            c >= 0x0134 && c <= 0x013E ||
            c >= 0x0141 && c <= 0x0148 ||
            c >= 0x014A && c <= 0x017E ||
            c >= 0x0180 && c <= 0x01C3 ||
            c >= 0x01CD && c <= 0x01F0 ||
            c >= 0x01F4 && c <= 0x01F5 ||
            c >= 0x01FA && c <= 0x0217 ||
            c >= 0x0250 && c <= 0x02A8 ||
            c >= 0x02BB && c <= 0x02C1 ||
            c == 0x0386 ||
            c >= 0x0388 && c <= 0x038A ||
            c == 0x038C ||
            c >= 0x038E && c <= 0x03A1 ||
            c >= 0x03A3 && c <= 0x03CE ||
            c >= 0x03D0 && c <= 0x03D6 ||
            c == 0x03DA ||
            c == 0x03DC ||
            c == 0x03DE ||
            c == 0x03E0 ||
            c >= 0x03E2 && c <= 0x03F3 ||
            c >= 0x0401 && c <= 0x040C ||
            c >= 0x040E && c <= 0x044F ||
            c >= 0x0451 && c <= 0x045C ||
            c >= 0x045E && c <= 0x0481 ||
            c >= 0x0490 && c <= 0x04C4 ||
            c >= 0x04C7 && c <= 0x04C8 ||
            c >= 0x04CB && c <= 0x04CC ||
            c >= 0x04D0 && c <= 0x04EB ||
            c >= 0x04EE && c <= 0x04F5 ||
            c >= 0x04F8 && c <= 0x04F9 ||
            c >= 0x0531 && c <= 0x0556 ||
            c == 0x0559 ||
            c >= 0x0561 && c <= 0x0586 ||
            c >= 0x05D0 && c <= 0x05EA ||
            c >= 0x05F0 && c <= 0x05F2 ||
            c >= 0x0621 && c <= 0x063A ||
            c >= 0x0641 && c <= 0x064A ||
            c >= 0x0671 && c <= 0x06B7 ||
            c >= 0x06BA && c <= 0x06BE ||
            c >= 0x06C0 && c <= 0x06CE ||
            c >= 0x06D0 && c <= 0x06D3 ||
            c == 0x06D5 ||
            c >= 0x06E5 && c <= 0x06E6 ||
            c >= 0x0905 && c <= 0x0939 ||
            c == 0x093D ||
            c >= 0x0958 && c <= 0x0961 ||
            c >= 0x0985 && c <= 0x098C ||
            c >= 0x098F && c <= 0x0990 ||
            c >= 0x0993 && c <= 0x09A8 ||
            c >= 0x09AA && c <= 0x09B0 ||
            c == 0x09B2 ||
            c >= 0x09B6 && c <= 0x09B9 ||
            c >= 0x09DC && c <= 0x09DD ||
            c >= 0x09DF && c <= 0x09E1 ||
            c >= 0x09F0 && c <= 0x09F1 ||
            c >= 0x0A05 && c <= 0x0A0A ||
            c >= 0x0A0F && c <= 0x0A10 ||
            c >= 0x0A13 && c <= 0x0A28 ||
            c >= 0x0A2A && c <= 0x0A30 ||
            c >= 0x0A32 && c <= 0x0A33 ||
            c >= 0x0A35 && c <= 0x0A36 ||
            c >= 0x0A38 && c <= 0x0A39 ||
            c >= 0x0A59 && c <= 0x0A5C ||
            c == 0x0A5E ||
            c >= 0x0A72 && c <= 0x0A74 ||
            c >= 0x0A85 && c <= 0x0A8B ||
            c == 0x0A8D ||
            c >= 0x0A8F && c <= 0x0A91 ||
            c >= 0x0A93 && c <= 0x0AA8 ||
            c >= 0x0AAA && c <= 0x0AB0 ||
            c >= 0x0AB2 && c <= 0x0AB3 ||
            c >= 0x0AB5 && c <= 0x0AB9 ||
            c == 0x0ABD ||
            c == 0x0AE0 ||
            c >= 0x0B05 && c <= 0x0B0C ||
            c >= 0x0B0F && c <= 0x0B10 ||
            c >= 0x0B13 && c <= 0x0B28 ||
            c >= 0x0B2A && c <= 0x0B30 ||
            c >= 0x0B32 && c <= 0x0B33 ||
            c >= 0x0B36 && c <= 0x0B39 ||
            c == 0x0B3D ||
            c >= 0x0B5C && c <= 0x0B5D ||
            c >= 0x0B5F && c <= 0x0B61 ||
            c >= 0x0B85 && c <= 0x0B8A ||
            c >= 0x0B8E && c <= 0x0B90 ||
            c >= 0x0B92 && c <= 0x0B95 ||
            c >= 0x0B99 && c <= 0x0B9A ||
            c == 0x0B9C ||
            c >= 0x0B9E && c <= 0x0B9F ||
            c >= 0x0BA3 && c <= 0x0BA4 ||
            c >= 0x0BA8 && c <= 0x0BAA ||
            c >= 0x0BAE && c <= 0x0BB5 ||
            c >= 0x0BB7 && c <= 0x0BB9 ||
            c >= 0x0C05 && c <= 0x0C0C ||
            c >= 0x0C0E && c <= 0x0C10 ||
            c >= 0x0C12 && c <= 0x0C28 ||
            c >= 0x0C2A && c <= 0x0C33 ||
            c >= 0x0C35 && c <= 0x0C39 ||
            c >= 0x0C60 && c <= 0x0C61 ||
            c >= 0x0C85 && c <= 0x0C8C ||
            c >= 0x0C8E && c <= 0x0C90 ||
            c >= 0x0C92 && c <= 0x0CA8 ||
            c >= 0x0CAA && c <= 0x0CB3 ||
            c >= 0x0CB5 && c <= 0x0CB9 ||
            c == 0x0CDE ||
            c >= 0x0CE0 && c <= 0x0CE1 ||
            c >= 0x0D05 && c <= 0x0D0C ||
            c >= 0x0D0E && c <= 0x0D10 ||
            c >= 0x0D12 && c <= 0x0D28 ||
            c >= 0x0D2A && c <= 0x0D39 ||
            c >= 0x0D60 && c <= 0x0D61 ||
            c >= 0x0E01 && c <= 0x0E2E ||
            c == 0x0E30 ||
            c >= 0x0E32 && c <= 0x0E33 ||
            c >= 0x0E40 && c <= 0x0E45 ||
            c >= 0x0E81 && c <= 0x0E82 ||
            c == 0x0E84 ||
            c >= 0x0E87 && c <= 0x0E88 ||
            c == 0x0E8A ||
            c == 0x0E8D ||
            c >= 0x0E94 && c <= 0x0E97 ||
            c >= 0x0E99 && c <= 0x0E9F ||
            c >= 0x0EA1 && c <= 0x0EA3 ||
            c == 0x0EA5 ||
            c == 0x0EA7 ||
            c >= 0x0EAA && c <= 0x0EAB ||
            c >= 0x0EAD && c <= 0x0EAE ||
            c == 0x0EB0 ||
            c >= 0x0EB2 && c <= 0x0EB3 ||
            c == 0x0EBD ||
            c >= 0x0EC0 && c <= 0x0EC4 ||
            c >= 0x0F40 && c <= 0x0F47 ||
            c >= 0x0F49 && c <= 0x0F69 ||
            c >= 0x10A0 && c <= 0x10C5 ||
            c >= 0x10D0 && c <= 0x10F6 ||
            c == 0x1100 ||
            c >= 0x1102 && c <= 0x1103 ||
            c >= 0x1105 && c <= 0x1107 ||
            c == 0x1109 ||
            c >= 0x110B && c <= 0x110C ||
            c >= 0x110E && c <= 0x1112 ||
            c == 0x113C ||
            c == 0x113E ||
            c == 0x1140 ||
            c == 0x114C ||
            c == 0x114E ||
            c == 0x1150 ||
            c >= 0x1154 && c <= 0x1155 ||
            c == 0x1159 ||
            c >= 0x115F && c <= 0x1161 ||
            c == 0x1163 ||
            c == 0x1165 ||
            c == 0x1167 ||
            c == 0x1169 ||
            c >= 0x116D && c <= 0x116E ||
            c >= 0x1172 && c <= 0x1173 ||
            c == 0x1175 ||
            c == 0x119E ||
            c == 0x11A8 ||
            c == 0x11AB ||
            c >= 0x11AE && c <= 0x11AF ||
            c >= 0x11B7 && c <= 0x11B8 ||
            c == 0x11BA ||
            c >= 0x11BC && c <= 0x11C2 ||
            c == 0x11EB ||
            c == 0x11F0 ||
            c == 0x11F9 ||
            c >= 0x1E00 && c <= 0x1E9B ||
            c >= 0x1EA0 && c <= 0x1EF9 ||
            c >= 0x1F00 && c <= 0x1F15 ||
            c >= 0x1F18 && c <= 0x1F1D ||
            c >= 0x1F20 && c <= 0x1F45 ||
            c >= 0x1F48 && c <= 0x1F4D ||
            c >= 0x1F50 && c <= 0x1F57 ||
            c == 0x1F59 ||
            c == 0x1F5B ||
            c == 0x1F5D ||
            c >= 0x1F5F && c <= 0x1F7D ||
            c >= 0x1F80 && c <= 0x1FB4 ||
            c >= 0x1FB6 && c <= 0x1FBC ||
            c == 0x1FBE ||
            c >= 0x1FC2 && c <= 0x1FC4 ||
            c >= 0x1FC6 && c <= 0x1FCC ||
            c >= 0x1FD0 && c <= 0x1FD3 ||
            c >= 0x1FD6 && c <= 0x1FDB ||
            c >= 0x1FE0 && c <= 0x1FEC ||
            c >= 0x1FF2 && c <= 0x1FF4 ||
            c >= 0x1FF6 && c <= 0x1FFC ||
            c == 0x2126 ||
            c >= 0x212A && c <= 0x212B ||
            c == 0x212E ||
            c >= 0x2180 && c <= 0x2182 ||
            c >= 0x3041 && c <= 0x3094 ||
            c >= 0x30A1 && c <= 0x30FA ||
            c >= 0x3105 && c <= 0x312C ||
            c >= 0xAC00 && c <= 0xD7A3 ||
            c >= 0x4E00 && c <= 0x9FA5 ||
            c == 0x3007 ||
            c >= 0x3021 && c <= 0x3029;
    };

    Utilities.isNCNameChar = function (c) {
        return c >= 0x0030 && c <= 0x0039
            || c >= 0x0660 && c <= 0x0669
            || c >= 0x06F0 && c <= 0x06F9
            || c >= 0x0966 && c <= 0x096F
            || c >= 0x09E6 && c <= 0x09EF
            || c >= 0x0A66 && c <= 0x0A6F
            || c >= 0x0AE6 && c <= 0x0AEF
            || c >= 0x0B66 && c <= 0x0B6F
            || c >= 0x0BE7 && c <= 0x0BEF
            || c >= 0x0C66 && c <= 0x0C6F
            || c >= 0x0CE6 && c <= 0x0CEF
            || c >= 0x0D66 && c <= 0x0D6F
            || c >= 0x0E50 && c <= 0x0E59
            || c >= 0x0ED0 && c <= 0x0ED9
            || c >= 0x0F20 && c <= 0x0F29
            || c == 0x002E
            || c == 0x002D
            || c == 0x005F
            || Utilities.isLetter(c)
            || c >= 0x0300 && c <= 0x0345
            || c >= 0x0360 && c <= 0x0361
            || c >= 0x0483 && c <= 0x0486
            || c >= 0x0591 && c <= 0x05A1
            || c >= 0x05A3 && c <= 0x05B9
            || c >= 0x05BB && c <= 0x05BD
            || c == 0x05BF
            || c >= 0x05C1 && c <= 0x05C2
            || c == 0x05C4
            || c >= 0x064B && c <= 0x0652
            || c == 0x0670
            || c >= 0x06D6 && c <= 0x06DC
            || c >= 0x06DD && c <= 0x06DF
            || c >= 0x06E0 && c <= 0x06E4
            || c >= 0x06E7 && c <= 0x06E8
            || c >= 0x06EA && c <= 0x06ED
            || c >= 0x0901 && c <= 0x0903
            || c == 0x093C
            || c >= 0x093E && c <= 0x094C
            || c == 0x094D
            || c >= 0x0951 && c <= 0x0954
            || c >= 0x0962 && c <= 0x0963
            || c >= 0x0981 && c <= 0x0983
            || c == 0x09BC
            || c == 0x09BE
            || c == 0x09BF
            || c >= 0x09C0 && c <= 0x09C4
            || c >= 0x09C7 && c <= 0x09C8
            || c >= 0x09CB && c <= 0x09CD
            || c == 0x09D7
            || c >= 0x09E2 && c <= 0x09E3
            || c == 0x0A02
            || c == 0x0A3C
            || c == 0x0A3E
            || c == 0x0A3F
            || c >= 0x0A40 && c <= 0x0A42
            || c >= 0x0A47 && c <= 0x0A48
            || c >= 0x0A4B && c <= 0x0A4D
            || c >= 0x0A70 && c <= 0x0A71
            || c >= 0x0A81 && c <= 0x0A83
            || c == 0x0ABC
            || c >= 0x0ABE && c <= 0x0AC5
            || c >= 0x0AC7 && c <= 0x0AC9
            || c >= 0x0ACB && c <= 0x0ACD
            || c >= 0x0B01 && c <= 0x0B03
            || c == 0x0B3C
            || c >= 0x0B3E && c <= 0x0B43
            || c >= 0x0B47 && c <= 0x0B48
            || c >= 0x0B4B && c <= 0x0B4D
            || c >= 0x0B56 && c <= 0x0B57
            || c >= 0x0B82 && c <= 0x0B83
            || c >= 0x0BBE && c <= 0x0BC2
            || c >= 0x0BC6 && c <= 0x0BC8
            || c >= 0x0BCA && c <= 0x0BCD
            || c == 0x0BD7
            || c >= 0x0C01 && c <= 0x0C03
            || c >= 0x0C3E && c <= 0x0C44
            || c >= 0x0C46 && c <= 0x0C48
            || c >= 0x0C4A && c <= 0x0C4D
            || c >= 0x0C55 && c <= 0x0C56
            || c >= 0x0C82 && c <= 0x0C83
            || c >= 0x0CBE && c <= 0x0CC4
            || c >= 0x0CC6 && c <= 0x0CC8
            || c >= 0x0CCA && c <= 0x0CCD
            || c >= 0x0CD5 && c <= 0x0CD6
            || c >= 0x0D02 && c <= 0x0D03
            || c >= 0x0D3E && c <= 0x0D43
            || c >= 0x0D46 && c <= 0x0D48
            || c >= 0x0D4A && c <= 0x0D4D
            || c == 0x0D57
            || c == 0x0E31
            || c >= 0x0E34 && c <= 0x0E3A
            || c >= 0x0E47 && c <= 0x0E4E
            || c == 0x0EB1
            || c >= 0x0EB4 && c <= 0x0EB9
            || c >= 0x0EBB && c <= 0x0EBC
            || c >= 0x0EC8 && c <= 0x0ECD
            || c >= 0x0F18 && c <= 0x0F19
            || c == 0x0F35
            || c == 0x0F37
            || c == 0x0F39
            || c == 0x0F3E
            || c == 0x0F3F
            || c >= 0x0F71 && c <= 0x0F84
            || c >= 0x0F86 && c <= 0x0F8B
            || c >= 0x0F90 && c <= 0x0F95
            || c == 0x0F97
            || c >= 0x0F99 && c <= 0x0FAD
            || c >= 0x0FB1 && c <= 0x0FB7
            || c == 0x0FB9
            || c >= 0x20D0 && c <= 0x20DC
            || c == 0x20E1
            || c >= 0x302A && c <= 0x302F
            || c == 0x3099
            || c == 0x309A
            || c == 0x00B7
            || c == 0x02D0
            || c == 0x02D1
            || c == 0x0387
            || c == 0x0640
            || c == 0x0E46
            || c == 0x0EC6
            || c == 0x3005
            || c >= 0x3031 && c <= 0x3035
            || c >= 0x309D && c <= 0x309E
            || c >= 0x30FC && c <= 0x30FE;
    };

    Utilities.coalesceText = function (n) {
        for (var m = n.firstChild; m != null; m = m.nextSibling) {
            if (m.nodeType == NodeTypes.TEXT_NODE || m.nodeType == NodeTypes.CDATA_SECTION_NODE) {
                var s = m.nodeValue;
                var first = m;
                m = m.nextSibling;
                while (m != null && (m.nodeType == NodeTypes.TEXT_NODE || m.nodeType == NodeTypes.CDATA_SECTION_NODE)) {
                    s += m.nodeValue;
                    var del = m;
                    m = m.nextSibling;
                    del.parentNode.removeChild(del);
                }
                if (first.nodeType == NodeTypes.CDATA_SECTION_NODE) {
                    var p = first.parentNode;
                    if (first.nextSibling == null) {
                        p.removeChild(first);
                        p.appendChild(p.ownerDocument.createTextNode(s));
                    } else {
                        var next = first.nextSibling;
                        p.removeChild(first);
                        p.insertBefore(p.ownerDocument.createTextNode(s), next);
                    }
                } else {
                    first.nodeValue = s;
                }
                if (m == null) {
                    break;
                }
            } else if (m.nodeType == NodeTypes.ELEMENT_NODE) {
                Utilities.coalesceText(m);
            }
        }
    };

    Utilities.instance_of = function (o, c) {
        while (o != null) {
            if (o.constructor === c) {
                return true;
            }
            if (o === Object) {
                return false;
            }
            o = o.constructor.superclass;
        }
        return false;
    };

    Utilities.getElementById = function (n, id) {
        // Note that this does not check the DTD to check for actual
        // attributes of type ID, so this may be a bit wrong.
        if (n.nodeType == NodeTypes.ELEMENT_NODE) {
            if (n.getAttribute("id") == id
                || n.getAttributeNS(null, "id") == id) {
                return n;
            }
        }
        for (var m = n.firstChild; m != null; m = m.nextSibling) {
            var res = Utilities.getElementById(m, id);
            if (res != null) {
                return res;
            }
        }
        return null;
    };

    // XPathException ////////////////////////////////////////////////////////////

    var XPathException = (function () {
        function getMessage(code, exception) {
            var msg = exception ? ": " + exception.toString() : "";
            switch (code) {
                case XPathException.INVALID_EXPRESSION_ERR:
                    return "Invalid expression" + msg;
                case XPathException.TYPE_ERR:
                    return "Type error" + msg;
            }
            return null;
        }

        function XPathException(code, error, message) {
            var err = Error.call(this, getMessage(code, error) || message);

            err.code = code;
            err.exception = error;

            return err;
        }

        XPathException.prototype = Object.create(Error.prototype);
        XPathException.prototype.constructor = XPathException;
        XPathException.superclass = Error;

        XPathException.prototype.toString = function () {
            return this.message;
        };

        XPathException.fromMessage = function (message, error) {
            return new XPathException(null, error, message);
        };

        XPathException.INVALID_EXPRESSION_ERR = 51;
        XPathException.TYPE_ERR = 52;

        return XPathException;
    })();

    // XPathExpression ///////////////////////////////////////////////////////////

    XPathExpression.prototype = {};
    XPathExpression.prototype.constructor = XPathExpression;
    XPathExpression.superclass = Object.prototype;

    function XPathExpression(e, r, p) {
        this.xpath = p.parse(e);
        this.context = new XPathContext();
        this.context.namespaceResolver = new XPathNSResolverWrapper(r);
    }

    XPathExpression.getOwnerDocument = function (n) {
        return n.nodeType === NodeTypes.DOCUMENT_NODE ? n : n.ownerDocument;
    }

    XPathExpression.detectHtmlDom = function (n) {
        if (!n) { return false; }

        var doc = XPathExpression.getOwnerDocument(n);

        try {
            return doc.implementation.hasFeature("HTML", "2.0");
        } catch (e) {
            return true;
        }
    }

    XPathExpression.prototype.evaluate = function (n, t, res) {
        this.context.expressionContextNode = n;
        // backward compatibility - no reliable way to detect whether the DOM is HTML, but
        // this library has been using this method up until now, so we will continue to use it
        // ONLY when using an XPathExpression
        this.context.caseInsensitive = XPathExpression.detectHtmlDom(n);

        var result = this.xpath.evaluate(this.context);
        return new XPathResult(result, t);
    }

    // XPathNSResolverWrapper ////////////////////////////////////////////////////

    XPathNSResolverWrapper.prototype = {};
    XPathNSResolverWrapper.prototype.constructor = XPathNSResolverWrapper;
    XPathNSResolverWrapper.superclass = Object.prototype;

    function XPathNSResolverWrapper(r) {
        this.xpathNSResolver = r;
    }

    XPathNSResolverWrapper.prototype.getNamespace = function (prefix, n) {
        if (this.xpathNSResolver == null) {
            return null;
        }
        return this.xpathNSResolver.lookupNamespaceURI(prefix);
    };

    // NodeXPathNSResolver ///////////////////////////////////////////////////////

    NodeXPathNSResolver.prototype = {};
    NodeXPathNSResolver.prototype.constructor = NodeXPathNSResolver;
    NodeXPathNSResolver.superclass = Object.prototype;

    function NodeXPathNSResolver(n) {
        this.node = n;
        this.namespaceResolver = new NamespaceResolver();
    }

    NodeXPathNSResolver.prototype.lookupNamespaceURI = function (prefix) {
        return this.namespaceResolver.getNamespace(prefix, this.node);
    };

    // XPathResult ///////////////////////////////////////////////////////////////

    XPathResult.prototype = {};
    XPathResult.prototype.constructor = XPathResult;
    XPathResult.superclass = Object.prototype;

    function XPathResult(v, t) {
        if (t == XPathResult.ANY_TYPE) {
            if (v.constructor === XString) {
                t = XPathResult.STRING_TYPE;
            } else if (v.constructor === XNumber) {
                t = XPathResult.NUMBER_TYPE;
            } else if (v.constructor === XBoolean) {
                t = XPathResult.BOOLEAN_TYPE;
            } else if (v.constructor === XNodeSet) {
                t = XPathResult.UNORDERED_NODE_ITERATOR_TYPE;
            }
        }
        this.resultType = t;
        switch (t) {
            case XPathResult.NUMBER_TYPE:
                this.numberValue = v.numberValue();
                return;
            case XPathResult.STRING_TYPE:
                this.stringValue = v.stringValue();
                return;
            case XPathResult.BOOLEAN_TYPE:
                this.booleanValue = v.booleanValue();
                return;
            case XPathResult.ANY_UNORDERED_NODE_TYPE:
            case XPathResult.FIRST_ORDERED_NODE_TYPE:
                if (v.constructor === XNodeSet) {
                    this.singleNodeValue = v.first();
                    return;
                }
                break;
            case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
            case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
                if (v.constructor === XNodeSet) {
                    this.invalidIteratorState = false;
                    this.nodes = v.toArray();
                    this.iteratorIndex = 0;
                    return;
                }
                break;
            case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
            case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:
                if (v.constructor === XNodeSet) {
                    this.nodes = v.toArray();
                    this.snapshotLength = this.nodes.length;
                    return;
                }
                break;
        }
        throw new XPathException(XPathException.TYPE_ERR);
    };

    XPathResult.prototype.iterateNext = function () {
        if (this.resultType != XPathResult.UNORDERED_NODE_ITERATOR_TYPE
            && this.resultType != XPathResult.ORDERED_NODE_ITERATOR_TYPE) {
            throw new XPathException(XPathException.TYPE_ERR);
        }
        return this.nodes[this.iteratorIndex++];
    };

    XPathResult.prototype.snapshotItem = function (i) {
        if (this.resultType != XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE
            && this.resultType != XPathResult.ORDERED_NODE_SNAPSHOT_TYPE) {
            throw new XPathException(XPathException.TYPE_ERR);
        }
        return this.nodes[i];
    };

    XPathResult.ANY_TYPE = 0;
    XPathResult.NUMBER_TYPE = 1;
    XPathResult.STRING_TYPE = 2;
    XPathResult.BOOLEAN_TYPE = 3;
    XPathResult.UNORDERED_NODE_ITERATOR_TYPE = 4;
    XPathResult.ORDERED_NODE_ITERATOR_TYPE = 5;
    XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE = 6;
    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE = 7;
    XPathResult.ANY_UNORDERED_NODE_TYPE = 8;
    XPathResult.FIRST_ORDERED_NODE_TYPE = 9;

    // DOM 3 XPath support ///////////////////////////////////////////////////////

    function installDOM3XPathSupport(doc, p) {
        doc.createExpression = function (e, r) {
            try {
                return new XPathExpression(e, r, p);
            } catch (e) {
                throw new XPathException(XPathException.INVALID_EXPRESSION_ERR, e);
            }
        };
        doc.createNSResolver = function (n) {
            return new NodeXPathNSResolver(n);
        };
        doc.evaluate = function (e, cn, r, t, res) {
            if (t < 0 || t > 9) {
                throw { code: 0, toString: function () { return "Request type not supported"; } };
            }
            return doc.createExpression(e, r, p).evaluate(cn, t, res);
        };
    };

    // ---------------------------------------------------------------------------

    // Install DOM 3 XPath support for the current document.
    try {
        var shouldInstall = true;
        try {
            if (document.implementation
                && document.implementation.hasFeature
                && document.implementation.hasFeature("XPath", null)) {
                shouldInstall = false;
            }
        } catch (e) {
        }
        if (shouldInstall) {
            installDOM3XPathSupport(document, new XPathParser());
        }
    } catch (e) {
    }

    // ---------------------------------------------------------------------------
    // exports for node.js

    installDOM3XPathSupport(exports, new XPathParser());

    (function () {
        var parser = new XPathParser();

        var defaultNSResolver = new NamespaceResolver();
        var defaultFunctionResolver = new FunctionResolver();
        var defaultVariableResolver = new VariableResolver();

        function makeNSResolverFromFunction(func) {
            return {
                getNamespace: function (prefix, node) {
                    var ns = func(prefix, node);

                    return ns || defaultNSResolver.getNamespace(prefix, node);
                }
            };
        }

        function makeNSResolverFromObject(obj) {
            return makeNSResolverFromFunction(obj.getNamespace.bind(obj));
        }

        function makeNSResolverFromMap(map) {
            return makeNSResolverFromFunction(function (prefix) {
                return map[prefix];
            });
        }

        function makeNSResolver(resolver) {
            if (resolver && typeof resolver.getNamespace === "function") {
                return makeNSResolverFromObject(resolver);
            }

            if (typeof resolver === "function") {
                return makeNSResolverFromFunction(resolver);
            }

            // assume prefix -> uri mapping
            if (typeof resolver === "object") {
                return makeNSResolverFromMap(resolver);
            }

            return defaultNSResolver;
        }

        /** Converts native JavaScript types to their XPath library equivalent */
        function convertValue(value) {
            if (value === null ||
                typeof value === "undefined" ||
                value instanceof XString ||
                value instanceof XBoolean ||
                value instanceof XNumber ||
                value instanceof XNodeSet) {
                return value;
            }

            switch (typeof value) {
                case "string": return new XString(value);
                case "boolean": return new XBoolean(value);
                case "number": return new XNumber(value);
            }

            // assume node(s)
            var ns = new XNodeSet();
            ns.addArray([].concat(value));
            return ns;
        }

        function makeEvaluator(func) {
            return function (context) {
                var args = Array.prototype.slice.call(arguments, 1).map(function (arg) {
                    return arg.evaluate(context);
                });
                var result = func.apply(this, [].concat(context, args));
                return convertValue(result);
            };
        }

        function makeFunctionResolverFromFunction(func) {
            return {
                getFunction: function (name, namespace) {
                    var found = func(name, namespace);
                    if (found) {
                        return makeEvaluator(found);
                    }
                    return defaultFunctionResolver.getFunction(name, namespace);
                }
            };
        }

        function makeFunctionResolverFromObject(obj) {
            return makeFunctionResolverFromFunction(obj.getFunction.bind(obj));
        }

        function makeFunctionResolverFromMap(map) {
            return makeFunctionResolverFromFunction(function (name) {
                return map[name];
            });
        }

        function makeFunctionResolver(resolver) {
            if (resolver && typeof resolver.getFunction === "function") {
                return makeFunctionResolverFromObject(resolver);
            }

            if (typeof resolver === "function") {
                return makeFunctionResolverFromFunction(resolver);
            }

            // assume map
            if (typeof resolver === "object") {
                return makeFunctionResolverFromMap(resolver);
            }

            return defaultFunctionResolver;
        }

        function makeVariableResolverFromFunction(func) {
            return {
                getVariable: function (name, namespace) {
                    var value = func(name, namespace);
                    return convertValue(value);
                }
            };
        }

        function makeVariableResolver(resolver) {
            if (resolver) {
                if (typeof resolver.getVariable === "function") {
                    return makeVariableResolverFromFunction(resolver.getVariable.bind(resolver));
                }

                if (typeof resolver === "function") {
                    return makeVariableResolverFromFunction(resolver);
                }

                // assume map
                if (typeof resolver === "object") {
                    return makeVariableResolverFromFunction(function (name) {
                        return resolver[name];
                    });
                }
            }

            return defaultVariableResolver;
        }

        function copyIfPresent(prop, dest, source) {
            if (prop in source) { dest[prop] = source[prop]; }
        }

        function makeContext(options) {
            var context = new XPathContext();

            if (options) {
                context.namespaceResolver = makeNSResolver(options.namespaces);
                context.functionResolver = makeFunctionResolver(options.functions);
                context.variableResolver = makeVariableResolver(options.variables);
                context.expressionContextNode = options.node;
                copyIfPresent('allowAnyNamespaceForNoPrefix', context, options);
                copyIfPresent('isHtml', context, options);
            } else {
                context.namespaceResolver = defaultNSResolver;
            }

            return context;
        }

        function evaluate(parsedExpression, options) {
            var context = makeContext(options);

            return parsedExpression.evaluate(context);
        }

        var evaluatorPrototype = {
            evaluate: function (options) {
                return evaluate(this.expression, options);
            }

            , evaluateNumber: function (options) {
                return this.evaluate(options).numberValue();
            }

            , evaluateString: function (options) {
                return this.evaluate(options).stringValue();
            }

            , evaluateBoolean: function (options) {
                return this.evaluate(options).booleanValue();
            }

            , evaluateNodeSet: function (options) {
                return this.evaluate(options).nodeset();
            }

            , select: function (options) {
                return this.evaluateNodeSet(options).toArray()
            }

            , select1: function (options) {
                return this.select(options)[0];
            }
        };

        function parse(xpath) {
            var parsed = parser.parse(xpath);

            return Object.create(evaluatorPrototype, {
                expression: {
                    value: parsed
                }
            });
        }

        exports.parse = parse;
    })();

    assign(
        exports,
        {
            XPath: XPath,
            XPathParser: XPathParser,
            XPathResult: XPathResult,

            Step: Step,
            PathExpr: PathExpr,
            NodeTest: NodeTest,
            LocationPath: LocationPath,

            OrOperation: OrOperation,
            AndOperation: AndOperation,

            BarOperation: BarOperation,

            EqualsOperation: EqualsOperation,
            NotEqualOperation: NotEqualOperation,
            LessThanOperation: LessThanOperation,
            GreaterThanOperation: GreaterThanOperation,
            LessThanOrEqualOperation: LessThanOrEqualOperation,
            GreaterThanOrEqualOperation: GreaterThanOrEqualOperation,

            PlusOperation: PlusOperation,
            MinusOperation: MinusOperation,
            MultiplyOperation: MultiplyOperation,
            DivOperation: DivOperation,
            ModOperation: ModOperation,
            UnaryMinusOperation: UnaryMinusOperation,
          
            FunctionCall: FunctionCall,
            VariableReference: VariableReference,
          
            XPathContext: XPathContext,
          
            XNodeSet: XNodeSet,
            XBoolean: XBoolean,
            XString: XString,
            XNumber: XNumber,
          
            NamespaceResolver: NamespaceResolver,
            FunctionResolver: FunctionResolver,
            VariableResolver: VariableResolver,
          
            Utilities: Utilities,
        }
    );

    // helper
    exports.select = function (e, doc, single) {
        return exports.selectWithResolver(e, doc, null, single);
    };

    exports.useNamespaces = function (mappings) {
        var resolver = {
            mappings: mappings || {},
            lookupNamespaceURI: function (prefix) {
                return this.mappings[prefix];
            }
        };

        return function (e, doc, single) {
            return exports.selectWithResolver(e, doc, resolver, single);
        };
    };

    exports.selectWithResolver = function (e, doc, resolver, single) {
        var expression = new XPathExpression(e, resolver, new XPathParser());
        var type = XPathResult.ANY_TYPE;

        var result = expression.evaluate(doc, type, null);

        if (result.resultType == XPathResult.STRING_TYPE) {
            result = result.stringValue;
        }
        else if (result.resultType == XPathResult.NUMBER_TYPE) {
            result = result.numberValue;
        }
        else if (result.resultType == XPathResult.BOOLEAN_TYPE) {
            result = result.booleanValue;
        }
        else {
            result = result.nodes;
            if (single) {
                result = result[0];
            }
        }

        return result;
    };

    exports.select1 = function (e, doc) {
        return exports.select(e, doc, true);
    };

    var isNodeLike = function (value) {
        return value 
            && typeof value.nodeType === "number" 
            && Number.isInteger(value.nodeType)
            && value.nodeType >= 1
            && value.nodeType <= 11
            && typeof value.nodeName === "string";
    };

    var isArrayOfNodes = function (value) {
        return Array.isArray(value) && value.every(isNodeLike);
    };

    var isNodeOfType = function (type) {
        return function (value) {
            return isNodeLike(value) && value.nodeType === type;
        };
    };

    assign(
        exports,
        {
            isNodeLike: isNodeLike,
            isArrayOfNodes: isArrayOfNodes,
            isElement: isNodeOfType(NodeTypes.ELEMENT_NODE),
            isAttribute: isNodeOfType(NodeTypes.ATTRIBUTE_NODE),
            isTextNode: isNodeOfType(NodeTypes.TEXT_NODE),
            isCDATASection: isNodeOfType(NodeTypes.CDATA_SECTION_NODE),
            isProcessingInstruction: isNodeOfType(NodeTypes.PROCESSING_INSTRUCTION_NODE),
            isComment: isNodeOfType(NodeTypes.COMMENT_NODE),
            isDocumentNode: isNodeOfType(NodeTypes.DOCUMENT_NODE),
            isDocumentTypeNode: isNodeOfType(NodeTypes.DOCUMENT_TYPE_NODE),
            isDocumentFragment: isNodeOfType(NodeTypes.DOCUMENT_FRAGMENT_NODE),
        }
    );
    // end non-node wrapper
})(xpath);
                                                                                                                                                                                                                                                                                                                                                                                                                            {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { LRUCache } from 'lru-cache'\nimport { posix, win32 } from 'node:path'\n\nimport { fileURLToPath } from 'node:url'\n\nimport {\n  lstatSync,\n  readdir as readdirCB,\n  readdirSync,\n  readlinkSync,\n  realpathSync as rps,\n} from 'fs'\nimport * as actualFS from 'node:fs'\n\nconst realpathSync = rps.native\n// TODO: test perf of fs/promises realpath vs realpathCB,\n// since the promises one uses realpath.native\n\nimport { lstat, readdir, readlink, realpath } from 'node:fs/promises'\n\nimport { Minipass } from 'minipass'\nimport type { Dirent, Stats } from 'node:fs'\n\n/**\n * An object that will be used to override the default `fs`\n * methods.  Any methods that are not overridden will use Node's\n * built-in implementations.\n *\n * - lstatSync\n * - readdir (callback `withFileTypes` Dirent variant, used for\n *   readdirCB and most walks)\n * - readdirSync\n * - readlinkSync\n * - realpathSync\n * - promises: Object containing the following async methods:\n *   - lstat\n *   - readdir (Dirent variant only)\n *   - readlink\n *   - realpath\n */\nexport interface FSOption {\n  lstatSync?: (path: string) => Stats\n  readdir?: (\n    path: string,\n    options: { withFileTypes: true },\n    cb: (er: NodeJS.ErrnoException | null, entries?: Dirent[]) => any,\n  ) => void\n  readdirSync?: (\n    path: string,\n    options: { withFileTypes: true },\n  ) => Dirent[]\n  readlinkSync?: (path: string) => string\n  realpathSync?: (path: string) => string\n  promises?: {\n    lstat?: (path: string) => Promise<Stats>\n    readdir?: (\n      path: string,\n      options: { withFileTypes: true },\n    ) => Promise<Dirent[]>\n    readlink?: (path: string) => Promise<string>\n    realpath?: (path: string) => Promise<string>\n    [k: string]: any\n  }\n  [k: string]: any\n}\n\ninterface FSValue {\n  lstatSync: (path: string) => Stats\n  readdir: (\n    path: string,\n    options: { withFileTypes: true },\n    cb: (er: NodeJS.ErrnoException | null, entries?: Dirent[]) => any,\n  ) => void\n  readdirSync: (path: string, options: { withFileTypes: true }) => Dirent[]\n  readlinkSync: (path: string) => string\n  realpathSync: (path: string) => string\n  promises: {\n    lstat: (path: string) => Promise<Stats>\n    readdir: (\n      path: string,\n      options: { withFileTypes: true },\n    ) => Promise<Dirent[]>\n    readlink: (path: string) => Promise<string>\n    realpath: (path: string) => Promise<string>\n    [k: string]: any\n  }\n  [k: string]: any\n}\n\nconst defaultFS: FSValue = {\n  lstatSync,\n  readdir: readdirCB,\n  readdirSync,\n  readlinkSync,\n  realpathSync,\n  promises: {\n    lstat,\n    readdir,\n    readlink,\n    realpath,\n  },\n}\n\n// if they just gave us require('fs') then use our default\nconst fsFromOption = (fsOption?: FSOption): FSValue =>\n  !fsOption || fsOption === defaultFS || fsOption === actualFS ?\n    defaultFS\n  : {\n      ...defaultFS,\n      ...fsOption,\n      promises: {\n        ...defaultFS.promises,\n        ...(fsOption.promises || {}),\n      },\n    }\n\n// turn something like //?/c:/ into c:\\\nconst uncDriveRegexp = /^\\\\\\\\\\?\\\\([a-z]:)\\\\?$/i\nconst uncToDrive = (rootPath: string): string =>\n  rootPath.replace(/\\//g, '\\\\').replace(uncDriveRegexp, '$1\\\\')\n\n// windows paths are separated by either / or \\\nconst eitherSep = /[\\\\\\/]/\n\nconst UNKNOWN = 0 // may not even exist, for all we know\nconst IFIFO = 0b0001\nconst IFCHR = 0b0010\nconst IFDIR = 0b0100\nconst IFBLK = 0b0110\nconst IFREG = 0b1000\nconst IFLNK = 0b1010\nconst IFSOCK = 0b1100\nconst IFMT = 0b1111\n\nexport type Type =\n  | 'Unknown'\n  | 'FIFO'\n  | 'CharacterDevice'\n  | 'Directory'\n  | 'BlockDevice'\n  | 'File'\n  | 'SymbolicLink'\n  | 'Socket'\n\n// mask to unset low 4 bits\nconst IFMT_UNKNOWN = ~IFMT\n\n// set after successfully calling readdir() and getting entries.\nconst READDIR_CALLED = 0b0000_0001_0000\n// set after a successful lstat()\nconst LSTAT_CALLED = 0b0000_0010_0000\n// set if an entry (or one of its parents) is definitely not a dir\nconst ENOTDIR = 0b0000_0100_0000\n// set if an entry (or one of its parents) does not exist\n// (can also be set on lstat errors like EACCES or ENAMETOOLONG)\nconst ENOENT = 0b0000_1000_0000\n// cannot have child entries -- also verify &IFMT is either IFDIR or IFLNK\n// set if we fail to readlink\nconst ENOREADLINK = 0b0001_0000_0000\n// set if we know realpath() will fail\nconst ENOREALPATH = 0b0010_0000_0000\n\nconst ENOCHILD = ENOTDIR | ENOENT | ENOREALPATH\nconst TYPEMASK = 0b0011_1111_1111\n\nconst entToType = (s: Dirent | Stats) =>\n  s.isFile() ? IFREG\n  : s.isDirectory() ? IFDIR\n  : s.isSymbolicLink() ? IFLNK\n  : s.isCharacterDevice() ? IFCHR\n  : s.isBlockDevice() ? IFBLK\n  : s.isSocket() ? IFSOCK\n  : s.isFIFO() ? IFIFO\n  : UNKNOWN\n\n// normalize unicode path names\nconst normalizeCache = new Map<string, string>()\nconst normalize = (s: string) => {\n  const c = normalizeCache.get(s)\n  if (c) return c\n  const n = s.normalize('NFKD')\n  normalizeCache.set(s, n)\n  return n\n}\n\nconst normalizeNocaseCache = new Map<string, string>()\nconst normalizeNocase = (s: string) => {\n  const c = normalizeNocaseCache.get(s)\n  if (c) return c\n  const n = normalize(s.toLowerCase())\n  normalizeNocaseCache.set(s, n)\n  return n\n}\n\n/**\n * Options that may be provided to the Path constructor\n */\nexport interface PathOpts {\n  fullpath?: string\n  relative?: string\n  relativePosix?: string\n  parent?: PathBase\n  /**\n   * See {@link FSOption}\n   */\n  fs?: FSOption\n}\n\n/**\n * An LRUCache for storing resolved path strings or Path objects.\n * @internal\n */\nexport class ResolveCache extends LRUCache<string, string> {\n  constructor() {\n    super({ max: 256 })\n  }\n}\n\n// In order to prevent blowing out the js heap by allocating hundreds of\n// thousands of Path entries when walking extremely large trees, the \"children\"\n// in this tree are represented by storing an array of Path entries in an\n// LRUCache, indexed by the parent.  At any time, Path.children() may return an\n// empty array, indicating that it doesn't know about any of its children, and\n// thus has to rebuild that cache.  This is fine, it just means that we don't\n// benefit as much from having the cached entries, but huge directory walks\n// don't blow out the stack, and smaller ones are still as fast as possible.\n//\n//It does impose some complexity when building up the readdir data, because we\n//need to pass a reference to the children array that we started with.\n\n/**\n * an LRUCache for storing child entries.\n * @internal\n */\nexport class ChildrenCache extends LRUCache<PathBase, Children> {\n  constructor(maxSize: number = 16 * 1024) {\n    super({\n      maxSize,\n      // parent + children\n      sizeCalculation: a => a.length + 1,\n    })\n  }\n}\n\n/**\n * Array of Path objects, plus a marker indicating the first provisional entry\n *\n * @internal\n */\nexport type Children = PathBase[] & { provisional: number }\n\nconst setAsCwd = Symbol('PathScurry setAsCwd')\n\n/**\n * Path objects are sort of like a super-powered\n * {@link https://nodejs.org/docs/latest/api/fs.html#class-fsdirent fs.Dirent}\n *\n * Each one represents a single filesystem entry on disk, which may or may not\n * exist. It includes methods for reading various types of information via\n * lstat, readlink, and readdir, and caches all information to the greatest\n * degree possible.\n *\n * Note that fs operations that would normally throw will instead return an\n * \"empty\" value. This is in order to prevent excessive overhead from error\n * stack traces.\n */\nexport abstract class PathBase implements Dirent {\n  /**\n   * the basename of this path\n   *\n   * **Important**: *always* test the path name against any test string\n   * usingthe {@link isNamed} method, and not by directly comparing this\n   * string. Otherwise, unicode path strings that the system sees as identical\n   * will not be properly treated as the same path, leading to incorrect\n   * behavior and possible security issues.\n   */\n  name: string\n  /**\n   * the Path entry corresponding to the path root.\n   *\n   * @internal\n   */\n  root: PathBase\n  /**\n   * All roots found within the current PathScurry family\n   *\n   * @internal\n   */\n  roots: { [k: string]: PathBase }\n  /**\n   * a reference to the parent path, or undefined in the case of root entries\n   *\n   * @internal\n   */\n  parent?: PathBase\n  /**\n   * boolean indicating whether paths are compared case-insensitively\n   * @internal\n   */\n  nocase: boolean\n\n  /**\n   * boolean indicating that this path is the current working directory\n   * of the PathScurry collection that contains it.\n   */\n  isCWD: boolean = false\n\n  /**\n   * the string or regexp used to split paths. On posix, it is `'/'`, and on\n   * windows it is a RegExp matching either `'/'` or `'\\\\'`\n   */\n  abstract splitSep: string | RegExp\n  /**\n   * The path separator string to use when joining paths\n   */\n  abstract sep: string\n\n  // potential default fs override\n  #fs: FSValue\n\n  // Stats fields\n  #dev?: number\n  get dev() {\n    return this.#dev\n  }\n  #mode?: number\n  get mode() {\n    return this.#mode\n  }\n  #nlink?: number\n  get nlink() {\n    return this.#nlink\n  }\n  #uid?: number\n  get uid() {\n    return this.#uid\n  }\n  #gid?: number\n  get gid() {\n    return this.#gid\n  }\n  #rdev?: number\n  get rdev() {\n    return this.#rdev\n  }\n  #blksize?: number\n  get blksize() {\n    return this.#blksize\n  }\n  #ino?: number\n  get ino() {\n    return this.#ino\n  }\n  #size?: number\n  get size() {\n    return this.#size\n  }\n  #blocks?: number\n  get blocks() {\n    return this.#blocks\n  }\n  #atimeMs?: number\n  get atimeMs() {\n    return this.#atimeMs\n  }\n  #mtimeMs?: number\n  get mtimeMs() {\n    return this.#mtimeMs\n  }\n  #ctimeMs?: number\n  get ctimeMs() {\n    return this.#ctimeMs\n  }\n  #birthtimeMs?: number\n  get birthtimeMs() {\n    return this.#birthtimeMs\n  }\n  #atime?: Date\n  get atime() {\n    return this.#atime\n  }\n  #mtime?: Date\n  get mtime() {\n    return this.#mtime\n  }\n  #ctime?: Date\n  get ctime() {\n    return this.#ctime\n  }\n  #birthtime?: Date\n  get birthtime() {\n    return this.#birthtime\n  }\n\n  #matchName: string\n  #depth?: number\n  #fullpath?: string\n  #fullpathPosix?: string\n  #relative?: string\n  #relativePosix?: string\n  #type: number\n  #children: ChildrenCache\n  #linkTarget?: PathBase\n  #realpath?: PathBase\n\n  /**\n   * This property is for compatibility with the Dirent class as of\n   * Node v20, where Dirent['parentPath'] refers to the path of the\n   * directory that was passed to readdir. For root entries, it's the path\n   * to the entry itself.\n   */\n  get parentPath(): string {\n    return (this.parent || this).fullpath()\n  }\n\n  /**\n   * Deprecated alias for Dirent['parentPath'] Somewhat counterintuitively,\n   * this property refers to the *parent* path, not the path object itself.\n   */\n  get path(): string {\n    return this.parentPath\n  }\n\n  /**\n   * Do not create new Path objects directly.  They should always be accessed\n   * via the PathScurry class or other methods on the Path class.\n   *\n   * @internal\n   */\n  constructor(\n    name: string,\n    type: number = UNKNOWN,\n    root: PathBase | undefined,\n    roots: { [k: string]: PathBase },\n    nocase: boolean,\n    children: ChildrenCache,\n    opts: PathOpts,\n  ) {\n    this.name = name\n    this.#matchName = nocase ? normalizeNocase(name) : normalize(name)\n    this.#type = type & TYPEMASK\n    this.nocase = nocase\n    this.roots = roots\n    this.root = root || this\n    this.#children = children\n    this.#fullpath = opts.fullpath\n    this.#relative = opts.relative\n    this.#relativePosix = opts.relativePosix\n    this.parent = opts.parent\n    if (this.parent) {\n      this.#fs = this.parent.#fs\n    } else {\n      this.#fs = fsFromOption(opts.fs)\n    }\n  }\n\n  /**\n   * Returns the depth of the Path object from its root.\n   *\n   * For example, a path at `/foo/bar` would have a depth of 2.\n   */\n  depth(): number {\n    if (this.#depth !== undefined) return this.#depth\n    if (!this.parent) return (this.#depth = 0)\n    return (this.#depth = this.parent.depth() + 1)\n  }\n\n  /**\n   * @internal\n   */\n  abstract getRootString(path: string): string\n  /**\n   * @internal\n   */\n  abstract getRoot(rootPath: string): PathBase\n  /**\n   * @internal\n   */\n  abstract newChild(name: string, type?: number, opts?: PathOpts): PathBase\n\n  /**\n   * @internal\n   */\n  childrenCache() {\n    return this.#children\n  }\n\n  /**\n   * Get the Path object referenced by the string path, resolved from this Path\n   */\n  resolve(path?: string): PathBase {\n    if (!path) {\n      return this\n    }\n    const rootPath = this.getRootString(path)\n    const dir = path.substring(rootPath.length)\n    const dirParts = dir.split(this.splitSep)\n    const result: PathBase =\n      rootPath ?\n        this.getRoot(rootPath).#resolveParts(dirParts)\n      : this.#resolveParts(dirParts)\n    return result\n  }\n\n  #resolveParts(dirParts: string[]) {\n    let p: PathBase = this\n    for (const part of dirParts) {\n      p = p.child(part)\n    }\n    return p\n  }\n\n  /**\n   * Returns the cached children Path objects, if still available.  If they\n   * have fallen out of the cache, then returns an empty array, and resets the\n   * READDIR_CALLED bit, so that future calls to readdir() will require an fs\n   * lookup.\n   *\n   * @internal\n   */\n  children(): Children {\n    const cached = this.#children.get(this)\n    if (cached) {\n      return cached\n    }\n    const children: Children = Object.assign([], { provisional: 0 })\n    this.#children.set(this, children)\n    this.#type &= ~READDIR_CALLED\n    return children\n  }\n\n  /**\n   * Resolves a path portion and returns or creates the child Path.\n   *\n   * Returns `this` if pathPart is `''` or `'.'`, or `parent` if pathPart is\n   * `'..'`.\n   *\n   * This should not be called directly.  If `pathPart` contains any path\n   * separators, it will lead to unsafe undefined behavior.\n   *\n   * Use `Path.resolve()` instead.\n   *\n   * @internal\n   */\n  child(pathPart: string, opts?: PathOpts): PathBase {\n    if (pathPart === '' || pathPart === '.') {\n      return this\n    }\n    if (pathPart === '..') {\n      return this.parent || this\n    }\n\n    // find the child\n    const children = this.children()\n    const name =\n      this.nocase ? normalizeNocase(pathPart) : normalize(pathPart)\n    for (const p of children) {\n      if (p.#matchName === name) {\n        return p\n      }\n    }\n\n    // didn't find it, create provisional child, since it might not\n    // actually exist.  If we know the parent isn't a dir, then\n    // in fact it CAN'T exist.\n    const s = this.parent ? this.sep : ''\n    const fullpath =\n      this.#fullpath ? this.#fullpath + s + pathPart : undefined\n    const pchild = this.newChild(pathPart, UNKNOWN, {\n      ...opts,\n      parent: this,\n      fullpath,\n    })\n\n    if (!this.canReaddir()) {\n      pchild.#type |= ENOENT\n    }\n\n    // don't have to update provisional, because if we have real children,\n    // then provisional is set to children.length, otherwise a lower number\n    children.push(pchild)\n    return pchild\n  }\n\n  /**\n   * The relative path from the cwd. If it does not share an ancestor with\n   * the cwd, then this ends up being equivalent to the fullpath()\n   */\n  relative(): string {\n    if (this.isCWD) return ''\n    if (this.#relative !== undefined) {\n      return this.#relative\n    }\n    const name = this.name\n    const p = this.parent\n    if (!p) {\n      return (this.#relative = this.name)\n    }\n    const pv = p.relative()\n    return pv + (!pv || !p.parent ? '' : this.sep) + name\n  }\n\n  /**\n   * The relative path from the cwd, using / as the path separator.\n   * If it does not share an ancestor with\n   * the cwd, then this ends up being equivalent to the fullpathPosix()\n   * On posix systems, this is identical to relative().\n   */\n  relativePosix(): string {\n    if (this.sep === '/') return this.relative()\n    if (this.isCWD) return ''\n    if (this.#relativePosix !== undefined) return this.#relativePosix\n    const name = this.name\n    const p = this.parent\n    if (!p) {\n      return (this.#relativePosix = this.fullpathPosix())\n    }\n    const pv = p.relativePosix()\n    return pv + (!pv || !p.parent ? '' : '/') + name\n  }\n\n  /**\n   * The fully resolved path string for this Path entry\n   */\n  fullpath(): string {\n    if (this.#fullpath !== undefined) {\n      return this.#fullpath\n    }\n    const name = this.name\n    const p = this.parent\n    if (!p) {\n      return (this.#fullpath = this.name)\n    }\n    const pv = p.fullpath()\n    const fp = pv + (!p.parent ? '' : this.sep) + name\n    return (this.#fullpath = fp)\n  }\n\n  /**\n   * On platforms other than windows, this is identical to fullpath.\n   *\n   * On windows, this is overridden to return the forward-slash form of the\n   * full UNC path.\n   */\n  fullpathPosix(): string {\n    if (this.#fullpathPosix !== undefined) return this.#fullpathPosix\n    if (this.sep === '/') return (this.#fullpathPosix = this.fullpath())\n    if (!this.parent) {\n      const p = this.fullpath().replace(/\\\\/g, '/')\n      if (/^[a-z]:\\//i.test(p)) {\n        return (this.#fullpathPosix = `//?/${p}`)\n      } else {\n        return (this.#fullpathPosix = p)\n      }\n    }\n    const p = this.parent\n    const pfpp = p.fullpathPosix()\n    const fpp = pfpp + (!pfpp || !p.parent ? '' : '/') + this.name\n    return (this.#fullpathPosix = fpp)\n  }\n\n  /**\n   * Is the Path of an unknown type?\n   *\n   * Note that we might know *something* about it if there has been a previous\n   * filesystem operation, for example that it does not exist, or is not a\n   * link, or whether it has child entries.\n   */\n  isUnknown(): boolean {\n    return (this.#type & IFMT) === UNKNOWN\n  }\n\n  isType(type: Type): boolean {\n    return this[`is${type}`]()\n  }\n\n  getType(): Type {\n    return (\n      this.isUnknown() ? 'Unknown'\n      : this.isDirectory() ? 'Directory'\n      : this.isFile() ? 'File'\n      : this.isSymbolicLink() ? 'SymbolicLink'\n      : this.isFIFO() ? 'FIFO'\n      : this.isCharacterDevice() ? 'CharacterDevice'\n      : this.isBlockDevice() ? 'BlockDevice'\n      : /* c8 ignore start */ this.isSocket() ? 'Socket'\n      : 'Unknown'\n    )\n    /* c8 ignore stop */\n  }\n\n  /**\n   * Is the Path a regular file?\n   */\n  isFile(): boolean {\n    return (this.#type & IFMT) === IFREG\n  }\n\n  /**\n   * Is the Path a directory?\n   */\n  isDirectory(): boolean {\n    return (this.#type & IFMT) === IFDIR\n  }\n\n  /**\n   * Is the path a character device?\n   */\n  isCharacterDevice(): boolean {\n    return (this.#type & IFMT) === IFCHR\n  }\n\n  /**\n   * Is the path a block device?\n   */\n  isBlockDevice(): boolean {\n    return (this.#type & IFMT) === IFBLK\n  }\n\n  /**\n   * Is the path a FIFO pipe?\n   */\n  isFIFO(): boolean {\n    return (this.#type & IFMT) === IFIFO\n  }\n\n  /**\n   * Is the path a socket?\n   */\n  isSocket(): boolean {\n    return (this.#type & IFMT) === IFSOCK\n  }\n\n  /**\n   * Is the path a symbolic link?\n   */\n  isSymbolicLink(): boolean {\n    return (this.#type & IFLNK) === IFLNK\n  }\n\n  /**\n   * Return the entry if it has been subject of a successful lstat, or\n   * undefined otherwise.\n   *\n   * Does not read the filesystem, so an undefined result *could* simply\n   * mean that we haven't called lstat on it.\n   */\n  lstatCached(): PathBase | undefined {\n    return this.#type & LSTAT_CALLED ? this : undefined\n  }\n\n  /**\n   * Return the cached link target if the entry has been the subject of a\n   * successful readlink, or undefined otherwise.\n   *\n   * Does not read the filesystem, so an undefined result *could* just mean we\n   * don't have any cached data. Only use it if you are very sure that a\n   * readlink() has been called at some point.\n   */\n  readlinkCached(): PathBase | undefined {\n    return this.#linkTarget\n  }\n\n  /**\n   * Returns the cached realpath target if the entry has been the subject\n   * of a successful realpath, or undefined otherwise.\n   *\n   * Does not read the filesystem, so an undefined result *could* just mean we\n   * don't have any cached data. Only use it if you are very sure that a\n   * realpath() has been called at some point.\n   */\n  realpathCached(): PathBase | undefined {\n    return this.#realpath\n  }\n\n  /**\n   * Returns the cached child Path entries array if the entry has been the\n   * subject of a successful readdir(), or [] otherwise.\n   *\n   * Does not read the filesystem, so an empty array *could* just mean we\n   * don't have any cached data. Only use it if you are very sure that a\n   * readdir() has been called recently enough to still be valid.\n   */\n  readdirCached(): PathBase[] {\n    const children = this.children()\n    return children.slice(0, children.provisional)\n  }\n\n  /**\n   * Return true if it's worth trying to readlink.  Ie, we don't (yet) have\n   * any indication that readlink will definitely fail.\n   *\n   * Returns false if the path is known to not be a symlink, if a previous\n   * readlink failed, or if the entry does not exist.\n   */\n  canReadlink(): boolean {\n    if (this.#linkTarget) return true\n    if (!this.parent) return false\n    // cases where it cannot possibly succeed\n    const ifmt = this.#type & IFMT\n    return !(\n      (ifmt !== UNKNOWN && ifmt !== IFLNK) ||\n      this.#type & ENOREADLINK ||\n      this.#type & ENOENT\n    )\n  }\n\n  /**\n   * Return true if readdir has previously been successfully called on this\n   * path, indicating that cachedReaddir() is likely valid.\n   */\n  calledReaddir(): boolean {\n    return !!(this.#type & READDIR_CALLED)\n  }\n\n  /**\n   * Returns true if the path is known to not exist. That is, a previous lstat\n   * or readdir failed to verify its existence when that would have been\n   * expected, or a parent entry was marked either enoent or enotdir.\n   */\n  isENOENT(): boolean {\n    return !!(this.#type & ENOENT)\n  }\n\n  /**\n   * Return true if the path is a match for the given path name.  This handles\n   * case sensitivity and unicode normalization.\n   *\n   * Note: even on case-sensitive systems, it is **not** safe to test the\n   * equality of the `.name` property to determine whether a given pathname\n   * matches, due to unicode normalization mismatches.\n   *\n   * Always use this method instead of testing the `path.name` property\n   * directly.\n   */\n  isNamed(n: string): boolean {\n    return !this.nocase ?\n        this.#matchName === normalize(n)\n      : this.#matchName === normalizeNocase(n)\n  }\n\n  /**\n   * Return the Path object corresponding to the target of a symbolic link.\n   *\n   * If the Path is not a symbolic link, or if the readlink call fails for any\n   * reason, `undefined` is returned.\n   *\n   * Result is cached, and thus may be outdated if the filesystem is mutated.\n   */\n  async readlink(): Promise<PathBase | undefined> {\n    const target = this.#linkTarget\n    if (target) {\n      return target\n    }\n    if (!this.canReadlink()) {\n      return undefined\n    }\n    /* c8 ignore start */\n    // already covered by the canReadlink test, here for ts grumples\n    if (!this.parent) {\n      return undefined\n    }\n    /* c8 ignore stop */\n    try {\n      const read = await this.#fs.promises.readlink(this.fullpath())\n      const linkTarget = (await this.parent.realpath())?.resolve(read)\n      if (linkTarget) {\n        return (this.#linkTarget = linkTarget)\n      }\n    } catch (er) {\n      this.#readlinkFail((er as NodeJS.ErrnoException).code)\n      return undefined\n    }\n  }\n\n  /**\n   * Synchronous {@link PathBase.readlink}\n   */\n  readlinkSync(): PathBase | undefined {\n    const target = this.#linkTarget\n    if (target) {\n      return target\n    }\n    if (!this.canReadlink()) {\n      return undefined\n    }\n    /* c8 ignore start */\n    // already covered by the canReadlink test, here for ts grumples\n    if (!this.parent) {\n      return undefined\n    }\n    /* c8 ignore stop */\n    try {\n      const read = this.#fs.readlinkSync(this.fullpath())\n      const linkTarget = this.parent.realpathSync()?.resolve(read)\n      if (linkTarget) {\n        return (this.#linkTarget = linkTarget)\n      }\n    } catch (er) {\n      this.#readlinkFail((er as NodeJS.ErrnoException).code)\n      return undefined\n    }\n  }\n\n  #readdirSuccess(children: Children) {\n    // succeeded, mark readdir called bit\n    this.#type |= READDIR_CALLED\n    // mark all remaining provisional children as ENOENT\n    for (let p = children.provisional; p < children.length; p++) {\n      const c = children[p]\n      if (c) c.#markENOENT()\n    }\n  }\n\n  #markENOENT() {\n    // mark as UNKNOWN and ENOENT\n    if (this.#type & ENOENT) return\n    this.#type = (this.#type | ENOENT) & IFMT_UNKNOWN\n    this.#markChildrenENOENT()\n  }\n\n  #markChildrenENOENT() {\n    // all children are provisional and do not exist\n    const children = this.children()\n    children.provisional = 0\n    for (const p of children) {\n      p.#markENOENT()\n    }\n  }\n\n  #markENOREALPATH() {\n    this.#type |= ENOREALPATH\n    this.#markENOTDIR()\n  }\n\n  // save the information when we know the entry is not a dir\n  #markENOTDIR() {\n    // entry is not a directory, so any children can't exist.\n    // this *should* be impossible, since any children created\n    // after it's been marked ENOTDIR should be marked ENOENT,\n    // so it won't even get to this point.\n    /* c8 ignore start */\n    if (this.#type & ENOTDIR) return\n    /* c8 ignore stop */\n    let t = this.#type\n    // this could happen if we stat a dir, then delete it,\n    // then try to read it or one of its children.\n    if ((t & IFMT) === IFDIR) t &= IFMT_UNKNOWN\n    this.#type = t | ENOTDIR\n    this.#markChildrenENOENT()\n  }\n\n  #readdirFail(code: string = '') {\n    // markENOTDIR and markENOENT also set provisional=0\n    if (code === 'ENOTDIR' || code === 'EPERM') {\n      this.#markENOTDIR()\n    } else if (code === 'ENOENT') {\n      this.#markENOENT()\n    } else {\n      this.children().provisional = 0\n    }\n  }\n\n  #lstatFail(code: string = '') {\n    // Windows just raises ENOENT in this case, disable for win CI\n    /* c8 ignore start */\n    if (code === 'ENOTDIR') {\n      // already know it has a parent by this point\n      const p = this.parent as PathBase\n      p.#markENOTDIR()\n    } else if (code === 'ENOENT') {\n      /* c8 ignore stop */\n      this.#markENOENT()\n    }\n  }\n\n  #readlinkFail(code: string = '') {\n    let ter = this.#type\n    ter |= ENOREADLINK\n    if (code === 'ENOENT') ter |= ENOENT\n    // windows gets a weird error when you try to readlink a file\n    if (code === 'EINVAL' || code === 'UNKNOWN') {\n      // exists, but not a symlink, we don't know WHAT it is, so remove\n      // all IFMT bits.\n      ter &= IFMT_UNKNOWN\n    }\n    this.#type = ter\n    // windows just gets ENOENT in this case.  We do cover the case,\n    // just disabled because it's impossible on Windows CI\n    /* c8 ignore start */\n    if (code === 'ENOTDIR' && this.parent) {\n      this.parent.#markENOTDIR()\n    }\n    /* c8 ignore stop */\n  }\n\n  #readdirAddChild(e: Dirent, c: Children) {\n    return (\n      this.#readdirMaybePromoteChild(e, c) ||\n      this.#readdirAddNewChild(e, c)\n    )\n  }\n\n  #readdirAddNewChild(e: Dirent, c: Children): PathBase {\n    // alloc new entry at head, so it's never provisional\n    const type = entToType(e)\n    const child = this.newChild(e.name, type, { parent: this })\n    const ifmt = child.#type & IFMT\n    if (ifmt !== IFDIR && ifmt !== IFLNK && ifmt !== UNKNOWN) {\n      child.#type |= ENOTDIR\n    }\n    c.unshift(child)\n    c.provisional++\n    return child\n  }\n\n  #readdirMaybePromoteChild(e: Dirent, c: Children): PathBase | undefined {\n    for (let p = c.provisional; p < c.length; p++) {\n      const pchild = c[p]\n      const name =\n        this.nocase ? normalizeNocase(e.name) : normalize(e.name)\n      if (name !== pchild!.#matchName) {\n        continue\n      }\n\n      return this.#readdirPromoteChild(e, pchild!, p, c)\n    }\n  }\n\n  #readdirPromoteChild(\n    e: Dirent,\n    p: PathBase,\n    index: number,\n    c: Children,\n  ): PathBase {\n    const v = p.name\n    // retain any other flags, but set ifmt from dirent\n    p.#type = (p.#type & IFMT_UNKNOWN) | entToType(e)\n    // case sensitivity fixing when we learn the true name.\n    if (v !== e.name) p.name = e.name\n\n    // just advance provisional index (potentially off the list),\n    // otherwise we have to splice/pop it out and re-insert at head\n    if (index !== c.provisional) {\n      if (index === c.length - 1) c.pop()\n      else c.splice(index, 1)\n      c.unshift(p)\n    }\n    c.provisional++\n    return p\n  }\n\n  /**\n   * Call lstat() on this Path, and update all known information that can be\n   * determined.\n   *\n   * Note that unlike `fs.lstat()`, the returned value does not contain some\n   * information, such as `mode`, `dev`, `nlink`, and `ino`.  If that\n   * information is required, you will need to call `fs.lstat` yourself.\n   *\n   * If the Path refers to a nonexistent file, or if the lstat call fails for\n   * any reason, `undefined` is returned.  Otherwise the updated Path object is\n   * returned.\n   *\n   * Results are cached, and thus may be out of date if the filesystem is\n   * mutated.\n   */\n  async lstat(): Promise<PathBase | undefined> {\n    if ((this.#type & ENOENT) === 0) {\n      try {\n        this.#applyStat(await this.#fs.promises.lstat(this.fullpath()))\n        return this\n      } catch (er) {\n        this.#lstatFail((er as NodeJS.ErrnoException).code)\n      }\n    }\n  }\n\n  /**\n   * synchronous {@link PathBase.lstat}\n   */\n  lstatSync(): PathBase | undefined {\n    if ((this.#type & ENOENT) === 0) {\n      try {\n        this.#applyStat(this.#fs.lstatSync(this.fullpath()))\n        return this\n      } catch (er) {\n        this.#lstatFail((er as NodeJS.ErrnoException).code)\n      }\n    }\n  }\n\n  #applyStat(st: Stats) {\n    const {\n      atime,\n      atimeMs,\n      birthtime,\n      birthtimeMs,\n      blksize,\n      blocks,\n      ctime,\n      ctimeMs,\n      dev,\n      gid,\n      ino,\n      mode,\n      mtime,\n      mtimeMs,\n      nlink,\n      rdev,\n      size,\n      uid,\n    } = st\n    this.#atime = atime\n    this.#atimeMs = atimeMs\n    this.#birthtime = birthtime\n    this.#birthtimeMs = birthtimeMs\n    this.#blksize = blksize\n    this.#blocks = blocks\n    this.#ctime = ctime\n    this.#ctimeMs = ctimeMs\n    this.#dev = dev\n    this.#gid = gid\n    this.#ino = ino\n    this.#mode = mode\n    this.#mtime = mtime\n    this.#mtimeMs = mtimeMs\n    this.#nlink = nlink\n    this.#rdev = rdev\n    this.#size = size\n    this.#uid = uid\n    const ifmt = entToType(st)\n    // retain any other flags, but set the ifmt\n    this.#type = (this.#type & IFMT_UNKNOWN) | ifmt | LSTAT_CALLED\n    if (ifmt !== UNKNOWN && ifmt !== IFDIR && ifmt !== IFLNK) {\n      this.#type |= ENOTDIR\n    }\n  }\n\n  #onReaddirCB: ((\n    er: NodeJS.ErrnoException | null,\n    entries: Path[],\n  ) => any)[] = []\n  #readdirCBInFlight: boolean = false\n  #callOnReaddirCB(children: Path[]) {\n    this.#readdirCBInFlight = false\n    const cbs = this.#onReaddirCB.slice()\n    this.#onReaddirCB.length = 0\n    cbs.forEach(cb => cb(null, children))\n  }\n\n  /**\n   * Standard node-style callback interface to get list of directory entries.\n   *\n   * If the Path cannot or does not contain any children, then an empty array\n   * is returned.\n   *\n   * Results are cached, and thus may be out of date if the filesystem is\n   * mutated.\n   *\n   * @param cb The callback called with (er, entries).  Note that the `er`\n   * param is somewhat extraneous, as all readdir() errors are handled and\n   * simply result in an empty set of entries being returned.\n   * @param allowZalgo Boolean indicating that immediately known results should\n   * *not* be deferred with `queueMicrotask`. Defaults to `false`. Release\n   * zalgo at your peril, the dark pony lord is devious and unforgiving.\n   */\n  readdirCB(\n    cb: (er: NodeJS.ErrnoException | null, entries: PathBase[]) => any,\n    allowZalgo: boolean = false,\n  ): void {\n    if (!this.canReaddir()) {\n      if (allowZalgo) cb(null, [])\n      else queueMicrotask(() => cb(null, []))\n      return\n    }\n\n    const children = this.children()\n    if (this.calledReaddir()) {\n      const c = children.slice(0, children.provisional)\n      if (allowZalgo) cb(null, c)\n      else queueMicrotask(() => cb(null, c))\n      return\n    }\n\n    // don't have to worry about zalgo at this point.\n    this.#onReaddirCB.push(cb)\n    if (this.#readdirCBInFlight) {\n      return\n    }\n    this.#readdirCBInFlight = true\n\n    // else read the directory, fill up children\n    // de-provisionalize any provisional children.\n    const fullpath = this.fullpath()\n    this.#fs.readdir(fullpath, { withFileTypes: true }, (er, entries) => {\n      if (er) {\n        this.#readdirFail((er as NodeJS.ErrnoException).code)\n        children.provisional = 0\n      } else {\n        // if we didn't get an error, we always get entries.\n        //@ts-ignore\n        for (const e of entries) {\n          this.#readdirAddChild(e, children)\n        }\n        this.#readdirSuccess(children)\n      }\n      this.#callOnReaddirCB(children.slice(0, children.provisional))\n      return\n    })\n  }\n\n  #asyncReaddirInFlight?: Promise<void>\n\n  /**\n   * Return an array of known child entries.\n   *\n   * If the Path cannot or does not contain any children, then an empty array\n   * is returned.\n   *\n   * Results are cached, and thus may be out of date if the filesystem is\n   * mutated.\n   */\n  async readdir(): Promise<PathBase[]> {\n    if (!this.canReaddir()) {\n      return []\n    }\n\n    const children = this.children()\n    if (this.calledReaddir()) {\n      return children.slice(0, children.provisional)\n    }\n\n    // else read the directory, fill up children\n    // de-provisionalize any provisional children.\n    const fullpath = this.fullpath()\n    if (this.#asyncReaddirInFlight) {\n      await this.#asyncReaddirInFlight\n    } else {\n      /* c8 ignore start */\n      let resolve: () => void = () => {}\n      /* c8 ignore stop */\n      this.#asyncReaddirInFlight = new Promise<void>(\n        res => (resolve = res),\n      )\n      try {\n        for (const e of await this.#fs.promises.readdir(fullpath, {\n          withFileTypes: true,\n        })) {\n          this.#readdirAddChild(e, children)\n        }\n        this.#readdirSuccess(children)\n      } catch (er) {\n        this.#readdirFail((er as NodeJS.ErrnoException).code)\n        children.provisional = 0\n      }\n      this.#asyncReaddirInFlight = undefined\n      resolve()\n    }\n    return children.slice(0, children.provisional)\n  }\n\n  /**\n   * synchronous {@link PathBase.readdir}\n   */\n  readdirSync(): PathBase[] {\n    if (!this.canReaddir()) {\n      return []\n    }\n\n    const children = this.children()\n    if (this.calledReaddir()) {\n      return children.slice(0, children.provisional)\n    }\n\n    // else read the directory, fill up children\n    // de-provisionalize any provisional children.\n    const fullpath = this.fullpath()\n    try {\n      for (const e of this.#fs.readdirSync(fullpath, {\n        withFileTypes: true,\n      })) {\n        this.#readdirAddChild(e, children)\n      }\n      this.#readdirSuccess(children)\n    } catch (er) {\n      this.#readdirFail((er as NodeJS.ErrnoException).code)\n      children.provisional = 0\n    }\n    return children.slice(0, children.provisional)\n  }\n\n  canReaddir() {\n    if (this.#type & ENOCHILD) return false\n    const ifmt = IFMT & this.#type\n    // we always set ENOTDIR when setting IFMT, so should be impossible\n    /* c8 ignore start */\n    if (!(ifmt === UNKNOWN || ifmt === IFDIR || ifmt === IFLNK)) {\n      return false\n    }\n    /* c8 ignore stop */\n    return true\n  }\n\n  shouldWalk(\n    dirs: Set<PathBase | undefined>,\n    walkFilter?: (e: PathBase) => boolean,\n  ): boolean {\n    return (\n      (this.#type & IFDIR) === IFDIR &&\n      !(this.#type & ENOCHILD) &&\n      !dirs.has(this) &&\n      (!walkFilter || walkFilter(this))\n    )\n  }\n\n  /**\n   * Return the Path object corresponding to path as resolved\n   * by realpath(3).\n   *\n   * If the realpath call fails for any reason, `undefined` is returned.\n   *\n   * Result is cached, and thus may be outdated if the filesystem is mutated.\n   * On success, returns a Path object.\n   */\n  async realpath(): Promise<PathBase | undefined> {\n    if (this.#realpath) return this.#realpath\n    if ((ENOREALPATH | ENOREADLINK | ENOENT) & this.#type) return undefined\n    try {\n      const rp = await this.#fs.promises.realpath(this.fullpath())\n      return (this.#realpath = this.resolve(rp))\n    } catch (_) {\n      this.#markENOREALPATH()\n    }\n  }\n\n  /**\n   * Synchronous {@link realpath}\n   */\n  realpathSync(): PathBase | undefined {\n    if (this.#realpath) return this.#realpath\n    if ((ENOREALPATH | ENOREADLINK | ENOENT) & this.#type) return undefined\n    try {\n      const rp = this.#fs.realpathSync(this.fullpath())\n      return (this.#realpath = this.resolve(rp))\n    } catch (_) {\n      this.#markENOREALPATH()\n    }\n  }\n\n  /**\n   * Internal method to mark this Path object as the scurry cwd,\n   * called by {@link PathScurry#chdir}\n   *\n   * @internal\n   */\n  [setAsCwd](oldCwd: PathBase): void {\n    if (oldCwd === this) return\n    oldCwd.isCWD = false\n    this.isCWD = true\n\n    const changed = new Set<PathBase>([])\n    let rp = []\n    let p: PathBase = this\n    while (p && p.parent) {\n      changed.add(p)\n      p.#relative = rp.join(this.sep)\n      p.#relativePosix = rp.join('/')\n      p = p.parent\n      rp.push('..')\n    }\n    // now un-memoize parents of old cwd\n    p = oldCwd\n    while (p && p.parent && !changed.has(p)) {\n      p.#relative = undefined\n      p.#relativePosix = undefined\n      p = p.parent\n    }\n  }\n}\n\n/**\n * Path class used on win32 systems\n *\n * Uses `'\\\\'` as the path separator for returned paths, either `'\\\\'` or `'/'`\n * as the path separator for parsing paths.\n */\nexport class PathWin32 extends PathBase {\n  /**\n   * Separator for generating path strings.\n   */\n  sep: '\\\\' = '\\\\'\n  /**\n   * Separator for parsing path strings.\n   */\n  splitSep: RegExp = eitherSep\n\n  /**\n   * Do not create new Path objects directly.  They should always be accessed\n   * via the PathScurry class or other methods on the Path class.\n   *\n   * @internal\n   */\n  constructor(\n    name: string,\n    type: number = UNKNOWN,\n    root: PathBase | undefined,\n    roots: { [k: string]: PathBase },\n    nocase: boolean,\n    children: ChildrenCache,\n    opts: PathOpts,\n  ) {\n    super(name, type, root, roots, nocase, children, opts)\n  }\n\n  /**\n   * @internal\n   */\n  newChild(name: string, type: number = UNKNOWN, opts: PathOpts = {}) {\n    return new PathWin32(\n      name,\n      type,\n      this.root,\n      this.roots,\n      this.nocase,\n      this.childrenCache(),\n      opts,\n    )\n  }\n\n  /**\n   * @internal\n   */\n  getRootString(path: string): string {\n    return win32.parse(path).root\n  }\n\n  /**\n   * @internal\n   */\n  getRoot(rootPath: string): PathBase {\n    rootPath = uncToDrive(rootPath.toUpperCase())\n    if (rootPath === this.root.name) {\n      return this.root\n    }\n    // ok, not that one, check if it matches another we know about\n    for (const [compare, root] of Object.entries(this.roots)) {\n      if (this.sameRoot(rootPath, compare)) {\n        return (this.roots[rootPath] = root)\n      }\n    }\n    // otherwise, have to create a new one.\n    return (this.roots[rootPath] = new PathScurryWin32(\n      rootPath,\n      this,\n    ).root)\n  }\n\n  /**\n   * @internal\n   */\n  sameRoot(rootPath: string, compare: string = this.root.name): boolean {\n    // windows can (rarely) have case-sensitive filesystem, but\n    // UNC and drive letters are always case-insensitive, and canonically\n    // represented uppercase.\n    rootPath = rootPath\n      .toUpperCase()\n      .replace(/\\//g, '\\\\')\n      .replace(uncDriveRegexp, '$1\\\\')\n    return rootPath === compare\n  }\n}\n\n/**\n * Path class used on all posix systems.\n *\n * Uses `'/'` as the path separator.\n */\nexport class PathPosix extends PathBase {\n  /**\n   * separator for parsing path strings\n   */\n  splitSep: '/' = '/'\n  /**\n   * separator for generating path strings\n   */\n  sep: '/' = '/'\n\n  /**\n   * Do not create new Path objects directly.  They should always be accessed\n   * via the PathScurry class or other methods on the Path class.\n   *\n   * @internal\n   */\n  constructor(\n    name: string,\n    type: number = UNKNOWN,\n    root: PathBase | undefined,\n    roots: { [k: string]: PathBase },\n    nocase: boolean,\n    children: ChildrenCache,\n    opts: PathOpts,\n  ) {\n    super(name, type, root, roots, nocase, children, opts)\n  }\n\n  /**\n   * @internal\n   */\n  getRootString(path: string): string {\n    return path.startsWith('/') ? '/' : ''\n  }\n\n  /**\n   * @internal\n   */\n  getRoot(_rootPath: string): PathBase {\n    return this.root\n  }\n\n  /**\n   * @internal\n   */\n  newChild(name: string, type: number = UNKNOWN, opts: PathOpts = {}) {\n    return new PathPosix(\n      name,\n      type,\n      this.root,\n      this.roots,\n      this.nocase,\n      this.childrenCache(),\n      opts,\n    )\n  }\n}\n\n/**\n * Options that may be provided to the PathScurry constructor\n */\nexport interface PathScurryOpts {\n  /**\n   * perform case-insensitive path matching. Default based on platform\n   * subclass.\n   */\n  nocase?: boolean\n  /**\n   * Number of Path entries to keep in the cache of Path child references.\n   *\n   * Setting this higher than 65536 will dramatically increase the data\n   * consumption and construction time overhead of each PathScurry.\n   *\n   * Setting this value to 256 or lower will significantly reduce the data\n   * consumption and construction time overhead, but may also reduce resolve()\n   * and readdir() performance on large filesystems.\n   *\n   * Default `16384`.\n   */\n  childrenCacheSize?: number\n  /**\n   * An object that overrides the built-in functions from the fs and\n   * fs/promises modules.\n   *\n   * See {@link FSOption}\n   */\n  fs?: FSOption\n}\n\n/**\n * The base class for all PathScurry classes, providing the interface for path\n * resolution and filesystem operations.\n *\n * Typically, you should *not* instantiate this class directly, but rather one\n * of the platform-specific classes, or the exported {@link PathScurry} which\n * defaults to the current platform.\n */\nexport abstract class PathScurryBase {\n  /**\n   * The root Path entry for the current working directory of this Scurry\n   */\n  root: PathBase\n  /**\n   * The string path for the root of this Scurry's current working directory\n   */\n  rootPath: string\n  /**\n   * A collection of all roots encountered, referenced by rootPath\n   */\n  roots: { [k: string]: PathBase }\n  /**\n   * The Path entry corresponding to this PathScurry's current working directory.\n   */\n  cwd: PathBase\n  #resolveCache: ResolveCache\n  #resolvePosixCache: ResolveCache\n  #children: ChildrenCache\n  /**\n   * Perform path comparisons case-insensitively.\n   *\n   * Defaults true on Darwin and Windows systems, false elsewhere.\n   */\n  nocase: boolean\n\n  /**\n   * The path separator used for parsing paths\n   *\n   * `'/'` on Posix systems, either `'/'` or `'\\\\'` on Windows\n   */\n  abstract sep: string | RegExp\n\n  #fs: FSValue\n\n  /**\n   * This class should not be instantiated directly.\n   *\n   * Use PathScurryWin32, PathScurryDarwin, PathScurryPosix, or PathScurry\n   *\n   * @internal\n   */\n  constructor(\n    cwd: URL | string = process.cwd(),\n    pathImpl: typeof win32 | typeof posix,\n    sep: string | RegExp,\n    {\n      nocase,\n      childrenCacheSize = 16 * 1024,\n      fs = defaultFS,\n    }: PathScurryOpts = {},\n  ) {\n    this.#fs = fsFromOption(fs)\n    if (cwd instanceof URL || cwd.startsWith('file://')) {\n      cwd = fileURLToPath(cwd)\n    }\n    // resolve and split root, and then add to the store.\n    // this is the only time we call path.resolve()\n    const cwdPath = pathImpl.resolve(cwd)\n    this.roots = Object.create(null)\n    this.rootPath = this.parseRootPath(cwdPath)\n    this.#resolveCache = new ResolveCache()\n    this.#resolvePosixCache = new ResolveCache()\n    this.#children = new ChildrenCache(childrenCacheSize)\n\n    const split = cwdPath.substring(this.rootPath.length).split(sep)\n    // resolve('/') leaves '', splits to [''], we don't want that.\n    if (split.length === 1 && !split[0]) {\n      split.pop()\n    }\n    /* c8 ignore start */\n    if (nocase === undefined) {\n      throw new TypeError(\n        'must provide nocase setting to PathScurryBase ctor',\n      )\n    }\n    /* c8 ignore stop */\n    this.nocase = nocase\n    this.root = this.newRoot(this.#fs)\n    this.roots[this.rootPath] = this.root\n    let prev: PathBase = this.root\n    let len = split.length - 1\n    const joinSep = pathImpl.sep\n    let abs = this.rootPath\n    let sawFirst = false\n    for (const part of split) {\n      const l = len--\n      prev = prev.child(part, {\n        relative: new Array(l).fill('..').join(joinSep),\n        relativePosix: new Array(l).fill('..').join('/'),\n        fullpath: (abs += (sawFirst ? '' : joinSep) + part),\n      })\n      sawFirst = true\n    }\n    this.cwd = prev\n  }\n\n  /**\n   * Get the depth of a provided path, string, or the cwd\n   */\n  depth(path: Path | string = this.cwd): number {\n    if (typeof path === 'string') {\n      path = this.cwd.resolve(path)\n    }\n    return path.depth()\n  }\n\n  /**\n   * Parse the root portion of a path string\n   *\n   * @internal\n   */\n  abstract parseRootPath(dir: string): string\n  /**\n   * create a new Path to use as root during construction.\n   *\n   * @internal\n   */\n  abstract newRoot(fs: FSValue): PathBase\n  /**\n   * Determine whether a given path string is absolute\n   */\n  abstract isAbsolute(p: string): boolean\n\n  /**\n   * Return the cache of child entries.  Exposed so subclasses can create\n   * child Path objects in a platform-specific way.\n   *\n   * @internal\n   */\n  childrenCache() {\n    return this.#children\n  }\n\n  /**\n   * Resolve one or more path strings to a resolved string\n   *\n   * Same interface as require('path').resolve.\n   *\n   * Much faster than path.resolve() when called multiple times for the same\n   * path, because the resolved Path objects are cached.  Much slower\n   * otherwise.\n   */\n  resolve(...paths: string[]): string {\n    // first figure out the minimum number of paths we have to test\n    // we always start at cwd, but any absolutes will bump the start\n    let r = ''\n    for (let i = paths.length - 1; i >= 0; i--) {\n      const p = paths[i]\n      if (!p || p === '.') continue\n      r = r ? `${p}/${r}` : p\n      if (this.isAbsolute(p)) {\n        break\n      }\n    }\n    const cached = this.#resolveCache.get(r)\n    if (cached !== undefined) {\n      return cached\n    }\n    const result = this.cwd.resolve(r).fullpath()\n    this.#resolveCache.set(r, result)\n    return result\n  }\n\n  /**\n   * Resolve one or more path strings to a resolved string, returning\n   * the posix path.  Identical to .resolve() on posix systems, but on\n   * windows will return a forward-slash separated UNC path.\n   *\n   * Same interface as require('path').resolve.\n   *\n   * Much faster than path.resolve() when called multiple times for the same\n   * path, because the resolved Path objects are cached.  Much slower\n   * otherwise.\n   */\n  resolvePosix(...paths: string[]): string {\n    // first figure out the minimum number of paths we have to test\n    // we always start at cwd, but any absolutes will bump the start\n    let r = ''\n    for (let i = paths.length - 1; i >= 0; i--) {\n      const p = paths[i]\n      if (!p || p === '.') continue\n      r = r ? `${p}/${r}` : p\n      if (this.isAbsolute(p)) {\n        break\n      }\n    }\n    const cached = this.#resolvePosixCache.get(r)\n    if (cached !== undefined) {\n      return cached\n    }\n    const result = this.cwd.resolve(r).fullpathPosix()\n    this.#resolvePosixCache.set(r, result)\n    return result\n  }\n\n  /**\n   * find the relative path from the cwd to the supplied path string or entry\n   */\n  relative(entry: PathBase | string = this.cwd): string {\n    if (typeof entry === 'string') {\n      entry = this.cwd.resolve(entry)\n    }\n    return entry.relative()\n  }\n\n  /**\n   * find the relative path from the cwd to the supplied path string or\n   * entry, using / as the path delimiter, even on Windows.\n   */\n  relativePosix(entry: PathBase | string = this.cwd): string {\n    if (typeof entry === 'string') {\n      entry = this.cwd.resolve(entry)\n    }\n    return entry.relativePosix()\n  }\n\n  /**\n   * Return the basename for the provided string or Path object\n   */\n  basename(entry: PathBase | string = this.cwd): string {\n    if (typeof entry === 'string') {\n      entry = this.cwd.resolve(entry)\n    }\n    return entry.name\n  }\n\n  /**\n   * Return the dirname for the provided string or Path object\n   */\n  dirname(entry: PathBase | string = this.cwd): string {\n    if (typeof entry === 'string') {\n      entry = this.cwd.resolve(entry)\n    }\n    return (entry.parent || entry).fullpath()\n  }\n\n  /**\n   * Return an array of known child entries.\n   *\n   * First argument may be either a string, or a Path object.\n   *\n   * If the Path cannot or does not contain any children, then an empty array\n   * is returned.\n   *\n   * Results are cached, and thus may be out of date if the filesystem is\n   * mutated.\n   *\n   * Unlike `fs.readdir()`, the `withFileTypes` option defaults to `true`. Set\n   * `{ withFileTypes: false }` to return strings.\n   */\n\n  readdir(): Promise<PathBase[]>\n  readdir(opts: { withFileTypes: true }): Promise<PathBase[]>\n  readdir(opts: { withFileTypes: false }): Promise<string[]>\n  readdir(opts: { withFileTypes: boolean }): Promise<PathBase[] | string[]>\n  readdir(entry: PathBase | string): Promise<PathBase[]>\n  readdir(\n    entry: PathBase | string,\n    opts: { withFileTypes: true },\n  ): Promise<PathBase[]>\n  readdir(\n    entry: PathBase | string,\n    opts: { withFileTypes: false },\n  ): Promise<string[]>\n  readdir(\n    entry: PathBase | string,\n    opts: { withFileTypes: boolean },\n  ): Promise<PathBase[] | string[]>\n  async readdir(\n    entry: PathBase | string | { withFileTypes: boolean } = this.cwd,\n    opts: { withFileTypes: boolean } = {\n      withFileTypes: true,\n    },\n  ): Promise<PathBase[] | string[]> {\n    if (typeof entry === 'string') {\n      entry = this.cwd.resolve(entry)\n    } else if (!(entry instanceof PathBase)) {\n      opts = entry\n      entry = this.cwd\n    }\n    const { withFileTypes } = opts\n    if (!entry.canReaddir()) {\n      return []\n    } else {\n      const p = await entry.readdir()\n      return withFileTypes ? p : p.map(e => e.name)\n    }\n  }\n\n  /**\n   * synchronous {@link PathScurryBase.readdir}\n   */\n  readdirSync(): PathBase[]\n  readdirSync(opts: { withFileTypes: true }): PathBase[]\n  readdirSync(opts: { withFileTypes: false }): string[]\n  readdirSync(opts: { withFileTypes: boolean }): PathBase[] | string[]\n  readdirSync(entry: PathBase | string): PathBase[]\n  readdirSync(\n    entry: PathBase | string,\n    opts: { withFileTypes: true },\n  ): PathBase[]\n  readdirSync(\n    entry: PathBase | string,\n    opts: { withFileTypes: false },\n  ): string[]\n  readdirSync(\n    entry: PathBase | string,\n    opts: { withFileTypes: boolean },\n  ): PathBase[] | string[]\n  readdirSync(\n    entry: PathBase | string | { withFileTypes: boolean } = this.cwd,\n    opts: { withFileTypes: boolean } = {\n      withFileTypes: true,\n    },\n  ): PathBase[] | string[] {\n    if (typeof entry === 'string') {\n      entry = this.cwd.resolve(entry)\n    } else if (!(entry instanceof PathBase)) {\n      opts = entry\n      entry = this.cwd\n    }\n    const { withFileTypes = true } = opts\n    if (!entry.canReaddir()) {\n      return []\n    } else if (withFileTypes) {\n      return entry.readdirSync()\n    } else {\n      return entry.readdirSync().map(e => e.name)\n    }\n  }\n\n  /**\n   * Call lstat() on the string or Path object, and update all known\n   * information that can be determined.\n   *\n   * Note that unlike `fs.lstat()`, the returned value does not contain some\n   * information, such as `mode`, `dev`, `nlink`, and `ino`.  If that\n   * information is required, you will need to call `fs.lstat` yourself.\n   *\n   * If the Path refers to a nonexistent file, or if the lstat call fails for\n   * any reason, `undefined` is returned.  Otherwise the updated Path object is\n   * returned.\n   *\n   * Results are cached, and thus may be out of date if the filesystem is\n   * mutated.\n   */\n  async lstat(\n    entry: string | PathBase = this.cwd,\n  ): Promise<PathBase | undefined> {\n    if (typeof entry === 'string') {\n      entry = this.cwd.resolve(entry)\n    }\n    return entry.lstat()\n  }\n\n  /**\n   * synchronous {@link PathScurryBase.lstat}\n   */\n  lstatSync(entry: string | PathBase = this.cwd): PathBase | undefined {\n    if (typeof entry === 'string') {\n      entry = this.cwd.resolve(entry)\n    }\n    return entry.lstatSync()\n  }\n\n  /**\n   * Return the Path object or string path corresponding to the target of a\n   * symbolic link.\n   *\n   * If the path is not a symbolic link, or if the readlink call fails for any\n   * reason, `undefined` is returned.\n   *\n   * Result is cached, and thus may be outdated if the filesystem is mutated.\n   *\n   * `{withFileTypes}` option defaults to `false`.\n   *\n   * On success, returns a Path object if `withFileTypes` option is true,\n   * otherwise a string.\n   */\n  readlink(): Promise<string | undefined>\n  readlink(opt: { withFileTypes: false }): Promise<string | undefined>\n  readlink(opt: { withFileTypes: true }): Promise<PathBase | undefined>\n  readlink(opt: {\n    withFileTypes: boolean\n  }): Promise<PathBase | string | undefined>\n  readlink(\n    entry: string | PathBase,\n    opt?: { withFileTypes: false },\n  ): Promise<string | undefined>\n  readlink(\n    entry: string | PathBase,\n    opt: { withFileTypes: true },\n  ): Promise<PathBase | undefined>\n  readlink(\n    entry: string | PathBase,\n    opt: { withFileTypes: boolean },\n  ): Promise<string | PathBase | undefined>\n  async readlink(\n    entry: string | PathBase | { withFileTypes: boolean } = this.cwd,\n    { withFileTypes }: { withFileTypes: boolean } = {\n      withFileTypes: false,\n    },\n  ): Promise<string | PathBase | undefined> {\n    if (typeof entry === 'string') {\n      entry = this.cwd.resolve(entry)\n    } else if (!(entry instanceof PathBase)) {\n      withFileTypes = entry.withFileTypes\n      entry = this.cwd\n    }\n    const e = await entry.readlink()\n    return withFileTypes ? e : e?.fullpath()\n  }\n\n  /**\n   * synchronous {@link PathScurryBase.readlink}\n   */\n  readlinkSync(): string | undefined\n  readlinkSync(opt: { withFileTypes: false }): string | undefined\n  readlinkSync(opt: { withFileTypes: true }): PathBase | undefined\n  readlinkSync(opt: {\n    withFileTypes: boolean\n  }): PathBase | string | undefined\n  readlinkSync(\n    entry: string | PathBase,\n    opt?: { withFileTypes: false },\n  ): string | undefined\n  readlinkSync(\n    entry: string | PathBase,\n    opt: { withFileTypes: true },\n  ): PathBase | undefined\n  readlinkSync(\n    entry: string | PathBase,\n    opt: { withFileTypes: boolean },\n  ): string | PathBase | undefined\n  readlinkSync(\n    entry: string | PathBase | { withFileTypes: boolean } = this.cwd,\n    { withFileTypes }: { withFileTypes: boolean } = {\n      withFileTypes: false,\n    },\n  ): string | PathBase | undefined {\n    if (typeof entry === 'string') {\n      entry = this.cwd.resolve(entry)\n    } else if (!(entry instanceof PathBase)) {\n      withFileTypes = entry.withFileTypes\n      entry = this.cwd\n    }\n    const e = entry.readlinkSync()\n    return withFileTypes ? e : e?.fullpath()\n  }\n\n  /**\n   * Return the Path object or string path corresponding to path as resolved\n   * by realpath(3).\n   *\n   * If the realpath call fails for any reason, `undefined` is returned.\n   *\n   * Result is cached, and thus may be outdated if the filesystem is mutated.\n   *\n   * `{withFileTypes}` option defaults to `false`.\n   *\n   * On success, returns a Path object if `withFileTypes` option is true,\n   * otherwise a string.\n   */\n  realpath(): Promise<string | undefined>\n  realpath(opt: { withFileTypes: false }): Promise<string | undefined>\n  realpath(opt: { withFileTypes: true }): Promise<PathBase | undefined>\n  realpath(opt: {\n    withFileTypes: boolean\n  }): Promise<PathBase | string | undefined>\n  realpath(\n    entry: string | PathBase,\n    opt?: { withFileTypes: false },\n  ): Promise<string | undefined>\n  realpath(\n    entry: string | PathBase,\n    opt: { withFileTypes: true },\n  ): Promise<PathBase | undefined>\n  realpath(\n    entry: string | PathBase,\n    opt: { withFileTypes: boolean },\n  ): Promise<string | PathBase | undefined>\n  async realpath(\n    entry: string | PathBase | { withFileTypes: boolean } = this.cwd,\n    { withFileTypes }: { withFileTypes: boolean } = {\n      withFileTypes: false,\n    },\n  ): Promise<string | PathBase | undefined> {\n    if (typeof entry === 'string') {\n      entry = this.cwd.resolve(entry)\n    } else if (!(entry instanceof PathBase)) {\n      withFileTypes = entry.withFileTypes\n      entry = this.cwd\n    }\n    const e = await entry.realpath()\n    return withFileTypes ? e : e?.fullpath()\n  }\n\n  realpathSync(): string | undefined\n  realpathSync(opt: { withFileTypes: false }): string | undefined\n  realpathSync(opt: { withFileTypes: true }): PathBase | undefined\n  realpathSync(opt: {\n    withFileTypes: boolean\n  }): PathBase | string | undefined\n  realpathSync(\n    entry: string | PathBase,\n    opt?: { withFileTypes: false },\n  ): string | undefined\n  realpathSync(\n    entry: string | PathBase,\n    opt: { withFileTypes: true },\n  ): PathBase | undefined\n  realpathSync(\n    entry: string | PathBase,\n    opt: { withFileTypes: boolean },\n  ): string | PathBase | undefined\n  realpathSync(\n    entry: string | PathBase | { withFileTypes: boolean } = this.cwd,\n    { withFileTypes }: { withFileTypes: boolean } = {\n      withFileTypes: false,\n    },\n  ): string | PathBase | undefined {\n    if (typeof entry === 'string') {\n      entry = this.cwd.resolve(entry)\n    } else if (!(entry instanceof PathBase)) {\n      withFileTypes = entry.withFileTypes\n      entry = this.cwd\n    }\n    const e = entry.realpathSync()\n    return withFileTypes ? e : e?.fullpath()\n  }\n\n  /**\n   * Asynchronously walk the directory tree, returning an array of\n   * all path strings or Path objects found.\n   *\n   * Note that this will be extremely memory-hungry on large filesystems.\n   * In such cases, it may be better to use the stream or async iterator\n   * walk implementation.\n   */\n  walk(): Promise<PathBase[]>\n  walk(\n    opts: WalkOptionsWithFileTypesTrue | WalkOptionsWithFileTypesUnset,\n  ): Promise<PathBase[]>\n  walk(opts: WalkOptionsWithFileTypesFalse): Promise<string[]>\n  walk(opts: WalkOptions): Promise<string[] | PathBase[]>\n  walk(entry: string | PathBase): Promise<PathBase[]>\n  walk(\n    entry: string | PathBase,\n    opts: WalkOptionsWithFileTypesTrue | WalkOptionsWithFileTypesUnset,\n  ): Promise<PathBase[]>\n  walk(\n    entry: string | PathBase,\n    opts: WalkOptionsWithFileTypesFalse,\n  ): Promise<string[]>\n  walk(\n    entry: string | PathBase,\n    opts: WalkOptions,\n  ): Promise<PathBase[] | string[]>\n  async walk(\n    entry: string | PathBase | WalkOptions = this.cwd,\n    opts: WalkOptions = {},\n  ): Promise<PathBase[] | string[]> {\n    if (typeof entry === 'string') {\n      entry = this.cwd.resolve(entry)\n    } else if (!(entry instanceof PathBase)) {\n      opts = entry\n      entry = this.cwd\n    }\n    const {\n      withFileTypes = true,\n      follow = false,\n      filter,\n      walkFilter,\n    } = opts\n    const results: (string | PathBase)[] = []\n    if (!filter || filter(entry)) {\n      results.push(withFileTypes ? entry : entry.fullpath())\n    }\n    const dirs = new Set<PathBase>()\n    const walk = (\n      dir: PathBase,\n      cb: (er?: NodeJS.ErrnoException) => void,\n    ) => {\n      dirs.add(dir)\n      dir.readdirCB((er, entries) => {\n        /* c8 ignore start */\n        if (er) {\n          return cb(er)\n        }\n        /* c8 ignore stop */\n        let len = entries.length\n        if (!len) return cb()\n        const next = () => {\n          if (--len === 0) {\n            cb()\n          }\n        }\n        for (const e of entries) {\n          if (!filter || filter(e)) {\n            results.push(withFileTypes ? e : e.fullpath())\n          }\n          if (follow && e.isSymbolicLink()) {\n            e.realpath()\n              .then(r => (r?.isUnknown() ? r.lstat() : r))\n              .then(r =>\n                r?.shouldWalk(dirs, walkFilter) ? walk(r, next) : next(),\n              )\n          } else {\n            if (e.shouldWalk(dirs, walkFilter)) {\n              walk(e, next)\n            } else {\n              next()\n            }\n          }\n        }\n      }, true) // zalgooooooo\n    }\n\n    const start = entry\n    return new Promise<PathBase[] | string[]>((res, rej) => {\n      walk(start, er => {\n        /* c8 ignore start */\n        if (er) return rej(er)\n        /* c8 ignore stop */\n        res(results as PathBase[] | string[])\n      })\n    })\n  }\n\n  /**\n   * Synchronously walk the directory tree, returning an array of\n   * all path strings or Path objects found.\n   *\n   * Note that this will be extremely memory-hungry on large filesystems.\n   * In such cases, it may be better to use the stream or async iterator\n   * walk implementation.\n   */\n  walkSync(): PathBase[]\n  walkSync(\n    opts: WalkOptionsWithFileTypesTrue | WalkOptionsWithFileTypesUnset,\n  ): PathBase[]\n  walkSync(opts: WalkOptionsWithFileTypesFalse): string[]\n  walkSync(opts: WalkOptions): string[] | PathBase[]\n  walkSync(entry: string | PathBase): PathBase[]\n  walkSync(\n    entry: string | PathBase,\n    opts: WalkOptionsWithFileTypesUnset | WalkOptionsWithFileTypesTrue,\n  ): PathBase[]\n  walkSync(\n    entry: string | PathBase,\n    opts: WalkOptionsWithFileTypesFalse,\n  ): string[]\n  walkSync(\n    entry: string | PathBase,\n    opts: WalkOptions,\n  ): PathBase[] | string[]\n  walkSync(\n    entry: string | PathBase | WalkOptions = this.cwd,\n    opts: WalkOptions = {},\n  ): PathBase[] | string[] {\n    if (typeof entry === 'string') {\n      entry = this.cwd.resolve(entry)\n    } else if (!(entry instanceof PathBase)) {\n      opts = entry\n      entry = this.cwd\n    }\n    const {\n      withFileTypes = true,\n      follow = false,\n      filter,\n      walkFilter,\n    } = opts\n    const results: (string | PathBase)[] = []\n    if (!filter || filter(entry)) {\n      results.push(withFileTypes ? entry : entry.fullpath())\n    }\n    const dirs = new Set<PathBase>([entry])\n    for (const dir of dirs) {\n      const entries = dir.readdirSync()\n      for (const e of entries) {\n        if (!filter || filter(e)) {\n          results.push(withFileTypes ? e : e.fullpath())\n        }\n        let r: PathBase | undefined = e\n        if (e.isSymbolicLink()) {\n          if (!(follow && (r = e.realpathSync()))) continue\n          if (r.isUnknown()) r.lstatSync()\n        }\n        if (r.shouldWalk(dirs, walkFilter)) {\n          dirs.add(r)\n        }\n      }\n    }\n    return results as string[] | PathBase[]\n  }\n\n  /**\n   * Support for `for await`\n   *\n   * Alias for {@link PathScurryBase.iterate}\n   *\n   * Note: As of Node 19, this is very slow, compared to other methods of\n   * walking.  Consider using {@link PathScurryBase.stream} if memory overhead\n   * and backpressure are concerns, or {@link PathScurryBase.walk} if not.\n   */\n  [Symbol.asyncIterator]() {\n    return this.iterate()\n  }\n\n  /**\n   * Async generator form of {@link PathScurryBase.walk}\n   *\n   * Note: As of Node 19, this is very slow, compared to other methods of\n   * walking, especially if most/all of the directory tree has been previously\n   * walked.  Consider using {@link PathScurryBase.stream} if memory overhead\n   * and backpressure are concerns, or {@link PathScurryBase.walk} if not.\n   */\n  iterate(): AsyncGenerator<PathBase, void, void>\n  iterate(\n    opts: WalkOptionsWithFileTypesTrue | WalkOptionsWithFileTypesUnset,\n  ): AsyncGenerator<PathBase, void, void>\n  iterate(\n    opts: WalkOptionsWithFileTypesFalse,\n  ): AsyncGenerator<string, void, void>\n  iterate(opts: WalkOptions): AsyncGenerator<string | PathBase, void, void>\n  iterate(entry: string | PathBase): AsyncGenerator<PathBase, void, void>\n  iterate(\n    entry: string | PathBase,\n    opts: WalkOptionsWithFileTypesTrue | WalkOptionsWithFileTypesUnset,\n  ): AsyncGenerator<PathBase, void, void>\n  iterate(\n    entry: string | PathBase,\n    opts: WalkOptionsWithFileTypesFalse,\n  ): AsyncGenerator<string, void, void>\n  iterate(\n    entry: string | PathBase,\n    opts: WalkOptions,\n  ): AsyncGenerator<PathBase | string, void, void>\n  iterate(\n    entry: string | PathBase | WalkOptions = this.cwd,\n    options: WalkOptions = {},\n  ): AsyncGenerator<PathBase | string, void, void> {\n    // iterating async over the stream is significantly more performant,\n    // especially in the warm-cache scenario, because it buffers up directory\n    // entries in the background instead of waiting for a yield for each one.\n    if (typeof entry === 'string') {\n      entry = this.cwd.resolve(entry)\n    } else if (!(entry instanceof PathBase)) {\n      options = entry\n      entry = this.cwd\n    }\n    return this.stream(entry, options)[Symbol.asyncIterator]()\n  }\n\n  /**\n   * Iterating over a PathScurry performs a synchronous walk.\n   *\n   * Alias for {@link PathScurryBase.iterateSync}\n   */\n  [Symbol.iterator]() {\n    return this.iterateSync()\n  }\n\n  iterateSync(): Generator<PathBase, void, void>\n  iterateSync(\n    opts: WalkOptionsWithFileTypesTrue | WalkOptionsWithFileTypesUnset,\n  ): Generator<PathBase, void, void>\n  iterateSync(\n    opts: WalkOptionsWithFileTypesFalse,\n  ): Generator<string, void, void>\n  iterateSync(opts: WalkOptions): Generator<string | PathBase, void, void>\n  iterateSync(entry: string | PathBase): Generator<PathBase, void, void>\n  iterateSync(\n    entry: string | PathBase,\n    opts: WalkOptionsWithFileTypesTrue | WalkOptionsWithFileTypesUnset,\n  ): Generator<PathBase, void, void>\n  iterateSync(\n    entry: string | PathBase,\n    opts: WalkOptionsWithFileTypesFalse,\n  ): Generator<string, void, void>\n  iterateSync(\n    entry: string | PathBase,\n    opts: WalkOptions,\n  ): Generator<PathBase | string, void, void>\n  *iterateSync(\n    entry: string | PathBase | WalkOptions = this.cwd,\n    opts: WalkOptions = {},\n  ): Generator<PathBase | string, void, void> {\n    if (typeof entry === 'string') {\n      entry = this.cwd.resolve(entry)\n    } else if (!(entry instanceof PathBase)) {\n      opts = entry\n      entry = this.cwd\n    }\n    const {\n      withFileTypes = true,\n      follow = false,\n      filter,\n      walkFilter,\n    } = opts\n    if (!filter || filter(entry)) {\n      yield withFileTypes ? entry : entry.fullpath()\n    }\n    const dirs = new Set<PathBase>([entry])\n    for (const dir of dirs) {\n      const entries = dir.readdirSync()\n      for (const e of entries) {\n        if (!filter || filter(e)) {\n          yield withFileTypes ? e : e.fullpath()\n        }\n        let r: PathBase | undefined = e\n        if (e.isSymbolicLink()) {\n          if (!(follow && (r = e.realpathSync()))) continue\n          if (r.isUnknown()) r.lstatSync()\n        }\n        if (r.shouldWalk(dirs, walkFilter)) {\n          dirs.add(r)\n        }\n      }\n    }\n  }\n\n  /**\n   * Stream form of {@link PathScurryBase.walk}\n   *\n   * Returns a Minipass stream that emits {@link PathBase} objects by default,\n   * or strings if `{ withFileTypes: false }` is set in the options.\n   */\n  stream(): Minipass<PathBase>\n  stream(\n    opts: WalkOptionsWithFileTypesTrue | WalkOptionsWithFileTypesUnset,\n  ): Minipass<PathBase>\n  stream(opts: WalkOptionsWithFileTypesFalse): Minipass<string>\n  stream(opts: WalkOptions): Minipass<string | PathBase>\n  stream(entry: string | PathBase): Minipass<PathBase>\n  stream(\n    entry: string | PathBase,\n    opts: WalkOptionsWithFileTypesUnset | WalkOptionsWithFileTypesTrue,\n  ): Minipass<PathBase>\n  stream(\n    entry: string | PathBase,\n    opts: WalkOptionsWithFileTypesFalse,\n  ): Minipass<string>\n  stream(\n    entry: string | PathBase,\n    opts: WalkOptions,\n  ): Minipass<string> | Minipass<PathBase>\n  stream(\n    entry: string | PathBase | WalkOptions = this.cwd,\n    opts: WalkOptions = {},\n  ): Minipass<string> | Minipass<PathBase> {\n    if (typeof entry === 'string') {\n      entry = this.cwd.resolve(entry)\n    } else if (!(entry instanceof PathBase)) {\n      opts = entry\n      entry = this.cwd\n    }\n    const {\n      withFileTypes = true,\n      follow = false,\n      filter,\n      walkFilter,\n    } = opts\n    const results = new Minipass<string | PathBase>({ objectMode: true })\n    if (!filter || filter(entry)) {\n      results.write(withFileTypes ? entry : entry.fullpath())\n    }\n    const dirs = new Set<PathBase>()\n    const queue: PathBase[] = [entry]\n    let processing = 0\n    const process = () => {\n      let paused = false\n      while (!paused) {\n        const dir = queue.shift()\n        if (!dir) {\n          if (processing === 0) results.end()\n          return\n        }\n\n        processing++\n        dirs.add(dir)\n\n        const onReaddir = (\n          er: null | NodeJS.ErrnoException,\n          entries: PathBase[],\n          didRealpaths: boolean = false,\n        ) => {\n          /* c8 ignore start */\n          if (er) return results.emit('error', er)\n          /* c8 ignore stop */\n          if (follow && !didRealpaths) {\n            const promises: Promise<PathBase | undefined>[] = []\n            for (const e of entries) {\n              if (e.isSymbolicLink()) {\n                promises.push(\n                  e\n                    .realpath()\n                    .then((r: PathBase | undefined) =>\n                      r?.isUnknown() ? r.lstat() : r,\n                    ),\n                )\n              }\n            }\n            if (promises.length) {\n              Promise.all(promises).then(() =>\n                onReaddir(null, entries, true),\n              )\n              return\n            }\n          }\n\n          for (const e of entries) {\n            if (e && (!filter || filter(e))) {\n              if (!results.write(withFileTypes ? e : e.fullpath())) {\n                paused = true\n              }\n            }\n          }\n\n          processing--\n          for (const e of entries) {\n            const r = e.realpathCached() || e\n            if (r.shouldWalk(dirs, walkFilter)) {\n              queue.push(r)\n            }\n          }\n          if (paused && !results.flowing) {\n            results.once('drain', process)\n          } else if (!sync) {\n            process()\n          }\n        }\n\n        // zalgo containment\n        let sync = true\n        dir.readdirCB(onReaddir, true)\n        sync = false\n      }\n    }\n    process()\n    return results as Minipass<string> | Minipass<PathBase>\n  }\n\n  /**\n   * Synchronous form of {@link PathScurryBase.stream}\n   *\n   * Returns a Minipass stream that emits {@link PathBase} objects by default,\n   * or strings if `{ withFileTypes: false }` is set in the options.\n   *\n   * Will complete the walk in a single tick if the stream is consumed fully.\n   * Otherwise, will pause as needed for stream backpressure.\n   */\n  streamSync(): Minipass<PathBase>\n  streamSync(\n    opts: WalkOptionsWithFileTypesTrue | WalkOptionsWithFileTypesUnset,\n  ): Minipass<PathBase>\n  streamSync(opts: WalkOptionsWithFileTypesFalse): Minipass<string>\n  streamSync(opts: WalkOptions): Minipass<string | PathBase>\n  streamSync(entry: string | PathBase): Minipass<PathBase>\n  streamSync(\n    entry: string | PathBase,\n    opts: WalkOptionsWithFileTypesUnset | WalkOptionsWithFileTypesTrue,\n  ): Minipass<PathBase>\n  streamSync(\n    entry: string | PathBase,\n    opts: WalkOptionsWithFileTypesFalse,\n  ): Minipass<string>\n  streamSync(\n    entry: string | PathBase,\n    opts: WalkOptions,\n  ): Minipass<string> | Minipass<PathBase>\n  streamSync(\n    entry: string | PathBase | WalkOptions = this.cwd,\n    opts: WalkOptions = {},\n  ): Minipass<string> | Minipass<PathBase> {\n    if (typeof entry === 'string') {\n      entry = this.cwd.resolve(entry)\n    } else if (!(entry instanceof PathBase)) {\n      opts = entry\n      entry = this.cwd\n    }\n    const {\n      withFileTypes = true,\n      follow = false,\n      filter,\n      walkFilter,\n    } = opts\n    const results = new Minipass<string | PathBase>({ objectMode: true })\n    const dirs = new Set<PathBase>()\n    if (!filter || filter(entry)) {\n      results.write(withFileTypes ? entry : entry.fullpath())\n    }\n    const queue: PathBase[] = [entry]\n    let processing = 0\n    const process = () => {\n      let paused = false\n      while (!paused) {\n        const dir = queue.shift()\n        if (!dir) {\n          if (processing === 0) results.end()\n          return\n        }\n        processing++\n        dirs.add(dir)\n\n        const entries = dir.readdirSync()\n        for (const e of entries) {\n          if (!filter || filter(e)) {\n            if (!results.write(withFileTypes ? e : e.fullpath())) {\n              paused = true\n            }\n          }\n        }\n        processing--\n        for (const e of entries) {\n          let r: PathBase | undefined = e\n          if (e.isSymbolicLink()) {\n            if (!(follow && (r = e.realpathSync()))) continue\n            if (r.isUnknown()) r.lstatSync()\n          }\n          if (r.shouldWalk(dirs, walkFilter)) {\n            queue.push(r)\n          }\n        }\n      }\n      if (paused && !results.flowing) results.once('drain', process)\n    }\n    process()\n    return results as Minipass<string> | Minipass<PathBase>\n  }\n\n  chdir(path: string | Path = this.cwd) {\n    const oldCwd = this.cwd\n    this.cwd = typeof path === 'string' ? this.cwd.resolve(path) : path\n    this.cwd[setAsCwd](oldCwd)\n  }\n}\n\n/**\n * Options provided to all walk methods.\n */\nexport interface WalkOptions {\n  /**\n   * Return results as {@link PathBase} objects rather than strings.\n   * When set to false, results are fully resolved paths, as returned by\n   * {@link PathBase.fullpath}.\n   * @default true\n   */\n  withFileTypes?: boolean\n\n  /**\n   *  Attempt to read directory entries from symbolic links. Otherwise, only\n   *  actual directories are traversed. Regardless of this setting, a given\n   *  target path will only ever be walked once, meaning that a symbolic link\n   *  to a previously traversed directory will never be followed.\n   *\n   *  Setting this imposes a slight performance penalty, because `readlink`\n   *  must be called on all symbolic links encountered, in order to avoid\n   *  infinite cycles.\n   * @default false\n   */\n  follow?: boolean\n\n  /**\n   * Only return entries where the provided function returns true.\n   *\n   * This will not prevent directories from being traversed, even if they do\n   * not pass the filter, though it will prevent directories themselves from\n   * being included in the result set.  See {@link walkFilter}\n   *\n   * Asynchronous functions are not supported here.\n   *\n   * By default, if no filter is provided, all entries and traversed\n   * directories are included.\n   */\n  filter?: (entry: PathBase) => boolean\n\n  /**\n   * Only traverse directories (and in the case of {@link follow} being set to\n   * true, symbolic links to directories) if the provided function returns\n   * true.\n   *\n   * This will not prevent directories from being included in the result set,\n   * even if they do not pass the supplied filter function.  See {@link filter}\n   * to do that.\n   *\n   * Asynchronous functions are not supported here.\n   */\n  walkFilter?: (entry: PathBase) => boolean\n}\n\nexport type WalkOptionsWithFileTypesUnset = WalkOptions & {\n  withFileTypes?: undefined\n}\nexport type WalkOptionsWithFileTypesTrue = WalkOptions & {\n  withFileTypes: true\n}\nexport type WalkOptionsWithFileTypesFalse = WalkOptions & {\n  withFileTypes: false\n}\n\n/**\n * Windows implementation of {@link PathScurryBase}\n *\n * Defaults to case insensitve, uses `'\\\\'` to generate path strings.  Uses\n * {@link PathWin32} for Path objects.\n */\nexport class PathScurryWin32 extends PathScurryBase {\n  /**\n   * separator for generating path strings\n   */\n  sep: '\\\\' = '\\\\'\n\n  constructor(\n    cwd: URL | string = process.cwd(),\n    opts: PathScurryOpts = {},\n  ) {\n    const { nocase = true } = opts\n    super(cwd, win32, '\\\\', { ...opts, nocase })\n    this.nocase = nocase\n    for (let p: PathBase | undefined = this.cwd; p; p = p.parent) {\n      p.nocase = this.nocase\n    }\n  }\n\n  /**\n   * @internal\n   */\n  parseRootPath(dir: string): string {\n    // if the path starts with a single separator, it's not a UNC, and we'll\n    // just get separator as the root, and driveFromUNC will return \\\n    // In that case, mount \\ on the root from the cwd.\n    return win32.parse(dir).root.toUpperCase()\n  }\n\n  /**\n   * @internal\n   */\n  newRoot(fs: FSValue) {\n    return new PathWin32(\n      this.rootPath,\n      IFDIR,\n      undefined,\n      this.roots,\n      this.nocase,\n      this.childrenCache(),\n      { fs },\n    )\n  }\n\n  /**\n   * Return true if the provided path string is an absolute path\n   */\n  isAbsolute(p: string): boolean {\n    return (\n      p.startsWith('/') || p.startsWith('\\\\') || /^[a-z]:(\\/|\\\\)/i.test(p)\n    )\n  }\n}\n\n/**\n * {@link PathScurryBase} implementation for all posix systems other than Darwin.\n *\n * Defaults to case-sensitive matching, uses `'/'` to generate path strings.\n *\n * Uses {@link PathPosix} for Path objects.\n */\nexport class PathScurryPosix extends PathScurryBase {\n  /**\n   * separator for generating path strings\n   */\n  sep: '/' = '/'\n  constructor(\n    cwd: URL | string = process.cwd(),\n    opts: PathScurryOpts = {},\n  ) {\n    const { nocase = false } = opts\n    super(cwd, posix, '/', { ...opts, nocase })\n    this.nocase = nocase\n  }\n\n  /**\n   * @internal\n   */\n  parseRootPath(_dir: string): string {\n    return '/'\n  }\n\n  /**\n   * @internal\n   */\n  newRoot(fs: FSValue) {\n    return new PathPosix(\n      this.rootPath,\n      IFDIR,\n      undefined,\n      this.roots,\n      this.nocase,\n      this.childrenCache(),\n      { fs },\n    )\n  }\n\n  /**\n   * Return true if the provided path string is an absolute path\n   */\n  isAbsolute(p: string): boolean {\n    return p.startsWith('/')\n  }\n}\n\n/**\n * {@link PathScurryBase} implementation for Darwin (macOS) systems.\n *\n * Defaults to case-insensitive matching, uses `'/'` for generating path\n * strings.\n *\n * Uses {@link PathPosix} for Path objects.\n */\nexport class PathScurryDarwin extends PathScurryPosix {\n  constructor(\n    cwd: URL | string = process.cwd(),\n    opts: PathScurryOpts = {},\n  ) {\n    const { nocase = true } = opts\n    super(cwd, { ...opts, nocase })\n  }\n}\n\n/**\n * Default {@link PathBase} implementation for the current platform.\n *\n * {@link PathWin32} on Windows systems, {@link PathPosix} on all others.\n */\nexport const Path = process.platform === 'win32' ? PathWin32 : PathPosix\nexport type Path = PathBase | InstanceType<typeof Path>\n\n/**\n * Default {@link PathScurryBase} implementation for the current platform.\n *\n * {@link PathScurryWin32} on Windows systems, {@link PathScurryDarwin} on\n * Darwin (macOS) systems, {@link PathScurryPosix} on all others.\n */\nexport const PathScurry:\n  | typeof PathScurryWin32\n  | typeof PathScurryDarwin\n  | typeof PathScurryPosix =\n  process.platform === 'win32' ? PathScurryWin32\n  : process.platform === 'darwin' ? PathScurryDarwin\n  : PathScurryPosix\nexport type PathScurry = PathScurryBase | InstanceType<typeof PathScurry>\n"]}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             4.21.2 / 2024-11-06
==========

  * deps: path-to-regexp@0.1.12
    - Fix backtracking protection
  * deps: path-to-regexp@0.1.11
    - Throws an error on invalid path values

4.21.1 / 2024-10-08
==========

  * Backported a fix for [CVE-2024-47764](https://nvd.nist.gov/vuln/detail/CVE-2024-47764)


4.21.0 / 2024-09-11
==========

  * Deprecate `res.location("back")` and `res.redirect("back")` magic string
  * deps: serve-static@1.16.2
    * includes send@0.19.0
  * deps: finalhandler@1.3.1
  * deps: qs@6.13.0

4.20.0 / 2024-09-10
==========
  * deps: serve-static@0.16.0
    * Remove link renderization in html while redirecting
  * deps: send@0.19.0
    * Remove link renderization in html while redirecting
  * deps: body-parser@0.6.0
    * add `depth` option to customize the depth level in the parser
    * IMPORTANT: The default `depth` level for parsing URL-encoded data is now `32` (previously was `Infinity`)
  * Remove link renderization in html while using `res.redirect`
  * deps: path-to-regexp@0.1.10
    - Adds support for named matching groups in the routes using a regex
    - Adds backtracking protection to parameters without regexes defined
  * deps: encodeurl@~2.0.0
    - Removes encoding of `\`, `|`, and `^` to align better with URL spec
  * Deprecate passing `options.maxAge` and `options.expires` to `res.clearCookie`
    - Will be ignored in v5, clearCookie will set a cookie with an expires in the past to instruct clients to delete the cookie

4.19.2 / 2024-03-25
==========

  * Improved fix for open redirect allow list bypass

4.19.1 / 2024-03-20
==========

  * Allow passing non-strings to res.location with new encoding handling checks

4.19.0 / 2024-03-20
==========

  * Prevent open redirect allow list bypass due to encodeurl
  * deps: cookie@0.6.0

4.18.3 / 2024-02-29
==========

  * Fix routing requests without method
  * deps: body-parser@1.20.2
    - Fix strict json error message on Node.js 19+
    - deps: content-type@~1.0.5
    - deps: raw-body@2.5.2
  * deps: cookie@0.6.0
    - Add `partitioned` option

4.18.2 / 2022-10-08
===================

  * Fix regression routing a large stack in a single route
  * deps: body-parser@1.20.1
    - deps: qs@6.11.0
    - perf: remove unnecessary object clone
  * deps: qs@6.11.0

4.18.1 / 2022-04-29
===================

  * Fix hanging on large stack of sync routes

4.18.0 / 2022-04-25
===================

  * Add "root" option to `res.download`
  * Allow `options` without `filename` in `res.download`
  * Deprecate string and non-integer arguments to `res.status`
  * Fix behavior of `null`/`undefined` as `maxAge` in `res.cookie`
  * Fix handling very large stacks of sync middleware
  * Ignore `Object.prototype` values in settings through `app.set`/`app.get`
  * Invoke `default` with same arguments as types in `res.format`
  * Support proper 205 responses using `res.send`
  * Use `http-errors` for `res.format` error
  * deps: body-parser@1.20.0
    - Fix error message for json parse whitespace in `strict`
    - Fix internal error when inflated body exceeds limit
    - Prevent loss of async hooks context
    - Prevent hanging when request already read
    - deps: depd@2.0.0
    - deps: http-errors@2.0.0
    - deps: on-finished@2.4.1
    - deps: qs@6.10.3
    - deps: raw-body@2.5.1
  * deps: cookie@0.5.0
    - Add `priority` option
    - Fix `expires` option to reject invalid dates
  * deps: depd@2.0.0
    - Replace internal `eval` usage with `Function` constructor
    - Use instance methods on `process` to check for listeners
  * deps: finalhandler@1.2.0
    - Remove set content headers that break response
    - deps: on-finished@2.4.1
    - deps: statuses@2.0.1
  * deps: on-finished@2.4.1
    - Prevent loss of async hooks context
  * deps: qs@6.10.3
  * deps: send@0.18.0
    - Fix emitted 416 error missing headers property
    - Limit the headers removed for 304 response
    - deps: depd@2.0.0
    - deps: destroy@1.2.0
    - deps: http-errors@2.0.0
    - deps: on-finished@2.4.1
    - deps: statuses@2.0.1
  * deps: serve-static@1.15.0
    - deps: send@0.18.0
  * deps: statuses@2.0.1
    - Remove code 306
    - Rename `425 Unordered Collection` to standard `425 Too Early`

4.17.3 / 2022-02-16
===================

  * deps: accepts@~1.3.8
    - deps: mime-types@~2.1.34
    - deps: negotiator@0.6.3
  * deps: body-parser@1.19.2
    - deps: bytes@3.1.2
    - deps: qs@6.9.7
    - deps: raw-body@2.4.3
  * deps: cookie@0.4.2
  * deps: qs@6.9.7
    * Fix handling of `__proto__` keys
  * pref: remove unnecessary regexp for trust proxy

4.17.2 / 2021-12-16
===================

  * Fix handling of `undefined` in `res.jsonp`
  * Fix handling of `undefined` when `"json escape"` is enabled
  * Fix incorrect middleware execution with unanchored `RegExp`s
  * Fix `res.jsonp(obj, status)` deprecation message
  * Fix typo in `res.is` JSDoc
  * deps: body-parser@1.19.1
    - deps: bytes@3.1.1
    - deps: http-errors@1.8.1
    - deps: qs@6.9.6
    - deps: raw-body@2.4.2
    - deps: safe-buffer@5.2.1
    - deps: type-is@~1.6.18
  * deps: content-disposition@0.5.4
    - deps: safe-buffer@5.2.1
  * deps: cookie@0.4.1
    - Fix `maxAge` option to reject invalid values
  * deps: proxy-addr@~2.0.7
    - Use `req.socket` over deprecated `req.connection`
    - deps: forwarded@0.2.0
    - deps: ipaddr.js@1.9.1
  * deps: qs@6.9.6
  * deps: safe-buffer@5.2.1
  * deps: send@0.17.2
    - deps: http-errors@1.8.1
    - deps: ms@2.1.3
    - pref: ignore empty http tokens
  * deps: serve-static@1.14.2
    - deps: send@0.17.2
  * deps: setprototypeof@1.2.0

4.17.1 / 2019-05-25
===================

  * Revert "Improve error message for `null`/`undefined` to `res.status`"

4.17.0 / 2019-05-16
===================

  * Add `express.raw` to parse bodies into `Buffer`
  * Add `express.text` to parse bodies into string
  * Improve error message for non-strings to `res.sendFile`
  * Improve error message for `null`/`undefined` to `res.status`
  * Support multiple hosts in `X-Forwarded-Host`
  * deps: accepts@~1.3.7
  * deps: body-parser@1.19.0
    - Add encoding MIK
    - Add petabyte (`pb`) support
    - Fix parsing array brackets after index
    - deps: bytes@3.1.0
    - deps: http-errors@1.7.2
    - deps: iconv-lite@0.4.24
    - deps: qs@6.7.0
    - deps: raw-body@2.4.0
    - deps: type-is@~1.6.17
  * deps: content-disposition@0.5.3
  * deps: cookie@0.4.0
    - Add `SameSite=None` support
  * deps: finalhandler@~1.1.2
    - Set stricter `Content-Security-Policy` header
    - deps: parseurl@~1.3.3
    - deps: statuses@~1.5.0
  * deps: parseurl@~1.3.3
  * deps: proxy-addr@~2.0.5
    - deps: ipaddr.js@1.9.0
  * deps: qs@6.7.0
    - Fix parsing array brackets after index
  * deps: range-parser@~1.2.1
  * deps: send@0.17.1
    - Set stricter CSP header in redirect & error responses
    - deps: http-errors@~1.7.2
    - deps: mime@1.6.0
    - deps: ms@2.1.1
    - deps: range-parser@~1.2.1
    - deps: statuses@~1.5.0
    - perf: remove redundant `path.normalize` call
  * deps: serve-static@1.14.1
    - Set stricter CSP header in redirect response
    - deps: parseurl@~1.3.3
    - deps: send@0.17.1
  * deps: setprototypeof@1.1.1
  * deps: statuses@~1.5.0
    - Add `103 Early Hints`
  * deps: type-is@~1.6.18
    - deps: mime-types@~2.1.24
    - perf: prevent internal `throw` on invalid type

4.16.4 / 2018-10-10
===================

  * Fix issue where `"Request aborted"` may be logged in `res.sendfile`
  * Fix JSDoc for `Router` constructor
  * deps: body-parser@1.18.3
    - Fix deprecation warnings on Node.js 10+
    - Fix stack trace for strict json parse error
    - deps: depd@~1.1.2
    - deps: http-errors@~1.6.3
    - deps: iconv-lite@0.4.23
    - deps: qs@6.5.2
    - deps: raw-body@2.3.3
    - deps: type-is@~1.6.16
  * deps: proxy-addr@~2.0.4
    - deps: ipaddr.js@1.8.0
  * deps: qs@6.5.2
  * deps: safe-buffer@5.1.2

4.16.3 / 2018-03-12
===================

  * deps: accepts@~1.3.5
    - deps: mime-types@~2.1.18
  * deps: depd@~1.1.2
    - perf: remove argument reassignment
  * deps: encodeurl@~1.0.2
    - Fix encoding `%` as last character
  * deps: finalhandler@1.1.1
    - Fix 404 output for bad / missing pathnames
    - deps: encodeurl@~1.0.2
    - deps: statuses@~1.4.0
  * deps: proxy-addr@~2.0.3
    - deps: ipaddr.js@1.6.0
  * deps: send@0.16.2
    - Fix incorrect end tag in default error & redirects
    - deps: depd@~1.1.2
    - deps: encodeurl@~1.0.2
    - deps: statuses@~1.4.0
  * deps: serve-static@1.13.2
    - Fix incorrect end tag in redirects
    - deps: encodeurl@~1.0.2
    - deps: send@0.16.2
  * deps: statuses@~1.4.0
  * deps: type-is@~1.6.16
    - deps: mime-types@~2.1.18

4.16.2 / 2017-10-09
===================

  * Fix `TypeError` in `res.send` when given `Buffer` and `ETag` header set
  * perf: skip parsing of entire `X-Forwarded-Proto` header

4.16.1 / 2017-09-29
===================

  * deps: send@0.16.1
  * deps: serve-static@1.13.1
    - Fix regression when `root` is incorrectly set to a file
    - deps: send@0.16.1

4.16.0 / 2017-09-28
===================

  * Add `"json escape"` setting for `res.json` and `res.jsonp`
  * Add `express.json` and `express.urlencoded` to parse bodies
  * Add `options` argument to `res.download`
  * Improve error message when autoloading invalid view engine
  * Improve error messages when non-function provided as middleware
  * Skip `Buffer` encoding when not generating ETag for small response
  * Use `safe-buffer` for improved Buffer API
  * deps: accepts@~1.3.4
    - deps: mime-types@~2.1.16
  * deps: content-type@~1.0.4
    - perf: remove argument reassignment
    - perf: skip parameter parsing when no parameters
  * deps: etag@~1.8.1
    - perf: replace regular expression with substring
  * deps: finalhandler@1.1.0
    - Use `res.headersSent` when available
  * deps: parseurl@~1.3.2
    - perf: reduce overhead for full URLs
    - perf: unroll the "fast-path" `RegExp`
  * deps: proxy-addr@~2.0.2
    - Fix trimming leading / trailing OWS in `X-Forwarded-For`
    - deps: forwarded@~0.1.2
    - deps: ipaddr.js@1.5.2
    - perf: reduce overhead when no `X-Forwarded-For` header
  * deps: qs@6.5.1
    - Fix parsing & compacting very deep objects
  * deps: send@0.16.0
    - Add 70 new types for file extensions
    - Add `immutable` option
    - Fix missing `</html>` in default error & redirects
    - Set charset as "UTF-8" for .js and .json
    - Use instance methods on steam to check for listeners
    - deps: mime@1.4.1
    - perf: improve path validation speed
  * deps: serve-static@1.13.0
    - Add 70 new types for file extensions
    - Add `immutable` option
    - Set charset as "UTF-8" for .js and .json
    - deps: send@0.16.0
  * deps: setprototypeof@1.1.0
  * deps: utils-merge@1.0.1
  * deps: vary@~1.1.2
    - perf: improve header token parsing speed
  * perf: re-use options object when generating ETags
  * perf: remove dead `.charset` set in `res.jsonp`

4.15.5 / 2017-09-24
===================

  * deps: debug@2.6.9
  * deps: finalhandler@~1.0.6
    - deps: debug@2.6.9
    - deps: parseurl@~1.3.2
  * deps: fresh@0.5.2
    - Fix handling of modified headers with invalid dates
    - perf: improve ETag match loop
    - perf: improve `If-None-Match` token parsing
  * deps: send@0.15.6
    - Fix handling of modified headers with invalid dates
    - deps: debug@2.6.9
    - deps: etag@~1.8.1
    - deps: fresh@0.5.2
    - perf: improve `If-Match` token parsing
  * deps: serve-static@1.12.6
    - deps: parseurl@~1.3.2
    - deps: send@0.15.6
    - perf: improve slash collapsing

4.15.4 / 2017-08-06
===================

  * deps: debug@2.6.8
  * deps: depd@~1.1.1
    - Remove unnecessary `Buffer` loading
  * deps: finalhandler@~1.0.4
    - deps: debug@2.6.8
  * deps: proxy-addr@~1.1.5
    - Fix array argument being altered
    - deps: ipaddr.js@1.4.0
  * deps: qs@6.5.0
  * deps: send@0.15.4
    - deps: debug@2.6.8
    - deps: depd@~1.1.1
    - deps: http-errors@~1.6.2
  * deps: serve-static@1.12.4
    - deps: send@0.15.4

4.15.3 / 2017-05-16
===================

  * Fix error when `res.set` cannot add charset to `Content-Type`
  * deps: debug@2.6.7
    - Fix `DEBUG_MAX_ARRAY_LENGTH`
    - deps: ms@2.0.0
  * deps: finalhandler@~1.0.3
    - Fix missing `</html>` in HTML document
    - deps: debug@2.6.7
  * deps: proxy-addr@~1.1.4
    - deps: ipaddr.js@1.3.0
  * deps: send@0.15.3
    - deps: debug@2.6.7
    - deps: ms@2.0.0
  * deps: serve-static@1.12.3
    - deps: send@0.15.3
  * deps: type-is@~1.6.15
    - deps: mime-types@~2.1.15
  * deps: vary@~1.1.1
    - perf: hoist regular expression

4.15.2 / 2017-03-06
===================

  * deps: qs@6.4.0
    - Fix regression parsing keys starting with `[`

4.15.1 / 2017-03-05
===================

  * deps: send@0.15.1
    - Fix issue when `Date.parse` does not return `NaN` on invalid date
    - Fix strict violation in broken environments
  * deps: serve-static@1.12.1
    - Fix issue when `Date.parse` does not return `NaN` on invalid date
    - deps: send@0.15.1

4.15.0 / 2017-03-01
===================

  * Add debug message when loading view engine
  * Add `next("router")` to exit from router
  * Fix case where `router.use` skipped requests routes did not
  * Remove usage of `res._headers` private field
    - Improves compatibility with Node.js 8 nightly
  * Skip routing when `req.url` is not set
  * Use `%o` in path debug to tell types apart
  * Use `Object.create` to setup request & response prototypes
  * Use `setprototypeof` module to replace `__proto__` setting
  * Use `statuses` instead of `http` module for status messages
  * deps: debug@2.6.1
    - Allow colors in workers
    - Deprecated `DEBUG_FD` environment variable set to `3` or higher
    - Fix error when running under React Native
    - Use same color for same namespace
    - deps: ms@0.7.2
  * deps: etag@~1.8.0
    - Use SHA1 instead of MD5 for ETag hashing
    - Works with FIPS 140-2 OpenSSL configuration
  * deps: finalhandler@~1.0.0
    - Fix exception when `err` cannot be converted to a string
    - Fully URL-encode the pathname in the 404
    - Only include the pathname in the 404 message
    - Send complete HTML document
    - Set `Content-Security-Policy: default-src 'self'` header
    - deps: debug@2.6.1
  * deps: fresh@0.5.0
    - Fix false detection of `no-cache` request directive
    - Fix incorrect result when `If-None-Match` has both `*` and ETags
    - Fix weak `ETag` matching to match spec
    - perf: delay reading header values until needed
    - perf: enable strict mode
    - perf: hoist regular expressions
    - perf: remove duplicate conditional
    - perf: remove unnecessary boolean coercions
    - perf: skip checking modified time if ETag check failed
    - perf: skip parsing `If-None-Match` when no `ETag` header
    - perf: use `Date.parse` instead of `new Date`
  * deps: qs@6.3.1
    - Fix array parsing from skipping empty values
    - Fix compacting nested arrays
  * deps: send@0.15.0
    - Fix false detection of `no-cache` request directive
    - Fix incorrect result when `If-None-Match` has both `*` and ETags
    - Fix weak `ETag` matching to match spec
    - Remove usage of `res._headers` private field
    - Support `If-Match` and `If-Unmodified-Since` headers
    - Use `res.getHeaderNames()` when available
    - Use `res.headersSent` when available
    - deps: debug@2.6.1
    - deps: etag@~1.8.0
    - deps: fresh@0.5.0
    - deps: http-errors@~1.6.1
  * deps: serve-static@1.12.0
    - Fix false detection of `no-cache` request directive
    - Fix incorrect result when `If-None-Match` has both `*` and ETags
    - Fix weak `ETag` matching to match spec
    - Remove usage of `res._headers` private field
    - Send complete HTML document in redirect response
    - Set default CSP header in redirect response
    - Support `If-Match` and `If-Unmodified-Since` headers
    - Use `res.getHeaderNames()` when available
    - Use `res.headersSent` when available
    - deps: send@0.15.0
  * perf: add fast match path for `*` route
  * perf: improve `req.ips` performance

4.14.1 / 2017-01-28
===================

  * deps: content-disposition@0.5.2
  * deps: finalhandler@0.5.1
    - Fix exception when `err.headers` is not an object
    - deps: statuses@~1.3.1
    - perf: hoist regular expressions
    - perf: remove duplicate validation path
  * deps: proxy-addr@~1.1.3
    - deps: ipaddr.js@1.2.0
  * deps: send@0.14.2
    - deps: http-errors@~1.5.1
    - deps: ms@0.7.2
    - deps: statuses@~1.3.1
  * deps: serve-static@~1.11.2
    - deps: send@0.14.2
  * deps: type-is@~1.6.14
    - deps: mime-types@~2.1.13

4.14.0 / 2016-06-16
===================

  * Add `acceptRanges` option to `res.sendFile`/`res.sendfile`
  * Add `cacheControl` option to `res.sendFile`/`res.sendfile`
  * Add `options` argument to `req.range`
    - Includes the `combine` option
  * Encode URL in `res.location`/`res.redirect` if not already encoded
  * Fix some redirect handling in `res.sendFile`/`res.sendfile`
  * Fix Windows absolute path check using forward slashes
  * Improve error with invalid arguments to `req.get()`
  * Improve performance for `res.json`/`res.jsonp` in most cases
  * Improve `Range` header handling in `res.sendFile`/`res.sendfile`
  * deps: accepts@~1.3.3
    - Fix including type extensions in parameters in `Accept` parsing
    - Fix parsing `Accept` parameters with quoted equals
    - Fix parsing `Accept` parameters with quoted semicolons
    - Many performance improvements
    - deps: mime-types@~2.1.11
    - deps: negotiator@0.6.1
  * deps: content-type@~1.0.2
    - perf: enable strict mode
  * deps: cookie@0.3.1
    - Add `sameSite` option
    - Fix cookie `Max-Age` to never be a floating point number
    - Improve error message when `encode` is not a function
    - Improve error message when `expires` is not a `Date`
    - Throw better error for invalid argument to parse
    - Throw on invalid values provided to `serialize`
    - perf: enable strict mode
    - perf: hoist regular expression
    - perf: use for loop in parse
    - perf: use string concatenation for serialization
  * deps: finalhandler@0.5.0
    - Change invalid or non-numeric status code to 500
    - Overwrite status message to match set status code
    - Prefer `err.statusCode` if `err.status` is invalid
    - Set response headers from `err.headers` object
    - Use `statuses` instead of `http` module for status messages
  * deps: proxy-addr@~1.1.2
    - Fix accepting various invalid netmasks
    - Fix IPv6-mapped IPv4 validation edge cases
    - IPv4 netmasks must be contiguous
    - IPv6 addresses cannot be used as a netmask
    - deps: ipaddr.js@1.1.1
  * deps: qs@6.2.0
    - Add `decoder` option in `parse` function
  * deps: range-parser@~1.2.0
    - Add `combine` option to combine overlapping ranges
    - Fix incorrectly returning -1 when there is at least one valid range
    - perf: remove internal function
  * deps: send@0.14.1
    - Add `acceptRanges` option
    - Add `cacheControl` option
    - Attempt to combine multiple ranges into single range
    - Correctly inherit from `Stream` class
    - Fix `Content-Range` header in 416 responses when using `start`/`end` options
    - Fix `Content-Range` header missing from default 416 responses
    - Fix redirect error when `path` contains raw non-URL characters
    - Fix redirect when `path` starts with multiple forward slashes
    - Ignore non-byte `Range` headers
    - deps: http-errors@~1.5.0
    - deps: range-parser@~1.2.0
    - deps: statuses@~1.3.0
    - perf: remove argument reassignment
  * deps: serve-static@~1.11.1
    - Add `acceptRanges` option
    - Add `cacheControl` option
    - Attempt to combine multiple ranges into single range
    - Fix redirect error when `req.url` contains raw non-URL characters
    - Ignore non-byte `Range` headers
    - Use status code 301 for redirects
    - deps: send@0.14.1
  * deps: type-is@~1.6.13
    - Fix type error when given invalid type to match against
    - deps: mime-types@~2.1.11
  * deps: vary@~1.1.0
    - Only accept valid field names in the `field` argument
  * perf: use strict equality when possible

4.13.4 / 2016-01-21
===================

  * deps: content-disposition@0.5.1
    - perf: enable strict mode
  * deps: cookie@0.1.5
    - Throw on invalid values provided to `serialize`
  * deps: depd@~1.1.0
    - Support web browser loading
    - perf: enable strict mode
  * deps: escape-html@~1.0.3
    - perf: enable strict mode
    - perf: optimize string replacement
    - perf: use faster string coercion
  * deps: finalhandler@0.4.1
    - deps: escape-html@~1.0.3
  * deps: merge-descriptors@1.0.1
    - perf: enable strict mode
  * deps: methods@~1.1.2
    - perf: enable strict mode
  * deps: parseurl@~1.3.1
    - perf: enable strict mode
  * deps: proxy-addr@~1.0.10
    - deps: ipaddr.js@1.0.5
    - perf: enable strict mode
  * deps: range-parser@~1.0.3
    - perf: enable strict mode
  * deps: send@0.13.1
    - deps: depd@~1.1.0
    - deps: destroy@~1.0.4
    - deps: escape-html@~1.0.3
    - deps: range-parser@~1.0.3
  * deps: serve-static@~1.10.2
    - deps: escape-html@~1.0.3
    - deps: parseurl@~1.3.0
    - deps: send@0.13.1

4.13.3 / 2015-08-02
===================

  * Fix infinite loop condition using `mergeParams: true`
  * Fix inner numeric indices incorrectly altering parent `req.params`

4.13.2 / 2015-07-31
===================

  * deps: accepts@~1.2.12
    - deps: mime-types@~2.1.4
  * deps: array-flatten@1.1.1
    - perf: enable strict mode
  * deps: path-to-regexp@0.1.7
    - Fix regression with escaped round brackets and matching groups
  * deps: type-is@~1.6.6
    - deps: mime-types@~2.1.4

4.13.1 / 2015-07-05
===================

  * deps: accepts@~1.2.10
    - deps: mime-types@~2.1.2
  * deps: qs@4.0.0
    - Fix dropping parameters like `hasOwnProperty`
    - Fix various parsing edge cases
  * deps: type-is@~1.6.4
    - deps: mime-types@~2.1.2
    - perf: enable strict mode
    - perf: remove argument reassignment

4.13.0 / 2015-06-20
===================

  * Add settings to debug output
  * Fix `res.format` error when only `default` provided
  * Fix issue where `next('route')` in `app.param` would incorrectly skip values
  * Fix hiding platform issues with `decodeURIComponent`
    - Only `URIError`s are a 400
  * Fix using `*` before params in routes
  * Fix using capture groups before params in routes
  * Simplify `res.cookie` to call `res.append`
  * Use `array-flatten` module for flattening arrays
  * deps: accepts@~1.2.9
    - deps: mime-types@~2.1.1
    - perf: avoid argument reassignment & argument slice
    - perf: avoid negotiator recursive construction
    - perf: enable strict mode
    - perf: remove unnecessary bitwise operator
  * deps: cookie@0.1.3
    - perf: deduce the scope of try-catch deopt
    - perf: remove argument reassignments
  * deps: escape-html@1.0.2
  * deps: etag@~1.7.0
    - Always include entity length in ETags for hash length extensions
    - Generate non-Stats ETags using MD5 only (no longer CRC32)
    - Improve stat performance by removing hashing
    - Improve support for JXcore
    - Remove base64 padding in ETags to shorten
    - Support "fake" stats objects in environments without fs
    - Use MD5 instead of MD4 in weak ETags over 1KB
  * deps: finalhandler@0.4.0
    - Fix a false-positive when unpiping in Node.js 0.8
    - Support `statusCode` property on `Error` objects
    - Use `unpipe` module for unpiping requests
    - deps: escape-html@1.0.2
    - deps: on-finished@~2.3.0
    - perf: enable strict mode
    - perf: remove argument reassignment
  * deps: fresh@0.3.0
    - Add weak `ETag` matching support
  * deps: on-finished@~2.3.0
    - Add defined behavior for HTTP `CONNECT` requests
    - Add defined behavior for HTTP `Upgrade` requests
    - deps: ee-first@1.1.1
  * deps: path-to-regexp@0.1.6
  * deps: send@0.13.0
    - Allow Node.js HTTP server to set `Date` response header
    - Fix incorrectly removing `Content-Location` on 304 response
    - Improve the default redirect response headers
    - Send appropriate headers on default error response
    - Use `http-errors` for standard emitted errors
    - Use `statuses` instead of `http` module for status messages
    - deps: escape-html@1.0.2
    - deps: etag@~1.7.0
    - deps: fresh@0.3.0
    - deps: on-finished@~2.3.0
    - perf: enable strict mode
    - perf: remove unnecessary array allocations
  * deps: serve-static@~1.10.0
    - Add `fallthrough` option
    - Fix reading options from options prototype
    - Improve the default redirect response headers
    - Malformed URLs now `next()` instead of 400
    - deps: escape-html@1.0.2
    - deps: send@0.13.0
    - perf: enable strict mode
    - perf: remove argument reassignment
  * deps: type-is@~1.6.3
    - deps: mime-types@~2.1.1
    - perf: reduce try block size
    - perf: remove bitwise operations
  * perf: enable strict mode
  * perf: isolate `app.render` try block
  * perf: remove argument reassignments in application
  * perf: remove argument reassignments in request prototype
  * perf: remove argument reassignments in response prototype
  * perf: remove argument reassignments in routing
  * perf: remove argument reassignments in `View`
  * perf: skip attempting to decode zero length string
  * perf: use saved reference to `http.STATUS_CODES`

4.12.4 / 2015-05-17
===================

  * deps: accepts@~1.2.7
    - deps: mime-types@~2.0.11
    - deps: negotiator@0.5.3
  * deps: debug@~2.2.0
    - deps: ms@0.7.1
  * deps: depd@~1.0.1
  * deps: etag@~1.6.0
    - Improve support for JXcore
    - Support "fake" stats objects in environments without `fs`
  * deps: finalhandler@0.3.6
    - deps: debug@~2.2.0
    - deps: on-finished@~2.2.1
  * deps: on-finished@~2.2.1
    - Fix `isFinished(req)` when data buffered
  * deps: proxy-addr@~1.0.8
    - deps: ipaddr.js@1.0.1
  * deps: qs@2.4.2
   - Fix allowing parameters like `constructor`
  * deps: send@0.12.3
    - deps: debug@~2.2.0
    - deps: depd@~1.0.1
    - deps: etag@~1.6.0
    - deps: ms@0.7.1
    - deps: on-finished@~2.2.1
  * deps: serve-static@~1.9.3
    - deps: send@0.12.3
  * deps: type-is@~1.6.2
    - deps: mime-types@~2.0.11

4.12.3 / 2015-03-17
===================

  * deps: accepts@~1.2.5
    - deps: mime-types@~2.0.10
  * deps: debug@~2.1.3
    - Fix high intensity foreground color for bold
    - deps: ms@0.7.0
  * deps: finalhandler@0.3.4
    - deps: debug@~2.1.3
  * deps: proxy-addr@~1.0.7
    - deps: ipaddr.js@0.1.9
  * deps: qs@2.4.1
    - Fix error when parameter `hasOwnProperty` is present
  * deps: send@0.12.2
    - Throw errors early for invalid `extensions` or `index` options
    - deps: debug@~2.1.3
  * deps: serve-static@~1.9.2
    - deps: send@0.12.2
  * deps: type-is@~1.6.1
    - deps: mime-types@~2.0.10

4.12.2 / 2015-03-02
===================

  * Fix regression where `"Request aborted"` is logged using `res.sendFile`

4.12.1 / 2015-03-01
===================

  * Fix constructing application with non-configurable prototype properties
  * Fix `ECONNRESET` errors from `res.sendFile` usage
  * Fix `req.host` when using "trust proxy" hops count
  * Fix `req.protocol`/`req.secure` when using "trust proxy" hops count
  * Fix wrong `code` on aborted connections from `res.sendFile`
  * deps: merge-descriptors@1.0.0

4.12.0 / 2015-02-23
===================

  * Fix `"trust proxy"` setting to inherit when app is mounted
  * Generate `ETag`s for all request responses
    - No longer restricted to only responses for `GET` and `HEAD` requests
  * Use `content-type` to parse `Content-Type` headers
  * deps: accepts@~1.2.4
    - Fix preference sorting to be stable for long acceptable lists
    - deps: mime-types@~2.0.9
    - deps: negotiator@0.5.1
  * deps: cookie-signature@1.0.6
  * deps: send@0.12.1
    - Always read the stat size from the file
    - Fix mutating passed-in `options`
    - deps: mime@1.3.4
  * deps: serve-static@~1.9.1
    - deps: send@0.12.1
  * deps: type-is@~1.6.0
    - fix argument reassignment
    - fix false-positives in `hasBody` `Transfer-Encoding` check
    - support wildcard for both type and subtype (`*/*`)
    - deps: mime-types@~2.0.9

4.11.2 / 2015-02-01
===================

  * Fix `res.redirect` double-calling `res.end` for `HEAD` requests
  * deps: accepts@~1.2.3
    - deps: mime-types@~2.0.8
  * deps: proxy-addr@~1.0.6
    - deps: ipaddr.js@0.1.8
  * deps: type-is@~1.5.6
    - deps: mime-types@~2.0.8

4.11.1 / 2015-01-20
===================

  * deps: send@0.11.1
    - Fix root path disclosure
  * deps: serve-static@~1.8.1
    - Fix redirect loop in Node.js 0.11.14
    - Fix root path disclosure
    - deps: send@0.11.1

4.11.0 / 2015-01-13
===================

  * Add `res.append(field, val)` to append headers
  * Deprecate leading `:` in `name` for `app.param(name, fn)`
  * Deprecate `req.param()` -- use `req.params`, `req.body`, or `req.query` instead
  * Deprecate `app.param(fn)`
  * Fix `OPTIONS` responses to include the `HEAD` method properly
  * Fix `res.sendFile` not always detecting aborted connection
  * Match routes iteratively to prevent stack overflows
  * deps: accepts@~1.2.2
    - deps: mime-types@~2.0.7
    - deps: negotiator@0.5.0
  * deps: send@0.11.0
    - deps: debug@~2.1.1
    - deps: etag@~1.5.1
    - deps: ms@0.7.0
    - deps: on-finished@~2.2.0
  * deps: serve-static@~1.8.0
    - deps: send@0.11.0

4.10.8 / 2015-01-13
===================

  * Fix crash from error within `OPTIONS` response handler
  * deps: proxy-addr@~1.0.5
    - deps: ipaddr.js@0.1.6

4.10.7 / 2015-01-04
===================

  * Fix `Allow` header for `OPTIONS` to not contain duplicate methods
  * Fix incorrect "Request aborted" for `res.sendFile` when `HEAD` or 304
  * deps: debug@~2.1.1
  * deps: finalhandler@0.3.3
    - deps: debug@~2.1.1
    - deps: on-finished@~2.2.0
  * deps: methods@~1.1.1
  * deps: on-finished@~2.2.0
  * deps: serve-static@~1.7.2
    - Fix potential open redirect when mounted at root
  * deps: type-is@~1.5.5
    - deps: mime-types@~2.0.7

4.10.6 / 2014-12-12
===================

  * Fix exception in `req.fresh`/`req.stale` without response headers

4.10.5 / 2014-12-10
===================

  * Fix `res.send` double-calling `res.end` for `HEAD` requests
  * deps: accepts@~1.1.4
    - deps: mime-types@~2.0.4
  * deps: type-is@~1.5.4
    - deps: mime-types@~2.0.4

4.10.4 / 2014-11-24
===================

  * Fix `res.sendfile` logging standard write errors

4.10.3 / 2014-11-23
===================

  * Fix `res.sendFile` logging standard write errors
  * deps: etag@~1.5.1
  * deps: proxy-addr@~1.0.4
    - deps: ipaddr.js@0.1.5
  * deps: qs@2.3.3
    - Fix `arrayLimit` behavior

4.10.2 / 2014-11-09
===================

  * Correctly invoke async router callback asynchronously
  * deps: accepts@~1.1.3
    - deps: mime-types@~2.0.3
  * deps: type-is@~1.5.3
    - deps: mime-types@~2.0.3

4.10.1 / 2014-10-28
===================

  * Fix handling of URLs containing `://` in the path
  * deps: qs@2.3.2
    - Fix parsing of mixed objects and values

4.10.0 / 2014-10-23
===================

  * Add support for `app.set('views', array)`
    - Views are looked up in sequence in array of directories
  * Fix `res.send(status)` to mention `res.sendStatus(status)`
  * Fix handling of invalid empty URLs
  * Use `content-disposition` module for `res.attachment`/`res.download`
    - Sends standards-compliant `Content-Disposition` header
    - Full Unicode support
  * Use `path.resolve` in view lookup
  * deps: debug@~2.1.0
    - Implement `DEBUG_FD` env variable support
  * deps: depd@~1.0.0
  * deps: etag@~1.5.0
    - Improve string performance
    - Slightly improve speed for weak ETags over 1KB
  * deps: finalhandler@0.3.2
    - Terminate in progress response only on error
    - Use `on-finished` to determine request status
    - deps: debug@~2.1.0
    - deps: on-finished@~2.1.1
  * deps: on-finished@~2.1.1
    - Fix handling of pipelined requests
  * deps: qs@2.3.0
    - Fix parsing of mixed implicit and explicit arrays
  * deps: send@0.10.1
    - deps: debug@~2.1.0
    - deps: depd@~1.0.0
    - deps: etag@~1.5.0
    - deps: on-finished@~2.1.1
  * deps: serve-static@~1.7.1
    - deps: send@0.10.1

4.9.8 / 2014-10-17
==================

  * Fix `res.redirect` body when redirect status specified
  * deps: accepts@~1.1.2
    - Fix error when media type has invalid parameter
    - deps: negotiator@0.4.9

4.9.7 / 2014-10-10
==================

  * Fix using same param name in array of paths

4.9.6 / 2014-10-08
==================

  * deps: accepts@~1.1.1
    - deps: mime-types@~2.0.2
    - deps: negotiator@0.4.8
  * deps: serve-static@~1.6.4
    - Fix redirect loop when index file serving disabled
  * deps: type-is@~1.5.2
    - deps: mime-types@~2.0.2

4.9.5 / 2014-09-24
==================

  * deps: etag@~1.4.0
  * deps: proxy-addr@~1.0.3
    - Use `forwarded` npm module
  * deps: send@0.9.3
    - deps: etag@~1.4.0
  * deps: serve-static@~1.6.3
    - deps: send@0.9.3

4.9.4 / 2014-09-19
==================

  * deps: qs@2.2.4
    - Fix issue with object keys starting with numbers truncated

4.9.3 / 2014-09-18
==================

  * deps: proxy-addr@~1.0.2
    - Fix a global leak when multiple subnets are trusted
    - deps: ipaddr.js@0.1.3

4.9.2 / 2014-09-17
==================

  * Fix regression for empty string `path` in `app.use`
  * Fix `router.use` to accept array of middleware without path
  * Improve error message for bad `app.use` arguments

4.9.1 / 2014-09-16
==================

  * Fix `app.use` to accept array of middleware without path
  * deps: depd@0.4.5
  * deps: etag@~1.3.1
  * deps: send@0.9.2
    - deps: depd@0.4.5
    - deps: etag@~1.3.1
    - deps: range-parser@~1.0.2
  * deps: serve-static@~1.6.2
    - deps: send@0.9.2

4.9.0 / 2014-09-08
==================

  * Add `res.sendStatus`
  * Invoke callback for sendfile when client aborts
    - Applies to `res.sendFile`, `res.sendfile`, and `res.download`
    - `err` will be populated with request aborted error
  * Support IP address host in `req.subdomains`
  * Use `etag` to generate `ETag` headers
  * deps: accepts@~1.1.0
    - update `mime-types`
  * deps: cookie-signature@1.0.5
  * deps: debug@~2.0.0
  * deps: finalhandler@0.2.0
    - Set `X-Content-Type-Options: nosniff` header
    - deps: debug@~2.0.0
  * deps: fresh@0.2.4
  * deps: media-typer@0.3.0
    - Throw error when parameter format invalid on parse
  * deps: qs@2.2.3
    - Fix issue where first empty value in array is discarded
  * deps: range-parser@~1.0.2
  * deps: send@0.9.1
    - Add `lastModified` option
    - Use `etag` to generate `ETag` header
    - deps: debug@~2.0.0
    - deps: fresh@0.2.4
  * deps: serve-static@~1.6.1
    - Add `lastModified` option
    - deps: send@0.9.1
  * deps: type-is@~1.5.1
    - fix `hasbody` to be true for `content-length: 0`
    - deps: media-typer@0.3.0
    - deps: mime-types@~2.0.1
  * deps: vary@~1.0.0
    - Accept valid `Vary` header string as `field`

4.8.8 / 2014-09-04
==================

  * deps: send@0.8.5
    - Fix a path traversal issue when using `root`
    - Fix malicious path detection for empty string path
  * deps: serve-static@~1.5.4
    - deps: send@0.8.5

4.8.7 / 2014-08-29
==================

  * deps: qs@2.2.2
    - Remove unnecessary cloning

4.8.6 / 2014-08-27
==================

  * deps: qs@2.2.0
    - Array parsing fix
    - Performance improvements

4.8.5 / 2014-08-18
==================

  * deps: send@0.8.3
    - deps: destroy@1.0.3
    - deps: on-finished@2.1.0
  * deps: serve-static@~1.5.3
    - deps: send@0.8.3

4.8.4 / 2014-08-14
==================

  * deps: qs@1.2.2
  * deps: send@0.8.2
    - Work around `fd` leak in Node.js 0.10 for `fs.ReadStream`
  * deps: serve-static@~1.5.2
    - deps: send@0.8.2

4.8.3 / 2014-08-10
==================

  * deps: parseurl@~1.3.0
  * deps: qs@1.2.1
  * deps: serve-static@~1.5.1
    - Fix parsing of weird `req.originalUrl` values
    - deps: parseurl@~1.3.0
    - deps: utils-merge@1.0.0

4.8.2 / 2014-08-07
==================

  * deps: qs@1.2.0
    - Fix parsing array of objects

4.8.1 / 2014-08-06
==================

  * fix incorrect deprecation warnings on `res.download`
  * deps: qs@1.1.0
    - Accept urlencoded square brackets
    - Accept empty values in implicit array notation

4.8.0 / 2014-08-05
==================

  * add `res.sendFile`
    - accepts a file system path instead of a URL
    - requires an absolute path or `root` option specified
  * deprecate `res.sendfile` -- use `res.sendFile` instead
  * support mounted app as any argument to `app.use()`
  * deps: qs@1.0.2
    - Complete rewrite
    - Limits array length to 20
    - Limits object depth to 5
    - Limits parameters to 1,000
  * deps: send@0.8.1
    - Add `extensions` option
  * deps: serve-static@~1.5.0
    - Add `extensions` option
    - deps: send@0.8.1

4.7.4 / 2014-08-04
==================

  * fix `res.sendfile` regression for serving directory index files
  * deps: send@0.7.4
    - Fix incorrect 403 on Windows and Node.js 0.11
    - Fix serving index files without root dir
  * deps: serve-static@~1.4.4
    - deps: send@0.7.4

4.7.3 / 2014-08-04
==================

  * deps: send@0.7.3
    - Fix incorrect 403 on Windows and Node.js 0.11
  * deps: serve-static@~1.4.3
    - Fix incorrect 403 on Windows and Node.js 0.11
    - deps: send@0.7.3

4.7.2 / 2014-07-27
==================

  * deps: depd@0.4.4
    - Work-around v8 generating empty stack traces
  * deps: send@0.7.2
    - deps: depd@0.4.4
  * deps: serve-static@~1.4.2

4.7.1 / 2014-07-26
==================

  * deps: depd@0.4.3
    - Fix exception when global `Error.stackTraceLimit` is too low
  * deps: send@0.7.1
    - deps: depd@0.4.3
  * deps: serve-static@~1.4.1

4.7.0 / 2014-07-25
==================

  * fix `req.protocol` for proxy-direct connections
  * configurable query parser with `app.set('query parser', parser)`
    - `app.set('query parser', 'extended')` parse with "qs" module
    - `app.set('query parser', 'simple')` parse with "querystring" core module
    - `app.set('query parser', false)` disable query string parsing
    - `app.set('query parser', true)` enable simple parsing
  * deprecate `res.json(status, obj)` -- use `res.status(status).json(obj)` instead
  * deprecate `res.jsonp(status, obj)` -- use `res.status(status).jsonp(obj)` instead
  * deprecate `res.send(status, body)` -- use `res.status(status).send(body)` instead
  * deps: debug@1.0.4
  * deps: depd@0.4.2
    - Add `TRACE_DEPRECATION` environment variable
    - Remove non-standard grey color from color output
    - Support `--no-deprecation` argument
    - Support `--trace-deprecation` argument
  * deps: finalhandler@0.1.0
    - Respond after request fully read
    - deps: debug@1.0.4
  * deps: parseurl@~1.2.0
    - Cache URLs based on original value
    - Remove no-longer-needed URL mis-parse work-around
    - Simplify the "fast-path" `RegExp`
  * deps: send@0.7.0
    - Add `dotfiles` option
    - Cap `maxAge` value to 1 year
    - deps: debug@1.0.4
    - deps: depd@0.4.2
  * deps: serve-static@~1.4.0
    - deps: parseurl@~1.2.0
    - deps: send@0.7.0
  * perf: prevent multiple `Buffer` creation in `res.send`

4.6.1 / 2014-07-12
==================

  * fix `subapp.mountpath` regression for `app.use(subapp)`

4.6.0 / 2014-07-11
==================

  * accept multiple callbacks to `app.use()`
  * add explicit "Rosetta Flash JSONP abuse" protection
    - previous versions are not vulnerable; this is just explicit protection
  * catch errors in multiple `req.param(name, fn)` handlers
  * deprecate `res.redirect(url, status)` -- use `res.redirect(status, url)` instead
  * fix `res.send(status, num)` to send `num` as json (not error)
  * remove unnecessary escaping when `res.jsonp` returns JSON response
  * support non-string `path` in `app.use(path, fn)`
    - supports array of paths
    - supports `RegExp`
  * router: fix optimization on router exit
  * router: refactor location of `try` blocks
  * router: speed up standard `app.use(fn)`
  * deps: debug@1.0.3
    - Add support for multiple wildcards in namespaces
  * deps: finalhandler@0.0.3
    - deps: debug@1.0.3
  * deps: methods@1.1.0
    - add `CONNECT`
  * deps: parseurl@~1.1.3
    - faster parsing of href-only URLs
  * deps: path-to-regexp@0.1.3
  * deps: send@0.6.0
    - deps: debug@1.0.3
  * deps: serve-static@~1.3.2
    - deps: parseurl@~1.1.3
    - deps: send@0.6.0
  * perf: fix arguments reassign deopt in some `res` methods

4.5.1 / 2014-07-06
==================

 * fix routing regression when altering `req.method`

4.5.0 / 2014-07-04
==================

 * add deprecation message to non-plural `req.accepts*`
 * add deprecation message to `res.send(body, status)`
 * add deprecation message to `res.vary()`
 * add `headers` option to `res.sendfile`
   - use to set headers on successful file transfer
 * add `mergeParams` option to `Router`
   - merges `req.params` from parent routes
 * add `req.hostname` -- correct name for what `req.host` returns
 * deprecate things with `depd` module
 * deprecate `req.host` -- use `req.hostname` instead
 * fix behavior when handling request without routes
 * fix handling when `route.all` is only route
 * invoke `router.param()` only when route matches
 * restore `req.params` after invoking router
 * use `finalhandler` for final response handling
 * use `media-typer` to alter content-type charset
 * deps: accepts@~1.0.7
 * deps: send@0.5.0
   - Accept string for `maxage` (converted by `ms`)
   - Include link in default redirect response
 * deps: serve-static@~1.3.0
   - Accept string for `maxAge` (converted by `ms`)
   - Add `setHeaders` option
   - Include HTML link in redirect response
   - deps: send@0.5.0
 * deps: type-is@~1.3.2

4.4.5 / 2014-06-26
==================

 * deps: cookie-signature@1.0.4
   - fix for timing attacks

4.4.4 / 2014-06-20
==================

 * fix `res.attachment` Unicode filenames in Safari
 * fix "trim prefix" debug message in `express:router`
 * deps: accepts@~1.0.5
 * deps: buffer-crc32@0.2.3

4.4.3 / 2014-06-11
==================

 * fix persistence of modified `req.params[name]` from `app.param()`
 * deps: accepts@1.0.3
   - deps: negotiator@0.4.6
 * deps: debug@1.0.2
 * deps: send@0.4.3
   - Do not throw uncatchable error on file open race condition
   - Use `escape-html` for HTML escaping
   - deps: debug@1.0.2
   - deps: finished@1.2.2
   - deps: fresh@0.2.2
 * deps: serve-static@1.2.3
   - Do not throw uncatchable error on file open race condition
   - deps: send@0.4.3

4.4.2 / 2014-06-09
==================

 * fix catching errors from top-level handlers
 * use `vary` module for `res.vary`
 * deps: debug@1.0.1
 * deps: proxy-addr@1.0.1
 * deps: send@0.4.2
   - fix "event emitter leak" warnings
   - deps: debug@1.0.1
   - deps: finished@1.2.1
 * deps: serve-static@1.2.2
   - fix "event emitter leak" warnings
   - deps: send@0.4.2
 * deps: type-is@1.2.1

4.4.1 / 2014-06-02
==================

 * deps: methods@1.0.1
 * deps: send@0.4.1
   - Send `max-age` in `Cache-Control` in correct format
 * deps: serve-static@1.2.1
   - use `escape-html` for escaping
   - deps: send@0.4.1

4.4.0 / 2014-05-30
==================

 * custom etag control with `app.set('etag', val)`
   - `app.set('etag', function(body, encoding){ return '"etag"' })` custom etag generation
   - `app.set('etag', 'weak')` weak tag
   - `app.set('etag', 'strong')` strong etag
   - `app.set('etag', false)` turn off
   - `app.set('etag', true)` standard etag
 * mark `res.send` ETag as weak and reduce collisions
 * update accepts to 1.0.2
   - Fix interpretation when header not in request
 * update send to 0.4.0
   - Calculate ETag with md5 for reduced collisions
   - Ignore stream errors after request ends
   - deps: debug@0.8.1
 * update serve-static to 1.2.0
   - Calculate ETag with md5 for reduced collisions
   - Ignore stream errors after request ends
   - deps: send@0.4.0

4.3.2 / 2014-05-28
==================

 * fix handling of errors from `router.param()` callbacks

4.3.1 / 2014-05-23
==================

 * revert "fix behavior of multiple `app.VERB` for the same path"
   - this caused a regression in the order of route execution

4.3.0 / 2014-05-21
==================

 * add `req.baseUrl` to access the path stripped from `req.url` in routes
 * fix behavior of multiple `app.VERB` for the same path
 * fix issue routing requests among sub routers
 * invoke `router.param()` only when necessary instead of every match
 * proper proxy trust with `app.set('trust proxy', trust)`
   - `app.set('trust proxy', 1)` trust first hop
   - `app.set('trust proxy', 'loopback')` trust loopback addresses
   - `app.set('trust proxy', '10.0.0.1')` trust single IP
   - `app.set('trust proxy', '10.0.0.1/16')` trust subnet
   - `app.set('trust proxy', '10.0.0.1, 10.0.0.2')` trust list
   - `app.set('trust proxy', false)` turn off
   - `app.set('trust proxy', true)` trust everything
 * set proper `charset` in `Content-Type` for `res.send`
 * update type-is to 1.2.0
   - support suffix matching

4.2.0 / 2014-05-11
==================

 * deprecate `app.del()` -- use `app.delete()` instead
 * deprecate `res.json(obj, status)` -- use `res.json(status, obj)` instead
   - the edge-case `res.json(status, num)` requires `res.status(status).json(num)`
 * deprecate `res.jsonp(obj, status)` -- use `res.jsonp(status, obj)` instead
   - the edge-case `res.jsonp(status, num)` requires `res.status(status).jsonp(num)`
 * fix `req.next` when inside router instance
 * include `ETag` header in `HEAD` requests
 * keep previous `Content-Type` for `res.jsonp`
 * support PURGE method
   - add `app.purge`
   - add `router.purge`
   - include PURGE in `app.all`
 * update debug to 0.8.0
   - add `enable()` method
   - change from stderr to stdout
 * update methods to 1.0.0
   - add PURGE

4.1.2 / 2014-05-08
==================

 * fix `req.host` for IPv6 literals
 * fix `res.jsonp` error if callback param is object

4.1.1 / 2014-04-27
==================

 * fix package.json to reflect supported node version

4.1.0 / 2014-04-24
==================

 * pass options from `res.sendfile` to `send`
 * preserve casing of headers in `res.header` and `res.set`
 * support unicode file names in `res.attachment` and `res.download`
 * update accepts to 1.0.1
   - deps: negotiator@0.4.0
 * update cookie to 0.1.2
   - Fix for maxAge == 0
   - made compat with expires field
 * update send to 0.3.0
   - Accept API options in options object
   - Coerce option types
   - Control whether to generate etags
   - Default directory access to 403 when index disabled
   - Fix sending files with dots without root set
   - Include file path in etag
   - Make "Can't set headers after they are sent." catchable
   - Send full entity-body for multi range requests
   - Set etags to "weak"
   - Support "If-Range" header
   - Support multiple index paths
   - deps: mime@1.2.11
 * update serve-static to 1.1.0
   - Accept options directly to `send` module
   - Resolve relative paths at middleware setup
   - Use parseurl to parse the URL from request
   - deps: send@0.3.0
 * update type-is to 1.1.0
   - add non-array values support
   - add `multipart` as a shorthand

4.0.0 / 2014-04-09
==================

 * remove:
   - node 0.8 support
   - connect and connect's patches except for charset handling
   - express(1) - moved to [express-generator](https://github.com/expressjs/generator)
   - `express.createServer()` - it has been deprecated for a long time. Use `express()`
   - `app.configure` - use logic in your own app code
   - `app.router` - is removed
   - `req.auth` - use `basic-auth` instead
   - `req.accepted*` - use `req.accepts*()` instead
   - `res.location` - relative URL resolution is removed
   - `res.charset` - include the charset in the content type when using `res.set()`
   - all bundled middleware except `static`
 * change:
   - `app.route` -> `app.mountpath` when mounting an express app in another express app
   - `json spaces` no longer enabled by default in development
   - `req.accepts*` -> `req.accepts*s` - i.e. `req.acceptsEncoding` -> `req.acceptsEncodings`
   - `req.params` is now an object instead of an array
   - `res.locals` is no longer a function. It is a plain js object. Treat it as such.
   - `res.headerSent` -> `res.headersSent` to match node.js ServerResponse object
 * refactor:
   - `req.accepts*` with [accepts](https://github.com/expressjs/accepts)
   - `req.is` with [type-is](https://github.com/expressjs/type-is)
   - [path-to-regexp](https://github.com/component/path-to-regexp)
 * add:
   - `app.router()` - returns the app Router instance
   - `app.route()` - Proxy to the app's `Router#route()` method to create a new route
   - Router & Route - public API

3.21.2 / 2015-07-31
===================

  * deps: connect@2.30.2
    - deps: body-parser@~1.13.3
    - deps: compression@~1.5.2
    - deps: errorhandler@~1.4.2
    - deps: method-override@~2.3.5
    - deps: serve-index@~1.7.2
    - deps: type-is@~1.6.6
    - deps: vhost@~3.0.1
  * deps: vary@~1.0.1
    - Fix setting empty header from empty `field`
    - perf: enable strict mode
    - perf: remove argument reassignments

3.21.1 / 2015-07-05
===================

  * deps: basic-auth@~1.0.3
  * deps: connect@2.30.1
    - deps: body-parser@~1.13.2
    - deps: compression@~1.5.1
    - deps: errorhandler@~1.4.1
    - deps: morgan@~1.6.1
    - deps: pause@0.1.0
    - deps: qs@4.0.0
    - deps: serve-index@~1.7.1
    - deps: type-is@~1.6.4

3.21.0 / 2015-06-18
===================

  * deps: basic-auth@1.0.2
    - perf: enable strict mode
    - perf: hoist regular expression
    - perf: parse with regular expressions
    - perf: remove argument reassignment
  * deps: connect@2.30.0
    - deps: body-parser@~1.13.1
    - deps: bytes@2.1.0
    - deps: compression@~1.5.0
    - deps: cookie@0.1.3
    - deps: cookie-parser@~1.3.5
    - deps: csurf@~1.8.3
    - deps: errorhandler@~1.4.0
    - deps: express-session@~1.11.3
    - deps: finalhandler@0.4.0
    - deps: fresh@0.3.0
    - deps: morgan@~1.6.0
    - deps: serve-favicon@~2.3.0
    - deps: serve-index@~1.7.0
    - deps: serve-static@~1.10.0
    - deps: type-is@~1.6.3
  * deps: cookie@0.1.3
    - perf: deduce the scope of try-catch deopt
    - perf: remove argument reassignments
  * deps: escape-html@1.0.2
  * deps: etag@~1.7.0
    - Always include entity length in ETags for hash length extensions
    - Generate non-Stats ETags using MD5 only (no longer CRC32)
    - Improve stat performance by removing hashing
    - Improve support for JXcore
    - Remove base64 padding in ETags to shorten
    - Support "fake" stats objects in environments without fs
    - Use MD5 instead of MD4 in weak ETags over 1KB
  * deps: fresh@0.3.0
    - Add weak `ETag` matching support
  * deps: mkdirp@0.5.1
    - Work in global strict mode
  * deps: send@0.13.0
    - Allow Node.js HTTP server to set `Date` response header
    - Fix incorrectly removing `Content-Location` on 304 response
    - Improve the default redirect response headers
    - Send appropriate headers on default error response
    - Use `http-errors` for standard emitted errors
    - Use `statuses` instead of `http` module for status messages
    - deps: escape-html@1.0.2
    - deps: etag@~1.7.0
    - deps: fresh@0.3.0
    - deps: on-finished@~2.3.0
    - perf: enable strict mode
    - perf: remove unnecessary array allocations

3.20.3 / 2015-05-17
===================

  * deps: connect@2.29.2
    - deps: body-parser@~1.12.4
    - deps: compression@~1.4.4
    - deps: connect-timeout@~1.6.2
    - deps: debug@~2.2.0
    - deps: depd@~1.0.1
    - deps: errorhandler@~1.3.6
    - deps: finalhandler@0.3.6
    - deps: method-override@~2.3.3
    - deps: morgan@~1.5.3
    - deps: qs@2.4.2
    - deps: response-time@~2.3.1
    - deps: serve-favicon@~2.2.1
    - deps: serve-index@~1.6.4
    - deps: serve-static@~1.9.3
    - deps: type-is@~1.6.2
  * deps: debug@~2.2.0
    - deps: ms@0.7.1
  * deps: depd@~1.0.1
  * deps: proxy-addr@~1.0.8
    - deps: ipaddr.js@1.0.1
  * deps: send@0.12.3
    - deps: debug@~2.2.0
    - deps: depd@~1.0.1
    - deps: etag@~1.6.0
    - deps: ms@0.7.1
    - deps: on-finished@~2.2.1

3.20.2 / 2015-03-16
===================

  * deps: connect@2.29.1
    - deps: body-parser@~1.12.2
    - deps: compression@~1.4.3
    - deps: connect-timeout@~1.6.1
    - deps: debug@~2.1.3
    - deps: errorhandler@~1.3.5
    - deps: express-session@~1.10.4
    - deps: finalhandler@0.3.4
    - deps: method-override@~2.3.2
    - deps: morgan@~1.5.2
    - deps: qs@2.4.1
    - deps: serve-index@~1.6.3
    - deps: serve-static@~1.9.2
    - deps: type-is@~1.6.1
  * deps: debug@~2.1.3
    - Fix high intensity foreground color for bold
    - deps: ms@0.7.0
  * deps: merge-descriptors@1.0.0
  * deps: proxy-addr@~1.0.7
    - deps: ipaddr.js@0.1.9
  * deps: send@0.12.2
    - Throw errors early for invalid `extensions` or `index` options
    - deps: debug@~2.1.3

3.20.1 / 2015-02-28
===================

  * Fix `req.host` when using "trust proxy" hops count
  * Fix `req.protocol`/`req.secure` when using "trust proxy" hops count

3.20.0 / 2015-02-18
===================

  * Fix `"trust proxy"` setting to inherit when app is mounted
  * Generate `ETag`s for all request responses
    - No longer restricted to only responses for `GET` and `HEAD` requests
  * Use `content-type` to parse `Content-Type` headers
  * deps: connect@2.29.0
    - Use `content-type` to parse `Content-Type` headers
    - deps: body-parser@~1.12.0
    - deps: compression@~1.4.1
    - deps: connect-timeout@~1.6.0
    - deps: cookie-parser@~1.3.4
    - deps: cookie-signature@1.0.6
    - deps: csurf@~1.7.0
    - deps: errorhandler@~1.3.4
    - deps: express-session@~1.10.3
    - deps: http-errors@~1.3.1
    - deps: response-time@~2.3.0
    - deps: serve-index@~1.6.2
    - deps: serve-static@~1.9.1
    - deps: type-is@~1.6.0
  * deps: cookie-signature@1.0.6
  * deps: send@0.12.1
    - Always read the stat size from the file
    - Fix mutating passed-in `options`
    - deps: mime@1.3.4

3.19.2 / 2015-02-01
===================

  * deps: connect@2.28.3
    - deps: compression@~1.3.1
    - deps: csurf@~1.6.6
    - deps: errorhandler@~1.3.3
    - deps: express-session@~1.10.2
    - deps: serve-index@~1.6.1
    - deps: type-is@~1.5.6
  * deps: proxy-addr@~1.0.6
    - deps: ipaddr.js@0.1.8

3.19.1 / 2015-01-20
===================

  * deps: connect@2.28.2
    - deps: body-parser@~1.10.2
    - deps: serve-static@~1.8.1
  * deps: send@0.11.1
    - Fix root path disclosure

3.19.0 / 2015-01-09
===================

  * Fix `OPTIONS` responses to include the `HEAD` method property
  * Use `readline` for prompt in `express(1)`
  * deps: commander@2.6.0
  * deps: connect@2.28.1
    - deps: body-parser@~1.10.1
    - deps: compression@~1.3.0
    - deps: connect-timeout@~1.5.0
    - deps: csurf@~1.6.4
    - deps: debug@~2.1.1
    - deps: errorhandler@~1.3.2
    - deps: express-session@~1.10.1
    - deps: finalhandler@0.3.3
    - deps: method-override@~2.3.1
    - deps: morgan@~1.5.1
    - deps: serve-favicon@~2.2.0
    - deps: serve-index@~1.6.0
    - deps: serve-static@~1.8.0
    - deps: type-is@~1.5.5
  * deps: debug@~2.1.1
  * deps: methods@~1.1.1
  * deps: proxy-addr@~1.0.5
    - deps: ipaddr.js@0.1.6
  * deps: send@0.11.0
    - deps: debug@~2.1.1
    - deps: etag@~1.5.1
    - deps: ms@0.7.0
    - deps: on-finished@~2.2.0

3.18.6 / 2014-12-12
===================

  * Fix exception in `req.fresh`/`req.stale` without response headers

3.18.5 / 2014-12-11
===================

  * deps: connect@2.27.6
    - deps: compression@~1.2.2
    - deps: express-session@~1.9.3
    - deps: http-errors@~1.2.8
    - deps: serve-index@~1.5.3
    - deps: type-is@~1.5.4

3.18.4 / 2014-11-23
===================

  * deps: connect@2.27.4
    - deps: body-parser@~1.9.3
    - deps: compression@~1.2.1
    - deps: errorhandler@~1.2.3
    - deps: express-session@~1.9.2
    - deps: qs@2.3.3
    - deps: serve-favicon@~2.1.7
    - deps: serve-static@~1.5.1
    - deps: type-is@~1.5.3
  * deps: etag@~1.5.1
  * deps: proxy-addr@~1.0.4
    - deps: ipaddr.js@0.1.5

3.18.3 / 2014-11-09
===================

  * deps: connect@2.27.3
    - Correctly invoke async callback asynchronously
    - deps: csurf@~1.6.3

3.18.2 / 2014-10-28
===================

  * deps: connect@2.27.2
    - Fix handling of URLs containing `://` in the path
    - deps: body-parser@~1.9.2
    - deps: qs@2.3.2

3.18.1 / 2014-10-22
===================

  * Fix internal `utils.merge` deprecation warnings
  * deps: connect@2.27.1
    - deps: body-parser@~1.9.1
    - deps: express-session@~1.9.1
    - deps: finalhandler@0.3.2
    - deps: morgan@~1.4.1
    - deps: qs@2.3.0
    - deps: serve-static@~1.7.1
  * deps: send@0.10.1
    - deps: on-finished@~2.1.1

3.18.0 / 2014-10-17
===================

  * Use `content-disposition` module for `res.attachment`/`res.download`
    - Sends standards-compliant `Content-Disposition` header
    - Full Unicode support
  * Use `etag` module to generate `ETag` headers
  * deps: connect@2.27.0
    - Use `http-errors` module for creating errors
    - Use `utils-merge` module for merging objects
    - deps: body-parser@~1.9.0
    - deps: compression@~1.2.0
    - deps: connect-timeout@~1.4.0
    - deps: debug@~2.1.0
    - deps: depd@~1.0.0
    - deps: express-session@~1.9.0
    - deps: finalhandler@0.3.1
    - deps: method-override@~2.3.0
    - deps: morgan@~1.4.0
    - deps: response-time@~2.2.0
    - deps: serve-favicon@~2.1.6
    - deps: serve-index@~1.5.0
    - deps: serve-static@~1.7.0
  * deps: debug@~2.1.0
    - Implement `DEBUG_FD` env variable support
  * deps: depd@~1.0.0
  * deps: send@0.10.0
    - deps: debug@~2.1.0
    - deps: depd@~1.0.0
    - deps: etag@~1.5.0

3.17.8 / 2014-10-15
===================

  * deps: connect@2.26.6
    - deps: compression@~1.1.2
    - deps: csurf@~1.6.2
    - deps: errorhandler@~1.2.2

3.17.7 / 2014-10-08
===================

  * deps: connect@2.26.5
    - Fix accepting non-object arguments to `logger`
    - deps: serve-static@~1.6.4

3.17.6 / 2014-10-02
===================

  * deps: connect@2.26.4
    - deps: morgan@~1.3.2
    - deps: type-is@~1.5.2

3.17.5 / 2014-09-24
===================

  * deps: connect@2.26.3
    - deps: body-parser@~1.8.4
    - deps: serve-favicon@~2.1.5
    - deps: serve-static@~1.6.3
  * deps: proxy-addr@~1.0.3
    - Use `forwarded` npm module
  * deps: send@0.9.3
    - deps: etag@~1.4.0

3.17.4 / 2014-09-19
===================

  * deps: connect@2.26.2
    - deps: body-parser@~1.8.3
    - deps: qs@2.2.4

3.17.3 / 2014-09-18
===================

  * deps: proxy-addr@~1.0.2
    - Fix a global leak when multiple subnets are trusted
    - deps: ipaddr.js@0.1.3

3.17.2 / 2014-09-15
===================

  * Use `crc` instead of `buffer-crc32` for speed
  * deps: connect@2.26.1
    - deps: body-parser@~1.8.2
    - deps: depd@0.4.5
    - deps: express-session@~1.8.2
    - deps: morgan@~1.3.1
    - deps: serve-favicon@~2.1.3
    - deps: serve-static@~1.6.2
  * deps: depd@0.4.5
  * deps: send@0.9.2
    - deps: depd@0.4.5
    - deps: etag@~1.3.1
    - deps: range-parser@~1.0.2

3.17.1 / 2014-09-08
===================

  * Fix error in `req.subdomains` on empty host

3.17.0 / 2014-09-08
===================

  * Support `X-Forwarded-Host` in `req.subdomains`
  * Support IP address host in `req.subdomains`
  * deps: connect@2.26.0
    - deps: body-parser@~1.8.1
    - deps: compression@~1.1.0
    - deps: connect-timeout@~1.3.0
    - deps: cookie-parser@~1.3.3
    - deps: cookie-signature@1.0.5
    - deps: csurf@~1.6.1
    - deps: debug@~2.0.0
    - deps: errorhandler@~1.2.0
    - deps: express-session@~1.8.1
    - deps: finalhandler@0.2.0
    - deps: fresh@0.2.4
    - deps: media-typer@0.3.0
    - deps: method-override@~2.2.0
    - deps: morgan@~1.3.0
    - deps: qs@2.2.3
    - deps: serve-favicon@~2.1.3
    - deps: serve-index@~1.2.1
    - deps: serve-static@~1.6.1
    - deps: type-is@~1.5.1
    - deps: vhost@~3.0.0
  * deps: cookie-signature@1.0.5
  * deps: debug@~2.0.0
  * deps: fresh@0.2.4
  * deps: media-typer@0.3.0
    - Throw error when parameter format invalid on parse
  * deps: range-parser@~1.0.2
  * deps: send@0.9.1
    - Add `lastModified` option
    - Use `etag` to generate `ETag` header
    - deps: debug@~2.0.0
    - deps: fresh@0.2.4
  * deps: vary@~1.0.0
    - Accept valid `Vary` header string as `field`

3.16.10 / 2014-09-04
====================

  * deps: connect@2.25.10
    - deps: serve-static@~1.5.4
  * deps: send@0.8.5
    - Fix a path traversal issue when using `root`
    - Fix malicious path detection for empty string path

3.16.9 / 2014-08-29
===================

  * deps: connect@2.25.9
    - deps: body-parser@~1.6.7
    - deps: qs@2.2.2

3.16.8 / 2014-08-27
===================

  * deps: connect@2.25.8
    - deps: body-parser@~1.6.6
    - deps: csurf@~1.4.1
    - deps: qs@2.2.0

3.16.7 / 2014-08-18
===================

  * deps: connect@2.25.7
    - deps: body-parser@~1.6.5
    - deps: express-session@~1.7.6
    - deps: morgan@~1.2.3
    - deps: serve-static@~1.5.3
  * deps: send@0.8.3
    - deps: destroy@1.0.3
    - deps: on-finished@2.1.0

3.16.6 / 2014-08-14
===================

  * deps: connect@2.25.6
    - deps: body-parser@~1.6.4
    - deps: qs@1.2.2
    - deps: serve-static@~1.5.2
  * deps: send@0.8.2
    - Work around `fd` leak in Node.js 0.10 for `fs.ReadStream`

3.16.5 / 2014-08-11
===================

  * deps: connect@2.25.5
    - Fix backwards compatibility in `logger`

3.16.4 / 2014-08-10
===================

  * Fix original URL parsing in `res.location`
  * deps: connect@2.25.4
    - Fix `query` middleware breaking with argument
    - deps: body-parser@~1.6.3
    - deps: compression@~1.0.11
    - deps: connect-timeout@~1.2.2
    - deps: express-session@~1.7.5
    - deps: method-override@~2.1.3
    - deps: on-headers@~1.0.0
    - deps: parseurl@~1.3.0
    - deps: qs@1.2.1
    - deps: response-time@~2.0.1
    - deps: serve-index@~1.1.6
    - deps: serve-static@~1.5.1
  * deps: parseurl@~1.3.0

3.16.3 / 2014-08-07
===================

  * deps: connect@2.25.3
    - deps: multiparty@3.3.2

3.16.2 / 2014-08-07
===================

  * deps: connect@2.25.2
    - deps: body-parser@~1.6.2
    - deps: qs@1.2.0

3.16.1 / 2014-08-06
===================

  * deps: connect@2.25.1
    - deps: body-parser@~1.6.1
    - deps: qs@1.1.0

3.16.0 / 2014-08-05
===================

  * deps: connect@2.25.0
    - deps: body-parser@~1.6.0
    - deps: compression@~1.0.10
    - deps: csurf@~1.4.0
    - deps: express-session@~1.7.4
    - deps: qs@1.0.2
    - deps: serve-static@~1.5.0
  * deps: send@0.8.1
    - Add `extensions` option

3.15.3 / 2014-08-04
===================

  * fix `res.sendfile` regression for serving directory index files
  * deps: connect@2.24.3
    - deps: serve-index@~1.1.5
    - deps: serve-static@~1.4.4
  * deps: send@0.7.4
    - Fix incorrect 403 on Windows and Node.js 0.11
    - Fix serving index files without root dir

3.15.2 / 2014-07-27
===================

  * deps: connect@2.24.2
    - deps: body-parser@~1.5.2
    - deps: depd@0.4.4
    - deps: express-session@~1.7.2
    - deps: morgan@~1.2.2
    - deps: serve-static@~1.4.2
  * deps: depd@0.4.4
    - Work-around v8 generating empty stack traces
  * deps: send@0.7.2
    - deps: depd@0.4.4

3.15.1 / 2014-07-26
===================

  * deps: connect@2.24.1
    - deps: body-parser@~1.5.1
    - deps: depd@0.4.3
    - deps: express-session@~1.7.1
    - deps: morgan@~1.2.1
    - deps: serve-index@~1.1.4
    - deps: serve-static@~1.4.1
  * deps: depd@0.4.3
    - Fix exception when global `Error.stackTraceLimit` is too low
  * deps: send@0.7.1
    - deps: depd@0.4.3

3.15.0 / 2014-07-22
===================

  * Fix `req.protocol` for proxy-direct connections
  * Pass options from `res.sendfile` to `send`
  * deps: connect@2.24.0
    - deps: body-parser@~1.5.0
    - deps: compression@~1.0.9
    - deps: connect-timeout@~1.2.1
    - deps: debug@1.0.4
    - deps: depd@0.4.2
    - deps: express-session@~1.7.0
    - deps: finalhandler@0.1.0
    - deps: method-override@~2.1.2
    - deps: morgan@~1.2.0
    - deps: multiparty@3.3.1
    - deps: parseurl@~1.2.0
    - deps: serve-static@~1.4.0
  * deps: debug@1.0.4
  * deps: depd@0.4.2
    - Add `TRACE_DEPRECATION` environment variable
    - Remove non-standard grey color from color output
    - Support `--no-deprecation` argument
    - Support `--trace-deprecation` argument
  * deps: parseurl@~1.2.0
    - Cache URLs based on original value
    - Remove no-longer-needed URL mis-parse work-around
    - Simplify the "fast-path" `RegExp`
  * deps: send@0.7.0
    - Add `dotfiles` option
    - Cap `maxAge` value to 1 year
    - deps: debug@1.0.4
    - deps: depd@0.4.2

3.14.0 / 2014-07-11
===================

 * add explicit "Rosetta Flash JSONP abuse" protection
   - previous versions are not vulnerable; this is just explicit protection
 * deprecate `res.redirect(url, status)` -- use `res.redirect(status, url)` instead
 * fix `res.send(status, num)` to send `num` as json (not error)
 * remove unnecessary escaping when `res.jsonp` returns JSON response
 * deps: basic-auth@1.0.0
   - support empty password
   - support empty username
 * deps: connect@2.23.0
   - deps: debug@1.0.3
   - deps: express-session@~1.6.4
   - deps: method-override@~2.1.0
   - deps: parseurl@~1.1.3
   - deps: serve-static@~1.3.1
  * deps: debug@1.0.3
    - Add support for multiple wildcards in namespaces
  * deps: methods@1.1.0
    - add `CONNECT`
  * deps: parseurl@~1.1.3
    - faster parsing of href-only URLs

3.13.0 / 2014-07-03
===================

 * add deprecation message to `app.configure`
 * add deprecation message to `req.auth`
 * use `basic-auth` to parse `Authorization` header
 * deps: connect@2.22.0
   - deps: csurf@~1.3.0
   - deps: express-session@~1.6.1
   - deps: multiparty@3.3.0
   - deps: serve-static@~1.3.0
 * deps: send@0.5.0
   - Accept string for `maxage` (converted by `ms`)
   - Include link in default redirect response

3.12.1 / 2014-06-26
===================

 * deps: connect@2.21.1
   - deps: cookie-parser@1.3.2
   - deps: cookie-signature@1.0.4
   - deps: express-session@~1.5.2
   - deps: type-is@~1.3.2
 * deps: cookie-signature@1.0.4
   - fix for timing attacks

3.12.0 / 2014-06-21
===================

 * use `media-typer` to alter content-type charset
 * deps: connect@2.21.0
   - deprecate `connect(middleware)` -- use `app.use(middleware)` instead
   - deprecate `connect.createServer()` -- use `connect()` instead
   - fix `res.setHeader()` patch to work with get -> append -> set pattern
   - deps: compression@~1.0.8
   - deps: errorhandler@~1.1.1
   - deps: express-session@~1.5.0
   - deps: serve-index@~1.1.3

3.11.0 / 2014-06-19
===================

 * deprecate things with `depd` module
 * deps: buffer-crc32@0.2.3
 * deps: connect@2.20.2
   - deprecate `verify` option to `json` -- use `body-parser` npm module instead
   - deprecate `verify` option to `urlencoded` -- use `body-parser` npm module instead
   - deprecate things with `depd` module
   - use `finalhandler` for final response handling
   - use `media-typer` to parse `content-type` for charset
   - deps: body-parser@1.4.3
   - deps: connect-timeout@1.1.1
   - deps: cookie-parser@1.3.1
   - deps: csurf@1.2.2
   - deps: errorhandler@1.1.0
   - deps: express-session@1.4.0
   - deps: multiparty@3.2.9
   - deps: serve-index@1.1.2
   - deps: type-is@1.3.1
   - deps: vhost@2.0.0

3.10.5 / 2014-06-11
===================

 * deps: connect@2.19.6
   - deps: body-parser@1.3.1
   - deps: compression@1.0.7
   - deps: debug@1.0.2
   - deps: serve-index@1.1.1
   - deps: serve-static@1.2.3
 * deps: debug@1.0.2
 * deps: send@0.4.3
   - Do not throw uncatchable error on file open race condition
   - Use `escape-html` for HTML escaping
   - deps: debug@1.0.2
   - deps: finished@1.2.2
   - deps: fresh@0.2.2

3.10.4 / 2014-06-09
===================

 * deps: connect@2.19.5
   - fix "event emitter leak" warnings
   - deps: csurf@1.2.1
   - deps: debug@1.0.1
   - deps: serve-static@1.2.2
   - deps: type-is@1.2.1
 * deps: debug@1.0.1
 * deps: send@0.4.2
   - fix "event emitter leak" warnings
   - deps: finished@1.2.1
   - deps: debug@1.0.1

3.10.3 / 2014-06-05
===================

 * use `vary` module for `res.vary`
 * deps: connect@2.19.4
   - deps: errorhandler@1.0.2
   - deps: method-override@2.0.2
   - deps: serve-favicon@2.0.1
 * deps: debug@1.0.0

3.10.2 / 2014-06-03
===================

 * deps: connect@2.19.3
   - deps: compression@1.0.6

3.10.1 / 2014-06-03
===================

 * deps: connect@2.19.2
   - deps: compression@1.0.4
 * deps: proxy-addr@1.0.1

3.10.0 / 2014-06-02
===================

 * deps: connect@2.19.1
   - deprecate `methodOverride()` -- use `method-override` npm module instead
   - deps: body-parser@1.3.0
   - deps: method-override@2.0.1
   - deps: multiparty@3.2.8
   - deps: response-time@2.0.0
   - deps: serve-static@1.2.1
 * deps: methods@1.0.1
 * deps: send@0.4.1
   - Send `max-age` in `Cache-Control` in correct format

3.9.0 / 2014-05-30
==================

 * custom etag control with `app.set('etag', val)`
   - `app.set('etag', function(body, encoding){ return '"etag"' })` custom etag generation
   - `app.set('etag', 'weak')` weak tag
   - `app.set('etag', 'strong')` strong etag
   - `app.set('etag', false)` turn off
   - `app.set('etag', true)` standard etag
 * Include ETag in HEAD requests
 * mark `res.send` ETag as weak and reduce collisions
 * update connect to 2.18.0
   - deps: compression@1.0.3
   - deps: serve-index@1.1.0
   - deps: serve-static@1.2.0
 * update send to 0.4.0
   - Calculate ETag with md5 for reduced collisions
   - Ignore stream errors after request ends
   - deps: debug@0.8.1

3.8.1 / 2014-05-27
==================

 * update connect to 2.17.3
   - deps: body-parser@1.2.2
   - deps: express-session@1.2.1
   - deps: method-override@1.0.2

3.8.0 / 2014-05-21
==================

 * keep previous `Content-Type` for `res.jsonp`
 * set proper `charset` in `Content-Type` for `res.send`
 * update connect to 2.17.1
   - fix `res.charset` appending charset when `content-type` has one
   - deps: express-session@1.2.0
   - deps: morgan@1.1.1
   - deps: serve-index@1.0.3

3.7.0 / 2014-05-18
==================

 * proper proxy trust with `app.set('trust proxy', trust)`
   - `app.set('trust proxy', 1)` trust first hop
   - `app.set('trust proxy', 'loopback')` trust loopback addresses
   - `app.set('trust proxy', '10.0.0.1')` trust single IP
   - `app.set('trust proxy', '10.0.0.1/16')` trust subnet
   - `app.set('trust proxy', '10.0.0.1, 10.0.0.2')` trust list
   - `app.set('trust proxy', false)` turn off
   - `app.set('trust proxy', true)` trust everything
 * update connect to 2.16.2
   - deprecate `res.headerSent` -- use `res.headersSent`
   - deprecate `res.on("header")` -- use on-headers module instead
   - fix edge-case in `res.appendHeader` that would append in wrong order
   - json: use body-parser
   - urlencoded: use body-parser
   - dep: bytes@1.0.0
   - dep: cookie-parser@1.1.0
   - dep: csurf@1.2.0
   - dep: express-session@1.1.0
   - dep: method-override@1.0.1

3.6.0 / 2014-05-09
==================

 * deprecate `app.del()` -- use `app.delete()` instead
 * deprecate `res.json(obj, status)` -- use `res.json(status, obj)` instead
   - the edge-case `res.json(status, num)` requires `res.status(status).json(num)`
 * deprecate `res.jsonp(obj, status)` -- use `res.jsonp(status, obj)` instead
   - the edge-case `res.jsonp(status, num)` requires `res.status(status).jsonp(num)`
 * support PURGE method
   - add `app.purge`
   - add `router.purge`
   - include PURGE in `app.all`
 * update connect to 2.15.0
   * Add `res.appendHeader`
   * Call error stack even when response has been sent
   * Patch `res.headerSent` to return Boolean
   * Patch `res.headersSent` for node.js 0.8
   * Prevent default 404 handler after response sent
   * dep: compression@1.0.2
   * dep: connect-timeout@1.1.0
   * dep: debug@^0.8.0
   * dep: errorhandler@1.0.1
   * dep: express-session@1.0.4
   * dep: morgan@1.0.1
   * dep: serve-favicon@2.0.0
   * dep: serve-index@1.0.2
 * update debug to 0.8.0
   * add `enable()` method
   * change from stderr to stdout
 * update methods to 1.0.0
   - add PURGE
 * update mkdirp to 0.5.0

3.5.3 / 2014-05-08
==================

 * fix `req.host` for IPv6 literals
 * fix `res.jsonp` error if callback param is object

3.5.2 / 2014-04-24
==================

 * update connect to 2.14.5
 * update cookie to 0.1.2
 * update mkdirp to 0.4.0
 * update send to 0.3.0

3.5.1 / 2014-03-25
==================

 * pin less-middleware in generated app

3.5.0 / 2014-03-06
==================

 * bump deps

3.4.8 / 2014-01-13
==================

 * prevent incorrect automatic OPTIONS responses #1868 @dpatti
 * update binary and examples for jade 1.0 #1876 @yossi, #1877 @reqshark, #1892 @matheusazzi
 * throw 400 in case of malformed paths @rlidwka

3.4.7 / 2013-12-10
==================

 * update connect

3.4.6 / 2013-12-01
==================

 * update connect (raw-body)

3.4.5 / 2013-11-27
==================

 * update connect
 * res.location: remove leading ./ #1802 @kapouer
 * res.redirect: fix `res.redirect('toString') #1829 @michaelficarra
 * res.send: always send ETag when content-length > 0
 * router: add Router.all() method

3.4.4 / 2013-10-29
==================

 * update connect
 * update supertest
 * update methods
 * express(1): replace bodyParser() with urlencoded() and json() #1795 @chirag04

3.4.3 / 2013-10-23
==================

 * update connect

3.4.2 / 2013-10-18
==================

 * update connect
 * downgrade commander

3.4.1 / 2013-10-15
==================

 * update connect
 * update commander
 * jsonp: check if callback is a function
 * router: wrap encodeURIComponent in a try/catch #1735 (@lxe)
 * res.format: now includes charset @1747 (@sorribas)
 * res.links: allow multiple calls @1746 (@sorribas)

3.4.0 / 2013-09-07
==================

 * add res.vary(). Closes #1682
 * update connect

3.3.8 / 2013-09-02
==================

 * update connect

3.3.7 / 2013-08-28
==================

 * update connect

3.3.6 / 2013-08-27
==================

 * Revert "remove charset from json responses. Closes #1631" (causes issues in some clients)
 * add: req.accepts take an argument list

3.3.4 / 2013-07-08
==================

 * update send and connect

3.3.3 / 2013-07-04
==================

 * update connect

3.3.2 / 2013-07-03
==================

 * update connect
 * update send
 * remove .version export

3.3.1 / 2013-06-27
==================

 * update connect

3.3.0 / 2013-06-26
==================

 * update connect
 * add support for multiple X-Forwarded-Proto values. Closes #1646
 * change: remove charset from json responses. Closes #1631
 * change: return actual booleans from req.accept* functions
 * fix jsonp callback array throw

3.2.6 / 2013-06-02
==================

 * update connect

3.2.5 / 2013-05-21
==================

 * update connect
 * update node-cookie
 * add: throw a meaningful error when there is no default engine
 * change generation of ETags with res.send() to GET requests only. Closes #1619

3.2.4 / 2013-05-09
==================

  * fix `req.subdomains` when no Host is present
  * fix `req.host` when no Host is present, return undefined

3.2.3 / 2013-05-07
==================

  * update connect / qs

3.2.2 / 2013-05-03
==================

  * update qs

3.2.1 / 2013-04-29
==================

  * add app.VERB() paths array deprecation warning
  * update connect
  * update qs and remove all ~ semver crap
  * fix: accept number as value of Signed Cookie

3.2.0 / 2013-04-15
==================

  * add "view" constructor setting to override view behaviour
  * add req.acceptsEncoding(name)
  * add req.acceptedEncodings
  * revert cookie signature change causing session race conditions
  * fix sorting of Accept values of the same quality

3.1.2 / 2013-04-12
==================

  * add support for custom Accept parameters
  * update cookie-signature

3.1.1 / 2013-04-01
==================

  * add X-Forwarded-Host support to `req.host`
  * fix relative redirects
  * update mkdirp
  * update buffer-crc32
  * remove legacy app.configure() method from app template.

3.1.0 / 2013-01-25
==================

  * add support for leading "." in "view engine" setting
  * add array support to `res.set()`
  * add node 0.8.x to travis.yml
  * add "subdomain offset" setting for tweaking `req.subdomains`
  * add `res.location(url)` implementing `res.redirect()`-like setting of Location
  * use app.get() for x-powered-by setting for inheritance
  * fix colons in passwords for `req.auth`

3.0.6 / 2013-01-04
==================

  * add http verb methods to Router
  * update connect
  * fix mangling of the `res.cookie()` options object
  * fix jsonp whitespace escape. Closes #1132

3.0.5 / 2012-12-19
==================

  * add throwing when a non-function is passed to a route
  * fix: explicitly remove Transfer-Encoding header from 204 and 304 responses
  * revert "add 'etag' option"

3.0.4 / 2012-12-05
==================

  * add 'etag' option to disable `res.send()` Etags
  * add escaping of urls in text/plain in `res.redirect()`
    for old browsers interpreting as html
  * change crc32 module for a more liberal license
  * update connect

3.0.3 / 2012-11-13
==================

  * update connect
  * update cookie module
  * fix cookie max-age

3.0.2 / 2012-11-08
==================

  * add OPTIONS to cors example. Closes #1398
  * fix route chaining regression. Closes #1397

3.0.1 / 2012-11-01
==================

  * update connect

3.0.0 / 2012-10-23
==================

  * add `make clean`
  * add "Basic" check to req.auth
  * add `req.auth` test coverage
  * add cb && cb(payload) to `res.jsonp()`. Closes #1374
  * add backwards compat for `res.redirect()` status. Closes #1336
  * add support for `res.json()` to retain previously defined Content-Types. Closes #1349
  * update connect
  * change `res.redirect()` to utilize a pathname-relative Location again. Closes #1382
  * remove non-primitive string support for `res.send()`
  * fix view-locals example. Closes #1370
  * fix route-separation example

3.0.0rc5 / 2012-09-18
==================

  * update connect
  * add redis search example
  * add static-files example
  * add "x-powered-by" setting (`app.disable('x-powered-by')`)
  * add "application/octet-stream" redirect Accept test case. Closes #1317

3.0.0rc4 / 2012-08-30
==================

  * add `res.jsonp()`. Closes #1307
  * add "verbose errors" option to error-pages example
  * add another route example to express(1) so people are not so confused
  * add redis online user activity tracking example
  * update connect dep
  * fix etag quoting. Closes #1310
  * fix error-pages 404 status
  * fix jsonp callback char restrictions
  * remove old OPTIONS default response

3.0.0rc3 / 2012-08-13
==================

  * update connect dep
  * fix signed cookies to work with `connect.cookieParser()` ("s:" prefix was missing) [tnydwrds]
  * fix `res.render()` clobbering of "locals"

3.0.0rc2 / 2012-08-03
==================

  * add CORS example
  * update connect dep
  * deprecate `.createServer()` & remove old stale examples
  * fix: escape `res.redirect()` link
  * fix vhost example

3.0.0rc1 / 2012-07-24
==================

  * add more examples to view-locals
  * add scheme-relative redirects (`res.redirect("//foo.com")`) support
  * update cookie dep
  * update connect dep
  * update send dep
  * fix `express(1)` -h flag, use -H for hogan. Closes #1245
  * fix `res.sendfile()` socket error handling regression

3.0.0beta7 / 2012-07-16
==================

  * update connect dep for `send()` root normalization regression

3.0.0beta6 / 2012-07-13
==================

  * add `err.view` property for view errors. Closes #1226
  * add "jsonp callback name" setting
  * add support for "/foo/:bar*" non-greedy matches
  * change `res.sendfile()` to use `send()` module
  * change `res.send` to use "response-send" module
  * remove `app.locals.use` and `res.locals.use`, use regular middleware

3.0.0beta5 / 2012-07-03
==================

  * add "make check" support
  * add route-map example
  * add `res.json(obj, status)` support back for BC
  * add "methods" dep, remove internal methods module
  * update connect dep
  * update auth example to utilize cores pbkdf2
  * updated tests to use "supertest"

3.0.0beta4 / 2012-06-25
==================

  * Added `req.auth`
  * Added `req.range(size)`
  * Added `res.links(obj)`
  * Added `res.send(body, status)` support back for backwards compat
  * Added `.default()` support to `res.format()`
  * Added 2xx / 304 check to `req.fresh`
  * Revert "Added + support to the router"
  * Fixed `res.send()` freshness check, respect res.statusCode

3.0.0beta3 / 2012-06-15
==================

  * Added hogan `--hjs` to express(1) [nullfirm]
  * Added another example to content-negotiation
  * Added `fresh` dep
  * Changed: `res.send()` always checks freshness
  * Fixed: expose connects mime module. Closes #1165

3.0.0beta2 / 2012-06-06
==================

  * Added `+` support to the router
  * Added `req.host`
  * Changed `req.param()` to check route first
  * Update connect dep

3.0.0beta1 / 2012-06-01
==================

  * Added `res.format()` callback to override default 406 behaviour
  * Fixed `res.redirect()` 406. Closes #1154

3.0.0alpha5 / 2012-05-30
==================

  * Added `req.ip`
  * Added `{ signed: true }` option to `res.cookie()`
  * Removed `res.signedCookie()`
  * Changed: dont reverse `req.ips`
  * Fixed "trust proxy" setting check for `req.ips`

3.0.0alpha4 / 2012-05-09
==================

  * Added: allow `[]` in jsonp callback. Closes #1128
  * Added `PORT` env var support in generated template. Closes #1118 [benatkin]
  * Updated: connect 2.2.2

3.0.0alpha3 / 2012-05-04
==================

  * Added public `app.routes`. Closes #887
  * Added _view-locals_ example
  * Added _mvc_ example
  * Added `res.locals.use()`. Closes #1120
  * Added conditional-GET support to `res.send()`
  * Added: coerce `res.set()` values to strings
  * Changed: moved `static()` in generated apps below router
  * Changed: `res.send()` only set ETag when not previously set
  * Changed connect 2.2.1 dep
  * Changed: `make test` now runs unit / acceptance tests
  * Fixed req/res proto inheritance

3.0.0alpha2 / 2012-04-26
==================

  * Added `make benchmark` back
  * Added `res.send()` support for `String` objects
  * Added client-side data exposing example
  * Added `res.header()` and `req.header()` aliases for BC
  * Added `express.createServer()` for BC
  * Perf: memoize parsed urls
  * Perf: connect 2.2.0 dep
  * Changed: make `expressInit()` middleware self-aware
  * Fixed: use app.get() for all core settings
  * Fixed redis session example
  * Fixed session example. Closes #1105
  * Fixed generated express dep. Closes #1078

3.0.0alpha1 / 2012-04-15
==================

  * Added `app.locals.use(callback)`
  * Added `app.locals` object
  * Added `app.locals(obj)`
  * Added `res.locals` object
  * Added `res.locals(obj)`
  * Added `res.format()` for content-negotiation
  * Added `app.engine()`
  * Added `res.cookie()` JSON cookie support
  * Added "trust proxy" setting
  * Added `req.subdomains`
  * Added `req.protocol`
  * Added `req.secure`
  * Added `req.path`
  * Added `req.ips`
  * Added `req.fresh`
  * Added `req.stale`
  * Added comma-delimited / array support for `req.accepts()`
  * Added debug instrumentation
  * Added `res.set(obj)`
  * Added `res.set(field, value)`
  * Added `res.get(field)`
  * Added `app.get(setting)`. Closes #842
  * Added `req.acceptsLanguage()`
  * Added `req.acceptsCharset()`
  * Added `req.accepted`
  * Added `req.acceptedLanguages`
  * Added `req.acceptedCharsets`
  * Added "json replacer" setting
  * Added "json spaces" setting
  * Added X-Forwarded-Proto support to `res.redirect()`. Closes #92
  * Added `--less` support to express(1)
  * Added `express.response` prototype
  * Added `express.request` prototype
  * Added `express.application` prototype
  * Added `app.path()`
  * Added `app.render()`
  * Added `res.type()` to replace `res.contentType()`
  * Changed: `res.redirect()` to add relative support
  * Changed: enable "jsonp callback" by default
  * Changed: renamed "case sensitive routes" to "case sensitive routing"
  * Rewrite of all tests with mocha
  * Removed "root" setting
  * Removed `res.redirect('home')` support
  * Removed `req.notify()`
  * Removed `app.register()`
  * Removed `app.redirect()`
  * Removed `app.is()`
  * Removed `app.helpers()`
  * Removed `app.dynamicHelpers()`
  * Fixed `res.sendfile()` with non-GET. Closes #723
  * Fixed express(1) public dir for windows. Closes #866

2.5.9/ 2012-04-02
==================

  * Added support for PURGE request method [pbuyle]
  * Fixed `express(1)` generated app `app.address()` before `listening` [mmalecki]

2.5.8 / 2012-02-08
==================

  * Update mkdirp dep. Closes #991

2.5.7 / 2012-02-06
==================

  * Fixed `app.all` duplicate DELETE requests [mscdex]

2.5.6 / 2012-01-13
==================

  * Updated hamljs dev dep. Closes #953

2.5.5 / 2012-01-08
==================

  * Fixed: set `filename` on cached templates [matthewleon]

2.5.4 / 2012-01-02
==================

  * Fixed `express(1)` eol on 0.4.x. Closes #947

2.5.3 / 2011-12-30
==================

  * Fixed `req.is()` when a charset is present

2.5.2 / 2011-12-10
==================

  * Fixed: express(1) LF -> CRLF for windows

2.5.1 / 2011-11-17
==================

  * Changed: updated connect to 1.8.x
  * Removed sass.js support from express(1)

2.5.0 / 2011-10-24
==================

  * Added ./routes dir for generated app by default
  * Added npm install reminder to express(1) app gen
  * Added 0.5.x support
  * Removed `make test-cov` since it wont work with node 0.5.x
  * Fixed express(1) public dir for windows. Closes #866

2.4.7 / 2011-10-05
==================

  * Added mkdirp to express(1). Closes #795
  * Added simple _json-config_ example
  * Added  shorthand for the parsed request's pathname via `req.path`
  * Changed connect dep to 1.7.x to fix npm issue...
  * Fixed `res.redirect()` __HEAD__ support. [reported by xerox]
  * Fixed `req.flash()`, only escape args
  * Fixed absolute path checking on windows. Closes #829 [reported by andrewpmckenzie]

2.4.6 / 2011-08-22
==================

  * Fixed multiple param callback regression. Closes #824 [reported by TroyGoode]

2.4.5 / 2011-08-19
==================

  * Added support for routes to handle errors. Closes #809
  * Added `app.routes.all()`. Closes #803
  * Added "basepath" setting to work in conjunction with reverse proxies etc.
  * Refactored `Route` to use a single array of callbacks
  * Added support for multiple callbacks for `app.param()`. Closes #801
Closes #805
  * Changed: removed .call(self) for route callbacks
  * Dependency: `qs >= 0.3.1`
  * Fixed `res.redirect()` on windows due to `join()` usage. Closes #808

2.4.4 / 2011-08-05
==================

  * Fixed `res.header()` intention of a set, even when `undefined`
  * Fixed `*`, value no longer required
  * Fixed `res.send(204)` support. Closes #771

2.4.3 / 2011-07-14
==================

  * Added docs for `status` option special-case. Closes #739
  * Fixed `options.filename`, exposing the view path to template engines

2.4.2. / 2011-07-06
==================

  * Revert "removed jsonp stripping" for XSS

2.4.1 / 2011-07-06
==================

  * Added `res.json()` JSONP support. Closes #737
  * Added _extending-templates_ example. Closes #730
  * Added "strict routing" setting for trailing slashes
  * Added support for multiple envs in `app.configure()` calls. Closes #735
  * Changed: `res.send()` using `res.json()`
  * Changed: when cookie `path === null` don't default it
  * Changed; default cookie path to "home" setting. Closes #731
  * Removed _pids/logs_ creation from express(1)

2.4.0 / 2011-06-28
==================

  * Added chainable `res.status(code)`
  * Added `res.json()`, an explicit version of `res.send(obj)`
  * Added simple web-service example

2.3.12 / 2011-06-22
==================

  * \#express is now on freenode! come join!
  * Added `req.get(field, param)`
  * Added links to Japanese documentation, thanks @hideyukisaito!
  * Added; the `express(1)` generated app outputs the env
  * Added `content-negotiation` example
  * Dependency: connect >= 1.5.1 < 2.0.0
  * Fixed view layout bug. Closes #720
  * Fixed; ignore body on 304. Closes #701

2.3.11 / 2011-06-04
==================

  * Added `npm test`
  * Removed generation of dummy test file from `express(1)`
  * Fixed; `express(1)` adds express as a dep
  * Fixed; prune on `prepublish`

2.3.10 / 2011-05-27
==================

  * Added `req.route`, exposing the current route
  * Added _package.json_ generation support to `express(1)`
  * Fixed call to `app.param()` function for optional params. Closes #682

2.3.9 / 2011-05-25
==================

  * Fixed bug-ish with `../' in `res.partial()` calls

2.3.8 / 2011-05-24
==================

  * Fixed `app.options()`

2.3.7 / 2011-05-23
==================

  * Added route `Collection`, ex: `app.get('/user/:id').remove();`
  * Added support for `app.param(fn)` to define param logic
  * Removed `app.param()` support for callback with return value
  * Removed module.parent check from express(1) generated app. Closes #670
  * Refactored router. Closes #639

2.3.6 / 2011-05-20
==================

  * Changed; using devDependencies instead of git submodules
  * Fixed redis session example
  * Fixed markdown example
  * Fixed view caching, should not be enabled in development

2.3.5 / 2011-05-20
==================

  * Added export `.view` as alias for `.View`

2.3.4 / 2011-05-08
==================

  * Added `./examples/say`
  * Fixed `res.sendfile()` bug preventing the transfer of files with spaces

2.3.3 / 2011-05-03
==================

  * Added "case sensitive routes" option.
  * Changed; split methods supported per rfc [slaskis]
  * Fixed route-specific middleware when using the same callback function several times

2.3.2 / 2011-04-27
==================

  * Fixed view hints

2.3.1 / 2011-04-26
==================

  * Added `app.match()` as `app.match.all()`
  * Added `app.lookup()` as `app.lookup.all()`
  * Added `app.remove()` for `app.remove.all()`
  * Added `app.remove.VERB()`
  * Fixed template caching collision issue. Closes #644
  * Moved router over from connect and started refactor

2.3.0 / 2011-04-25
==================

  * Added options support to `res.clearCookie()`
  * Added `res.helpers()` as alias of `res.locals()`
  * Added; json defaults to UTF-8 with `res.send()`. Closes #632. [Daniel   * Dependency `connect >= 1.4.0`
  * Changed; auto set Content-Type in res.attachement [Aaron Heckmann]
  * Renamed "cache views" to "view cache". Closes #628
  * Fixed caching of views when using several apps. Closes #637
  * Fixed gotcha invoking `app.param()` callbacks once per route middleware.
Closes #638
  * Fixed partial lookup precedence. Closes #631
Shaw]

2.2.2 / 2011-04-12
==================

  * Added second callback support for `res.download()` connection errors
  * Fixed `filename` option passing to template engine

2.2.1 / 2011-04-04
==================

  * Added `layout(path)` helper to change the layout within a view. Closes #610
  * Fixed `partial()` collection object support.
    Previously only anything with `.length` would work.
    When `.length` is present one must still be aware of holes,
    however now `{ collection: {foo: 'bar'}}` is valid, exposes
    `keyInCollection` and `keysInCollection`.

  * Performance improved with better view caching
  * Removed `request` and `response` locals
  * Changed; errorHandler page title is now `Express` instead of `Connect`

2.2.0 / 2011-03-30
==================

  * Added `app.lookup.VERB()`, ex `app.lookup.put('/user/:id')`. Closes #606
  * Added `app.match.VERB()`, ex `app.match.put('/user/12')`. Closes #606
  * Added `app.VERB(path)` as alias of `app.lookup.VERB()`.
  * Dependency `connect >= 1.2.0`

2.1.1 / 2011-03-29
==================

  * Added; expose `err.view` object when failing to locate a view
  * Fixed `res.partial()` call `next(err)` when no callback is given [reported by aheckmann]
  * Fixed; `res.send(undefined)` responds with 204 [aheckmann]

2.1.0 / 2011-03-24
==================

  * Added `<root>/_?<name>` partial lookup support. Closes #447
  * Added `request`, `response`, and `app` local variables
  * Added `settings` local variable, containing the app's settings
  * Added `req.flash()` exception if `req.session` is not available
  * Added `res.send(bool)` support (json response)
  * Fixed stylus example for latest version
  * Fixed; wrap try/catch around `res.render()`

2.0.0 / 2011-03-17
==================

  * Fixed up index view path alternative.
  * Changed; `res.locals()` without object returns the locals

2.0.0rc3 / 2011-03-17
==================

  * Added `res.locals(obj)` to compliment `res.local(key, val)`
  * Added `res.partial()` callback support
  * Fixed recursive error reporting issue in `res.render()`

2.0.0rc2 / 2011-03-17
==================

  * Changed; `partial()` "locals" are now optional
  * Fixed `SlowBuffer` support. Closes #584 [reported by tyrda01]
  * Fixed .filename view engine option [reported by drudge]
  * Fixed blog example
  * Fixed `{req,res}.app` reference when mounting [Ben Weaver]

2.0.0rc / 2011-03-14
==================

  * Fixed; expose `HTTPSServer` constructor
  * Fixed express(1) default test charset. Closes #579 [reported by secoif]
  * Fixed; default charset to utf-8 instead of utf8 for lame IE [reported by NickP]

2.0.0beta3 / 2011-03-09
==================

  * Added support for `res.contentType()` literal
    The original `res.contentType('.json')`,
    `res.contentType('application/json')`, and `res.contentType('json')`
    will work now.
  * Added `res.render()` status option support back
  * Added charset option for `res.render()`
  * Added `.charset` support (via connect 1.0.4)
  * Added view resolution hints when in development and a lookup fails
  * Added layout lookup support relative to the page view.
    For example while rendering `./views/user/index.jade` if you create
    `./views/user/layout.jade` it will be used in favour of the root layout.
  * Fixed `res.redirect()`. RFC states absolute url [reported by unlink]
  * Fixed; default `res.send()` string charset to utf8
  * Removed `Partial` constructor (not currently used)

2.0.0beta2 / 2011-03-07
==================

  * Added res.render() `.locals` support back to aid in migration process
  * Fixed flash example

2.0.0beta / 2011-03-03
==================

  * Added HTTPS support
  * Added `res.cookie()` maxAge support
  * Added `req.header()` _Referrer_ / _Referer_ special-case, either works
  * Added mount support for `res.redirect()`, now respects the mount-point
  * Added `union()` util, taking place of `merge(clone())` combo
  * Added stylus support to express(1) generated app
  * Added secret to session middleware used in examples and generated app
  * Added `res.local(name, val)` for progressive view locals
  * Added default param support to `req.param(name, default)`
  * Added `app.disabled()` and `app.enabled()`
  * Added `app.register()` support for omitting leading ".", either works
  * Added `res.partial()`, using the same interface as `partial()` within a view. Closes #539
  * Added `app.param()` to map route params to async/sync logic
  * Added; aliased `app.helpers()` as `app.locals()`. Closes #481
  * Added extname with no leading "." support to `res.contentType()`
  * Added `cache views` setting, defaulting to enabled in "production" env
  * Added index file partial resolution, eg: partial('user') may try _views/user/index.jade_.
  * Added `req.accepts()` support for extensions
  * Changed; `res.download()` and `res.sendfile()` now utilize Connect's
    static file server `connect.static.send()`.
  * Changed; replaced `connect.utils.mime()` with npm _mime_ module
  * Changed; allow `req.query` to be pre-defined (via middleware or other parent
  * Changed view partial resolution, now relative to parent view
  * Changed view engine signature. no longer `engine.render(str, options, callback)`, now `engine.compile(str, options) -> Function`, the returned function accepts `fn(locals)`.
  * Fixed `req.param()` bug returning Array.prototype methods. Closes #552
  * Fixed; using `Stream#pipe()` instead of `sys.pump()` in `res.sendfile()`
  * Fixed; using _qs_ module instead of _querystring_
  * Fixed; strip unsafe chars from jsonp callbacks
  * Removed "stream threshold" setting

1.0.8 / 2011-03-01
==================

  * Allow `req.query` to be pre-defined (via middleware or other parent app)
  * "connect": ">= 0.5.0 < 1.0.0". Closes #547
  * Removed the long deprecated __EXPRESS_ENV__ support

1.0.7 / 2011-02-07
==================

  * Fixed `render()` setting inheritance.
    Mounted apps would not inherit "view engine"

1.0.6 / 2011-02-07
==================

  * Fixed `view engine` setting bug when period is in dirname

1.0.5 / 2011-02-05
==================

  * Added secret to generated app `session()` call

1.0.4 / 2011-02-05
==================

  * Added `qs` dependency to _package.json_
  * Fixed namespaced `require()`s for latest connect support

1.0.3 / 2011-01-13
==================

  * Remove unsafe characters from JSONP callback names [Ryan Grove]

1.0.2 / 2011-01-10
==================

  * Removed nested require, using `connect.router`

1.0.1 / 2010-12-29
==================

  * Fixed for middleware stacked via `createServer()`
    previously the `foo` middleware passed to `createServer(foo)`
    would not have access to Express methods such as `res.send()`
    or props like `req.query` etc.

1.0.0 / 2010-11-16
==================

  * Added; deduce partial object names from the last segment.
    For example by default `partial('forum/post', postObject)` will
    give you the _post_ object, providing a meaningful default.
  * Added http status code string representation to `res.redirect()` body
  * Added; `res.redirect()` supporting _text/plain_ and _text/html_ via __Accept__.
  * Added `req.is()` to aid in content negotiation
  * Added partial local inheritance [suggested by masylum]. Closes #102
    providing access to parent template locals.
  * Added _-s, --session[s]_ flag to express(1) to add session related middleware
  * Added _--template_ flag to express(1) to specify the
    template engine to use.
  * Added _--css_ flag to express(1) to specify the
    stylesheet engine to use (or just plain css by default).
  * Added `app.all()` support [thanks aheckmann]
  * Added partial direct object support.
    You may now `partial('user', user)` providing the "user" local,
    vs previously `partial('user', { object: user })`.
  * Added _route-separation_ example since many people question ways
    to do this with CommonJS modules. Also view the _blog_ example for
    an alternative.
  * Performance; caching view path derived partial object names
  * Fixed partial local inheritance precedence. [reported by Nick Poulden] Closes #454
  * Fixed jsonp support; _text/javascript_ as per mailinglist discussion

1.0.0rc4 / 2010-10-14
==================

  * Added _NODE_ENV_ support, _EXPRESS_ENV_ is deprecated and will be removed in 1.0.0
  * Added route-middleware support (very helpful, see the [docs](http://expressjs.com/guide.html#Route-Middleware))
  * Added _jsonp callback_ setting to enable/disable jsonp autowrapping [Dav Glass]
  * Added callback query check on response.send to autowrap JSON objects for simple webservice implementations [Dav Glass]
  * Added `partial()` support for array-like collections. Closes #434
  * Added support for swappable querystring parsers
  * Added session usage docs. Closes #443
  * Added dynamic helper caching. Closes #439 [suggested by maritz]
  * Added authentication example
  * Added basic Range support to `res.sendfile()` (and `res.download()` etc)
  * Changed; `express(1)` generated app using 2 spaces instead of 4
  * Default env to "development" again [aheckmann]
  * Removed _context_ option is no more, use "scope"
  * Fixed; exposing _./support_ libs to examples so they can run without installs
  * Fixed mvc example

1.0.0rc3 / 2010-09-20
==================

  * Added confirmation for `express(1)` app generation. Closes #391
  * Added extending of flash formatters via `app.flashFormatters`
  * Added flash formatter support. Closes #411
  * Added streaming support to `res.sendfile()` using `sys.pump()` when >= "stream threshold"
  * Added _stream threshold_ setting for `res.sendfile()`
  * Added `res.send()` __HEAD__ support
  * Added `res.clearCookie()`
  * Added `res.cookie()`
  * Added `res.render()` headers option
  * Added `res.redirect()` response bodies
  * Added `res.render()` status option support. Closes #425 [thanks aheckmann]
  * Fixed `res.sendfile()` responding with 403 on malicious path
  * Fixed `res.download()` bug; when an error occurs remove _Content-Disposition_
  * Fixed; mounted apps settings now inherit from parent app [aheckmann]
  * Fixed; stripping Content-Length / Content-Type when 204
  * Fixed `res.send()` 204. Closes #419
  * Fixed multiple _Set-Cookie_ headers via `res.header()`. Closes #402
  * Fixed bug messing with error handlers when `listenFD()` is called instead of `listen()`. [thanks guillermo]


1.0.0rc2 / 2010-08-17
==================

  * Added `app.register()` for template engine mapping. Closes #390
  * Added `res.render()` callback support as second argument (no options)
  * Added callback support to `res.download()`
  * Added callback support for `res.sendfile()`
  * Added support for middleware access via `express.middlewareName()` vs `connect.middlewareName()`
  * Added "partials" setting to docs
  * Added default expresso tests to `express(1)` generated app. Closes #384
  * Fixed `res.sendfile()` error handling, defer via `next()`
  * Fixed `res.render()` callback when a layout is used [thanks guillermo]
  * Fixed; `make install` creating ~/.node_libraries when not present
  * Fixed issue preventing error handlers from being defined anywhere. Closes #387

1.0.0rc / 2010-07-28
==================

  * Added mounted hook. Closes #369
  * Added connect dependency to _package.json_

  * Removed "reload views" setting and support code
    development env never caches, production always caches.

  * Removed _param_ in route callbacks, signature is now
    simply (req, res, next), previously (req, res, params, next).
    Use _req.params_ for path captures, _req.query_ for GET params.

  * Fixed "home" setting
  * Fixed middleware/router precedence issue. Closes #366
  * Fixed; _configure()_ callbacks called immediately. Closes #368

1.0.0beta2 / 2010-07-23
==================

  * Added more examples
  * Added; exporting `Server` constructor
  * Added `Server#helpers()` for view locals
  * Added `Server#dynamicHelpers()` for dynamic view locals. Closes #349
  * Added support for absolute view paths
  * Added; _home_ setting defaults to `Server#route` for mounted apps. Closes #363
  * Added Guillermo Rauch to the contributor list
  * Added support for "as" for non-collection partials. Closes #341
  * Fixed _install.sh_, ensuring _~/.node_libraries_ exists. Closes #362 [thanks jf]
  * Fixed `res.render()` exceptions, now passed to `next()` when no callback is given [thanks guillermo]
  * Fixed instanceof `Array` checks, now `Array.isArray()`
  * Fixed express(1) expansion of public dirs. Closes #348
  * Fixed middleware precedence. Closes #345
  * Fixed view watcher, now async [thanks aheckmann]

1.0.0beta / 2010-07-15
==================

  * Re-write
    - much faster
    - much lighter
    - Check [ExpressJS.com](http://expressjs.com) for migration guide and updated docs

0.14.0 / 2010-06-15
==================

  * Utilize relative requires
  * Added Static bufferSize option [aheckmann]
  * Fixed caching of view and partial subdirectories [aheckmann]
  * Fixed mime.type() comments now that ".ext" is not supported
  * Updated haml submodule
  * Updated class submodule
  * Removed bin/express

0.13.0 / 2010-06-01
==================

  * Added node v0.1.97 compatibility
  * Added support for deleting cookies via Request#cookie('key', null)
  * Updated haml submodule
  * Fixed not-found page, now using charset utf-8
  * Fixed show-exceptions page, now using charset utf-8
  * Fixed view support due to fs.readFile Buffers
  * Changed; mime.type() no longer accepts ".type" due to node extname() changes

0.12.0 / 2010-05-22
==================

  * Added node v0.1.96 compatibility
  * Added view `helpers` export which act as additional local variables
  * Updated haml submodule
  * Changed ETag; removed inode, modified time only
  * Fixed LF to CRLF for setting multiple cookies
  * Fixed cookie compilation; values are now urlencoded
  * Fixed cookies parsing; accepts quoted values and url escaped cookies

0.11.0 / 2010-05-06
==================

  * Added support for layouts using different engines
    - this.render('page.html.haml', { layout: 'super-cool-layout.html.ejs' })
    - this.render('page.html.haml', { layout: 'foo' }) // assumes 'foo.html.haml'
    - this.render('page.html.haml', { layout: false }) // no layout
  * Updated ext submodule
  * Updated haml submodule
  * Fixed EJS partial support by passing along the context. Issue #307

0.10.1 / 2010-05-03
==================

  * Fixed binary uploads.

0.10.0 / 2010-04-30
==================

  * Added charset support via Request#charset (automatically assigned to 'UTF-8' when respond()'s
    encoding is set to 'utf8' or 'utf-8').
  * Added "encoding" option to Request#render(). Closes #299
  * Added "dump exceptions" setting, which is enabled by default.
  * Added simple ejs template engine support
  * Added error response support for text/plain, application/json. Closes #297
  * Added callback function param to Request#error()
  * Added Request#sendHead()
  * Added Request#stream()
  * Added support for Request#respond(304, null) for empty response bodies
  * Added ETag support to Request#sendfile()
  * Added options to Request#sendfile(), passed to fs.createReadStream()
  * Added filename arg to Request#download()
  * Performance enhanced due to pre-reversing plugins so that plugins.reverse() is not called on each request
  * Performance enhanced by preventing several calls to toLowerCase() in Router#match()
  * Changed; Request#sendfile() now streams
  * Changed; Renamed Request#halt() to Request#respond(). Closes #289
  * Changed; Using sys.inspect() instead of JSON.encode() for error output
  * Changed; run() returns the http.Server instance. Closes #298
  * Changed; Defaulting Server#host to null (INADDR_ANY)
  * Changed; Logger "common" format scale of 0.4f
  * Removed Logger "request" format
  * Fixed; Catching ENOENT in view caching, preventing error when "views/partials" is not found
  * Fixed several issues with http client
  * Fixed Logger Content-Length output
  * Fixed bug preventing Opera from retaining the generated session id. Closes #292

0.9.0 / 2010-04-14
==================

  * Added DSL level error() route support
  * Added DSL level notFound() route support
  * Added Request#error()
  * Added Request#notFound()
  * Added Request#render() callback function. Closes #258
  * Added "max upload size" setting
  * Added "magic" variables to collection partials (\_\_index\_\_, \_\_length\_\_, \_\_isFirst\_\_, \_\_isLast\_\_). Closes #254
  * Added [haml.js](http://github.com/visionmedia/haml.js) submodule; removed haml-js
  * Added callback function support to Request#halt() as 3rd/4th arg
  * Added preprocessing of route param wildcards using param(). Closes #251
  * Added view partial support (with collections etc.)
  * Fixed bug preventing falsey params (such as ?page=0). Closes #286
  * Fixed setting of multiple cookies. Closes #199
  * Changed; view naming convention is now NAME.TYPE.ENGINE (for example page.html.haml)
  * Changed; session cookie is now httpOnly
  * Changed; Request is no longer global
  * Changed; Event is no longer global
  * Changed; "sys" module is no longer global
  * Changed; moved Request#download to Static plugin where it belongs
  * Changed; Request instance created before body parsing. Closes #262
  * Changed; Pre-caching views in memory when "cache view contents" is enabled. Closes #253
  * Changed; Pre-caching view partials in memory when "cache view partials" is enabled
  * Updated support to node --version 0.1.90
  * Updated dependencies
  * Removed set("session cookie") in favour of use(Session, { cookie: { ... }})
  * Removed utils.mixin(); use Object#mergeDeep()

0.8.0 / 2010-03-19
==================

  * Added coffeescript example app. Closes #242
  * Changed; cache api now async friendly. Closes #240
  * Removed deprecated 'express/static' support. Use 'express/plugins/static'

0.7.6 / 2010-03-19
==================

  * Added Request#isXHR. Closes #229
  * Added `make install` (for the executable)
  * Added `express` executable for setting up simple app templates
  * Added "GET /public/*" to Static plugin, defaulting to <root>/public
  * Added Static plugin
  * Fixed; Request#render() only calls cache.get() once
  * Fixed; Namespacing View caches with "view:"
  * Fixed; Namespacing Static caches with "static:"
  * Fixed; Both example apps now use the Static plugin
  * Fixed set("views"). Closes #239
  * Fixed missing space for combined log format
  * Deprecated Request#sendfile() and 'express/static'
  * Removed Server#running

0.7.5 / 2010-03-16
==================

  * Added Request#flash() support without args, now returns all flashes
  * Updated ext submodule

0.7.4 / 2010-03-16
==================

  * Fixed session reaper
  * Changed; class.js replacing js-oo Class implementation (quite a bit faster, no browser cruft)

0.7.3 / 2010-03-16
==================

  * Added package.json
  * Fixed requiring of haml / sass due to kiwi removal

0.7.2 / 2010-03-16
==================

  * Fixed GIT submodules (HAH!)

0.7.1 / 2010-03-16
==================

  * Changed; Express now using submodules again until a PM is adopted
  * Changed; chat example using millisecond conversions from ext

0.7.0 / 2010-03-15
==================

  * Added Request#pass() support (finds the next matching route, or the given path)
  * Added Logger plugin (default "common" format replaces CommonLogger)
  * Removed Profiler plugin
  * Removed CommonLogger plugin

0.6.0 / 2010-03-11
==================

  * Added seed.yml for kiwi package management support
  * Added HTTP client query string support when method is GET. Closes #205

  * Added support for arbitrary view engines.
    For example "foo.engine.html" will now require('engine'),
    the exports from this module are cached after the first require().

  * Added async plugin support

  * Removed usage of RESTful route funcs as http client
    get() etc, use http.get() and friends

  * Removed custom exceptions

0.5.0 / 2010-03-10
==================

  * Added ext dependency (library of js extensions)
  * Removed extname() / basename() utils. Use path module
  * Removed toArray() util. Use arguments.values
  * Removed escapeRegexp() util. Use RegExp.escape()
  * Removed process.mixin() dependency. Use utils.mixin()
  * Removed Collection
  * Removed ElementCollection
  * Shameless self promotion of ebook "Advanced JavaScript" (http://dev-mag.com)  ;)

0.4.0 / 2010-02-11
==================

  * Added flash() example to sample upload app
  * Added high level restful http client module (express/http)
  * Changed; RESTful route functions double as HTTP clients. Closes #69
  * Changed; throwing error when routes are added at runtime
  * Changed; defaulting render() context to the current Request. Closes #197
  * Updated haml submodule

0.3.0 / 2010-02-11
==================

  * Updated haml / sass submodules. Closes #200
  * Added flash message support. Closes #64
  * Added accepts() now allows multiple args. fixes #117
  * Added support for plugins to halt. Closes #189
  * Added alternate layout support. Closes #119
  * Removed Route#run(). Closes #188
  * Fixed broken specs due to use(Cookie) missing

0.2.1 / 2010-02-05
==================

  * Added "plot" format option for Profiler (for gnuplot processing)
  * Added request number to Profiler plugin
  * Fixed binary encoding for multipart file uploads, was previously defaulting to UTF8
  * Fixed issue with routes not firing when not files are present. Closes #184
  * Fixed process.Promise -> events.Promise

0.2.0 / 2010-02-03
==================

  * Added parseParam() support for name[] etc. (allows for file inputs with "multiple" attr) Closes #180
  * Added Both Cache and Session option "reapInterval" may be "reapEvery". Closes #174
  * Added expiration support to cache api with reaper. Closes #133
  * Added cache Store.Memory#reap()
  * Added Cache; cache api now uses first class Cache instances
  * Added abstract session Store. Closes #172
  * Changed; cache Memory.Store#get() utilizing Collection
  * Renamed MemoryStore -> Store.Memory
  * Fixed use() of the same plugin several time will always use latest options. Closes #176

0.1.0 / 2010-02-03
==================

  * Changed; Hooks (before / after) pass request as arg as well as evaluated in their context
  * Updated node support to 0.1.27 Closes #169
  * Updated dirname(__filename) -> __dirname
  * Updated libxmljs support to v0.2.0
  * Added session support with memory store / reaping
  * Added quick uid() helper
  * Added multi-part upload support
  * Added Sass.js support / submodule
  * Added production env caching view contents and static files
  * Added static file caching. Closes #136
  * Added cache plugin with memory stores
  * Added support to StaticFile so that it works with non-textual files.
  * Removed dirname() helper
  * Removed several globals (now their modules must be required)

0.0.2 / 2010-01-10
==================

  * Added view benchmarks; currently haml vs ejs
  * Added Request#attachment() specs. Closes #116
  * Added use of node's parseQuery() util. Closes #123
  * Added `make init` for submodules
  * Updated Haml
  * Updated sample chat app to show messages on load
  * Updated libxmljs parseString -> parseHtmlString
  * Fixed `make init` to work with older versions of git
  * Fixed specs can now run independent specs for those who can't build deps. Closes #127
  * Fixed issues introduced by the node url module changes. Closes 126.
  * Fixed two assertions failing due to Collection#keys() returning strings
  * Fixed faulty Collection#toArray() spec due to keys() returning strings
  * Fixed `make test` now builds libxmljs.node before testing

0.0.1 / 2010-01-03
==================

  * Initial release
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               