%%
%% This is file `luababel.def',
%% generated with the docstrip utility.
%%
%% The original source files were:
%%
%% babel.dtx  (with options: `luatex')
%% 
%%
%% Copyright (C) 2012-2025 Javier Bezos and Johannes L. Braams.
%% Copyright (C) 1989-2012 Johannes L. Braams and
%%           any individual authors listed elsewhere in this file.
%% All rights reserved.
%%
%%
%% This file is part of the Babel system.
%% --------------------------------------
%%
%% It may be distributed and/or modified under the
%% conditions of the LaTeX Project Public License, either version 1.3
%% of this license or (at your option) any later version.
%% The latest version of this license is in
%%   http://www.latex-project.org/lppl.txt
%% and version 1.3 or later is part of all distributions of LaTeX
%% version 2003/12/01 or later.
%%
%% This work has the LPPL maintenance status "maintained".
%%
%% The Current Maintainer of this work is Javier Bezos.
%%
%% The list of derived (unpacked) files belonging to the distribution
%% and covered by LPPL is defined by the unpacking scripts (with
%% extension |.ins|) which are part of the distribution.
%%
\directlua{ Babel = Babel or {} } % DL2
\ifx\AddBabelHook\@undefined % When plain.def, babel.sty starts
\bbl@trace{Read language.dat}
\ifx\bbl@readstream\@undefined
  \csname newread\endcsname\bbl@readstream
