text: showdown.subParser('headers', function (text, options, globals) {
    'use strict';
  
    text = globals.converter._dispatch('headers.before', text, options, globals);
  
    var prefixHeader = options.prefixHeaderId,
        headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart),
        ghHeaderId = options.ghCompatibleHeaderId,
  
    // Set text-style headers:
    //	Header 1
    //	========
    //
    //	Header 2
    //	--------
    //
        setextRegexH1 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n={2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n=+[ \t]*\n+/gm,
        setextRegexH2 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n-+[ \t]*\n+/gm;
  
    text = text.replace(setextRegexH1, function (wholeMatch, m1) {
  
      var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),
          hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',
          hLevel = headerLevelStart,
          hashBlock = '<h' + hLevel + hID + '>' + spanGamut + '</h' + hLevel + '>';
      return showdown.subParser('hashBlock')(hashBlock, options, globals);
    });
  
    text = text.replace(setextRegexH2, function (matchFound, m1) {
      var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),
          hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',
          hLevel = headerLevelStart + 1,
        hashBlock = '<h' + hLevel + hID + '>' + spanGamut + '</h' + hLevel + '>';
      return showdown.subParser('hashBlock')(hashBlock, options, globals);
    });
  
    // atx-style headers:
    //  # Header 1
    //  ## Header 2
    //  ## Header 2 with closing hashes ##
    //  ...
    //  ###### Header 6
    //
    var atxStyle = (options.requireSpaceBeforeHeadingText) ? /^(#{1,6})[ \t]+(.+?)[ \t]*#*\n+/gm : /^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm;
  
    text = text.replace(atxStyle, function (wholeMatch, m1, m2) {
      var span = showdown.subParser('spanGamut')(m2, options, globals),
          hID = (options.noHeaderId) ? '' : ' id="' + headerId(m2) + '"',
          hLevel = headerLevelStart - 1 + m1.length,
          header = '<h' + hLevel + hID + '>' + span + '</h' + hLevel + '>';
  
      return showdown.subParser('hashBlock')(header, options, globals);
    });
  
    function headerId(m) {
      var title, escapedId;
  
      if (ghHeaderId) {
        escapedId = m
          .replace(/ /g, '-')
          //replace previously escaped chars (&, ~ and $)
          .replace(/&amp;/g, '')
          .replace(/~T/g, '')
          .replace(/~D/g, '')
          //replace rest of the chars (&~$ are repeated as they might have been escaped)
          // borrowed from github's redcarpet (some they should produce similar results)
          .replace(/[&+$,\/:;=?@"#{}|^~\[\]`\\*)(%.!'<>]/g, '')
          .toLowerCase();
      } else {
        escapedId = m.replace(/[^\w]/g, '').toLowerCase();
      }
  
      if (globals.hashLinkCounts[escapedId]) {
        title = escapedId + '-' + (globals.hashLinkCounts[escapedId]++);
      } else {
        title = escapedId;
        globals.hashLinkCounts[escapedId] = 1;
      }
  
      // Prefix id to prevent causing inadvertent pre-existing style matches.
      if (prefixHeader === true) {
        prefixHeader = 'section';
      }
  
      if (showdown.helper.isString(prefixHeader)) {
        return prefixHeader + title;
      }
      return title;
    }
  
    text = globals.converter._dispatch('headers.after', text, options, globals);
    return text;
  });
  