docs: function createNamedRegex(regexp, flags) {
  
      if (typeof regexp === "boolean") {
        // options parameter
        if (regexp === false) {
          cache = undefined;
        } else if (!cache) {
          cache = {};
        }
        return;
      }
  
      if (typeof regexp !== "string") {
        // parameter is regexp literal
        flags = (regexp.global ? "g" : "") +
          (regexp.multiline ? "m" : "") +
          (regexp.ignoreCase ? "i" : "");
        regexp = regexp.source;
      }
  
      var info = cache ? (cache[regexp] || (cache[regexp] = parseRegex(regexp))) : parseRegex(regexp);
      var regex = new RegExp(info.regexText, flags);
  
      regex.groupsIndices = info.mapper;
  
      function extendMatched(matched) {
        var mapper = info.mapper;
        /**
        * Returns value for group name or undefined. If same group name was defined multiple time, it returns first not undefined value.
        * If all is set to true, then it returns array of all matched values.
        */
        matched.group = function (name, all) {
          var indices = mapper[name];
          if (typeof indices === "number") {
            // name group is defined only once
            return matched[indices];
          } else if (all) {
            // name group is defined multiple time and because all is true, return array of all matched values
            return indices.map(function (v) { return matched[v]; });
          } else if (indices) {
            // name group is defined multiple time and because all is false, return first not undefined matched value
            for (var i = 0; i < indices.length; ++i) {
              var value = matched[indices[i]];
              if (value !== undefined) {
                return value;
              }
            }
          }
          return undefined;
        };
        var cachedGroups, cachedGroupsAll;
        matched.groups = function (all) {
          var cg = all ? cachedGroupsAll : cachedGroups;
          if (cg) {
            return cg;
          }
          cg = {};
          for (var name in mapper) {
            cg[name] = matched.group(name, all);
          }
          return all ? cachedGroupsAll = cg : cachedGroups = cg;
        };
        return matched;
      }
  
      regex.exec = function (text) {
        var matched = RegExp.prototype.exec.call(this, text);
        if (matched) {
          extendMatched(matched);
        }
        return matched;
      }
      regex.execGroups = function (text, all) {
        var matched = this.exec(text);
        if (!matched) {
          return null;
        }
        return matched.groups(all);
      }
  
      regex.replace = function (text, replacement) {
        if (typeof replacement === "function") {
          return text.replace(regex, function () {
            var matched = Array.prototype.slice.call(arguments, 0, arguments.length - 2);
            extendMatched(matched);
            return replacement.apply(matched, arguments);
          });
        } else {
          var replacementText = parseReplacement(replacement, this.groupsIndices);
          return text.replace(this, replacementText);
        }
      }
      return regex;
    }