\fi
\begingroup
  \toks@{}
  \count@\z@ % 0=start, 1=0th, 2=normal
  \def\bbl@process@line#1#2 #3 #4 {%
    \ifx=#1%
      \bbl@process@synonym{#2}%
    \else
      \bbl@process@language{#1#2}{#3}{#4}%
    \fi
    \ignorespaces}
  \def\bbl@manylang{%
    \ifnum\bbl@last>\@ne
      \bbl@info{Non-standard hyphenation setup}%
    \fi
    \let\bbl@manylang\relax}
  \def\bbl@process@language#1#2#3{%
    \ifcase\count@
      \@ifundefined{zth@#1}{\count@\tw@}{\count@\@ne}%
    \or
      \count@\tw@
    \fi
    \ifnum\count@=\tw@
      \expandafter\addlanguage\csname l@#1\endcsname
      \language\allocationnumber
      \chardef\bbl@last\allocationnumber
      \bbl@manylang
      \let\bbl@elt\relax
      \xdef\bbl@languages{%
        \bbl@languages\bbl@elt{#1}{\the\language}{#2}{#3}}%
    \fi
    \the\toks@
    \toks@{}}
  \def\bbl@process@synonym@aux#1#2{%
    \global\expandafter\chardef\csname l@#1\endcsname#2\relax
    \let\bbl@elt\relax
    \xdef\bbl@languages{%
      \bbl@languages\bbl@elt{#1}{#2}{}{}}}%
  \def\bbl@process@synonym#1{%
    \ifcase\count@
      \toks@\expandafter{\the\toks@\relax\bbl@process@synonym{#1}}%
    \or
      \@ifundefined{zth@#1}{\bbl@process@synonym@aux{#1}{0}}{}%
    \else
      \bbl@process@synonym@aux{#1}{\the\bbl@last}%
    \fi}
  \ifx\bbl@languages\@undefined % Just a (sensible?) guess
    \chardef\l@english\z@
    \chardef\l@USenglish\z@
    \chardef\bbl@last\z@
    \global\@namedef{bbl@hyphendata@0}{{hyphen.tex}{}}
    \gdef\bbl@languages{%
      \bbl@elt{english}{0}{hyphen.tex}{}%
      \bbl@elt{USenglish}{0}{}{}}
  \else
    \global\let\bbl@languages@format\bbl@languages
    \def\bbl@elt#1#2#3#4{% Remove all except language 0
      \ifnum#2>\z@\else
        \noexpand\bbl@elt{#1}{#2}{#3}{#4}%
      \fi}%
    \xdef\bbl@languages{\bbl@languages}%
  \fi
  \def\bbl@elt#1#2#3#4{\@namedef{zth@#1}{}} % Define flags
  \bbl@languages
  \openin\bbl@readstream=language.dat
  \ifeof\bbl@readstream
    \bbl@warning{I couldn't find language.dat. No additional\\%
                 patterns loaded. Reported}%
  \else
    \loop
      \endlinechar\m@ne
      \read\bbl@readstream to \bbl@line
      \endlinechar`\^^M
      \if T\ifeof\bbl@readstream F\fi T\relax
        \ifx\bbl@line\@empty\else
          \edef\bbl@line{\bbl@line\space\space\space}%
          \expandafter\bbl@process@line\bbl@line\relax
        \fi
    \repeat
  \fi
  \closein\bbl@readstream
\endgroup
\bbl@trace{Macros for reading patterns files}
\def\bbl@get@enc#1:#2:#3\@@@{\def\bbl@hyph@enc{#2}}
\ifx\babelcatcodetablenum\@undefined
  \ifx\newcatcodetable\@undefined
    \def\babelcatcodetablenum{5211}
    \def\bbl@pattcodes{\numexpr\babelcatcodetablenum+1\relax}
  \else
    \newcatcodetable\babelcatcodetablenum
    \newcatcodetable\bbl@pattcodes
  \fi
\else
  \def\bbl@pattcodes{\numexpr\babelcatcodetablenum+1\relax}
\fi
\def\bbl@luapatterns#1#2{%
  \bbl@get@enc#1::\@@@
  \setbox\z@\hbox\bgroup
    \begingroup
      \savecatcodetable\babelcatcodetablenum\relax
      \initcatcodetable\bbl@pattcodes\relax
      \catcodetable\bbl@pattcodes\relax
        \catcode`\#=6  \catcode`\$=3 \catcode`\&=4 \catcode`\^=7
        \catcode`\_=8  \catcode`\{=1 \catcode`\}=2 \catcode`\~=13
        \catcode`\@=11 \catcode`\^^I=10 \catcode`\^^J=12
        \catcode`\<=12 \catcode`\>=12 \catcode`\*=12 \catcode`\.=12
        \catcode`\-=12 \catcode`\/=12 \catcode`\[=12 \catcode`\]=12
        \catcode`\`=12 \catcode`\'=12 \catcode`\"=12
        \input #1\relax
      \catcodetable\babelcatcodetablenum\relax
    \endgroup
    \def\bbl@tempa{#2}%
    \ifx\bbl@tempa\@empty\else
      \input #2\relax
    \fi
  \egroup}%
\def\bbl@patterns@lua#1{%
  \language=\expandafter\ifx\csname l@#1:\f@encoding\endcsname\relax
    \csname l@#1\endcsname
    \edef\bbl@tempa{#1}%
  \else
    \csname l@#1:\f@encoding\endcsname
    \edef\bbl@tempa{#1:\f@encoding}%
  \fi\relax
  \@namedef{lu@texhyphen@loaded@\the\language}{}% Temp
  \@ifundefined{bbl@hyphendata@\the\language}%
    {\def\bbl@elt##1##2##3##4{%
       \ifnum##2=\csname l@\bbl@tempa\endcsname % #2=spanish, dutch:OT1...
         \def\bbl@tempb{##3}%
         \ifx\bbl@tempb\@empty\else % if not a synonymous
           \def\bbl@tempc{{##3}{##4}}%
         \fi
         \bbl@csarg\xdef{hyphendata@##2}{\bbl@tempc}%
       \fi}%
     \bbl@languages
     \@ifundefined{bbl@hyphendata@\the\language}%
       {\bbl@info{No hyphenation patterns were set for\\%
                  language '\bbl@tempa'. Reported}}%
       {\expandafter\expandafter\expandafter\bbl@luapatterns
          \csname bbl@hyphendata@\the\language\endcsname}}{}}
\endinput\fi
\ifx\DisableBabelHook\@undefined
  \AddBabelHook{luatex}{everylanguage}{%
    \def\process@language##1##2##3{%
      \def\process@line####1####2 ####3 ####4 {}}}
  \AddBabelHook{luatex}{loadpatterns}{%
     \input #1\relax
     \expandafter\gdef\csname bbl@hyphendata@\the\language\endcsname
       {{#1}{}}}
  \AddBabelHook{luatex}{loadexceptions}{%
     \input #1\relax
     \def\bbl@tempb##1##2{{##1}{#1}}%
     \expandafter\xdef\csname bbl@hyphendata@\the\language\endcsname
       {\expandafter\expandafter\expandafter\bbl@tempb
        \csname bbl@hyphendata@\the\language\endcsname}}
\endinput\fi
\begingroup
\catcode`\%=12
\catcode`\'=12
\catcode`\"=12
\catcode`\:=12
\directlua{
  Babel.locale_props = Babel.locale_props or {}
  function Babel.lua_error(e, a)
    tex.print([[\noexpand\csname bbl@error\endcsname{]] ..
      e .. '}{' .. (a or '') .. '}{}{}')
  end

  function Babel.bytes(line)
    return line:gsub("(.)",
      function (chr) return unicode.utf8.char(string.byte(chr)) end)
  end

  function Babel.priority_in_callback(name,description)
    for i,v in ipairs(luatexbase.callback_descriptions(name)) do
      if v == description then return i end
    end
    return false
  end

  function Babel.begin_process_input()
    if luatexbase and luatexbase.add_to_callback then
      luatexbase.add_to_callback('process_input_buffer',
                                 Babel.bytes,'Babel.bytes')
    else
      Babel.callback = callback.find('process_input_buffer')
      callback.register('process_input_buffer',Babel.bytes)
    end
  end
  function Babel.end_process_input ()
    if luatexbase and luatexbase.remove_from_callback then
      luatexbase.remove_from_callback('process_input_buffer','Babel.bytes')
    else
      callback.register('process_input_buffer',Babel.callback)
    end
  end

  function Babel.str_to_nodes(fn, matches, base)
    local n, head, last
    if fn == nil then return nil end
    for s in string.utfvalues(fn(matches)) do
      if base.id == 7 then
        base = base.replace
      end
      n = node.copy(base)
      n.char    = s
      if not head then
        head = n
      else
        last.next = n
      end
      last = n
    end
    return head
  end

  Babel.linebreaking = Babel.linebreaking or {}
  Babel.linebreaking.before = {}
  Babel.linebreaking.after = {}
  Babel.locale = {}
  function Babel.linebreaking.add_before(func, pos)
    tex.print([[\noexpand\csname bbl@luahyphenate\endcsname]])
    if pos == nil then
      table.insert(Babel.linebreaking.before, func)
    else
      table.insert(Babel.linebreaking.before, pos, func)
    end
  end
  function Babel.linebreaking.add_after(func)
    tex.print([[\noexpand\csname bbl@luahyphenate\endcsname]])
    table.insert(Babel.linebreaking.after, func)
  end

  function Babel.addpatterns(pp, lg)
    local lg = lang.new(lg)
    local pats = lang.patterns(lg) or ''
    lang.clear_patterns(lg)
    for p in pp:gmatch('[^%s]+') do
      ss = ''
      for i in string.utfcharacters(p:gsub('%d', '')) do
         ss = ss .. '%d?' .. i
      end
      ss = ss:gsub('^%%d%?%.', '%%.') .. '%d?'
      ss = ss:gsub('%.%%d%?$', '%%.')
      pats, n = pats:gsub('%s' .. ss .. '%s', ' ' .. p .. ' ')
      if n == 0 then
        tex.sprint(
          [[\string\csname\space bbl@info\endcsname{New pattern: ]]
          .. p .. [[}]])
        pats = pats .. ' ' .. p
      else
        tex.sprint(
          [[\string\csname\space bbl@info\endcsname{Renew pattern: ]]
          .. p .. [[}]])
      end
    end
    lang.patterns(lg, pats)
  end

  Babel.characters = Babel.characters or {}
  Babel.ranges = Babel.ranges or {}
  function Babel.hlist_has_bidi(head)
    local has_bidi = false
    local ranges = Babel.ranges
    for item in node.traverse(head) do
      if item.id == node.id'glyph' then
        local itemchar = item.char
        local chardata = Babel.characters[itemchar]
        local dir = chardata and chardata.d or nil
        if not dir then
          for nn, et in ipairs(ranges) do
            if itemchar < et[1] then
              break
            elseif itemchar <= et[2] then
              dir = et[3]
              break
            end
          end
        end
        if dir and (dir == 'al' or dir == 'r') then
          has_bidi = true
        end
      end
    end
    return has_bidi
  end
  function Babel.set_chranges_b (script, chrng)
    if chrng == '' then return end
    texio.write('Replacing ' .. script .. ' script ranges')
    Babel.script_blocks[script] = {}
    for s, e in string.gmatch(chrng..' ', '(.-)%.%.(.-)%s') do
      table.insert(
        Babel.script_blocks[script], {tonumber(s,16), tonumber(e,16)})
    end
  end

  function Babel.discard_sublr(str)
    if str:find( [[\string\indexentry]] ) and
         str:find( [[\string\babelsublr]] ) then
     str = str:gsub( [[\string\babelsublr%s*(%b{})]],
                     function(m) return m:sub(2,-2) end )
     end
     return str
  end
}
\endgroup
\ifx\newattribute\@undefined\else % Test for plain
  \newattribute\bbl@attr@locale % DL4
  \directlua{ Babel.attr_locale = luatexbase.registernumber'bbl@attr@locale' }
  \AddBabelHook{luatex}{beforeextras}{%
    \setattribute\bbl@attr@locale\localeid}
\fi
\def\BabelStringsDefault{unicode}
\let\luabbl@stop\relax
\AddBabelHook{luatex}{encodedcommands}{%
  \def\bbl@tempa{utf8}\def\bbl@tempb{#1}%
  \ifx\bbl@tempa\bbl@tempb\else
    \directlua{Babel.begin_process_input()}%
    \def\luabbl@stop{%
      \directlua{Babel.end_process_input()}}%
  \fi}%
\AddBabelHook{luatex}{stopcommands}{%
  \luabbl@stop
  \let\luabbl@stop\relax}
\AddBabelHook{luatex}{patterns}{%
  \@ifundefined{bbl@hyphendata@\the\language}%
    {\def\bbl@elt##1##2##3##4{%
       \ifnum##2=\csname l@#2\endcsname % #2=spanish, dutch:OT1...
         \def\bbl@tempb{##3}%
         \ifx\bbl@tempb\@empty\else % if not a synonymous
           \def\bbl@tempc{{##3}{##4}}%
         \fi
         \bbl@csarg\xdef{hyphendata@##2}{\bbl@tempc}%
       \fi}%
     \bbl@languages
     \@ifundefined{bbl@hyphendata@\the\language}%
       {\bbl@info{No hyphenation patterns were set for\\%
                  language '#2'. Reported}}%
       {\expandafter\expandafter\expandafter\bbl@luapatterns
          \csname bbl@hyphendata@\the\language\endcsname}}{}%
  \@ifundefined{bbl@patterns@}{}{%
    \begingroup
      \bbl@xin@{,\number\language,}{,\bbl@pttnlist}%
      \ifin@\else
        \ifx\bbl@patterns@\@empty\else
           \directlua{ Babel.addpatterns(
             [[\bbl@patterns@]], \number\language) }%
        \fi
        \@ifundefined{bbl@patterns@#1}%
          \@empty
          {\directlua{ Babel.addpatterns(
               [[\space\csname bbl@patterns@#1\endcsname]],
               \number\language) }}%
        \xdef\bbl@pttnlist{\bbl@pttnlist\number\language,}%
      \fi
    \endgroup}%
  \bbl@exp{%
    \bbl@ifunset{bbl@prehc@\languagename}{}%
      {\\\bbl@ifblank{\bbl@cs{prehc@\languagename}}{}%
        {\prehyphenchar=\bbl@cl{prehc}\relax}}}}
\@onlypreamble\babelpatterns
\AtEndOfPackage{%
  \newcommand\babelpatterns[2][\@empty]{%
    \ifx\bbl@patterns@\relax
      \let\bbl@patterns@\@empty
    \fi
    \ifx\bbl@pttnlist\@empty\else
      \bbl@warning{%
        You must not intermingle \string\selectlanguage\space and\\%
        \string\babelpatterns\space or some patterns will not\\%
        be taken into account. Reported}%
    \fi
    \ifx\@empty#1%
      \protected@edef\bbl@patterns@{\bbl@patterns@\space#2}%
    \else
      \edef\bbl@tempb{\zap@space#1 \@empty}%
      \bbl@for\bbl@tempa\bbl@tempb{%
        \bbl@fixname\bbl@tempa
        \bbl@iflanguage\bbl@tempa{%
          \bbl@csarg\protected@edef{patterns@\bbl@tempa}{%
            \@ifundefined{bbl@patterns@\bbl@tempa}%
              \@empty
              {\csname bbl@patterns@\bbl@tempa\endcsname\space}%
            #2}}}%
    \fi}}
\def\bbl@intraspace#1 #2 #3\@@{%
  \directlua{
    Babel.intraspaces = Babel.intraspaces or {}
    Babel.intraspaces['\csname bbl@sbcp@\languagename\endcsname'] = %
       {b = #1, p = #2, m = #3}
    Babel.locale_props[\the\localeid].intraspace = %
       {b = #1, p = #2, m = #3}
  }}
\def\bbl@intrapenalty#1\@@{%
  \directlua{
    Babel.intrapenalties = Babel.intrapenalties or {}
    Babel.intrapenalties['\csname bbl@sbcp@\languagename\endcsname'] = #1
    Babel.locale_props[\the\localeid].intrapenalty = #1
  }}
\begingroup
\catcode`\%=12
\catcode`\&=14
\catcode`\'=12
\catcode`\~=12
\gdef\bbl@seaintraspace{&
  \let\bbl@seaintraspace\relax
  \directlua{
    Babel.sea_enabled = true
    Babel.sea_ranges = Babel.sea_ranges or {}
    function Babel.set_chranges (script, chrng)
      local c = 0
      for s, e in string.gmatch(chrng..' ', '(.-)%.%.(.-)%s') do
        Babel.sea_ranges[script..c]={tonumber(s,16), tonumber(e,16)}
        c = c + 1
      end
    end
    function Babel.sea_disc_to_space (head)
      local sea_ranges = Babel.sea_ranges
      local last_char = nil
      local quad = 655360      &% 10 pt = 655360 = 10 * 65536
      for item in node.traverse(head) do
        local i = item.id
        if i == node.id'glyph' then
          last_char = item
        elseif i == 7 and item.subtype == 3 and last_char
            and last_char.char > 0x0C99 then
          quad = font.getfont(last_char.font).size
          for lg, rg in pairs(sea_ranges) do
            if last_char.char > rg[1] and last_char.char < rg[2] then
              lg = lg:sub(1, 4)  &% Remove trailing number of, e.g., Cyrl1
              local intraspace = Babel.intraspaces[lg]
              local intrapenalty = Babel.intrapenalties[lg]
              local n
              if intrapenalty ~= 0 then
                n = node.new(14, 0)     &% penalty
                n.penalty = intrapenalty
                node.insert_before(head, item, n)
              end
              n = node.new(12, 13)      &% (glue, spaceskip)
              node.setglue(n, intraspace.b * quad,
                              intraspace.p * quad,
                              intraspace.m * quad)
              node.insert_before(head, item, n)
              node.remove(head, item)
            end
          end
        end
      end
    end
  }&
  \bbl@luahyphenate}
\catcode`\%=14
\gdef\bbl@cjkintraspace{%
  \let\bbl@cjkintraspace\relax
  \directlua{
    require('babel-data-cjk.lua')
    Babel.cjk_enabled = true
    function Babel.cjk_linebreak(head)
      local GLYPH = node.id'glyph'
      local last_char = nil
      local quad = 655360      % 10 pt = 655360 = 10 * 65536
      local last_class = nil
      local last_lang = nil
      for item in node.traverse(head) do
        if item.id == GLYPH then
          local lang = item.lang
          local LOCALE = node.get_attribute(item,
                Babel.attr_locale)
          local props = Babel.locale_props[LOCALE] or {}
          local class = Babel.cjk_class[item.char].c
          if props.cjk_quotes and props.cjk_quotes[item.char] then
            class = props.cjk_quotes[item.char]
          end
          if class == 'cp' then class = 'cl' % )] as CL
          elseif class == 'id' then class = 'I'
          elseif class == 'cj' then class = 'I' % loose
          end
          local br = 0
          if class and last_class and Babel.cjk_breaks[last_class][class] then
            br = Babel.cjk_breaks[last_class][class]
          end
          if br == 1 and props.linebreak == 'c' and
              lang ~= \the\l@nohyphenation\space and
              last_lang ~= \the\l@nohyphenation then
            local intrapenalty = props.intrapenalty
            if intrapenalty ~= 0 then
              local n = node.new(14, 0)     % penalty
              n.penalty = intrapenalty
              node.insert_before(head, item, n)
            end
            local intraspace = props.intraspace
            local n = node.new(12, 13)      % (glue, spaceskip)
            node.setglue(n, intraspace.b * quad,
                            intraspace.p * quad,
                            intraspace.m * quad)
            node.insert_before(head, item, n)
          end
          if font.getfont(item.font) then
            quad = font.getfont(item.font).size
          end
          last_class = class
          last_lang = lang
        else % if penalty, glue or anything else
          last_class = nil
        end
      end
      lang.hyphenate(head)
    end
  }%
  \bbl@luahyphenate}
\gdef\bbl@luahyphenate{%
  \let\bbl@luahyphenate\relax
  \directlua{
    luatexbase.add_to_callback('hyphenate',
    function (head, tail)
      if Babel.linebreaking.before then
        for k, func in ipairs(Babel.linebreaking.before)  do
          func(head)
        end
      end
      lang.hyphenate(head)
      if Babel.cjk_enabled then
        Babel.cjk_linebreak(head)
      end
      if Babel.linebreaking.after then
        for k, func in ipairs(Babel.linebreaking.after)  do
          func(head)
        end
      end
      if Babel.set_hboxed then
        Babel.set_hboxed(head)
      end
      if Babel.sea_enabled then
        Babel.sea_disc_to_space(head)
      end
    end,
    'Babel.hyphenate')
  }}
\endgroup
\def\bbl@provide@intraspace{%
  \bbl@ifunset{bbl@intsp@\languagename}{}%
    {\expandafter\ifx\csname bbl@intsp@\languagename\endcsname\@empty\else
       \bbl@xin@{/c}{/\bbl@cl{lnbrk}}%
       \ifin@           % cjk
         \bbl@cjkintraspace
         \directlua{
             Babel.locale_props = Babel.locale_props or {}
             Babel.locale_props[\the\localeid].linebreak = 'c'
         }%
         \bbl@exp{\\\bbl@intraspace\bbl@cl{intsp}\\\@@}%
         \ifx\bbl@KVP@intrapenalty\@nnil
           \bbl@intrapenalty0\@@
         \fi
       \else            % sea
         \bbl@seaintraspace
         \bbl@exp{\\\bbl@intraspace\bbl@cl{intsp}\\\@@}%
         \directlua{
            Babel.sea_ranges = Babel.sea_ranges or {}
            Babel.set_chranges('\bbl@cl{sbcp}',
                               '\bbl@cl{chrng}')
         }%
         \ifx\bbl@KVP@intrapenalty\@nnil
           \bbl@intrapenalty0\@@
         \fi
       \fi
     \fi
     \ifx\bbl@KVP@intrapenalty\@nnil\else
       \expandafter\bbl@intrapenalty\bbl@KVP@intrapenalty\@@
     \fi}}
\ifnum\bbl@bidimode>100 \ifnum\bbl@bidimode<200
\def\bblar@chars{%
  0628,0629,062A,062B,062C,062D,062E,062F,0630,0631,0632,0633,%
  0634,0635,0636,0637,0638,0639,063A,063B,063C,063D,063E,063F,%
  0640,0641,0642,0643,0644,0645,0646,0647,0649}
\def\bblar@elongated{%
  0626,0628,062A,062B,0633,0634,0635,0636,063B,%
  063C,063D,063E,063F,0641,0642,0643,0644,0646,%
  0649,064A}
\begingroup
  \catcode`_=11 \catcode`:=11
  \gdef\bblar@nofswarn{\gdef\msg_warning:nnx##1##2##3{}}
\endgroup
\gdef\bbl@arabicjust{%
  \let\bbl@arabicjust\relax
  \newattribute\bblar@kashida
  \directlua{ Babel.attr_kashida = luatexbase.registernumber'bblar@kashida' }%
  \bblar@kashida=\z@
  \bbl@patchfont{{\bbl@parsejalt}}%
  \directlua{
    Babel.arabic.elong_map   = Babel.arabic.elong_map or {}
    Babel.arabic.elong_map[\the\localeid]   = {}
    luatexbase.add_to_callback('post_linebreak_filter',
      Babel.arabic.justify, 'Babel.arabic.justify')
    luatexbase.add_to_callback('hpack_filter',
      Babel.arabic.justify_hbox, 'Babel.arabic.justify_hbox')
  }}%
\def\bblar@fetchjalt#1#2#3#4{%
  \bbl@exp{\\\bbl@foreach{#1}}{%
    \bbl@ifunset{bblar@JE@##1}%
      {\setbox\z@\hbox{\textdir TRT ^^^^200d\char"##1#2}}%
      {\setbox\z@\hbox{\textdir TRT ^^^^200d\char"\@nameuse{bblar@JE@##1}#2}}%
    \directlua{%
      local last = nil
      for item in node.traverse(tex.box[0].head) do
        if item.id == node.id'glyph' and item.char > 0x600 and
            not (item.char == 0x200D) then
          last = item
        end
      end
      Babel.arabic.#3['##1#4'] = last.char
    }}}
\gdef\bbl@parsejalt{%
  \ifx\addfontfeature\@undefined\else
    \bbl@xin@{/e}{/\bbl@cl{lnbrk}}%
    \ifin@
      \directlua{%
        if Babel.arabic.elong_map[\the\localeid][\fontid\font] == nil then
          Babel.arabic.elong_map[\the\localeid][\fontid\font] = {}
          tex.print([[\string\csname\space bbl@parsejalti\endcsname]])
        end
      }%
    \fi
  \fi}
\gdef\bbl@parsejalti{%
  \begingroup
    \let\bbl@parsejalt\relax     % To avoid infinite loop
    \edef\bbl@tempb{\fontid\font}%
    \bblar@nofswarn
    \bblar@fetchjalt\bblar@elongated{}{from}{}%
    \bblar@fetchjalt\bblar@chars{^^^^064a}{from}{a}% Alef maksura
    \bblar@fetchjalt\bblar@chars{^^^^0649}{from}{y}% Yeh
    \addfontfeature{RawFeature=+jalt}%
    % \@namedef{bblar@JE@0643}{06AA}% todo: catch medial kaf
    \bblar@fetchjalt\bblar@elongated{}{dest}{}%
    \bblar@fetchjalt\bblar@chars{^^^^064a}{dest}{a}%
    \bblar@fetchjalt\bblar@chars{^^^^0649}{dest}{y}%
      \directlua{%
        for k, v in pairs(Babel.arabic.from) do
          if Babel.arabic.dest[k] and
              not (Babel.arabic.from[k] == Babel.arabic.dest[k]) then
            Babel.arabic.elong_map[\the\localeid][\bbl@tempb]
               [Babel.arabic.from[k]] = Babel.arabic.dest[k]
          end
        end
      }%
  \endgroup}
\begingroup
\catcode`#=11
\catcode`~=11
\directlua{

Babel.arabic = Babel.arabic or {}
Babel.arabic.from = {}
Babel.arabic.dest = {}
Babel.arabic.justify_factor = 0.95
Babel.arabic.justify_enabled = true
Babel.arabic.kashida_limit = -1

function Babel.arabic.justify(head)
  if not Babel.arabic.justify_enabled then return head end
  for line in node.traverse_id(node.id'hlist', head) do
    Babel.arabic.justify_hlist(head, line)
  end
  % In case the very first item is a line (eg, in \vbox):
  while head.prev do head = head.prev end
  return head
end

function Babel.arabic.justify_hbox(head, gc, size, pack)
  local has_inf = false
  if Babel.arabic.justify_enabled and pack == 'exactly' then
    for n in node.traverse_id(12, head) do
      if n.stretch_order > 0 then has_inf = true end
    end
    if not has_inf then
      Babel.arabic.justify_hlist(head, nil, gc, size, pack)
    end
  end
  return head
end

function Babel.arabic.justify_hlist(head, line, gc, size, pack)
  local d, new
  local k_list, k_item, pos_inline
  local width, width_new, full, k_curr, wt_pos, goal, shift
  local subst_done = false
  local elong_map = Babel.arabic.elong_map
  local cnt
  local last_line
  local GLYPH = node.id'glyph'
  local KASHIDA = Babel.attr_kashida
  local LOCALE = Babel.attr_locale

  if line == nil then
    line = {}
    line.glue_sign = 1
    line.glue_order = 0
    line.head = head
    line.shift = 0
    line.width = size
  end

  % Exclude last line. todo. But-- it discards one-word lines, too!
  % ? Look for glue = 12:15
  if (line.glue_sign == 1 and line.glue_order == 0) then
    elongs = {}     % Stores elongated candidates of each line
    k_list = {}     % And all letters with kashida
    pos_inline = 0  % Not yet used

    for n in node.traverse_id(GLYPH, line.head) do
      pos_inline = pos_inline + 1 % To find where it is. Not used.

      % Elongated glyphs
      if elong_map then
        local locale = node.get_attribute(n, LOCALE)
        if elong_map[locale] and elong_map[locale][n.font] and
            elong_map[locale][n.font][n.char] then
          table.insert(elongs, {node = n, locale = locale} )
          node.set_attribute(n.prev, KASHIDA, 0)
        end
      end

      % Tatwil. First create a list of nodes marked with kashida. The
      % rest of nodes can be ignored. The list of used weigths is build
      % when transforms with the key kashida= are declared.
      if Babel.kashida_wts then
        local k_wt = node.get_attribute(n, KASHIDA)
        if k_wt > 0 then % todo. parameter for multi inserts
          table.insert(k_list, {node = n, weight = k_wt, pos = pos_inline})
        end
      end

    end % of node.traverse_id

    if #elongs == 0 and #k_list == 0 then goto next_line end
    full  = line.width
    shift = line.shift
    goal  = full * Babel.arabic.justify_factor % A bit crude
    width = node.dimensions(line.head)    % The 'natural' width

    % == Elongated ==
    % Original idea taken from 'chikenize'
    while (#elongs > 0 and width < goal) do
      subst_done = true
      local x = #elongs
      local curr = elongs[x].node
      local oldchar = curr.char
      curr.char = elong_map[elongs[x].locale][curr.font][curr.char]
      width = node.dimensions(line.head)  % Check if the line is too wide
      % Substitute back if the line would be too wide and break:
      if width > goal then
        curr.char = oldchar
        break
      end
      % If continue, pop the just substituted node from the list:
      table.remove(elongs, x)
    end

    % == Tatwil ==
    % Traverse the kashida node list so many times as required, until
    % the line if filled. The first pass adds a tatweel after each
    % node with kashida in the line, the second pass adds another one,
    % and so on. In each pass, add first the kashida with the highest
    % weight, then with lower weight and so on.
    if #k_list == 0 then goto next_line end

    width = node.dimensions(line.head)    % The 'natural' width
    k_curr = #k_list % Traverse backwards, from the end
    wt_pos = 1

    while width < goal do
      subst_done = true
      k_item = k_list[k_curr].node
      if k_list[k_curr].weight == Babel.kashida_wts[wt_pos] then
        d = node.copy(k_item)
        d.char = 0x0640
        d.yoffset = 0 % TODO. From the prev char. But 0 seems safe.
        d.xoffset = 0
        line.head, new = node.insert_after(line.head, k_item, d)
        width_new = node.dimensions(line.head)
        if width > goal or width == width_new then
          node.remove(line.head, new) % Better compute before
          break
        end
        if Babel.fix_diacr then
          Babel.fix_diacr(k_item.next)
        end
        width = width_new
      end
      if k_curr == 1 then
        k_curr = #k_list
        wt_pos = (wt_pos >= table.getn(Babel.kashida_wts)) and 1 or wt_pos+1
      else
        k_curr = k_curr - 1
      end
    end

    % Limit the number of tatweel by removing them. Not very efficient,
    % but it does the job in a quite predictable way.
    if Babel.arabic.kashida_limit > -1 then
      cnt = 0
      for n in node.traverse_id(GLYPH, line.head) do
        if n.char == 0x0640 then
          cnt = cnt + 1
          if cnt > Babel.arabic.kashida_limit then
            node.remove(line.head, n)
          end
        else
          cnt = 0
        end
      end
    end

    ::next_line::

    % Must take into account marks and ins, see luatex manual.
    % Have to be executed only if there are changes. Investigate
    % what's going on exactly.
    if subst_done and not gc then
      d = node.hpack(line.head, full, 'exactly')
      d.shift = shift
      node.insert_before(head, line, d)
      node.remove(head, line)
    end
  end % if process line
end
}
\endgroup
\fi\fi % ends Arabic just block: \ifnum\bbl@bidimode>100...
\def\bbl@scr@node@list{%
 ,Armenian,Coptic,Cyrillic,Georgian,,Glagolitic,Gothic,%
 ,Greek,Latin,Old Church Slavonic Cyrillic,}
\ifnum\bbl@bidimode=102 % bidi-r
   \bbl@add\bbl@scr@node@list{Arabic,Hebrew,Syriac}
\fi
\def\bbl@set@renderer{%
  \bbl@xin@{\bbl@cl{sname}}{\bbl@scr@node@list}%
  \ifin@
    \let\bbl@unset@renderer\relax
  \else
    \bbl@exp{%
       \def\\\bbl@unset@renderer{%
         \def\<g__fontspec_default_fontopts_clist>{%
           \[g__fontspec_default_fontopts_clist]}}%
       \def\<g__fontspec_default_fontopts_clist>{%
         Renderer=Harfbuzz,\[g__fontspec_default_fontopts_clist]}}%
  \fi}
\bbl@trace{Font handling with fontspec}
\AddBabelHook{babel-fontspec}{afterextras}{\bbl@switchfont}
\AddBabelHook{babel-fontspec}{beforestart}{\bbl@ckeckstdfonts}
\DisableBabelHook{babel-fontspec}
\@onlypreamble\babelfont
\ifx\NewDocumentCommand\@undefined\else % Not plain
  \NewDocumentCommand\babelfont{O{}mO{}mO{}}{%
    \bbl@bblfont@o[#1]{#2}[#3,#5]{#4}}
\fi
\newcommand\bbl@bblfont@o[2][]{%  1=langs/scripts 2=fam
  \ifx\fontspec\@undefined
    \usepackage{fontspec}%
  \fi
  \EnableBabelHook{babel-fontspec}%
  \edef\bbl@tempa{#1}%
  \def\bbl@tempb{#2}%  Used by \bbl@bblfont
  \bbl@bblfont}
\newcommand\bbl@bblfont[2][]{% 1=features 2=fontname, @font=rm|sf|tt
  \bbl@ifunset{\bbl@tempb family}%
    {\bbl@providefam{\bbl@tempb}}%
    {}%
  % For the default font, just in case:
  \bbl@ifunset{bbl@lsys@\languagename}{\bbl@provide@lsys{\languagename}}{}%
  \expandafter\bbl@ifblank\expandafter{\bbl@tempa}%
    {\bbl@csarg\edef{\bbl@tempb dflt@}{<>{#1}{#2}}% save bbl@rmdflt@
     \bbl@exp{%
       \let\<bbl@\bbl@tempb dflt@\languagename>\<bbl@\bbl@tempb dflt@>%
       \\\bbl@font@set\<bbl@\bbl@tempb dflt@\languagename>%
                      \<\bbl@tempb default>\<\bbl@tempb family>}}%
    {\bbl@foreach\bbl@tempa{% i.e., bbl@rmdflt@lang / *scrt
       \bbl@csarg\def{\bbl@tempb dflt@##1}{<>{#1}{#2}}}}}%
\def\bbl@providefam#1{%
  \bbl@exp{%
    \\\newcommand\<#1default>{}% Just define it
    \\\bbl@add@list\\\bbl@font@fams{#1}%
    \\\NewHook{#1family}%
    \\\DeclareRobustCommand\<#1family>{%
      \\\not@math@alphabet\<#1family>\relax
      % \\\prepare@family@series@update{#1}\<#1default>% TODO. Fails
      \\\fontfamily\<#1default>%
      \\\UseHook{#1family}%
      \\\selectfont}%
    \\\DeclareTextFontCommand{\<text#1>}{\<#1family>}}}
\def\bbl@nostdfont#1{%
  \bbl@once{nostdfam-\f@family}%
    {\bbl@infowarn{The current font is not a babel standard family:\\%
       #1%
       \fontname\font\\%
       There is nothing intrinsically wrong, and you can\\%,
       ignore this message altogether if you do not need\\%
       this font. If they are used in the document, be aware\\%
       'babel' will not set Script and Language for it, so\\%
       you may consider defining a new family with \string\babelfont.\\%
       See the manual for further details about \string\babelfont.
       Reported}}
   {}}%
\gdef\bbl@switchfont{%
  \bbl@ifunset{bbl@lsys@\languagename}{\bbl@provide@lsys{\languagename}}{}%
  \bbl@exp{%  e.g., Arabic -> arabic
    \lowercase{\edef\\\bbl@tempa{\bbl@cl{sname}}}}%
  \bbl@foreach\bbl@font@fams{%
    \bbl@ifunset{bbl@##1dflt@\languagename}%    (1) language?
      {\bbl@ifunset{bbl@##1dflt@*\bbl@tempa}%   (2) from script?
         {\bbl@ifunset{bbl@##1dflt@}%           2=F - (3) from generic?
           {}%                                  123=F - nothing!
           {\bbl@exp{%                          3=T - from generic
              \global\let\<bbl@##1dflt@\languagename>%
                         \<bbl@##1dflt@>}}}%
         {\bbl@exp{%                            2=T - from script
            \global\let\<bbl@##1dflt@\languagename>%
                       \<bbl@##1dflt@*\bbl@tempa>}}}%
      {}}%                               1=T - language, already defined
  \def\bbl@tempa{\bbl@nostdfont{}}%
  \bbl@foreach\bbl@font@fams{%     don't gather with prev for
    \bbl@ifunset{bbl@##1dflt@\languagename}%
      {\bbl@cs{famrst@##1}%
       \global\bbl@csarg\let{famrst@##1}\relax}%
      {\bbl@exp{% order is relevant.
         \\\bbl@add\\\originalTeX{%
           \\\bbl@font@rst{\bbl@cl{##1dflt}}%
                          \<##1default>\<##1family>{##1}}%
         \\\bbl@font@set\<bbl@##1dflt@\languagename>% the main part!
                        \<##1default>\<##1family>}}}%
  \bbl@ifrestoring{}{\bbl@tempa}}%
\ifx\f@family\@undefined\else   % if latex
  \ifcase\bbl@engine            % if pdftex
    \let\bbl@ckeckstdfonts\relax
  \else
    \def\bbl@ckeckstdfonts{%
      \begingroup
        \global\let\bbl@ckeckstdfonts\relax
        \let\bbl@tempa\@empty
        \bbl@foreach\bbl@font@fams{%
          \bbl@ifunset{bbl@##1dflt@}%
            {\@nameuse{##1family}%
             \bbl@csarg\gdef{WFF@\f@family}{}% Flag
             \bbl@exp{\\\bbl@add\\\bbl@tempa{* \<##1family>= \f@family\\\\%
                \space\space\fontname\font\\\\}}%
             \bbl@csarg\xdef{##1dflt@}{\f@family}%
             \expandafter\xdef\csname ##1default\endcsname{\f@family}}%
            {}}%
        \ifx\bbl@tempa\@empty\else
          \bbl@infowarn{The following font families will use the default\\%
            settings for all or some languages:\\%
            \bbl@tempa
            There is nothing intrinsically wrong with it, but\\%
            'babel' will no set Script and Language, which could\\%
             be relevant in some languages. If your document uses\\%
             these families, consider redefining them with \string\babelfont.\\%
            Reported}%
        \fi
      \endgroup}
  \fi
\fi
\def\bbl@font@set#1#2#3{% e.g., \bbl@rmdflt@lang \rmdefault \rmfamily
  \bbl@xin@{<>}{#1}%
  \ifin@
    \bbl@exp{\\\bbl@fontspec@set\\#1\expandafter\@gobbletwo#1\\#3}%
  \fi
  \bbl@exp{%              'Unprotected' macros return prev values
    \def\\#2{#1}%         e.g., \rmdefault{\bbl@rmdflt@lang}
    \\\bbl@ifsamestring{#2}{\f@family}%
      {\\#3%
       \\\bbl@ifsamestring{\f@series}{\bfdefault}{\\\bfseries}{}%
       \let\\\bbl@tempa\relax}%
      {}}}
\def\bbl@fontspec@set#1#2#3#4{% eg \bbl@rmdflt@lang fnt-opt fnt-nme \xxfamily
  \let\bbl@tempe\bbl@mapselect
  \edef\bbl@tempb{\bbl@stripslash#4/}% Catcodes hack (better pass it).
  \bbl@exp{\\\bbl@replace\\\bbl@tempb{\bbl@stripslash\family/}{}}%
  \let\bbl@mapselect\relax
  \let\bbl@temp@fam#4%       e.g., '\rmfamily', to be restored below
  \let#4\@empty      %       Make sure \renewfontfamily is valid
  \bbl@set@renderer
  \bbl@exp{%
    \let\\\bbl@temp@pfam\<\bbl@stripslash#4\space>% e.g., '\rmfamily '
    \<keys_if_exist:nnF>{fontspec-opentype}{Script/\bbl@cl{sname}}%
      {\\\newfontscript{\bbl@cl{sname}}{\bbl@cl{sotf}}}%
    \<keys_if_exist:nnF>{fontspec-opentype}{Language/\bbl@cl{lname}}%
      {\\\newfontlanguage{\bbl@cl{lname}}{\bbl@cl{lotf}}}%
    \\\renewfontfamily\\#4%
      [\bbl@cl{lsys},% xetex removes unknown features :-(
       \ifcase\bbl@engine\or RawFeature={family=\bbl@tempb},\fi
       #2]}{#3}% i.e., \bbl@exp{..}{#3}
  \bbl@unset@renderer
  \begingroup
     #4%
     \xdef#1{\f@family}%     e.g., \bbl@rmdflt@lang{FreeSerif(0)}
  \endgroup
  \bbl@xin@{\string>\string s\string s\string u\string b\string*}%
    {\expandafter\meaning\csname TU/#1/bx/sc\endcsname}%
  \ifin@
    \global\bbl@ccarg\let{TU/#1/bx/sc}{TU/#1/b/sc}%
  \fi
  \bbl@xin@{\string>\string s\string s\string u\string b\string*}%
    {\expandafter\meaning\csname TU/#1/bx/scit\endcsname}%
  \ifin@
    \global\bbl@ccarg\let{TU/#1/bx/scit}{TU/#1/b/scit}%
  \fi
  \let#4\bbl@temp@fam
  \bbl@exp{\let\<\bbl@stripslash#4\space>}\bbl@temp@pfam
  \let\bbl@mapselect\bbl@tempe}%
\def\bbl@font@rst#1#2#3#4{%
  \bbl@csarg\def{famrst@#4}{\bbl@font@set{#1}#2#3}}
\def\bbl@font@fams{rm,sf,tt}
\directlua{% DL6
Babel.script_blocks = {
  ['dflt'] = {},
  ['Arab'] = {{0x0600, 0x06FF}, {0x08A0, 0x08FF}, {0x0750, 0x077F},
              {0xFE70, 0xFEFF}, {0xFB50, 0xFDFF}, {0x1EE00, 0x1EEFF}},
  ['Armn'] = {{0x0530, 0x058F}},
  ['Beng'] = {{0x0980, 0x09FF}},
  ['Cher'] = {{0x13A0, 0x13FF}, {0xAB70, 0xABBF}},
  ['Copt'] = {{0x03E2, 0x03EF}, {0x2C80, 0x2CFF}, {0x102E0, 0x102FF}},
  ['Cyrl'] = {{0x0400, 0x04FF}, {0x0500, 0x052F}, {0x1C80, 0x1C8F},
              {0x2DE0, 0x2DFF}, {0xA640, 0xA69F}},
  ['Deva'] = {{0x0900, 0x097F}, {0xA8E0, 0xA8FF}},
  ['Ethi'] = {{0x1200, 0x137F}, {0x1380, 0x139F}, {0x2D80, 0x2DDF},
              {0xAB00, 0xAB2F}},
  ['Geor'] = {{0x10A0, 0x10FF}, {0x2D00, 0x2D2F}},
  % Don't follow strictly Unicode, which places some Coptic letters in
  % the 'Greek and Coptic' block
  ['Grek'] = {{0x0370, 0x03E1}, {0x03F0, 0x03FF}, {0x1F00, 0x1FFF}},
  ['Hans'] = {{0x2E80, 0x2EFF}, {0x3000, 0x303F}, {0x31C0, 0x31EF},
              {0x3300, 0x33FF}, {0x3400, 0x4DBF}, {0x4E00, 0x9FFF},
              {0xF900, 0xFAFF}, {0xFE30, 0xFE4F}, {0xFF00, 0xFFEF},
              {0x20000, 0x2A6DF}, {0x2A700, 0x2B73F},
              {0x2B740, 0x2B81F}, {0x2B820, 0x2CEAF},
              {0x2CEB0, 0x2EBEF}, {0x2F800, 0x2FA1F}},
  ['Hebr'] = {{0x0590, 0x05FF},
              {0xFB1F, 0xFB4E}}, % <- Includes some <reserved>
  ['Jpan'] = {{0x3000, 0x303F}, {0x3040, 0x309F}, {0x30A0, 0x30FF},
              {0x4E00, 0x9FAF}, {0xFF00, 0xFFEF}},
  ['Khmr'] = {{0x1780, 0x17FF}, {0x19E0, 0x19FF}},
  ['Knda'] = {{0x0C80, 0x0CFF}},
  ['Kore'] = {{0x1100, 0x11FF}, {0x3000, 0x303F}, {0x3130, 0x318F},
              {0x4E00, 0x9FAF}, {0xA960, 0xA97F}, {0xAC00, 0xD7AF},
              {0xD7B0, 0xD7FF}, {0xFF00, 0xFFEF}},
  ['Laoo'] = {{0x0E80, 0x0EFF}},
  ['Latn'] = {{0x0000, 0x007F}, {0x0080, 0x00FF}, {0x0100, 0x017F},
              {0x0180, 0x024F}, {0x1E00, 0x1EFF}, {0x2C60, 0x2C7F},
              {0xA720, 0xA7FF}, {0xAB30, 0xAB6F}},
  ['Mahj'] = {{0x11150, 0x1117F}},
  ['Mlym'] = {{0x0D00, 0x0D7F}},
  ['Mymr'] = {{0x1000, 0x109F}, {0xAA60, 0xAA7F}, {0xA9E0, 0xA9FF}},
  ['Orya'] = {{0x0B00, 0x0B7F}},
  ['Sinh'] = {{0x0D80, 0x0DFF}, {0x111E0, 0x111FF}},
  ['Syrc'] = {{0x0700, 0x074F}, {0x0860, 0x086F}},
  ['Taml'] = {{0x0B80, 0x0BFF}},
  ['Telu'] = {{0x0C00, 0x0C7F}},
  ['Tfng'] = {{0x2D30, 0x2D7F}},
  ['Thai'] = {{0x0E00, 0x0E7F}},
  ['Tibt'] = {{0x0F00, 0x0FFF}},
  ['Vaii'] = {{0xA500, 0xA63F}},
  ['Yiii'] = {{0xA000, 0xA48F}, {0xA490, 0xA4CF}}
}

Babel.script_blocks.Cyrs = Babel.script_blocks.Cyrl
Babel.script_blocks.Hant = Babel.script_blocks.Hans
Babel.script_blocks.Kana = Babel.script_blocks.Jpan

function Babel.locale_map(head)
  if not Babel.locale_mapped then return head end

  local LOCALE = Babel.attr_locale
  local GLYPH = node.id('glyph')
  local inmath = false
  local toloc_save
  for item in node.traverse(head) do
    local toloc
    if not inmath and item.id == GLYPH then
      % Optimization: build a table with the chars found
      if Babel.chr_to_loc[item.char] then
        toloc = Babel.chr_to_loc[item.char]
      else
        for lc, maps in pairs(Babel.loc_to_scr) do
          for _, rg in pairs(maps) do
            if item.char >= rg[1] and item.char <= rg[2] then
              Babel.chr_to_loc[item.char] = lc
              toloc = lc
              break
            end
          end
        end
        % Treat composite chars in a different fashion, because they
        % 'inherit' the previous locale.
        if (item.char >= 0x0300 and item.char <= 0x036F) or
           (item.char >= 0x1AB0 and item.char <= 0x1AFF) or
           (item.char >= 0x1DC0 and item.char <= 0x1DFF) then
             Babel.chr_to_loc[item.char] = -2000
             toloc = -2000
        end
        if not toloc then
          Babel.chr_to_loc[item.char] = -1000
        end
      end
      if toloc == -2000 then
        toloc = toloc_save
      elseif toloc == -1000 then
        toloc = nil
      end
      if toloc and Babel.locale_props[toloc] and
          Babel.locale_props[toloc].letters and
          tex.getcatcode(item.char) \string~= 11 then
        toloc = nil
      end
      if toloc and Babel.locale_props[toloc].script
          and Babel.locale_props[node.get_attribute(item, LOCALE)].script
          and Babel.locale_props[toloc].script ==
            Babel.locale_props[node.get_attribute(item, LOCALE)].script then
        toloc = nil
      end
      if toloc then
        if Babel.locale_props[toloc].lg then
          item.lang = Babel.locale_props[toloc].lg
          node.set_attribute(item, LOCALE, toloc)
        end
        if Babel.locale_props[toloc]['/'..item.font] then
          item.font = Babel.locale_props[toloc]['/'..item.font]
        end
      end
      toloc_save = toloc
    elseif not inmath and item.id == 7 then % Apply recursively
      item.replace = item.replace and Babel.locale_map(item.replace)
      item.pre     = item.pre and Babel.locale_map(item.pre)
      item.post    = item.post and Babel.locale_map(item.post)
    elseif item.id == node.id'math' then
      inmath = (item.subtype == 0)
    end
  end
  return head
end
}
\newcommand\babelcharproperty[1]{%
  \count@=#1\relax
  \ifvmode
    \expandafter\bbl@chprop
  \else
    \bbl@error{charproperty-only-vertical}{}{}{}%
  \fi}
\newcommand\bbl@chprop[3][\the\count@]{%
  \@tempcnta=#1\relax
  \bbl@ifunset{bbl@chprop@#2}% {unknown-char-property}
    {\bbl@error{unknown-char-property}{}{#2}{}}%
    {}%
  \loop
    \bbl@cs{chprop@#2}{#3}%
  \ifnum\count@<\@tempcnta
    \advance\count@\@ne
  \repeat}
\def\bbl@chprop@direction#1{%
  \directlua{
    Babel.characters[\the\count@] =  Babel.characters[\the\count@] or {}
    Babel.characters[\the\count@]['d'] = '#1'
  }}
\let\bbl@chprop@bc\bbl@chprop@direction
\def\bbl@chprop@mirror#1{%
  \directlua{
    Babel.characters[\the\count@] =  Babel.characters[\the\count@] or {}
    Babel.characters[\the\count@]['m'] = '\number#1'
  }}
\let\bbl@chprop@bmg\bbl@chprop@mirror
\def\bbl@chprop@linebreak#1{%
  \directlua{
    Babel.cjk_characters[\the\count@] = Babel.cjk_characters[\the\count@] or {}
    Babel.cjk_characters[\the\count@]['c'] = '#1'
  }}
\let\bbl@chprop@lb\bbl@chprop@linebreak
\def\bbl@chprop@locale#1{%
  \directlua{
    Babel.chr_to_loc = Babel.chr_to_loc or {}
    Babel.chr_to_loc[\the\count@] =
      \bbl@ifblank{#1}{-1000}{\the\bbl@cs{id@@#1}}\space
  }}
\directlua{% DL7
  Babel.nohyphenation = \the\l@nohyphenation
}
\begingroup
\catcode`\~=12
\catcode`\%=12
\catcode`\&=14
\catcode`\|=12
\gdef\babelprehyphenation{&%
  \@ifnextchar[{\bbl@settransform{0}}{\bbl@settransform{0}[]}}
\gdef\babelposthyphenation{&%
  \@ifnextchar[{\bbl@settransform{1}}{\bbl@settransform{1}[]}}
\gdef\bbl@settransform#1[#2]#3#4#5{&%
  \ifcase#1
    \bbl@activateprehyphen
  \or
    \bbl@activateposthyphen
  \fi
  \begingroup
    \def\babeltempa{\bbl@add@list\babeltempb}&%
    \let\babeltempb\@empty
    \def\bbl@tempa{#5}&%
    \bbl@replace\bbl@tempa{,}{ ,}&% TODO. Ugly trick to preserve {}
    \expandafter\bbl@foreach\expandafter{\bbl@tempa}{&%
      \bbl@ifsamestring{##1}{remove}&%
        {\bbl@add@list\babeltempb{nil}}&%
        {\directlua{
           local rep = [=[##1]=]
           local three_args = '%s*=%s*([%-%d%.%a{}|]+)%s+([%-%d%.%a{}|]+)%s+([%-%d%.%a{}|]+)'
           &% Numeric passes directly: kern, penalty...
           rep = rep:gsub('^%s*(remove)%s*$', 'remove = true')
           rep = rep:gsub('^%s*(insert)%s*,', 'insert = true, ')
           rep = rep:gsub('^%s*(after)%s*,', 'after = true, ')
           rep = rep:gsub('(string)%s*=%s*([^%s,]*)', Babel.capture_func)
           rep = rep:gsub('node%s*=%s*(%a+)%s*(%a*)', Babel.capture_node)
           rep = rep:gsub( '(norule)' .. three_args,
               'norule = {' .. '%2, %3, %4' .. '}')
           if #1 == 0 or #1 == 2 then
             rep = rep:gsub( '(space)' .. three_args,
               'space = {' .. '%2, %3, %4' .. '}')
             rep = rep:gsub( '(spacefactor)' .. three_args,
               'spacefactor = {' .. '%2, %3, %4' .. '}')
             rep = rep:gsub('(kashida)%s*=%s*([^%s,]*)', Babel.capture_kashida)
             &% Transform values
             rep, n = rep:gsub( '{([%a%-%.]+)|([%a%_%.]+)}',
               function(v,d)
                 return string.format (
                   '{\the\csname bbl@id@@#3\endcsname,"%s",%s}',
                   v,
                   load( 'return Babel.locale_props'..
                         '[\the\csname bbl@id@@#3\endcsname].' .. d)() )
               end )
             rep, n = rep:gsub( '{([%a%-%.]+)|([%-%d%.]+)}',
              '{\the\csname bbl@id@@#3\endcsname,"%1",%2}')
           end
           if #1 == 1 then
             rep = rep:gsub(    '(no)%s*=%s*([^%s,]*)', Babel.capture_func)
             rep = rep:gsub(   '(pre)%s*=%s*([^%s,]*)', Babel.capture_func)
             rep = rep:gsub(  '(post)%s*=%s*([^%s,]*)', Babel.capture_func)
           end
           tex.print([[\string\babeltempa{{]] .. rep .. [[}}]])
         }}}&%
    \bbl@foreach\babeltempb{&%
      \bbl@forkv{{##1}}{&%
        \in@{,####1,}{,nil,step,data,remove,insert,string,no,pre,no,&%
          post,penalty,kashida,space,spacefactor,kern,node,after,norule,}&%
        \ifin@\else
          \bbl@error{bad-transform-option}{####1}{}{}&%
        \fi}}&%
    \let\bbl@kv@attribute\relax
    \let\bbl@kv@label\relax
    \let\bbl@kv@fonts\@empty
    \let\bbl@kv@prepend\relax
    \bbl@forkv{#2}{\bbl@csarg\edef{kv@##1}{##2}}&%
    \ifx\bbl@kv@fonts\@empty\else\bbl@settransfont\fi
    \ifx\bbl@kv@attribute\relax
      \ifx\bbl@kv@label\relax\else
        \bbl@exp{\\\bbl@trim@def\\\bbl@kv@fonts{\bbl@kv@fonts}}&%
        \bbl@replace\bbl@kv@fonts{ }{,}&%
        \edef\bbl@kv@attribute{bbl@ATR@\bbl@kv@label @#3@\bbl@kv@fonts}&%
        \count@\z@
        \def\bbl@elt##1##2##3{&%
          \bbl@ifsamestring{#3,\bbl@kv@label}{##1,##2}&%
            {\bbl@ifsamestring{\bbl@kv@fonts}{##3}&%
               {\count@\@ne}&%
               {\bbl@error{font-conflict-transforms}{}{}{}}}&%
            {}}&%
        \bbl@transfont@list
        \ifnum\count@=\z@
          \bbl@exp{\global\\\bbl@add\\\bbl@transfont@list
            {\\\bbl@elt{#3}{\bbl@kv@label}{\bbl@kv@fonts}}}&%
        \fi
        \bbl@ifunset{\bbl@kv@attribute}&%
          {\global\bbl@carg\newattribute{\bbl@kv@attribute}}&%
          {}&%
        \global\bbl@carg\setattribute{\bbl@kv@attribute}\@ne
      \fi
    \else
      \edef\bbl@kv@attribute{\expandafter\bbl@stripslash\bbl@kv@attribute}&%
    \fi
    \directlua{
      local lbkr = Babel.linebreaking.replacements[#1]
      local u = unicode.utf8
      local id, attr, label
      if #1 == 0 then
        id = \the\csname bbl@id@@#3\endcsname\space
      else
        id = \the\csname l@#3\endcsname\space
      end
      \ifx\bbl@kv@attribute\relax
        attr = -1
      \else
        attr = luatexbase.registernumber'\bbl@kv@attribute'
      \fi
      \ifx\bbl@kv@label\relax\else  &% Same refs:
        label = [==[\bbl@kv@label]==]
      \fi
      &% Convert pattern:
      local patt = string.gsub([==[#4]==], '%s', '')
      if #1 == 0 then
        patt = string.gsub(patt, '|', ' ')
      end
      if not u.find(patt, '()', nil, true) then
        patt = '()' .. patt .. '()'
      end
      if #1 == 1 then
        patt = string.gsub(patt, '%(%)%^', '^()')
        patt = string.gsub(patt, '%$%(%)', '()$')
      end
      patt = u.gsub(patt, '{(.)}',
             function (n)
               return '%' .. (tonumber(n) and (tonumber(n)+1) or n)
             end)
      patt = u.gsub(patt, '{(%x%x%x%x+)}',
             function (n)
               return u.gsub(u.char(tonumber(n, 16)), '(%p)', '%%%1')
             end)
      lbkr[id] = lbkr[id] or {}
      table.insert(lbkr[id], \ifx\bbl@kv@prepend\relax\else 1,\fi
        { label=label, attr=attr, pattern=patt, replace={\babeltempb} })
    }&%
  \endgroup}
\endgroup
\let\bbl@transfont@list\@empty
\def\bbl@settransfont{%
  \global\let\bbl@settransfont\relax % Execute only once
  \gdef\bbl@transfont{%
    \def\bbl@elt####1####2####3{%
      \bbl@ifblank{####3}%
         {\count@\tw@}% Do nothing if no fonts
         {\count@\z@
          \bbl@vforeach{####3}{%
            \def\bbl@tempd{########1}%
            \edef\bbl@tempe{\bbl@transfam/\f@series/\f@shape}%
            \ifx\bbl@tempd\bbl@tempe
              \count@\@ne
            \else\ifx\bbl@tempd\bbl@transfam
              \count@\@ne
            \fi\fi}%
         \ifcase\count@
           \bbl@csarg\unsetattribute{ATR@####2@####1@####3}%
         \or
           \bbl@csarg\setattribute{ATR@####2@####1@####3}\@ne
         \fi}}%
      \bbl@transfont@list}%
  \AddToHook{selectfont}{\bbl@transfont}% Hooks are global.
  \gdef\bbl@transfam{-unknown-}%
  \bbl@foreach\bbl@font@fams{%
    \AddToHook{##1family}{\def\bbl@transfam{##1}}%
    \bbl@ifsamestring{\@nameuse{##1default}}\familydefault
      {\xdef\bbl@transfam{##1}}%
      {}}}
\DeclareRobustCommand\enablelocaletransform[1]{%
  \bbl@ifunset{bbl@ATR@#1@\languagename @}%
    {\bbl@error{transform-not-available}{#1}{}{}}%
    {\bbl@csarg\setattribute{ATR@#1@\languagename @}\@ne}}
\DeclareRobustCommand\disablelocaletransform[1]{%
  \bbl@ifunset{bbl@ATR@#1@\languagename @}%
    {\bbl@error{transform-not-available-b}{#1}{}{}}%
    {\bbl@csarg\unsetattribute{ATR@#1@\languagename @}}}
\def\bbl@activateposthyphen{%
  \let\bbl@activateposthyphen\relax
  \ifx\bbl@attr@hboxed\@undefined
    \newattribute\bbl@attr@hboxed
  \fi
  \directlua{
    require('babel-transforms.lua')
    Babel.linebreaking.add_after(Babel.post_hyphenate_replace)
  }}
\def\bbl@activateprehyphen{%
  \let\bbl@activateprehyphen\relax
  \ifx\bbl@attr@hboxed\@undefined
    \newattribute\bbl@attr@hboxed
  \fi
  \directlua{
    require('babel-transforms.lua')
    Babel.linebreaking.add_before(Babel.pre_hyphenate_replace)
  }}
\newcommand\SetTransformValue[3]{%
  \directlua{
    Babel.locale_props[\the\csname bbl@id@@#1\endcsname].vars["#2"] = #3
  }}
\newcommand\ShowBabelTransforms[1]{%
  \bbl@activateprehyphen
  \bbl@activateposthyphen
  \begingroup
    \directlua{ Babel.show_transforms = true }%
    \setbox\z@\vbox{#1}%
    \directlua{ Babel.show_transforms = false }%
  \endgroup}
\newcommand\localeprehyphenation[1]{%
  \directlua{ Babel.string_prehyphenation([==[#1]==], \the\localeid) }}
\def\bbl@activate@preotf{%
  \let\bbl@activate@preotf\relax  % only once
  \directlua{
    function Babel.pre_otfload_v(head)
      if Babel.numbers and Babel.digits_mapped then
        head = Babel.numbers(head)
      end
      if Babel.bidi_enabled then
        head = Babel.bidi(head, false, dir)
      end
      return head
    end
    %
    function Babel.pre_otfload_h(head, gc, sz, pt, dir)
      if Babel.numbers and Babel.digits_mapped then
        head = Babel.numbers(head)
      end
      if Babel.bidi_enabled then
        head = Babel.bidi(head, false, dir)
      end
      return head
    end
    %
    luatexbase.add_to_callback('pre_linebreak_filter',
      Babel.pre_otfload_v,
      'Babel.pre_otfload_v',
      Babel.priority_in_callback('pre_linebreak_filter',
        'luaotfload.node_processor') or nil)
    %
    luatexbase.add_to_callback('hpack_filter',
      Babel.pre_otfload_h,
      'Babel.pre_otfload_h',
      Babel.priority_in_callback('hpack_filter',
        'luaotfload.node_processor') or nil)
  }}
\breakafterdirmode=1
\ifnum\bbl@bidimode>\@ne % Any bidi= except default (=1)
  \let\bbl@beforeforeign\leavevmode
  \AtEndOfPackage{\EnableBabelHook{babel-bidi}}
  \RequirePackage{luatexbase}
  \bbl@activate@preotf
  \directlua{
    require('babel-data-bidi.lua')
    \ifcase\expandafter\@gobbletwo\the\bbl@bidimode\or
      require('babel-bidi-basic.lua')
    \or
      require('babel-bidi-basic-r.lua')
      table.insert(Babel.ranges, {0xE000,   0xF8FF, 'on'})
      table.insert(Babel.ranges, {0xF0000,  0xFFFFD, 'on'})
      table.insert(Babel.ranges, {0x100000, 0x10FFFD, 'on'})
    \fi}
  \newattribute\bbl@attr@dir
  \directlua{ Babel.attr_dir = luatexbase.registernumber'bbl@attr@dir' }
  \bbl@exp{\output{\bodydir\pagedir\the\output}}
\fi
\chardef\bbl@thetextdir\z@
\chardef\bbl@thepardir\z@
\def\bbl@getluadir#1{%
  \directlua{
    if tex.#1dir == 'TLT' then
      tex.sprint('0')
    elseif tex.#1dir == 'TRT' then
      tex.sprint('1')
    else
      tex.sprint('0')
    end}}
\def\bbl@setluadir#1#2#3{% 1=text/par.. 2=\textdir.. 3=0 lr/1 rl
  \ifcase#3\relax
    \ifcase\bbl@getluadir{#1}\relax\else
      #2 TLT\relax
    \fi
  \else
    \ifcase\bbl@getluadir{#1}\relax
      #2 TRT\relax
    \fi
  \fi}
\def\bbl@thedir{0}
\def\bbl@textdir#1{%
  \bbl@setluadir{text}\textdir{#1}%
  \chardef\bbl@thetextdir#1\relax
  \edef\bbl@thedir{\the\numexpr\bbl@thepardir*4+#1}%
  \setattribute\bbl@attr@dir{\numexpr\bbl@thepardir*4+#1}}
\def\bbl@pardir#1{%  Used twice
  \bbl@setluadir{par}\pardir{#1}%
  \chardef\bbl@thepardir#1\relax}
\def\bbl@bodydir{\bbl@setluadir{body}\bodydir}%   Used once
\def\bbl@pagedir{\bbl@setluadir{page}\pagedir}%   Unused
\def\bbl@dirparastext{\pardir\the\textdir\relax}% Used once
\ifnum\bbl@bidimode>\z@ % Any bidi=
  \def\bbl@insidemath{0}%
  \def\bbl@everymath{\def\bbl@insidemath{1}}
  \def\bbl@everydisplay{\def\bbl@insidemath{2}}
  \frozen@everymath\expandafter{%
    \expandafter\bbl@everymath\the\frozen@everymath}
  \frozen@everydisplay\expandafter{%
    \expandafter\bbl@everydisplay\the\frozen@everydisplay}
  \AtBeginDocument{
    \directlua{
      function Babel.math_box_dir(head)
        if not (token.get_macro('bbl@insidemath') == '0') then
          if Babel.hlist_has_bidi(head) then
            local d = node.new(node.id'dir')
            d.dir = '+TRT'
            node.insert_before(head, node.has_glyph(head), d)
            local inmath = false
            for item in node.traverse(head) do
              if item.id == 11 then
                inmath = (item.subtype == 0)
              elseif not inmath then
                node.set_attribute(item,
                  Babel.attr_dir, token.get_macro('bbl@thedir'))
              end
            end
          end
        end
        return head
      end
      luatexbase.add_to_callback("hpack_filter", Babel.math_box_dir,
        "Babel.math_box_dir", 0)
      if Babel.unset_atdir then
        luatexbase.add_to_callback("pre_linebreak_filter", Babel.unset_atdir,
          "Babel.unset_atdir")
        luatexbase.add_to_callback("hpack_filter", Babel.unset_atdir,
          "Babel.unset_atdir")
      end
  }}%
\fi
\DeclareRobustCommand\localebox[1]{%
  {\def\bbl@insidemath{0}%
   \mbox{\foreignlanguage{\languagename}{#1}}}}
\bbl@trace{Redefinitions for bidi layout}
\ifnum\bbl@bidimode>\z@ % Any bidi=
  \matheqdirmode\@ne % A luatex primitive
  \let\bbl@eqnodir\relax
  \def\bbl@eqdel{()}
  \def\bbl@eqnum{%
    {\normalfont\normalcolor
     \expandafter\@firstoftwo\bbl@eqdel
     \theequation
     \expandafter\@secondoftwo\bbl@eqdel}}
  \def\bbl@puteqno#1{\eqno\hbox{#1}}
  \def\bbl@putleqno#1{\leqno\hbox{#1}}
  \def\bbl@eqno@flip#1{%
    \ifdim\predisplaysize=-\maxdimen
      \eqno
      \hb@xt@.01pt{%
        \hb@xt@\displaywidth{\hss{#1\glet\bbl@upset\@currentlabel}}\hss}%
    \else
      \leqno\hbox{#1\glet\bbl@upset\@currentlabel}%
    \fi
    \bbl@exp{\def\\\@currentlabel{\[bbl@upset]}}}
  \def\bbl@leqno@flip#1{%
    \ifdim\predisplaysize=-\maxdimen
      \leqno
      \hb@xt@.01pt{%
        \hss\hb@xt@\displaywidth{{#1\glet\bbl@upset\@currentlabel}\hss}}%
    \else
      \eqno\hbox{#1\glet\bbl@upset\@currentlabel}%
    \fi
    \bbl@exp{\def\\\@currentlabel{\[bbl@upset]}}}
  \AtBeginDocument{%
    \ifx\bbl@noamsmath\relax\else
    \ifx\maketag@@@\@undefined % Normal equation, eqnarray
      \AddToHook{env/equation/begin}{%
        \ifnum\bbl@thetextdir>\z@
          \def\bbl@mathboxdir{\def\bbl@insidemath{1}}%
          \let\@eqnnum\bbl@eqnum
          \edef\bbl@eqnodir{\noexpand\bbl@textdir{\the\bbl@thetextdir}}%
          \chardef\bbl@thetextdir\z@
          \bbl@add\normalfont{\bbl@eqnodir}%
          \ifcase\bbl@eqnpos
            \let\bbl@puteqno\bbl@eqno@flip
          \or
            \let\bbl@puteqno\bbl@leqno@flip
          \fi
        \fi}%
      \ifnum\bbl@eqnpos=\tw@\else
        \def\endequation{\bbl@puteqno{\@eqnnum}$$\@ignoretrue}%
      \fi
      \AddToHook{env/eqnarray/begin}{%
        \ifnum\bbl@thetextdir>\z@
          \def\bbl@mathboxdir{\def\bbl@insidemath{1}}%
          \edef\bbl@eqnodir{\noexpand\bbl@textdir{\the\bbl@thetextdir}}%
          \chardef\bbl@thetextdir\z@
          \bbl@add\normalfont{\bbl@eqnodir}%
          \ifnum\bbl@eqnpos=\@ne
            \def\@eqnnum{%
              \setbox\z@\hbox{\bbl@eqnum}%
              \hbox to0.01pt{\hss\hbox to\displaywidth{\box\z@\hss}}}%
          \else
            \let\@eqnnum\bbl@eqnum
          \fi
        \fi}
      % Hack for wrong vertical spacing with \[ \]. YA luatex bug?:
      \expandafter\bbl@sreplace\csname] \endcsname{$$}{\eqno\kern.001pt$$}%
    \else % amstex
      \bbl@exp{% Hack to hide maybe undefined conditionals:
        \chardef\bbl@eqnpos=0%
          \<iftagsleft@>1\<else>\<if@fleqn>2\<fi>\<fi>\relax}%
      \ifnum\bbl@eqnpos=\@ne
        \let\bbl@ams@lap\hbox
      \else
        \let\bbl@ams@lap\llap
      \fi
      \ExplSyntaxOn % Required by \bbl@sreplace with \intertext@
      \bbl@sreplace\intertext@{\normalbaselines}%
        {\normalbaselines
         \ifx\bbl@eqnodir\relax\else\bbl@pardir\@ne\bbl@eqnodir\fi}%
      \ExplSyntaxOff
      \def\bbl@ams@tagbox#1#2{#1{\bbl@eqnodir#2}}% #1=hbox|@lap|flip
      \ifx\bbl@ams@lap\hbox % leqno
        \def\bbl@ams@flip#1{%
          \hbox to 0.01pt{\hss\hbox to\displaywidth{{#1}\hss}}}%
      \else % eqno
        \def\bbl@ams@flip#1{%
          \hbox to 0.01pt{\hbox to\displaywidth{\hss{#1}}\hss}}%
      \fi
      \def\bbl@ams@preset#1{%
        \def\bbl@mathboxdir{\def\bbl@insidemath{1}}%
        \ifnum\bbl@thetextdir>\z@
          \edef\bbl@eqnodir{\noexpand\bbl@textdir{\the\bbl@thetextdir}}%
          \bbl@sreplace\textdef@{\hbox}{\bbl@ams@tagbox\hbox}%
          \bbl@sreplace\maketag@@@{\hbox}{\bbl@ams@tagbox#1}%
        \fi}%
      \ifnum\bbl@eqnpos=\tw@\else
        \def\bbl@ams@equation{%
          \def\bbl@mathboxdir{\def\bbl@insidemath{1}}%
          \ifnum\bbl@thetextdir>\z@
            \edef\bbl@eqnodir{\noexpand\bbl@textdir{\the\bbl@thetextdir}}%
            \chardef\bbl@thetextdir\z@
            \bbl@add\normalfont{\bbl@eqnodir}%
            \ifcase\bbl@eqnpos
              \def\veqno##1##2{\bbl@eqno@flip{##1##2}}%
            \or
              \def\veqno##1##2{\bbl@leqno@flip{##1##2}}%
            \fi
          \fi}%
        \AddToHook{env/equation/begin}{\bbl@ams@equation}%
        \AddToHook{env/equation*/begin}{\bbl@ams@equation}%
      \fi
      \AddToHook{env/cases/begin}{\bbl@ams@preset\bbl@ams@lap}%
      \AddToHook{env/multline/begin}{\bbl@ams@preset\hbox}%
      \AddToHook{env/gather/begin}{\bbl@ams@preset\bbl@ams@lap}%
      \AddToHook{env/gather*/begin}{\bbl@ams@preset\bbl@ams@lap}%
      \AddToHook{env/align/begin}{\bbl@ams@preset\bbl@ams@lap}%
      \AddToHook{env/align*/begin}{\bbl@ams@preset\bbl@ams@lap}%
      \AddToHook{env/alignat/begin}{\bbl@ams@preset\bbl@ams@lap}%
      \AddToHook{env/alignat*/begin}{\bbl@ams@preset\bbl@ams@lap}%
      \AddToHook{env/eqnalign/begin}{\bbl@ams@preset\hbox}%
      % Hackish, for proper alignment. Don’t ask me why it works!:
      \bbl@exp{% Avoid a 'visible' conditional
        \\\AddToHook{env/align*/end}{\<iftag@>\<else>\\\tag*{}\<fi>}%
        \\\AddToHook{env/alignat*/end}{\<iftag@>\<else>\\\tag*{}\<fi>}}%
      \AddToHook{env/flalign/begin}{\bbl@ams@preset\hbox}%
      \AddToHook{env/split/before}{%
        \def\bbl@mathboxdir{\def\bbl@insidemath{1}}%
        \ifnum\bbl@thetextdir>\z@
          \bbl@ifsamestring\@currenvir{equation}%
            {\ifx\bbl@ams@lap\hbox % leqno
               \def\bbl@ams@flip#1{%
                 \hbox to 0.01pt{\hbox to\displaywidth{{#1}\hss}\hss}}%
             \else
               \def\bbl@ams@flip#1{%
                 \hbox to 0.01pt{\hss\hbox to\displaywidth{\hss{#1}}}}%
             \fi}%
           {}%
        \fi}%
    \fi\fi}
\fi
\def\bbl@provide@extra#1{%
   % == onchar ==
  \ifx\bbl@KVP@onchar\@nnil\else
    \bbl@luahyphenate
    \bbl@exp{%
      \\\AddToHook{env/document/before}{%
        {\let\\\bbl@ifrestoring\\\@firstoftwo
         \\\select@language{#1}{}}}}%
    \directlua{
      if Babel.locale_mapped == nil then
        Babel.locale_mapped = true
        Babel.linebreaking.add_before(Babel.locale_map, 1)
        Babel.loc_to_scr = {}
        Babel.chr_to_loc = Babel.chr_to_loc or {}
      end
      Babel.locale_props[\the\localeid].letters = false
    }%
    \bbl@xin@{ letters }{ \bbl@KVP@onchar\space}%
    \ifin@
      \directlua{
        Babel.locale_props[\the\localeid].letters = true
      }%
    \fi
    \bbl@xin@{ ids }{ \bbl@KVP@onchar\space}%
    \ifin@
      \ifx\bbl@starthyphens\@undefined % Needed if no explicit selection
        \AddBabelHook{babel-onchar}{beforestart}{{\bbl@starthyphens}}%
      \fi
      \bbl@exp{\\\bbl@add\\\bbl@starthyphens
        {\\\bbl@patterns@lua{\languagename}}}%
      \directlua{
        if Babel.script_blocks['\bbl@cl{sbcp}'] then
          Babel.loc_to_scr[\the\localeid] = Babel.script_blocks['\bbl@cl{sbcp}']
          Babel.locale_props[\the\localeid].lg = \the\@nameuse{l@\languagename}\space
        end
      }%
    \fi
    \bbl@xin@{ fonts }{ \bbl@KVP@onchar\space}%
    \ifin@
      \bbl@ifunset{bbl@lsys@\languagename}{\bbl@provide@lsys{\languagename}}{}%
      \bbl@ifunset{bbl@wdir@\languagename}{\bbl@provide@dirs{\languagename}}{}%
      \directlua{
        if Babel.script_blocks['\bbl@cl{sbcp}'] then
          Babel.loc_to_scr[\the\localeid] =
            Babel.script_blocks['\bbl@cl{sbcp}']
        end}%
      \ifx\bbl@mapselect\@undefined
        \AtBeginDocument{%
          \bbl@patchfont{{\bbl@mapselect}}%
          {\selectfont}}%
        \def\bbl@mapselect{%
          \let\bbl@mapselect\relax
          \edef\bbl@prefontid{\fontid\font}}%
        \def\bbl@mapdir##1{%
          \begingroup
            \setbox\z@\hbox{% Force text mode
              \def\languagename{##1}%
              \let\bbl@ifrestoring\@firstoftwo % To avoid font warning
              \bbl@switchfont
              \ifnum\fontid\font>\z@ % A hack, for the pgf nullfont hack
                \directlua{
                  Babel.locale_props[\the\csname bbl@id@@##1\endcsname]%
                          ['/\bbl@prefontid'] = \fontid\font\space}%
              \fi}%
          \endgroup}%
      \fi
      \bbl@exp{\\\bbl@add\\\bbl@mapselect{\\\bbl@mapdir{\languagename}}}%
    \fi
  \fi
  % == mapfont ==
  % For bidi texts, to switch the font based on direction. Deprecated
  \ifx\bbl@KVP@mapfont\@nnil\else
    \bbl@ifsamestring{\bbl@KVP@mapfont}{direction}{}%
      {\bbl@error{unknown-mapfont}{}{}{}}%
    \bbl@ifunset{bbl@lsys@\languagename}{\bbl@provide@lsys{\languagename}}{}%
    \bbl@ifunset{bbl@wdir@\languagename}{\bbl@provide@dirs{\languagename}}{}%
    \ifx\bbl@mapselect\@undefined
      \AtBeginDocument{%
        \bbl@patchfont{{\bbl@mapselect}}%
        {\selectfont}}%
      \def\bbl@mapselect{%
        \let\bbl@mapselect\relax
        \edef\bbl@prefontid{\fontid\font}}%
      \def\bbl@mapdir##1{%
        {\def\languagename{##1}%
         \let\bbl@ifrestoring\@firstoftwo % avoid font warning
         \bbl@switchfont
         \directlua{Babel.fontmap
           [\the\csname bbl@wdir@##1\endcsname]%
           [\bbl@prefontid]=\fontid\font}}}%
    \fi
    \bbl@exp{\\\bbl@add\\\bbl@mapselect{\\\bbl@mapdir{\languagename}}}%
  \fi
  % == Line breaking: CJK quotes ==
  \ifcase\bbl@engine\or
    \bbl@xin@{/c}{/\bbl@cl{lnbrk}}%
    \ifin@
      \bbl@ifunset{bbl@quote@\languagename}{}%
        {\directlua{
           Babel.locale_props[\the\localeid].cjk_quotes = {}
           local cs = 'op'
           for c in string.utfvalues(%
               [[\csname bbl@quote@\languagename\endcsname]]) do
             if Babel.cjk_characters[c].c == 'qu' then
               Babel.locale_props[\the\localeid].cjk_quotes[c] = cs
             end
             cs = ( cs == 'op') and 'cl' or 'op'
           end
        }}%
    \fi
  \fi
  % == Counters: mapdigits ==
  % Native digits
  \ifx\bbl@KVP@mapdigits\@nnil\else
    \bbl@ifunset{bbl@dgnat@\languagename}{}%
      {\bbl@activate@preotf
       \directlua{
         Babel.digits_mapped = true
         Babel.digits = Babel.digits or {}
         Babel.digits[\the\localeid] =
           table.pack(string.utfvalue('\bbl@cl{dgnat}'))
         if not Babel.numbers then
           function Babel.numbers(head)
             local LOCALE = Babel.attr_locale
             local GLYPH = node.id'glyph'
             local inmath = false
             for item in node.traverse(head) do
               if not inmath and item.id == GLYPH then
                 local temp = node.get_attribute(item, LOCALE)
                 if Babel.digits[temp] then
                   local chr = item.char
                   if chr > 47 and chr < 58 then
                     item.char = Babel.digits[temp][chr-47]
                   end
                 end
               elseif item.id == node.id'math' then
                 inmath = (item.subtype == 0)
               end
             end
             return head
           end
         end
      }}%
  \fi
  % == transforms ==
  \ifx\bbl@KVP@transforms\@nnil\else
    \def\bbl@elt##1##2##3{%
      \in@{$transforms.}{$##1}%
      \ifin@
        \def\bbl@tempa{##1}%
        \bbl@replace\bbl@tempa{transforms.}{}%
        \bbl@carg\bbl@transforms{babel\bbl@tempa}{##2}{##3}%
      \fi}%
    \bbl@exp{%
      \\\bbl@ifblank{\bbl@cl{dgnat}}%
       {\let\\\bbl@tempa\relax}%
       {\def\\\bbl@tempa{%
         \\\bbl@elt{transforms.prehyphenation}%
          {digits.native.1.0}{([0-9])}%
         \\\bbl@elt{transforms.prehyphenation}%
          {digits.native.1.1}{string={1\string|0123456789\string|\bbl@cl{dgnat}}}}}}%
    \ifx\bbl@tempa\relax\else
      \toks@\expandafter\expandafter\expandafter{%
        \csname bbl@inidata@\languagename\endcsname}%
      \bbl@csarg\edef{inidata@\languagename}{%
        \unexpanded\expandafter{\bbl@tempa}%
        \the\toks@}%
    \fi
    \csname bbl@inidata@\languagename\endcsname
    \bbl@release@transforms\relax % \relax closes the last item.
  \fi}
\def\localerestoredirs{%
  \ifcase\bbl@thetextdir
    \ifnum\textdirection=\z@\else\textdir TLT\fi
  \else
    \ifnum\textdirection=\@ne\else\textdir TRT\fi
  \fi
  \ifcase\bbl@thepardir
    \ifnum\pardirection=\z@\else\pardir TLT\bodydir TLT\fi
  \else
    \ifnum\pardirection=\@ne\else\pardir TRT\bodydir TRT\fi
  \fi}
\IfBabelLayout{tabular}%
  {\chardef\bbl@tabular@mode\tw@}% All RTL
  {\IfBabelLayout{notabular}%
    {\chardef\bbl@tabular@mode\z@}%
    {\chardef\bbl@tabular@mode\@ne}}% Mixed, with LTR cols
\ifnum\bbl@bidimode>\@ne % Any lua bidi= except default=1
  % Redefine: vrules mess up dirs.
  \def\@arstrut{\relax\copy\@arstrutbox}%
  \ifcase\bbl@tabular@mode\or % 1 = Mixed - default
    \let\bbl@parabefore\relax
    \AddToHook{para/before}{\bbl@parabefore}
    \AtBeginDocument{%
      \bbl@replace\@tabular{$}{$%
        \def\bbl@insidemath{0}%
        \def\bbl@parabefore{\localerestoredirs}}%
      \ifnum\bbl@tabular@mode=\@ne
        \bbl@ifunset{@tabclassz}{}{%
          \bbl@exp{% Hide conditionals
            \\\bbl@sreplace\\\@tabclassz
              {\<ifcase>\\\@chnum}%
              {\\\localerestoredirs\<ifcase>\\\@chnum}}}%
        \@ifpackageloaded{colortbl}%
          {\bbl@sreplace\@classz
            {\hbox\bgroup\bgroup}{\hbox\bgroup\bgroup\localerestoredirs}}%
          {\@ifpackageloaded{array}%
             {\bbl@exp{% Hide conditionals
                \\\bbl@sreplace\\\@classz
                  {\<ifcase>\\\@chnum}%
                  {\bgroup\\\localerestoredirs\<ifcase>\\\@chnum}%
                \\\bbl@sreplace\\\@classz
                  {\\\do@row@strut\<fi>}{\\\do@row@strut\<fi>\egroup}}}%
             {}}%
    \fi}%
  \or % 2 = All RTL - tabular
    \let\bbl@parabefore\relax
    \AddToHook{para/before}{\bbl@parabefore}%
    \AtBeginDocument{%
      \@ifpackageloaded{colortbl}%
        {\bbl@replace\@tabular{$}{$%
           \def\bbl@insidemath{0}%
           \def\bbl@parabefore{\localerestoredirs}}%
         \bbl@sreplace\@classz
           {\hbox\bgroup\bgroup}{\hbox\bgroup\bgroup\localerestoredirs}}%
        {}}%
  \fi
  \AtBeginDocument{%
    \@ifpackageloaded{multicol}%
      {\toks@\expandafter{\multi@column@out}%
       \edef\multi@column@out{\bodydir\pagedir\the\toks@}}%
      {}%
    \@ifpackageloaded{paracol}%
      {\edef\pcol@output{%
        \bodydir\pagedir\unexpanded\expandafter{\pcol@output}}}%
      {}}%
\fi
\ifx\bbl@opt@layout\@nnil\endinput\fi
\ifnum\bbl@bidimode>\z@ % Any bidi=
  \def\bbl@nextfake#1{%  non-local changes, use always inside a group!
    \bbl@exp{%
      \mathdir\the\bodydir
      #1%              Once entered in math, set boxes to restore values
      \def\\\bbl@insidemath{0}%
      \<ifmmode>%
        \everyvbox{%
          \the\everyvbox
          \bodydir\the\bodydir
          \mathdir\the\mathdir
          \everyhbox{\the\everyhbox}%
          \everyvbox{\the\everyvbox}}%
        \everyhbox{%
          \the\everyhbox
          \bodydir\the\bodydir
          \mathdir\the\mathdir
          \everyhbox{\the\everyhbox}%
          \everyvbox{\the\everyvbox}}%
      \<fi>}}%
\IfBabelLayout{nopars}
  {}
  {\edef\bbl@opt@layout{\bbl@opt@layout.pars.}}%
\IfBabelLayout{pars}
  {\def\@hangfrom#1{%
    \setbox\@tempboxa\hbox{{#1}}%
    \hangindent\wd\@tempboxa
    \ifnum\bbl@getluadir{page}=\bbl@getluadir{par}\else
      \shapemode\@ne
    \fi
    \noindent\box\@tempboxa}}
  {}
\fi
\IfBabelLayout{tabular}
  {\let\bbl@OL@@tabular\@tabular
   \bbl@replace\@tabular{$}{\bbl@nextfake$}%
   \let\bbl@NL@@tabular\@tabular
   \AtBeginDocument{%
     \ifx\bbl@NL@@tabular\@tabular\else
       \bbl@exp{\\\in@{\\\bbl@nextfake}{\[@tabular]}}%
       \ifin@\else
         \bbl@replace\@tabular{$}{\bbl@nextfake$}%
       \fi
       \let\bbl@NL@@tabular\@tabular
     \fi}}
   {}
\IfBabelLayout{lists}
  {\let\bbl@OL@list\list
   \bbl@sreplace\list{\parshape}{\bbl@listparshape}%
   \let\bbl@NL@list\list
   \def\bbl@listparshape#1#2#3{%
     \parshape #1 #2 #3 %
     \ifnum\bbl@getluadir{page}=\bbl@getluadir{par}\else
       \shapemode\tw@
     \fi}}
  {}
\IfBabelLayout{graphics}
  {\let\bbl@pictresetdir\relax
   \def\bbl@pictsetdir#1{%
     \ifcase\bbl@thetextdir
       \let\bbl@pictresetdir\relax
     \else
       \ifcase#1\bodydir TLT  % Remember this sets the inner boxes
         \or\textdir TLT
         \else\bodydir TLT \textdir TLT
       \fi
       % \(text|par)dir required in pgf:
       \def\bbl@pictresetdir{\bodydir TRT\pardir TRT\textdir TRT\relax}%
     \fi}%
   \AddToHook{env/picture/begin}{\bbl@pictsetdir\tw@}%
   \directlua{
     Babel.get_picture_dir = true
     Babel.picture_has_bidi = 0
     %
     function Babel.picture_dir (head)
       if not Babel.get_picture_dir then return head end
       if Babel.hlist_has_bidi(head) then
         Babel.picture_has_bidi = 1
       end
       return head
     end
     luatexbase.add_to_callback("hpack_filter", Babel.picture_dir,
       "Babel.picture_dir")
   }%
   \AtBeginDocument{%
     \def\LS@rot{%
       \setbox\@outputbox\vbox{%
         \hbox dir TLT{\rotatebox{90}{\box\@outputbox}}}}%
     \long\def\put(#1,#2)#3{%
       \@killglue
       % Try:
       \ifx\bbl@pictresetdir\relax
         \def\bbl@tempc{0}%
       \else
         \directlua{
           Babel.get_picture_dir = true
           Babel.picture_has_bidi = 0
         }%
         \setbox\z@\hb@xt@\z@{%
           \@defaultunitsset\@tempdimc{#1}\unitlength
           \kern\@tempdimc
           #3\hss}%
         \edef\bbl@tempc{\directlua{tex.print(Babel.picture_has_bidi)}}%
       \fi
       % Do:
       \@defaultunitsset\@tempdimc{#2}\unitlength
       \raise\@tempdimc\hb@xt@\z@{%
         \@defaultunitsset\@tempdimc{#1}\unitlength
         \kern\@tempdimc
         {\ifnum\bbl@tempc>\z@\bbl@pictresetdir\fi#3}\hss}%
       \ignorespaces}%
     \MakeRobust\put}%
   \AtBeginDocument
     {\AddToHook{cmd/diagbox@pict/before}{\let\bbl@pictsetdir\@gobble}%
      \ifx\pgfpicture\@undefined\else
        \AddToHook{env/pgfpicture/begin}{\bbl@pictsetdir\@ne}%
        \bbl@add\pgfinterruptpicture{\bbl@pictresetdir}%
        \bbl@add\pgfsys@beginpicture{\bbl@pictsetdir\z@}%
      \fi
      \ifx\tikzpicture\@undefined\else
        \AddToHook{env/tikzpicture/begin}{\bbl@pictsetdir\tw@}%
        \bbl@add\tikz@atbegin@node{\bbl@pictresetdir}%
        \bbl@sreplace\tikz{\begingroup}{\begingroup\bbl@pictsetdir\tw@}%
        \bbl@sreplace\tikzpicture{\begingroup}{\begingroup\bbl@pictsetdir\tw@}%
      \fi
      \ifx\tcolorbox\@undefined\else
        \def\tcb@drawing@env@begin{%
          \csname tcb@before@\tcb@split@state\endcsname
          \bbl@pictsetdir\tw@
          \begin{\kvtcb@graphenv}%
          \tcb@bbdraw
          \tcb@apply@graph@patches}%
        \def\tcb@drawing@env@end{%
          \end{\kvtcb@graphenv}%
          \bbl@pictresetdir
          \csname tcb@after@\tcb@split@state\endcsname}%
      \fi
    }}
  {}
\IfBabelLayout{counters*}%
  {\bbl@add\bbl@opt@layout{.counters.}%
   \directlua{
     luatexbase.add_to_callback("process_output_buffer",
       Babel.discard_sublr , "Babel.discard_sublr") }%
  }{}
\IfBabelLayout{counters}%
  {\let\bbl@OL@@textsuperscript\@textsuperscript
   \bbl@sreplace\@textsuperscript{\m@th}{\m@th\mathdir\pagedir}%
   \let\bbl@latinarabic=\@arabic
   \let\bbl@OL@@arabic\@arabic
   \def\@arabic#1{\babelsublr{\bbl@latinarabic#1}}%
   \@ifpackagewith{babel}{bidi=default}%
     {\let\bbl@asciiroman=\@roman
      \let\bbl@OL@@roman\@roman
      \def\@roman#1{\babelsublr{\ensureascii{\bbl@asciiroman#1}}}%
      \let\bbl@asciiRoman=\@Roman
      \let\bbl@OL@@roman\@Roman
      \def\@Roman#1{\babelsublr{\ensureascii{\bbl@asciiRoman#1}}}%
      \let\bbl@OL@labelenumii\labelenumii
      \def\labelenumii{)\theenumii(}%
      \let\bbl@OL@p@enumiii\p@enumiii
      \def\p@enumiii{\p@enumii)\theenumii(}}{}}{}
\IfBabelLayout{extras}%
  {\bbl@ncarg\let\bbl@OL@underline{underline }%
   \bbl@carg\bbl@sreplace{underline }%
     {$\@@underline}{\bgroup\bbl@nextfake$\@@underline}%
   \bbl@carg\bbl@sreplace{underline }%
     {\m@th$}{\m@th$\egroup}%
   \let\bbl@OL@LaTeXe\LaTeXe
   \DeclareRobustCommand{\LaTeXe}{\mbox{\m@th
     \if b\expandafter\@car\f@series\@nil\boldmath\fi
     \babelsublr{%
       \LaTeX\kern.15em2\bbl@nextfake$_{\textstyle\varepsilon}$}}}}
  {}
\endinput
%%
%% End of file `luababel.def'.
