text: /*!
   * XRegExp Unicode Base 3.1.0
   * <xregexp.com>
   * Steven Levithan (c) 2008-2016 MIT License
   */
  
  /**
   * Adds base support for Unicode matching:
   * - Adds syntax `\p{..}` for matching Unicode tokens. Tokens can be inverted using `\P{..}` or
   *   `\p{^..}`. Token names ignore case, spaces, hyphens, and underscores. You can omit the braces
   *   for token names that are a single letter (e.g. `\pL` or `PL`).
   * - Adds flag A (astral), which enables 21-bit Unicode support.
   * - Adds the `XRegExp.addUnicodeData` method used by other addons to provide character data.
   *
   * Unicode Base relies on externally provided Unicode character data. Official addons are available
   * to provide data for Unicode categories, scripts, blocks, and properties.
   *
   * @requires XRegExp
   */
  module.exports = function(XRegExp) {
      'use strict';
  
  // Storage for Unicode data
      var unicode = {};
  
  /* ==============================
   * Private functions
   * ============================== */
  
  // Generates a token lookup name: lowercase, with hyphens, spaces, and underscores removed
      function normalize(name) {
          return name.replace(/[- _]+/g, '').toLowerCase();
      }
  
  // Adds leading zeros if shorter than four characters
      function pad4(str) {
          while (str.length < 4) {
              str = '0' + str;
          }
          return str;
      }
  
  // Converts a hexadecimal number to decimal
      function dec(hex) {
          return parseInt(hex, 16);
      }
  
  // Converts a decimal number to hexadecimal
      function hex(dec) {
          return parseInt(dec, 10).toString(16);
      }
  
  // Gets the decimal code of a literal code unit, \xHH, \uHHHH, or a backslash-escaped literal
      function charCode(chr) {
          var esc = /^\\[xu](.+)/.exec(chr);
          return esc ?
              dec(esc[1]) :
              chr.charCodeAt(chr.charAt(0) === '\\' ? 1 : 0);
      }
  
  // Inverts a list of ordered BMP characters and ranges
      function invertBmp(range) {
          var output = '',
              lastEnd = -1,
              start;
          XRegExp.forEach(range, /(\\x..|\\u....|\\?[\s\S])(?:-(\\x..|\\u....|\\?[\s\S]))?/, function(m) {
              start = charCode(m[1]);
              if (start > (lastEnd + 1)) {
                  output += '\\u' + pad4(hex(lastEnd + 1));
                  if (start > (lastEnd + 2)) {
                      output += '-\\u' + pad4(hex(start - 1));
                  }
              }
              lastEnd = charCode(m[2] || m[1]);
          });
          if (lastEnd < 0xFFFF) {
              output += '\\u' + pad4(hex(lastEnd + 1));
              if (lastEnd < 0xFFFE) {
                  output += '-\\uFFFF';
              }
          }
          return output;
      }
  
  // Generates an inverted BMP range on first use
      function cacheInvertedBmp(slug) {
          var prop = 'b!';
          return unicode[slug][prop] || (
              unicode[slug][prop] = invertBmp(unicode[slug].bmp)
          );
      }
  
  // Combines and optionally negates BMP and astral data
      function buildAstral(slug, isNegated) {
          var item = unicode[slug],
              combined = '';
          if (item.bmp && !item.isBmpLast) {
              combined = '[' + item.bmp + ']' + (item.astral ? '|' : '');
          }
          if (item.astral) {
              combined += item.astral;
          }
          if (item.isBmpLast && item.bmp) {
              combined += (item.astral ? '|' : '') + '[' + item.bmp + ']';
          }
          // Astral Unicode tokens always match a code point, never a code unit
          return isNegated ?
              '(?:(?!' + combined + ')(?:[\uD800-\uDBFF][\uDC00-\uDFFF]|[\0-\uFFFF]))' :
              '(?:' + combined + ')';
      }
  
  // Builds a complete astral pattern on first use
      function cacheAstral(slug, isNegated) {
          var prop = isNegated ? 'a!' : 'a=';
          return unicode[slug][prop] || (
              unicode[slug][prop] = buildAstral(slug, isNegated)
          );
      }
  
  /* ==============================
   * Core functionality
   * ============================== */
  
  /*
   * Add Unicode token syntax: \p{..}, \P{..}, \p{^..}. Also add astral mode (flag A).
   */
      XRegExp.addToken(
          // Use `*` instead of `+` to avoid capturing `^` as the token name in `\p{^}`
          /\\([pP])(?:{(\^?)([^}]*)}|([A-Za-z]))/,
          function(match, scope, flags) {
              var ERR_DOUBLE_NEG = 'Invalid double negation ',
                  ERR_UNKNOWN_NAME = 'Unknown Unicode token ',
                  ERR_UNKNOWN_REF = 'Unicode token missing data ',
                  ERR_ASTRAL_ONLY = 'Astral mode required for Unicode token ',
                  ERR_ASTRAL_IN_CLASS = 'Astral mode does not support Unicode tokens within character classes',
                  // Negated via \P{..} or \p{^..}
                  isNegated = match[1] === 'P' || !!match[2],
                  // Switch from BMP (0-FFFF) to astral (0-10FFFF) mode via flag A
                  isAstralMode = flags.indexOf('A') > -1,
                  // Token lookup name. Check `[4]` first to avoid passing `undefined` via `\p{}`
                  slug = normalize(match[4] || match[3]),
                  // Token data object
                  item = unicode[slug];
  
              if (match[1] === 'P' && match[2]) {
                  throw new SyntaxError(ERR_DOUBLE_NEG + match[0]);
              }
              if (!unicode.hasOwnProperty(slug)) {
                  throw new SyntaxError(ERR_UNKNOWN_NAME + match[0]);
              }
  
              // Switch to the negated form of the referenced Unicode token
              if (item.inverseOf) {
                  slug = normalize(item.inverseOf);
                  if (!unicode.hasOwnProperty(slug)) {
                      throw new ReferenceError(ERR_UNKNOWN_REF + match[0] + ' -> ' + item.inverseOf);
                  }
                  item = unicode[slug];
                  isNegated = !isNegated;
              }
  
              if (!(item.bmp || isAstralMode)) {
                  throw new SyntaxError(ERR_ASTRAL_ONLY + match[0]);
              }
              if (isAstralMode) {
                  if (scope === 'class') {
                      throw new SyntaxError(ERR_ASTRAL_IN_CLASS);
                  }
  
                  return cacheAstral(slug, isNegated);
              }
  
              return scope === 'class' ?
                  (isNegated ? cacheInvertedBmp(slug) : item.bmp) :
                  (isNegated ? '[^' : '[') + item.bmp + ']';
          },
          {
              scope: 'all',
              optionalFlags: 'A',
              leadChar: '\\'
          }
      );
  
  /**
   * Adds to the list of Unicode tokens that XRegExp regexes can match via `\p` or `\P`.
   *
   * @memberOf XRegExp
   * @param {Array} data Objects with named character ranges. Each object may have properties `name`,
   *   `alias`, `isBmpLast`, `inverseOf`, `bmp`, and `astral`. All but `name` are optional, although
   *   one of `bmp` or `astral` is required (unless `inverseOf` is set). If `astral` is absent, the
   *   `bmp` data is used for BMP and astral modes. If `bmp` is absent, the name errors in BMP mode
   *   but works in astral mode. If both `bmp` and `astral` are provided, the `bmp` data only is used
   *   in BMP mode, and the combination of `bmp` and `astral` data is used in astral mode.
   *   `isBmpLast` is needed when a token matches orphan high surrogates *and* uses surrogate pairs
   *   to match astral code points. The `bmp` and `astral` data should be a combination of literal
   *   characters and `\xHH` or `\uHHHH` escape sequences, with hyphens to create ranges. Any regex
   *   metacharacters in the data should be escaped, apart from range-creating hyphens. The `astral`
   *   data can additionally use character classes and alternation, and should use surrogate pairs to
   *   represent astral code points. `inverseOf` can be used to avoid duplicating character data if a
   *   Unicode token is defined as the exact inverse of another token.
   * @example
   *
   * // Basic use
   * XRegExp.addUnicodeData([{
   *   name: 'XDigit',
   *   alias: 'Hexadecimal',
   *   bmp: '0-9A-Fa-f'
   * }]);
   * XRegExp('\\p{XDigit}:\\p{Hexadecimal}+').test('0:3D'); // -> true
   */
      XRegExp.addUnicodeData = function(data) {
          var ERR_NO_NAME = 'Unicode token requires name',
              ERR_NO_DATA = 'Unicode token has no character data ',
              item,
              i;
  
          for (i = 0; i < data.length; ++i) {
              item = data[i];
              if (!item.name) {
                  throw new Error(ERR_NO_NAME);
              }
              if (!(item.inverseOf || item.bmp || item.astral)) {
                  throw new Error(ERR_NO_DATA + item.name);
              }
              unicode[normalize(item.name)] = item;
              if (item.alias) {
                  unicode[normalize(item.alias)] = item;
              }
          }
  
          // Reset the pattern cache used by the `XRegExp` constructor, since the same pattern and
          // flags might now produce different results
          XRegExp.cache.flush('patterns');
      };
  
  };
  