<script>
// Lwarp MathJax emulation code
//
// Based on code by Davide P. Cervone.
// Equation numbering: https://github.com/mathjax/MathJax/issues/2427
// Starred and ifnextchar macros: https://github.com/mathjax/MathJax/issues/2428
// \left, \right delimiters: https://github.com/mathjax/MathJax/issues/2535
//
// Modified by Brian Dunn to adjust equation numbering and add subequations.
//
// LaTeX can use \seteqnumber{subequations?}{section}{number} before each equation.
// subequations? is 0 usually, 1 if inside subequations.
// section is a string printed as-is, or empty.
// number is auto-incremented by MathJax between equations.
//
MathJax = {
  subequations: "0",
  section: "",
  loader: {
    load: ['[tex]/tagformat', '[tex]/textmacros'],
  },
  startup: {
    ready() {
      //  These would be replaced by import commands if you wanted to make
      //  a proper extension.
      const Configuration = MathJax._.input.tex.Configuration.Configuration;
      const CommandMap = MathJax._.input.tex.SymbolMap.CommandMap;
      const Macro = MathJax._.input.tex.Symbol.Macro;
      const TexError = MathJax._.input.tex.TexError.default;
      const ParseUtil = MathJax._.input.tex.ParseUtil.default;
      const expandable = MathJax._.util.Options.expandable;

      //  Insert the replacement string into the TeX string, and check
      //  that there haven't been too many maxro substitutions (prevents
      //  infinite loops).
      const useArgument = (parser, text) => {
        parser.string = ParseUtil.addArgs(parser, text, parser.string.slice(parser.i));
        parser.i = 0;
        if (++parser.macroCount > parser.configuration.options.maxMacros) {
          throw new TexError('MaxMacroSub1',
          'MathJax maximum macro substitution count exceeded; ' +
          'is there a recursive macro call?');
        }
      }

      //  Create the command map for:
      //    \ifstar, \ifnextchar, \ifblank, \ifstrequal, \gsub, \seteqnumber
      new CommandMap('Lwarp-macros', {
        ifstar: 'IfstarFunction',
        ifnextchar: 'IfnextcharFunction',
        ifblank: 'IfblankFunction',
        ifstrequal: 'IfstrequalFunction',
        gsubstitute: 'GsubstituteFunction',
        seteqnumber: 'SeteqnumberFunction'
      }, {
        //  This function implements an ifstar macro.
        IfstarFunction(parser, name) {
          const resultstar = parser.GetArgument(name);
          const resultnostar = parser.GetArgument(name);
          const star = parser.GetStar();                 // true if there is a *
          useArgument(parser, star ? resultstar : resultnostar);
        },

        //  This function implements an ifnextchar macro.
        IfnextcharFunction(parser, name) {
          let whichchar = parser.GetArgument(name);
          if (whichchar.match(/^(?:0x[0-9A-F]+|[0-9]+)$/i)) {
            // $ syntax highlighting
            whichchar = String.fromCodePoint(parseInt(whichchar));
          }
          const resultnextchar = parser.GetArgument(name);
          const resultnotnextchar = parser.GetArgument(name);
          const gotchar = (parser.GetNext() === whichchar);
          useArgument(parser, gotchar ? resultnextchar : resultnotnextchar);
        },

        // This function implements an ifblank macro.
        IfblankFunction(parser, name) {
          const blankarg = parser.GetArgument(name);
          const resultblank = parser.GetArgument(name);
          const resultnotblank = parser.GetArgument(name);
          const isblank = (blankarg.trim() == "");
          useArgument(parser, isblank ? resultblank : resultnotblank);
        },

        // This function implements an ifstrequal macro.
        IfstrequalFunction(parser, name) {
          const strequalfirst = parser.GetArgument(name);
          const strequalsecond = parser.GetArgument(name);
          const resultequal = parser.GetArgument(name);
          const resultnotequal = parser.GetArgument(name);
          const isequal = (strequalfirst == strequalsecond);
          useArgument(parser, isequal ? resultequal : resultnotequal);
        },

        // This function implements a gsub macro.
        GsubstituteFunction(parser, name) {
          const gsubfirst = parser.GetArgument(name);
          const gsubsecond = parser.GetArgument(name);
          const gsubthird = parser.GetArgument(name);
          let gsubresult=gsubfirst.replace(gsubsecond, gsubthird);
          useArgument(parser, gsubresult);
        },

        //  This function modifies the equation numbers.
        SeteqnumberFunction(parser, name) {
            //  Get the macro parameters
            const star = parser.GetStar();                  // true if there is a *
            const optBrackets = parser.GetBrackets(name);   // contents of optional brackets
            const newsubequations = parser.GetArgument(name);  // the subequations argument
            const neweqsection = parser.GetArgument(name);  // the eq section argument
            const neweqnumber = parser.GetArgument(name);   // the eq number argument
            MathJax.config.subequations=newsubequations ;   // a string with boolean meaning
            MathJax.config.section=neweqsection ;           // a string with numeric meaning
            parser.tags.counter = parser.tags.allCounter = neweqnumber ;
        }

      });

      //  Create the Lwarp-macros package
      Configuration.create('Lwarp-macros', {
        handler: {macro: ['Lwarp-macros']}
      });

      MathJax.startup.defaultReady();

      // For forward references:
      MathJax.startup.input[0].preFilters.add(({math}) => {
        if (math.inputData.recompile){
            MathJax.config.subequations = math.inputData.recompile.subequations;
            MathJax.config.section = math.inputData.recompile.section;
        }
      });
      MathJax.startup.input[0].postFilters.add(({math}) => {
        if (math.inputData.recompile){
            math.inputData.recompile.subequations = MathJax.config.subequations;
            math.inputData.recompile.section = MathJax.config.section;
        }
      });

        // For \left, \right with unicode-math:
        const {DelimiterMap} = MathJax._.input.tex.SymbolMap;
        const {Symbol} = MathJax._.input.tex.Symbol;
        const {MapHandler} = MathJax._.input.tex.MapHandler;
        const delimiter = MapHandler.getMap('delimiter');
        delimiter.add('\\lBrack', new Symbol('\\lBrack', '\u27E6'));
        delimiter.add('\\rBrack', new Symbol('\\rBrack', '\u27E7'));
        delimiter.add('\\lAngle', new Symbol('\\lAngle', '\u27EA'));
        delimiter.add('\\rAngle', new Symbol('\\rAngle', '\u27EB'));
        delimiter.add('\\lbrbrak', new Symbol('\\lbrbrak', '\u2772'));
        delimiter.add('\\rbrbrak', new Symbol('\\rbrbrak', '\u2773'));
        delimiter.add('\\lbag', new Symbol('\\lbag', '\u27C5'));
        delimiter.add('\\rbag', new Symbol('\\rbag', '\u27C6'));
        delimiter.add('\\llparenthesis', new Symbol('\\llparenthesis', '\u2987'));
        delimiter.add('\\rrparenthesis', new Symbol('\\rrparenthesis', '\u2988'));
        delimiter.add('\\llangle', new Symbol('\\llangle', '\u2989'));
        delimiter.add('\\rrangle', new Symbol('\\rrangle', '\u298A'));
        delimiter.add('\\Lbrbrak', new Symbol('\\Lbrbrak', '\u27EC'));
        delimiter.add('\\Rbrbrak', new Symbol('\\Rbrbrak', '\u27ED'));
        delimiter.add('\\lBrace', new Symbol('\\lBrace', '\u2983'));
        delimiter.add('\\rBrace', new Symbol('\\rBrace', '\u2984'));
        delimiter.add('\\lParen', new Symbol('\\lParen', '\u2985'));
        delimiter.add('\\rParen', new Symbol('\\rParen', '\u2986'));
        delimiter.add('\\lbrackubar', new Symbol('\\lbrackubar', '\u298B'));
        delimiter.add('\\rbrackubar', new Symbol('\\rbrackubar', '\u298C'));
        delimiter.add('\\lbrackultick', new Symbol('\\lbrackultick', '\u298D'));
        delimiter.add('\\rbracklrtick', new Symbol('\\rbracklrtick', '\u298E'));
        delimiter.add('\\lbracklltick', new Symbol('\\lbracklltick', '\u298F'));
        delimiter.add('\\rbrackurtick', new Symbol('\\rbrackurtick', '\u2990'));
        delimiter.add('\\langledot', new Symbol('\\langledot', '\u2991'));
        delimiter.add('\\rangledot', new Symbol('\\rangledot', '\u2992'));
        delimiter.add('\\lparenless', new Symbol('\\lparenless', '\u2993'));
        delimiter.add('\\rparengtr', new Symbol('\\rparengtr', '\u2994'));
        delimiter.add('\\Lparengtr', new Symbol('\\Lparengtr', '\u2995'));
        delimiter.add('\\Rparenless', new Symbol('\\Rparenless', '\u2996'));
        delimiter.add('\\lblkbrbrak', new Symbol('\\lblkbrbrak', '\u2997'));
        delimiter.add('\\rblkbrbrak', new Symbol('\\rblkbrbrak', '\u2998'));
        delimiter.add('\\lvzigzag', new Symbol('\\lvzigzag', '\u29D8'));
        delimiter.add('\\rvzigzag', new Symbol('\\rvzigzag', '\u29D9'));
        delimiter.add('\\Lvzigzag', new Symbol('\\Lvzigzag', '\u29DA'));
        delimiter.add('\\Rvzigzag', new Symbol('\\Rvzigzag', '\u29DB'));
        delimiter.add('\\lcurvyangle', new Symbol('\\lcurvyangle', '\u29FC'));
        delimiter.add('\\rcurvyangle', new Symbol('\\rcurvyangle', '\u29FD'));
        delimiter.add('\\Vvert', new Symbol('\\Vvert', '\u2980'));
    }   // ready
  },    // startup

  tex: {
    packages: {'[+]': ['tagformat', 'Lwarp-macros', 'textmacros']},
    tags: "ams",
        tagformat: {
            number: function (n) {
                if(MathJax.config.subequations==0)
                    return(MathJax.config.section + n);
                else
                    return(MathJax.config.section + String.fromCharCode(96+n));
            },
        },
  }
}
</script>

<script
    id="MathJax-script"
    src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"
></script>
