From 5ce60cc98a304d837dfa451dd7d389dbd5cfaa77 Mon Sep 17 00:00:00 2001
From: Philipp Gesang <phg@phi-gamma.net>
Date: Tue, 19 Apr 2016 08:09:38 +0200
Subject: [*] shred 2014 fontloader
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This one hasn’t been touched for ages. The will be no compatibility
loader this year. For testing, creating a loader on the fly from the Git
repos is sufficient.
---
 src/fontloader/runtime/fontloader-tl2014.lua | 13936 -------------------------
 src/luaotfload-configuration.lua             |     1 -
 src/luaotfload-database.lua                  |     1 -
 src/luaotfload-features.lua                  |     2 +-
 src/luaotfload-init.lua                      |     3 -
 src/luaotfload-main.lua                      |    27 +-
 6 files changed, 3 insertions(+), 13967 deletions(-)
 delete mode 100644 src/fontloader/runtime/fontloader-tl2014.lua

(limited to 'src')

diff --git a/src/fontloader/runtime/fontloader-tl2014.lua b/src/fontloader/runtime/fontloader-tl2014.lua
deleted file mode 100644
index 12b68a5..0000000
--- a/src/fontloader/runtime/fontloader-tl2014.lua
+++ /dev/null
@@ -1,13936 +0,0 @@
--- merged file : luatex-fonts-merged.lua
--- parent file : luatex-fonts.lua
--- merge date  : 07/29/14 00:30:11
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-lua']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local major,minor=string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$")
-_MAJORVERSION=tonumber(major) or 5
-_MINORVERSION=tonumber(minor) or 1
-_LUAVERSION=_MAJORVERSION+_MINORVERSION/10
-if not lpeg then
-  lpeg=require("lpeg")
-end
-if loadstring then
-  local loadnormal=load
-  function load(first,...)
-    if type(first)=="string" then
-      return loadstring(first,...)
-    else
-      return loadnormal(first,...)
-    end
-  end
-else
-  loadstring=load
-end
-if not ipairs then
-  local function iterate(a,i)
-    i=i+1
-    local v=a[i]
-    if v~=nil then
-      return i,v 
-    end
-  end
-  function ipairs(a)
-    return iterate,a,0
-  end
-end
-if not pairs then
-  function pairs(t)
-    return next,t 
-  end
-end
-if not table.unpack then
-  table.unpack=_G.unpack
-elseif not unpack then
-  _G.unpack=table.unpack
-end
-if not package.loaders then 
-  package.loaders=package.searchers
-end
-local print,select,tostring=print,select,tostring
-local inspectors={}
-function setinspector(inspector) 
-  inspectors[#inspectors+1]=inspector
-end
-function inspect(...) 
-  for s=1,select("#",...) do
-    local value=select(s,...)
-    local done=false
-    for i=1,#inspectors do
-      done=inspectors[i](value)
-      if done then
-        break
-      end
-    end
-    if not done then
-      print(tostring(value))
-    end
-  end
-end
-local dummy=function() end
-function optionalrequire(...)
-  local ok,result=xpcall(require,dummy,...)
-  if ok then
-    return result
-  end
-end
-if lua then
-  lua.mask=load([[τεχ = 1]]) and "utf" or "ascii"
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-lpeg']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-lpeg=require("lpeg")
-if not lpeg.print then function lpeg.print(...) print(lpeg.pcode(...)) end end
-local type,next,tostring=type,next,tostring
-local byte,char,gmatch,format=string.byte,string.char,string.gmatch,string.format
-local floor=math.floor
-local P,R,S,V,Ct,C,Cs,Cc,Cp,Cmt=lpeg.P,lpeg.R,lpeg.S,lpeg.V,lpeg.Ct,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Cp,lpeg.Cmt
-local lpegtype,lpegmatch,lpegprint=lpeg.type,lpeg.match,lpeg.print
-if setinspector then
-  setinspector(function(v) if lpegtype(v) then lpegprint(v) return true end end)
-end
-lpeg.patterns=lpeg.patterns or {} 
-local patterns=lpeg.patterns
-local anything=P(1)
-local endofstring=P(-1)
-local alwaysmatched=P(true)
-patterns.anything=anything
-patterns.endofstring=endofstring
-patterns.beginofstring=alwaysmatched
-patterns.alwaysmatched=alwaysmatched
-local sign=S('+-')
-local zero=P('0')
-local digit=R('09')
-local octdigit=R("07")
-local lowercase=R("az")
-local uppercase=R("AZ")
-local underscore=P("_")
-local hexdigit=digit+lowercase+uppercase
-local cr,lf,crlf=P("\r"),P("\n"),P("\r\n")
-local newline=P("\r")*(P("\n")+P(true))+P("\n")
-local escaped=P("\\")*anything
-local squote=P("'")
-local dquote=P('"')
-local space=P(" ")
-local period=P(".")
-local comma=P(",")
-local utfbom_32_be=P('\000\000\254\255') 
-local utfbom_32_le=P('\255\254\000\000') 
-local utfbom_16_be=P('\254\255')     
-local utfbom_16_le=P('\255\254')     
-local utfbom_8=P('\239\187\191')   
-local utfbom=utfbom_32_be+utfbom_32_le+utfbom_16_be+utfbom_16_le+utfbom_8
-local utftype=utfbom_32_be*Cc("utf-32-be")+utfbom_32_le*Cc("utf-32-le")+utfbom_16_be*Cc("utf-16-be")+utfbom_16_le*Cc("utf-16-le")+utfbom_8*Cc("utf-8")+alwaysmatched*Cc("utf-8") 
-local utfstricttype=utfbom_32_be*Cc("utf-32-be")+utfbom_32_le*Cc("utf-32-le")+utfbom_16_be*Cc("utf-16-be")+utfbom_16_le*Cc("utf-16-le")+utfbom_8*Cc("utf-8")
-local utfoffset=utfbom_32_be*Cc(4)+utfbom_32_le*Cc(4)+utfbom_16_be*Cc(2)+utfbom_16_le*Cc(2)+utfbom_8*Cc(3)+Cc(0)
-local utf8next=R("\128\191")
-patterns.utfbom_32_be=utfbom_32_be
-patterns.utfbom_32_le=utfbom_32_le
-patterns.utfbom_16_be=utfbom_16_be
-patterns.utfbom_16_le=utfbom_16_le
-patterns.utfbom_8=utfbom_8
-patterns.utf_16_be_nl=P("\000\r\000\n")+P("\000\r")+P("\000\n") 
-patterns.utf_16_le_nl=P("\r\000\n\000")+P("\r\000")+P("\n\000") 
-patterns.utf8one=R("\000\127")
-patterns.utf8two=R("\194\223")*utf8next
-patterns.utf8three=R("\224\239")*utf8next*utf8next
-patterns.utf8four=R("\240\244")*utf8next*utf8next*utf8next
-patterns.utfbom=utfbom
-patterns.utftype=utftype
-patterns.utfstricttype=utfstricttype
-patterns.utfoffset=utfoffset
-local utf8char=patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four
-local validutf8char=utf8char^0*endofstring*Cc(true)+Cc(false)
-local utf8character=P(1)*R("\128\191")^0 
-patterns.utf8=utf8char
-patterns.utf8char=utf8char
-patterns.utf8character=utf8character 
-patterns.validutf8=validutf8char
-patterns.validutf8char=validutf8char
-local eol=S("\n\r")
-local spacer=S(" \t\f\v") 
-local whitespace=eol+spacer
-local nonspacer=1-spacer
-local nonwhitespace=1-whitespace
-patterns.eol=eol
-patterns.spacer=spacer
-patterns.whitespace=whitespace
-patterns.nonspacer=nonspacer
-patterns.nonwhitespace=nonwhitespace
-local stripper=spacer^0*C((spacer^0*nonspacer^1)^0)   
-local fullstripper=whitespace^0*C((whitespace^0*nonwhitespace^1)^0)
-local collapser=Cs(spacer^0/""*nonspacer^0*((spacer^0/" "*nonspacer^1)^0))
-patterns.stripper=stripper
-patterns.fullstripper=fullstripper
-patterns.collapser=collapser
-patterns.lowercase=lowercase
-patterns.uppercase=uppercase
-patterns.letter=patterns.lowercase+patterns.uppercase
-patterns.space=space
-patterns.tab=P("\t")
-patterns.spaceortab=patterns.space+patterns.tab
-patterns.newline=newline
-patterns.emptyline=newline^1
-patterns.equal=P("=")
-patterns.comma=comma
-patterns.commaspacer=comma*spacer^0
-patterns.period=period
-patterns.colon=P(":")
-patterns.semicolon=P(";")
-patterns.underscore=underscore
-patterns.escaped=escaped
-patterns.squote=squote
-patterns.dquote=dquote
-patterns.nosquote=(escaped+(1-squote))^0
-patterns.nodquote=(escaped+(1-dquote))^0
-patterns.unsingle=(squote/"")*patterns.nosquote*(squote/"") 
-patterns.undouble=(dquote/"")*patterns.nodquote*(dquote/"") 
-patterns.unquoted=patterns.undouble+patterns.unsingle 
-patterns.unspacer=((patterns.spacer^1)/"")^0
-patterns.singlequoted=squote*patterns.nosquote*squote
-patterns.doublequoted=dquote*patterns.nodquote*dquote
-patterns.quoted=patterns.doublequoted+patterns.singlequoted
-patterns.digit=digit
-patterns.octdigit=octdigit
-patterns.hexdigit=hexdigit
-patterns.sign=sign
-patterns.cardinal=digit^1
-patterns.integer=sign^-1*digit^1
-patterns.unsigned=digit^0*period*digit^1
-patterns.float=sign^-1*patterns.unsigned
-patterns.cunsigned=digit^0*comma*digit^1
-patterns.cpunsigned=digit^0*(period+comma)*digit^1
-patterns.cfloat=sign^-1*patterns.cunsigned
-patterns.cpfloat=sign^-1*patterns.cpunsigned
-patterns.number=patterns.float+patterns.integer
-patterns.cnumber=patterns.cfloat+patterns.integer
-patterns.cpnumber=patterns.cpfloat+patterns.integer
-patterns.oct=zero*octdigit^1
-patterns.octal=patterns.oct
-patterns.HEX=zero*P("X")*(digit+uppercase)^1
-patterns.hex=zero*P("x")*(digit+lowercase)^1
-patterns.hexadecimal=zero*S("xX")*hexdigit^1
-patterns.hexafloat=sign^-1*zero*S("xX")*(hexdigit^0*period*hexdigit^1+hexdigit^1*period*hexdigit^0+hexdigit^1)*(S("pP")*sign^-1*hexdigit^1)^-1
-patterns.decafloat=sign^-1*(digit^0*period*digit^1+digit^1*period*digit^0+digit^1)*S("eE")*sign^-1*digit^1
-patterns.propername=(uppercase+lowercase+underscore)*(uppercase+lowercase+underscore+digit)^0*endofstring
-patterns.somecontent=(anything-newline-space)^1 
-patterns.beginline=#(1-newline)
-patterns.longtostring=Cs(whitespace^0/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(P(-1)+Cc(" ")))^0))
-local function anywhere(pattern) 
-  return P { P(pattern)+1*V(1) }
-end
-lpeg.anywhere=anywhere
-function lpeg.instringchecker(p)
-  p=anywhere(p)
-  return function(str)
-    return lpegmatch(p,str) and true or false
-  end
-end
-function lpeg.splitter(pattern,action)
-  return (((1-P(pattern))^1)/action+1)^0
-end
-function lpeg.tsplitter(pattern,action)
-  return Ct((((1-P(pattern))^1)/action+1)^0)
-end
-local splitters_s,splitters_m,splitters_t={},{},{}
-local function splitat(separator,single)
-  local splitter=(single and splitters_s[separator]) or splitters_m[separator]
-  if not splitter then
-    separator=P(separator)
-    local other=C((1-separator)^0)
-    if single then
-      local any=anything
-      splitter=other*(separator*C(any^0)+"") 
-      splitters_s[separator]=splitter
-    else
-      splitter=other*(separator*other)^0
-      splitters_m[separator]=splitter
-    end
-  end
-  return splitter
-end
-local function tsplitat(separator)
-  local splitter=splitters_t[separator]
-  if not splitter then
-    splitter=Ct(splitat(separator))
-    splitters_t[separator]=splitter
-  end
-  return splitter
-end
-lpeg.splitat=splitat
-lpeg.tsplitat=tsplitat
-function string.splitup(str,separator)
-  if not separator then
-    separator=","
-  end
-  return lpegmatch(splitters_m[separator] or splitat(separator),str)
-end
-local cache={}
-function lpeg.split(separator,str)
-  local c=cache[separator]
-  if not c then
-    c=tsplitat(separator)
-    cache[separator]=c
-  end
-  return lpegmatch(c,str)
-end
-function string.split(str,separator)
-  if separator then
-    local c=cache[separator]
-    if not c then
-      c=tsplitat(separator)
-      cache[separator]=c
-    end
-    return lpegmatch(c,str)
-  else
-    return { str }
-  end
-end
-local spacing=patterns.spacer^0*newline 
-local empty=spacing*Cc("")
-local nonempty=Cs((1-spacing)^1)*spacing^-1
-local content=(empty+nonempty)^1
-patterns.textline=content
-local linesplitter=tsplitat(newline)
-patterns.linesplitter=linesplitter
-function string.splitlines(str)
-  return lpegmatch(linesplitter,str)
-end
-local cache={}
-function lpeg.checkedsplit(separator,str)
-  local c=cache[separator]
-  if not c then
-    separator=P(separator)
-    local other=C((1-separator)^1)
-    c=Ct(separator^0*other*(separator^1*other)^0)
-    cache[separator]=c
-  end
-  return lpegmatch(c,str)
-end
-function string.checkedsplit(str,separator)
-  local c=cache[separator]
-  if not c then
-    separator=P(separator)
-    local other=C((1-separator)^1)
-    c=Ct(separator^0*other*(separator^1*other)^0)
-    cache[separator]=c
-  end
-  return lpegmatch(c,str)
-end
-local function f2(s) local c1,c2=byte(s,1,2) return  c1*64+c2-12416 end
-local function f3(s) local c1,c2,c3=byte(s,1,3) return (c1*64+c2)*64+c3-925824 end
-local function f4(s) local c1,c2,c3,c4=byte(s,1,4) return ((c1*64+c2)*64+c3)*64+c4-63447168 end
-local utf8byte=patterns.utf8one/byte+patterns.utf8two/f2+patterns.utf8three/f3+patterns.utf8four/f4
-patterns.utf8byte=utf8byte
-local cache={}
-function lpeg.stripper(str)
-  if type(str)=="string" then
-    local s=cache[str]
-    if not s then
-      s=Cs(((S(str)^1)/""+1)^0)
-      cache[str]=s
-    end
-    return s
-  else
-    return Cs(((str^1)/""+1)^0)
-  end
-end
-local cache={}
-function lpeg.keeper(str)
-  if type(str)=="string" then
-    local s=cache[str]
-    if not s then
-      s=Cs((((1-S(str))^1)/""+1)^0)
-      cache[str]=s
-    end
-    return s
-  else
-    return Cs((((1-str)^1)/""+1)^0)
-  end
-end
-function lpeg.frontstripper(str) 
-  return (P(str)+P(true))*Cs(anything^0)
-end
-function lpeg.endstripper(str) 
-  return Cs((1-P(str)*endofstring)^0)
-end
-function lpeg.replacer(one,two,makefunction,isutf) 
-  local pattern
-  local u=isutf and utf8char or 1
-  if type(one)=="table" then
-    local no=#one
-    local p=P(false)
-    if no==0 then
-      for k,v in next,one do
-        p=p+P(k)/v
-      end
-      pattern=Cs((p+u)^0)
-    elseif no==1 then
-      local o=one[1]
-      one,two=P(o[1]),o[2]
-      pattern=Cs((one/two+u)^0)
-    else
-      for i=1,no do
-        local o=one[i]
-        p=p+P(o[1])/o[2]
-      end
-      pattern=Cs((p+u)^0)
-    end
-  else
-    pattern=Cs((P(one)/(two or "")+u)^0)
-  end
-  if makefunction then
-    return function(str)
-      return lpegmatch(pattern,str)
-    end
-  else
-    return pattern
-  end
-end
-function lpeg.finder(lst,makefunction,isutf) 
-  local pattern
-  if type(lst)=="table" then
-    pattern=P(false)
-    if #lst==0 then
-      for k,v in next,lst do
-        pattern=pattern+P(k) 
-      end
-    else
-      for i=1,#lst do
-        pattern=pattern+P(lst[i])
-      end
-    end
-  else
-    pattern=P(lst)
-  end
-  if isutf then
-    pattern=((utf8char or 1)-pattern)^0*pattern
-  else
-    pattern=(1-pattern)^0*pattern
-  end
-  if makefunction then
-    return function(str)
-      return lpegmatch(pattern,str)
-    end
-  else
-    return pattern
-  end
-end
-local splitters_f,splitters_s={},{}
-function lpeg.firstofsplit(separator) 
-  local splitter=splitters_f[separator]
-  if not splitter then
-    local pattern=P(separator)
-    splitter=C((1-pattern)^0)
-    splitters_f[separator]=splitter
-  end
-  return splitter
-end
-function lpeg.secondofsplit(separator) 
-  local splitter=splitters_s[separator]
-  if not splitter then
-    local pattern=P(separator)
-    splitter=(1-pattern)^0*pattern*C(anything^0)
-    splitters_s[separator]=splitter
-  end
-  return splitter
-end
-local splitters_s,splitters_p={},{}
-function lpeg.beforesuffix(separator) 
-  local splitter=splitters_s[separator]
-  if not splitter then
-    local pattern=P(separator)
-    splitter=C((1-pattern)^0)*pattern*endofstring
-    splitters_s[separator]=splitter
-  end
-  return splitter
-end
-function lpeg.afterprefix(separator) 
-  local splitter=splitters_p[separator]
-  if not splitter then
-    local pattern=P(separator)
-    splitter=pattern*C(anything^0)
-    splitters_p[separator]=splitter
-  end
-  return splitter
-end
-function lpeg.balancer(left,right)
-  left,right=P(left),P(right)
-  return P { left*((1-left-right)+V(1))^0*right }
-end
-local nany=utf8char/""
-function lpeg.counter(pattern)
-  pattern=Cs((P(pattern)/" "+nany)^0)
-  return function(str)
-    return #lpegmatch(pattern,str)
-  end
-end
-utf=utf or (unicode and unicode.utf8) or {}
-local utfcharacters=utf and utf.characters or string.utfcharacters
-local utfgmatch=utf and utf.gmatch
-local utfchar=utf and utf.char
-lpeg.UP=lpeg.P
-if utfcharacters then
-  function lpeg.US(str)
-    local p=P(false)
-    for uc in utfcharacters(str) do
-      p=p+P(uc)
-    end
-    return p
-  end
-elseif utfgmatch then
-  function lpeg.US(str)
-    local p=P(false)
-    for uc in utfgmatch(str,".") do
-      p=p+P(uc)
-    end
-    return p
-  end
-else
-  function lpeg.US(str)
-    local p=P(false)
-    local f=function(uc)
-      p=p+P(uc)
-    end
-    lpegmatch((utf8char/f)^0,str)
-    return p
-  end
-end
-local range=utf8byte*utf8byte+Cc(false) 
-function lpeg.UR(str,more)
-  local first,last
-  if type(str)=="number" then
-    first=str
-    last=more or first
-  else
-    first,last=lpegmatch(range,str)
-    if not last then
-      return P(str)
-    end
-  end
-  if first==last then
-    return P(str)
-  elseif utfchar and (last-first<8) then 
-    local p=P(false)
-    for i=first,last do
-      p=p+P(utfchar(i))
-    end
-    return p 
-  else
-    local f=function(b)
-      return b>=first and b<=last
-    end
-    return utf8byte/f 
-  end
-end
-function lpeg.is_lpeg(p)
-  return p and lpegtype(p)=="pattern"
-end
-function lpeg.oneof(list,...) 
-  if type(list)~="table" then
-    list={ list,... }
-  end
-  local p=P(list[1])
-  for l=2,#list do
-    p=p+P(list[l])
-  end
-  return p
-end
-local sort=table.sort
-local function copyindexed(old)
-  local new={}
-  for i=1,#old do
-    new[i]=old
-  end
-  return new
-end
-local function sortedkeys(tab)
-  local keys,s={},0
-  for key,_ in next,tab do
-    s=s+1
-    keys[s]=key
-  end
-  sort(keys)
-  return keys
-end
-function lpeg.append(list,pp,delayed,checked)
-  local p=pp
-  if #list>0 then
-    local keys=copyindexed(list)
-    sort(keys)
-    for i=#keys,1,-1 do
-      local k=keys[i]
-      if p then
-        p=P(k)+p
-      else
-        p=P(k)
-      end
-    end
-  elseif delayed then 
-    local keys=sortedkeys(list)
-    if p then
-      for i=1,#keys,1 do
-        local k=keys[i]
-        local v=list[k]
-        p=P(k)/list+p
-      end
-    else
-      for i=1,#keys do
-        local k=keys[i]
-        local v=list[k]
-        if p then
-          p=P(k)+p
-        else
-          p=P(k)
-        end
-      end
-      if p then
-        p=p/list
-      end
-    end
-  elseif checked then
-    local keys=sortedkeys(list)
-    for i=1,#keys do
-      local k=keys[i]
-      local v=list[k]
-      if p then
-        if k==v then
-          p=P(k)+p
-        else
-          p=P(k)/v+p
-        end
-      else
-        if k==v then
-          p=P(k)
-        else
-          p=P(k)/v
-        end
-      end
-    end
-  else
-    local keys=sortedkeys(list)
-    for i=1,#keys do
-      local k=keys[i]
-      local v=list[k]
-      if p then
-        p=P(k)/v+p
-      else
-        p=P(k)/v
-      end
-    end
-  end
-  return p
-end
-local function make(t,hash)
-  local p=P(false)
-  local keys=sortedkeys(t)
-  for i=1,#keys do
-    local k=keys[i]
-    local v=t[k]
-    local h=hash[v]
-    if h then
-      if next(v) then
-        p=p+P(k)*(make(v,hash)+P(true))
-      else
-        p=p+P(k)*P(true)
-      end
-    else
-      if next(v) then
-        p=p+P(k)*make(v,hash)
-      else
-        p=p+P(k)
-      end
-    end
-  end
-  return p
-end
-function lpeg.utfchartabletopattern(list) 
-  local tree={}
-  local hash={}
-  local n=#list
-  if n==0 then
-    for s in next,list do
-      local t=tree
-      for c in gmatch(s,".") do
-        local tc=t[c]
-        if not tc then
-          tc={}
-          t[c]=tc
-        end
-        t=tc
-      end
-      hash[t]=s
-    end
-  else
-    for i=1,n do
-      local t=tree
-      local s=list[i]
-      for c in gmatch(s,".") do
-        local tc=t[c]
-        if not tc then
-          tc={}
-          t[c]=tc
-        end
-        t=tc
-      end
-      hash[t]=s
-    end
-  end
-  return make(tree,hash)
-end
-patterns.containseol=lpeg.finder(eol)
-local function nextstep(n,step,result)
-  local m=n%step   
-  local d=floor(n/step) 
-  if d>0 then
-    local v=V(tostring(step))
-    local s=result.start
-    for i=1,d do
-      if s then
-        s=v*s
-      else
-        s=v
-      end
-    end
-    result.start=s
-  end
-  if step>1 and result.start then
-    local v=V(tostring(step/2))
-    result[tostring(step)]=v*v
-  end
-  if step>0 then
-    return nextstep(m,step/2,result)
-  else
-    return result
-  end
-end
-function lpeg.times(pattern,n)
-  return P(nextstep(n,2^16,{ "start",["1"]=pattern }))
-end
-local trailingzeros=zero^0*-digit 
-local case_1=period*trailingzeros/""
-local case_2=period*(digit-trailingzeros)^1*(trailingzeros/"")
-local number=digit^1*(case_1+case_2)
-local stripper=Cs((number+1)^0)
-lpeg.patterns.stripzeros=stripper
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-functions']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-functions=functions or {}
-function functions.dummy() end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-string']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local string=string
-local sub,gmatch,format,char,byte,rep,lower=string.sub,string.gmatch,string.format,string.char,string.byte,string.rep,string.lower
-local lpegmatch,patterns=lpeg.match,lpeg.patterns
-local P,S,C,Ct,Cc,Cs=lpeg.P,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cc,lpeg.Cs
-local unquoted=patterns.squote*C(patterns.nosquote)*patterns.squote+patterns.dquote*C(patterns.nodquote)*patterns.dquote
-function string.unquoted(str)
-  return lpegmatch(unquoted,str) or str
-end
-function string.quoted(str)
-  return format("%q",str) 
-end
-function string.count(str,pattern) 
-  local n=0
-  for _ in gmatch(str,pattern) do 
-    n=n+1
-  end
-  return n
-end
-function string.limit(str,n,sentinel) 
-  if #str>n then
-    sentinel=sentinel or "..."
-    return sub(str,1,(n-#sentinel))..sentinel
-  else
-    return str
-  end
-end
-local stripper=patterns.stripper
-local fullstripper=patterns.fullstripper
-local collapser=patterns.collapser
-local longtostring=patterns.longtostring
-function string.strip(str)
-  return lpegmatch(stripper,str) or ""
-end
-function string.fullstrip(str)
-  return lpegmatch(fullstripper,str) or ""
-end
-function string.collapsespaces(str)
-  return lpegmatch(collapser,str) or ""
-end
-function string.longtostring(str)
-  return lpegmatch(longtostring,str) or ""
-end
-local pattern=P(" ")^0*P(-1)
-function string.is_empty(str)
-  if str=="" then
-    return true
-  else
-    return lpegmatch(pattern,str) and true or false
-  end
-end
-local anything=patterns.anything
-local allescapes=Cc("%")*S(".-+%?()[]*") 
-local someescapes=Cc("%")*S(".-+%()[]")  
-local matchescapes=Cc(".")*S("*?")     
-local pattern_a=Cs ((allescapes+anything )^0 )
-local pattern_b=Cs ((someescapes+matchescapes+anything )^0 )
-local pattern_c=Cs (Cc("^")*(someescapes+matchescapes+anything )^0*Cc("$") )
-function string.escapedpattern(str,simple)
-  return lpegmatch(simple and pattern_b or pattern_a,str)
-end
-function string.topattern(str,lowercase,strict)
-  if str=="" or type(str)~="string" then
-    return ".*"
-  elseif strict then
-    str=lpegmatch(pattern_c,str)
-  else
-    str=lpegmatch(pattern_b,str)
-  end
-  if lowercase then
-    return lower(str)
-  else
-    return str
-  end
-end
-function string.valid(str,default)
-  return (type(str)=="string" and str~="" and str) or default or nil
-end
-string.itself=function(s) return s end
-local pattern=Ct(C(1)^0) 
-function string.totable(str)
-  return lpegmatch(pattern,str)
-end
-local replacer=lpeg.replacer("@","%%") 
-function string.tformat(fmt,...)
-  return format(lpegmatch(replacer,fmt),...)
-end
-string.quote=string.quoted
-string.unquote=string.unquoted
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-table']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local type,next,tostring,tonumber,ipairs,select=type,next,tostring,tonumber,ipairs,select
-local table,string=table,string
-local concat,sort,insert,remove=table.concat,table.sort,table.insert,table.remove
-local format,lower,dump=string.format,string.lower,string.dump
-local getmetatable,setmetatable=getmetatable,setmetatable
-local getinfo=debug.getinfo
-local lpegmatch,patterns=lpeg.match,lpeg.patterns
-local floor=math.floor
-local stripper=patterns.stripper
-function table.strip(tab)
-  local lst,l={},0
-  for i=1,#tab do
-    local s=lpegmatch(stripper,tab[i]) or ""
-    if s=="" then
-    else
-      l=l+1
-      lst[l]=s
-    end
-  end
-  return lst
-end
-function table.keys(t)
-  if t then
-    local keys,k={},0
-    for key,_ in next,t do
-      k=k+1
-      keys[k]=key
-    end
-    return keys
-  else
-    return {}
-  end
-end
-local function compare(a,b)
-  local ta,tb=type(a),type(b) 
-  if ta==tb then
-    return a<b
-  else
-    return tostring(a)<tostring(b)
-  end
-end
-local function sortedkeys(tab)
-  if tab then
-    local srt,category,s={},0,0 
-    for key,_ in next,tab do
-      s=s+1
-      srt[s]=key
-      if category==3 then
-      else
-        local tkey=type(key)
-        if tkey=="string" then
-          category=(category==2 and 3) or 1
-        elseif tkey=="number" then
-          category=(category==1 and 3) or 2
-        else
-          category=3
-        end
-      end
-    end
-    if category==0 or category==3 then
-      sort(srt,compare)
-    else
-      sort(srt)
-    end
-    return srt
-  else
-    return {}
-  end
-end
-local function sortedhashonly(tab)
-  if tab then
-    local srt,s={},0
-    for key,_ in next,tab do
-      if type(key)=="string" then
-        s=s+1
-        srt[s]=key
-      end
-    end
-    sort(srt)
-    return srt
-  else
-    return {}
-  end
-end
-local function sortedindexonly(tab)
-  if tab then
-    local srt,s={},0
-    for key,_ in next,tab do
-      if type(key)=="number" then
-        s=s+1
-        srt[s]=key
-      end
-    end
-    sort(srt)
-    return srt
-  else
-    return {}
-  end
-end
-local function sortedhashkeys(tab,cmp) 
-  if tab then
-    local srt,s={},0
-    for key,_ in next,tab do
-      if key then
-        s=s+1
-        srt[s]=key
-      end
-    end
-    sort(srt,cmp)
-    return srt
-  else
-    return {}
-  end
-end
-function table.allkeys(t)
-  local keys={}
-  for k,v in next,t do
-    for k,v in next,v do
-      keys[k]=true
-    end
-  end
-  return sortedkeys(keys)
-end
-table.sortedkeys=sortedkeys
-table.sortedhashonly=sortedhashonly
-table.sortedindexonly=sortedindexonly
-table.sortedhashkeys=sortedhashkeys
-local function nothing() end
-local function sortedhash(t,cmp)
-  if t then
-    local s
-    if cmp then
-      s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end)
-    else
-      s=sortedkeys(t) 
-    end
-    local n=0
-    local m=#s
-    local function kv() 
-      if n<m then
-        n=n+1
-        local k=s[n]
-        return k,t[k]
-      end
-    end
-    return kv 
-  else
-    return nothing
-  end
-end
-table.sortedhash=sortedhash
-table.sortedpairs=sortedhash 
-function table.append(t,list)
-  local n=#t
-  for i=1,#list do
-    n=n+1
-    t[n]=list[i]
-  end
-  return t
-end
-function table.prepend(t,list)
-  local nl=#list
-  local nt=nl+#t
-  for i=#t,1,-1 do
-    t[nt]=t[i]
-    nt=nt-1
-  end
-  for i=1,#list do
-    t[i]=list[i]
-  end
-  return t
-end
-function table.merge(t,...) 
-  t=t or {}
-  for i=1,select("#",...) do
-    for k,v in next,(select(i,...)) do
-      t[k]=v
-    end
-  end
-  return t
-end
-function table.merged(...)
-  local t={}
-  for i=1,select("#",...) do
-    for k,v in next,(select(i,...)) do
-      t[k]=v
-    end
-  end
-  return t
-end
-function table.imerge(t,...)
-  local nt=#t
-  for i=1,select("#",...) do
-    local nst=select(i,...)
-    for j=1,#nst do
-      nt=nt+1
-      t[nt]=nst[j]
-    end
-  end
-  return t
-end
-function table.imerged(...)
-  local tmp,ntmp={},0
-  for i=1,select("#",...) do
-    local nst=select(i,...)
-    for j=1,#nst do
-      ntmp=ntmp+1
-      tmp[ntmp]=nst[j]
-    end
-  end
-  return tmp
-end
-local function fastcopy(old,metatabletoo) 
-  if old then
-    local new={}
-    for k,v in next,old do
-      if type(v)=="table" then
-        new[k]=fastcopy(v,metatabletoo) 
-      else
-        new[k]=v
-      end
-    end
-    if metatabletoo then
-      local mt=getmetatable(old)
-      if mt then
-        setmetatable(new,mt)
-      end
-    end
-    return new
-  else
-    return {}
-  end
-end
-local function copy(t,tables) 
-  tables=tables or {}
-  local tcopy={}
-  if not tables[t] then
-    tables[t]=tcopy
-  end
-  for i,v in next,t do 
-    if type(i)=="table" then
-      if tables[i] then
-        i=tables[i]
-      else
-        i=copy(i,tables)
-      end
-    end
-    if type(v)~="table" then
-      tcopy[i]=v
-    elseif tables[v] then
-      tcopy[i]=tables[v]
-    else
-      tcopy[i]=copy(v,tables)
-    end
-  end
-  local mt=getmetatable(t)
-  if mt then
-    setmetatable(tcopy,mt)
-  end
-  return tcopy
-end
-table.fastcopy=fastcopy
-table.copy=copy
-function table.derive(parent) 
-  local child={}
-  if parent then
-    setmetatable(child,{ __index=parent })
-  end
-  return child
-end
-function table.tohash(t,value)
-  local h={}
-  if t then
-    if value==nil then value=true end
-    for _,v in next,t do 
-      h[v]=value
-    end
-  end
-  return h
-end
-function table.fromhash(t)
-  local hsh,h={},0
-  for k,v in next,t do 
-    if v then
-      h=h+1
-      hsh[h]=k
-    end
-  end
-  return hsh
-end
-local noquotes,hexify,handle,reduce,compact,inline,functions
-local reserved=table.tohash { 
-  'and','break','do','else','elseif','end','false','for','function','if',
-  'in','local','nil','not','or','repeat','return','then','true','until','while',
-  'NaN','goto',
-}
-local function simple_table(t)
-  if #t>0 then
-    local n=0
-    for _,v in next,t do
-      n=n+1
-    end
-    if n==#t then
-      local tt,nt={},0
-      for i=1,#t do
-        local v=t[i]
-        local tv=type(v)
-        if tv=="number" then
-          nt=nt+1
-          if hexify then
-            tt[nt]=format("0x%X",v)
-          else
-            tt[nt]=tostring(v) 
-          end
-        elseif tv=="string" then
-          nt=nt+1
-          tt[nt]=format("%q",v)
-        elseif tv=="boolean" then
-          nt=nt+1
-          tt[nt]=v and "true" or "false"
-        else
-          tt=nil
-          break
-        end
-      end
-      return tt
-    end
-  end
-  return nil
-end
-local propername=patterns.propername 
-local function dummy() end
-local function do_serialize(root,name,depth,level,indexed)
-  if level>0 then
-    depth=depth.." "
-    if indexed then
-      handle(format("%s{",depth))
-    else
-      local tn=type(name)
-      if tn=="number" then
-        if hexify then
-          handle(format("%s[0x%X]={",depth,name))
-        else
-          handle(format("%s[%s]={",depth,name))
-        end
-      elseif tn=="string" then
-        if noquotes and not reserved[name] and lpegmatch(propername,name) then
-          handle(format("%s%s={",depth,name))
-        else
-          handle(format("%s[%q]={",depth,name))
-        end
-      elseif tn=="boolean" then
-        handle(format("%s[%s]={",depth,name and "true" or "false"))
-      else
-        handle(format("%s{",depth))
-      end
-    end
-  end
-  if root and next(root) then
-    local first,last=nil,0
-    if compact then
-      last=#root
-      for k=1,last do
-        if root[k]==nil then
-          last=k-1
-          break
-        end
-      end
-      if last>0 then
-        first=1
-      end
-    end
-    local sk=sortedkeys(root)
-    for i=1,#sk do
-      local k=sk[i]
-      local v=root[k]
-      local tv,tk=type(v),type(k)
-      if compact and first and tk=="number" and k>=first and k<=last then
-        if tv=="number" then
-          if hexify then
-            handle(format("%s 0x%X,",depth,v))
-          else
-            handle(format("%s %s,",depth,v)) 
-          end
-        elseif tv=="string" then
-          if reduce and tonumber(v) then
-            handle(format("%s %s,",depth,v))
-          else
-            handle(format("%s %q,",depth,v))
-          end
-        elseif tv=="table" then
-          if not next(v) then
-            handle(format("%s {},",depth))
-          elseif inline then 
-            local st=simple_table(v)
-            if st then
-              handle(format("%s { %s },",depth,concat(st,", ")))
-            else
-              do_serialize(v,k,depth,level+1,true)
-            end
-          else
-            do_serialize(v,k,depth,level+1,true)
-          end
-        elseif tv=="boolean" then
-          handle(format("%s %s,",depth,v and "true" or "false"))
-        elseif tv=="function" then
-          if functions then
-            handle(format('%s load(%q),',depth,dump(v))) 
-          else
-            handle(format('%s "function",',depth))
-          end
-        else
-          handle(format("%s %q,",depth,tostring(v)))
-        end
-      elseif k=="__p__" then 
-        if false then
-          handle(format("%s __p__=nil,",depth))
-        end
-      elseif tv=="number" then
-        if tk=="number" then
-          if hexify then
-            handle(format("%s [0x%X]=0x%X,",depth,k,v))
-          else
-            handle(format("%s [%s]=%s,",depth,k,v)) 
-          end
-        elseif tk=="boolean" then
-          if hexify then
-            handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v))
-          else
-            handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) 
-          end
-        elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
-          if hexify then
-            handle(format("%s %s=0x%X,",depth,k,v))
-          else
-            handle(format("%s %s=%s,",depth,k,v)) 
-          end
-        else
-          if hexify then
-            handle(format("%s [%q]=0x%X,",depth,k,v))
-          else
-            handle(format("%s [%q]=%s,",depth,k,v)) 
-          end
-        end
-      elseif tv=="string" then
-        if reduce and tonumber(v) then
-          if tk=="number" then
-            if hexify then
-              handle(format("%s [0x%X]=%s,",depth,k,v))
-            else
-              handle(format("%s [%s]=%s,",depth,k,v))
-            end
-          elseif tk=="boolean" then
-            handle(format("%s [%s]=%s,",depth,k and "true" or "false",v))
-          elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
-            handle(format("%s %s=%s,",depth,k,v))
-          else
-            handle(format("%s [%q]=%s,",depth,k,v))
-          end
-        else
-          if tk=="number" then
-            if hexify then
-              handle(format("%s [0x%X]=%q,",depth,k,v))
-            else
-              handle(format("%s [%s]=%q,",depth,k,v))
-            end
-          elseif tk=="boolean" then
-            handle(format("%s [%s]=%q,",depth,k and "true" or "false",v))
-          elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
-            handle(format("%s %s=%q,",depth,k,v))
-          else
-            handle(format("%s [%q]=%q,",depth,k,v))
-          end
-        end
-      elseif tv=="table" then
-        if not next(v) then
-          if tk=="number" then
-            if hexify then
-              handle(format("%s [0x%X]={},",depth,k))
-            else
-              handle(format("%s [%s]={},",depth,k))
-            end
-          elseif tk=="boolean" then
-            handle(format("%s [%s]={},",depth,k and "true" or "false"))
-          elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
-            handle(format("%s %s={},",depth,k))
-          else
-            handle(format("%s [%q]={},",depth,k))
-          end
-        elseif inline then
-          local st=simple_table(v)
-          if st then
-            if tk=="number" then
-              if hexify then
-                handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", ")))
-              else
-                handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))
-              end
-            elseif tk=="boolean" then
-              handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", ")))
-            elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
-              handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
-            else
-              handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
-            end
-          else
-            do_serialize(v,k,depth,level+1)
-          end
-        else
-          do_serialize(v,k,depth,level+1)
-        end
-      elseif tv=="boolean" then
-        if tk=="number" then
-          if hexify then
-            handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false"))
-          else
-            handle(format("%s [%s]=%s,",depth,k,v and "true" or "false"))
-          end
-        elseif tk=="boolean" then
-          handle(format("%s [%s]=%s,",depth,tostring(k),v and "true" or "false"))
-        elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
-          handle(format("%s %s=%s,",depth,k,v and "true" or "false"))
-        else
-          handle(format("%s [%q]=%s,",depth,k,v and "true" or "false"))
-        end
-      elseif tv=="function" then
-        if functions then
-          local f=getinfo(v).what=="C" and dump(dummy) or dump(v)
-          if tk=="number" then
-            if hexify then
-              handle(format("%s [0x%X]=load(%q),",depth,k,f))
-            else
-              handle(format("%s [%s]=load(%q),",depth,k,f))
-            end
-          elseif tk=="boolean" then
-            handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f))
-          elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
-            handle(format("%s %s=load(%q),",depth,k,f))
-          else
-            handle(format("%s [%q]=load(%q),",depth,k,f))
-          end
-        end
-      else
-        if tk=="number" then
-          if hexify then
-            handle(format("%s [0x%X]=%q,",depth,k,tostring(v)))
-          else
-            handle(format("%s [%s]=%q,",depth,k,tostring(v)))
-          end
-        elseif tk=="boolean" then
-          handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v)))
-        elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
-          handle(format("%s %s=%q,",depth,k,tostring(v)))
-        else
-          handle(format("%s [%q]=%q,",depth,k,tostring(v)))
-        end
-      end
-    end
-  end
-  if level>0 then
-    handle(format("%s},",depth))
-  end
-end
-local function serialize(_handle,root,name,specification) 
-  local tname=type(name)
-  if type(specification)=="table" then
-    noquotes=specification.noquotes
-    hexify=specification.hexify
-    handle=_handle or specification.handle or print
-    reduce=specification.reduce or false
-    functions=specification.functions
-    compact=specification.compact
-    inline=specification.inline and compact
-    if functions==nil then
-      functions=true
-    end
-    if compact==nil then
-      compact=true
-    end
-    if inline==nil then
-      inline=compact
-    end
-  else
-    noquotes=false
-    hexify=false
-    handle=_handle or print
-    reduce=false
-    compact=true
-    inline=true
-    functions=true
-  end
-  if tname=="string" then
-    if name=="return" then
-      handle("return {")
-    else
-      handle(name.."={")
-    end
-  elseif tname=="number" then
-    if hexify then
-      handle(format("[0x%X]={",name))
-    else
-      handle("["..name.."]={")
-    end
-  elseif tname=="boolean" then
-    if name then
-      handle("return {")
-    else
-      handle("{")
-    end
-  else
-    handle("t={")
-  end
-  if root then
-    if getmetatable(root) then 
-      local dummy=root._w_h_a_t_e_v_e_r_
-      root._w_h_a_t_e_v_e_r_=nil
-    end
-    if next(root) then
-      do_serialize(root,name,"",0)
-    end
-  end
-  handle("}")
-end
-function table.serialize(root,name,specification)
-  local t,n={},0
-  local function flush(s)
-    n=n+1
-    t[n]=s
-  end
-  serialize(flush,root,name,specification)
-  return concat(t,"\n")
-end
-table.tohandle=serialize
-local maxtab=2*1024
-function table.tofile(filename,root,name,specification)
-  local f=io.open(filename,'w')
-  if f then
-    if maxtab>1 then
-      local t,n={},0
-      local function flush(s)
-        n=n+1
-        t[n]=s
-        if n>maxtab then
-          f:write(concat(t,"\n"),"\n") 
-          t,n={},0 
-        end
-      end
-      serialize(flush,root,name,specification)
-      f:write(concat(t,"\n"),"\n")
-    else
-      local function flush(s)
-        f:write(s,"\n")
-      end
-      serialize(flush,root,name,specification)
-    end
-    f:close()
-    io.flush()
-  end
-end
-local function flattened(t,f,depth) 
-  if f==nil then
-    f={}
-    depth=0xFFFF
-  elseif tonumber(f) then
-    depth=f
-    f={}
-  elseif not depth then
-    depth=0xFFFF
-  end
-  for k,v in next,t do
-    if type(k)~="number" then
-      if depth>0 and type(v)=="table" then
-        flattened(v,f,depth-1)
-      else
-        f[#f+1]=v
-      end
-    end
-  end
-  for k=1,#t do
-    local v=t[k]
-    if depth>0 and type(v)=="table" then
-      flattened(v,f,depth-1)
-    else
-      f[#f+1]=v
-    end
-  end
-  return f
-end
-table.flattened=flattened
-local function unnest(t,f) 
-  if not f then     
-    f={}      
-  end
-  for i=1,#t do
-    local v=t[i]
-    if type(v)=="table" then
-      if type(v[1])=="table" then
-        unnest(v,f)
-      else
-        f[#f+1]=v
-      end
-    else
-      f[#f+1]=v
-    end
-  end
-  return f
-end
-function table.unnest(t) 
-  return unnest(t)
-end
-local function are_equal(a,b,n,m) 
-  if a and b and #a==#b then
-    n=n or 1
-    m=m or #a
-    for i=n,m do
-      local ai,bi=a[i],b[i]
-      if ai==bi then
-      elseif type(ai)=="table" and type(bi)=="table" then
-        if not are_equal(ai,bi) then
-          return false
-        end
-      else
-        return false
-      end
-    end
-    return true
-  else
-    return false
-  end
-end
-local function identical(a,b) 
-  for ka,va in next,a do
-    local vb=b[ka]
-    if va==vb then
-    elseif type(va)=="table" and type(vb)=="table" then
-      if not identical(va,vb) then
-        return false
-      end
-    else
-      return false
-    end
-  end
-  return true
-end
-table.identical=identical
-table.are_equal=are_equal
-local function sparse(old,nest,keeptables)
-  local new={}
-  for k,v in next,old do
-    if not (v=="" or v==false) then
-      if nest and type(v)=="table" then
-        v=sparse(v,nest)
-        if keeptables or next(v) then
-          new[k]=v
-        end
-      else
-        new[k]=v
-      end
-    end
-  end
-  return new
-end
-table.sparse=sparse
-function table.compact(t)
-  return sparse(t,true,true)
-end
-function table.contains(t,v)
-  if t then
-    for i=1,#t do
-      if t[i]==v then
-        return i
-      end
-    end
-  end
-  return false
-end
-function table.count(t)
-  local n=0
-  for k,v in next,t do
-    n=n+1
-  end
-  return n
-end
-function table.swapped(t,s) 
-  local n={}
-  if s then
-    for k,v in next,s do
-      n[k]=v
-    end
-  end
-  for k,v in next,t do
-    n[v]=k
-  end
-  return n
-end
-function table.mirrored(t) 
-  local n={}
-  for k,v in next,t do
-    n[v]=k
-    n[k]=v
-  end
-  return n
-end
-function table.reversed(t)
-  if t then
-    local tt,tn={},#t
-    if tn>0 then
-      local ttn=0
-      for i=tn,1,-1 do
-        ttn=ttn+1
-        tt[ttn]=t[i]
-      end
-    end
-    return tt
-  end
-end
-function table.reverse(t)
-  if t then
-    local n=#t
-    for i=1,floor(n/2) do
-      local j=n-i+1
-      t[i],t[j]=t[j],t[i]
-    end
-    return t
-  end
-end
-function table.sequenced(t,sep,simple) 
-  if not t then
-    return ""
-  end
-  local n=#t
-  local s={}
-  if n>0 then
-    for i=1,n do
-      s[i]=tostring(t[i])
-    end
-  else
-    n=0
-    for k,v in sortedhash(t) do
-      if simple then
-        if v==true then
-          n=n+1
-          s[n]=k
-        elseif v and v~="" then
-          n=n+1
-          s[n]=k.."="..tostring(v)
-        end
-      else
-        n=n+1
-        s[n]=k.."="..tostring(v)
-      end
-    end
-  end
-  return concat(s,sep or " | ")
-end
-function table.print(t,...)
-  if type(t)~="table" then
-    print(tostring(t))
-  else
-    serialize(print,t,...)
-  end
-end
-if setinspector then
-  setinspector(function(v) if type(v)=="table" then serialize(print,v,"table") return true end end)
-end
-function table.sub(t,i,j)
-  return { unpack(t,i,j) }
-end
-function table.is_empty(t)
-  return not t or not next(t)
-end
-function table.has_one_entry(t)
-  return t and not next(t,next(t))
-end
-function table.loweredkeys(t) 
-  local l={}
-  for k,v in next,t do
-    l[lower(k)]=v
-  end
-  return l
-end
-function table.unique(old)
-  local hash={}
-  local new={}
-  local n=0
-  for i=1,#old do
-    local oi=old[i]
-    if not hash[oi] then
-      n=n+1
-      new[n]=oi
-      hash[oi]=true
-    end
-  end
-  return new
-end
-function table.sorted(t,...)
-  sort(t,...)
-  return t 
-end
-function table.values(t,s) 
-  if t then
-    local values,keys,v={},{},0
-    for key,value in next,t do
-      if not keys[value] then
-        v=v+1
-        values[v]=value
-        keys[k]=key
-      end
-    end
-    if s then
-      sort(values)
-    end
-    return values
-  else
-    return {}
-  end
-end
-function table.filtered(t,pattern,sort,cmp)
-  if t and type(pattern)=="string" then
-    if sort then
-      local s
-      if cmp then
-        s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end)
-      else
-        s=sortedkeys(t) 
-      end
-      local n=0
-      local m=#s
-      local function kv(s)
-        while n<m do
-          n=n+1
-          local k=s[n]
-          if find(k,pattern) then
-            return k,t[k]
-          end
-        end
-      end
-      return kv,s
-    else
-      local n=next(t)
-      local function iterator()
-        while n do
-          local k=n
-          n=next(t,k)
-          if find(k,pattern) then
-            return k,t[k]
-          end
-        end
-      end
-      return iterator,t
-    end
-  else
-    return nothing
-  end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-io']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local io=io
-local byte,find,gsub,format=string.byte,string.find,string.gsub,string.format
-local concat=table.concat
-local floor=math.floor
-local type=type
-if string.find(os.getenv("PATH"),";",1,true) then
-  io.fileseparator,io.pathseparator="\\",";"
-else
-  io.fileseparator,io.pathseparator="/",":"
-end
-local function readall(f)
-  return f:read("*all")
-end
-local function readall(f)
-  local size=f:seek("end")
-  if size==0 then
-    return ""
-  elseif size<1024*1024 then
-    f:seek("set",0)
-    return f:read('*all')
-  else
-    local done=f:seek("set",0)
-    local step
-    if size<1024*1024 then
-      step=1024*1024
-    elseif size>16*1024*1024 then
-      step=16*1024*1024
-    else
-      step=floor(size/(1024*1024))*1024*1024/8
-    end
-    local data={}
-    while true do
-      local r=f:read(step)
-      if not r then
-        return concat(data)
-      else
-        data[#data+1]=r
-      end
-    end
-  end
-end
-io.readall=readall
-function io.loaddata(filename,textmode) 
-  local f=io.open(filename,(textmode and 'r') or 'rb')
-  if f then
-    local data=readall(f)
-    f:close()
-    if #data>0 then
-      return data
-    end
-  end
-end
-function io.savedata(filename,data,joiner)
-  local f=io.open(filename,"wb")
-  if f then
-    if type(data)=="table" then
-      f:write(concat(data,joiner or ""))
-    elseif type(data)=="function" then
-      data(f)
-    else
-      f:write(data or "")
-    end
-    f:close()
-    io.flush()
-    return true
-  else
-    return false
-  end
-end
-function io.loadlines(filename,n) 
-  local f=io.open(filename,'r')
-  if not f then
-  elseif n then
-    local lines={}
-    for i=1,n do
-      local line=f:read("*lines")
-      if line then
-        lines[#lines+1]=line
-      else
-        break
-      end
-    end
-    f:close()
-    lines=concat(lines,"\n")
-    if #lines>0 then
-      return lines
-    end
-  else
-    local line=f:read("*line") or ""
-    f:close()
-    if #line>0 then
-      return line
-    end
-  end
-end
-function io.loadchunk(filename,n)
-  local f=io.open(filename,'rb')
-  if f then
-    local data=f:read(n or 1024)
-    f:close()
-    if #data>0 then
-      return data
-    end
-  end
-end
-function io.exists(filename)
-  local f=io.open(filename)
-  if f==nil then
-    return false
-  else
-    f:close()
-    return true
-  end
-end
-function io.size(filename)
-  local f=io.open(filename)
-  if f==nil then
-    return 0
-  else
-    local s=f:seek("end")
-    f:close()
-    return s
-  end
-end
-function io.noflines(f)
-  if type(f)=="string" then
-    local f=io.open(filename)
-    if f then
-      local n=f and io.noflines(f) or 0
-      f:close()
-      return n
-    else
-      return 0
-    end
-  else
-    local n=0
-    for _ in f:lines() do
-      n=n+1
-    end
-    f:seek('set',0)
-    return n
-  end
-end
-local nextchar={
-  [ 4]=function(f)
-    return f:read(1,1,1,1)
-  end,
-  [ 2]=function(f)
-    return f:read(1,1)
-  end,
-  [ 1]=function(f)
-    return f:read(1)
-  end,
-  [-2]=function(f)
-    local a,b=f:read(1,1)
-    return b,a
-  end,
-  [-4]=function(f)
-    local a,b,c,d=f:read(1,1,1,1)
-    return d,c,b,a
-  end
-}
-function io.characters(f,n)
-  if f then
-    return nextchar[n or 1],f
-  end
-end
-local nextbyte={
-  [4]=function(f)
-    local a,b,c,d=f:read(1,1,1,1)
-    if d then
-      return byte(a),byte(b),byte(c),byte(d)
-    end
-  end,
-  [3]=function(f)
-    local a,b,c=f:read(1,1,1)
-    if b then
-      return byte(a),byte(b),byte(c)
-    end
-  end,
-  [2]=function(f)
-    local a,b=f:read(1,1)
-    if b then
-      return byte(a),byte(b)
-    end
-  end,
-  [1]=function (f)
-    local a=f:read(1)
-    if a then
-      return byte(a)
-    end
-  end,
-  [-2]=function (f)
-    local a,b=f:read(1,1)
-    if b then
-      return byte(b),byte(a)
-    end
-  end,
-  [-3]=function(f)
-    local a,b,c=f:read(1,1,1)
-    if b then
-      return byte(c),byte(b),byte(a)
-    end
-  end,
-  [-4]=function(f)
-    local a,b,c,d=f:read(1,1,1,1)
-    if d then
-      return byte(d),byte(c),byte(b),byte(a)
-    end
-  end
-}
-function io.bytes(f,n)
-  if f then
-    return nextbyte[n or 1],f
-  else
-    return nil,nil
-  end
-end
-function io.ask(question,default,options)
-  while true do
-    io.write(question)
-    if options then
-      io.write(format(" [%s]",concat(options,"|")))
-    end
-    if default then
-      io.write(format(" [%s]",default))
-    end
-    io.write(format(" "))
-    io.flush()
-    local answer=io.read()
-    answer=gsub(answer,"^%s*(.*)%s*$","%1")
-    if answer=="" and default then
-      return default
-    elseif not options then
-      return answer
-    else
-      for k=1,#options do
-        if options[k]==answer then
-          return answer
-        end
-      end
-      local pattern="^"..answer
-      for k=1,#options do
-        local v=options[k]
-        if find(v,pattern) then
-          return v
-        end
-      end
-    end
-  end
-end
-local function readnumber(f,n,m)
-  if m then
-    f:seek("set",n)
-    n=m
-  end
-  if n==1 then
-    return byte(f:read(1))
-  elseif n==2 then
-    local a,b=byte(f:read(2),1,2)
-    return 256*a+b
-  elseif n==3 then
-    local a,b,c=byte(f:read(3),1,3)
-    return 256*256*a+256*b+c
-  elseif n==4 then
-    local a,b,c,d=byte(f:read(4),1,4)
-    return 256*256*256*a+256*256*b+256*c+d
-  elseif n==8 then
-    local a,b=readnumber(f,4),readnumber(f,4)
-    return 256*a+b
-  elseif n==12 then
-    local a,b,c=readnumber(f,4),readnumber(f,4),readnumber(f,4)
-    return 256*256*a+256*b+c
-  elseif n==-2 then
-    local b,a=byte(f:read(2),1,2)
-    return 256*a+b
-  elseif n==-3 then
-    local c,b,a=byte(f:read(3),1,3)
-    return 256*256*a+256*b+c
-  elseif n==-4 then
-    local d,c,b,a=byte(f:read(4),1,4)
-    return 256*256*256*a+256*256*b+256*c+d
-  elseif n==-8 then
-    local h,g,f,e,d,c,b,a=byte(f:read(8),1,8)
-    return 256*256*256*256*256*256*256*a+256*256*256*256*256*256*b+256*256*256*256*256*c+256*256*256*256*d+256*256*256*e+256*256*f+256*g+h
-  else
-    return 0
-  end
-end
-io.readnumber=readnumber
-function io.readstring(f,n,m)
-  if m then
-    f:seek("set",n)
-    n=m
-  end
-  local str=gsub(f:read(n),"\000","")
-  return str
-end
-if not io.i_limiter then function io.i_limiter() end end 
-if not io.o_limiter then function io.o_limiter() end end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-file']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-file=file or {}
-local file=file
-if not lfs then
-  lfs=optionalrequire("lfs")
-end
-if not lfs then
-  lfs={
-    getcurrentdir=function()
-      return "."
-    end,
-    attributes=function()
-      return nil
-    end,
-    isfile=function(name)
-      local f=io.open(name,'rb')
-      if f then
-        f:close()
-        return true
-      end
-    end,
-    isdir=function(name)
-      print("you need to load lfs")
-      return false
-    end
-  }
-elseif not lfs.isfile then
-  local attributes=lfs.attributes
-  function lfs.isdir(name)
-    return attributes(name,"mode")=="directory"
-  end
-  function lfs.isfile(name)
-    return attributes(name,"mode")=="file"
-  end
-end
-local insert,concat=table.insert,table.concat
-local match,find,gmatch=string.match,string.find,string.gmatch
-local lpegmatch=lpeg.match
-local getcurrentdir,attributes=lfs.currentdir,lfs.attributes
-local checkedsplit=string.checkedsplit
-local P,R,S,C,Cs,Cp,Cc,Ct=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Cp,lpeg.Cc,lpeg.Ct
-local colon=P(":")
-local period=P(".")
-local periods=P("..")
-local fwslash=P("/")
-local bwslash=P("\\")
-local slashes=S("\\/")
-local noperiod=1-period
-local noslashes=1-slashes
-local name=noperiod^1
-local suffix=period/""*(1-period-slashes)^1*-1
-local pattern=C((1-(slashes^1*noslashes^1*-1))^1)*P(1) 
-local function pathpart(name,default)
-  return name and lpegmatch(pattern,name) or default or ""
-end
-local pattern=(noslashes^0*slashes)^1*C(noslashes^1)*-1
-local function basename(name)
-  return name and lpegmatch(pattern,name) or name
-end
-local pattern=(noslashes^0*slashes^1)^0*Cs((1-suffix)^1)*suffix^0
-local function nameonly(name)
-  return name and lpegmatch(pattern,name) or name
-end
-local pattern=(noslashes^0*slashes)^0*(noperiod^1*period)^1*C(noperiod^1)*-1
-local function suffixonly(name)
-  return name and lpegmatch(pattern,name) or ""
-end
-local pattern=(noslashes^0*slashes)^0*noperiod^1*((period*C(noperiod^1))^1)*-1+Cc("")
-local function suffixesonly(name)
-  if name then
-    return lpegmatch(pattern,name)
-  else
-    return ""
-  end
-end
-file.pathpart=pathpart
-file.basename=basename
-file.nameonly=nameonly
-file.suffixonly=suffixonly
-file.suffix=suffixonly
-file.suffixesonly=suffixesonly
-file.suffixes=suffixesonly
-file.dirname=pathpart  
-file.extname=suffixonly
-local drive=C(R("az","AZ"))*colon
-local path=C((noslashes^0*slashes)^0)
-local suffix=period*C(P(1-period)^0*P(-1))
-local base=C((1-suffix)^0)
-local rest=C(P(1)^0)
-drive=drive+Cc("")
-path=path+Cc("")
-base=base+Cc("")
-suffix=suffix+Cc("")
-local pattern_a=drive*path*base*suffix
-local pattern_b=path*base*suffix
-local pattern_c=C(drive*path)*C(base*suffix) 
-local pattern_d=path*rest
-function file.splitname(str,splitdrive)
-  if not str then
-  elseif splitdrive then
-    return lpegmatch(pattern_a,str) 
-  else
-    return lpegmatch(pattern_b,str) 
-  end
-end
-function file.splitbase(str)
-  if str then
-    return lpegmatch(pattern_d,str) 
-  else
-    return "",str 
-  end
-end
-function file.nametotable(str,splitdrive)
-  if str then
-    local path,drive,subpath,name,base,suffix=lpegmatch(pattern_c,str)
-    if splitdrive then
-      return {
-        path=path,
-        drive=drive,
-        subpath=subpath,
-        name=name,
-        base=base,
-        suffix=suffix,
-      }
-    else
-      return {
-        path=path,
-        name=name,
-        base=base,
-        suffix=suffix,
-      }
-    end
-  end
-end
-local pattern=Cs(((period*(1-period-slashes)^1*-1)/""+1)^1)
-function file.removesuffix(name)
-  return name and lpegmatch(pattern,name)
-end
-local suffix=period/""*(1-period-slashes)^1*-1
-local pattern=Cs((noslashes^0*slashes^1)^0*((1-suffix)^1))*Cs(suffix)
-function file.addsuffix(filename,suffix,criterium)
-  if not filename or not suffix or suffix=="" then
-    return filename
-  elseif criterium==true then
-    return filename.."."..suffix
-  elseif not criterium then
-    local n,s=lpegmatch(pattern,filename)
-    if not s or s=="" then
-      return filename.."."..suffix
-    else
-      return filename
-    end
-  else
-    local n,s=lpegmatch(pattern,filename)
-    if s and s~="" then
-      local t=type(criterium)
-      if t=="table" then
-        for i=1,#criterium do
-          if s==criterium[i] then
-            return filename
-          end
-        end
-      elseif t=="string" then
-        if s==criterium then
-          return filename
-        end
-      end
-    end
-    return (n or filename).."."..suffix
-  end
-end
-local suffix=period*(1-period-slashes)^1*-1
-local pattern=Cs((1-suffix)^0)
-function file.replacesuffix(name,suffix)
-  if name and suffix and suffix~="" then
-    return lpegmatch(pattern,name).."."..suffix
-  else
-    return name
-  end
-end
-local reslasher=lpeg.replacer(P("\\"),"/")
-function file.reslash(str)
-  return str and lpegmatch(reslasher,str)
-end
-function file.is_writable(name)
-  if not name then
-  elseif lfs.isdir(name) then
-    name=name.."/m_t_x_t_e_s_t.tmp"
-    local f=io.open(name,"wb")
-    if f then
-      f:close()
-      os.remove(name)
-      return true
-    end
-  elseif lfs.isfile(name) then
-    local f=io.open(name,"ab")
-    if f then
-      f:close()
-      return true
-    end
-  else
-    local f=io.open(name,"ab")
-    if f then
-      f:close()
-      os.remove(name)
-      return true
-    end
-  end
-  return false
-end
-local readable=P("r")*Cc(true)
-function file.is_readable(name)
-  if name then
-    local a=attributes(name)
-    return a and lpegmatch(readable,a.permissions) or false
-  else
-    return false
-  end
-end
-file.isreadable=file.is_readable 
-file.iswritable=file.is_writable 
-function file.size(name)
-  if name then
-    local a=attributes(name)
-    return a and a.size or 0
-  else
-    return 0
-  end
-end
-function file.splitpath(str,separator) 
-  return str and checkedsplit(lpegmatch(reslasher,str),separator or io.pathseparator)
-end
-function file.joinpath(tab,separator) 
-  return tab and concat(tab,separator or io.pathseparator) 
-end
-local someslash=S("\\/")
-local stripper=Cs(P(fwslash)^0/""*reslasher)
-local isnetwork=someslash*someslash*(1-someslash)+(1-fwslash-colon)^1*colon
-local isroot=fwslash^1*-1
-local hasroot=fwslash^1
-local reslasher=lpeg.replacer(S("\\/"),"/")
-local deslasher=lpeg.replacer(S("\\/")^1,"/")
-function file.join(one,two,three,...)
-  if not two then
-    return one=="" and one or lpegmatch(stripper,one)
-  end
-  if one=="" then
-    return lpegmatch(stripper,three and concat({ two,three,... },"/") or two)
-  end
-  if lpegmatch(isnetwork,one) then
-    local one=lpegmatch(reslasher,one)
-    local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two)
-    if lpegmatch(hasroot,two) then
-      return one..two
-    else
-      return one.."/"..two
-    end
-  elseif lpegmatch(isroot,one) then
-    local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two)
-    if lpegmatch(hasroot,two) then
-      return two
-    else
-      return "/"..two
-    end
-  else
-    return lpegmatch(deslasher,concat({ one,two,three,... },"/"))
-  end
-end
-local drivespec=R("az","AZ")^1*colon
-local anchors=fwslash+drivespec
-local untouched=periods+(1-period)^1*P(-1)
-local mswindrive=Cs(drivespec*(bwslash/"/"+fwslash)^0)
-local mswinuncpath=(bwslash+fwslash)*(bwslash+fwslash)*Cc("//")
-local splitstarter=(mswindrive+mswinuncpath+Cc(false))*Ct(lpeg.splitat(S("/\\")^1))
-local absolute=fwslash
-function file.collapsepath(str,anchor) 
-  if not str then
-    return
-  end
-  if anchor==true and not lpegmatch(anchors,str) then
-    str=getcurrentdir().."/"..str
-  end
-  if str=="" or str=="." then
-    return "."
-  elseif lpegmatch(untouched,str) then
-    return lpegmatch(reslasher,str)
-  end
-  local starter,oldelements=lpegmatch(splitstarter,str)
-  local newelements={}
-  local i=#oldelements
-  while i>0 do
-    local element=oldelements[i]
-    if element=='.' then
-    elseif element=='..' then
-      local n=i-1
-      while n>0 do
-        local element=oldelements[n]
-        if element~='..' and element~='.' then
-          oldelements[n]='.'
-          break
-        else
-          n=n-1
-        end
-       end
-      if n<1 then
-        insert(newelements,1,'..')
-      end
-    elseif element~="" then
-      insert(newelements,1,element)
-    end
-    i=i-1
-  end
-  if #newelements==0 then
-    return starter or "."
-  elseif starter then
-    return starter..concat(newelements,'/')
-  elseif lpegmatch(absolute,str) then
-    return "/"..concat(newelements,'/')
-  else
-    newelements=concat(newelements,'/')
-    if anchor=="." and find(str,"^%./") then
-      return "./"..newelements
-    else
-      return newelements
-    end
-  end
-end
-local tricky=S("/\\")*P(-1)
-local attributes=lfs.attributes
-function lfs.isdir(name)
-  if lpegmatch(tricky,name) then
-    return attributes(name,"mode")=="directory"
-  else
-    return attributes(name.."/.","mode")=="directory"
-  end
-end
-function lfs.isfile(name)
-  return attributes(name,"mode")=="file"
-end
-local validchars=R("az","09","AZ","--","..")
-local pattern_a=lpeg.replacer(1-validchars)
-local pattern_a=Cs((validchars+P(1)/"-")^1)
-local whatever=P("-")^0/""
-local pattern_b=Cs(whatever*(1-whatever*-1)^1)
-function file.robustname(str,strict)
-  if str then
-    str=lpegmatch(pattern_a,str) or str
-    if strict then
-      return lpegmatch(pattern_b,str) or str 
-    else
-      return str
-    end
-  end
-end
-file.readdata=io.loaddata
-file.savedata=io.savedata
-function file.copy(oldname,newname)
-  if oldname and newname then
-    local data=io.loaddata(oldname)
-    if data and data~="" then
-      file.savedata(newname,data)
-    end
-  end
-end
-local letter=R("az","AZ")+S("_-+")
-local separator=P("://")
-local qualified=period^0*fwslash+letter*colon+letter^1*separator+letter^1*fwslash
-local rootbased=fwslash+letter*colon
-lpeg.patterns.qualified=qualified
-lpeg.patterns.rootbased=rootbased
-function file.is_qualified_path(filename)
-  return filename and lpegmatch(qualified,filename)~=nil
-end
-function file.is_rootbased_path(filename)
-  return filename and lpegmatch(rootbased,filename)~=nil
-end
-function file.strip(name,dir)
-  if name then
-    local b,a=match(name,"^(.-)"..dir.."(.*)$")
-    return a~="" and a or name
-  end
-end
-function lfs.mkdirs(path)
-  local full=""
-  for sub in gmatch(path,"(/*[^\\/]+)") do 
-    full=full..sub
-    lfs.mkdir(full)
-  end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-boolean']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local type,tonumber=type,tonumber
-boolean=boolean or {}
-local boolean=boolean
-function boolean.tonumber(b)
-  if b then return 1 else return 0 end 
-end
-function toboolean(str,tolerant) 
-  if str==nil then
-    return false
-  elseif str==false then
-    return false
-  elseif str==true then
-    return true
-  elseif str=="true" then
-    return true
-  elseif str=="false" then
-    return false
-  elseif not tolerant then
-    return false
-  elseif str==0 then
-    return false
-  elseif (tonumber(str) or 0)>0 then
-    return true
-  else
-    return str=="yes" or str=="on" or str=="t"
-  end
-end
-string.toboolean=toboolean
-function string.booleanstring(str)
-  if str=="0" then
-    return false
-  elseif str=="1" then
-    return true
-  elseif str=="" then
-    return false
-  elseif str=="false" then
-    return false
-  elseif str=="true" then
-    return true
-  elseif (tonumber(str) or 0)>0 then
-    return true
-  else
-    return str=="yes" or str=="on" or str=="t"
-  end
-end
-function string.is_boolean(str,default)
-  if type(str)=="string" then
-    if str=="true" or str=="yes" or str=="on" or str=="t" or str=="1" then
-      return true
-    elseif str=="false" or str=="no" or str=="off" or str=="f" or str=="0" then
-      return false
-    end
-  end
-  return default
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-math']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local floor,sin,cos,tan=math.floor,math.sin,math.cos,math.tan
-if not math.round then
-  function math.round(x) return floor(x+0.5) end
-end
-if not math.div then
-  function math.div(n,m) return floor(n/m) end
-end
-if not math.mod then
-  function math.mod(n,m) return n%m end
-end
-local pipi=2*math.pi/360
-if not math.sind then
-  function math.sind(d) return sin(d*pipi) end
-  function math.cosd(d) return cos(d*pipi) end
-  function math.tand(d) return tan(d*pipi) end
-end
-if not math.odd then
-  function math.odd (n) return n%2~=0 end
-  function math.even(n) return n%2==0 end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['util-str']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-utilities=utilities or {}
-utilities.strings=utilities.strings or {}
-local strings=utilities.strings
-local format,gsub,rep,sub=string.format,string.gsub,string.rep,string.sub
-local load,dump=load,string.dump
-local tonumber,type,tostring=tonumber,type,tostring
-local unpack,concat=table.unpack,table.concat
-local P,V,C,S,R,Ct,Cs,Cp,Carg,Cc=lpeg.P,lpeg.V,lpeg.C,lpeg.S,lpeg.R,lpeg.Ct,lpeg.Cs,lpeg.Cp,lpeg.Carg,lpeg.Cc
-local patterns,lpegmatch=lpeg.patterns,lpeg.match
-local utfchar,utfbyte=utf.char,utf.byte
-local loadstripped=nil
-if _LUAVERSION<5.2 then
-  loadstripped=function(str,shortcuts)
-    return load(str)
-  end
-else
-  loadstripped=function(str,shortcuts)
-    if shortcuts then
-      return load(dump(load(str),true),nil,nil,shortcuts)
-    else
-      return load(dump(load(str),true))
-    end
-  end
-end
-if not number then number={} end 
-local stripper=patterns.stripzeros
-local function points(n)
-  n=tonumber(n)
-  return (not n or n==0) and "0pt" or lpegmatch(stripper,format("%.5fpt",n/65536))
-end
-local function basepoints(n)
-  n=tonumber(n)
-  return (not n or n==0) and "0bp" or lpegmatch(stripper,format("%.5fbp",n*(7200/7227)/65536))
-end
-number.points=points
-number.basepoints=basepoints
-local rubish=patterns.spaceortab^0*patterns.newline
-local anyrubish=patterns.spaceortab+patterns.newline
-local anything=patterns.anything
-local stripped=(patterns.spaceortab^1/"")*patterns.newline
-local leading=rubish^0/""
-local trailing=(anyrubish^1*patterns.endofstring)/""
-local redundant=rubish^3/"\n"
-local pattern=Cs(leading*(trailing+redundant+stripped+anything)^0)
-function strings.collapsecrlf(str)
-  return lpegmatch(pattern,str)
-end
-local repeaters={} 
-function strings.newrepeater(str,offset)
-  offset=offset or 0
-  local s=repeaters[str]
-  if not s then
-    s={}
-    repeaters[str]=s
-  end
-  local t=s[offset]
-  if t then
-    return t
-  end
-  t={}
-  setmetatable(t,{ __index=function(t,k)
-    if not k then
-      return ""
-    end
-    local n=k+offset
-    local s=n>0 and rep(str,n) or ""
-    t[k]=s
-    return s
-  end })
-  s[offset]=t
-  return t
-end
-local extra,tab,start=0,0,4,0
-local nspaces=strings.newrepeater(" ")
-string.nspaces=nspaces
-local pattern=Carg(1)/function(t)
-    extra,tab,start=0,t or 7,1
-  end*Cs((
-   Cp()*patterns.tab/function(position)
-     local current=(position-start+1)+extra
-     local spaces=tab-(current-1)%tab
-     if spaces>0 then
-       extra=extra+spaces-1
-       return nspaces[spaces] 
-     else
-       return ""
-     end
-   end+patterns.newline*Cp()/function(position)
-     extra,start=0,position
-   end+patterns.anything
- )^1)
-function strings.tabtospace(str,tab)
-  return lpegmatch(pattern,str,1,tab or 7)
-end
-local newline=patterns.newline
-local endofstring=patterns.endofstring
-local whitespace=patterns.whitespace
-local spacer=patterns.spacer
-local space=spacer^0
-local nospace=space/""
-local endofline=nospace*newline
-local stripend=(whitespace^1*endofstring)/""
-local normalline=(nospace*((1-space*(newline+endofstring))^1)*nospace)
-local stripempty=endofline^1/""
-local normalempty=endofline^1
-local singleempty=endofline*(endofline^0/"")
-local doubleempty=endofline*endofline^-1*(endofline^0/"")
-local stripstart=stripempty^0
-local p_prune_normal=Cs (stripstart*(stripend+normalline+normalempty )^0 )
-local p_prune_collapse=Cs (stripstart*(stripend+normalline+doubleempty )^0 )
-local p_prune_noempty=Cs (stripstart*(stripend+normalline+singleempty )^0 )
-local p_retain_normal=Cs ((normalline+normalempty )^0 )
-local p_retain_collapse=Cs ((normalline+doubleempty )^0 )
-local p_retain_noempty=Cs ((normalline+singleempty )^0 )
-local striplinepatterns={
-  ["prune"]=p_prune_normal,
-  ["prune and collapse"]=p_prune_collapse,
-  ["prune and no empty"]=p_prune_noempty,
-  ["retain"]=p_retain_normal,
-  ["retain and collapse"]=p_retain_collapse,
-  ["retain and no empty"]=p_retain_noempty,
-  ["collapse"]=patterns.collapser,
-}
-strings.striplinepatterns=striplinepatterns
-function strings.striplines(str,how)
-  return str and lpegmatch(how and striplinepatterns[how] or p_prune_collapse,str) or str
-end
-strings.striplong=strings.striplines
-function strings.nice(str)
-  str=gsub(str,"[:%-+_]+"," ") 
-  return str
-end
-local n=0
-local sequenced=table.sequenced
-function string.autodouble(s,sep)
-  if s==nil then
-    return '""'
-  end
-  local t=type(s)
-  if t=="number" then
-    return tostring(s) 
-  end
-  if t=="table" then
-    return ('"'..sequenced(s,sep or ",")..'"')
-  end
-  return ('"'..tostring(s)..'"')
-end
-function string.autosingle(s,sep)
-  if s==nil then
-    return "''"
-  end
-  local t=type(s)
-  if t=="number" then
-    return tostring(s) 
-  end
-  if t=="table" then
-    return ("'"..sequenced(s,sep or ",").."'")
-  end
-  return ("'"..tostring(s).."'")
-end
-local tracedchars={}
-string.tracedchars=tracedchars
-strings.tracers=tracedchars
-function string.tracedchar(b)
-  if type(b)=="number" then
-    return tracedchars[b] or (utfchar(b).." (U+"..format('%05X',b)..")")
-  else
-    local c=utfbyte(b)
-    return tracedchars[c] or (b.." (U+"..format('%05X',c)..")")
-  end
-end
-function number.signed(i)
-  if i>0 then
-    return "+",i
-  else
-    return "-",-i
-  end
-end
-local zero=P("0")^1/""
-local plus=P("+")/""
-local minus=P("-")
-local separator=S(".")
-local digit=R("09")
-local trailing=zero^1*#S("eE")
-local exponent=(S("eE")*(plus+Cs((minus*zero^0*P(-1))/"")+minus)*zero^0*(P(-1)*Cc("0")+P(1)^1))
-local pattern_a=Cs(minus^0*digit^1*(separator/""*trailing+separator*(trailing+digit)^0)*exponent)
-local pattern_b=Cs((exponent+P(1))^0)
-function number.sparseexponent(f,n)
-  if not n then
-    n=f
-    f="%e"
-  end
-  local tn=type(n)
-  if tn=="string" then 
-    local m=tonumber(n)
-    if m then
-      return lpegmatch((f=="%e" or f=="%E") and pattern_a or pattern_b,format(f,m))
-    end
-  elseif tn=="number" then
-    return lpegmatch((f=="%e" or f=="%E") and pattern_a or pattern_b,format(f,n))
-  end
-  return tostring(n)
-end
-local template=[[
-%s
-%s
-return function(%s) return %s end
-]]
-local preamble,environment="",{}
-if _LUAVERSION<5.2 then
-  preamble=[[
-local lpeg=lpeg
-local type=type
-local tostring=tostring
-local tonumber=tonumber
-local format=string.format
-local concat=table.concat
-local signed=number.signed
-local points=number.points
-local basepoints= number.basepoints
-local utfchar=utf.char
-local utfbyte=utf.byte
-local lpegmatch=lpeg.match
-local nspaces=string.nspaces
-local tracedchar=string.tracedchar
-local autosingle=string.autosingle
-local autodouble=string.autodouble
-local sequenced=table.sequenced
-local formattednumber=number.formatted
-local sparseexponent=number.sparseexponent
-    ]]
-else
-  environment={
-    global=global or _G,
-    lpeg=lpeg,
-    type=type,
-    tostring=tostring,
-    tonumber=tonumber,
-    format=string.format,
-    concat=table.concat,
-    signed=number.signed,
-    points=number.points,
-    basepoints=number.basepoints,
-    utfchar=utf.char,
-    utfbyte=utf.byte,
-    lpegmatch=lpeg.match,
-    nspaces=string.nspaces,
-    tracedchar=string.tracedchar,
-    autosingle=string.autosingle,
-    autodouble=string.autodouble,
-    sequenced=table.sequenced,
-    formattednumber=number.formatted,
-    sparseexponent=number.sparseexponent,
-  }
-end
-local arguments={ "a1" } 
-setmetatable(arguments,{ __index=function(t,k)
-    local v=t[k-1]..",a"..k
-    t[k]=v
-    return v
-  end
-})
-local prefix_any=C((S("+- .")+R("09"))^0)
-local prefix_tab=P("{")*C((1-P("}"))^0)*P("}")+C((1-R("az","AZ","09","%%"))^0)
-local format_s=function(f)
-  n=n+1
-  if f and f~="" then
-    return format("format('%%%ss',a%s)",f,n)
-  else 
-    return format("(a%s or '')",n) 
-  end
-end
-local format_S=function(f) 
-  n=n+1
-  if f and f~="" then
-    return format("format('%%%ss',tostring(a%s))",f,n)
-  else
-    return format("tostring(a%s)",n)
-  end
-end
-local format_q=function()
-  n=n+1
-  return format("(a%s and format('%%q',a%s) or '')",n,n) 
-end
-local format_Q=function() 
-  n=n+1
-  return format("format('%%q',tostring(a%s))",n)
-end
-local format_i=function(f)
-  n=n+1
-  if f and f~="" then
-    return format("format('%%%si',a%s)",f,n)
-  else
-    return format("format('%%i',a%s)",n) 
-  end
-end
-local format_d=format_i
-local format_I=function(f)
-  n=n+1
-  return format("format('%%s%%%si',signed(a%s))",f,n)
-end
-local format_f=function(f)
-  n=n+1
-  return format("format('%%%sf',a%s)",f,n)
-end
-local format_F=function() 
-  n=n+1
-  if not f or f=="" then
-    return format("(((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or format((a%s %% 1 == 0) and '%%i' or '%%.9f',a%s))",n,n,n,n)
-  else
-    return format("format((a%s %% 1 == 0) and '%%i' or '%%%sf',a%s)",n,f,n)
-  end
-end
-local format_g=function(f)
-  n=n+1
-  return format("format('%%%sg',a%s)",f,n)
-end
-local format_G=function(f)
-  n=n+1
-  return format("format('%%%sG',a%s)",f,n)
-end
-local format_e=function(f)
-  n=n+1
-  return format("format('%%%se',a%s)",f,n)
-end
-local format_E=function(f)
-  n=n+1
-  return format("format('%%%sE',a%s)",f,n)
-end
-local format_j=function(f)
-  n=n+1
-  return format("sparseexponent('%%%se',a%s)",f,n)
-end
-local format_J=function(f)
-  n=n+1
-  return format("sparseexponent('%%%sE',a%s)",f,n)
-end
-local format_x=function(f)
-  n=n+1
-  return format("format('%%%sx',a%s)",f,n)
-end
-local format_X=function(f)
-  n=n+1
-  return format("format('%%%sX',a%s)",f,n)
-end
-local format_o=function(f)
-  n=n+1
-  return format("format('%%%so',a%s)",f,n)
-end
-local format_c=function()
-  n=n+1
-  return format("utfchar(a%s)",n)
-end
-local format_C=function()
-  n=n+1
-  return format("tracedchar(a%s)",n)
-end
-local format_r=function(f)
-  n=n+1
-  return format("format('%%%s.0f',a%s)",f,n)
-end
-local format_h=function(f)
-  n=n+1
-  if f=="-" then
-    f=sub(f,2)
-    return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
-  else
-    return format("format('0x%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
-  end
-end
-local format_H=function(f)
-  n=n+1
-  if f=="-" then
-    f=sub(f,2)
-    return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
-  else
-    return format("format('0x%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
-  end
-end
-local format_u=function(f)
-  n=n+1
-  if f=="-" then
-    f=sub(f,2)
-    return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
-  else
-    return format("format('u+%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
-  end
-end
-local format_U=function(f)
-  n=n+1
-  if f=="-" then
-    f=sub(f,2)
-    return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
-  else
-    return format("format('U+%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
-  end
-end
-local format_p=function()
-  n=n+1
-  return format("points(a%s)",n)
-end
-local format_b=function()
-  n=n+1
-  return format("basepoints(a%s)",n)
-end
-local format_t=function(f)
-  n=n+1
-  if f and f~="" then
-    return format("concat(a%s,%q)",n,f)
-  else
-    return format("concat(a%s)",n)
-  end
-end
-local format_T=function(f)
-  n=n+1
-  if f and f~="" then
-    return format("sequenced(a%s,%q)",n,f)
-  else
-    return format("sequenced(a%s)",n)
-  end
-end
-local format_l=function()
-  n=n+1
-  return format("(a%s and 'true' or 'false')",n)
-end
-local format_L=function()
-  n=n+1
-  return format("(a%s and 'TRUE' or 'FALSE')",n)
-end
-local format_N=function() 
-  n=n+1
-  return format("tostring(tonumber(a%s) or a%s)",n,n)
-end
-local format_a=function(f)
-  n=n+1
-  if f and f~="" then
-    return format("autosingle(a%s,%q)",n,f)
-  else
-    return format("autosingle(a%s)",n)
-  end
-end
-local format_A=function(f)
-  n=n+1
-  if f and f~="" then
-    return format("autodouble(a%s,%q)",n,f)
-  else
-    return format("autodouble(a%s)",n)
-  end
-end
-local format_w=function(f) 
-  n=n+1
-  f=tonumber(f)
-  if f then 
-    return format("nspaces[%s+a%s]",f,n) 
-  else
-    return format("nspaces[a%s]",n) 
-  end
-end
-local format_W=function(f) 
-  return format("nspaces[%s]",tonumber(f) or 0)
-end
-local digit=patterns.digit
-local period=patterns.period
-local three=digit*digit*digit
-local splitter=Cs (
-  (((1-(three^1*period))^1+C(three))*(Carg(1)*three)^1+C((1-period)^1))*(P(1)/""*Carg(2))*C(2)
-)
-patterns.formattednumber=splitter
-function number.formatted(n,sep1,sep2)
-  local s=type(s)=="string" and n or format("%0.2f",n)
-  if sep1==true then
-    return lpegmatch(splitter,s,1,".",",")
-  elseif sep1=="." then
-    return lpegmatch(splitter,s,1,sep1,sep2 or ",")
-  elseif sep1=="," then
-    return lpegmatch(splitter,s,1,sep1,sep2 or ".")
-  else
-    return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".")
-  end
-end
-local format_m=function(f)
-  n=n+1
-  if not f or f=="" then
-    f=","
-  end
-  return format([[formattednumber(a%s,%q,".")]],n,f)
-end
-local format_M=function(f)
-  n=n+1
-  if not f or f=="" then
-    f="."
-  end
-  return format([[formattednumber(a%s,%q,",")]],n,f)
-end
-local format_z=function(f)
-  n=n+(tonumber(f) or 1)
-  return "''" 
-end
-local format_rest=function(s)
-  return format("%q",s) 
-end
-local format_extension=function(extensions,f,name)
-  local extension=extensions[name] or "tostring(%s)"
-  local f=tonumber(f) or 1
-  if f==0 then
-    return extension
-  elseif f==1 then
-    n=n+1
-    local a="a"..n
-    return format(extension,a,a) 
-  elseif f<0 then
-    local a="a"..(n+f+1)
-    return format(extension,a,a)
-  else
-    local t={}
-    for i=1,f do
-      n=n+1
-      t[#t+1]="a"..n
-    end
-    return format(extension,unpack(t))
-  end
-end
-local builder=Cs { "start",
-  start=(
-    (
-      P("%")/""*(
-        V("!") 
-+V("s")+V("q")+V("i")+V("d")+V("f")+V("F")+V("g")+V("G")+V("e")+V("E")+V("x")+V("X")+V("o")
-+V("c")+V("C")+V("S") 
-+V("Q") 
-+V("N")
-+V("r")+V("h")+V("H")+V("u")+V("U")+V("p")+V("b")+V("t")+V("T")+V("l")+V("L")+V("I")+V("w") 
-+V("W") 
-+V("a") 
-+V("A") 
-+V("j")+V("J") 
-+V("m")+V("M") 
-+V("z")
-+V("*") 
-      )+V("*")
-    )*(P(-1)+Carg(1))
-  )^0,
-  ["s"]=(prefix_any*P("s"))/format_s,
-  ["q"]=(prefix_any*P("q"))/format_q,
-  ["i"]=(prefix_any*P("i"))/format_i,
-  ["d"]=(prefix_any*P("d"))/format_d,
-  ["f"]=(prefix_any*P("f"))/format_f,
-  ["F"]=(prefix_any*P("F"))/format_F,
-  ["g"]=(prefix_any*P("g"))/format_g,
-  ["G"]=(prefix_any*P("G"))/format_G,
-  ["e"]=(prefix_any*P("e"))/format_e,
-  ["E"]=(prefix_any*P("E"))/format_E,
-  ["x"]=(prefix_any*P("x"))/format_x,
-  ["X"]=(prefix_any*P("X"))/format_X,
-  ["o"]=(prefix_any*P("o"))/format_o,
-  ["S"]=(prefix_any*P("S"))/format_S,
-  ["Q"]=(prefix_any*P("Q"))/format_S,
-  ["N"]=(prefix_any*P("N"))/format_N,
-  ["c"]=(prefix_any*P("c"))/format_c,
-  ["C"]=(prefix_any*P("C"))/format_C,
-  ["r"]=(prefix_any*P("r"))/format_r,
-  ["h"]=(prefix_any*P("h"))/format_h,
-  ["H"]=(prefix_any*P("H"))/format_H,
-  ["u"]=(prefix_any*P("u"))/format_u,
-  ["U"]=(prefix_any*P("U"))/format_U,
-  ["p"]=(prefix_any*P("p"))/format_p,
-  ["b"]=(prefix_any*P("b"))/format_b,
-  ["t"]=(prefix_tab*P("t"))/format_t,
-  ["T"]=(prefix_tab*P("T"))/format_T,
-  ["l"]=(prefix_any*P("l"))/format_l,
-  ["L"]=(prefix_any*P("L"))/format_L,
-  ["I"]=(prefix_any*P("I"))/format_I,
-  ["w"]=(prefix_any*P("w"))/format_w,
-  ["W"]=(prefix_any*P("W"))/format_W,
-  ["j"]=(prefix_any*P("j"))/format_j,
-  ["J"]=(prefix_any*P("J"))/format_J,
-  ["m"]=(prefix_tab*P("m"))/format_m,
-  ["M"]=(prefix_tab*P("M"))/format_M,
-  ["z"]=(prefix_any*P("z"))/format_z,
-  ["a"]=(prefix_any*P("a"))/format_a,
-  ["A"]=(prefix_any*P("A"))/format_A,
-  ["*"]=Cs(((1-P("%"))^1+P("%%")/"%%")^1)/format_rest,
-  ["!"]=Carg(2)*prefix_any*P("!")*C((1-P("!"))^1)*P("!")/format_extension,
-}
-local direct=Cs (
-  P("%")*(S("+- .")+R("09"))^0*S("sqidfgGeExXo")*P(-1)/[[local format = string.format return function(str) return format("%0",str) end]]
-)
-local function make(t,str)
-  local f
-  local p
-  local p=lpegmatch(direct,str)
-  if p then
-    f=loadstripped(p)()
-  else
-    n=0
-    p=lpegmatch(builder,str,1,t._connector_,t._extensions_) 
-    if n>0 then
-      p=format(template,preamble,t._preamble_,arguments[n],p)
-      f=loadstripped(p,t._environment_)() 
-    else
-      f=function() return str end
-    end
-  end
-  t[str]=f
-  return f
-end
-local function use(t,fmt,...)
-  return t[fmt](...)
-end
-strings.formatters={}
-if _LUAVERSION<5.2 then
-  function strings.formatters.new(noconcat)
-    local t={ _type_="formatter",_connector_=noconcat and "," or "..",_extensions_={},_preamble_=preamble,_environment_={} }
-    setmetatable(t,{ __index=make,__call=use })
-    return t
-  end
-else
-  function strings.formatters.new(noconcat)
-    local e={} 
-    for k,v in next,environment do
-      e[k]=v
-    end
-    local t={ _type_="formatter",_connector_=noconcat and "," or "..",_extensions_={},_preamble_="",_environment_=e }
-    setmetatable(t,{ __index=make,__call=use })
-    return t
-  end
-end
-local formatters=strings.formatters.new() 
-string.formatters=formatters 
-string.formatter=function(str,...) return formatters[str](...) end 
-local function add(t,name,template,preamble)
-  if type(t)=="table" and t._type_=="formatter" then
-    t._extensions_[name]=template or "%s"
-    if type(preamble)=="string" then
-      t._preamble_=preamble.."\n"..t._preamble_ 
-    elseif type(preamble)=="table" then
-      for k,v in next,preamble do
-        t._environment_[k]=v
-      end
-    end
-  end
-end
-strings.formatters.add=add
-patterns.xmlescape=Cs((P("<")/"&lt;"+P(">")/"&gt;"+P("&")/"&amp;"+P('"')/"&quot;"+P(1))^0)
-patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+P(1))^0)
-patterns.luaescape=Cs(((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0) 
-patterns.luaquoted=Cs(Cc('"')*((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0*Cc('"'))
-if _LUAVERSION<5.2 then
-  add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],"local xmlescape = lpeg.patterns.xmlescape")
-  add(formatters,"tex",[[lpegmatch(texescape,%s)]],"local texescape = lpeg.patterns.texescape")
-  add(formatters,"lua",[[lpegmatch(luaescape,%s)]],"local luaescape = lpeg.patterns.luaescape")
-else
-  add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape=lpeg.patterns.xmlescape })
-  add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=lpeg.patterns.texescape })
-  add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=lpeg.patterns.luaescape })
-end
-local dquote=patterns.dquote 
-local equote=patterns.escaped+dquote/'\\"'+1
-local space=patterns.space
-local cquote=Cc('"')
-local pattern=Cs(dquote*(equote-P(-2))^0*dquote)          
-+Cs(cquote*(equote-space)^0*space*equote^0*cquote) 
-function string.optionalquoted(str)
-  return lpegmatch(pattern,str) or str
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['luat-basics-gen']={
-  version=1.100,
-  comment="companion to luatex-*.tex",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-if context then
-  texio.write_nl("fatal error: this module is not for context")
-  os.exit()
-end
-local dummyfunction=function()
-end
-local dummyreporter=function(c)
-  return function(...)
-    (texio.reporter or texio.write_nl)(c.." : "..string.formatters(...))
-  end
-end
-statistics={
-  register=dummyfunction,
-  starttiming=dummyfunction,
-  stoptiming=dummyfunction,
-  elapsedtime=nil,
-}
-directives={
-  register=dummyfunction,
-  enable=dummyfunction,
-  disable=dummyfunction,
-}
-trackers={
-  register=dummyfunction,
-  enable=dummyfunction,
-  disable=dummyfunction,
-}
-experiments={
-  register=dummyfunction,
-  enable=dummyfunction,
-  disable=dummyfunction,
-}
-storage={ 
-  register=dummyfunction,
-  shared={},
-}
-logs={
-  new=dummyreporter,
-  reporter=dummyreporter,
-  messenger=dummyreporter,
-  report=dummyfunction,
-}
-callbacks={
-  register=function(n,f) return callback.register(n,f) end,
-}
-utilities={
-  storage={
-    allocate=function(t) return t or {} end,
-    mark=function(t) return t or {} end,
-  },
-}
-characters=characters or {
-  data={}
-}
-texconfig.kpse_init=true
-resolvers=resolvers or {} 
-local remapper={
-  otf="opentype fonts",
-  ttf="truetype fonts",
-  ttc="truetype fonts",
-  dfont="truetype fonts",
-  cid="cid maps",
-  cidmap="cid maps",
-  fea="font feature files",
-  pfa="type1 fonts",
-  pfb="type1 fonts",
-  afm="afm",
-}
-function resolvers.findfile(name,fileformat)
-  name=string.gsub(name,"\\","/")
-  if not fileformat or fileformat=="" then
-    fileformat=file.suffix(name)
-    if fileformat=="" then
-      fileformat="tex"
-    end
-  end
-  fileformat=string.lower(fileformat)
-  fileformat=remapper[fileformat] or fileformat
-  local found=kpse.find_file(name,fileformat)
-  if not found or found=="" then
-    found=kpse.find_file(name,"other text files")
-  end
-  return found
-end
-resolvers.findbinfile=resolvers.findfile
-function resolvers.loadbinfile(filename,filetype)
-  local data=io.loaddata(filename)
-  return true,data,#data
-end
-function resolvers.resolve(s)
-  return s
-end
-function resolvers.unresolve(s)
-  return s
-end
-caches={}
-local writable=nil
-local readables={}
-local usingjit=jit
-if not caches.namespace or caches.namespace=="" or caches.namespace=="context" then
-  caches.namespace='generic'
-end
-do
-  local cachepaths=kpse.expand_var('$TEXMFCACHE') or ""
-  if cachepaths=="" or cachepaths=="$TEXMFCACHE" then
-    cachepaths=kpse.expand_var('$TEXMFVAR') or ""
-  end
-  if cachepaths=="" or cachepaths=="$TEXMFVAR" then
-    cachepaths=kpse.expand_var('$VARTEXMF') or ""
-  end
-  if cachepaths=="" then
-    local fallbacks={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" }
-    for i=1,#fallbacks do
-      cachepaths=os.getenv(fallbacks[i]) or ""
-      if cachepath~="" and lfs.isdir(cachepath) then
-        break
-      end
-    end
-  end
-  if cachepaths=="" then
-    cachepaths="."
-  end
-  cachepaths=string.split(cachepaths,os.type=="windows" and ";" or ":")
-  for i=1,#cachepaths do
-    local cachepath=cachepaths[i]
-    if not lfs.isdir(cachepath) then
-      lfs.mkdirs(cachepath) 
-      if lfs.isdir(cachepath) then
-        texio.write(string.format("(created cache path: %s)",cachepath))
-      end
-    end
-    if file.is_writable(cachepath) then
-      writable=file.join(cachepath,"luatex-cache")
-      lfs.mkdir(writable)
-      writable=file.join(writable,caches.namespace)
-      lfs.mkdir(writable)
-      break
-    end
-  end
-  for i=1,#cachepaths do
-    if file.is_readable(cachepaths[i]) then
-      readables[#readables+1]=file.join(cachepaths[i],"luatex-cache",caches.namespace)
-    end
-  end
-  if not writable then
-    texio.write_nl("quiting: fix your writable cache path")
-    os.exit()
-  elseif #readables==0 then
-    texio.write_nl("quiting: fix your readable cache path")
-    os.exit()
-  elseif #readables==1 and readables[1]==writable then
-    texio.write(string.format("(using cache: %s)",writable))
-  else
-    texio.write(string.format("(using write cache: %s)",writable))
-    texio.write(string.format("(using read cache: %s)",table.concat(readables," ")))
-  end
-end
-function caches.getwritablepath(category,subcategory)
-  local path=file.join(writable,category)
-  lfs.mkdir(path)
-  path=file.join(path,subcategory)
-  lfs.mkdir(path)
-  return path
-end
-function caches.getreadablepaths(category,subcategory)
-  local t={}
-  for i=1,#readables do
-    t[i]=file.join(readables[i],category,subcategory)
-  end
-  return t
-end
-local function makefullname(path,name)
-  if path and path~="" then
-    return file.addsuffix(file.join(path,name),"lua"),file.addsuffix(file.join(path,name),usingjit and "lub" or "luc")
-  end
-end
-function caches.is_writable(path,name)
-  local fullname=makefullname(path,name)
-  return fullname and file.is_writable(fullname)
-end
-function caches.loaddata(paths,name)
-  for i=1,#paths do
-    local data=false
-    local luaname,lucname=makefullname(paths[i],name)
-    if lucname and not lfs.isfile(lucname) and type(caches.compile)=="function" then
-      texio.write(string.format("(compiling luc: %s)",lucname))
-      data=loadfile(luaname)
-      if data then
-        data=data()
-      end
-      if data then
-        caches.compile(data,luaname,lucname)
-        return data
-      end
-    end
-    if lucname and lfs.isfile(lucname) then 
-      texio.write(string.format("(load luc: %s)",lucname))
-      data=loadfile(lucname)
-      if data then
-        data=data()
-      end
-      if data then
-        return data
-      else
-        texio.write(string.format("(loading failed: %s)",lucname))
-      end
-    end
-    if luaname and lfs.isfile(luaname) then
-      texio.write(string.format("(load lua: %s)",luaname))
-      data=loadfile(luaname)
-      if data then
-        data=data()
-      end
-      if data then
-        return data
-      end
-    end
-  end
-end
-function caches.savedata(path,name,data)
-  local luaname,lucname=makefullname(path,name)
-  if luaname then
-    texio.write(string.format("(save: %s)",luaname))
-    table.tofile(luaname,data,true)
-    if lucname and type(caches.compile)=="function" then
-      os.remove(lucname) 
-      texio.write(string.format("(save: %s)",lucname))
-      caches.compile(data,luaname,lucname)
-    end
-  end
-end
-function caches.compile(data,luaname,lucname)
-  local d=io.loaddata(luaname)
-  if not d or d=="" then
-    d=table.serialize(data,true) 
-  end
-  if d and d~="" then
-    local f=io.open(lucname,'wb')
-    if f then
-      local s=loadstring(d)
-      if s then
-        f:write(string.dump(s,true))
-      end
-      f:close()
-    end
-  end
-end
-function table.setmetatableindex(t,f)
-  setmetatable(t,{ __index=f })
-end
-arguments={}
-if arg then
-  for i=1,#arg do
-    local k,v=string.match(arg[i],"^%-%-([^=]+)=?(.-)$")
-    if k and v then
-      arguments[k]=v
-    end
-  end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['data-con']={
-  version=1.100,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local format,lower,gsub=string.format,string.lower,string.gsub
-local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end)
-local trace_containers=false trackers.register("resolvers.containers",function(v) trace_containers=v end)
-local trace_storage=false trackers.register("resolvers.storage",function(v) trace_storage=v end)
-containers=containers or {}
-local containers=containers
-containers.usecache=true
-local report_containers=logs.reporter("resolvers","containers")
-local allocated={}
-local mt={
-  __index=function(t,k)
-    if k=="writable" then
-      local writable=caches.getwritablepath(t.category,t.subcategory) or { "." }
-      t.writable=writable
-      return writable
-    elseif k=="readables" then
-      local readables=caches.getreadablepaths(t.category,t.subcategory) or { "." }
-      t.readables=readables
-      return readables
-    end
-  end,
-  __storage__=true
-}
-function containers.define(category,subcategory,version,enabled)
-  if category and subcategory then
-    local c=allocated[category]
-    if not c then
-      c={}
-      allocated[category]=c
-    end
-    local s=c[subcategory]
-    if not s then
-      s={
-        category=category,
-        subcategory=subcategory,
-        storage={},
-        enabled=enabled,
-        version=version or math.pi,
-        trace=false,
-      }
-      setmetatable(s,mt)
-      c[subcategory]=s
-    end
-    return s
-  end
-end
-function containers.is_usable(container,name)
-  return container.enabled and caches and caches.is_writable(container.writable,name)
-end
-function containers.is_valid(container,name)
-  if name and name~="" then
-    local storage=container.storage[name]
-    return storage and storage.cache_version==container.version
-  else
-    return false
-  end
-end
-function containers.read(container,name)
-  local storage=container.storage
-  local stored=storage[name]
-  if not stored and container.enabled and caches and containers.usecache then
-    stored=caches.loaddata(container.readables,name)
-    if stored and stored.cache_version==container.version then
-      if trace_cache or trace_containers then
-        report_containers("action %a, category %a, name %a","load",container.subcategory,name)
-      end
-    else
-      stored=nil
-    end
-    storage[name]=stored
-  elseif stored then
-    if trace_cache or trace_containers then
-      report_containers("action %a, category %a, name %a","reuse",container.subcategory,name)
-    end
-  end
-  return stored
-end
-function containers.write(container,name,data)
-  if data then
-    data.cache_version=container.version
-    if container.enabled and caches then
-      local unique,shared=data.unique,data.shared
-      data.unique,data.shared=nil,nil
-      caches.savedata(container.writable,name,data)
-      if trace_cache or trace_containers then
-        report_containers("action %a, category %a, name %a","save",container.subcategory,name)
-      end
-      data.unique,data.shared=unique,shared
-    end
-    if trace_cache or trace_containers then
-      report_containers("action %a, category %a, name %a","store",container.subcategory,name)
-    end
-    container.storage[name]=data
-  end
-  return data
-end
-function containers.content(container,name)
-  return container.storage[name]
-end
-function containers.cleanname(name)
-  return (gsub(lower(name),"[^%w\128-\255]+","-")) 
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['luatex-fonts-nod']={
-  version=1.001,
-  comment="companion to luatex-fonts.lua",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-if context then
-  texio.write_nl("fatal error: this module is not for context")
-  os.exit()
-end
-if tex.attribute[0]~=0 then
-  texio.write_nl("log","!")
-  texio.write_nl("log","! Attribute 0 is reserved for ConTeXt's font feature management and has to be")
-  texio.write_nl("log","! set to zero. Also, some attributes in the range 1-255 are used for special")
-  texio.write_nl("log","! purposes so setting them at the TeX end might break the font handler.")
-  texio.write_nl("log","!")
-  tex.attribute[0]=0 
-end
-attributes=attributes or {}
-attributes.unsetvalue=-0x7FFFFFFF
-local numbers,last={},127
-attributes.private=attributes.private or function(name)
-  local number=numbers[name]
-  if not number then
-    if last<255 then
-      last=last+1
-    end
-    number=last
-    numbers[name]=number
-  end
-  return number
-end
-nodes={}
-nodes.pool={}
-nodes.handlers={}
-local nodecodes={} for k,v in next,node.types  () do nodecodes[string.gsub(v,"_","")]=k end
-local whatcodes={} for k,v in next,node.whatsits() do whatcodes[string.gsub(v,"_","")]=k end
-local glyphcodes={ [0]="character","glyph","ligature","ghost","left","right" }
-local disccodes={ [0]="discretionary","explicit","automatic","regular","first","second" }
-nodes.nodecodes=nodecodes
-nodes.whatcodes=whatcodes
-nodes.whatsitcodes=whatcodes
-nodes.glyphcodes=glyphcodes
-nodes.disccodes=disccodes
-local free_node=node.free
-local remove_node=node.remove
-local new_node=node.new
-local traverse_id=node.traverse_id
-nodes.handlers.protectglyphs=node.protect_glyphs
-nodes.handlers.unprotectglyphs=node.unprotect_glyphs
-local math_code=nodecodes.math
-local end_of_math=node.end_of_math
-function node.end_of_math(n)
-  if n.id==math_code and n.subtype==1 then
-    return n
-  else
-    return end_of_math(n)
-  end
-end
-function nodes.remove(head,current,free_too)
-  local t=current
-  head,current=remove_node(head,current)
-  if t then
-    if free_too then
-      free_node(t)
-      t=nil
-    else
-      t.next,t.prev=nil,nil
-    end
-  end
-  return head,current,t
-end
-function nodes.delete(head,current)
-  return nodes.remove(head,current,true)
-end
-function nodes.pool.kern(k)
-  local n=new_node("kern",1)
-  n.kern=k
-  return n
-end
-local getfield=node.getfield or function(n,tag)    return n[tag] end
-local setfield=node.setfield or function(n,tag,value) n[tag]=value end
-nodes.getfield=getfield
-nodes.setfield=setfield
-nodes.getattr=getfield
-nodes.setattr=setfield
-if node.getid   then nodes.getid=node.getid   else function nodes.getid   (n) return getfield(n,"id")   end end
-if node.getsubtype then nodes.getsubtype=node.getsubtype else function nodes.getsubtype(n) return getfield(n,"subtype") end end
-if node.getnext  then nodes.getnext=node.getnext  else function nodes.getnext  (n) return getfield(n,"next")  end end
-if node.getprev  then nodes.getprev=node.getprev  else function nodes.getprev  (n) return getfield(n,"prev")  end end
-if node.getchar  then nodes.getchar=node.getchar  else function nodes.getchar  (n) return getfield(n,"char")  end end
-if node.getfont  then nodes.getfont=node.getfont  else function nodes.getfont  (n) return getfield(n,"font")  end end
-if node.getlist  then nodes.getlist=node.getlist  else function nodes.getlist  (n) return getfield(n,"list")  end end
-function nodes.tonut (n) return n end
-function nodes.tonode(n) return n end
-nodes.tostring=node.tostring or tostring
-nodes.copy=node.copy
-nodes.copy_list=node.copy_list
-nodes.delete=node.delete
-nodes.dimensions=node.dimensions
-nodes.end_of_math=node.end_of_math
-nodes.flush_list=node.flush_list
-nodes.flush_node=node.flush_node
-nodes.free=node.free
-nodes.insert_after=node.insert_after
-nodes.insert_before=node.insert_before
-nodes.hpack=node.hpack
-nodes.new=node.new
-nodes.tail=node.tail
-nodes.traverse=node.traverse
-nodes.traverse_id=node.traverse_id
-nodes.slide=node.slide
-nodes.vpack=node.vpack
-nodes.first_glyph=node.first_glyph
-nodes.first_character=node.first_character
-nodes.has_glyph=node.has_glyph or node.first_glyph
-nodes.current_attr=node.current_attr
-nodes.do_ligature_n=node.do_ligature_n
-nodes.has_field=node.has_field
-nodes.last_node=node.last_node
-nodes.usedlist=node.usedlist
-nodes.protrusion_skippable=node.protrusion_skippable
-nodes.write=node.write
-nodes.has_attribute=node.has_attribute
-nodes.set_attribute=node.set_attribute
-nodes.unset_attribute=node.unset_attribute
-nodes.protect_glyphs=node.protect_glyphs
-nodes.unprotect_glyphs=node.unprotect_glyphs
-nodes.kerning=node.kerning
-nodes.ligaturing=node.ligaturing
-nodes.mlist_to_hlist=node.mlist_to_hlist
-nodes.nuts=nodes
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['font-ini']={
-  version=1.001,
-  comment="companion to font-ini.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local allocate=utilities.storage.allocate
-local report_defining=logs.reporter("fonts","defining")
-fonts=fonts or {}
-local fonts=fonts
-fonts.hashes={ identifiers=allocate() }
-fonts.tables=fonts.tables   or {}
-fonts.helpers=fonts.helpers  or {}
-fonts.tracers=fonts.tracers  or {} 
-fonts.specifiers=fonts.specifiers or {} 
-fonts.analyzers={} 
-fonts.readers={}
-fonts.definers={ methods={} }
-fonts.loggers={ register=function() end }
-fontloader.totable=fontloader.to_table
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['font-con']={
-  version=1.001,
-  comment="companion to font-ini.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local next,tostring,rawget=next,tostring,rawget
-local format,match,lower,gsub=string.format,string.match,string.lower,string.gsub
-local utfbyte=utf.byte
-local sort,insert,concat,sortedkeys,serialize,fastcopy=table.sort,table.insert,table.concat,table.sortedkeys,table.serialize,table.fastcopy
-local derivetable=table.derive
-local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end)
-local trace_scaling=false trackers.register("fonts.scaling",function(v) trace_scaling=v end)
-local report_defining=logs.reporter("fonts","defining")
-local fonts=fonts
-local constructors=fonts.constructors or {}
-fonts.constructors=constructors
-local handlers=fonts.handlers or {} 
-fonts.handlers=handlers
-local allocate=utilities.storage.allocate
-local setmetatableindex=table.setmetatableindex
-constructors.dontembed=allocate()
-constructors.autocleanup=true
-constructors.namemode="fullpath" 
-constructors.version=1.01
-constructors.cache=containers.define("fonts","constructors",constructors.version,false)
-constructors.privateoffset=0xF0000
-constructors.keys={
-  properties={
-    encodingbytes="number",
-    embedding="number",
-    cidinfo={},
-    format="string",
-    fontname="string",
-    fullname="string",
-    filename="filename",
-    psname="string",
-    name="string",
-    virtualized="boolean",
-    hasitalics="boolean",
-    autoitalicamount="basepoints",
-    nostackmath="boolean",
-    noglyphnames="boolean",
-    mode="string",
-    hasmath="boolean",
-    mathitalics="boolean",
-    textitalics="boolean",
-    finalized="boolean",
-  },
-  parameters={
-    mathsize="number",
-    scriptpercentage="float",
-    scriptscriptpercentage="float",
-    units="cardinal",
-    designsize="scaledpoints",
-    expansion={
-                  stretch="integerscale",
-                  shrink="integerscale",
-                  step="integerscale",
-                  auto="boolean",
-                 },
-    protrusion={
-                  auto="boolean",
-                 },
-    slantfactor="float",
-    extendfactor="float",
-    factor="float",
-    hfactor="float",
-    vfactor="float",
-    size="scaledpoints",
-    units="scaledpoints",
-    scaledpoints="scaledpoints",
-    slantperpoint="scaledpoints",
-    spacing={
-                  width="scaledpoints",
-                  stretch="scaledpoints",
-                  shrink="scaledpoints",
-                  extra="scaledpoints",
-                 },
-    xheight="scaledpoints",
-    quad="scaledpoints",
-    ascender="scaledpoints",
-    descender="scaledpoints",
-    synonyms={
-                  space="spacing.width",
-                  spacestretch="spacing.stretch",
-                  spaceshrink="spacing.shrink",
-                  extraspace="spacing.extra",
-                  x_height="xheight",
-                  space_stretch="spacing.stretch",
-                  space_shrink="spacing.shrink",
-                  extra_space="spacing.extra",
-                  em="quad",
-                  ex="xheight",
-                  slant="slantperpoint",
-                 },
-  },
-  description={
-    width="basepoints",
-    height="basepoints",
-    depth="basepoints",
-    boundingbox={},
-  },
-  character={
-    width="scaledpoints",
-    height="scaledpoints",
-    depth="scaledpoints",
-    italic="scaledpoints",
-  },
-}
-local designsizes=allocate()
-constructors.designsizes=designsizes
-local loadedfonts=allocate()
-constructors.loadedfonts=loadedfonts
-local factors={
-  pt=65536.0,
-  bp=65781.8,
-}
-function constructors.setfactor(f)
-  constructors.factor=factors[f or 'pt'] or factors.pt
-end
-constructors.setfactor()
-function constructors.scaled(scaledpoints,designsize) 
-  if scaledpoints<0 then
-    if designsize then
-      local factor=constructors.factor
-      if designsize>factor then 
-        return (- scaledpoints/1000)*designsize 
-      else
-        return (- scaledpoints/1000)*designsize*factor
-      end
-    else
-      return (- scaledpoints/1000)*10*factor
-    end
-  else
-    return scaledpoints
-  end
-end
-function constructors.cleanuptable(tfmdata)
-  if constructors.autocleanup and tfmdata.properties.virtualized then
-    for k,v in next,tfmdata.characters do
-      if v.commands then v.commands=nil end
-    end
-  end
-end
-function constructors.calculatescale(tfmdata,scaledpoints)
-  local parameters=tfmdata.parameters
-  if scaledpoints<0 then
-    scaledpoints=(- scaledpoints/1000)*(tfmdata.designsize or parameters.designsize) 
-  end
-  return scaledpoints,scaledpoints/(parameters.units or 1000) 
-end
-local unscaled={
-  ScriptPercentScaleDown=true,
-  ScriptScriptPercentScaleDown=true,
-  RadicalDegreeBottomRaisePercent=true
-}
-function constructors.assignmathparameters(target,original)
-  local mathparameters=original.mathparameters
-  if mathparameters and next(mathparameters) then
-    local targetparameters=target.parameters
-    local targetproperties=target.properties
-    local targetmathparameters={}
-    local factor=targetproperties.math_is_scaled and 1 or targetparameters.factor
-    for name,value in next,mathparameters do
-      if unscaled[name] then
-        targetmathparameters[name]=value
-      else
-        targetmathparameters[name]=value*factor
-      end
-    end
-    if not targetmathparameters.FractionDelimiterSize then
-      targetmathparameters.FractionDelimiterSize=1.01*targetparameters.size
-    end
-    if not mathparameters.FractionDelimiterDisplayStyleSize then
-      targetmathparameters.FractionDelimiterDisplayStyleSize=2.40*targetparameters.size
-    end
-    target.mathparameters=targetmathparameters
-  end
-end
-function constructors.beforecopyingcharacters(target,original)
-end
-function constructors.aftercopyingcharacters(target,original)
-end
-constructors.sharefonts=false
-constructors.nofsharedfonts=0
-local sharednames={}
-function constructors.trytosharefont(target,tfmdata)
-  if constructors.sharefonts then 
-    local characters=target.characters
-    local n=1
-    local t={ target.psname }
-    local u=sortedkeys(characters)
-    for i=1,#u do
-      local k=u[i]
-      n=n+1;t[n]=k
-      n=n+1;t[n]=characters[k].index or k
-    end
-    local h=md5.HEX(concat(t," "))
-    local s=sharednames[h]
-    if s then
-      if trace_defining then
-        report_defining("font %a uses backend resources of font %a",target.fullname,s)
-      end
-      target.fullname=s
-      constructors.nofsharedfonts=constructors.nofsharedfonts+1
-      target.properties.sharedwith=s
-    else
-      sharednames[h]=target.fullname
-    end
-  end
-end
-function constructors.enhanceparameters(parameters)
-  local xheight=parameters.x_height
-  local quad=parameters.quad
-  local space=parameters.space
-  local stretch=parameters.space_stretch
-  local shrink=parameters.space_shrink
-  local extra=parameters.extra_space
-  local slant=parameters.slant
-  parameters.xheight=xheight
-  parameters.spacestretch=stretch
-  parameters.spaceshrink=shrink
-  parameters.extraspace=extra
-  parameters.em=quad
-  parameters.ex=xheight
-  parameters.slantperpoint=slant
-  parameters.spacing={
-    width=space,
-    stretch=stretch,
-    shrink=shrink,
-    extra=extra,
-  }
-end
-function constructors.scale(tfmdata,specification)
-  local target={}
-  if tonumber(specification) then
-    specification={ size=specification }
-  end
-  target.specification=specification
-  local scaledpoints=specification.size
-  local relativeid=specification.relativeid
-  local properties=tfmdata.properties   or {}
-  local goodies=tfmdata.goodies    or {}
-  local resources=tfmdata.resources   or {}
-  local descriptions=tfmdata.descriptions  or {} 
-  local characters=tfmdata.characters   or {} 
-  local changed=tfmdata.changed    or {} 
-  local shared=tfmdata.shared     or {}
-  local parameters=tfmdata.parameters   or {}
-  local mathparameters=tfmdata.mathparameters or {}
-  local targetcharacters={}
-  local targetdescriptions=derivetable(descriptions)
-  local targetparameters=derivetable(parameters)
-  local targetproperties=derivetable(properties)
-  local targetgoodies=goodies            
-  target.characters=targetcharacters
-  target.descriptions=targetdescriptions
-  target.parameters=targetparameters
-  target.properties=targetproperties
-  target.goodies=targetgoodies
-  target.shared=shared
-  target.resources=resources
-  target.unscaled=tfmdata
-  local mathsize=tonumber(specification.mathsize) or 0
-  local textsize=tonumber(specification.textsize) or scaledpoints
-  local forcedsize=tonumber(parameters.mathsize  ) or 0
-  local extrafactor=tonumber(specification.factor ) or 1
-  if (mathsize==2 or forcedsize==2) and parameters.scriptpercentage then
-    scaledpoints=parameters.scriptpercentage*textsize/100
-  elseif (mathsize==3 or forcedsize==3) and parameters.scriptscriptpercentage then
-    scaledpoints=parameters.scriptscriptpercentage*textsize/100
-  elseif forcedsize>1000 then 
-    scaledpoints=forcedsize
-  end
-  targetparameters.mathsize=mathsize  
-  targetparameters.textsize=textsize  
-  targetparameters.forcedsize=forcedsize 
-  targetparameters.extrafactor=extrafactor
-  local tounicode=resources.tounicode
-  local defaultwidth=resources.defaultwidth or 0
-  local defaultheight=resources.defaultheight or 0
-  local defaultdepth=resources.defaultdepth or 0
-  local units=parameters.units or 1000
-  if target.fonts then
-    target.fonts=fastcopy(target.fonts) 
-  end
-  targetproperties.language=properties.language or "dflt" 
-  targetproperties.script=properties.script  or "dflt" 
-  targetproperties.mode=properties.mode   or "base"
-  local askedscaledpoints=scaledpoints
-  local scaledpoints,delta=constructors.calculatescale(tfmdata,scaledpoints,nil,specification)
-  local hdelta=delta
-  local vdelta=delta
-  target.designsize=parameters.designsize 
-  target.units_per_em=units
-  local direction=properties.direction or tfmdata.direction or 0 
-  target.direction=direction
-  properties.direction=direction
-  target.size=scaledpoints
-  target.encodingbytes=properties.encodingbytes or 1
-  target.embedding=properties.embedding or "subset"
-  target.tounicode=1
-  target.cidinfo=properties.cidinfo
-  target.format=properties.format
-  local fontname=properties.fontname or tfmdata.fontname 
-  local fullname=properties.fullname or tfmdata.fullname 
-  local filename=properties.filename or tfmdata.filename 
-  local psname=properties.psname  or tfmdata.psname  
-  local name=properties.name   or tfmdata.name
-  if not psname or psname=="" then
-    psname=fontname or (fullname and fonts.names.cleanname(fullname))
-  end
-  target.fontname=fontname
-  target.fullname=fullname
-  target.filename=filename
-  target.psname=psname
-  target.name=name
-  properties.fontname=fontname
-  properties.fullname=fullname
-  properties.filename=filename
-  properties.psname=psname
-  properties.name=name
-  local expansion=parameters.expansion
-  if expansion then
-    target.stretch=expansion.stretch
-    target.shrink=expansion.shrink
-    target.step=expansion.step
-    target.auto_expand=expansion.auto
-  end
-  local protrusion=parameters.protrusion
-  if protrusion then
-    target.auto_protrude=protrusion.auto
-  end
-  local extendfactor=parameters.extendfactor or 0
-  if extendfactor~=0 and extendfactor~=1 then
-    hdelta=hdelta*extendfactor
-    target.extend=extendfactor*1000 
-  else
-    target.extend=1000 
-  end
-  local slantfactor=parameters.slantfactor or 0
-  if slantfactor~=0 then
-    target.slant=slantfactor*1000
-  else
-    target.slant=0
-  end
-  targetparameters.factor=delta
-  targetparameters.hfactor=hdelta
-  targetparameters.vfactor=vdelta
-  targetparameters.size=scaledpoints
-  targetparameters.units=units
-  targetparameters.scaledpoints=askedscaledpoints
-  local isvirtual=properties.virtualized or tfmdata.type=="virtual"
-  local hasquality=target.auto_expand or target.auto_protrude
-  local hasitalics=properties.hasitalics
-  local autoitalicamount=properties.autoitalicamount
-  local stackmath=not properties.nostackmath
-  local nonames=properties.noglyphnames
-  local nodemode=properties.mode=="node"
-  if changed and not next(changed) then
-    changed=false
-  end
-  target.type=isvirtual and "virtual" or "real"
-  target.postprocessors=tfmdata.postprocessors
-  local targetslant=(parameters.slant     or parameters[1] or 0)*factors.pt 
-  local targetspace=(parameters.space     or parameters[2] or 0)*hdelta
-  local targetspace_stretch=(parameters.space_stretch or parameters[3] or 0)*hdelta
-  local targetspace_shrink=(parameters.space_shrink or parameters[4] or 0)*hdelta
-  local targetx_height=(parameters.x_height   or parameters[5] or 0)*vdelta
-  local targetquad=(parameters.quad     or parameters[6] or 0)*hdelta
-  local targetextra_space=(parameters.extra_space  or parameters[7] or 0)*hdelta
-  targetparameters.slant=targetslant 
-  targetparameters.space=targetspace
-  targetparameters.space_stretch=targetspace_stretch
-  targetparameters.space_shrink=targetspace_shrink
-  targetparameters.x_height=targetx_height
-  targetparameters.quad=targetquad
-  targetparameters.extra_space=targetextra_space
-  local ascender=parameters.ascender
-  if ascender then
-    targetparameters.ascender=delta*ascender
-  end
-  local descender=parameters.descender
-  if descender then
-    targetparameters.descender=delta*descender
-  end
-  constructors.enhanceparameters(targetparameters)
-  local protrusionfactor=(targetquad~=0 and 1000/targetquad) or 0
-  local scaledwidth=defaultwidth*hdelta
-  local scaledheight=defaultheight*vdelta
-  local scaleddepth=defaultdepth*vdelta
-  local hasmath=(properties.hasmath or next(mathparameters)) and true
-  if hasmath then
-    constructors.assignmathparameters(target,tfmdata) 
-    properties.hasmath=true
-    target.nomath=false
-    target.MathConstants=target.mathparameters
-  else
-    properties.hasmath=false
-    target.nomath=true
-    target.mathparameters=nil 
-  end
-  local italickey="italic"
-  local useitalics=true
-  if hasmath then
-    autoitalicamount=false 
-  elseif properties.textitalics then
-    italickey="italic_correction"
-    useitalics=false
-    if properties.delaytextitalics then
-      autoitalicamount=false
-    end
-  end
-  if trace_defining then
-    report_defining("defining tfm, name %a, fullname %a, filename %a, hscale %a, vscale %a, math %a, italics %a",
-      name,fullname,filename,hdelta,vdelta,
-      hasmath and "enabled" or "disabled",useitalics and "enabled" or "disabled")
-  end
-  constructors.beforecopyingcharacters(target,tfmdata)
-  local sharedkerns={}
-  for unicode,character in next,characters do
-    local chr,description,index,touni
-    if changed then
-      local c=changed[unicode]
-      if c then
-        local ligatures=character.ligatures 
-        description=descriptions[c] or descriptions[unicode] or character
-        character=characters[c] or character
-        index=description.index or c
-        if tounicode then
-          touni=tounicode[index] 
-          if not touni then 
-            local d=descriptions[unicode] or characters[unicode]
-            local i=d.index or unicode
-            touni=tounicode[i] 
-          end
-        end
-        if ligatures and not character.ligatures then
-          character.ligatures=ligatures 
-        end
-      else
-        description=descriptions[unicode] or character
-        index=description.index or unicode
-        if tounicode then
-          touni=tounicode[index] 
-        end
-      end
-    else
-      description=descriptions[unicode] or character
-      index=description.index or unicode
-      if tounicode then
-        touni=tounicode[index] 
-      end
-    end
-    local width=description.width
-    local height=description.height
-    local depth=description.depth
-    if width then width=hdelta*width else width=scaledwidth end
-    if height then height=vdelta*height else height=scaledheight end
-    if depth and depth~=0 then
-      depth=delta*depth
-      if nonames then
-        chr={
-          index=index,
-          height=height,
-          depth=depth,
-          width=width,
-        }
-      else
-        chr={
-          name=description.name,
-          index=index,
-          height=height,
-          depth=depth,
-          width=width,
-        }
-      end
-    else
-      if nonames then
-        chr={
-          index=index,
-          height=height,
-          width=width,
-        }
-      else
-        chr={
-          name=description.name,
-          index=index,
-          height=height,
-          width=width,
-        }
-      end
-    end
-    if touni then
-      chr.tounicode=touni
-    end
-    if hasquality then
-      local ve=character.expansion_factor
-      if ve then
-        chr.expansion_factor=ve*1000 
-      end
-      local vl=character.left_protruding
-      if vl then
-        chr.left_protruding=protrusionfactor*width*vl
-      end
-      local vr=character.right_protruding
-      if vr then
-        chr.right_protruding=protrusionfactor*width*vr
-      end
-    end
-    if autoitalicamount then
-      local vi=description.italic
-      if not vi then
-        local vi=description.boundingbox[3]-description.width+autoitalicamount
-        if vi>0 then 
-          chr[italickey]=vi*hdelta
-        end
-      elseif vi~=0 then
-        chr[italickey]=vi*hdelta
-      end
-    elseif hasitalics then
-      local vi=description.italic
-      if vi and vi~=0 then
-        chr[italickey]=vi*hdelta
-      end
-    end
-    if hasmath then
-      local vn=character.next
-      if vn then
-        chr.next=vn
-      else
-        local vv=character.vert_variants
-        if vv then
-          local t={}
-          for i=1,#vv do
-            local vvi=vv[i]
-            t[i]={
-              ["start"]=(vvi["start"]  or 0)*vdelta,
-              ["end"]=(vvi["end"]   or 0)*vdelta,
-              ["advance"]=(vvi["advance"] or 0)*vdelta,
-              ["extender"]=vvi["extender"],
-              ["glyph"]=vvi["glyph"],
-            }
-          end
-          chr.vert_variants=t
-        else
-          local hv=character.horiz_variants
-          if hv then
-            local t={}
-            for i=1,#hv do
-              local hvi=hv[i]
-              t[i]={
-                ["start"]=(hvi["start"]  or 0)*hdelta,
-                ["end"]=(hvi["end"]   or 0)*hdelta,
-                ["advance"]=(hvi["advance"] or 0)*hdelta,
-                ["extender"]=hvi["extender"],
-                ["glyph"]=hvi["glyph"],
-              }
-            end
-            chr.horiz_variants=t
-          end
-        end
-      end
-      local va=character.top_accent
-      if va then
-        chr.top_accent=vdelta*va
-      end
-      if stackmath then
-        local mk=character.mathkerns 
-        if mk then
-          local kerns={}
-          local v=mk.top_right  if v then local k={} for i=1,#v do local vi=v[i]
-            k[i]={ height=vdelta*vi.height,kern=vdelta*vi.kern }
-          end   kerns.top_right=k end
-          local v=mk.top_left   if v then local k={} for i=1,#v do local vi=v[i]
-            k[i]={ height=vdelta*vi.height,kern=vdelta*vi.kern }
-          end   kerns.top_left=k end
-          local v=mk.bottom_left if v then local k={} for i=1,#v do local vi=v[i]
-            k[i]={ height=vdelta*vi.height,kern=vdelta*vi.kern }
-          end   kerns.bottom_left=k end
-          local v=mk.bottom_right if v then local k={} for i=1,#v do local vi=v[i]
-            k[i]={ height=vdelta*vi.height,kern=vdelta*vi.kern }
-          end   kerns.bottom_right=k end
-          chr.mathkern=kerns 
-        end
-      end
-    end
-    if not nodemode then
-      local vk=character.kerns
-      if vk then
-        local s=sharedkerns[vk]
-        if not s then
-          s={}
-          for k,v in next,vk do s[k]=v*hdelta end
-          sharedkerns[vk]=s
-        end
-        chr.kerns=s
-      end
-      local vl=character.ligatures
-      if vl then
-        if true then
-          chr.ligatures=vl 
-        else
-          local tt={}
-          for i,l in next,vl do
-            tt[i]=l
-          end
-          chr.ligatures=tt
-        end
-      end
-    end
-    if isvirtual then
-      local vc=character.commands
-      if vc then
-        local ok=false
-        for i=1,#vc do
-          local key=vc[i][1]
-          if key=="right" or key=="down" then
-            ok=true
-            break
-          end
-        end
-        if ok then
-          local tt={}
-          for i=1,#vc do
-            local ivc=vc[i]
-            local key=ivc[1]
-            if key=="right" then
-              tt[i]={ key,ivc[2]*hdelta }
-            elseif key=="down" then
-              tt[i]={ key,ivc[2]*vdelta }
-            elseif key=="rule" then
-              tt[i]={ key,ivc[2]*vdelta,ivc[3]*hdelta }
-            else 
-              tt[i]=ivc 
-            end
-          end
-          chr.commands=tt
-        else
-          chr.commands=vc
-        end
-        chr.index=nil
-      end
-    end
-    targetcharacters[unicode]=chr
-  end
-  constructors.aftercopyingcharacters(target,tfmdata)
-  constructors.trytosharefont(target,tfmdata)
-  return target
-end
-function constructors.finalize(tfmdata)
-  if tfmdata.properties and tfmdata.properties.finalized then
-    return
-  end
-  if not tfmdata.characters then
-    return nil
-  end
-  if not tfmdata.goodies then
-    tfmdata.goodies={} 
-  end
-  local parameters=tfmdata.parameters
-  if not parameters then
-    return nil
-  end
-  if not parameters.expansion then
-    parameters.expansion={
-      stretch=tfmdata.stretch   or 0,
-      shrink=tfmdata.shrink   or 0,
-      step=tfmdata.step    or 0,
-      auto=tfmdata.auto_expand or false,
-    }
-  end
-  if not parameters.protrusion then
-    parameters.protrusion={
-      auto=auto_protrude
-    }
-  end
-  if not parameters.size then
-    parameters.size=tfmdata.size
-  end
-  if not parameters.extendfactor then
-    parameters.extendfactor=tfmdata.extend or 0
-  end
-  if not parameters.slantfactor then
-    parameters.slantfactor=tfmdata.slant or 0
-  end
-  if not parameters.designsize then
-    parameters.designsize=tfmdata.designsize or (factors.pt*10)
-  end
-  if not parameters.units then
-    parameters.units=tfmdata.units_per_em or 1000
-  end
-  if not tfmdata.descriptions then
-    local descriptions={} 
-    setmetatableindex(descriptions,function(t,k) local v={} t[k]=v return v end)
-    tfmdata.descriptions=descriptions
-  end
-  local properties=tfmdata.properties
-  if not properties then
-    properties={}
-    tfmdata.properties=properties
-  end
-  if not properties.virtualized then
-    properties.virtualized=tfmdata.type=="virtual"
-  end
-  if not tfmdata.properties then
-    tfmdata.properties={
-      fontname=tfmdata.fontname,
-      filename=tfmdata.filename,
-      fullname=tfmdata.fullname,
-      name=tfmdata.name,
-      psname=tfmdata.psname,
-      encodingbytes=tfmdata.encodingbytes or 1,
-      embedding=tfmdata.embedding   or "subset",
-      tounicode=tfmdata.tounicode   or 1,
-      cidinfo=tfmdata.cidinfo    or nil,
-      format=tfmdata.format    or "type1",
-      direction=tfmdata.direction   or 0,
-    }
-  end
-  if not tfmdata.resources then
-    tfmdata.resources={}
-  end
-  if not tfmdata.shared then
-    tfmdata.shared={}
-  end
-  if not properties.hasmath then
-    properties.hasmath=not tfmdata.nomath
-  end
-  tfmdata.MathConstants=nil
-  tfmdata.postprocessors=nil
-  tfmdata.fontname=nil
-  tfmdata.filename=nil
-  tfmdata.fullname=nil
-  tfmdata.name=nil 
-  tfmdata.psname=nil
-  tfmdata.encodingbytes=nil
-  tfmdata.embedding=nil
-  tfmdata.tounicode=nil
-  tfmdata.cidinfo=nil
-  tfmdata.format=nil
-  tfmdata.direction=nil
-  tfmdata.type=nil
-  tfmdata.nomath=nil
-  tfmdata.designsize=nil
-  tfmdata.size=nil
-  tfmdata.stretch=nil
-  tfmdata.shrink=nil
-  tfmdata.step=nil
-  tfmdata.auto_expand=nil
-  tfmdata.auto_protrude=nil
-  tfmdata.extend=nil
-  tfmdata.slant=nil
-  tfmdata.units_per_em=nil
-  properties.finalized=true
-  return tfmdata
-end
-local hashmethods={}
-constructors.hashmethods=hashmethods
-function constructors.hashfeatures(specification) 
-  local features=specification.features
-  if features then
-    local t,tn={},0
-    for category,list in next,features do
-      if next(list) then
-        local hasher=hashmethods[category]
-        if hasher then
-          local hash=hasher(list)
-          if hash then
-            tn=tn+1
-            t[tn]=category..":"..hash
-          end
-        end
-      end
-    end
-    if tn>0 then
-      return concat(t," & ")
-    end
-  end
-  return "unknown"
-end
-hashmethods.normal=function(list)
-  local s={}
-  local n=0
-  for k,v in next,list do
-    if not k then
-    elseif k=="number" or k=="features" then
-    else
-      n=n+1
-      s[n]=k
-    end
-  end
-  if n>0 then
-    sort(s)
-    for i=1,n do
-      local k=s[i]
-      s[i]=k..'='..tostring(list[k])
-    end
-    return concat(s,"+")
-  end
-end
-function constructors.hashinstance(specification,force)
-  local hash,size,fallbacks=specification.hash,specification.size,specification.fallbacks
-  if force or not hash then
-    hash=constructors.hashfeatures(specification)
-    specification.hash=hash
-  end
-  if size<1000 and designsizes[hash] then
-    size=math.round(constructors.scaled(size,designsizes[hash]))
-    specification.size=size
-  end
-  if fallbacks then
-    return hash..' @ '..tostring(size)..' @ '..fallbacks
-  else
-    return hash..' @ '..tostring(size)
-  end
-end
-function constructors.setname(tfmdata,specification) 
-  if constructors.namemode=="specification" then
-    local specname=specification.specification
-    if specname then
-      tfmdata.properties.name=specname
-      if trace_defining then
-        report_otf("overloaded fontname %a",specname)
-      end
-    end
-  end
-end
-function constructors.checkedfilename(data)
-  local foundfilename=data.foundfilename
-  if not foundfilename then
-    local askedfilename=data.filename or ""
-    if askedfilename~="" then
-      askedfilename=resolvers.resolve(askedfilename) 
-      foundfilename=resolvers.findbinfile(askedfilename,"") or ""
-      if foundfilename=="" then
-        report_defining("source file %a is not found",askedfilename)
-        foundfilename=resolvers.findbinfile(file.basename(askedfilename),"") or ""
-        if foundfilename~="" then
-          report_defining("using source file %a due to cache mismatch",foundfilename)
-        end
-      end
-    end
-    data.foundfilename=foundfilename
-  end
-  return foundfilename
-end
-local formats=allocate()
-fonts.formats=formats
-setmetatableindex(formats,function(t,k)
-  local l=lower(k)
-  if rawget(t,k) then
-    t[k]=l
-    return l
-  end
-  return rawget(t,file.suffix(l))
-end)
-local locations={}
-local function setindeed(mode,target,group,name,action,position)
-  local t=target[mode]
-  if not t then
-    report_defining("fatal error in setting feature %a, group %a, mode %a",name,group,mode)
-    os.exit()
-  elseif position then
-    insert(t,position,{ name=name,action=action })
-  else
-    for i=1,#t do
-      local ti=t[i]
-      if ti.name==name then
-        ti.action=action
-        return
-      end
-    end
-    insert(t,{ name=name,action=action })
-  end
-end
-local function set(group,name,target,source)
-  target=target[group]
-  if not target then
-    report_defining("fatal target error in setting feature %a, group %a",name,group)
-    os.exit()
-  end
-  local source=source[group]
-  if not source then
-    report_defining("fatal source error in setting feature %a, group %a",name,group)
-    os.exit()
-  end
-  local node=source.node
-  local base=source.base
-  local position=source.position
-  if node then
-    setindeed("node",target,group,name,node,position)
-  end
-  if base then
-    setindeed("base",target,group,name,base,position)
-  end
-end
-local function register(where,specification)
-  local name=specification.name
-  if name and name~="" then
-    local default=specification.default
-    local description=specification.description
-    local initializers=specification.initializers
-    local processors=specification.processors
-    local manipulators=specification.manipulators
-    local modechecker=specification.modechecker
-    if default then
-      where.defaults[name]=default
-    end
-    if description and description~="" then
-      where.descriptions[name]=description
-    end
-    if initializers then
-      set('initializers',name,where,specification)
-    end
-    if processors then
-      set('processors',name,where,specification)
-    end
-    if manipulators then
-      set('manipulators',name,where,specification)
-    end
-    if modechecker then
-      where.modechecker=modechecker
-    end
-  end
-end
-constructors.registerfeature=register
-function constructors.getfeatureaction(what,where,mode,name)
-  what=handlers[what].features
-  if what then
-    where=what[where]
-    if where then
-      mode=where[mode]
-      if mode then
-        for i=1,#mode do
-          local m=mode[i]
-          if m.name==name then
-            return m.action
-          end
-        end
-      end
-    end
-  end
-end
-function constructors.newhandler(what) 
-  local handler=handlers[what]
-  if not handler then
-    handler={}
-    handlers[what]=handler
-  end
-  return handler
-end
-function constructors.newfeatures(what) 
-  local handler=handlers[what]
-  local features=handler.features
-  if not features then
-    local tables=handler.tables   
-    local statistics=handler.statistics 
-    features=allocate {
-      defaults={},
-      descriptions=tables and tables.features or {},
-      used=statistics and statistics.usedfeatures or {},
-      initializers={ base={},node={} },
-      processors={ base={},node={} },
-      manipulators={ base={},node={} },
-    }
-    features.register=function(specification) return register(features,specification) end
-    handler.features=features 
-  end
-  return features
-end
-function constructors.checkedfeatures(what,features)
-  local defaults=handlers[what].features.defaults
-  if features and next(features) then
-    features=fastcopy(features) 
-    for key,value in next,defaults do
-      if features[key]==nil then
-        features[key]=value
-      end
-    end
-    return features
-  else
-    return fastcopy(defaults) 
-  end
-end
-function constructors.initializefeatures(what,tfmdata,features,trace,report)
-  if features and next(features) then
-    local properties=tfmdata.properties or {} 
-    local whathandler=handlers[what]
-    local whatfeatures=whathandler.features
-    local whatinitializers=whatfeatures.initializers
-    local whatmodechecker=whatfeatures.modechecker
-    local mode=properties.mode or (whatmodechecker and whatmodechecker(tfmdata,features,features.mode)) or features.mode or "base"
-    properties.mode=mode 
-    features.mode=mode
-    local done={}
-    while true do
-      local redo=false
-      local initializers=whatfeatures.initializers[mode]
-      if initializers then
-        for i=1,#initializers do
-          local step=initializers[i]
-          local feature=step.name
-          local value=features[feature]
-          if not value then
-          elseif done[feature] then
-          else
-            local action=step.action
-            if trace then
-              report("initializing feature %a to %a for mode %a for font %a",feature,
-                value,mode,tfmdata.properties.fullname)
-            end
-            action(tfmdata,value,features) 
-            if mode~=properties.mode or mode~=features.mode then
-              if whatmodechecker then
-                properties.mode=whatmodechecker(tfmdata,features,properties.mode) 
-                features.mode=properties.mode
-              end
-              if mode~=properties.mode then
-                mode=properties.mode
-                redo=true
-              end
-            end
-            done[feature]=true
-          end
-          if redo then
-            break
-          end
-        end
-        if not redo then
-          break
-        end
-      else
-        break
-      end
-    end
-    properties.mode=mode 
-    return true
-  else
-    return false
-  end
-end
-function constructors.collectprocessors(what,tfmdata,features,trace,report)
-  local processes,nofprocesses={},0
-  if features and next(features) then
-    local properties=tfmdata.properties
-    local whathandler=handlers[what]
-    local whatfeatures=whathandler.features
-    local whatprocessors=whatfeatures.processors
-    local mode=properties.mode
-    local processors=whatprocessors[mode]
-    if processors then
-      for i=1,#processors do
-        local step=processors[i]
-        local feature=step.name
-        if features[feature] then
-          local action=step.action
-          if trace then
-            report("installing feature processor %a for mode %a for font %a",feature,mode,tfmdata.properties.fullname)
-          end
-          if action then
-            nofprocesses=nofprocesses+1
-            processes[nofprocesses]=action
-          end
-        end
-      end
-    elseif trace then
-      report("no feature processors for mode %a for font %a",mode,properties.fullname)
-    end
-  end
-  return processes
-end
-function constructors.applymanipulators(what,tfmdata,features,trace,report)
-  if features and next(features) then
-    local properties=tfmdata.properties
-    local whathandler=handlers[what]
-    local whatfeatures=whathandler.features
-    local whatmanipulators=whatfeatures.manipulators
-    local mode=properties.mode
-    local manipulators=whatmanipulators[mode]
-    if manipulators then
-      for i=1,#manipulators do
-        local step=manipulators[i]
-        local feature=step.name
-        local value=features[feature]
-        if value then
-          local action=step.action
-          if trace then
-            report("applying feature manipulator %a for mode %a for font %a",feature,mode,properties.fullname)
-          end
-          if action then
-            action(tfmdata,feature,value)
-          end
-        end
-      end
-    end
-  end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['luatex-font-enc']={
-  version=1.001,
-  comment="companion to luatex-*.tex",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-if context then
-  texio.write_nl("fatal error: this module is not for context")
-  os.exit()
-end
-local fonts=fonts
-fonts.encodings={}
-fonts.encodings.agl={}
-fonts.encodings.known={}
-setmetatable(fonts.encodings.agl,{ __index=function(t,k)
-  if k=="unicodes" then
-    texio.write(" <loading (extended) adobe glyph list>")
-    local unicodes=dofile(resolvers.findfile("font-age.lua"))
-    fonts.encodings.agl={ unicodes=unicodes }
-    return unicodes
-  else
-    return nil
-  end
-end })
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['font-cid']={
-  version=1.001,
-  comment="companion to font-otf.lua (cidmaps)",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local format,match,lower=string.format,string.match,string.lower
-local tonumber=tonumber
-local P,S,R,C,V,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.V,lpeg.match
-local fonts,logs,trackers=fonts,logs,trackers
-local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end)
-local report_otf=logs.reporter("fonts","otf loading")
-local cid={}
-fonts.cid=cid
-local cidmap={}
-local cidmax=10
-local number=C(R("09","af","AF")^1)
-local space=S(" \n\r\t")
-local spaces=space^0
-local period=P(".")
-local periods=period*period
-local name=P("/")*C((1-space)^1)
-local unicodes,names={},{} 
-local function do_one(a,b)
-  unicodes[tonumber(a)]=tonumber(b,16)
-end
-local function do_range(a,b,c)
-  c=tonumber(c,16)
-  for i=tonumber(a),tonumber(b) do
-    unicodes[i]=c
-    c=c+1
-  end
-end
-local function do_name(a,b)
-  names[tonumber(a)]=b
-end
-local grammar=P { "start",
-  start=number*spaces*number*V("series"),
-  series=(spaces*(V("one")+V("range")+V("named")))^1,
-  one=(number*spaces*number)/do_one,
-  range=(number*periods*number*spaces*number)/do_range,
-  named=(number*spaces*name)/do_name
-}
-local function loadcidfile(filename)
-  local data=io.loaddata(filename)
-  if data then
-    unicodes,names={},{}
-    lpegmatch(grammar,data)
-    local supplement,registry,ordering=match(filename,"^(.-)%-(.-)%-()%.(.-)$")
-    return {
-      supplement=supplement,
-      registry=registry,
-      ordering=ordering,
-      filename=filename,
-      unicodes=unicodes,
-      names=names
-    }
-  end
-end
-cid.loadfile=loadcidfile 
-local template="%s-%s-%s.cidmap"
-local function locate(registry,ordering,supplement)
-  local filename=format(template,registry,ordering,supplement)
-  local hashname=lower(filename)
-  local found=cidmap[hashname]
-  if not found then
-    if trace_loading then
-      report_otf("checking cidmap, registry %a, ordering %a, supplement %a, filename %a",registry,ordering,supplement,filename)
-    end
-    local fullname=resolvers.findfile(filename,'cid') or ""
-    if fullname~="" then
-      found=loadcidfile(fullname)
-      if found then
-        if trace_loading then
-          report_otf("using cidmap file %a",filename)
-        end
-        cidmap[hashname]=found
-        found.usedname=file.basename(filename)
-      end
-    end
-  end
-  return found
-end
-function cid.getmap(specification)
-  if not specification then
-    report_otf("invalid cidinfo specification, table expected")
-    return
-  end
-  local registry=specification.registry
-  local ordering=specification.ordering
-  local supplement=specification.supplement
-  local filename=format(registry,ordering,supplement)
-  local found=cidmap[lower(filename)]
-  if found then
-    return found
-  end
-  if trace_loading then
-    report_otf("cidmap needed, registry %a, ordering %a, supplement %a",registry,ordering,supplement)
-  end
-  found=locate(registry,ordering,supplement)
-  if not found then
-    local supnum=tonumber(supplement)
-    local cidnum=nil
-    if supnum<cidmax then
-      for s=supnum+1,cidmax do
-        local c=locate(registry,ordering,s)
-        if c then
-          found,cidnum=c,s
-          break
-        end
-      end
-    end
-    if not found and supnum>0 then
-      for s=supnum-1,0,-1 do
-        local c=locate(registry,ordering,s)
-        if c then
-          found,cidnum=c,s
-          break
-        end
-      end
-    end
-    registry=lower(registry)
-    ordering=lower(ordering)
-    if found and cidnum>0 then
-      for s=0,cidnum-1 do
-        local filename=format(template,registry,ordering,s)
-        if not cidmap[filename] then
-          cidmap[filename]=found
-        end
-      end
-    end
-  end
-  return found
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['font-map']={
-  version=1.001,
-  comment="companion to font-ini.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local tonumber=tonumber
-local match,format,find,concat,gsub,lower=string.match,string.format,string.find,table.concat,string.gsub,string.lower
-local P,R,S,C,Ct,Cc,lpegmatch=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cc,lpeg.match
-local utfbyte=utf.byte
-local floor=math.floor
-local trace_loading=false trackers.register("fonts.loading",function(v) trace_loading=v end)
-local trace_mapping=false trackers.register("fonts.mapping",function(v) trace_unimapping=v end)
-local report_fonts=logs.reporter("fonts","loading") 
-local fonts=fonts or {}
-local mappings=fonts.mappings or {}
-fonts.mappings=mappings
-local function loadlumtable(filename) 
-  local lumname=file.replacesuffix(file.basename(filename),"lum")
-  local lumfile=resolvers.findfile(lumname,"map") or ""
-  if lumfile~="" and lfs.isfile(lumfile) then
-    if trace_loading or trace_mapping then
-      report_fonts("loading map table %a",lumfile)
-    end
-    lumunic=dofile(lumfile)
-    return lumunic,lumfile
-  end
-end
-local hex=R("AF","09")
-local hexfour=(hex*hex*hex*hex)/function(s) return tonumber(s,16) end
-local hexsix=(hex*hex*hex*hex*hex*hex)/function(s) return tonumber(s,16) end
-local dec=(R("09")^1)/tonumber
-local period=P(".")
-local unicode=P("uni")*(hexfour*(period+P(-1))*Cc(false)+Ct(hexfour^1)*Cc(true))
-local ucode=P("u")*(hexsix*(period+P(-1))*Cc(false)+Ct(hexsix^1)*Cc(true))
-local index=P("index")*dec*Cc(false)
-local parser=unicode+ucode+index
-local parsers={}
-local function makenameparser(str)
-  if not str or str=="" then
-    return parser
-  else
-    local p=parsers[str]
-    if not p then
-      p=P(str)*period*dec*Cc(false)
-      parsers[str]=p
-    end
-    return p
-  end
-end
-local function tounicode16(unicode,name)
-  if unicode<0x10000 then
-    return format("%04X",unicode)
-  elseif unicode<0x1FFFFFFFFF then
-    return format("%04X%04X",floor(unicode/1024),unicode%1024+0xDC00)
-  else
-    report_fonts("can't convert %a in %a into tounicode",unicode,name)
-  end
-end
-local function tounicode16sequence(unicodes,name)
-  local t={}
-  for l=1,#unicodes do
-    local unicode=unicodes[l]
-    if unicode<0x10000 then
-      t[l]=format("%04X",unicode)
-    elseif unicode<0x1FFFFFFFFF then
-      t[l]=format("%04X%04X",floor(unicode/1024),unicode%1024+0xDC00)
-    else
-      report_fonts ("can't convert %a in %a into tounicode",unicode,name)
-    end
-  end
-  return concat(t)
-end
-local function fromunicode16(str)
-  if #str==4 then
-    return tonumber(str,16)
-  else
-    local l,r=match(str,"(....)(....)")
-    return (tonumber(l,16))*0x400+tonumber(r,16)-0xDC00
-  end
-end
-mappings.loadlumtable=loadlumtable
-mappings.makenameparser=makenameparser
-mappings.tounicode16=tounicode16
-mappings.tounicode16sequence=tounicode16sequence
-mappings.fromunicode16=fromunicode16
-local ligseparator=P("_")
-local varseparator=P(".")
-local namesplitter=Ct(C((1-ligseparator-varseparator)^1)*(ligseparator*C((1-ligseparator-varseparator)^1))^0)
-function mappings.addtounicode(data,filename)
-  local resources=data.resources
-  local properties=data.properties
-  local descriptions=data.descriptions
-  local unicodes=resources.unicodes
-  if not unicodes then
-    return
-  end
-  unicodes['space']=unicodes['space'] or 32
-  unicodes['hyphen']=unicodes['hyphen'] or 45
-  unicodes['zwj']=unicodes['zwj']  or 0x200D
-  unicodes['zwnj']=unicodes['zwnj']  or 0x200C
-  local private=fonts.constructors.privateoffset
-  local unknown=format("%04X",utfbyte("?"))
-  local unicodevector=fonts.encodings.agl.unicodes 
-  local tounicode={}
-  local originals={}
-  resources.tounicode=tounicode
-  resources.originals=originals
-  local lumunic,uparser,oparser
-  local cidinfo,cidnames,cidcodes,usedmap
-  if false then 
-    lumunic=loadlumtable(filename)
-    lumunic=lumunic and lumunic.tounicode
-  end
-  cidinfo=properties.cidinfo
-  usedmap=cidinfo and fonts.cid.getmap(cidinfo)
-  if usedmap then
-    oparser=usedmap and makenameparser(cidinfo.ordering)
-    cidnames=usedmap.names
-    cidcodes=usedmap.unicodes
-  end
-  uparser=makenameparser()
-  local ns,nl=0,0
-  for unic,glyph in next,descriptions do
-    local index=glyph.index
-    local name=glyph.name
-    if unic==-1 or unic>=private or (unic>=0xE000 and unic<=0xF8FF) or unic==0xFFFE or unic==0xFFFF then
-      local unicode=lumunic and lumunic[name] or unicodevector[name]
-      if unicode then
-        originals[index]=unicode
-        tounicode[index]=tounicode16(unicode,name)
-        ns=ns+1
-      end
-      if (not unicode) and usedmap then
-        local foundindex=lpegmatch(oparser,name)
-        if foundindex then
-          unicode=cidcodes[foundindex] 
-          if unicode then
-            originals[index]=unicode
-            tounicode[index]=tounicode16(unicode,name)
-            ns=ns+1
-          else
-            local reference=cidnames[foundindex] 
-            if reference then
-              local foundindex=lpegmatch(oparser,reference)
-              if foundindex then
-                unicode=cidcodes[foundindex]
-                if unicode then
-                  originals[index]=unicode
-                  tounicode[index]=tounicode16(unicode,name)
-                  ns=ns+1
-                end
-              end
-              if not unicode or unicode=="" then
-                local foundcodes,multiple=lpegmatch(uparser,reference)
-                if foundcodes then
-                  originals[index]=foundcodes
-                  if multiple then
-                    tounicode[index]=tounicode16sequence(foundcodes)
-                    nl=nl+1
-                    unicode=true
-                  else
-                    tounicode[index]=tounicode16(foundcodes,name)
-                    ns=ns+1
-                    unicode=foundcodes
-                  end
-                end
-              end
-            end
-          end
-        end
-      end
-      if not unicode or unicode=="" then
-        local split=lpegmatch(namesplitter,name)
-        local nsplit=split and #split or 0
-        local t,n={},0
-        unicode=true
-        for l=1,nsplit do
-          local base=split[l]
-          local u=unicodes[base] or unicodevector[base]
-          if not u then
-            break
-          elseif type(u)=="table" then
-            if u[1]>=private then
-              unicode=false
-              break
-            end
-            n=n+1
-            t[n]=u[1]
-          else
-            if u>=private then
-              unicode=false
-              break
-            end
-            n=n+1
-            t[n]=u
-          end
-        end
-        if n==0 then
-        elseif n==1 then
-          originals[index]=t[1]
-          tounicode[index]=tounicode16(t[1],name)
-        else
-          originals[index]=t
-          tounicode[index]=tounicode16sequence(t)
-        end
-        nl=nl+1
-      end
-      if not unicode or unicode=="" then
-        local foundcodes,multiple=lpegmatch(uparser,name)
-        if foundcodes then
-          if multiple then
-            originals[index]=foundcodes
-            tounicode[index]=tounicode16sequence(foundcodes,name)
-            nl=nl+1
-            unicode=true
-          else
-            originals[index]=foundcodes
-            tounicode[index]=tounicode16(foundcodes,name)
-            ns=ns+1
-            unicode=foundcodes
-          end
-        end
-      end
-    end
-  end
-  if trace_mapping then
-    for unic,glyph in table.sortedhash(descriptions) do
-      local name=glyph.name
-      local index=glyph.index
-      local toun=tounicode[index]
-      if toun then
-        report_fonts("internal slot %U, name %a, unicode %U, tounicode %a",index,name,unic,toun)
-      else
-        report_fonts("internal slot %U, name %a, unicode %U",index,name,unic)
-      end
-    end
-  end
-  if trace_loading and (ns>0 or nl>0) then
-    report_fonts("%s tounicode entries added, ligatures %s",nl+ns,ns)
-  end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['luatex-fonts-syn']={
-  version=1.001,
-  comment="companion to luatex-*.tex",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-if context then
-  texio.write_nl("fatal error: this module is not for context")
-  os.exit()
-end
-local fonts=fonts
-fonts.names=fonts.names or {}
-fonts.names.version=1.001 
-fonts.names.basename="luatex-fonts-names"
-fonts.names.new_to_old={}
-fonts.names.old_to_new={}
-fonts.names.cache=containers.define("fonts","data",fonts.names.version,true)
-local data,loaded=nil,false
-local fileformats={ "lua","tex","other text files" }
-function fonts.names.reportmissingbase()
-  texio.write("<missing font database, run: mtxrun --script fonts --reload --simple>")
-  fonts.names.reportmissingbase=nil
-end
-function fonts.names.reportmissingname()
-  texio.write("<unknown font in database, run: mtxrun --script fonts --reload --simple>")
-  fonts.names.reportmissingname=nil
-end
-function fonts.names.resolve(name,sub)
-  if not loaded then
-    local basename=fonts.names.basename
-    if basename and basename~="" then
-      data=containers.read(fonts.names.cache,basename)
-      if not data then
-        basename=file.addsuffix(basename,"lua")
-        for i=1,#fileformats do
-          local format=fileformats[i]
-          local foundname=resolvers.findfile(basename,format) or ""
-          if foundname~="" then
-            data=dofile(foundname)
-            texio.write("<font database loaded: ",foundname,">")
-            break
-          end
-        end
-      end
-    end
-    loaded=true
-  end
-  if type(data)=="table" and data.version==fonts.names.version then
-    local condensed=string.gsub(string.lower(name),"[^%a%d]","")
-    local found=data.mappings and data.mappings[condensed]
-    if found then
-      local fontname,filename,subfont=found[1],found[2],found[3]
-      if subfont then
-        return filename,fontname
-      else
-        return filename,false
-      end
-    elseif fonts.names.reportmissingname then
-      fonts.names.reportmissingname()
-      return name,false 
-    end
-  elseif fonts.names.reportmissingbase then
-    fonts.names.reportmissingbase()
-  end
-end
-fonts.names.resolvespec=fonts.names.resolve 
-function fonts.names.getfilename(askedname,suffix) 
-  return ""
-end
-function fonts.names.ignoredfile(filename) 
-  return false 
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['font-tfm']={
-  version=1.001,
-  comment="companion to font-ini.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local next=next
-local match=string.match
-local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end)
-local trace_features=false trackers.register("tfm.features",function(v) trace_features=v end)
-local report_defining=logs.reporter("fonts","defining")
-local report_tfm=logs.reporter("fonts","tfm loading")
-local findbinfile=resolvers.findbinfile
-local fonts=fonts
-local handlers=fonts.handlers
-local readers=fonts.readers
-local constructors=fonts.constructors
-local encodings=fonts.encodings
-local tfm=constructors.newhandler("tfm")
-local tfmfeatures=constructors.newfeatures("tfm")
-local registertfmfeature=tfmfeatures.register
-constructors.resolvevirtualtoo=false 
-fonts.formats.tfm="type1"
-function tfm.setfeatures(tfmdata,features)
-  local okay=constructors.initializefeatures("tfm",tfmdata,features,trace_features,report_tfm)
-  if okay then
-    return constructors.collectprocessors("tfm",tfmdata,features,trace_features,report_tfm)
-  else
-    return {} 
-  end
-end
-local function read_from_tfm(specification)
-  local filename=specification.filename
-  local size=specification.size
-  if trace_defining then
-    report_defining("loading tfm file %a at size %s",filename,size)
-  end
-  local tfmdata=font.read_tfm(filename,size) 
-  if tfmdata then
-    local features=specification.features and specification.features.normal or {}
-    local resources=tfmdata.resources or {}
-    local properties=tfmdata.properties or {}
-    local parameters=tfmdata.parameters or {}
-    local shared=tfmdata.shared   or {}
-    properties.name=tfmdata.name
-    properties.fontname=tfmdata.fontname
-    properties.psname=tfmdata.psname
-    properties.filename=specification.filename
-    parameters.size=size
-    shared.rawdata={}
-    shared.features=features
-    shared.processes=next(features) and tfm.setfeatures(tfmdata,features) or nil
-    tfmdata.properties=properties
-    tfmdata.resources=resources
-    tfmdata.parameters=parameters
-    tfmdata.shared=shared
-    parameters.slant=parameters.slant     or parameters[1] or 0
-    parameters.space=parameters.space     or parameters[2] or 0
-    parameters.space_stretch=parameters.space_stretch or parameters[3] or 0
-    parameters.space_shrink=parameters.space_shrink  or parameters[4] or 0
-    parameters.x_height=parameters.x_height    or parameters[5] or 0
-    parameters.quad=parameters.quad      or parameters[6] or 0
-    parameters.extra_space=parameters.extra_space  or parameters[7] or 0
-    constructors.enhanceparameters(parameters)
-    if constructors.resolvevirtualtoo then
-      fonts.loggers.register(tfmdata,file.suffix(filename),specification) 
-      local vfname=findbinfile(specification.name,'ovf')
-      if vfname and vfname~="" then
-        local vfdata=font.read_vf(vfname,size) 
-        if vfdata then
-          local chars=tfmdata.characters
-          for k,v in next,vfdata.characters do
-            chars[k].commands=v.commands
-          end
-          properties.virtualized=true
-          tfmdata.fonts=vfdata.fonts
-        end
-      end
-    end
-    local allfeatures=tfmdata.shared.features or specification.features.normal
-    constructors.applymanipulators("tfm",tfmdata,allfeatures.normal,trace_features,report_tfm)
-    if not features.encoding then
-      local encoding,filename=match(properties.filename,"^(.-)%-(.*)$") 
-      if filename and encoding and encodings.known and encodings.known[encoding] then
-        features.encoding=encoding
-      end
-    end
-    return tfmdata
-  end
-end
-local function check_tfm(specification,fullname) 
-  local foundname=findbinfile(fullname,'tfm') or ""
-  if foundname=="" then
-    foundname=findbinfile(fullname,'ofm') or "" 
-  end
-  if foundname=="" then
-    foundname=fonts.names.getfilename(fullname,"tfm") or ""
-  end
-  if foundname~="" then
-    specification.filename=foundname
-    specification.format="ofm"
-    return read_from_tfm(specification)
-  elseif trace_defining then
-    report_defining("loading tfm with name %a fails",specification.name)
-  end
-end
-readers.check_tfm=check_tfm
-function readers.tfm(specification)
-  local fullname=specification.filename or ""
-  if fullname=="" then
-    local forced=specification.forced or ""
-    if forced~="" then
-      fullname=specification.name.."."..forced
-    else
-      fullname=specification.name
-    end
-  end
-  return check_tfm(specification,fullname)
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['font-afm']={
-  version=1.001,
-  comment="companion to font-ini.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local fonts,logs,trackers,containers,resolvers=fonts,logs,trackers,containers,resolvers
-local next,type,tonumber=next,type,tonumber
-local format,match,gmatch,lower,gsub,strip=string.format,string.match,string.gmatch,string.lower,string.gsub,string.strip
-local abs=math.abs
-local P,S,C,R,lpegmatch,patterns=lpeg.P,lpeg.S,lpeg.C,lpeg.R,lpeg.match,lpeg.patterns
-local derivetable=table.derive
-local trace_features=false trackers.register("afm.features",function(v) trace_features=v end)
-local trace_indexing=false trackers.register("afm.indexing",function(v) trace_indexing=v end)
-local trace_loading=false trackers.register("afm.loading",function(v) trace_loading=v end)
-local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end)
-local report_afm=logs.reporter("fonts","afm loading")
-local findbinfile=resolvers.findbinfile
-local definers=fonts.definers
-local readers=fonts.readers
-local constructors=fonts.constructors
-local afm=constructors.newhandler("afm")
-local pfb=constructors.newhandler("pfb")
-local afmfeatures=constructors.newfeatures("afm")
-local registerafmfeature=afmfeatures.register
-afm.version=1.410 
-afm.cache=containers.define("fonts","afm",afm.version,true)
-afm.autoprefixed=true 
-afm.helpdata={} 
-afm.syncspace=true 
-afm.addligatures=true 
-afm.addtexligatures=true 
-afm.addkerns=true 
-local applyruntimefixes=fonts.treatments and fonts.treatments.applyfixes
-local function setmode(tfmdata,value)
-  if value then
-    tfmdata.properties.mode=lower(value)
-  end
-end
-registerafmfeature {
-  name="mode",
-  description="mode",
-  initializers={
-    base=setmode,
-    node=setmode,
-  }
-}
-local comment=P("Comment")
-local spacing=patterns.spacer 
-local lineend=patterns.newline 
-local words=C((1-lineend)^1)
-local number=C((R("09")+S("."))^1)/tonumber*spacing^0
-local data=lpeg.Carg(1)
-local pattern=(
-  comment*spacing*(
-      data*(
-        ("CODINGSCHEME"*spacing*words                   )/function(fd,a)                   end+("DESIGNSIZE"*spacing*number*words               )/function(fd,a)   fd[ 1]=a    end+("CHECKSUM"*spacing*number*words               )/function(fd,a)   fd[ 2]=a    end+("SPACE"*spacing*number*"plus"*number*"minus"*number)/function(fd,a,b,c) fd[ 3],fd[ 4],fd[ 5]=a,b,c end+("QUAD"*spacing*number                   )/function(fd,a)   fd[ 6]=a    end+("EXTRASPACE"*spacing*number                   )/function(fd,a)   fd[ 7]=a    end+("NUM"*spacing*number*number*number          )/function(fd,a,b,c) fd[ 8],fd[ 9],fd[10]=a,b,c end+("DENOM"*spacing*number*number              )/function(fd,a,b ) fd[11],fd[12]=a,b  end+("SUP"*spacing*number*number*number          )/function(fd,a,b,c) fd[13],fd[14],fd[15]=a,b,c end+("SUB"*spacing*number*number              )/function(fd,a,b)  fd[16],fd[17]=a,b  end+("SUPDROP"*spacing*number                   )/function(fd,a)   fd[18]=a    end+("SUBDROP"*spacing*number                   )/function(fd,a)   fd[19]=a    end+("DELIM"*spacing*number*number              )/function(fd,a,b)  fd[20],fd[21]=a,b  end+("AXISHEIGHT"*spacing*number                   )/function(fd,a)   fd[22]=a    end
-      )+(1-lineend)^0
-    )+(1-comment)^1
-)^0
-local function scan_comment(str)
-  local fd={}
-  lpegmatch(pattern,str,1,fd)
-  return fd
-end
-local keys={}
-function keys.FontName  (data,line) data.metadata.fontname=strip  (line) 
-                   data.metadata.fullname=strip  (line) end
-function keys.ItalicAngle (data,line) data.metadata.italicangle=tonumber (line) end
-function keys.IsFixedPitch(data,line) data.metadata.isfixedpitch=toboolean(line,true) end
-function keys.CharWidth  (data,line) data.metadata.charwidth=tonumber (line) end
-function keys.XHeight   (data,line) data.metadata.xheight=tonumber (line) end
-function keys.Descender  (data,line) data.metadata.descender=tonumber (line) end
-function keys.Ascender  (data,line) data.metadata.ascender=tonumber (line) end
-function keys.Comment   (data,line)
-  line=lower(line)
-  local designsize=match(line,"designsize[^%d]*(%d+)")
-  if designsize then data.metadata.designsize=tonumber(designsize) end
-end
-local function get_charmetrics(data,charmetrics,vector)
-  local characters=data.characters
-  local chr,ind={},0
-  for k,v in gmatch(charmetrics,"([%a]+) +(.-) *;") do
-    if k=='C' then
-      v=tonumber(v)
-      if v<0 then
-        ind=ind+1 
-      else
-        ind=v
-      end
-      chr={
-        index=ind
-      }
-    elseif k=='WX' then
-      chr.width=tonumber(v)
-    elseif k=='N' then
-      characters[v]=chr
-    elseif k=='B' then
-      local llx,lly,urx,ury=match(v,"^ *(.-) +(.-) +(.-) +(.-)$")
-      chr.boundingbox={ tonumber(llx),tonumber(lly),tonumber(urx),tonumber(ury) }
-    elseif k=='L' then
-      local plus,becomes=match(v,"^(.-) +(.-)$")
-      local ligatures=chr.ligatures
-      if ligatures then
-        ligatures[plus]=becomes
-      else
-        chr.ligatures={ [plus]=becomes }
-      end
-    end
-  end
-end
-local function get_kernpairs(data,kernpairs)
-  local characters=data.characters
-  for one,two,value in gmatch(kernpairs,"KPX +(.-) +(.-) +(.-)\n") do
-    local chr=characters[one]
-    if chr then
-      local kerns=chr.kerns
-      if kerns then
-        kerns[two]=tonumber(value)
-      else
-        chr.kerns={ [two]=tonumber(value) }
-      end
-    end
-  end
-end
-local function get_variables(data,fontmetrics)
-  for key,rest in gmatch(fontmetrics,"(%a+) *(.-)[\n\r]") do
-    local keyhandler=keys[key]
-    if keyhandler then
-      keyhandler(data,rest)
-    end
-  end
-end
-local function get_indexes(data,pfbname)
-  data.resources.filename=resolvers.unresolve(pfbname) 
-  local pfbblob=fontloader.open(pfbname)
-  if pfbblob then
-    local characters=data.characters
-    local pfbdata=fontloader.to_table(pfbblob)
-    if pfbdata then
-      local glyphs=pfbdata.glyphs
-      if glyphs then
-        if trace_loading then
-          report_afm("getting index data from %a",pfbname)
-        end
-        for index,glyph in next,glyphs do
-          local name=glyph.name
-          if name then
-            local char=characters[name]
-            if char then
-              if trace_indexing then
-                report_afm("glyph %a has index %a",name,index)
-              end
-              char.index=index
-            end
-          end
-        end
-      elseif trace_loading then
-        report_afm("no glyph data in pfb file %a",pfbname)
-      end
-    elseif trace_loading then
-      report_afm("no data in pfb file %a",pfbname)
-    end
-    fontloader.close(pfbblob)
-  elseif trace_loading then
-    report_afm("invalid pfb file %a",pfbname)
-  end
-end
-local function readafm(filename)
-  local ok,afmblob,size=resolvers.loadbinfile(filename) 
-  if ok and afmblob then
-    local data={
-      resources={
-        filename=resolvers.unresolve(filename),
-        version=afm.version,
-        creator="context mkiv",
-      },
-      properties={
-        hasitalics=false,
-      },
-      goodies={},
-      metadata={
-        filename=file.removesuffix(file.basename(filename))
-      },
-      characters={
-      },
-      descriptions={
-      },
-    }
-    afmblob=gsub(afmblob,"StartCharMetrics(.-)EndCharMetrics",function(charmetrics)
-      if trace_loading then
-        report_afm("loading char metrics")
-      end
-      get_charmetrics(data,charmetrics,vector)
-      return ""
-    end)
-    afmblob=gsub(afmblob,"StartKernPairs(.-)EndKernPairs",function(kernpairs)
-      if trace_loading then
-        report_afm("loading kern pairs")
-      end
-      get_kernpairs(data,kernpairs)
-      return ""
-    end)
-    afmblob=gsub(afmblob,"StartFontMetrics%s+([%d%.]+)(.-)EndFontMetrics",function(version,fontmetrics)
-      if trace_loading then
-        report_afm("loading variables")
-      end
-      data.afmversion=version
-      get_variables(data,fontmetrics)
-      data.fontdimens=scan_comment(fontmetrics) 
-      return ""
-    end)
-    return data
-  else
-    if trace_loading then
-      report_afm("no valid afm file %a",filename)
-    end
-    return nil
-  end
-end
-local addkerns,addligatures,addtexligatures,unify,normalize 
-function afm.load(filename)
-  filename=resolvers.findfile(filename,'afm') or ""
-  if filename~="" and not fonts.names.ignoredfile(filename) then
-    local name=file.removesuffix(file.basename(filename))
-    local data=containers.read(afm.cache,name)
-    local attr=lfs.attributes(filename)
-    local size,time=attr.size or 0,attr.modification or 0
-    local pfbfile=file.replacesuffix(name,"pfb")
-    local pfbname=resolvers.findfile(pfbfile,"pfb") or ""
-    if pfbname=="" then
-      pfbname=resolvers.findfile(file.basename(pfbfile),"pfb") or ""
-    end
-    local pfbsize,pfbtime=0,0
-    if pfbname~="" then
-      local attr=lfs.attributes(pfbname)
-      pfbsize=attr.size or 0
-      pfbtime=attr.modification or 0
-    end
-    if not data or data.size~=size or data.time~=time or data.pfbsize~=pfbsize or data.pfbtime~=pfbtime then
-      report_afm("reading %a",filename)
-      data=readafm(filename)
-      if data then
-        if pfbname~="" then
-          get_indexes(data,pfbname)
-        elseif trace_loading then
-          report_afm("no pfb file for %a",filename)
-        end
-        report_afm("unifying %a",filename)
-        unify(data,filename)
-        if afm.addligatures then
-          report_afm("add ligatures")
-          addligatures(data)
-        end
-        if afm.addtexligatures then
-          report_afm("add tex ligatures")
-          addtexligatures(data)
-        end
-        if afm.addkerns then
-          report_afm("add extra kerns")
-          addkerns(data)
-        end
-        normalize(data)
-        report_afm("add tounicode data")
-        fonts.mappings.addtounicode(data,filename)
-        data.size=size
-        data.time=time
-        data.pfbsize=pfbsize
-        data.pfbtime=pfbtime
-        report_afm("saving %a in cache",name)
-        data=containers.write(afm.cache,name,data)
-        data=containers.read(afm.cache,name)
-      end
-      if applyruntimefixes and data then
-        applyruntimefixes(filename,data)
-      end
-    end
-    return data
-  else
-    return nil
-  end
-end
-local uparser=fonts.mappings.makenameparser()
-unify=function(data,filename)
-  local unicodevector=fonts.encodings.agl.unicodes 
-  local unicodes,names={},{}
-  local private=constructors.privateoffset
-  local descriptions=data.descriptions
-  for name,blob in next,data.characters do
-    local code=unicodevector[name] 
-    if not code then
-      code=lpegmatch(uparser,name)
-      if not code then
-        code=private
-        private=private+1
-        report_afm("assigning private slot %U for unknown glyph name %a",code,name)
-      end
-    end
-    local index=blob.index
-    unicodes[name]=code
-    names[name]=index
-    blob.name=name
-    descriptions[code]={
-      boundingbox=blob.boundingbox,
-      width=blob.width,
-      kerns=blob.kerns,
-      index=index,
-      name=name,
-    }
-  end
-  for unicode,description in next,descriptions do
-    local kerns=description.kerns
-    if kerns then
-      local krn={}
-      for name,kern in next,kerns do
-        local unicode=unicodes[name]
-        if unicode then
-          krn[unicode]=kern
-        else
-        end
-      end
-      description.kerns=krn
-    end
-  end
-  data.characters=nil
-  local resources=data.resources
-  local filename=resources.filename or file.removesuffix(file.basename(filename))
-  resources.filename=resolvers.unresolve(filename) 
-  resources.unicodes=unicodes 
-  resources.marks={} 
-  resources.names=names 
-  resources.private=private
-end
-normalize=function(data)
-end
-local addthem=function(rawdata,ligatures)
-  if ligatures then
-    local descriptions=rawdata.descriptions
-    local resources=rawdata.resources
-    local unicodes=resources.unicodes
-    local names=resources.names
-    for ligname,ligdata in next,ligatures do
-      local one=descriptions[unicodes[ligname]]
-      if one then
-        for _,pair in next,ligdata do
-          local two,three=unicodes[pair[1]],unicodes[pair[2]]
-          if two and three then
-            local ol=one.ligatures
-            if ol then
-              if not ol[two] then
-                ol[two]=three
-              end
-            else
-              one.ligatures={ [two]=three }
-            end
-          end
-        end
-      end
-    end
-  end
-end
-addligatures=function(rawdata) addthem(rawdata,afm.helpdata.ligatures  ) end
-addtexligatures=function(rawdata) addthem(rawdata,afm.helpdata.texligatures) end
-addkerns=function(rawdata) 
-  local descriptions=rawdata.descriptions
-  local resources=rawdata.resources
-  local unicodes=resources.unicodes
-  local function do_it_left(what)
-    if what then
-      for unicode,description in next,descriptions do
-        local kerns=description.kerns
-        if kerns then
-          local extrakerns
-          for complex,simple in next,what do
-            complex=unicodes[complex]
-            simple=unicodes[simple]
-            if complex and simple then
-              local ks=kerns[simple]
-              if ks and not kerns[complex] then
-                if extrakerns then
-                  extrakerns[complex]=ks
-                else
-                  extrakerns={ [complex]=ks }
-                end
-              end
-            end
-          end
-          if extrakerns then
-            description.extrakerns=extrakerns
-          end
-        end
-      end
-    end
-  end
-  local function do_it_copy(what)
-    if what then
-      for complex,simple in next,what do
-        complex=unicodes[complex]
-        simple=unicodes[simple]
-        if complex and simple then
-          local complexdescription=descriptions[complex]
-          if complexdescription then 
-            local simpledescription=descriptions[complex]
-            if simpledescription then
-              local extrakerns
-              local kerns=simpledescription.kerns
-              if kerns then
-                for unicode,kern in next,kerns do
-                  if extrakerns then
-                    extrakerns[unicode]=kern
-                  else
-                    extrakerns={ [unicode]=kern }
-                  end
-                end
-              end
-              local extrakerns=simpledescription.extrakerns
-              if extrakerns then
-                for unicode,kern in next,extrakerns do
-                  if extrakerns then
-                    extrakerns[unicode]=kern
-                  else
-                    extrakerns={ [unicode]=kern }
-                  end
-                end
-              end
-              if extrakerns then
-                complexdescription.extrakerns=extrakerns
-              end
-            end
-          end
-        end
-      end
-    end
-  end
-  do_it_left(afm.helpdata.leftkerned)
-  do_it_left(afm.helpdata.bothkerned)
-  do_it_copy(afm.helpdata.bothkerned)
-  do_it_copy(afm.helpdata.rightkerned)
-end
-local function adddimensions(data) 
-  if data then
-    for unicode,description in next,data.descriptions do
-      local bb=description.boundingbox
-      if bb then
-        local ht,dp=bb[4],-bb[2]
-        if ht==0 or ht<0 then
-        else
-          description.height=ht
-        end
-        if dp==0 or dp<0 then
-        else
-          description.depth=dp
-        end
-      end
-    end
-  end
-end
-local function copytotfm(data)
-  if data and data.descriptions then
-    local metadata=data.metadata
-    local resources=data.resources
-    local properties=derivetable(data.properties)
-    local descriptions=derivetable(data.descriptions)
-    local goodies=derivetable(data.goodies)
-    local characters={}
-    local parameters={}
-    local unicodes=resources.unicodes
-    for unicode,description in next,data.descriptions do 
-      characters[unicode]={}
-    end
-    local filename=constructors.checkedfilename(resources)
-    local fontname=metadata.fontname or metadata.fullname
-    local fullname=metadata.fullname or metadata.fontname
-    local endash=unicodes['space']
-    local emdash=unicodes['emdash']
-    local spacer="space"
-    local spaceunits=500
-    local monospaced=metadata.isfixedpitch
-    local charwidth=metadata.charwidth
-    local italicangle=metadata.italicangle
-    local charxheight=metadata.xheight and metadata.xheight>0 and metadata.xheight
-    properties.monospaced=monospaced
-    parameters.italicangle=italicangle
-    parameters.charwidth=charwidth
-    parameters.charxheight=charxheight
-    if properties.monospaced then
-      if descriptions[endash] then
-        spaceunits,spacer=descriptions[endash].width,"space"
-      end
-      if not spaceunits and descriptions[emdash] then
-        spaceunits,spacer=descriptions[emdash].width,"emdash"
-      end
-      if not spaceunits and charwidth then
-        spaceunits,spacer=charwidth,"charwidth"
-      end
-    else
-      if descriptions[endash] then
-        spaceunits,spacer=descriptions[endash].width,"space"
-      end
-      if not spaceunits and charwidth then
-        spaceunits,spacer=charwidth,"charwidth"
-      end
-    end
-    spaceunits=tonumber(spaceunits)
-    if spaceunits<200 then
-    end
-    parameters.slant=0
-    parameters.space=spaceunits
-    parameters.space_stretch=500
-    parameters.space_shrink=333
-    parameters.x_height=400
-    parameters.quad=1000
-    if italicangle and italicangle~=0 then
-      parameters.italicangle=italicangle
-      parameters.italicfactor=math.cos(math.rad(90+italicangle))
-      parameters.slant=- math.tan(italicangle*math.pi/180)
-    end
-    if monospaced then
-      parameters.space_stretch=0
-      parameters.space_shrink=0
-    elseif afm.syncspace then
-      parameters.space_stretch=spaceunits/2
-      parameters.space_shrink=spaceunits/3
-    end
-    parameters.extra_space=parameters.space_shrink
-    if charxheight then
-      parameters.x_height=charxheight
-    else
-      local x=unicodes['x']
-      if x then
-        local x=descriptions[x]
-        if x then
-          parameters.x_height=x.height
-        end
-      end
-    end
-    local fd=data.fontdimens
-    if fd and fd[8] and fd[9] and fd[10] then 
-      for k,v in next,fd do
-        parameters[k]=v
-      end
-    end
-    parameters.designsize=(metadata.designsize or 10)*65536
-    parameters.ascender=abs(metadata.ascender or 0)
-    parameters.descender=abs(metadata.descender or 0)
-    parameters.units=1000
-    properties.spacer=spacer
-    properties.encodingbytes=2
-    properties.format=fonts.formats[filename] or "type1"
-    properties.filename=filename
-    properties.fontname=fontname
-    properties.fullname=fullname
-    properties.psname=fullname
-    properties.name=filename or fullname or fontname
-    if next(characters) then
-      return {
-        characters=characters,
-        descriptions=descriptions,
-        parameters=parameters,
-        resources=resources,
-        properties=properties,
-        goodies=goodies,
-      }
-    end
-  end
-  return nil
-end
-function afm.setfeatures(tfmdata,features)
-  local okay=constructors.initializefeatures("afm",tfmdata,features,trace_features,report_afm)
-  if okay then
-    return constructors.collectprocessors("afm",tfmdata,features,trace_features,report_afm)
-  else
-    return {} 
-  end
-end
-local function checkfeatures(specification)
-end
-local function afmtotfm(specification)
-  local afmname=specification.filename or specification.name
-  if specification.forced=="afm" or specification.format=="afm" then 
-    if trace_loading then
-      report_afm("forcing afm format for %a",afmname)
-    end
-  else
-    local tfmname=findbinfile(afmname,"ofm") or ""
-    if tfmname~="" then
-      if trace_loading then
-        report_afm("fallback from afm to tfm for %a",afmname)
-      end
-      return 
-    end
-  end
-  if afmname~="" then
-    local features=constructors.checkedfeatures("afm",specification.features.normal)
-    specification.features.normal=features
-    constructors.hashinstance(specification,true)
-    specification=definers.resolve(specification) 
-    local cache_id=specification.hash
-    local tfmdata=containers.read(constructors.cache,cache_id) 
-    if not tfmdata then
-      local rawdata=afm.load(afmname)
-      if rawdata and next(rawdata) then
-        adddimensions(rawdata)
-        tfmdata=copytotfm(rawdata)
-        if tfmdata and next(tfmdata) then
-          local shared=tfmdata.shared
-          if not shared then
-            shared={}
-            tfmdata.shared=shared
-          end
-          shared.rawdata=rawdata
-          shared.features=features
-          shared.processes=afm.setfeatures(tfmdata,features)
-        end
-      elseif trace_loading then
-        report_afm("no (valid) afm file found with name %a",afmname)
-      end
-      tfmdata=containers.write(constructors.cache,cache_id,tfmdata)
-    end
-    return tfmdata
-  end
-end
-local function read_from_afm(specification)
-  local tfmdata=afmtotfm(specification)
-  if tfmdata then
-    tfmdata.properties.name=specification.name
-    tfmdata=constructors.scale(tfmdata,specification)
-    local allfeatures=tfmdata.shared.features or specification.features.normal
-    constructors.applymanipulators("afm",tfmdata,allfeatures,trace_features,report_afm)
-    fonts.loggers.register(tfmdata,'afm',specification)
-  end
-  return tfmdata
-end
-local function prepareligatures(tfmdata,ligatures,value)
-  if value then
-    local descriptions=tfmdata.descriptions
-    for unicode,character in next,tfmdata.characters do
-      local description=descriptions[unicode]
-      local dligatures=description.ligatures
-      if dligatures then
-        local cligatures=character.ligatures
-        if not cligatures then
-          cligatures={}
-          character.ligatures=cligatures
-        end
-        for unicode,ligature in next,dligatures do
-          cligatures[unicode]={
-            char=ligature,
-            type=0
-          }
-        end
-      end
-    end
-  end
-end
-local function preparekerns(tfmdata,kerns,value)
-  if value then
-    local rawdata=tfmdata.shared.rawdata
-    local resources=rawdata.resources
-    local unicodes=resources.unicodes
-    local descriptions=tfmdata.descriptions
-    for u,chr in next,tfmdata.characters do
-      local d=descriptions[u]
-      local newkerns=d[kerns]
-      if newkerns then
-        local kerns=chr.kerns
-        if not kerns then
-          kerns={}
-          chr.kerns=kerns
-        end
-        for k,v in next,newkerns do
-          local uk=unicodes[k]
-          if uk then
-            kerns[uk]=v
-          end
-        end
-      end
-    end
-  end
-end
-local list={
-  [0x0027]=0x2019,
-}
-local function texreplacements(tfmdata,value)
-  local descriptions=tfmdata.descriptions
-  local characters=tfmdata.characters
-  for k,v in next,list do
-    characters [k]=characters [v] 
-    descriptions[k]=descriptions[v] 
-  end
-end
-local function ligatures  (tfmdata,value) prepareligatures(tfmdata,'ligatures',value) end
-local function texligatures(tfmdata,value) prepareligatures(tfmdata,'texligatures',value) end
-local function kerns    (tfmdata,value) preparekerns  (tfmdata,'kerns',value) end
-local function extrakerns (tfmdata,value) preparekerns  (tfmdata,'extrakerns',value) end
-registerafmfeature {
-  name="liga",
-  description="traditional ligatures",
-  initializers={
-    base=ligatures,
-    node=ligatures,
-  }
-}
-registerafmfeature {
-  name="kern",
-  description="intercharacter kerning",
-  initializers={
-    base=kerns,
-    node=kerns,
-  }
-}
-registerafmfeature {
-  name="extrakerns",
-  description="additional intercharacter kerning",
-  initializers={
-    base=extrakerns,
-    node=extrakerns,
-  }
-}
-registerafmfeature {
-  name='tlig',
-  description='tex ligatures',
-  initializers={
-    base=texligatures,
-    node=texligatures,
-  }
-}
-registerafmfeature {
-  name='trep',
-  description='tex replacements',
-  initializers={
-    base=texreplacements,
-    node=texreplacements,
-  }
-}
-local check_tfm=readers.check_tfm
-fonts.formats.afm="type1"
-fonts.formats.pfb="type1"
-local function check_afm(specification,fullname)
-  local foundname=findbinfile(fullname,'afm') or "" 
-  if foundname=="" then
-    foundname=fonts.names.getfilename(fullname,"afm") or ""
-  end
-  if foundname=="" and afm.autoprefixed then
-    local encoding,shortname=match(fullname,"^(.-)%-(.*)$") 
-    if encoding and shortname and fonts.encodings.known[encoding] then
-      shortname=findbinfile(shortname,'afm') or "" 
-      if shortname~="" then
-        foundname=shortname
-        if trace_defining then
-          report_afm("stripping encoding prefix from filename %a",afmname)
-        end
-      end
-    end
-  end
-  if foundname~="" then
-    specification.filename=foundname
-    specification.format="afm"
-    return read_from_afm(specification)
-  end
-end
-function readers.afm(specification,method)
-  local fullname,tfmdata=specification.filename or "",nil
-  if fullname=="" then
-    local forced=specification.forced or ""
-    if forced~="" then
-      tfmdata=check_afm(specification,specification.name.."."..forced)
-    end
-    if not tfmdata then
-      method=method or definers.method or "afm or tfm"
-      if method=="tfm" then
-        tfmdata=check_tfm(specification,specification.name)
-      elseif method=="afm" then
-        tfmdata=check_afm(specification,specification.name)
-      elseif method=="tfm or afm" then
-        tfmdata=check_tfm(specification,specification.name) or check_afm(specification,specification.name)
-      else 
-        tfmdata=check_afm(specification,specification.name) or check_tfm(specification,specification.name)
-      end
-    end
-  else
-    tfmdata=check_afm(specification,fullname)
-  end
-  return tfmdata
-end
-function readers.pfb(specification,method) 
-  local original=specification.specification
-  if trace_defining then
-    report_afm("using afm reader for %a",original)
-  end
-  specification.specification=gsub(original,"%.pfb",".afm")
-  specification.forced="afm"
-  return readers.afm(specification,method)
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['font-afk']={
-  version=1.001,
-  comment="companion to font-afm.lua",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files",
-  dataonly=true,
-}
-local allocate=utilities.storage.allocate
-fonts.handlers.afm.helpdata={
-  ligatures=allocate { 
-    ['f']={ 
-      { 'f','ff' },
-      { 'i','fi' },
-      { 'l','fl' },
-    },
-    ['ff']={
-      { 'i','ffi' }
-    },
-    ['fi']={
-      { 'i','fii' }
-    },
-    ['fl']={
-      { 'i','fli' }
-    },
-    ['s']={
-      { 't','st' }
-    },
-    ['i']={
-      { 'j','ij' }
-    },
-  },
-  texligatures=allocate {
-    ['quoteleft']={
-      { 'quoteleft','quotedblleft' }
-    },
-    ['quoteright']={
-      { 'quoteright','quotedblright' }
-    },
-    ['hyphen']={
-      { 'hyphen','endash' }
-    },
-    ['endash']={
-      { 'hyphen','emdash' }
-    }
-  },
-  leftkerned=allocate {
-    AEligature="A",aeligature="a",
-    OEligature="O",oeligature="o",
-    IJligature="I",ijligature="i",
-    AE="A",ae="a",
-    OE="O",oe="o",
-    IJ="I",ij="i",
-    Ssharp="S",ssharp="s",
-  },
-  rightkerned=allocate {
-    AEligature="E",aeligature="e",
-    OEligature="E",oeligature="e",
-    IJligature="J",ijligature="j",
-    AE="E",ae="e",
-    OE="E",oe="e",
-    IJ="J",ij="j",
-    Ssharp="S",ssharp="s",
-  },
-  bothkerned=allocate {
-    Acircumflex="A",acircumflex="a",
-    Ccircumflex="C",ccircumflex="c",
-    Ecircumflex="E",ecircumflex="e",
-    Gcircumflex="G",gcircumflex="g",
-    Hcircumflex="H",hcircumflex="h",
-    Icircumflex="I",icircumflex="i",
-    Jcircumflex="J",jcircumflex="j",
-    Ocircumflex="O",ocircumflex="o",
-    Scircumflex="S",scircumflex="s",
-    Ucircumflex="U",ucircumflex="u",
-    Wcircumflex="W",wcircumflex="w",
-    Ycircumflex="Y",ycircumflex="y",
-    Agrave="A",agrave="a",
-    Egrave="E",egrave="e",
-    Igrave="I",igrave="i",
-    Ograve="O",ograve="o",
-    Ugrave="U",ugrave="u",
-    Ygrave="Y",ygrave="y",
-    Atilde="A",atilde="a",
-    Itilde="I",itilde="i",
-    Otilde="O",otilde="o",
-    Utilde="U",utilde="u",
-    Ntilde="N",ntilde="n",
-    Adiaeresis="A",adiaeresis="a",Adieresis="A",adieresis="a",
-    Ediaeresis="E",ediaeresis="e",Edieresis="E",edieresis="e",
-    Idiaeresis="I",idiaeresis="i",Idieresis="I",idieresis="i",
-    Odiaeresis="O",odiaeresis="o",Odieresis="O",odieresis="o",
-    Udiaeresis="U",udiaeresis="u",Udieresis="U",udieresis="u",
-    Ydiaeresis="Y",ydiaeresis="y",Ydieresis="Y",ydieresis="y",
-    Aacute="A",aacute="a",
-    Cacute="C",cacute="c",
-    Eacute="E",eacute="e",
-    Iacute="I",iacute="i",
-    Lacute="L",lacute="l",
-    Nacute="N",nacute="n",
-    Oacute="O",oacute="o",
-    Racute="R",racute="r",
-    Sacute="S",sacute="s",
-    Uacute="U",uacute="u",
-    Yacute="Y",yacute="y",
-    Zacute="Z",zacute="z",
-    Dstroke="D",dstroke="d",
-    Hstroke="H",hstroke="h",
-    Tstroke="T",tstroke="t",
-    Cdotaccent="C",cdotaccent="c",
-    Edotaccent="E",edotaccent="e",
-    Gdotaccent="G",gdotaccent="g",
-    Idotaccent="I",idotaccent="i",
-    Zdotaccent="Z",zdotaccent="z",
-    Amacron="A",amacron="a",
-    Emacron="E",emacron="e",
-    Imacron="I",imacron="i",
-    Omacron="O",omacron="o",
-    Umacron="U",umacron="u",
-    Ccedilla="C",ccedilla="c",
-    Kcedilla="K",kcedilla="k",
-    Lcedilla="L",lcedilla="l",
-    Ncedilla="N",ncedilla="n",
-    Rcedilla="R",rcedilla="r",
-    Scedilla="S",scedilla="s",
-    Tcedilla="T",tcedilla="t",
-    Ohungarumlaut="O",ohungarumlaut="o",
-    Uhungarumlaut="U",uhungarumlaut="u",
-    Aogonek="A",aogonek="a",
-    Eogonek="E",eogonek="e",
-    Iogonek="I",iogonek="i",
-    Uogonek="U",uogonek="u",
-    Aring="A",aring="a",
-    Uring="U",uring="u",
-    Abreve="A",abreve="a",
-    Ebreve="E",ebreve="e",
-    Gbreve="G",gbreve="g",
-    Ibreve="I",ibreve="i",
-    Obreve="O",obreve="o",
-    Ubreve="U",ubreve="u",
-    Ccaron="C",ccaron="c",
-    Dcaron="D",dcaron="d",
-    Ecaron="E",ecaron="e",
-    Lcaron="L",lcaron="l",
-    Ncaron="N",ncaron="n",
-    Rcaron="R",rcaron="r",
-    Scaron="S",scaron="s",
-    Tcaron="T",tcaron="t",
-    Zcaron="Z",zcaron="z",
-    dotlessI="I",dotlessi="i",
-    dotlessJ="J",dotlessj="j",
-    AEligature="AE",aeligature="ae",AE="AE",ae="ae",
-    OEligature="OE",oeligature="oe",OE="OE",oe="oe",
-    IJligature="IJ",ijligature="ij",IJ="IJ",ij="ij",
-    Lstroke="L",lstroke="l",Lslash="L",lslash="l",
-    Ostroke="O",ostroke="o",Oslash="O",oslash="o",
-    Ssharp="SS",ssharp="ss",
-    Aumlaut="A",aumlaut="a",
-    Eumlaut="E",eumlaut="e",
-    Iumlaut="I",iumlaut="i",
-    Oumlaut="O",oumlaut="o",
-    Uumlaut="U",uumlaut="u",
-  }
-}
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['luatex-fonts-tfm']={
-  version=1.001,
-  comment="companion to luatex-*.tex",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-if context then
-  texio.write_nl("fatal error: this module is not for context")
-  os.exit()
-end
-local fonts=fonts
-local tfm={}
-fonts.handlers.tfm=tfm
-fonts.formats.tfm="type1" 
-function fonts.readers.tfm(specification)
-  local fullname=specification.filename or ""
-  if fullname=="" then
-    local forced=specification.forced or ""
-    if forced~="" then
-      fullname=specification.name.."."..forced
-    else
-      fullname=specification.name
-    end
-  end
-  local foundname=resolvers.findbinfile(fullname,'tfm') or ""
-  if foundname=="" then
-    foundname=resolvers.findbinfile(fullname,'ofm') or ""
-  end
-  if foundname~="" then
-    specification.filename=foundname
-    specification.format="ofm"
-    return font.read_tfm(specification.filename,specification.size)
-  end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['font-oti']={
-  version=1.001,
-  comment="companion to font-ini.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local lower=string.lower
-local fonts=fonts
-local constructors=fonts.constructors
-local otf=constructors.newhandler("otf")
-local otffeatures=constructors.newfeatures("otf")
-local otftables=otf.tables
-local registerotffeature=otffeatures.register
-local allocate=utilities.storage.allocate
-registerotffeature {
-  name="features",
-  description="initialization of feature handler",
-  default=true,
-}
-local function setmode(tfmdata,value)
-  if value then
-    tfmdata.properties.mode=lower(value)
-  end
-end
-local function setlanguage(tfmdata,value)
-  if value then
-    local cleanvalue=lower(value)
-    local languages=otftables and otftables.languages
-    local properties=tfmdata.properties
-    if not languages then
-      properties.language=cleanvalue
-    elseif languages[value] then
-      properties.language=cleanvalue
-    else
-      properties.language="dflt"
-    end
-  end
-end
-local function setscript(tfmdata,value)
-  if value then
-    local cleanvalue=lower(value)
-    local scripts=otftables and otftables.scripts
-    local properties=tfmdata.properties
-    if not scripts then
-      properties.script=cleanvalue
-    elseif scripts[value] then
-      properties.script=cleanvalue
-    else
-      properties.script="dflt"
-    end
-  end
-end
-registerotffeature {
-  name="mode",
-  description="mode",
-  initializers={
-    base=setmode,
-    node=setmode,
-  }
-}
-registerotffeature {
-  name="language",
-  description="language",
-  initializers={
-    base=setlanguage,
-    node=setlanguage,
-  }
-}
-registerotffeature {
-  name="script",
-  description="script",
-  initializers={
-    base=setscript,
-    node=setscript,
-  }
-}
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['font-otf']={
-  version=1.001,
-  comment="companion to font-ini.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local utfbyte=utf.byte
-local format,gmatch,gsub,find,match,lower,strip=string.format,string.gmatch,string.gsub,string.find,string.match,string.lower,string.strip
-local type,next,tonumber,tostring=type,next,tonumber,tostring
-local abs=math.abs
-local insert=table.insert
-local lpegmatch=lpeg.match
-local reversed,concat,remove,sortedkeys=table.reversed,table.concat,table.remove,table.sortedkeys
-local ioflush=io.flush
-local fastcopy,tohash,derivetable=table.fastcopy,table.tohash,table.derive
-local formatters=string.formatters
-local allocate=utilities.storage.allocate
-local registertracker=trackers.register
-local registerdirective=directives.register
-local starttiming=statistics.starttiming
-local stoptiming=statistics.stoptiming
-local elapsedtime=statistics.elapsedtime
-local findbinfile=resolvers.findbinfile
-local trace_private=false registertracker("otf.private",function(v) trace_private=v end)
-local trace_loading=false registertracker("otf.loading",function(v) trace_loading=v end)
-local trace_features=false registertracker("otf.features",function(v) trace_features=v end)
-local trace_dynamics=false registertracker("otf.dynamics",function(v) trace_dynamics=v end)
-local trace_sequences=false registertracker("otf.sequences",function(v) trace_sequences=v end)
-local trace_markwidth=false registertracker("otf.markwidth",function(v) trace_markwidth=v end)
-local trace_defining=false registertracker("fonts.defining",function(v) trace_defining=v end)
-local report_otf=logs.reporter("fonts","otf loading")
-local fonts=fonts
-local otf=fonts.handlers.otf
-otf.glists={ "gsub","gpos" }
-otf.version=2.759 
-otf.cache=containers.define("fonts","otf",otf.version,true)
-local fontdata=fonts.hashes.identifiers
-local chardata=characters and characters.data 
-local otffeatures=fonts.constructors.newfeatures("otf")
-local registerotffeature=otffeatures.register
-local enhancers=allocate()
-otf.enhancers=enhancers
-local patches={}
-enhancers.patches=patches
-local definers=fonts.definers
-local readers=fonts.readers
-local constructors=fonts.constructors
-local forceload=false
-local cleanup=0   
-local usemetatables=false 
-local packdata=true
-local syncspace=true
-local forcenotdef=false
-local includesubfonts=false
-local overloadkerns=false 
-local applyruntimefixes=fonts.treatments and fonts.treatments.applyfixes
-local wildcard="*"
-local default="dflt"
-local fontloaderfields=fontloader.fields
-local mainfields=nil
-local glyphfields=nil 
-local formats=fonts.formats
-formats.otf="opentype"
-formats.ttf="truetype"
-formats.ttc="truetype"
-formats.dfont="truetype"
-registerdirective("fonts.otf.loader.cleanup",function(v) cleanup=tonumber(v) or (v and 1) or 0 end)
-registerdirective("fonts.otf.loader.force",function(v) forceload=v end)
-registerdirective("fonts.otf.loader.usemetatables",function(v) usemetatables=v end)
-registerdirective("fonts.otf.loader.pack",function(v) packdata=v end)
-registerdirective("fonts.otf.loader.syncspace",function(v) syncspace=v end)
-registerdirective("fonts.otf.loader.forcenotdef",function(v) forcenotdef=v end)
-registerdirective("fonts.otf.loader.overloadkerns",function(v) overloadkerns=v end)
-function otf.fileformat(filename)
-  local leader=lower(io.loadchunk(filename,4))
-  local suffix=lower(file.suffix(filename))
-  if leader=="otto" then
-    return formats.otf,suffix=="otf"
-  elseif leader=="ttcf" then
-    return formats.ttc,suffix=="ttc"
-  elseif suffix=="ttc" then
-    return formats.ttc,true
-  elseif suffix=="dfont" then
-    return formats.dfont,true
-  else
-    return formats.ttf,suffix=="ttf"
-  end
-end
-local function otf_format(filename)
-  local format,okay=otf.fileformat(filename)
-  if not okay then
-    report_otf("font %a is actually an %a file",filename,format)
-  end
-  return format
-end
-local function load_featurefile(raw,featurefile)
-  if featurefile and featurefile~="" then
-    if trace_loading then
-      report_otf("using featurefile %a",featurefile)
-    end
-    fontloader.apply_featurefile(raw,featurefile)
-  end
-end
-local function showfeatureorder(rawdata,filename)
-  local sequences=rawdata.resources.sequences
-  if sequences and #sequences>0 then
-    if trace_loading then
-      report_otf("font %a has %s sequences",filename,#sequences)
-      report_otf(" ")
-    end
-    for nos=1,#sequences do
-      local sequence=sequences[nos]
-      local typ=sequence.type   or "no-type"
-      local name=sequence.name   or "no-name"
-      local subtables=sequence.subtables or { "no-subtables" }
-      local features=sequence.features
-      if trace_loading then
-        report_otf("%3i  %-15s  %-20s  [% t]",nos,name,typ,subtables)
-      end
-      if features then
-        for feature,scripts in next,features do
-          local tt={}
-          if type(scripts)=="table" then
-            for script,languages in next,scripts do
-              local ttt={}
-              for language,_ in next,languages do
-                ttt[#ttt+1]=language
-              end
-              tt[#tt+1]=formatters["[%s: % t]"](script,ttt)
-            end
-            if trace_loading then
-              report_otf("       %s: % t",feature,tt)
-            end
-          else
-            if trace_loading then
-              report_otf("       %s: %S",feature,scripts)
-            end
-          end
-        end
-      end
-    end
-    if trace_loading then
-      report_otf("\n")
-    end
-  elseif trace_loading then
-    report_otf("font %a has no sequences",filename)
-  end
-end
-local valid_fields=table.tohash {
-  "ascent",
-  "cidinfo",
-  "copyright",
-  "descent",
-  "design_range_bottom",
-  "design_range_top",
-  "design_size",
-  "encodingchanged",
-  "extrema_bound",
-  "familyname",
-  "fontname",
-  "fontname",
-  "fontstyle_id",
-  "fontstyle_name",
-  "fullname",
-  "hasvmetrics",
-  "horiz_base",
-  "issans",
-  "isserif",
-  "italicangle",
-  "macstyle",
-  "onlybitmaps",
-  "origname",
-  "os2_version",
-  "pfminfo",
-  "serifcheck",
-  "sfd_version",
-  "strokedfont",
-  "strokewidth",
-  "table_version",
-  "ttf_tables",
-  "uni_interp",
-  "uniqueid",
-  "units_per_em",
-  "upos",
-  "use_typo_metrics",
-  "uwidth",
-  "validation_state",
-  "version",
-  "vert_base",
-  "weight",
-  "weight_width_slope_only",
-}
-local ordered_enhancers={
-  "prepare tables",
-  "prepare glyphs",
-  "prepare lookups",
-  "analyze glyphs",
-  "analyze math",
-  "prepare tounicode",
-  "reorganize lookups",
-  "reorganize mark classes",
-  "reorganize anchor classes",
-  "reorganize glyph kerns",
-  "reorganize glyph lookups",
-  "reorganize glyph anchors",
-  "merge kern classes",
-  "reorganize features",
-  "reorganize subtables",
-  "check glyphs",
-  "check metadata",
-  "check extra features",
-  "check encoding",
-  "add duplicates",
-  "cleanup tables",
-}
-local actions=allocate()
-local before=allocate()
-local after=allocate()
-patches.before=before
-patches.after=after
-local function enhance(name,data,filename,raw)
-  local enhancer=actions[name]
-  if enhancer then
-    if trace_loading then
-      report_otf("apply enhancement %a to file %a",name,filename)
-      ioflush()
-    end
-    enhancer(data,filename,raw)
-  else
-  end
-end
-function enhancers.apply(data,filename,raw)
-  local basename=file.basename(lower(filename))
-  if trace_loading then
-    report_otf("%s enhancing file %a","start",filename)
-  end
-  ioflush() 
-  for e=1,#ordered_enhancers do
-    local enhancer=ordered_enhancers[e]
-    local b=before[enhancer]
-    if b then
-      for pattern,action in next,b do
-        if find(basename,pattern) then
-          action(data,filename,raw)
-        end
-      end
-    end
-    enhance(enhancer,data,filename,raw)
-    local a=after[enhancer]
-    if a then
-      for pattern,action in next,a do
-        if find(basename,pattern) then
-          action(data,filename,raw)
-        end
-      end
-    end
-    ioflush() 
-  end
-  if trace_loading then
-    report_otf("%s enhancing file %a","stop",filename)
-  end
-  ioflush() 
-end
-function patches.register(what,where,pattern,action)
-  local pw=patches[what]
-  if pw then
-    local ww=pw[where]
-    if ww then
-      ww[pattern]=action
-    else
-      pw[where]={ [pattern]=action}
-    end
-  end
-end
-function patches.report(fmt,...)
-  if trace_loading then
-    report_otf("patching: %s",formatters[fmt](...))
-  end
-end
-function enhancers.register(what,action) 
-  actions[what]=action
-end
-function otf.load(filename,sub,featurefile) 
-  local base=file.basename(file.removesuffix(filename))
-  local name=file.removesuffix(base)
-  local attr=lfs.attributes(filename)
-  local size=attr and attr.size or 0
-  local time=attr and attr.modification or 0
-  if featurefile then
-    name=name.."@"..file.removesuffix(file.basename(featurefile))
-  end
-  if sub=="" then
-    sub=false
-  end
-  local hash=name
-  if sub then
-    hash=hash.."-"..sub
-  end
-  hash=containers.cleanname(hash)
-  local featurefiles
-  if featurefile then
-    featurefiles={}
-    for s in gmatch(featurefile,"[^,]+") do
-      local name=resolvers.findfile(file.addsuffix(s,'fea'),'fea') or ""
-      if name=="" then
-        report_otf("loading error, no featurefile %a",s)
-      else
-        local attr=lfs.attributes(name)
-        featurefiles[#featurefiles+1]={
-          name=name,
-          size=attr and attr.size or 0,
-          time=attr and attr.modification or 0,
-        }
-      end
-    end
-    if #featurefiles==0 then
-      featurefiles=nil
-    end
-  end
-  local data=containers.read(otf.cache,hash)
-  local reload=not data or data.size~=size or data.time~=time
-  if forceload then
-    report_otf("forced reload of %a due to hard coded flag",filename)
-    reload=true
-  end
-  if not reload then
-    local featuredata=data.featuredata
-    if featurefiles then
-      if not featuredata or #featuredata~=#featurefiles then
-        reload=true
-      else
-        for i=1,#featurefiles do
-          local fi,fd=featurefiles[i],featuredata[i]
-          if fi.name~=fd.name or fi.size~=fd.size or fi.time~=fd.time then
-            reload=true
-            break
-          end
-        end
-      end
-    elseif featuredata then
-      reload=true
-    end
-    if reload then
-      report_otf("loading: forced reload due to changed featurefile specification %a",featurefile)
-    end
-   end
-   if reload then
-    report_otf("loading %a, hash %a",filename,hash)
-    local fontdata,messages
-    if sub then
-      fontdata,messages=fontloader.open(filename,sub)
-    else
-      fontdata,messages=fontloader.open(filename)
-    end
-    if fontdata then
-      mainfields=mainfields or (fontloaderfields and fontloaderfields(fontdata))
-    end
-    if trace_loading and messages and #messages>0 then
-      if type(messages)=="string" then
-        report_otf("warning: %s",messages)
-      else
-        for m=1,#messages do
-          report_otf("warning: %S",messages[m])
-        end
-      end
-    else
-      report_otf("loading done")
-    end
-    if fontdata then
-      if featurefiles then
-        for i=1,#featurefiles do
-          load_featurefile(fontdata,featurefiles[i].name)
-        end
-      end
-      local unicodes={
-      }
-      local splitter=lpeg.splitter(" ",unicodes)
-      data={
-        size=size,
-        time=time,
-        format=otf_format(filename),
-        featuredata=featurefiles,
-        resources={
-          filename=resolvers.unresolve(filename),
-          version=otf.version,
-          creator="context mkiv",
-          unicodes=unicodes,
-          indices={
-          },
-          duplicates={
-          },
-          variants={
-          },
-          lookuptypes={},
-        },
-        metadata={
-        },
-        properties={
-        },
-        descriptions={},
-        goodies={},
-        helpers={ 
-          tounicodelist=splitter,
-          tounicodetable=lpeg.Ct(splitter),
-        },
-      }
-      starttiming(data)
-      report_otf("file size: %s",size)
-      enhancers.apply(data,filename,fontdata)
-      local packtime={}
-      if packdata then
-        if cleanup>0 then
-          collectgarbage("collect")
-        end
-        starttiming(packtime)
-        enhance("pack",data,filename,nil)
-        stoptiming(packtime)
-      end
-      report_otf("saving %a in cache",filename)
-      data=containers.write(otf.cache,hash,data)
-      if cleanup>1 then
-        collectgarbage("collect")
-      end
-      stoptiming(data)
-      if elapsedtime then 
-        report_otf("preprocessing and caching time %s, packtime %s",
-          elapsedtime(data),packdata and elapsedtime(packtime) or 0)
-      end
-      fontloader.close(fontdata) 
-      if cleanup>3 then
-        collectgarbage("collect")
-      end
-      data=containers.read(otf.cache,hash) 
-      if cleanup>2 then
-        collectgarbage("collect")
-      end
-    else
-      data=nil
-      report_otf("loading failed due to read error")
-    end
-  end
-  if data then
-    if trace_defining then
-      report_otf("loading from cache using hash %a",hash)
-    end
-    enhance("unpack",data,filename,nil,false)
-    if applyruntimefixes then
-      applyruntimefixes(filename,data)
-    end
-    enhance("add dimensions",data,filename,nil,false)
-    if trace_sequences then
-      showfeatureorder(data,filename)
-    end
-  end
-  return data
-end
-local mt={
-  __index=function(t,k) 
-    if k=="height" then
-      local ht=t.boundingbox[4]
-      return ht<0 and 0 or ht
-    elseif k=="depth" then
-      local dp=-t.boundingbox[2]
-      return dp<0 and 0 or dp
-    elseif k=="width" then
-      return 0
-    elseif k=="name" then 
-      return forcenotdef and ".notdef"
-    end
-  end
-}
-actions["prepare tables"]=function(data,filename,raw)
-  data.properties.hasitalics=false
-end
-actions["add dimensions"]=function(data,filename)
-  if data then
-    local descriptions=data.descriptions
-    local resources=data.resources
-    local defaultwidth=resources.defaultwidth or 0
-    local defaultheight=resources.defaultheight or 0
-    local defaultdepth=resources.defaultdepth or 0
-    local basename=trace_markwidth and file.basename(filename)
-    if usemetatables then
-      for _,d in next,descriptions do
-        local wd=d.width
-        if not wd then
-          d.width=defaultwidth
-        elseif trace_markwidth and wd~=0 and d.class=="mark" then
-          report_otf("mark %a with width %b found in %a",d.name or "<noname>",wd,basename)
-        end
-        setmetatable(d,mt)
-      end
-    else
-      for _,d in next,descriptions do
-        local bb,wd=d.boundingbox,d.width
-        if not wd then
-          d.width=defaultwidth
-        elseif trace_markwidth and wd~=0 and d.class=="mark" then
-          report_otf("mark %a with width %b found in %a",d.name or "<noname>",wd,basename)
-        end
-        if bb then
-          local ht,dp=bb[4],-bb[2]
-          if ht==0 or ht<0 then
-          else
-            d.height=ht
-          end
-          if dp==0 or dp<0 then
-          else
-            d.depth=dp
-          end
-        end
-      end
-    end
-  end
-end
-local function somecopy(old) 
-  if old then
-    local new={}
-    if type(old)=="table" then
-      for k,v in next,old do
-        if k=="glyphs" then
-        elseif type(v)=="table" then
-          new[k]=somecopy(v)
-        else
-          new[k]=v
-        end
-      end
-    else
-      for i=1,#mainfields do
-        local k=mainfields[i]
-        local v=old[k]
-        if k=="glyphs" then
-        elseif type(v)=="table" then
-          new[k]=somecopy(v)
-        else
-          new[k]=v
-        end
-      end
-    end
-    return new
-  else
-    return {}
-  end
-end
-actions["prepare glyphs"]=function(data,filename,raw)
-  local rawglyphs=raw.glyphs
-  local rawsubfonts=raw.subfonts
-  local rawcidinfo=raw.cidinfo
-  local criterium=constructors.privateoffset
-  local private=criterium
-  local resources=data.resources
-  local metadata=data.metadata
-  local properties=data.properties
-  local descriptions=data.descriptions
-  local unicodes=resources.unicodes 
-  local indices=resources.indices 
-  local duplicates=resources.duplicates
-  local variants=resources.variants
-  if rawsubfonts then
-    metadata.subfonts=includesubfonts and {}
-    properties.cidinfo=rawcidinfo
-    if rawcidinfo.registry then
-      local cidmap=fonts.cid.getmap(rawcidinfo)
-      if cidmap then
-        rawcidinfo.usedname=cidmap.usedname
-        local nofnames,nofunicodes=0,0
-        local cidunicodes,cidnames=cidmap.unicodes,cidmap.names
-        for cidindex=1,#rawsubfonts do
-          local subfont=rawsubfonts[cidindex]
-          local cidglyphs=subfont.glyphs
-          if includesubfonts then
-            metadata.subfonts[cidindex]=somecopy(subfont)
-          end
-          for index=0,subfont.glyphcnt-1 do 
-            local glyph=cidglyphs[index]
-            if glyph then
-              local unicode=glyph.unicode
-if   unicode>=0x00E000 and unicode<=0x00F8FF then
-                unicode=-1
-elseif unicode>=0x0F0000 and unicode<=0x0FFFFD then
-                unicode=-1
-elseif unicode>=0x100000 and unicode<=0x10FFFD then
-                unicode=-1
-end
-              local name=glyph.name or cidnames[index]
-              if not unicode or unicode==-1 then 
-                unicode=cidunicodes[index]
-              end
-              if unicode and descriptions[unicode] then
-                if trace_private then
-                  report_otf("preventing glyph %a at index %H to overload unicode %U",name or "noname",index,unicode)
-                end
-                unicode=-1
-              end
-              if not unicode or unicode==-1 then 
-                if not name then
-                  name=format("u%06X.ctx",private)
-                end
-                unicode=private
-                unicodes[name]=private
-                if trace_private then
-                  report_otf("glyph %a at index %H is moved to private unicode slot %U",name,index,private)
-                end
-                private=private+1
-                nofnames=nofnames+1
-              else
-                if not name then
-                  name=format("u%06X.ctx",unicode)
-                end
-                unicodes[name]=unicode
-                nofunicodes=nofunicodes+1
-              end
-              indices[index]=unicode 
-              local description={
-                boundingbox=glyph.boundingbox,
-                name=glyph.name or name or "unknown",
-                cidindex=cidindex,
-                index=index,
-                glyph=glyph,
-              }
-              descriptions[unicode]=description
-            else
-            end
-          end
-        end
-        if trace_loading then
-          report_otf("cid font remapped, %s unicode points, %s symbolic names, %s glyphs",nofunicodes,nofnames,nofunicodes+nofnames)
-        end
-      elseif trace_loading then
-        report_otf("unable to remap cid font, missing cid file for %a",filename)
-      end
-    elseif trace_loading then
-      report_otf("font %a has no glyphs",filename)
-    end
-  else
-    for index=0,raw.glyphcnt-1 do 
-      local glyph=rawglyphs[index]
-      if glyph then
-        local unicode=glyph.unicode
-        local name=glyph.name
-        if not unicode or unicode==-1 then 
-          unicode=private
-          unicodes[name]=private
-          if trace_private then
-            report_otf("glyph %a at index %H is moved to private unicode slot %U",name,index,private)
-          end
-          private=private+1
-        else
-          if unicode>criterium then
-            local taken=descriptions[unicode]
-            if taken then
-              if unicode>=private then
-                private=unicode+1 
-              else
-                private=private+1 
-              end
-              descriptions[private]=taken
-              unicodes[taken.name]=private
-              indices[taken.index]=private
-              if trace_private then
-                report_otf("slot %U is moved to %U due to private in font",unicode)
-              end
-            else
-              if unicode>=private then
-                private=unicode+1 
-              end
-            end
-          end
-          unicodes[name]=unicode
-        end
-        indices[index]=unicode
-        descriptions[unicode]={
-          boundingbox=glyph.boundingbox,
-          name=name,
-          index=index,
-          glyph=glyph,
-        }
-        local altuni=glyph.altuni
-        if altuni then
-          for i=1,#altuni do
-            local a=altuni[i]
-            local u=a.unicode
-            local v=a.variant
-            if v then
-              local vv=variants[v]
-              if vv then
-                vv[u]=unicode
-              else 
-                vv={ [u]=unicode }
-                variants[v]=vv
-              end
-            end
-          end
-        end
-      else
-        report_otf("potential problem: glyph %U is used but empty",index)
-      end
-    end
-  end
-  resources.private=private
-end
-actions["check encoding"]=function(data,filename,raw)
-  local descriptions=data.descriptions
-  local resources=data.resources
-  local properties=data.properties
-  local unicodes=resources.unicodes 
-  local indices=resources.indices 
-  local duplicates=resources.duplicates
-  local mapdata=raw.map or {}
-  local unicodetoindex=mapdata and mapdata.map or {}
-  local indextounicode=mapdata and mapdata.backmap or {}
-  local encname=lower(data.enc_name or mapdata.enc_name or "")
-  local criterium=0xFFFF 
-  local privateoffset=constructors.privateoffset
-  if find(encname,"unicode") then 
-    if trace_loading then
-      report_otf("checking embedded unicode map %a",encname)
-    end
-    local reported={}
-    for maybeunicode,index in next,unicodetoindex do
-      if descriptions[maybeunicode] then
-      else
-        local unicode=indices[index]
-        if not unicode then
-        elseif maybeunicode==unicode then
-        elseif unicode>privateoffset then
-        else
-          local d=descriptions[unicode]
-          if d then
-            local c=d.copies
-            if c then
-              c[maybeunicode]=true
-            else
-              d.copies={ [maybeunicode]=true }
-            end
-          elseif index and not reported[index] then
-            report_otf("missing index %i",index)
-            reported[index]=true
-          end
-        end
-      end
-    end
-    for unicode,data in next,descriptions do
-      local d=data.copies
-      if d then
-        duplicates[unicode]=sortedkeys(d)
-        data.copies=nil
-      end
-    end
-  elseif properties.cidinfo then
-    report_otf("warning: no unicode map, used cidmap %a",properties.cidinfo.usedname)
-  else
-    report_otf("warning: non unicode map %a, only using glyph unicode data",encname or "whatever")
-  end
-  if mapdata then
-    mapdata.map={} 
-    mapdata.backmap={} 
-  end
-end
-actions["add duplicates"]=function(data,filename,raw)
-  local descriptions=data.descriptions
-  local resources=data.resources
-  local properties=data.properties
-  local unicodes=resources.unicodes 
-  local indices=resources.indices 
-  local duplicates=resources.duplicates
-  for unicode,d in next,duplicates do
-    local nofduplicates=#d
-    if nofduplicates>4 then
-      if trace_loading then
-        report_otf("ignoring excessive duplicates of %U (n=%s)",unicode,nofduplicates)
-      end
-    else
-      for i=1,nofduplicates do
-        local u=d[i]
-        if not descriptions[u] then
-          local description=descriptions[unicode]
-          local n=0
-          for _,description in next,descriptions do
-            if kerns then
-              local kerns=description.kerns
-              for _,k in next,kerns do
-                local ku=k[unicode]
-                if ku then
-                  k[u]=ku
-                  n=n+1
-                end
-              end
-            end
-          end
-          if u>0 then 
-            local duplicate=table.copy(description) 
-            duplicate.comment=format("copy of U+%05X",unicode)
-            descriptions[u]=duplicate
-            if trace_loading then
-              report_otf("duplicating %U to %U with index %H (%s kerns)",unicode,u,description.index,n)
-            end
-          end
-        end
-      end
-    end
-  end
-end
-actions["analyze glyphs"]=function(data,filename,raw) 
-  local descriptions=data.descriptions
-  local resources=data.resources
-  local metadata=data.metadata
-  local properties=data.properties
-  local hasitalics=false
-  local widths={}
-  local marks={} 
-  for unicode,description in next,descriptions do
-    local glyph=description.glyph
-    local italic=glyph.italic_correction
-    if not italic then
-    elseif italic==0 then
-    else
-      description.italic=italic
-      hasitalics=true
-    end
-    local width=glyph.width
-    widths[width]=(widths[width] or 0)+1
-    local class=glyph.class
-    if class then
-      if class=="mark" then
-        marks[unicode]=true
-      end
-      description.class=class
-    end
-  end
-  properties.hasitalics=hasitalics
-  resources.marks=marks
-  local wd,most=0,1
-  for k,v in next,widths do
-    if v>most then
-      wd,most=k,v
-    end
-  end
-  if most>1000 then 
-    if trace_loading then
-      report_otf("most common width: %s (%s times), sharing (cjk font)",wd,most)
-    end
-    for unicode,description in next,descriptions do
-      if description.width==wd then
-      else
-        description.width=description.glyph.width
-      end
-    end
-    resources.defaultwidth=wd
-  else
-    for unicode,description in next,descriptions do
-      description.width=description.glyph.width
-    end
-  end
-end
-actions["reorganize mark classes"]=function(data,filename,raw)
-  local mark_classes=raw.mark_classes
-  if mark_classes then
-    local resources=data.resources
-    local unicodes=resources.unicodes
-    local markclasses={}
-    resources.markclasses=markclasses 
-    for name,class in next,mark_classes do
-      local t={}
-      for s in gmatch(class,"[^ ]+") do
-        t[unicodes[s]]=true
-      end
-      markclasses[name]=t
-    end
-  end
-end
-actions["reorganize features"]=function(data,filename,raw) 
-  local features={}
-  data.resources.features=features
-  for k,what in next,otf.glists do
-    local dw=raw[what]
-    if dw then
-      local f={}
-      features[what]=f
-      for i=1,#dw do
-        local d=dw[i]
-        local dfeatures=d.features
-        if dfeatures then
-          for i=1,#dfeatures do
-            local df=dfeatures[i]
-            local tag=strip(lower(df.tag))
-            local ft=f[tag]
-            if not ft then
-              ft={}
-              f[tag]=ft
-            end
-            local dscripts=df.scripts
-            for i=1,#dscripts do
-              local d=dscripts[i]
-              local languages=d.langs
-              local script=strip(lower(d.script))
-              local fts=ft[script] if not fts then fts={} ft[script]=fts end
-              for i=1,#languages do
-                fts[strip(lower(languages[i]))]=true
-              end
-            end
-          end
-        end
-      end
-    end
-  end
-end
-actions["reorganize anchor classes"]=function(data,filename,raw)
-  local resources=data.resources
-  local anchor_to_lookup={}
-  local lookup_to_anchor={}
-  resources.anchor_to_lookup=anchor_to_lookup
-  resources.lookup_to_anchor=lookup_to_anchor
-  local classes=raw.anchor_classes 
-  if classes then
-    for c=1,#classes do
-      local class=classes[c]
-      local anchor=class.name
-      local lookups=class.lookup
-      if type(lookups)~="table" then
-        lookups={ lookups }
-      end
-      local a=anchor_to_lookup[anchor]
-      if not a then
-        a={}
-        anchor_to_lookup[anchor]=a
-      end
-      for l=1,#lookups do
-        local lookup=lookups[l]
-        local l=lookup_to_anchor[lookup]
-        if l then
-          l[anchor]=true
-        else
-          l={ [anchor]=true }
-          lookup_to_anchor[lookup]=l
-        end
-        a[lookup]=true
-      end
-    end
-  end
-end
-actions["prepare tounicode"]=function(data,filename,raw)
-  fonts.mappings.addtounicode(data,filename)
-end
-local g_directions={
-  gsub_contextchain=1,
-  gpos_contextchain=1,
-  gsub_reversecontextchain=-1,
-  gpos_reversecontextchain=-1,
-}
-actions["reorganize subtables"]=function(data,filename,raw)
-  local resources=data.resources
-  local sequences={}
-  local lookups={}
-  local chainedfeatures={}
-  resources.sequences=sequences
-  resources.lookups=lookups
-  for _,what in next,otf.glists do
-    local dw=raw[what]
-    if dw then
-      for k=1,#dw do
-        local gk=dw[k]
-        local features=gk.features
-          local typ=gk.type
-          local chain=g_directions[typ] or 0
-          local subtables=gk.subtables
-          if subtables then
-            local t={}
-            for s=1,#subtables do
-              t[s]=subtables[s].name
-            end
-            subtables=t
-          end
-          local flags,markclass=gk.flags,nil
-          if flags then
-            local t={ 
-              (flags.ignorecombiningmarks and "mark")   or false,
-              (flags.ignoreligatures   and "ligature") or false,
-              (flags.ignorebaseglyphs   and "base")   or false,
-               flags.r2l                 or false,
-            }
-            markclass=flags.mark_class
-            if markclass then
-              markclass=resources.markclasses[markclass]
-            end
-            flags=t
-          end
-          local name=gk.name
-          if not name then
-            report_otf("skipping weird lookup number %s",k)
-          elseif features then
-            local f={}
-            local o={}
-            for i=1,#features do
-              local df=features[i]
-              local tag=strip(lower(df.tag))
-              local ft=f[tag]
-              if not ft then
-                ft={}
-                f[tag]=ft
-                o[#o+1]=tag
-              end
-              local dscripts=df.scripts
-              for i=1,#dscripts do
-                local d=dscripts[i]
-                local languages=d.langs
-                local script=strip(lower(d.script))
-                local fts=ft[script] if not fts then fts={} ft[script]=fts end
-                for i=1,#languages do
-                  fts[strip(lower(languages[i]))]=true
-                end
-              end
-            end
-            sequences[#sequences+1]={
-              type=typ,
-              chain=chain,
-              flags=flags,
-              name=name,
-              subtables=subtables,
-              markclass=markclass,
-              features=f,
-              order=o,
-            }
-          else
-            lookups[name]={
-              type=typ,
-              chain=chain,
-              flags=flags,
-              subtables=subtables,
-              markclass=markclass,
-            }
-          end
-      end
-    end
-  end
-end
-actions["prepare lookups"]=function(data,filename,raw)
-  local lookups=raw.lookups
-  if lookups then
-    data.lookups=lookups
-  end
-end
-local function t_uncover(splitter,cache,covers)
-  local result={}
-  for n=1,#covers do
-    local cover=covers[n]
-    local uncovered=cache[cover]
-    if not uncovered then
-      uncovered=lpegmatch(splitter,cover)
-      cache[cover]=uncovered
-    end
-    result[n]=uncovered
-  end
-  return result
-end
-local function s_uncover(splitter,cache,cover)
-  if cover=="" then
-    return nil
-  else
-    local uncovered=cache[cover]
-    if not uncovered then
-      uncovered=lpegmatch(splitter,cover)
-      cache[cover]=uncovered
-    end
-    return { uncovered }
-  end
-end
-local function t_hashed(t,cache)
-  if t then
-    local ht={}
-    for i=1,#t do
-      local ti=t[i]
-      local tih=cache[ti]
-      if not tih then
-        tih={}
-        for i=1,#ti do
-          tih[ti[i]]=true
-        end
-        cache[ti]=tih
-      end
-      ht[i]=tih
-    end
-    return ht
-  else
-    return nil
-  end
-end
-local function s_hashed(t,cache)
-  if t then
-    local ht={}
-    local tf=t[1]
-    for i=1,#tf do
-      ht[i]={ [tf[i]]=true }
-    end
-    return ht
-  else
-    return nil
-  end
-end
-local function r_uncover(splitter,cache,cover,replacements)
-  if cover=="" then
-    return nil
-  else
-    local uncovered=cover[1]
-    local replaced=cache[replacements]
-    if not replaced then
-      replaced=lpegmatch(splitter,replacements)
-      cache[replacements]=replaced
-    end
-    local nu,nr=#uncovered,#replaced
-    local r={}
-    if nu==nr then
-      for i=1,nu do
-        r[uncovered[i]]=replaced[i]
-      end
-    end
-    return r
-  end
-end
-actions["reorganize lookups"]=function(data,filename,raw)
-  if data.lookups then
-    local splitter=data.helpers.tounicodetable
-    local t_u_cache={}
-    local s_u_cache=t_u_cache 
-    local t_h_cache={}
-    local s_h_cache=t_h_cache 
-    local r_u_cache={} 
-    for _,lookup in next,data.lookups do
-      local rules=lookup.rules
-      if rules then
-        local format=lookup.format
-        if format=="class" then
-          local before_class=lookup.before_class
-          if before_class then
-            before_class=t_uncover(splitter,t_u_cache,reversed(before_class))
-          end
-          local current_class=lookup.current_class
-          if current_class then
-            current_class=t_uncover(splitter,t_u_cache,current_class)
-          end
-          local after_class=lookup.after_class
-          if after_class then
-            after_class=t_uncover(splitter,t_u_cache,after_class)
-          end
-          for i=1,#rules do
-            local rule=rules[i]
-            local class=rule.class
-            local before=class.before
-            if before then
-              for i=1,#before do
-                before[i]=before_class[before[i]] or {}
-              end
-              rule.before=t_hashed(before,t_h_cache)
-            end
-            local current=class.current
-            local lookups=rule.lookups
-            if current then
-              for i=1,#current do
-                current[i]=current_class[current[i]] or {}
-                if lookups and not lookups[i] then
-                  lookups[i]="" 
-                end
-              end
-              rule.current=t_hashed(current,t_h_cache)
-            end
-            local after=class.after
-            if after then
-              for i=1,#after do
-                after[i]=after_class[after[i]] or {}
-              end
-              rule.after=t_hashed(after,t_h_cache)
-            end
-            rule.class=nil
-          end
-          lookup.before_class=nil
-          lookup.current_class=nil
-          lookup.after_class=nil
-          lookup.format="coverage"
-        elseif format=="coverage" then
-          for i=1,#rules do
-            local rule=rules[i]
-            local coverage=rule.coverage
-            if coverage then
-              local before=coverage.before
-              if before then
-                before=t_uncover(splitter,t_u_cache,reversed(before))
-                rule.before=t_hashed(before,t_h_cache)
-              end
-              local current=coverage.current
-              if current then
-                current=t_uncover(splitter,t_u_cache,current)
-                local lookups=rule.lookups
-                if lookups then
-                  for i=1,#current do
-                    if not lookups[i] then
-                      lookups[i]="" 
-                    end
-                  end
-                end
-                rule.current=t_hashed(current,t_h_cache)
-              end
-              local after=coverage.after
-              if after then
-                after=t_uncover(splitter,t_u_cache,after)
-                rule.after=t_hashed(after,t_h_cache)
-              end
-              rule.coverage=nil
-            end
-          end
-        elseif format=="reversecoverage" then 
-          for i=1,#rules do
-            local rule=rules[i]
-            local reversecoverage=rule.reversecoverage
-            if reversecoverage then
-              local before=reversecoverage.before
-              if before then
-                before=t_uncover(splitter,t_u_cache,reversed(before))
-                rule.before=t_hashed(before,t_h_cache)
-              end
-              local current=reversecoverage.current
-              if current then
-                current=t_uncover(splitter,t_u_cache,current)
-                rule.current=t_hashed(current,t_h_cache)
-              end
-              local after=reversecoverage.after
-              if after then
-                after=t_uncover(splitter,t_u_cache,after)
-                rule.after=t_hashed(after,t_h_cache)
-              end
-              local replacements=reversecoverage.replacements
-              if replacements then
-                rule.replacements=r_uncover(splitter,r_u_cache,current,replacements)
-              end
-              rule.reversecoverage=nil
-            end
-          end
-        elseif format=="glyphs" then
-          for i=1,#rules do
-            local rule=rules[i]
-            local glyphs=rule.glyphs
-            if glyphs then
-              local fore=glyphs.fore
-              if fore and fore~="" then
-                fore=s_uncover(splitter,s_u_cache,fore)
-                rule.after=s_hashed(fore,s_h_cache)
-              end
-              local back=glyphs.back
-              if back then
-                back=s_uncover(splitter,s_u_cache,back)
-                rule.before=s_hashed(back,s_h_cache)
-              end
-              local names=glyphs.names
-              if names then
-                names=s_uncover(splitter,s_u_cache,names)
-                rule.current=s_hashed(names,s_h_cache)
-              end
-              rule.glyphs=nil
-              local lookups=rule.lookups
-              if lookups then
-                for i=1,#names do
-                  if not lookups[i] then
-                    lookups[i]="" 
-                  end
-                end
-              end
-            end
-          end
-        end
-      end
-    end
-  end
-end
-local function check_variants(unicode,the_variants,splitter,unicodes)
-  local variants=the_variants.variants
-  if variants then 
-    local glyphs=lpegmatch(splitter,variants)
-    local done={ [unicode]=true }
-    local n=0
-    for i=1,#glyphs do
-      local g=glyphs[i]
-      if done[g] then
-        if i>1 then
-          report_otf("skipping cyclic reference %U in math variant %U",g,unicode)
-        end
-      else
-        if n==0 then
-          n=1
-          variants={ g }
-        else
-          n=n+1
-          variants[n]=g
-        end
-        done[g]=true
-      end
-    end
-    if n==0 then
-      variants=nil
-    end
-  end
-  local parts=the_variants.parts
-  if parts then
-    local p=#parts
-    if p>0 then
-      for i=1,p do
-        local pi=parts[i]
-        pi.glyph=unicodes[pi.component] or 0
-        pi.component=nil
-      end
-    else
-      parts=nil
-    end
-  end
-  local italic_correction=the_variants.italic_correction
-  if italic_correction and italic_correction==0 then
-    italic_correction=nil
-  end
-  return variants,parts,italic_correction
-end
-actions["analyze math"]=function(data,filename,raw)
-  if raw.math then
-    data.metadata.math=raw.math
-    local unicodes=data.resources.unicodes
-    local splitter=data.helpers.tounicodetable
-    for unicode,description in next,data.descriptions do
-      local glyph=description.glyph
-      local mathkerns=glyph.mathkern 
-      local horiz_variants=glyph.horiz_variants
-      local vert_variants=glyph.vert_variants
-      local top_accent=glyph.top_accent
-      if mathkerns or horiz_variants or vert_variants or top_accent then
-        local math={}
-        if top_accent then
-          math.top_accent=top_accent
-        end
-        if mathkerns then
-          for k,v in next,mathkerns do
-            if not next(v) then
-              mathkerns[k]=nil
-            else
-              for k,v in next,v do
-                if v==0 then
-                  k[v]=nil 
-                end
-              end
-            end
-          end
-          math.kerns=mathkerns
-        end
-        if horiz_variants then
-          math.horiz_variants,math.horiz_parts,math.horiz_italic_correction=check_variants(unicode,horiz_variants,splitter,unicodes)
-        end
-        if vert_variants then
-          math.vert_variants,math.vert_parts,math.vert_italic_correction=check_variants(unicode,vert_variants,splitter,unicodes)
-        end
-        local italic_correction=description.italic
-        if italic_correction and italic_correction~=0 then
-          math.italic_correction=italic_correction
-        end
-        description.math=math
-      end
-    end
-  end
-end
-actions["reorganize glyph kerns"]=function(data,filename,raw)
-  local descriptions=data.descriptions
-  local resources=data.resources
-  local unicodes=resources.unicodes
-  for unicode,description in next,descriptions do
-    local kerns=description.glyph.kerns
-    if kerns then
-      local newkerns={}
-      for k,kern in next,kerns do
-        local name=kern.char
-        local offset=kern.off
-        local lookup=kern.lookup
-        if name and offset and lookup then
-          local unicode=unicodes[name]
-          if unicode then
-            if type(lookup)=="table" then
-              for l=1,#lookup do
-                local lookup=lookup[l]
-                local lookupkerns=newkerns[lookup]
-                if lookupkerns then
-                  lookupkerns[unicode]=offset
-                else
-                  newkerns[lookup]={ [unicode]=offset }
-                end
-              end
-            else
-              local lookupkerns=newkerns[lookup]
-              if lookupkerns then
-                lookupkerns[unicode]=offset
-              else
-                newkerns[lookup]={ [unicode]=offset }
-              end
-            end
-          elseif trace_loading then
-            report_otf("problems with unicode %a of kern %a of glyph %U",name,k,unicode)
-          end
-        end
-      end
-      description.kerns=newkerns
-    end
-  end
-end
-actions["merge kern classes"]=function(data,filename,raw)
-  local gposlist=raw.gpos
-  if gposlist then
-    local descriptions=data.descriptions
-    local resources=data.resources
-    local unicodes=resources.unicodes
-    local splitter=data.helpers.tounicodetable
-    local ignored=0
-    local blocked=0
-    for gp=1,#gposlist do
-      local gpos=gposlist[gp]
-      local subtables=gpos.subtables
-      if subtables then
-        local first_done={} 
-        local split={} 
-        for s=1,#subtables do
-          local subtable=subtables[s]
-          local kernclass=subtable.kernclass 
-          local lookup=subtable.lookup or subtable.name
-          if kernclass then 
-            if #kernclass>0 then
-              kernclass=kernclass[1]
-              lookup=type(kernclass.lookup)=="string" and kernclass.lookup or lookup
-              report_otf("fixing kernclass table of lookup %a",lookup)
-            end
-            local firsts=kernclass.firsts
-            local seconds=kernclass.seconds
-            local offsets=kernclass.offsets
-            for n,s in next,firsts do
-              split[s]=split[s] or lpegmatch(splitter,s)
-            end
-            local maxseconds=0
-            for n,s in next,seconds do
-              if n>maxseconds then
-                maxseconds=n
-              end
-              split[s]=split[s] or lpegmatch(splitter,s)
-            end
-            for fk=1,#firsts do 
-              local fv=firsts[fk]
-              local splt=split[fv]
-              if splt then
-                local extrakerns={}
-                local baseoffset=(fk-1)*maxseconds
-                for sk=2,maxseconds do 
-                  local sv=seconds[sk]
-                  local splt=split[sv]
-                  if splt then 
-                    local offset=offsets[baseoffset+sk]
-                    if offset then
-                      for i=1,#splt do
-                        extrakerns[splt[i]]=offset
-                      end
-                    end
-                  end
-                end
-                for i=1,#splt do
-                  local first_unicode=splt[i]
-                  if first_done[first_unicode] then
-                    report_otf("lookup %a: ignoring further kerns of %C",lookup,first_unicode)
-                    blocked=blocked+1
-                  else
-                    first_done[first_unicode]=true
-                    local description=descriptions[first_unicode]
-                    if description then
-                      local kerns=description.kerns
-                      if not kerns then
-                        kerns={} 
-                        description.kerns=kerns
-                      end
-                      local lookupkerns=kerns[lookup]
-                      if not lookupkerns then
-                        lookupkerns={}
-                        kerns[lookup]=lookupkerns
-                      end
-                      if overloadkerns then
-                        for second_unicode,kern in next,extrakerns do
-                          lookupkerns[second_unicode]=kern
-                        end
-                      else
-                        for second_unicode,kern in next,extrakerns do
-                          local k=lookupkerns[second_unicode]
-                          if not k then
-                            lookupkerns[second_unicode]=kern
-                          elseif k~=kern then
-                            if trace_loading then
-                              report_otf("lookup %a: ignoring overload of kern between %C and %C, rejecting %a, keeping %a",lookup,first_unicode,second_unicode,k,kern)
-                            end
-                            ignored=ignored+1
-                          end
-                        end
-                      end
-                    elseif trace_loading then
-                      report_otf("no glyph data for %U",first_unicode)
-                    end
-                  end
-                end
-              end
-            end
-            subtable.kernclass={}
-          end
-        end
-      end
-    end
-    if ignored>0 then
-      report_otf("%s kern overloads ignored",ignored)
-    end
-    if blocked>0 then
-      report_otf("%s succesive kerns blocked",blocked)
-    end
-  end
-end
-actions["check glyphs"]=function(data,filename,raw)
-  for unicode,description in next,data.descriptions do
-    description.glyph=nil
-  end
-end
-actions["check metadata"]=function(data,filename,raw)
-  local metadata=data.metadata
-  for _,k in next,mainfields do
-    if valid_fields[k] then
-      local v=raw[k]
-      if not metadata[k] then
-        metadata[k]=v
-      end
-    end
-  end
-  local ttftables=metadata.ttf_tables
-  if ttftables then
-    for i=1,#ttftables do
-      ttftables[i].data="deleted"
-    end
-  end
-  if metadata.validation_state and table.contains(metadata.validation_state,"bad_ps_fontname") then
-    local name=file.nameonly(filename)
-    metadata.fontname="bad-fontname-"..name
-    metadata.fullname="bad-fullname-"..name
-  end
-end
-actions["cleanup tables"]=function(data,filename,raw)
-  data.resources.indices=nil 
-  data.helpers=nil
-end
-actions["reorganize glyph lookups"]=function(data,filename,raw)
-  local resources=data.resources
-  local unicodes=resources.unicodes
-  local descriptions=data.descriptions
-  local splitter=data.helpers.tounicodelist
-  local lookuptypes=resources.lookuptypes
-  for unicode,description in next,descriptions do
-    local lookups=description.glyph.lookups
-    if lookups then
-      for tag,lookuplist in next,lookups do
-        for l=1,#lookuplist do
-          local lookup=lookuplist[l]
-          local specification=lookup.specification
-          local lookuptype=lookup.type
-          local lt=lookuptypes[tag]
-          if not lt then
-            lookuptypes[tag]=lookuptype
-          elseif lt~=lookuptype then
-            report_otf("conflicting lookuptypes, %a points to %a and %a",tag,lt,lookuptype)
-          end
-          if lookuptype=="ligature" then
-            lookuplist[l]={ lpegmatch(splitter,specification.components) }
-          elseif lookuptype=="alternate" then
-            lookuplist[l]={ lpegmatch(splitter,specification.components) }
-          elseif lookuptype=="substitution" then
-            lookuplist[l]=unicodes[specification.variant]
-          elseif lookuptype=="multiple" then
-            lookuplist[l]={ lpegmatch(splitter,specification.components) }
-          elseif lookuptype=="position" then
-            lookuplist[l]={
-              specification.x or 0,
-              specification.y or 0,
-              specification.h or 0,
-              specification.v or 0
-            }
-          elseif lookuptype=="pair" then
-            local one=specification.offsets[1]
-            local two=specification.offsets[2]
-            local paired=unicodes[specification.paired]
-            if one then
-              if two then
-                lookuplist[l]={ paired,{ one.x or 0,one.y or 0,one.h or 0,one.v or 0 },{ two.x or 0,two.y or 0,two.h or 0,two.v or 0 } }
-              else
-                lookuplist[l]={ paired,{ one.x or 0,one.y or 0,one.h or 0,one.v or 0 } }
-              end
-            else
-              if two then
-                lookuplist[l]={ paired,{},{ two.x or 0,two.y or 0,two.h or 0,two.v or 0} } 
-              else
-                lookuplist[l]={ paired }
-              end
-            end
-          end
-        end
-      end
-      local slookups,mlookups
-      for tag,lookuplist in next,lookups do
-        if #lookuplist==1 then
-          if slookups then
-            slookups[tag]=lookuplist[1]
-          else
-            slookups={ [tag]=lookuplist[1] }
-          end
-        else
-          if mlookups then
-            mlookups[tag]=lookuplist
-          else
-            mlookups={ [tag]=lookuplist }
-          end
-        end
-      end
-      if slookups then
-        description.slookups=slookups
-      end
-      if mlookups then
-        description.mlookups=mlookups
-      end
-    end
-  end
-end
-actions["reorganize glyph anchors"]=function(data,filename,raw) 
-  local descriptions=data.descriptions
-  for unicode,description in next,descriptions do
-    local anchors=description.glyph.anchors
-    if anchors then
-      for class,data in next,anchors do
-        if class=="baselig" then
-          for tag,specification in next,data do
-            for i=1,#specification do
-              local si=specification[i]
-              specification[i]={ si and si.x or 0,si and si.y or 0 }
-            end
-          end
-        else
-          for tag,specification in next,data do
-            data[tag]={ specification.x or 0,specification.y or 0 }
-          end
-        end
-      end
-      description.anchors=anchors
-    end
-  end
-end
-function otf.setfeatures(tfmdata,features)
-  local okay=constructors.initializefeatures("otf",tfmdata,features,trace_features,report_otf)
-  if okay then
-    return constructors.collectprocessors("otf",tfmdata,features,trace_features,report_otf)
-  else
-    return {} 
-  end
-end
-local function copytotfm(data,cache_id)
-  if data then
-    local metadata=data.metadata
-    local resources=data.resources
-    local properties=derivetable(data.properties)
-    local descriptions=derivetable(data.descriptions)
-    local goodies=derivetable(data.goodies)
-    local characters={}
-    local parameters={}
-    local mathparameters={}
-    local pfminfo=metadata.pfminfo or {}
-    local resources=data.resources
-    local unicodes=resources.unicodes
-    local spaceunits=500
-    local spacer="space"
-    local designsize=metadata.designsize or metadata.design_size or 100
-    local mathspecs=metadata.math
-    if designsize==0 then
-      designsize=100
-    end
-    if mathspecs then
-      for name,value in next,mathspecs do
-        mathparameters[name]=value
-      end
-    end
-    for unicode,_ in next,data.descriptions do 
-      characters[unicode]={}
-    end
-    if mathspecs then
-      for unicode,character in next,characters do
-        local d=descriptions[unicode]
-        local m=d.math
-        if m then
-          local variants=m.horiz_variants
-          local parts=m.horiz_parts
-          if variants then
-            local c=character
-            for i=1,#variants do
-              local un=variants[i]
-                c.next=un
-                c=characters[un]
-            end 
-            c.horiz_variants=parts
-          elseif parts then
-            character.horiz_variants=parts
-          end
-          local variants=m.vert_variants
-          local parts=m.vert_parts
-          if variants then
-            local c=character
-            for i=1,#variants do
-              local un=variants[i]
-                c.next=un
-                c=characters[un]
-            end 
-            c.vert_variants=parts
-          elseif parts then
-            character.vert_variants=parts
-          end
-          local italic_correction=m.vert_italic_correction
-          if italic_correction then
-            character.vert_italic_correction=italic_correction 
-          end
-          local top_accent=m.top_accent
-          if top_accent then
-            character.top_accent=top_accent
-          end
-          local kerns=m.kerns
-          if kerns then
-            character.mathkerns=kerns
-          end
-        end
-      end
-    end
-    local filename=constructors.checkedfilename(resources)
-    local fontname=metadata.fontname
-    local fullname=metadata.fullname or fontname
-    local units=metadata.units_per_em or 1000
-    if units==0 then 
-      units=1000 
-      metadata.units_per_em=1000
-      report_otf("changing %a units to %a",0,units)
-    end
-    local monospaced=metadata.isfixedpitch or (pfminfo.panose and pfminfo.panose.proportion=="Monospaced")
-    local charwidth=pfminfo.avgwidth 
-    local charxheight=pfminfo.os2_xheight and pfminfo.os2_xheight>0 and pfminfo.os2_xheight
-    local italicangle=metadata.italicangle
-    properties.monospaced=monospaced
-    parameters.italicangle=italicangle
-    parameters.charwidth=charwidth
-    parameters.charxheight=charxheight
-    local space=0x0020 
-    local emdash=0x2014 
-    if monospaced then
-      if descriptions[space] then
-        spaceunits,spacer=descriptions[space].width,"space"
-      end
-      if not spaceunits and descriptions[emdash] then
-        spaceunits,spacer=descriptions[emdash].width,"emdash"
-      end
-      if not spaceunits and charwidth then
-        spaceunits,spacer=charwidth,"charwidth"
-      end
-    else
-      if descriptions[space] then
-        spaceunits,spacer=descriptions[space].width,"space"
-      end
-      if not spaceunits and descriptions[emdash] then
-        spaceunits,spacer=descriptions[emdash].width/2,"emdash/2"
-      end
-      if not spaceunits and charwidth then
-        spaceunits,spacer=charwidth,"charwidth"
-      end
-    end
-    spaceunits=tonumber(spaceunits) or 500
-    parameters.slant=0
-    parameters.space=spaceunits     
-    parameters.space_stretch=units/2  
-    parameters.space_shrink=1*units/3 
-    parameters.x_height=2*units/5 
-    parameters.quad=units   
-    if spaceunits<2*units/5 then
-    end
-    if italicangle and italicangle~=0 then
-      parameters.italicangle=italicangle
-      parameters.italicfactor=math.cos(math.rad(90+italicangle))
-      parameters.slant=- math.tan(italicangle*math.pi/180)
-    end
-    if monospaced then
-      parameters.space_stretch=0
-      parameters.space_shrink=0
-    elseif syncspace then 
-      parameters.space_stretch=spaceunits/2
-      parameters.space_shrink=spaceunits/3
-    end
-    parameters.extra_space=parameters.space_shrink 
-    if charxheight then
-      parameters.x_height=charxheight
-    else
-      local x=0x78 
-      if x then
-        local x=descriptions[x]
-        if x then
-          parameters.x_height=x.height
-        end
-      end
-    end
-    parameters.designsize=(designsize/10)*65536
-    parameters.ascender=abs(metadata.ascent or 0)
-    parameters.descender=abs(metadata.descent or 0)
-    parameters.units=units
-    properties.space=spacer
-    properties.encodingbytes=2
-    properties.format=data.format or otf_format(filename) or formats.otf
-    properties.noglyphnames=true
-    properties.filename=filename
-    properties.fontname=fontname
-    properties.fullname=fullname
-    properties.psname=fontname or fullname
-    properties.name=filename or fullname
-    return {
-      characters=characters,
-      descriptions=descriptions,
-      parameters=parameters,
-      mathparameters=mathparameters,
-      resources=resources,
-      properties=properties,
-      goodies=goodies,
-    }
-  end
-end
-local function otftotfm(specification)
-  local cache_id=specification.hash
-  local tfmdata=containers.read(constructors.cache,cache_id)
-  if not tfmdata then
-    local name=specification.name
-    local sub=specification.sub
-    local filename=specification.filename
-    local features=specification.features.normal
-    local rawdata=otf.load(filename,sub,features and features.featurefile)
-    if rawdata and next(rawdata) then
-      local descriptions=rawdata.descriptions
-      local duplicates=rawdata.resources.duplicates
-      if duplicates then
-        local nofduplicates,nofduplicated=0,0
-        for parent,list in next,duplicates do
-          for i=1,#list do
-            local unicode=list[i]
-            if not descriptions[unicode] then
-              descriptions[unicode]=descriptions[parent] 
-              nofduplicated=nofduplicated+1
-            end
-          end
-          nofduplicates=nofduplicates+#list
-        end
-        if trace_otf and nofduplicated~=nofduplicates then
-          report_otf("%i extra duplicates copied out of %i",nofduplicated,nofduplicates)
-        end
-      end
-      rawdata.lookuphash={}
-      tfmdata=copytotfm(rawdata,cache_id)
-      if tfmdata and next(tfmdata) then
-        local features=constructors.checkedfeatures("otf",features)
-        local shared=tfmdata.shared
-        if not shared then
-          shared={}
-          tfmdata.shared=shared
-        end
-        shared.rawdata=rawdata
-        shared.dynamics={}
-        tfmdata.changed={}
-        shared.features=features
-        shared.processes=otf.setfeatures(tfmdata,features)
-      end
-    end
-    containers.write(constructors.cache,cache_id,tfmdata)
-  end
-  return tfmdata
-end
-local function read_from_otf(specification)
-  local tfmdata=otftotfm(specification)
-  if tfmdata then
-    tfmdata.properties.name=specification.name
-    tfmdata.properties.sub=specification.sub
-    tfmdata=constructors.scale(tfmdata,specification)
-    local allfeatures=tfmdata.shared.features or specification.features.normal
-    constructors.applymanipulators("otf",tfmdata,allfeatures,trace_features,report_otf)
-    constructors.setname(tfmdata,specification) 
-    fonts.loggers.register(tfmdata,file.suffix(specification.filename),specification)
-  end
-  return tfmdata
-end
-local function checkmathsize(tfmdata,mathsize)
-  local mathdata=tfmdata.shared.rawdata.metadata.math
-  local mathsize=tonumber(mathsize)
-  if mathdata then 
-    local parameters=tfmdata.parameters
-    parameters.scriptpercentage=mathdata.ScriptPercentScaleDown
-    parameters.scriptscriptpercentage=mathdata.ScriptScriptPercentScaleDown
-    parameters.mathsize=mathsize
-  end
-end
-registerotffeature {
-  name="mathsize",
-  description="apply mathsize specified in the font",
-  initializers={
-    base=checkmathsize,
-    node=checkmathsize,
-  }
-}
-function otf.collectlookups(rawdata,kind,script,language)
-  local sequences=rawdata.resources.sequences
-  if sequences then
-    local featuremap,featurelist={},{}
-    for s=1,#sequences do
-      local sequence=sequences[s]
-      local features=sequence.features
-      features=features and features[kind]
-      features=features and (features[script]  or features[default] or features[wildcard])
-      features=features and (features[language] or features[default] or features[wildcard])
-      if features then
-        local subtables=sequence.subtables
-        if subtables then
-          for s=1,#subtables do
-            local ss=subtables[s]
-            if not featuremap[s] then
-              featuremap[ss]=true
-              featurelist[#featurelist+1]=ss
-            end
-          end
-        end
-      end
-    end
-    if #featurelist>0 then
-      return featuremap,featurelist
-    end
-  end
-  return nil,nil
-end
-local function check_otf(forced,specification,suffix)
-  local name=specification.name
-  if forced then
-    name=specification.forcedname 
-  end
-  local fullname=findbinfile(name,suffix) or ""
-  if fullname=="" then
-    fullname=fonts.names.getfilename(name,suffix) or ""
-  end
-  if fullname~="" and not fonts.names.ignoredfile(fullname) then
-    specification.filename=fullname
-    return read_from_otf(specification)
-  end
-end
-local function opentypereader(specification,suffix)
-  local forced=specification.forced or ""
-  if formats[forced] then
-    return check_otf(true,specification,forced)
-  else
-    return check_otf(false,specification,suffix)
-  end
-end
-readers.opentype=opentypereader 
-function readers.otf (specification) return opentypereader(specification,"otf") end
-function readers.ttf (specification) return opentypereader(specification,"ttf") end
-function readers.ttc (specification) return opentypereader(specification,"ttf") end
-function readers.dfont(specification) return opentypereader(specification,"ttf") end
-function otf.scriptandlanguage(tfmdata,attr)
-  local properties=tfmdata.properties
-  return properties.script or "dflt",properties.language or "dflt"
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['font-otb']={
-  version=1.001,
-  comment="companion to font-ini.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local concat=table.concat
-local format,gmatch,gsub,find,match,lower,strip=string.format,string.gmatch,string.gsub,string.find,string.match,string.lower,string.strip
-local type,next,tonumber,tostring=type,next,tonumber,tostring
-local lpegmatch=lpeg.match
-local utfchar=utf.char
-local trace_baseinit=false trackers.register("otf.baseinit",function(v) trace_baseinit=v end)
-local trace_singles=false trackers.register("otf.singles",function(v) trace_singles=v end)
-local trace_multiples=false trackers.register("otf.multiples",function(v) trace_multiples=v end)
-local trace_alternatives=false trackers.register("otf.alternatives",function(v) trace_alternatives=v end)
-local trace_ligatures=false trackers.register("otf.ligatures",function(v) trace_ligatures=v end)
-local trace_ligatures_detail=false trackers.register("otf.ligatures.detail",function(v) trace_ligatures_detail=v end)
-local trace_kerns=false trackers.register("otf.kerns",function(v) trace_kerns=v end)
-local trace_preparing=false trackers.register("otf.preparing",function(v) trace_preparing=v end)
-local report_prepare=logs.reporter("fonts","otf prepare")
-local fonts=fonts
-local otf=fonts.handlers.otf
-local otffeatures=otf.features
-local registerotffeature=otffeatures.register
-otf.defaultbasealternate="none" 
-local wildcard="*"
-local default="dflt"
-local formatters=string.formatters
-local f_unicode=formatters["%U"]
-local f_uniname=formatters["%U (%s)"]
-local f_unilist=formatters["% t (% t)"]
-local function gref(descriptions,n)
-  if type(n)=="number" then
-    local name=descriptions[n].name
-    if name then
-      return f_uniname(n,name)
-    else
-      return f_unicode(n)
-    end
-  elseif n then
-    local num,nam,j={},{},0
-    for i=1,#n do
-      local ni=n[i]
-      if tonumber(ni) then 
-        j=j+1
-        local di=descriptions[ni]
-        num[j]=f_unicode(ni)
-        nam[j]=di and di.name or "-"
-      end
-    end
-    return f_unilist(num,nam)
-  else
-    return "<error in base mode tracing>"
-  end
-end
-local function cref(feature,lookupname)
-  if lookupname then
-    return formatters["feature %a, lookup %a"](feature,lookupname)
-  else
-    return formatters["feature %a"](feature)
-  end
-end
-local function report_alternate(feature,lookupname,descriptions,unicode,replacement,value,comment)
-  report_prepare("%s: base alternate %s => %s (%S => %S)",
-    cref(feature,lookupname),
-    gref(descriptions,unicode),
-    replacement and gref(descriptions,replacement),
-    value,
-    comment)
-end
-local function report_substitution(feature,lookupname,descriptions,unicode,substitution)
-  report_prepare("%s: base substitution %s => %S",
-    cref(feature,lookupname),
-    gref(descriptions,unicode),
-    gref(descriptions,substitution))
-end
-local function report_ligature(feature,lookupname,descriptions,unicode,ligature)
-  report_prepare("%s: base ligature %s => %S",
-    cref(feature,lookupname),
-    gref(descriptions,ligature),
-    gref(descriptions,unicode))
-end
-local function report_kern(feature,lookupname,descriptions,unicode,otherunicode,value)
-  report_prepare("%s: base kern %s + %s => %S",
-    cref(feature,lookupname),
-    gref(descriptions,unicode),
-    gref(descriptions,otherunicode),
-    value)
-end
-local basemethods={}
-local basemethod="<unset>"
-local function applybasemethod(what,...)
-  local m=basemethods[basemethod][what]
-  if m then
-    return m(...)
-  end
-end
-local basehash,basehashes,applied={},1,{}
-local function registerbasehash(tfmdata)
-  local properties=tfmdata.properties
-  local hash=concat(applied," ")
-  local base=basehash[hash]
-  if not base then
-    basehashes=basehashes+1
-    base=basehashes
-    basehash[hash]=base
-  end
-  properties.basehash=base
-  properties.fullname=properties.fullname.."-"..base
-  applied={}
-end
-local function registerbasefeature(feature,value)
-  applied[#applied+1]=feature.."="..tostring(value)
-end
-local trace=false
-local function finalize_ligatures(tfmdata,ligatures)
-  local nofligatures=#ligatures
-  if nofligatures>0 then
-    local characters=tfmdata.characters
-    local descriptions=tfmdata.descriptions
-    local resources=tfmdata.resources
-    local unicodes=resources.unicodes
-    local private=resources.private
-    local alldone=false
-    while not alldone do
-      local done=0
-      for i=1,nofligatures do
-        local ligature=ligatures[i]
-        if ligature then
-          local unicode,lookupdata=ligature[1],ligature[2]
-          if trace_ligatures_detail then
-            report_prepare("building % a into %a",lookupdata,unicode)
-          end
-          local size=#lookupdata
-          local firstcode=lookupdata[1] 
-          local firstdata=characters[firstcode]
-          local okay=false
-          if firstdata then
-            local firstname="ctx_"..firstcode
-            for i=1,size-1 do 
-              local firstdata=characters[firstcode]
-              if not firstdata then
-                firstcode=private
-                if trace_ligatures_detail then
-                  report_prepare("defining %a as %a",firstname,firstcode)
-                end
-                unicodes[firstname]=firstcode
-                firstdata={ intermediate=true,ligatures={} }
-                characters[firstcode]=firstdata
-                descriptions[firstcode]={ name=firstname }
-                private=private+1
-              end
-              local target
-              local secondcode=lookupdata[i+1]
-              local secondname=firstname.."_"..secondcode
-              if i==size-1 then
-                target=unicode
-                if not unicodes[secondname] then
-                  unicodes[secondname]=unicode 
-                end
-                okay=true
-              else
-                target=unicodes[secondname]
-                if not target then
-                  break
-                end
-              end
-              if trace_ligatures_detail then
-                report_prepare("codes (%a,%a) + (%a,%a) -> %a",firstname,firstcode,secondname,secondcode,target)
-              end
-              local firstligs=firstdata.ligatures
-              if firstligs then
-                firstligs[secondcode]={ char=target }
-              else
-                firstdata.ligatures={ [secondcode]={ char=target } }
-              end
-              firstcode=target
-              firstname=secondname
-            end
-          elseif trace_ligatures_detail then
-            report_prepare("no glyph (%a,%a) for building %a",firstname,firstcode,target)
-          end
-          if okay then
-            ligatures[i]=false
-            done=done+1
-          end
-        end
-      end
-      alldone=done==0
-    end
-    if trace_ligatures_detail then
-      for k,v in table.sortedhash(characters) do
-        if v.ligatures then
-          table.print(v,k)
-        end
-      end
-    end
-    resources.private=private
-  end
-end
-local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist)
-  local characters=tfmdata.characters
-  local descriptions=tfmdata.descriptions
-  local resources=tfmdata.resources
-  local changed=tfmdata.changed
-  local unicodes=resources.unicodes
-  local lookuphash=resources.lookuphash
-  local lookuptypes=resources.lookuptypes
-  local ligatures={}
-  local alternate=tonumber(value) or true and 1
-  local defaultalt=otf.defaultbasealternate
-  local trace_singles=trace_baseinit and trace_singles
-  local trace_alternatives=trace_baseinit and trace_alternatives
-  local trace_ligatures=trace_baseinit and trace_ligatures
-  local actions={
-    substitution=function(lookupdata,lookupname,description,unicode)
-      if trace_singles then
-        report_substitution(feature,lookupname,descriptions,unicode,lookupdata)
-      end
-      changed[unicode]=lookupdata
-    end,
-    alternate=function(lookupdata,lookupname,description,unicode)
-      local replacement=lookupdata[alternate]
-      if replacement then
-        changed[unicode]=replacement
-        if trace_alternatives then
-          report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"normal")
-        end
-      elseif defaultalt=="first" then
-        replacement=lookupdata[1]
-        changed[unicode]=replacement
-        if trace_alternatives then
-          report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt)
-        end
-      elseif defaultalt=="last" then
-        replacement=lookupdata[#data]
-        if trace_alternatives then
-          report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt)
-        end
-      else
-        if trace_alternatives then
-          report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"unknown")
-        end
-      end
-    end,
-    ligature=function(lookupdata,lookupname,description,unicode)
-      if trace_ligatures then
-        report_ligature(feature,lookupname,descriptions,unicode,lookupdata)
-      end
-      ligatures[#ligatures+1]={ unicode,lookupdata }
-    end,
-  }
-  for unicode,character in next,characters do
-    local description=descriptions[unicode]
-    local lookups=description.slookups
-    if lookups then
-      for l=1,#lookuplist do
-        local lookupname=lookuplist[l]
-        local lookupdata=lookups[lookupname]
-        if lookupdata then
-          local lookuptype=lookuptypes[lookupname]
-          local action=actions[lookuptype]
-          if action then
-            action(lookupdata,lookupname,description,unicode)
-          end
-        end
-      end
-    end
-    local lookups=description.mlookups
-    if lookups then
-      for l=1,#lookuplist do
-        local lookupname=lookuplist[l]
-        local lookuplist=lookups[lookupname]
-        if lookuplist then
-          local lookuptype=lookuptypes[lookupname]
-          local action=actions[lookuptype]
-          if action then
-            for i=1,#lookuplist do
-              action(lookuplist[i],lookupname,description,unicode)
-            end
-          end
-        end
-      end
-    end
-  end
-  finalize_ligatures(tfmdata,ligatures)
-end
-local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist) 
-  local characters=tfmdata.characters
-  local descriptions=tfmdata.descriptions
-  local resources=tfmdata.resources
-  local unicodes=resources.unicodes
-  local sharedkerns={}
-  local traceindeed=trace_baseinit and trace_kerns
-  for unicode,character in next,characters do
-    local description=descriptions[unicode]
-    local rawkerns=description.kerns 
-    if rawkerns then
-      local s=sharedkerns[rawkerns]
-      if s==false then
-      elseif s then
-        character.kerns=s
-      else
-        local newkerns=character.kerns
-        local done=false
-        for l=1,#lookuplist do
-          local lookup=lookuplist[l]
-          local kerns=rawkerns[lookup]
-          if kerns then
-            for otherunicode,value in next,kerns do
-              if value==0 then
-              elseif not newkerns then
-                newkerns={ [otherunicode]=value }
-                done=true
-                if traceindeed then
-                  report_kern(feature,lookup,descriptions,unicode,otherunicode,value)
-                end
-              elseif not newkerns[otherunicode] then 
-                newkerns[otherunicode]=value
-                done=true
-                if traceindeed then
-                  report_kern(feature,lookup,descriptions,unicode,otherunicode,value)
-                end
-              end
-            end
-          end
-        end
-        if done then
-          sharedkerns[rawkerns]=newkerns
-          character.kerns=newkerns 
-        else
-          sharedkerns[rawkerns]=false
-        end
-      end
-    end
-  end
-end
-basemethods.independent={
-  preparesubstitutions=preparesubstitutions,
-  preparepositionings=preparepositionings,
-}
-local function makefake(tfmdata,name,present)
-  local resources=tfmdata.resources
-  local private=resources.private
-  local character={ intermediate=true,ligatures={} }
-  resources.unicodes[name]=private
-  tfmdata.characters[private]=character
-  tfmdata.descriptions[private]={ name=name }
-  resources.private=private+1
-  present[name]=private
-  return character
-end
-local function make_1(present,tree,name)
-  for k,v in next,tree do
-    if k=="ligature" then
-      present[name]=v
-    else
-      make_1(present,v,name.."_"..k)
-    end
-  end
-end
-local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,done,lookupname)
-  for k,v in next,tree do
-    if k=="ligature" then
-      local character=characters[preceding]
-      if not character then
-        if trace_baseinit then
-          report_prepare("weird ligature in lookup %a, current %C, preceding %C",lookupname,v,preceding)
-        end
-        character=makefake(tfmdata,name,present)
-      end
-      local ligatures=character.ligatures
-      if ligatures then
-        ligatures[unicode]={ char=v }
-      else
-        character.ligatures={ [unicode]={ char=v } }
-      end
-      if done then
-        local d=done[lookupname]
-        if not d then
-          done[lookupname]={ "dummy",v }
-        else
-          d[#d+1]=v
-        end
-      end
-    else
-      local code=present[name] or unicode
-      local name=name.."_"..k
-      make_2(present,tfmdata,characters,v,name,code,k,done,lookupname)
-    end
-  end
-end
-local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist)
-  local characters=tfmdata.characters
-  local descriptions=tfmdata.descriptions
-  local resources=tfmdata.resources
-  local changed=tfmdata.changed
-  local lookuphash=resources.lookuphash
-  local lookuptypes=resources.lookuptypes
-  local ligatures={}
-  local alternate=tonumber(value) or true and 1
-  local defaultalt=otf.defaultbasealternate
-  local trace_singles=trace_baseinit and trace_singles
-  local trace_alternatives=trace_baseinit and trace_alternatives
-  local trace_ligatures=trace_baseinit and trace_ligatures
-  for l=1,#lookuplist do
-    local lookupname=lookuplist[l]
-    local lookupdata=lookuphash[lookupname]
-    local lookuptype=lookuptypes[lookupname]
-    for unicode,data in next,lookupdata do
-      if lookuptype=="substitution" then
-        if trace_singles then
-          report_substitution(feature,lookupname,descriptions,unicode,data)
-        end
-        changed[unicode]=data
-      elseif lookuptype=="alternate" then
-        local replacement=data[alternate]
-        if replacement then
-          changed[unicode]=replacement
-          if trace_alternatives then
-            report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"normal")
-          end
-        elseif defaultalt=="first" then
-          replacement=data[1]
-          changed[unicode]=replacement
-          if trace_alternatives then
-            report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt)
-          end
-        elseif defaultalt=="last" then
-          replacement=data[#data]
-          if trace_alternatives then
-            report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt)
-          end
-        else
-          if trace_alternatives then
-            report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"unknown")
-          end
-        end
-      elseif lookuptype=="ligature" then
-        ligatures[#ligatures+1]={ unicode,data,lookupname }
-        if trace_ligatures then
-          report_ligature(feature,lookupname,descriptions,unicode,data)
-        end
-      end
-    end
-  end
-  local nofligatures=#ligatures
-  if nofligatures>0 then
-    local characters=tfmdata.characters
-    local present={}
-    local done=trace_baseinit and trace_ligatures and {}
-    for i=1,nofligatures do
-      local ligature=ligatures[i]
-      local unicode,tree=ligature[1],ligature[2]
-      make_1(present,tree,"ctx_"..unicode)
-    end
-    for i=1,nofligatures do
-      local ligature=ligatures[i]
-      local unicode,tree,lookupname=ligature[1],ligature[2],ligature[3]
-      make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,lookupname)
-    end
-  end
-end
-local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist)
-  local characters=tfmdata.characters
-  local descriptions=tfmdata.descriptions
-  local resources=tfmdata.resources
-  local lookuphash=resources.lookuphash
-  local traceindeed=trace_baseinit and trace_kerns
-  for l=1,#lookuplist do
-    local lookupname=lookuplist[l]
-    local lookupdata=lookuphash[lookupname]
-    for unicode,data in next,lookupdata do
-      local character=characters[unicode]
-      local kerns=character.kerns
-      if not kerns then
-        kerns={}
-        character.kerns=kerns
-      end
-      if traceindeed then
-        for otherunicode,kern in next,data do
-          if not kerns[otherunicode] and kern~=0 then
-            kerns[otherunicode]=kern
-            report_kern(feature,lookup,descriptions,unicode,otherunicode,kern)
-          end
-        end
-      else
-        for otherunicode,kern in next,data do
-          if not kerns[otherunicode] and kern~=0 then
-            kerns[otherunicode]=kern
-          end
-        end
-      end
-    end
-  end
-end
-local function initializehashes(tfmdata)
-  nodeinitializers.features(tfmdata)
-end
-basemethods.shared={
-  initializehashes=initializehashes,
-  preparesubstitutions=preparesubstitutions,
-  preparepositionings=preparepositionings,
-}
-basemethod="independent"
-local function featuresinitializer(tfmdata,value)
-  if true then 
-    local starttime=trace_preparing and os.clock()
-    local features=tfmdata.shared.features
-    local fullname=tfmdata.properties.fullname or "?"
-    if features then
-      applybasemethod("initializehashes",tfmdata)
-      local collectlookups=otf.collectlookups
-      local rawdata=tfmdata.shared.rawdata
-      local properties=tfmdata.properties
-      local script=properties.script
-      local language=properties.language
-      local basesubstitutions=rawdata.resources.features.gsub
-      local basepositionings=rawdata.resources.features.gpos
-      if basesubstitutions or basepositionings then
-        local sequences=tfmdata.resources.sequences
-        for s=1,#sequences do
-          local sequence=sequences[s]
-          local sfeatures=sequence.features
-          if sfeatures then
-            local order=sequence.order
-            if order then
-              for i=1,#order do 
-                local feature=order[i]
-                local value=features[feature]
-                if value then
-                  local validlookups,lookuplist=collectlookups(rawdata,feature,script,language)
-                  if not validlookups then
-                  elseif basesubstitutions and basesubstitutions[feature] then
-                    if trace_preparing then
-                      report_prepare("filtering base %s feature %a for %a with value %a","sub",feature,fullname,value)
-                    end
-                    applybasemethod("preparesubstitutions",tfmdata,feature,value,validlookups,lookuplist)
-                    registerbasefeature(feature,value)
-                  elseif basepositionings and basepositionings[feature] then
-                    if trace_preparing then
-                      report_prepare("filtering base %a feature %a for %a with value %a","pos",feature,fullname,value)
-                    end
-                    applybasemethod("preparepositionings",tfmdata,feature,value,validlookups,lookuplist)
-                    registerbasefeature(feature,value)
-                  end
-                end
-              end
-            end
-          end
-        end
-      end
-      registerbasehash(tfmdata)
-    end
-    if trace_preparing then
-      report_prepare("preparation time is %0.3f seconds for %a",os.clock()-starttime,fullname)
-    end
-  end
-end
-registerotffeature {
-  name="features",
-  description="features",
-  default=true,
-  initializers={
-    base=featuresinitializer,
-  }
-}
-directives.register("fonts.otf.loader.basemethod",function(v)
-  if basemethods[v] then
-    basemethod=v
-  end
-end)
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['node-inj']={
-  version=1.001,
-  comment="companion to node-ini.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files",
-}
-local next=next
-local utfchar=utf.char
-local trace_injections=false trackers.register("nodes.injections",function(v) trace_injections=v end)
-local report_injections=logs.reporter("nodes","injections")
-local attributes,nodes,node=attributes,nodes,node
-fonts=fonts
-local fontdata=fonts.hashes.identifiers
-nodes.injections=nodes.injections or {}
-local injections=nodes.injections
-local nodecodes=nodes.nodecodes
-local glyph_code=nodecodes.glyph
-local kern_code=nodecodes.kern
-local nodepool=nodes.pool
-local newkern=nodepool.kern
-local traverse_id=node.traverse_id
-local insert_node_before=node.insert_before
-local insert_node_after=node.insert_after
-local a_kernpair=attributes.private('kernpair')
-local a_ligacomp=attributes.private('ligacomp')
-local a_markbase=attributes.private('markbase')
-local a_markmark=attributes.private('markmark')
-local a_markdone=attributes.private('markdone')
-local a_cursbase=attributes.private('cursbase')
-local a_curscurs=attributes.private('curscurs')
-local a_cursdone=attributes.private('cursdone')
-function injections.installnewkern(nk)
-  newkern=nk or newkern
-end
-local cursives={}
-local marks={}
-local kerns={}
-function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
-  local dx,dy=factor*(exit[1]-entry[1]),factor*(exit[2]-entry[2])
-  local ws,wn=tfmstart.width,tfmnext.width
-  local bound=#cursives+1
-  start[a_cursbase]=bound
-  nxt[a_curscurs]=bound
-  cursives[bound]={ rlmode,dx,dy,ws,wn }
-  return dx,dy,bound
-end
-function injections.setpair(current,factor,rlmode,r2lflag,spec,tfmchr)
-  local x,y,w,h=factor*spec[1],factor*spec[2],factor*spec[3],factor*spec[4]
-  if x~=0 or w~=0 or y~=0 or h~=0 then
-    local bound=current[a_kernpair]
-    if bound then
-      local kb=kerns[bound]
-      kb[2],kb[3],kb[4],kb[5]=(kb[2] or 0)+x,(kb[3] or 0)+y,(kb[4] or 0)+w,(kb[5] or 0)+h
-    else
-      bound=#kerns+1
-      current[a_kernpair]=bound
-      kerns[bound]={ rlmode,x,y,w,h,r2lflag,tfmchr.width }
-    end
-    return x,y,w,h,bound
-  end
-  return x,y,w,h 
-end
-function injections.setkern(current,factor,rlmode,x,tfmchr)
-  local dx=factor*x
-  if dx~=0 then
-    local bound=#kerns+1
-    current[a_kernpair]=bound
-    kerns[bound]={ rlmode,dx }
-    return dx,bound
-  else
-    return 0,0
-  end
-end
-function injections.setmark(start,base,factor,rlmode,ba,ma) 
-  local dx,dy=factor*(ba[1]-ma[1]),factor*(ba[2]-ma[2])
-  local bound=base[a_markbase]
-  local index=1
-  if bound then
-    local mb=marks[bound]
-    if mb then
-      index=#mb+1
-      mb[index]={ dx,dy,rlmode }
-      start[a_markmark]=bound
-      start[a_markdone]=index
-      return dx,dy,bound
-    else
-      report_injections("possible problem, %U is base mark without data (id %a)",base.char,bound)
-    end
-  end
-  index=index or 1
-  bound=#marks+1
-  base[a_markbase]=bound
-  start[a_markmark]=bound
-  start[a_markdone]=index
-  marks[bound]={ [index]={ dx,dy,rlmode } }
-  return dx,dy,bound
-end
-local function dir(n)
-  return (n and n<0 and "r-to-l") or (n and n>0 and "l-to-r") or "unset"
-end
-local function trace(head)
-  report_injections("begin run")
-  for n in traverse_id(glyph_code,head) do
-    if n.subtype<256 then
-      local kp=n[a_kernpair]
-      local mb=n[a_markbase]
-      local mm=n[a_markmark]
-      local md=n[a_markdone]
-      local cb=n[a_cursbase]
-      local cc=n[a_curscurs]
-      local char=n.char
-      report_injections("font %s, char %U, glyph %c",n.font,char,char)
-      if kp then
-        local k=kerns[kp]
-        if k[3] then
-          report_injections("  pairkern: dir %a, x %p, y %p, w %p, h %p",dir(k[1]),k[2],k[3],k[4],k[5])
-        else
-          report_injections("  kern: dir %a, dx %p",dir(k[1]),k[2])
-        end
-      end
-      if mb then
-        report_injections("  markbase: bound %a",mb)
-      end
-      if mm then
-        local m=marks[mm]
-        if mb then
-          local m=m[mb]
-          if m then
-            report_injections("  markmark: bound %a, index %a, dx %p, dy %p",mm,md,m[1],m[2])
-          else
-            report_injections("  markmark: bound %a, missing index",mm)
-          end
-        else
-          m=m[1]
-          report_injections("  markmark: bound %a, dx %p, dy %p",mm,m and m[1],m and m[2])
-        end
-      end
-      if cb then
-        report_injections("  cursbase: bound %a",cb)
-      end
-      if cc then
-        local c=cursives[cc]
-        report_injections("  curscurs: bound %a, dir %a, dx %p, dy %p",cc,dir(c[1]),c[2],c[3])
-      end
-    end
-  end
-  report_injections("end run")
-end
-local function show_result(head)
-  local current=head
-  local skipping=false
-  while current do
-    local id=current.id
-    if id==glyph_code then
-      report_injections("char: %C, width %p, xoffset %p, yoffset %p",current.char,current.width,current.xoffset,current.yoffset)
-      skipping=false
-    elseif id==kern_code then
-      report_injections("kern: %p",current.kern)
-      skipping=false
-    elseif not skipping then
-      report_injections()
-      skipping=true
-    end
-    current=current.next
-  end
-end
-function injections.handler(head,where,keep)
-  local has_marks,has_cursives,has_kerns=next(marks),next(cursives),next(kerns)
-  if has_marks or has_cursives then
-    if trace_injections then
-      trace(head)
-    end
-    local done,ky,rl,valid,cx,wx,mk,nofvalid=false,{},{},{},{},{},{},0
-    if has_kerns then 
-      local nf,tm=nil,nil
-      for n in traverse_id(glyph_code,head) do 
-        if n.subtype<256 then
-          nofvalid=nofvalid+1
-          valid[nofvalid]=n
-          if n.font~=nf then
-            nf=n.font
-            tm=fontdata[nf].resources.marks
-          end
-          if tm then
-            mk[n]=tm[n.char]
-          end
-          local k=n[a_kernpair]
-          if k then
-            local kk=kerns[k]
-            if kk then
-              local x,y,w,h=kk[2] or 0,kk[3] or 0,kk[4] or 0,kk[5] or 0
-              local dy=y-h
-              if dy~=0 then
-                ky[n]=dy
-              end
-              if w~=0 or x~=0 then
-                wx[n]=kk
-              end
-              rl[n]=kk[1] 
-            end
-          end
-        end
-      end
-    else
-      local nf,tm=nil,nil
-      for n in traverse_id(glyph_code,head) do
-        if n.subtype<256 then
-          nofvalid=nofvalid+1
-          valid[nofvalid]=n
-          if n.font~=nf then
-            nf=n.font
-            tm=fontdata[nf].resources.marks
-          end
-          if tm then
-            mk[n]=tm[n.char]
-          end
-        end
-      end
-    end
-    if nofvalid>0 then
-      local cx={}
-      if has_kerns and next(ky) then
-        for n,k in next,ky do
-          n.yoffset=k
-        end
-      end
-      if has_cursives then
-        local p_cursbase,p=nil,nil
-        local t,d,maxt={},{},0
-        for i=1,nofvalid do 
-          local n=valid[i]
-          if not mk[n] then
-            local n_cursbase=n[a_cursbase]
-            if p_cursbase then
-              local n_curscurs=n[a_curscurs]
-              if p_cursbase==n_curscurs then
-                local c=cursives[n_curscurs]
-                if c then
-                  local rlmode,dx,dy,ws,wn=c[1],c[2],c[3],c[4],c[5]
-                  if rlmode>=0 then
-                    dx=dx-ws
-                  else
-                    dx=dx+wn
-                  end
-                  if dx~=0 then
-                    cx[n]=dx
-                    rl[n]=rlmode
-                  end
-                    dy=-dy
-                  maxt=maxt+1
-                  t[maxt]=p
-                  d[maxt]=dy
-                else
-                  maxt=0
-                end
-              end
-            elseif maxt>0 then
-              local ny=n.yoffset
-              for i=maxt,1,-1 do
-                ny=ny+d[i]
-                local ti=t[i]
-                ti.yoffset=ti.yoffset+ny
-              end
-              maxt=0
-            end
-            if not n_cursbase and maxt>0 then
-              local ny=n.yoffset
-              for i=maxt,1,-1 do
-                ny=ny+d[i]
-                local ti=t[i]
-                ti.yoffset=ny
-              end
-              maxt=0
-            end
-            p_cursbase,p=n_cursbase,n
-          end
-        end
-        if maxt>0 then
-          local ny=n.yoffset
-          for i=maxt,1,-1 do
-            ny=ny+d[i]
-            local ti=t[i]
-            ti.yoffset=ny
-          end
-          maxt=0
-        end
-        if not keep then
-          cursives={}
-        end
-      end
-      if has_marks then
-        for i=1,nofvalid do
-          local p=valid[i]
-          local p_markbase=p[a_markbase]
-          if p_markbase then
-            local mrks=marks[p_markbase]
-            local nofmarks=#mrks
-            for n in traverse_id(glyph_code,p.next) do
-              local n_markmark=n[a_markmark]
-              if p_markbase==n_markmark then
-                local index=n[a_markdone] or 1
-                local d=mrks[index]
-                if d then
-                  local rlmode=d[3]
-                  local k=wx[p]
-                  if k then
-                    local x=k[2]
-                    local w=k[4]
-                    if w then
-                      if rlmode and rlmode>=0 then
-                        n.xoffset=p.xoffset-p.width+d[1]-(w-x)
-                      else
-                        n.xoffset=p.xoffset-d[1]-x
-                      end
-                    else
-                      if rlmode and rlmode>=0 then
-                        n.xoffset=p.xoffset-p.width+d[1]
-                      else
-                        n.xoffset=p.xoffset-d[1]-x
-                      end
-                    end
-                  else
-                    if rlmode and rlmode>=0 then
-                      n.xoffset=p.xoffset-p.width+d[1]
-                    else
-                      n.xoffset=p.xoffset-d[1]
-                    end
-                    local w=n.width
-                    if w~=0 then
-                      insert_node_before(head,n,newkern(-w/2))
-                      insert_node_after(head,n,newkern(-w/2))
-                    end
-                  end
-                  if mk[p] then
-                    n.yoffset=p.yoffset+d[2]
-                  else
-                    n.yoffset=n.yoffset+p.yoffset+d[2]
-                  end
-                  if nofmarks==1 then
-                    break
-                  else
-                    nofmarks=nofmarks-1
-                  end
-                end
-              else
-              end
-            end
-          end
-        end
-        if not keep then
-          marks={}
-        end
-      end
-      if next(wx) then
-        for n,k in next,wx do
-          local x=k[2]
-          local w=k[4]
-          if w then
-            local rl=k[1] 
-            local wx=w-x
-            if rl<0 then	
-              if wx~=0 then
-                insert_node_before(head,n,newkern(wx)) 
-              end
-              if x~=0 then
-                insert_node_after (head,n,newkern(x)) 
-              end
-            else
-              if x~=0 then
-                insert_node_before(head,n,newkern(x)) 
-              end
-              if wx~=0 then
-                insert_node_after (head,n,newkern(wx)) 
-              end
-            end
-          elseif x~=0 then
-            insert_node_before(head,n,newkern(x)) 
-          end
-        end
-      end
-      if next(cx) then
-        for n,k in next,cx do
-          if k~=0 then
-            local rln=rl[n]
-            if rln and rln<0 then
-              insert_node_before(head,n,newkern(-k)) 
-            else
-              insert_node_before(head,n,newkern(k)) 
-            end
-          end
-        end
-      end
-      if not keep then
-        kerns={}
-      end
-      return head,true
-    elseif not keep then
-      kerns,cursives,marks={},{},{}
-    end
-  elseif has_kerns then
-    if trace_injections then
-      trace(head)
-    end
-    for n in traverse_id(glyph_code,head) do
-      if n.subtype<256 then
-        local k=n[a_kernpair]
-        if k then
-          local kk=kerns[k]
-          if kk then
-            local rl,x,y,w=kk[1],kk[2] or 0,kk[3],kk[4]
-            if y and y~=0 then
-              n.yoffset=y 
-            end
-            if w then
-              local wx=w-x
-              if rl<0 then 
-                if wx~=0 then
-                  insert_node_before(head,n,newkern(wx))
-                end
-                if x~=0 then
-                  insert_node_after (head,n,newkern(x))
-                end
-              else
-                if x~=0 then
-                  insert_node_before(head,n,newkern(x))
-                end
-                if wx~=0 then
-                  insert_node_after(head,n,newkern(wx))
-                end
-              end
-            else
-              if x~=0 then
-                insert_node_before(head,n,newkern(x))
-              end
-            end
-          end
-        end
-      end
-    end
-    if not keep then
-      kerns={}
-    end
-    return head,true
-  else
-  end
-  return head,false
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['font-ota']={
-  version=1.001,
-  comment="companion to font-otf.lua (analysing)",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local type=type
-if not trackers then trackers={ register=function() end } end
-local fonts,nodes,node=fonts,nodes,node
-local allocate=utilities.storage.allocate
-local otf=fonts.handlers.otf
-local analyzers=fonts.analyzers
-local initializers=allocate()
-local methods=allocate()
-analyzers.initializers=initializers
-analyzers.methods=methods
-analyzers.useunicodemarks=false
-local a_state=attributes.private('state')
-local nodecodes=nodes.nodecodes
-local glyph_code=nodecodes.glyph
-local disc_code=nodecodes.disc
-local math_code=nodecodes.math
-local traverse_id=node.traverse_id
-local traverse_node_list=node.traverse
-local end_of_math=node.end_of_math
-local fontdata=fonts.hashes.identifiers
-local categories=characters and characters.categories or {} 
-local otffeatures=fonts.constructors.newfeatures("otf")
-local registerotffeature=otffeatures.register
-local s_init=1  local s_rphf=7
-local s_medi=2  local s_half=8
-local s_fina=3  local s_pref=9
-local s_isol=4  local s_blwf=10
-local s_mark=5  local s_pstf=11
-local s_rest=6
-local states={
-  init=s_init,
-  medi=s_medi,
-  fina=s_fina,
-  isol=s_isol,
-  mark=s_mark,
-  rest=s_rest,
-  rphf=s_rphf,
-  half=s_half,
-  pref=s_pref,
-  blwf=s_blwf,
-  pstf=s_pstf,
-}
-local features={
-  init=s_init,
-  medi=s_medi,
-  fina=s_fina,
-  isol=s_isol,
-  rphf=s_rphf,
-  half=s_half,
-  pref=s_pref,
-  blwf=s_blwf,
-  pstf=s_pstf,
-}
-analyzers.states=states
-analyzers.features=features
-function analyzers.setstate(head,font)
-  local useunicodemarks=analyzers.useunicodemarks
-  local tfmdata=fontdata[font]
-  local descriptions=tfmdata.descriptions
-  local first,last,current,n,done=nil,nil,head,0,false 
-  while current do
-    local id=current.id
-    if id==glyph_code and current.font==font then
-      done=true
-      local char=current.char
-      local d=descriptions[char]
-      if d then
-        if d.class=="mark" or (useunicodemarks and categories[char]=="mn") then
-          done=true
-          current[a_state]=s_mark
-        elseif n==0 then
-          first,last,n=current,current,1
-          current[a_state]=s_init
-        else
-          last,n=current,n+1
-          current[a_state]=s_medi
-        end
-      else 
-        if first and first==last then
-          last[a_state]=s_isol
-        elseif last then
-          last[a_state]=s_fina
-        end
-        first,last,n=nil,nil,0
-      end
-    elseif id==disc_code then
-      current[a_state]=s_medi
-      last=current
-    else 
-      if first and first==last then
-        last[a_state]=s_isol
-      elseif last then
-        last[a_state]=s_fina
-      end
-      first,last,n=nil,nil,0
-      if id==math_code then
-        current=end_of_math(current)
-      end
-    end
-    current=current.next
-  end
-  if first and first==last then
-    last[a_state]=s_isol
-  elseif last then
-    last[a_state]=s_fina
-  end
-  return head,done
-end
-local function analyzeinitializer(tfmdata,value) 
-  local script,language=otf.scriptandlanguage(tfmdata) 
-  local action=initializers[script]
-  if not action then
-  elseif type(action)=="function" then
-    return action(tfmdata,value)
-  else
-    local action=action[language]
-    if action then
-      return action(tfmdata,value)
-    end
-  end
-end
-local function analyzeprocessor(head,font,attr)
-  local tfmdata=fontdata[font]
-  local script,language=otf.scriptandlanguage(tfmdata,attr)
-  local action=methods[script]
-  if not action then
-  elseif type(action)=="function" then
-    return action(head,font,attr)
-  else
-    action=action[language]
-    if action then
-      return action(head,font,attr)
-    end
-  end
-  return head,false
-end
-registerotffeature {
-  name="analyze",
-  description="analysis of character classes",
-  default=true,
-  initializers={
-    node=analyzeinitializer,
-  },
-  processors={
-    position=1,
-    node=analyzeprocessor,
-  }
-}
-methods.latn=analyzers.setstate
-local tatweel=0x0640
-local zwnj=0x200C
-local zwj=0x200D
-local isolated={ 
-  [0x0600]=true,[0x0601]=true,[0x0602]=true,[0x0603]=true,
-  [0x0604]=true,
-  [0x0608]=true,[0x060B]=true,[0x0621]=true,[0x0674]=true,
-  [0x06DD]=true,
-  [0x0856]=true,[0x0858]=true,[0x0857]=true,
-  [0x07FA]=true,
-  [zwnj]=true,
-  [0x08AD]=true,
-}
-local final={ 
-  [0x0622]=true,[0x0623]=true,[0x0624]=true,[0x0625]=true,
-  [0x0627]=true,[0x0629]=true,[0x062F]=true,[0x0630]=true,
-  [0x0631]=true,[0x0632]=true,[0x0648]=true,[0x0671]=true,
-  [0x0672]=true,[0x0673]=true,[0x0675]=true,[0x0676]=true,
-  [0x0677]=true,[0x0688]=true,[0x0689]=true,[0x068A]=true,
-  [0x068B]=true,[0x068C]=true,[0x068D]=true,[0x068E]=true,
-  [0x068F]=true,[0x0690]=true,[0x0691]=true,[0x0692]=true,
-  [0x0693]=true,[0x0694]=true,[0x0695]=true,[0x0696]=true,
-  [0x0697]=true,[0x0698]=true,[0x0699]=true,[0x06C0]=true,
-  [0x06C3]=true,[0x06C4]=true,[0x06C5]=true,[0x06C6]=true,
-  [0x06C7]=true,[0x06C8]=true,[0x06C9]=true,[0x06CA]=true,
-  [0x06CB]=true,[0x06CD]=true,[0x06CF]=true,[0x06D2]=true,
-  [0x06D3]=true,[0x06D5]=true,[0x06EE]=true,[0x06EF]=true,
-  [0x0759]=true,[0x075A]=true,[0x075B]=true,[0x076B]=true,
-  [0x076C]=true,[0x0771]=true,[0x0773]=true,[0x0774]=true,
-  [0x0778]=true,[0x0779]=true,
-  [0x08AA]=true,[0x08AB]=true,[0x08AC]=true,
-  [0xFEF5]=true,[0xFEF7]=true,[0xFEF9]=true,[0xFEFB]=true,
-  [0x0710]=true,[0x0715]=true,[0x0716]=true,[0x0717]=true,
-  [0x0718]=true,[0x0719]=true,[0x0728]=true,[0x072A]=true,
-  [0x072C]=true,[0x071E]=true,
-  [0x072F]=true,[0x074D]=true,
-  [0x0840]=true,[0x0849]=true,[0x0854]=true,[0x0846]=true,
-  [0x084F]=true,
-  [0x08AE]=true,[0x08B1]=true,[0x08B2]=true,
-}
-local medial={ 
-  [0x0626]=true,[0x0628]=true,[0x062A]=true,[0x062B]=true,
-  [0x062C]=true,[0x062D]=true,[0x062E]=true,[0x0633]=true,
-  [0x0634]=true,[0x0635]=true,[0x0636]=true,[0x0637]=true,
-  [0x0638]=true,[0x0639]=true,[0x063A]=true,[0x063B]=true,
-  [0x063C]=true,[0x063D]=true,[0x063E]=true,[0x063F]=true,
-  [0x0641]=true,[0x0642]=true,[0x0643]=true,
-  [0x0644]=true,[0x0645]=true,[0x0646]=true,[0x0647]=true,
-  [0x0649]=true,[0x064A]=true,[0x066E]=true,[0x066F]=true,
-  [0x0678]=true,[0x0679]=true,[0x067A]=true,[0x067B]=true,
-  [0x067C]=true,[0x067D]=true,[0x067E]=true,[0x067F]=true,
-  [0x0680]=true,[0x0681]=true,[0x0682]=true,[0x0683]=true,
-  [0x0684]=true,[0x0685]=true,[0x0686]=true,[0x0687]=true,
-  [0x069A]=true,[0x069B]=true,[0x069C]=true,[0x069D]=true,
-  [0x069E]=true,[0x069F]=true,[0x06A0]=true,[0x06A1]=true,
-  [0x06A2]=true,[0x06A3]=true,[0x06A4]=true,[0x06A5]=true,
-  [0x06A6]=true,[0x06A7]=true,[0x06A8]=true,[0x06A9]=true,
-  [0x06AA]=true,[0x06AB]=true,[0x06AC]=true,[0x06AD]=true,
-  [0x06AE]=true,[0x06AF]=true,[0x06B0]=true,[0x06B1]=true,
-  [0x06B2]=true,[0x06B3]=true,[0x06B4]=true,[0x06B5]=true,
-  [0x06B6]=true,[0x06B7]=true,[0x06B8]=true,[0x06B9]=true,
-  [0x06BA]=true,[0x06BB]=true,[0x06BC]=true,[0x06BD]=true,
-  [0x06BE]=true,[0x06BF]=true,[0x06C1]=true,[0x06C2]=true,
-  [0x06CC]=true,[0x06CE]=true,[0x06D0]=true,[0x06D1]=true,
-  [0x06FA]=true,[0x06FB]=true,[0x06FC]=true,[0x06FF]=true,
-  [0x0750]=true,[0x0751]=true,[0x0752]=true,[0x0753]=true,
-  [0x0754]=true,[0x0755]=true,[0x0756]=true,[0x0757]=true,
-  [0x0758]=true,[0x075C]=true,[0x075D]=true,[0x075E]=true,
-  [0x075F]=true,[0x0760]=true,[0x0761]=true,[0x0762]=true,
-  [0x0763]=true,[0x0764]=true,[0x0765]=true,[0x0766]=true,
-  [0x0767]=true,[0x0768]=true,[0x0769]=true,[0x076A]=true,
-  [0x076D]=true,[0x076E]=true,[0x076F]=true,[0x0770]=true,
-  [0x0772]=true,[0x0775]=true,[0x0776]=true,[0x0777]=true,
-  [0x077A]=true,[0x077B]=true,[0x077C]=true,[0x077D]=true,
-  [0x077E]=true,[0x077F]=true,
-  [0x08A0]=true,[0x08A2]=true,[0x08A4]=true,[0x08A5]=true,
-  [0x08A6]=true,[0x0620]=true,[0x08A8]=true,[0x08A9]=true,
-  [0x08A7]=true,[0x08A3]=true,
-  [0x0712]=true,[0x0713]=true,[0x0714]=true,[0x071A]=true,
-  [0x071B]=true,[0x071C]=true,[0x071D]=true,[0x071F]=true,
-  [0x0720]=true,[0x0721]=true,[0x0722]=true,[0x0723]=true,
-  [0x0724]=true,[0x0725]=true,[0x0726]=true,[0x0727]=true,
-  [0x0729]=true,[0x072B]=true,[0x072D]=true,[0x072E]=true,
-  [0x074E]=true,[0x074F]=true,
-  [0x0841]=true,[0x0842]=true,[0x0843]=true,[0x0844]=true,
-  [0x0845]=true,[0x0847]=true,[0x0848]=true,[0x0855]=true,
-  [0x0851]=true,[0x084E]=true,[0x084D]=true,[0x084A]=true,
-  [0x084B]=true,[0x084C]=true,[0x0850]=true,[0x0852]=true,
-  [0x0853]=true,
-  [0x07D7]=true,[0x07E8]=true,[0x07D9]=true,[0x07EA]=true,
-  [0x07CA]=true,[0x07DB]=true,[0x07CC]=true,[0x07DD]=true,
-  [0x07CE]=true,[0x07DF]=true,[0x07D4]=true,[0x07E5]=true,
-  [0x07E9]=true,[0x07E7]=true,[0x07E3]=true,[0x07E2]=true,
-  [0x07E0]=true,[0x07E1]=true,[0x07DE]=true,[0x07DC]=true,
-  [0x07D1]=true,[0x07DA]=true,[0x07D8]=true,[0x07D6]=true,
-  [0x07D2]=true,[0x07D0]=true,[0x07CF]=true,[0x07CD]=true,
-  [0x07CB]=true,[0x07D3]=true,[0x07E4]=true,[0x07D5]=true,
-  [0x07E6]=true,
-  [tatweel]=true,[zwj]=true,
-  [0x08A1]=true,[0x08AF]=true,[0x08B0]=true,
-}
-local arab_warned={}
-local function warning(current,what)
-  local char=current.char
-  if not arab_warned[char] then
-    log.report("analyze","arab: character %C has no %a class",char,what)
-    arab_warned[char]=true
-  end
-end
-local function finish(first,last)
-  if last then
-    if first==last then
-      local fc=first.char
-      if medial[fc] or final[fc] then
-        first[a_state]=s_isol
-      else
-        warning(first,"isol")
-        first[a_state]=s_error
-      end
-    else
-      local lc=last.char
-      if medial[lc] or final[lc] then
-        last[a_state]=s_fina
-      else
-        warning(last,"fina")
-        last[a_state]=s_error
-      end
-    end
-    first,last=nil,nil
-  elseif first then
-    local fc=first.char
-    if medial[fc] or final[fc] then
-      first[a_state]=s_isol
-    else
-      warning(first,"isol")
-      first[a_state]=s_error
-    end
-    first=nil
-  end
-  return first,last
-end
-function methods.arab(head,font,attr)
-  local useunicodemarks=analyzers.useunicodemarks
-  local tfmdata=fontdata[font]
-  local marks=tfmdata.resources.marks
-  local first,last,current,done=nil,nil,head,false
-  while current do
-    local id=current.id
-    if id==glyph_code and current.font==font and current.subtype<256 and not current[a_state] then
-      done=true
-      local char=current.char
-      if marks[char] or (useunicodemarks and categories[char]=="mn") then
-        current[a_state]=s_mark
-      elseif isolated[char] then 
-        first,last=finish(first,last)
-        current[a_state]=s_isol
-        first,last=nil,nil
-      elseif not first then
-        if medial[char] then
-          current[a_state]=s_init
-          first,last=first or current,current
-        elseif final[char] then
-          current[a_state]=s_isol
-          first,last=nil,nil
-        else 
-          first,last=finish(first,last)
-        end
-      elseif medial[char] then
-        first,last=first or current,current
-        current[a_state]=s_medi
-      elseif final[char] then
-        if not last[a_state]==s_init then
-          last[a_state]=s_medi
-        end
-        current[a_state]=s_fina
-        first,last=nil,nil
-      elseif char>=0x0600 and char<=0x06FF then 
-        current[a_state]=s_rest
-        first,last=finish(first,last)
-      else 
-        first,last=finish(first,last)
-      end
-    else
-      if first or last then
-        first,last=finish(first,last)
-      end
-      if id==math_code then
-        current=end_of_math(current)
-      end
-    end
-    current=current.next
-  end
-  if first or last then
-    finish(first,last)
-  end
-  return head,done
-end
-methods.syrc=methods.arab
-methods.mand=methods.arab
-methods.nko=methods.arab
-directives.register("otf.analyze.useunicodemarks",function(v)
-  analyzers.useunicodemarks=v
-end)
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['font-otn']={
-  version=1.001,
-  comment="companion to font-ini.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files",
-}
-local concat,insert,remove=table.concat,table.insert,table.remove
-local gmatch,gsub,find,match,lower,strip=string.gmatch,string.gsub,string.find,string.match,string.lower,string.strip
-local type,next,tonumber,tostring=type,next,tonumber,tostring
-local lpegmatch=lpeg.match
-local random=math.random
-local formatters=string.formatters
-local logs,trackers,nodes,attributes=logs,trackers,nodes,attributes
-local registertracker=trackers.register
-local fonts=fonts
-local otf=fonts.handlers.otf
-local trace_lookups=false registertracker("otf.lookups",function(v) trace_lookups=v end)
-local trace_singles=false registertracker("otf.singles",function(v) trace_singles=v end)
-local trace_multiples=false registertracker("otf.multiples",function(v) trace_multiples=v end)
-local trace_alternatives=false registertracker("otf.alternatives",function(v) trace_alternatives=v end)
-local trace_ligatures=false registertracker("otf.ligatures",function(v) trace_ligatures=v end)
-local trace_contexts=false registertracker("otf.contexts",function(v) trace_contexts=v end)
-local trace_marks=false registertracker("otf.marks",function(v) trace_marks=v end)
-local trace_kerns=false registertracker("otf.kerns",function(v) trace_kerns=v end)
-local trace_cursive=false registertracker("otf.cursive",function(v) trace_cursive=v end)
-local trace_preparing=false registertracker("otf.preparing",function(v) trace_preparing=v end)
-local trace_bugs=false registertracker("otf.bugs",function(v) trace_bugs=v end)
-local trace_details=false registertracker("otf.details",function(v) trace_details=v end)
-local trace_applied=false registertracker("otf.applied",function(v) trace_applied=v end)
-local trace_steps=false registertracker("otf.steps",function(v) trace_steps=v end)
-local trace_skips=false registertracker("otf.skips",function(v) trace_skips=v end)
-local trace_directions=false registertracker("otf.directions",function(v) trace_directions=v end)
-local report_direct=logs.reporter("fonts","otf direct")
-local report_subchain=logs.reporter("fonts","otf subchain")
-local report_chain=logs.reporter("fonts","otf chain")
-local report_process=logs.reporter("fonts","otf process")
-local report_prepare=logs.reporter("fonts","otf prepare")
-local report_warning=logs.reporter("fonts","otf warning")
-registertracker("otf.verbose_chain",function(v) otf.setcontextchain(v and "verbose") end)
-registertracker("otf.normal_chain",function(v) otf.setcontextchain(v and "normal") end)
-registertracker("otf.replacements","otf.singles,otf.multiples,otf.alternatives,otf.ligatures")
-registertracker("otf.positions","otf.marks,otf.kerns,otf.cursive")
-registertracker("otf.actions","otf.replacements,otf.positions")
-registertracker("otf.injections","nodes.injections")
-registertracker("*otf.sample","otf.steps,otf.actions,otf.analyzing")
-local insert_node_after=node.insert_after
-local delete_node=nodes.delete
-local copy_node=node.copy
-local find_node_tail=node.tail or node.slide
-local flush_node_list=node.flush_list
-local end_of_math=node.end_of_math
-local setmetatableindex=table.setmetatableindex
-local zwnj=0x200C
-local zwj=0x200D
-local wildcard="*"
-local default="dflt"
-local nodecodes=nodes.nodecodes
-local whatcodes=nodes.whatcodes
-local glyphcodes=nodes.glyphcodes
-local disccodes=nodes.disccodes
-local glyph_code=nodecodes.glyph
-local glue_code=nodecodes.glue
-local disc_code=nodecodes.disc
-local whatsit_code=nodecodes.whatsit
-local math_code=nodecodes.math
-local dir_code=whatcodes.dir
-local localpar_code=whatcodes.localpar
-local discretionary_code=disccodes.discretionary
-local ligature_code=glyphcodes.ligature
-local privateattribute=attributes.private
-local a_state=privateattribute('state')
-local a_markbase=privateattribute('markbase')
-local a_markmark=privateattribute('markmark')
-local a_markdone=privateattribute('markdone') 
-local a_cursbase=privateattribute('cursbase')
-local a_curscurs=privateattribute('curscurs')
-local a_cursdone=privateattribute('cursdone')
-local a_kernpair=privateattribute('kernpair')
-local a_ligacomp=privateattribute('ligacomp') 
-local injections=nodes.injections
-local setmark=injections.setmark
-local setcursive=injections.setcursive
-local setkern=injections.setkern
-local setpair=injections.setpair
-local markonce=true
-local cursonce=true
-local kernonce=true
-local fonthashes=fonts.hashes
-local fontdata=fonthashes.identifiers
-local otffeatures=fonts.constructors.newfeatures("otf")
-local registerotffeature=otffeatures.register
-local onetimemessage=fonts.loggers.onetimemessage or function() end
-otf.defaultnodealternate="none"
-local tfmdata=false
-local characters=false
-local descriptions=false
-local resources=false
-local marks=false
-local currentfont=false
-local lookuptable=false
-local anchorlookups=false
-local lookuptypes=false
-local handlers={}
-local rlmode=0
-local featurevalue=false
-local checkstep=(nodes and nodes.tracers and nodes.tracers.steppers.check)  or function() end
-local registerstep=(nodes and nodes.tracers and nodes.tracers.steppers.register) or function() end
-local registermessage=(nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end
-local function logprocess(...)
-  if trace_steps then
-    registermessage(...)
-  end
-  report_direct(...)
-end
-local function logwarning(...)
-  report_direct(...)
-end
-local f_unicode=formatters["%U"]
-local f_uniname=formatters["%U (%s)"]
-local f_unilist=formatters["% t (% t)"]
-local function gref(n) 
-  if type(n)=="number" then
-    local description=descriptions[n]
-    local name=description and description.name
-    if name then
-      return f_uniname(n,name)
-    else
-      return f_unicode(n)
-    end
-  elseif n then
-    local num,nam={},{}
-    for i=1,#n do
-      local ni=n[i]
-      if tonumber(ni) then 
-        local di=descriptions[ni]
-        num[i]=f_unicode(ni)
-        nam[i]=di and di.name or "-"
-      end
-    end
-    return f_unilist(num,nam)
-  else
-    return "<error in node mode tracing>"
-  end
-end
-local function cref(kind,chainname,chainlookupname,lookupname,index) 
-  if index then
-    return formatters["feature %a, chain %a, sub %a, lookup %a, index %a"](kind,chainname,chainlookupname,lookupname,index)
-  elseif lookupname then
-    return formatters["feature %a, chain %a, sub %a, lookup %a"](kind,chainname,chainlookupname,lookupname)
-  elseif chainlookupname then
-    return formatters["feature %a, chain %a, sub %a"](kind,chainname,chainlookupname)
-  elseif chainname then
-    return formatters["feature %a, chain %a"](kind,chainname)
-  else
-    return formatters["feature %a"](kind)
-  end
-end
-local function pref(kind,lookupname)
-  return formatters["feature %a, lookup %a"](kind,lookupname)
-end
-local function copy_glyph(g) 
-  local components=g.components
-  if components then
-    g.components=nil
-    local n=copy_node(g)
-    g.components=components
-    return n
-  else
-    return copy_node(g)
-  end
-end
-local function markstoligature(kind,lookupname,head,start,stop,char)
-  if start==stop and start.char==char then
-    return head,start
-  else
-    local prev=start.prev
-    local next=stop.next
-    start.prev=nil
-    stop.next=nil
-    local base=copy_glyph(start)
-    if head==start then
-      head=base
-    end
-    base.char=char
-    base.subtype=ligature_code
-    base.components=start
-    if prev then
-      prev.next=base
-    end
-    if next then
-      next.prev=base
-    end
-    base.next=next
-    base.prev=prev
-    return head,base
-  end
-end
-local function getcomponentindex(start)
-  if start.id~=glyph_code then
-    return 0
-  elseif start.subtype==ligature_code then
-    local i=0
-    local components=start.components
-    while components do
-      i=i+getcomponentindex(components)
-      components=components.next
-    end
-    return i
-  elseif not marks[start.char] then
-    return 1
-  else
-    return 0
-  end
-end
-local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound) 
-  if start==stop and start.char==char then
-    start.char=char
-    return head,start
-  end
-  local prev=start.prev
-  local next=stop.next
-  start.prev=nil
-  stop.next=nil
-  local base=copy_glyph(start)
-  if start==head then
-    head=base
-  end
-  base.char=char
-  base.subtype=ligature_code
-  base.components=start 
-  if prev then
-    prev.next=base
-  end
-  if next then
-    next.prev=base
-  end
-  base.next=next
-  base.prev=prev
-  if not discfound then
-    local deletemarks=markflag~="mark"
-    local components=start
-    local baseindex=0
-    local componentindex=0
-    local head=base
-    local current=base
-    while start do
-      local char=start.char
-      if not marks[char] then
-        baseindex=baseindex+componentindex
-        componentindex=getcomponentindex(start)
-      elseif not deletemarks then 
-        start[a_ligacomp]=baseindex+(start[a_ligacomp] or componentindex)
-        if trace_marks then
-          logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),start[a_ligacomp])
-        end
-        head,current=insert_node_after(head,current,copy_node(start)) 
-      elseif trace_marks then
-        logwarning("%s: delete mark %s",pref(kind,lookupname),gref(char))
-      end
-      start=start.next
-    end
-    local start=current.next
-    while start and start.id==glyph_code do
-      local char=start.char
-      if marks[char] then
-        start[a_ligacomp]=baseindex+(start[a_ligacomp] or componentindex)
-        if trace_marks then
-          logwarning("%s: set mark %s, gets index %s",pref(kind,lookupname),gref(char),start[a_ligacomp])
-        end
-      else
-        break
-      end
-      start=start.next
-    end
-  end
-  return head,base
-end
-function handlers.gsub_single(head,start,kind,lookupname,replacement)
-  if trace_singles then
-    logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(start.char),gref(replacement))
-  end
-  start.char=replacement
-  return head,start,true
-end
-local function get_alternative_glyph(start,alternatives,value,trace_alternatives)
-  local n=#alternatives
-  if value=="random" then
-    local r=random(1,n)
-    return alternatives[r],trace_alternatives and formatters["value %a, taking %a"](value,r)
-  elseif value=="first" then
-    return alternatives[1],trace_alternatives and formatters["value %a, taking %a"](value,1)
-  elseif value=="last" then
-    return alternatives[n],trace_alternatives and formatters["value %a, taking %a"](value,n)
-  else
-    value=tonumber(value)
-    if type(value)~="number" then
-      return alternatives[1],trace_alternatives and formatters["invalid value %s, taking %a"](value,1)
-    elseif value>n then
-      local defaultalt=otf.defaultnodealternate
-      if defaultalt=="first" then
-        return alternatives[n],trace_alternatives and formatters["invalid value %s, taking %a"](value,1)
-      elseif defaultalt=="last" then
-        return alternatives[1],trace_alternatives and formatters["invalid value %s, taking %a"](value,n)
-      else
-        return false,trace_alternatives and formatters["invalid value %a, %s"](value,"out of range")
-      end
-    elseif value==0 then
-      return start.char,trace_alternatives and formatters["invalid value %a, %s"](value,"no change")
-    elseif value<1 then
-      return alternatives[1],trace_alternatives and formatters["invalid value %a, taking %a"](value,1)
-    else
-      return alternatives[value],trace_alternatives and formatters["value %a, taking %a"](value,value)
-    end
-  end
-end
-local function multiple_glyphs(head,start,multiple,ignoremarks)
-  local nofmultiples=#multiple
-  if nofmultiples>0 then
-    start.char=multiple[1]
-    if nofmultiples>1 then
-      local sn=start.next
-      for k=2,nofmultiples do
-        local n=copy_node(start) 
-        n.char=multiple[k]
-        n.next=sn
-        n.prev=start
-        if sn then
-          sn.prev=n
-        end
-        start.next=n
-        start=n
-      end
-    end
-    return head,start,true
-  else
-    if trace_multiples then
-      logprocess("no multiple for %s",gref(start.char))
-    end
-    return head,start,false
-  end
-end
-function handlers.gsub_alternate(head,start,kind,lookupname,alternative,sequence)
-  local value=featurevalue==true and tfmdata.shared.features[kind] or featurevalue
-  local choice,comment=get_alternative_glyph(start,alternative,value,trace_alternatives)
-  if choice then
-    if trace_alternatives then
-      logprocess("%s: replacing %s by alternative %a to %s, %s",pref(kind,lookupname),gref(start.char),choice,gref(choice),comment)
-    end
-    start.char=choice
-  else
-    if trace_alternatives then
-      logwarning("%s: no variant %a for %s, %s",pref(kind,lookupname),value,gref(start.char),comment)
-    end
-  end
-  return head,start,true
-end
-function handlers.gsub_multiple(head,start,kind,lookupname,multiple,sequence)
-  if trace_multiples then
-    logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(start.char),gref(multiple))
-  end
-  return multiple_glyphs(head,start,multiple,sequence.flags[1])
-end
-function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
-  local s,stop,discfound=start.next,nil,false
-  local startchar=start.char
-  if marks[startchar] then
-    while s do
-      local id=s.id
-      if id==glyph_code and s.font==currentfont and s.subtype<256 then
-        local lg=ligature[s.char]
-        if lg then
-          stop=s
-          ligature=lg
-          s=s.next
-        else
-          break
-        end
-      else
-        break
-      end
-    end
-    if stop then
-      local lig=ligature.ligature
-      if lig then
-        if trace_ligatures then
-          local stopchar=stop.char
-          head,start=markstoligature(kind,lookupname,head,start,stop,lig)
-          logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
-        else
-          head,start=markstoligature(kind,lookupname,head,start,stop,lig)
-        end
-        return head,start,true
-      else
-      end
-    end
-  else
-    local skipmark=sequence.flags[1]
-    while s do
-      local id=s.id
-      if id==glyph_code and s.subtype<256 then
-        if s.font==currentfont then
-          local char=s.char
-          if skipmark and marks[char] then
-            s=s.next
-          else
-            local lg=ligature[char]
-            if lg then
-              stop=s
-              ligature=lg
-              s=s.next
-            else
-              break
-            end
-          end
-        else
-          break
-        end
-      elseif id==disc_code then
-        discfound=true
-        s=s.next
-      else
-        break
-      end
-    end
-    local lig=ligature.ligature
-    if lig then
-      if stop then
-        if trace_ligatures then
-          local stopchar=stop.char
-          head,start=toligature(kind,lookupname,head,start,stop,lig,skipmark,discfound)
-          logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
-        else
-          head,start=toligature(kind,lookupname,head,start,stop,lig,skipmark,discfound)
-        end
-        return head,start,true
-      else
-        start.char=lig
-        if trace_ligatures then
-          logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(kind,lookupname),gref(startchar),gref(lig))
-        end
-        return head,start,true
-      end
-    else
-    end
-  end
-  return head,start,false
-end
-function handlers.gpos_mark2base(head,start,kind,lookupname,markanchors,sequence)
-  local markchar=start.char
-  if marks[markchar] then
-    local base=start.prev 
-    if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
-      local basechar=base.char
-      if marks[basechar] then
-        while true do
-          base=base.prev
-          if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
-            basechar=base.char
-            if not marks[basechar] then
-              break
-            end
-          else
-            if trace_bugs then
-              logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar))
-            end
-            return head,start,false
-          end
-        end
-      end
-      local baseanchors=descriptions[basechar]
-      if baseanchors then
-        baseanchors=baseanchors.anchors
-      end
-      if baseanchors then
-        local baseanchors=baseanchors['basechar']
-        if baseanchors then
-          local al=anchorlookups[lookupname]
-          for anchor,ba in next,baseanchors do
-            if al[anchor] then
-              local ma=markanchors[anchor]
-              if ma then
-                local dx,dy,bound=setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma)
-                if trace_marks then
-                  logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)",
-                    pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
-                end
-                return head,start,true
-              end
-            end
-          end
-          if trace_bugs then
-            logwarning("%s, no matching anchors for mark %s and base %s",pref(kind,lookupname),gref(markchar),gref(basechar))
-          end
-        end
-      elseif trace_bugs then
-        onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
-      end
-    elseif trace_bugs then
-      logwarning("%s: prev node is no char",pref(kind,lookupname))
-    end
-  elseif trace_bugs then
-    logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
-  end
-  return head,start,false
-end
-function handlers.gpos_mark2ligature(head,start,kind,lookupname,markanchors,sequence)
-  local markchar=start.char
-  if marks[markchar] then
-    local base=start.prev 
-    if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
-      local basechar=base.char
-      if marks[basechar] then
-        while true do
-          base=base.prev
-          if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
-            basechar=base.char
-            if not marks[basechar] then
-              break
-            end
-          else
-            if trace_bugs then
-              logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar))
-            end
-            return head,start,false
-          end
-        end
-      end
-      local index=start[a_ligacomp]
-      local baseanchors=descriptions[basechar]
-      if baseanchors then
-        baseanchors=baseanchors.anchors
-        if baseanchors then
-          local baseanchors=baseanchors['baselig']
-          if baseanchors then
-            local al=anchorlookups[lookupname]
-            for anchor,ba in next,baseanchors do
-              if al[anchor] then
-                local ma=markanchors[anchor]
-                if ma then
-                  ba=ba[index]
-                  if ba then
-                    local dx,dy,bound=setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma) 
-                    if trace_marks then
-                      logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)",
-                        pref(kind,lookupname),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy)
-                    end
-                    return head,start,true
-                  else
-                    if trace_bugs then
-                      logwarning("%s: no matching anchors for mark %s and baselig %s with index %a",pref(kind,lookupname),gref(markchar),gref(basechar),index)
-                    end
-                  end
-                end
-              end
-            end
-            if trace_bugs then
-              logwarning("%s: no matching anchors for mark %s and baselig %s",pref(kind,lookupname),gref(markchar),gref(basechar))
-            end
-          end
-        end
-      elseif trace_bugs then
-        onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
-      end
-    elseif trace_bugs then
-      logwarning("%s: prev node is no char",pref(kind,lookupname))
-    end
-  elseif trace_bugs then
-    logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
-  end
-  return head,start,false
-end
-function handlers.gpos_mark2mark(head,start,kind,lookupname,markanchors,sequence)
-  local markchar=start.char
-  if marks[markchar] then
-    local base=start.prev 
-    local slc=start[a_ligacomp]
-    if slc then 
-      while base do
-        local blc=base[a_ligacomp]
-        if blc and blc~=slc then
-          base=base.prev
-        else
-          break
-        end
-      end
-    end
-    if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then 
-      local basechar=base.char
-      local baseanchors=descriptions[basechar]
-      if baseanchors then
-        baseanchors=baseanchors.anchors
-        if baseanchors then
-          baseanchors=baseanchors['basemark']
-          if baseanchors then
-            local al=anchorlookups[lookupname]
-            for anchor,ba in next,baseanchors do
-              if al[anchor] then
-                local ma=markanchors[anchor]
-                if ma then
-                  local dx,dy,bound=setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,true)
-                  if trace_marks then
-                    logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
-                      pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
-                  end
-                  return head,start,true
-                end
-              end
-            end
-            if trace_bugs then
-              logwarning("%s: no matching anchors for mark %s and basemark %s",pref(kind,lookupname),gref(markchar),gref(basechar))
-            end
-          end
-        end
-      elseif trace_bugs then
-        onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
-      end
-    elseif trace_bugs then
-      logwarning("%s: prev node is no mark",pref(kind,lookupname))
-    end
-  elseif trace_bugs then
-    logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
-  end
-  return head,start,false
-end
-function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence) 
-  local alreadydone=cursonce and start[a_cursbase]
-  if not alreadydone then
-    local done=false
-    local startchar=start.char
-    if marks[startchar] then
-      if trace_cursive then
-        logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar))
-      end
-    else
-      local nxt=start.next
-      while not done and nxt and nxt.id==glyph_code and nxt.font==currentfont and nxt.subtype<256 do
-        local nextchar=nxt.char
-        if marks[nextchar] then
-          nxt=nxt.next
-        else
-          local entryanchors=descriptions[nextchar]
-          if entryanchors then
-            entryanchors=entryanchors.anchors
-            if entryanchors then
-              entryanchors=entryanchors['centry']
-              if entryanchors then
-                local al=anchorlookups[lookupname]
-                for anchor,entry in next,entryanchors do
-                  if al[anchor] then
-                    local exit=exitanchors[anchor]
-                    if exit then
-                      local dx,dy,bound=setcursive(start,nxt,tfmdata.parameters.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
-                      if trace_cursive then
-                        logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode)
-                      end
-                      done=true
-                      break
-                    end
-                  end
-                end
-              end
-            end
-          elseif trace_bugs then
-            onetimemessage(currentfont,startchar,"no entry anchors",report_fonts)
-          end
-          break
-        end
-      end
-    end
-    return head,start,done
-  else
-    if trace_cursive and trace_details then
-      logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone)
-    end
-    return head,start,false
-  end
-end
-function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence)
-  local startchar=start.char
-  local dx,dy,w,h=setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
-  if trace_kerns then
-    logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),dx,dy,w,h)
-  end
-  return head,start,false
-end
-function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)
-  local snext=start.next
-  if not snext then
-    return head,start,false
-  else
-    local prev,done=start,false
-    local factor=tfmdata.parameters.factor
-    local lookuptype=lookuptypes[lookupname]
-    while snext and snext.id==glyph_code and snext.font==currentfont and snext.subtype<256 do
-      local nextchar=snext.char
-      local krn=kerns[nextchar]
-      if not krn and marks[nextchar] then
-        prev=snext
-        snext=snext.next
-      else
-        if not krn then
-        elseif type(krn)=="table" then
-          if lookuptype=="pair" then 
-            local a,b=krn[2],krn[3]
-            if a and #a>0 then
-              local startchar=start.char
-              local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
-              if trace_kerns then
-                logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
-              end
-            end
-            if b and #b>0 then
-              local startchar=start.char
-              local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar])
-              if trace_kerns then
-                logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
-              end
-            end
-          else 
-            report_process("%s: check this out (old kern stuff)",pref(kind,lookupname))
-          end
-          done=true
-        elseif krn~=0 then
-          local k=setkern(snext,factor,rlmode,krn)
-          if trace_kerns then
-            logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar))
-          end
-          done=true
-        end
-        break
-      end
-    end
-    return head,start,done
-  end
-end
-local chainmores={}
-local chainprocs={}
-local function logprocess(...)
-  if trace_steps then
-    registermessage(...)
-  end
-  report_subchain(...)
-end
-local logwarning=report_subchain
-local function logprocess(...)
-  if trace_steps then
-    registermessage(...)
-  end
-  report_chain(...)
-end
-local logwarning=report_chain
-function chainprocs.chainsub(head,start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname)
-  logwarning("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
-  return head,start,false
-end
-function chainmores.chainsub(head,start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname,n)
-  logprocess("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
-  return head,start,false
-end
-function chainprocs.reversesub(head,start,stop,kind,chainname,currentcontext,lookuphash,replacements)
-  local char=start.char
-  local replacement=replacements[char]
-  if replacement then
-    if trace_singles then
-      logprocess("%s: single reverse replacement of %s by %s",cref(kind,chainname),gref(char),gref(replacement))
-    end
-    start.char=replacement
-    return head,start,true
-  else
-    return head,start,false
-  end
-end
-function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)
-  local current=start
-  local subtables=currentlookup.subtables
-  if #subtables>1 then
-    logwarning("todo: check if we need to loop over the replacements: %s",concat(subtables," "))
-  end
-  while current do
-    if current.id==glyph_code then
-      local currentchar=current.char
-      local lookupname=subtables[1] 
-      local replacement=lookuphash[lookupname]
-      if not replacement then
-        if trace_bugs then
-          logwarning("%s: no single hits",cref(kind,chainname,chainlookupname,lookupname,chainindex))
-        end
-      else
-        replacement=replacement[currentchar]
-        if not replacement or replacement=="" then
-          if trace_bugs then
-            logwarning("%s: no single for %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar))
-          end
-        else
-          if trace_singles then
-            logprocess("%s: replacing single %s by %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar),gref(replacement))
-          end
-          current.char=replacement
-        end
-      end
-      return head,start,true
-    elseif current==stop then
-      break
-    else
-      current=current.next
-    end
-  end
-  return head,start,false
-end
-chainmores.gsub_single=chainprocs.gsub_single
-function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
-  local startchar=start.char
-  local subtables=currentlookup.subtables
-  local lookupname=subtables[1]
-  local replacements=lookuphash[lookupname]
-  if not replacements then
-    if trace_bugs then
-      logwarning("%s: no multiple hits",cref(kind,chainname,chainlookupname,lookupname))
-    end
-  else
-    replacements=replacements[startchar]
-    if not replacements or replacement=="" then
-      if trace_bugs then
-        logwarning("%s: no multiple for %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar))
-      end
-    else
-      if trace_multiples then
-        logprocess("%s: replacing %s by multiple characters %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar),gref(replacements))
-      end
-      return multiple_glyphs(head,start,replacements,currentlookup.flags[1])
-    end
-  end
-  return head,start,false
-end
-chainmores.gsub_multiple=chainprocs.gsub_multiple
-function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
-  local current=start
-  local subtables=currentlookup.subtables
-  local value=featurevalue==true and tfmdata.shared.features[kind] or featurevalue
-  while current do
-    if current.id==glyph_code then 
-      local currentchar=current.char
-      local lookupname=subtables[1]
-      local alternatives=lookuphash[lookupname]
-      if not alternatives then
-        if trace_bugs then
-          logwarning("%s: no alternative hit",cref(kind,chainname,chainlookupname,lookupname))
-        end
-      else
-        alternatives=alternatives[currentchar]
-        if alternatives then
-          local choice,comment=get_alternative_glyph(current,alternatives,value,trace_alternatives)
-          if choice then
-            if trace_alternatives then
-              logprocess("%s: replacing %s by alternative %a to %s, %s",cref(kind,chainname,chainlookupname,lookupname),gref(char),choice,gref(choice),comment)
-            end
-            start.char=choice
-          else
-            if trace_alternatives then
-              logwarning("%s: no variant %a for %s, %s",cref(kind,chainname,chainlookupname,lookupname),value,gref(char),comment)
-            end
-          end
-        elseif trace_bugs then
-          logwarning("%s: no alternative for %s, %s",cref(kind,chainname,chainlookupname,lookupname),gref(currentchar),comment)
-        end
-      end
-      return head,start,true
-    elseif current==stop then
-      break
-    else
-      current=current.next
-    end
-  end
-  return head,start,false
-end
-chainmores.gsub_alternate=chainprocs.gsub_alternate
-function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)
-  local startchar=start.char
-  local subtables=currentlookup.subtables
-  local lookupname=subtables[1]
-  local ligatures=lookuphash[lookupname]
-  if not ligatures then
-    if trace_bugs then
-      logwarning("%s: no ligature hits",cref(kind,chainname,chainlookupname,lookupname,chainindex))
-    end
-  else
-    ligatures=ligatures[startchar]
-    if not ligatures then
-      if trace_bugs then
-        logwarning("%s: no ligatures starting with %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
-      end
-    else
-      local s=start.next
-      local discfound=false
-      local last=stop
-      local nofreplacements=0
-      local skipmark=currentlookup.flags[1]
-      while s do
-        local id=s.id
-        if id==disc_code then
-          s=s.next
-          discfound=true
-        else
-          local schar=s.char
-          if skipmark and marks[schar] then 
-            s=s.next
-          else
-            local lg=ligatures[schar]
-            if lg then
-              ligatures,last,nofreplacements=lg,s,nofreplacements+1
-              if s==stop then
-                break
-              else
-                s=s.next
-              end
-            else
-              break
-            end
-          end
-        end
-      end
-      local l2=ligatures.ligature
-      if l2 then
-        if chainindex then
-          stop=last
-        end
-        if trace_ligatures then
-          if start==stop then
-            logprocess("%s: replacing character %s by ligature %s case 3",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(l2))
-          else
-            logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char),gref(l2))
-          end
-        end
-        head,start=toligature(kind,lookupname,head,start,stop,l2,currentlookup.flags[1],discfound)
-        return head,start,true,nofreplacements
-      elseif trace_bugs then
-        if start==stop then
-          logwarning("%s: replacing character %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
-        else
-          logwarning("%s: replacing character %s upto %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char))
-        end
-      end
-    end
-  end
-  return head,start,false,0
-end
-chainmores.gsub_ligature=chainprocs.gsub_ligature
-function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
-  local markchar=start.char
-  if marks[markchar] then
-    local subtables=currentlookup.subtables
-    local lookupname=subtables[1]
-    local markanchors=lookuphash[lookupname]
-    if markanchors then
-      markanchors=markanchors[markchar]
-    end
-    if markanchors then
-      local base=start.prev 
-      if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
-        local basechar=base.char
-        if marks[basechar] then
-          while true do
-            base=base.prev
-            if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
-              basechar=base.char
-              if not marks[basechar] then
-                break
-              end
-            else
-              if trace_bugs then
-                logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar))
-              end
-              return head,start,false
-            end
-          end
-        end
-        local baseanchors=descriptions[basechar].anchors
-        if baseanchors then
-          local baseanchors=baseanchors['basechar']
-          if baseanchors then
-            local al=anchorlookups[lookupname]
-            for anchor,ba in next,baseanchors do
-              if al[anchor] then
-                local ma=markanchors[anchor]
-                if ma then
-                  local dx,dy,bound=setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma)
-                  if trace_marks then
-                    logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)",
-                      cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
-                  end
-                  return head,start,true
-                end
-              end
-            end
-            if trace_bugs then
-              logwarning("%s, no matching anchors for mark %s and base %s",cref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar))
-            end
-          end
-        end
-      elseif trace_bugs then
-        logwarning("%s: prev node is no char",cref(kind,chainname,chainlookupname,lookupname))
-      end
-    elseif trace_bugs then
-      logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar))
-    end
-  elseif trace_bugs then
-    logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))
-  end
-  return head,start,false
-end
-function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
-  local markchar=start.char
-  if marks[markchar] then
-    local subtables=currentlookup.subtables
-    local lookupname=subtables[1]
-    local markanchors=lookuphash[lookupname]
-    if markanchors then
-      markanchors=markanchors[markchar]
-    end
-    if markanchors then
-      local base=start.prev 
-      if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
-        local basechar=base.char
-        if marks[basechar] then
-          while true do
-            base=base.prev
-            if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
-              basechar=base.char
-              if not marks[basechar] then
-                break
-              end
-            else
-              if trace_bugs then
-                logwarning("%s: no base for mark %s",cref(kind,chainname,chainlookupname,lookupname),markchar)
-              end
-              return head,start,false
-            end
-          end
-        end
-        local index=start[a_ligacomp]
-        local baseanchors=descriptions[basechar].anchors
-        if baseanchors then
-          local baseanchors=baseanchors['baselig']
-          if baseanchors then
-            local al=anchorlookups[lookupname]
-            for anchor,ba in next,baseanchors do
-              if al[anchor] then
-                local ma=markanchors[anchor]
-                if ma then
-                  ba=ba[index]
-                  if ba then
-                    local dx,dy,bound=setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma) 
-                    if trace_marks then
-                      logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)",
-                        cref(kind,chainname,chainlookupname,lookupname),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy)
-                    end
-                    return head,start,true
-                  end
-                end
-              end
-            end
-            if trace_bugs then
-              logwarning("%s: no matching anchors for mark %s and baselig %s",cref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar))
-            end
-          end
-        end
-      elseif trace_bugs then
-        logwarning("feature %s, lookup %s: prev node is no char",kind,lookupname)
-      end
-    elseif trace_bugs then
-      logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar))
-    end
-  elseif trace_bugs then
-    logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))
-  end
-  return head,start,false
-end
-function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
-  local markchar=start.char
-  if marks[markchar] then
-      local subtables=currentlookup.subtables
-      local lookupname=subtables[1]
-      local markanchors=lookuphash[lookupname]
-      if markanchors then
-        markanchors=markanchors[markchar]
-      end
-      if markanchors then
-        local base=start.prev 
-        local slc=start[a_ligacomp]
-        if slc then 
-          while base do
-            local blc=base[a_ligacomp]
-            if blc and blc~=slc then
-              base=base.prev
-            else
-              break
-            end
-          end
-        end
-        if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then 
-          local basechar=base.char
-          local baseanchors=descriptions[basechar].anchors
-          if baseanchors then
-            baseanchors=baseanchors['basemark']
-            if baseanchors then
-              local al=anchorlookups[lookupname]
-              for anchor,ba in next,baseanchors do
-                if al[anchor] then
-                  local ma=markanchors[anchor]
-                  if ma then
-                    local dx,dy,bound=setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,true)
-                    if trace_marks then
-                      logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
-                        cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
-                    end
-                    return head,start,true
-                  end
-                end
-              end
-              if trace_bugs then
-                logwarning("%s: no matching anchors for mark %s and basemark %s",gref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar))
-              end
-            end
-          end
-        elseif trace_bugs then
-          logwarning("%s: prev node is no mark",cref(kind,chainname,chainlookupname,lookupname))
-        end
-      elseif trace_bugs then
-        logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar))
-      end
-  elseif trace_bugs then
-    logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))
-  end
-  return head,start,false
-end
-function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
-  local alreadydone=cursonce and start[a_cursbase]
-  if not alreadydone then
-    local startchar=start.char
-    local subtables=currentlookup.subtables
-    local lookupname=subtables[1]
-    local exitanchors=lookuphash[lookupname]
-    if exitanchors then
-      exitanchors=exitanchors[startchar]
-    end
-    if exitanchors then
-      local done=false
-      if marks[startchar] then
-        if trace_cursive then
-          logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar))
-        end
-      else
-        local nxt=start.next
-        while not done and nxt and nxt.id==glyph_code and nxt.font==currentfont and nxt.subtype<256 do
-          local nextchar=nxt.char
-          if marks[nextchar] then
-            nxt=nxt.next
-          else
-            local entryanchors=descriptions[nextchar]
-            if entryanchors then
-              entryanchors=entryanchors.anchors
-              if entryanchors then
-                entryanchors=entryanchors['centry']
-                if entryanchors then
-                  local al=anchorlookups[lookupname]
-                  for anchor,entry in next,entryanchors do
-                    if al[anchor] then
-                      local exit=exitanchors[anchor]
-                      if exit then
-                        local dx,dy,bound=setcursive(start,nxt,tfmdata.parameters.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
-                        if trace_cursive then
-                          logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode)
-                        end
-                        done=true
-                        break
-                      end
-                    end
-                  end
-                end
-              end
-            elseif trace_bugs then
-              onetimemessage(currentfont,startchar,"no entry anchors",report_fonts)
-            end
-            break
-          end
-        end
-      end
-      return head,start,done
-    else
-      if trace_cursive and trace_details then
-        logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone)
-      end
-      return head,start,false
-    end
-  end
-  return head,start,false
-end
-function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
-  local startchar=start.char
-  local subtables=currentlookup.subtables
-  local lookupname=subtables[1]
-  local kerns=lookuphash[lookupname]
-  if kerns then
-    kerns=kerns[startchar] 
-    if kerns then
-      local dx,dy,w,h=setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
-      if trace_kerns then
-        logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h)
-      end
-    end
-  end
-  return head,start,false
-end
-chainmores.gpos_single=chainprocs.gpos_single
-function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
-  local snext=start.next
-  if snext then
-    local startchar=start.char
-    local subtables=currentlookup.subtables
-    local lookupname=subtables[1]
-    local kerns=lookuphash[lookupname]
-    if kerns then
-      kerns=kerns[startchar]
-      if kerns then
-        local lookuptype=lookuptypes[lookupname]
-        local prev,done=start,false
-        local factor=tfmdata.parameters.factor
-        while snext and snext.id==glyph_code and snext.font==currentfont and snext.subtype<256 do
-          local nextchar=snext.char
-          local krn=kerns[nextchar]
-          if not krn and marks[nextchar] then
-            prev=snext
-            snext=snext.next
-          else
-            if not krn then
-            elseif type(krn)=="table" then
-              if lookuptype=="pair" then
-                local a,b=krn[2],krn[3]
-                if a and #a>0 then
-                  local startchar=start.char
-                  local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
-                  if trace_kerns then
-                    logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
-                  end
-                end
-                if b and #b>0 then
-                  local startchar=start.char
-                  local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar])
-                  if trace_kerns then
-                    logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
-                  end
-                end
-              else
-                report_process("%s: check this out (old kern stuff)",cref(kind,chainname,chainlookupname))
-                local a,b=krn[2],krn[6]
-                if a and a~=0 then
-                  local k=setkern(snext,factor,rlmode,a)
-                  if trace_kerns then
-                    logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar))
-                  end
-                end
-                if b and b~=0 then
-                  logwarning("%s: ignoring second kern xoff %s",cref(kind,chainname,chainlookupname),b*factor)
-                end
-              end
-              done=true
-            elseif krn~=0 then
-              local k=setkern(snext,factor,rlmode,krn)
-              if trace_kerns then
-                logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar))
-              end
-              done=true
-            end
-            break
-          end
-        end
-        return head,start,done
-      end
-    end
-  end
-  return head,start,false
-end
-chainmores.gpos_pair=chainprocs.gpos_pair
-local function show_skip(kind,chainname,char,ck,class)
-  if ck[9] then
-    logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a, %a => %a",cref(kind,chainname),gref(char),class,ck[1],ck[2],ck[9],ck[10])
-  else
-    logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(kind,chainname),gref(char),class,ck[1],ck[2])
-  end
-end
-local function normal_handle_contextchain(head,start,kind,chainname,contexts,sequence,lookuphash)
-  local flags=sequence.flags
-  local done=false
-  local skipmark=flags[1]
-  local skipligature=flags[2]
-  local skipbase=flags[3]
-  local someskip=skipmark or skipligature or skipbase 
-  local markclass=sequence.markclass          
-  local skipped=false
-  for k=1,#contexts do
-    local match=true
-    local current=start
-    local last=start
-    local ck=contexts[k]
-    local seq=ck[3]
-    local s=#seq
-    if s==1 then
-      match=current.id==glyph_code and current.font==currentfont and current.subtype<256 and seq[1][current.char]
-    else
-      local f,l=ck[4],ck[5]
-      if f==1 and f==l then
-      else
-        if f==l then
-        else
-          local n=f+1
-          last=last.next
-          while n<=l do
-            if last then
-              local id=last.id
-              if id==glyph_code then
-                if last.font==currentfont and last.subtype<256 then
-                  local char=last.char
-                  local ccd=descriptions[char]
-                  if ccd then
-                    local class=ccd.class
-                    if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then
-                      skipped=true
-                      if trace_skips then
-                        show_skip(kind,chainname,char,ck,class)
-                      end
-                      last=last.next
-                    elseif seq[n][char] then
-                      if n<l then
-                        last=last.next
-                      end
-                      n=n+1
-                    else
-                      match=false
-                      break
-                    end
-                  else
-                    match=false
-                    break
-                  end
-                else
-                  match=false
-                  break
-                end
-              elseif id==disc_code then
-                last=last.next
-              else
-                match=false
-                break
-              end
-            else
-              match=false
-              break
-            end
-          end
-        end
-      end
-      if match and f>1 then
-        local prev=start.prev
-        if prev then
-          local n=f-1
-          while n>=1 do
-            if prev then
-              local id=prev.id
-              if id==glyph_code then
-                if prev.font==currentfont and prev.subtype<256 then 
-                  local char=prev.char
-                  local ccd=descriptions[char]
-                  if ccd then
-                    local class=ccd.class
-                    if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then
-                      skipped=true
-                      if trace_skips then
-                        show_skip(kind,chainname,char,ck,class)
-                      end
-                    elseif seq[n][char] then
-                      n=n -1
-                    else
-                      match=false
-                      break
-                    end
-                  else
-                    match=false
-                    break
-                  end
-                else
-                  match=false
-                  break
-                end
-              elseif id==disc_code then
-              elseif seq[n][32] then
-                n=n -1
-              else
-                match=false
-                break
-              end
-              prev=prev.prev
-            elseif seq[n][32] then 
-              n=n -1
-            else
-              match=false
-              break
-            end
-          end
-        elseif f==2 then
-          match=seq[1][32]
-        else
-          for n=f-1,1 do
-            if not seq[n][32] then
-              match=false
-              break
-            end
-          end
-        end
-      end
-      if match and s>l then
-        local current=last and last.next
-        if current then
-          local n=l+1
-          while n<=s do
-            if current then
-              local id=current.id
-              if id==glyph_code then
-                if current.font==currentfont and current.subtype<256 then 
-                  local char=current.char
-                  local ccd=descriptions[char]
-                  if ccd then
-                    local class=ccd.class
-                    if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then
-                      skipped=true
-                      if trace_skips then
-                        show_skip(kind,chainname,char,ck,class)
-                      end
-                    elseif seq[n][char] then
-                      n=n+1
-                    else
-                      match=false
-                      break
-                    end
-                  else
-                    match=false
-                    break
-                  end
-                else
-                  match=false
-                  break
-                end
-              elseif id==disc_code then
-              elseif seq[n][32] then 
-                n=n+1
-              else
-                match=false
-                break
-              end
-              current=current.next
-            elseif seq[n][32] then
-              n=n+1
-            else
-              match=false
-              break
-            end
-          end
-        elseif s-l==1 then
-          match=seq[s][32]
-        else
-          for n=l+1,s do
-            if not seq[n][32] then
-              match=false
-              break
-            end
-          end
-        end
-      end
-    end
-    if match then
-      if trace_contexts then
-        local rule,lookuptype,f,l=ck[1],ck[2],ck[4],ck[5]
-        local char=start.char
-        if ck[9] then
-          logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a, %a => %a",
-            cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype,ck[9],ck[10])
-        else
-          logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a",
-            cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype)
-        end
-      end
-      local chainlookups=ck[6]
-      if chainlookups then
-        local nofchainlookups=#chainlookups
-        if nofchainlookups==1 then
-          local chainlookupname=chainlookups[1]
-          local chainlookup=lookuptable[chainlookupname]
-          if chainlookup then
-            local cp=chainprocs[chainlookup.type]
-            if cp then
-              local ok
-              head,start,ok=cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence)
-              if ok then
-                done=true
-              end
-            else
-              logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
-            end
-          else 
-            logprocess("%s is not yet supported",cref(kind,chainname,chainlookupname))
-          end
-         else
-          local i=1
-          repeat
-            if skipped then
-              while true do
-                local char=start.char
-                local ccd=descriptions[char]
-                if ccd then
-                  local class=ccd.class
-                  if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then
-                    start=start.next
-                  else
-                    break
-                  end
-                else
-                  break
-                end
-              end
-            end
-            local chainlookupname=chainlookups[i]
-            local chainlookup=lookuptable[chainlookupname]
-            if not chainlookup then
-              i=i+1
-            else
-              local cp=chainmores[chainlookup.type]
-              if not cp then
-                logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
-                i=i+1
-              else
-                local ok,n
-                head,start,ok,n=cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence)
-                if ok then
-                  done=true
-                  i=i+(n or 1)
-                else
-                  i=i+1
-                end
-              end
-            end
-            if start then
-              start=start.next
-            else
-            end
-          until i>nofchainlookups
-        end
-      else
-        local replacements=ck[7]
-        if replacements then
-          head,start,done=chainprocs.reversesub(head,start,last,kind,chainname,ck,lookuphash,replacements) 
-        else
-          done=true 
-          if trace_contexts then
-            logprocess("%s: skipping match",cref(kind,chainname))
-          end
-        end
-      end
-    end
-  end
-  return head,start,done
-end
-local verbose_handle_contextchain=function(font,...)
-  logwarning("no verbose handler installed, reverting to 'normal'")
-  otf.setcontextchain()
-  return normal_handle_contextchain(...)
-end
-otf.chainhandlers={
-  normal=normal_handle_contextchain,
-  verbose=verbose_handle_contextchain,
-}
-function otf.setcontextchain(method)
-  if not method or method=="normal" or not otf.chainhandlers[method] then
-    if handlers.contextchain then 
-      logwarning("installing normal contextchain handler")
-    end
-    handlers.contextchain=normal_handle_contextchain
-  else
-    logwarning("installing contextchain handler %a",method)
-    local handler=otf.chainhandlers[method]
-    handlers.contextchain=function(...)
-      return handler(currentfont,...) 
-    end
-  end
-  handlers.gsub_context=handlers.contextchain
-  handlers.gsub_contextchain=handlers.contextchain
-  handlers.gsub_reversecontextchain=handlers.contextchain
-  handlers.gpos_contextchain=handlers.contextchain
-  handlers.gpos_context=handlers.contextchain
-end
-otf.setcontextchain()
-local missing={} 
-local function logprocess(...)
-  if trace_steps then
-    registermessage(...)
-  end
-  report_process(...)
-end
-local logwarning=report_process
-local function report_missing_cache(typ,lookup)
-  local f=missing[currentfont] if not f then f={} missing[currentfont]=f end
-  local t=f[typ]        if not t then t={} f[typ]=t end
-  if not t[lookup] then
-    t[lookup]=true
-    logwarning("missing cache for lookup %a, type %a, font %a, name %a",lookup,typ,currentfont,tfmdata.properties.fullname)
-  end
-end
-local resolved={}
-local lookuphashes={}
-setmetatableindex(lookuphashes,function(t,font)
-  local lookuphash=fontdata[font].resources.lookuphash
-  if not lookuphash or not next(lookuphash) then
-    lookuphash=false
-  end
-  t[font]=lookuphash
-  return lookuphash
-end)
-local autofeatures=fonts.analyzers.features 
-local function initialize(sequence,script,language,enabled)
-  local features=sequence.features
-  if features then
-    local order=sequence.order
-    if order then
-      for i=1,#order do
-        local kind=order[i] 
-        local valid=enabled[kind]
-        if valid then
-          local scripts=features[kind] 
-          local languages=scripts[script] or scripts[wildcard]
-          if languages and (languages[language] or languages[wildcard]) then
-            return { valid,autofeatures[kind] or false,sequence.chain or 0,kind,sequence }
-          end
-        end
-      end
-    else
-    end
-  end
-  return false
-end
-function otf.dataset(tfmdata,font) 
-  local shared=tfmdata.shared
-  local properties=tfmdata.properties
-  local language=properties.language or "dflt"
-  local script=properties.script  or "dflt"
-  local enabled=shared.features
-  local res=resolved[font]
-  if not res then
-    res={}
-    resolved[font]=res
-  end
-  local rs=res[script]
-  if not rs then
-    rs={}
-    res[script]=rs
-  end
-  local rl=rs[language]
-  if not rl then
-    rl={
-    }
-    rs[language]=rl
-    local sequences=tfmdata.resources.sequences
-    for s=1,#sequences do
-      local v=enabled and initialize(sequences[s],script,language,enabled)
-      if v then
-        rl[#rl+1]=v
-      end
-    end
-  end
-  return rl
-end
-local function featuresprocessor(head,font,attr)
-  local lookuphash=lookuphashes[font] 
-  if not lookuphash then
-    return head,false
-  end
-  if trace_steps then
-    checkstep(head)
-  end
-  tfmdata=fontdata[font]
-  descriptions=tfmdata.descriptions
-  characters=tfmdata.characters
-  resources=tfmdata.resources
-  marks=resources.marks
-  anchorlookups=resources.lookup_to_anchor
-  lookuptable=resources.lookups
-  lookuptypes=resources.lookuptypes
-  currentfont=font
-  rlmode=0
-  local sequences=resources.sequences
-  local done=false
-  local datasets=otf.dataset(tfmdata,font,attr)
-  local dirstack={}
-  for s=1,#datasets do
-    local dataset=datasets[s]
-    featurevalue=dataset[1] 
-    local sequence=dataset[5] 
-    local rlparmode=0
-    local topstack=0
-    local success=false
-    local attribute=dataset[2]
-    local chain=dataset[3] 
-    local typ=sequence.type
-    local subtables=sequence.subtables
-    if chain<0 then
-      local handler=handlers[typ]
-      local start=find_node_tail(head) 
-      while start do
-        local id=start.id
-        if id==glyph_code then
-          if start.font==font and start.subtype<256 then
-            local a=start[0]
-            if a then
-              a=a==attr
-            else
-              a=true
-            end
-            if a then
-              for i=1,#subtables do
-                local lookupname=subtables[i]
-                local lookupcache=lookuphash[lookupname]
-                if lookupcache then
-                  local lookupmatch=lookupcache[start.char]
-                  if lookupmatch then
-                    head,start,success=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
-                    if success then
-                      break
-                    end
-                  end
-                else
-                  report_missing_cache(typ,lookupname)
-                end
-              end
-              if start then start=start.prev end
-            else
-              start=start.prev
-            end
-          else
-            start=start.prev
-          end
-        else
-          start=start.prev
-        end
-      end
-    else
-      local handler=handlers[typ]
-      local ns=#subtables
-      local start=head 
-      rlmode=0 
-      if ns==1 then 
-        local lookupname=subtables[1]
-        local lookupcache=lookuphash[lookupname]
-        if not lookupcache then 
-          report_missing_cache(typ,lookupname)
-        else
-          local function subrun(start)
-            local head=start
-            local done=false
-            while start do
-              local id=start.id
-              if id==glyph_code and start.font==font and start.subtype<256 then
-                local a=start[0]
-                if a then
-                  a=(a==attr) and (not attribute or start[a_state]==attribute)
-                else
-                  a=not attribute or start[a_state]==attribute
-                end
-                if a then
-                  local lookupmatch=lookupcache[start.char]
-                  if lookupmatch then
-                    local ok
-                    head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
-                    if ok then
-                      done=true
-                    end
-                  end
-                  if start then start=start.next end
-                else
-                  start=start.next
-                end
-              else
-                start=start.next
-              end
-            end
-            if done then
-              success=true
-              return head
-            end
-          end
-          local function kerndisc(disc) 
-            local prev=disc.prev
-            local next=disc.next
-            if prev and next then
-              prev.next=next
-              local a=prev[0]
-              if a then
-                a=(a==attr) and (not attribute or prev[a_state]==attribute)
-              else
-                a=not attribute or prev[a_state]==attribute
-              end
-              if a then
-                local lookupmatch=lookupcache[prev.char]
-                if lookupmatch then
-                  local h,d,ok=handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
-                  if ok then
-                    done=true
-                    success=true
-                  end
-                end
-              end
-              prev.next=disc
-            end
-            return next
-          end
-          while start do
-            local id=start.id
-            if id==glyph_code then
-              if start.font==font and start.subtype<256 then
-                local a=start[0]
-                if a then
-                  a=(a==attr) and (not attribute or start[a_state]==attribute)
-                else
-                  a=not attribute or start[a_state]==attribute
-                end
-                if a then
-                  local lookupmatch=lookupcache[start.char]
-                  if lookupmatch then
-                    local ok
-                    head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
-                    if ok then
-                      success=true
-                    end
-                  end
-                  if start then start=start.next end
-                else
-                  start=start.next
-                end
-              else
-                start=start.next
-              end
-            elseif id==disc_code then
-              if start.subtype==discretionary_code then
-                local pre=start.pre
-                if pre then
-                  local new=subrun(pre)
-                  if new then start.pre=new end
-                end
-                local post=start.post
-                if post then
-                  local new=subrun(post)
-                  if new then start.post=new end
-                end
-                local replace=start.replace
-                if replace then
-                  local new=subrun(replace)
-                  if new then start.replace=new end
-                end
-elseif typ=="gpos_single" or typ=="gpos_pair" then
-  kerndisc(start)
-              end
-              start=start.next
-            elseif id==whatsit_code then 
-              local subtype=start.subtype
-              if subtype==dir_code then
-                local dir=start.dir
-                if   dir=="+TRT" or dir=="+TLT" then
-                  topstack=topstack+1
-                  dirstack[topstack]=dir
-                elseif dir=="-TRT" or dir=="-TLT" then
-                  topstack=topstack-1
-                end
-                local newdir=dirstack[topstack]
-                if newdir=="+TRT" then
-                  rlmode=-1
-                elseif newdir=="+TLT" then
-                  rlmode=1
-                else
-                  rlmode=rlparmode
-                end
-                if trace_directions then
-                  report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir)
-                end
-              elseif subtype==localpar_code then
-                local dir=start.dir
-                if dir=="TRT" then
-                  rlparmode=-1
-                elseif dir=="TLT" then
-                  rlparmode=1
-                else
-                  rlparmode=0
-                end
-                rlmode=rlparmode
-                if trace_directions then
-                  report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode)
-                end
-              end
-              start=start.next
-            elseif id==math_code then
-              start=end_of_math(start).next
-            else
-              start=start.next
-            end
-          end
-        end
-      else
-        local function subrun(start)
-          local head=start
-          local done=false
-          while start do
-            local id=start.id
-            if id==glyph_code and start.id==font and start.subtype<256 then
-              local a=start[0]
-              if a then
-                a=(a==attr) and (not attribute or start[a_state]==attribute)
-              else
-                a=not attribute or start[a_state]==attribute
-              end
-              if a then
-                for i=1,ns do
-                  local lookupname=subtables[i]
-                  local lookupcache=lookuphash[lookupname]
-                  if lookupcache then
-                    local lookupmatch=lookupcache[start.char]
-                    if lookupmatch then
-                      local ok
-                      head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
-                      if ok then
-                        done=true
-                        break
-                      elseif not start then
-                        break
-                      end
-                    end
-                  else
-                    report_missing_cache(typ,lookupname)
-                  end
-                end
-                if start then start=start.next end
-              else
-                start=start.next
-              end
-            else
-              start=start.next
-            end
-          end
-          if done then
-            success=true
-            return head
-          end
-        end
-        local function kerndisc(disc) 
-          local prev=disc.prev
-          local next=disc.next
-          if prev and next then
-            prev.next=next
-            local a=prev[0]
-            if a then
-              a=(a==attr) and (not attribute or prev[a_state]==attribute)
-            else
-              a=not attribute or prev[a_state]==attribute
-            end
-            if a then
-              for i=1,ns do
-                local lookupname=subtables[i]
-                local lookupcache=lookuphash[lookupname]
-                if lookupcache then
-                  local lookupmatch=lookupcache[prev.char]
-                  if lookupmatch then
-                    local h,d,ok=handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
-                    if ok then
-                      done=true
-                      break
-                    end
-                  end
-                else
-                  report_missing_cache(typ,lookupname)
-                end
-              end
-            end
-            prev.next=disc
-          end
-          return next
-        end
-        while start do
-          local id=start.id
-          if id==glyph_code then
-            if start.font==font and start.subtype<256 then
-              local a=start[0]
-              if a then
-                a=(a==attr) and (not attribute or start[a_state]==attribute)
-              else
-                a=not attribute or start[a_state]==attribute
-              end
-              if a then
-                for i=1,ns do
-                  local lookupname=subtables[i]
-                  local lookupcache=lookuphash[lookupname]
-                  if lookupcache then
-                    local lookupmatch=lookupcache[start.char]
-                    if lookupmatch then
-                      local ok
-                      head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
-                      if ok then
-                        success=true
-                        break
-                      elseif not start then
-                        break
-                      end
-                    end
-                  else
-                    report_missing_cache(typ,lookupname)
-                  end
-                end
-                if start then start=start.next end
-              else
-                start=start.next
-              end
-            else
-              start=start.next
-            end
-          elseif id==disc_code then
-            if start.subtype==discretionary_code then
-              local pre=start.pre
-              if pre then
-                local new=subrun(pre)
-                if new then start.pre=new end
-              end
-              local post=start.post
-              if post then
-                local new=subrun(post)
-                if new then start.post=new end
-              end
-              local replace=start.replace
-              if replace then
-                local new=subrun(replace)
-                if new then start.replace=new end
-              end
-elseif typ=="gpos_single" or typ=="gpos_pair" then
-  kerndisc(start)
-            end
-            start=start.next
-          elseif id==whatsit_code then
-            local subtype=start.subtype
-            if subtype==dir_code then
-              local dir=start.dir
-              if   dir=="+TRT" or dir=="+TLT" then
-                topstack=topstack+1
-                dirstack[topstack]=dir
-              elseif dir=="-TRT" or dir=="-TLT" then
-                topstack=topstack-1
-              end
-              local newdir=dirstack[topstack]
-              if newdir=="+TRT" then
-                rlmode=-1
-              elseif newdir=="+TLT" then
-                rlmode=1
-              else
-                rlmode=rlparmode
-              end
-              if trace_directions then
-                report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir)
-              end
-            elseif subtype==localpar_code then
-              local dir=start.dir
-              if dir=="TRT" then
-                rlparmode=-1
-              elseif dir=="TLT" then
-                rlparmode=1
-              else
-                rlparmode=0
-              end
-              rlmode=rlparmode
-              if trace_directions then
-                report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode)
-              end
-            end
-            start=start.next
-          elseif id==math_code then
-            start=end_of_math(start).next
-          else
-            start=start.next
-          end
-        end
-      end
-    end
-    if success then
-      done=true
-    end
-    if trace_steps then 
-      registerstep(head)
-    end
-  end
-  return head,done
-end
-local function generic(lookupdata,lookupname,unicode,lookuphash)
-  local target=lookuphash[lookupname]
-  if target then
-    target[unicode]=lookupdata
-  else
-    lookuphash[lookupname]={ [unicode]=lookupdata }
-  end
-end
-local action={
-  substitution=generic,
-  multiple=generic,
-  alternate=generic,
-  position=generic,
-  ligature=function(lookupdata,lookupname,unicode,lookuphash)
-    local target=lookuphash[lookupname]
-    if not target then
-      target={}
-      lookuphash[lookupname]=target
-    end
-    for i=1,#lookupdata do
-      local li=lookupdata[i]
-      local tu=target[li]
-      if not tu then
-        tu={}
-        target[li]=tu
-      end
-      target=tu
-    end
-    target.ligature=unicode
-  end,
-  pair=function(lookupdata,lookupname,unicode,lookuphash)
-    local target=lookuphash[lookupname]
-    if not target then
-      target={}
-      lookuphash[lookupname]=target
-    end
-    local others=target[unicode]
-    local paired=lookupdata[1]
-    if others then
-      others[paired]=lookupdata
-    else
-      others={ [paired]=lookupdata }
-      target[unicode]=others
-    end
-  end,
-}
-local function prepare_lookups(tfmdata)
-  local rawdata=tfmdata.shared.rawdata
-  local resources=rawdata.resources
-  local lookuphash=resources.lookuphash
-  local anchor_to_lookup=resources.anchor_to_lookup
-  local lookup_to_anchor=resources.lookup_to_anchor
-  local lookuptypes=resources.lookuptypes
-  local characters=tfmdata.characters
-  local descriptions=tfmdata.descriptions
-  for unicode,character in next,characters do 
-    local description=descriptions[unicode]
-    if description then
-      local lookups=description.slookups
-      if lookups then
-        for lookupname,lookupdata in next,lookups do
-          action[lookuptypes[lookupname]](lookupdata,lookupname,unicode,lookuphash)
-        end
-      end
-      local lookups=description.mlookups
-      if lookups then
-        for lookupname,lookuplist in next,lookups do
-          local lookuptype=lookuptypes[lookupname]
-          for l=1,#lookuplist do
-            local lookupdata=lookuplist[l]
-            action[lookuptype](lookupdata,lookupname,unicode,lookuphash)
-          end
-        end
-      end
-      local list=description.kerns
-      if list then
-        for lookup,krn in next,list do 
-          local target=lookuphash[lookup]
-          if target then
-            target[unicode]=krn
-          else
-            lookuphash[lookup]={ [unicode]=krn }
-          end
-        end
-      end
-      local list=description.anchors
-      if list then
-        for typ,anchors in next,list do 
-          if typ=="mark" or typ=="cexit" then 
-            for name,anchor in next,anchors do
-              local lookups=anchor_to_lookup[name]
-              if lookups then
-                for lookup,_ in next,lookups do
-                  local target=lookuphash[lookup]
-                  if target then
-                    target[unicode]=anchors
-                  else
-                    lookuphash[lookup]={ [unicode]=anchors }
-                  end
-                end
-              end
-            end
-          end
-        end
-      end
-    end
-  end
-end
-local function split(replacement,original)
-  local result={}
-  for i=1,#replacement do
-    result[original[i]]=replacement[i]
-  end
-  return result
-end
-local valid={
-  coverage={ chainsub=true,chainpos=true,contextsub=true },
-  reversecoverage={ reversesub=true },
-  glyphs={ chainsub=true,chainpos=true },
-}
-local function prepare_contextchains(tfmdata)
-  local rawdata=tfmdata.shared.rawdata
-  local resources=rawdata.resources
-  local lookuphash=resources.lookuphash
-  local lookups=rawdata.lookups
-  if lookups then
-    for lookupname,lookupdata in next,rawdata.lookups do
-      local lookuptype=lookupdata.type
-      if lookuptype then
-        local rules=lookupdata.rules
-        if rules then
-          local format=lookupdata.format
-          local validformat=valid[format]
-          if not validformat then
-            report_prepare("unsupported format %a",format)
-          elseif not validformat[lookuptype] then
-            report_prepare("unsupported format %a, lookuptype %a, lookupname %a",format,lookuptype,lookupname)
-          else
-            local contexts=lookuphash[lookupname]
-            if not contexts then
-              contexts={}
-              lookuphash[lookupname]=contexts
-            end
-            local t,nt={},0
-            for nofrules=1,#rules do
-              local rule=rules[nofrules]
-              local current=rule.current
-              local before=rule.before
-              local after=rule.after
-              local replacements=rule.replacements
-              local sequence={}
-              local nofsequences=0
-              if before then
-                for n=1,#before do
-                  nofsequences=nofsequences+1
-                  sequence[nofsequences]=before[n]
-                end
-              end
-              local start=nofsequences+1
-              for n=1,#current do
-                nofsequences=nofsequences+1
-                sequence[nofsequences]=current[n]
-              end
-              local stop=nofsequences
-              if after then
-                for n=1,#after do
-                  nofsequences=nofsequences+1
-                  sequence[nofsequences]=after[n]
-                end
-              end
-              if sequence[1] then
-                nt=nt+1
-                t[nt]={ nofrules,lookuptype,sequence,start,stop,rule.lookups,replacements }
-                for unic,_ in next,sequence[start] do
-                  local cu=contexts[unic]
-                  if not cu then
-                    contexts[unic]=t
-                  end
-                end
-              end
-            end
-          end
-        else
-        end
-      else
-        report_prepare("missing lookuptype for lookupname %a",lookupname)
-      end
-    end
-  end
-end
-local function featuresinitializer(tfmdata,value)
-  if true then
-    local rawdata=tfmdata.shared.rawdata
-    local properties=rawdata.properties
-    if not properties.initialized then
-      local starttime=trace_preparing and os.clock()
-      local resources=rawdata.resources
-      resources.lookuphash=resources.lookuphash or {}
-      prepare_contextchains(tfmdata)
-      prepare_lookups(tfmdata)
-      properties.initialized=true
-      if trace_preparing then
-        report_prepare("preparation time is %0.3f seconds for %a",os.clock()-starttime,tfmdata.properties.fullname)
-      end
-    end
-  end
-end
-registerotffeature {
-  name="features",
-  description="features",
-  default=true,
-  initializers={
-    position=1,
-    node=featuresinitializer,
-  },
-  processors={
-    node=featuresprocessor,
-  }
-}
-otf.handlers=handlers
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['font-otp']={
-  version=1.001,
-  comment="companion to font-otf.lua (packing)",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local next,type=next,type
-local sort,concat=table.sort,table.concat
-local sortedhash=table.sortedhash
-local trace_packing=false trackers.register("otf.packing",function(v) trace_packing=v end)
-local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end)
-local report_otf=logs.reporter("fonts","otf loading")
-fonts=fonts or {}
-local handlers=fonts.handlers or {}
-fonts.handlers=handlers
-local otf=handlers.otf or {}
-handlers.otf=otf
-local enhancers=otf.enhancers or {}
-otf.enhancers=enhancers
-local glists=otf.glists or { "gsub","gpos" }
-otf.glists=glists
-local criterium=1
-local threshold=0
-local function tabstr_normal(t)
-  local s={}
-  local n=0
-  for k,v in next,t do
-    n=n+1
-    if type(v)=="table" then
-      s[n]=k..">"..tabstr_normal(v)
-    elseif v==true then
-      s[n]=k.."+" 
-    elseif v then
-      s[n]=k.."="..v
-    else
-      s[n]=k.."-" 
-    end
-  end
-  if n==0 then
-    return ""
-  elseif n==1 then
-    return s[1]
-  else
-    sort(s) 
-    return concat(s,",")
-  end
-end
-local function tabstr_flat(t)
-  local s={}
-  local n=0
-  for k,v in next,t do
-    n=n+1
-    s[n]=k.."="..v
-  end
-  if n==0 then
-    return ""
-  elseif n==1 then
-    return s[1]
-  else
-    sort(s) 
-    return concat(s,",")
-  end
-end
-local function tabstr_mixed(t) 
-  local s={}
-  local n=#t
-  if n==0 then
-    return ""
-  elseif n==1 then
-    local k=t[1]
-    if k==true then
-      return "++" 
-    elseif k==false then
-      return "--" 
-    else
-      return tostring(k) 
-    end
-  else
-    for i=1,n do
-      local k=t[i]
-      if k==true then
-        s[i]="++" 
-      elseif k==false then
-        s[i]="--" 
-      else
-        s[i]=k 
-      end
-    end
-    return concat(s,",")
-  end
-end
-local function tabstr_boolean(t)
-  local s={}
-  local n=0
-  for k,v in next,t do
-    n=n+1
-    if v then
-      s[n]=k.."+"
-    else
-      s[n]=k.."-"
-    end
-  end
-  if n==0 then
-    return ""
-  elseif n==1 then
-    return s[1]
-  else
-    sort(s) 
-    return concat(s,",")
-  end
-end
-local function packdata(data)
-  if data then
-    local h,t,c={},{},{}
-    local hh,tt,cc={},{},{}
-    local nt,ntt=0,0
-    local function pack_normal(v)
-      local tag=tabstr_normal(v)
-      local ht=h[tag]
-      if ht then
-        c[ht]=c[ht]+1
-        return ht
-      else
-        nt=nt+1
-        t[nt]=v
-        h[tag]=nt
-        c[nt]=1
-        return nt
-      end
-    end
-    local function pack_flat(v)
-      local tag=tabstr_flat(v)
-      local ht=h[tag]
-      if ht then
-        c[ht]=c[ht]+1
-        return ht
-      else
-        nt=nt+1
-        t[nt]=v
-        h[tag]=nt
-        c[nt]=1
-        return nt
-      end
-    end
-    local function pack_boolean(v)
-      local tag=tabstr_boolean(v)
-      local ht=h[tag]
-      if ht then
-        c[ht]=c[ht]+1
-        return ht
-      else
-        nt=nt+1
-        t[nt]=v
-        h[tag]=nt
-        c[nt]=1
-        return nt
-      end
-    end
-    local function pack_indexed(v)
-      local tag=concat(v," ")
-      local ht=h[tag]
-      if ht then
-        c[ht]=c[ht]+1
-        return ht
-      else
-        nt=nt+1
-        t[nt]=v
-        h[tag]=nt
-        c[nt]=1
-        return nt
-      end
-    end
-    local function pack_mixed(v)
-      local tag=tabstr_mixed(v)
-      local ht=h[tag]
-      if ht then
-        c[ht]=c[ht]+1
-        return ht
-      else
-        nt=nt+1
-        t[nt]=v
-        h[tag]=nt
-        c[nt]=1
-        return nt
-      end
-    end
-    local function pack_final(v)
-      if c[v]<=criterium then
-        return t[v]
-      else
-        local hv=hh[v]
-        if hv then
-          return hv
-        else
-          ntt=ntt+1
-          tt[ntt]=t[v]
-          hh[v]=ntt
-          cc[ntt]=c[v]
-          return ntt
-        end
-      end
-    end
-    local function success(stage,pass)
-      if nt==0 then
-        if trace_loading or trace_packing then
-          report_otf("pack quality: nothing to pack")
-        end
-        return false
-      elseif nt>=threshold then
-        local one,two,rest=0,0,0
-        if pass==1 then
-          for k,v in next,c do
-            if v==1 then
-              one=one+1
-            elseif v==2 then
-              two=two+1
-            else
-              rest=rest+1
-            end
-          end
-        else
-          for k,v in next,cc do
-            if v>20 then
-              rest=rest+1
-            elseif v>10 then
-              two=two+1
-            else
-              one=one+1
-            end
-          end
-          data.tables=tt
-        end
-        if trace_loading or trace_packing then
-          report_otf("pack quality: stage %s, pass %s, %s packed, 1-10:%s, 11-20:%s, rest:%s (criterium: %s)",stage,pass,one+two+rest,one,two,rest,criterium)
-        end
-        return true
-      else
-        if trace_loading or trace_packing then
-          report_otf("pack quality: stage %s, pass %s, %s packed, aborting pack (threshold: %s)",stage,pass,nt,threshold)
-        end
-        return false
-      end
-    end
-    local function packers(pass)
-      if pass==1 then
-        return pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed
-      else
-        return pack_final,pack_final,pack_final,pack_final,pack_final
-      end
-    end
-    local resources=data.resources
-    local lookuptypes=resources.lookuptypes
-    for pass=1,2 do
-      if trace_packing then
-        report_otf("start packing: stage 1, pass %s",pass)
-      end
-      local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed=packers(pass)
-      for unicode,description in next,data.descriptions do
-        local boundingbox=description.boundingbox
-        if boundingbox then
-          description.boundingbox=pack_indexed(boundingbox)
-        end
-        local slookups=description.slookups
-        if slookups then
-          for tag,slookup in next,slookups do
-            local what=lookuptypes[tag]
-            if what=="pair" then
-              local t=slookup[2] if t then slookup[2]=pack_indexed(t) end
-              local t=slookup[3] if t then slookup[3]=pack_indexed(t) end
-            elseif what~="substitution" then
-              slookups[tag]=pack_indexed(slookup) 
-            end
-          end
-        end
-        local mlookups=description.mlookups
-        if mlookups then
-          for tag,mlookup in next,mlookups do
-            local what=lookuptypes[tag]
-            if what=="pair" then
-              for i=1,#mlookup do
-                local lookup=mlookup[i]
-                local t=lookup[2] if t then lookup[2]=pack_indexed(t) end
-                local t=lookup[3] if t then lookup[3]=pack_indexed(t) end
-              end
-            elseif what~="substitution" then
-              for i=1,#mlookup do
-                mlookup[i]=pack_indexed(mlookup[i]) 
-              end
-            end
-          end
-        end
-        local kerns=description.kerns
-        if kerns then
-          for tag,kern in next,kerns do
-            kerns[tag]=pack_flat(kern)
-          end
-        end
-        local math=description.math
-        if math then
-          local kerns=math.kerns
-          if kerns then
-            for tag,kern in next,kerns do
-              kerns[tag]=pack_normal(kern)
-            end
-          end
-        end
-        local anchors=description.anchors
-        if anchors then
-          for what,anchor in next,anchors do
-            if what=="baselig" then
-              for _,a in next,anchor do
-                for k=1,#a do
-                  a[k]=pack_indexed(a[k])
-                end
-              end
-            else
-              for k,v in next,anchor do
-                anchor[k]=pack_indexed(v)
-              end
-            end
-          end
-        end
-        local altuni=description.altuni
-        if altuni then
-          for i=1,#altuni do
-            altuni[i]=pack_flat(altuni[i])
-          end
-        end
-      end
-      local lookups=data.lookups
-      if lookups then
-        for _,lookup in next,lookups do
-          local rules=lookup.rules
-          if rules then
-            for i=1,#rules do
-              local rule=rules[i]
-              local r=rule.before    if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
-              local r=rule.after    if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
-              local r=rule.current   if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
-              local r=rule.replacements if r then rule.replacements=pack_flat  (r)  end 
-              local r=rule.lookups   if r then rule.lookups=pack_indexed(r)  end
-            end
-          end
-        end
-      end
-      local anchor_to_lookup=resources.anchor_to_lookup
-      if anchor_to_lookup then
-        for anchor,lookup in next,anchor_to_lookup do
-          anchor_to_lookup[anchor]=pack_normal(lookup)
-        end
-      end
-      local lookup_to_anchor=resources.lookup_to_anchor
-      if lookup_to_anchor then
-        for lookup,anchor in next,lookup_to_anchor do
-          lookup_to_anchor[lookup]=pack_normal(anchor)
-        end
-      end
-      local sequences=resources.sequences
-      if sequences then
-        for feature,sequence in next,sequences do
-          local flags=sequence.flags
-          if flags then
-            sequence.flags=pack_normal(flags)
-          end
-          local subtables=sequence.subtables
-          if subtables then
-            sequence.subtables=pack_normal(subtables)
-          end
-          local features=sequence.features
-          if features then
-            for script,feature in next,features do
-              features[script]=pack_normal(feature)
-            end
-          end
-          local order=sequence.order
-          if order then
-            sequence.order=pack_indexed(order)
-          end
-          local markclass=sequence.markclass
-          if markclass then
-            sequence.markclass=pack_boolean(markclass)
-          end
-        end
-      end
-      local lookups=resources.lookups
-      if lookups then
-        for name,lookup in next,lookups do
-          local flags=lookup.flags
-          if flags then
-            lookup.flags=pack_normal(flags)
-          end
-          local subtables=lookup.subtables
-          if subtables then
-            lookup.subtables=pack_normal(subtables)
-          end
-        end
-      end
-      local features=resources.features
-      if features then
-        for _,what in next,glists do
-          local list=features[what]
-          if list then
-            for feature,spec in next,list do
-              list[feature]=pack_normal(spec)
-            end
-          end
-        end
-      end
-      if not success(1,pass) then
-        return
-      end
-    end
-    if nt>0 then
-      for pass=1,2 do
-        if trace_packing then
-          report_otf("start packing: stage 2, pass %s",pass)
-        end
-        local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed=packers(pass)
-        for unicode,description in next,data.descriptions do
-          local kerns=description.kerns
-          if kerns then
-            description.kerns=pack_normal(kerns)
-          end
-          local math=description.math
-          if math then
-            local kerns=math.kerns
-            if kerns then
-              math.kerns=pack_normal(kerns)
-            end
-          end
-          local anchors=description.anchors
-          if anchors then
-            description.anchors=pack_normal(anchors)
-          end
-          local mlookups=description.mlookups
-          if mlookups then
-            for tag,mlookup in next,mlookups do
-              mlookups[tag]=pack_normal(mlookup)
-            end
-          end
-          local altuni=description.altuni
-          if altuni then
-            description.altuni=pack_normal(altuni)
-          end
-        end
-        local lookups=data.lookups
-        if lookups then
-          for _,lookup in next,lookups do
-            local rules=lookup.rules
-            if rules then
-              for i=1,#rules do 
-                local rule=rules[i]
-                local r=rule.before if r then rule.before=pack_normal(r) end
-                local r=rule.after  if r then rule.after=pack_normal(r) end
-                local r=rule.current if r then rule.current=pack_normal(r) end
-              end
-            end
-          end
-        end
-        local sequences=resources.sequences
-        if sequences then
-          for feature,sequence in next,sequences do
-            sequence.features=pack_normal(sequence.features)
-          end
-        end
-        if not success(2,pass) then
-        end
-      end
-      for pass=1,2 do
-        local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed=packers(pass)
-        for unicode,description in next,data.descriptions do
-          local slookups=description.slookups
-          if slookups then
-            description.slookups=pack_normal(slookups)
-          end
-          local mlookups=description.mlookups
-          if mlookups then
-            description.mlookups=pack_normal(mlookups)
-          end
-        end
-      end
-    end
-  end
-end
-local unpacked_mt={
-  __index=function(t,k)
-      t[k]=false
-      return k 
-    end
-}
-local function unpackdata(data)
-  if data then
-    local tables=data.tables
-    if tables then
-      local resources=data.resources
-      local lookuptypes=resources.lookuptypes
-      local unpacked={}
-      setmetatable(unpacked,unpacked_mt)
-      for unicode,description in next,data.descriptions do
-        local tv=tables[description.boundingbox]
-        if tv then
-          description.boundingbox=tv
-        end
-        local slookups=description.slookups
-        if slookups then
-          local tv=tables[slookups]
-          if tv then
-            description.slookups=tv
-            slookups=unpacked[tv]
-          end
-          if slookups then
-            for tag,lookup in next,slookups do
-              local what=lookuptypes[tag]
-              if what=="pair" then
-                local tv=tables[lookup[2]]
-                if tv then
-                  lookup[2]=tv
-                end
-                local tv=tables[lookup[3]]
-                if tv then
-                  lookup[3]=tv
-                end
-              elseif what~="substitution" then
-                local tv=tables[lookup]
-                if tv then
-                  slookups[tag]=tv
-                end
-              end
-            end
-          end
-        end
-        local mlookups=description.mlookups
-        if mlookups then
-          local tv=tables[mlookups]
-          if tv then
-            description.mlookups=tv
-            mlookups=unpacked[tv]
-          end
-          if mlookups then
-            for tag,list in next,mlookups do
-              local tv=tables[list]
-              if tv then
-                mlookups[tag]=tv
-                list=unpacked[tv]
-              end
-              if list then
-                local what=lookuptypes[tag]
-                if what=="pair" then
-                  for i=1,#list do
-                    local lookup=list[i]
-                    local tv=tables[lookup[2]]
-                    if tv then
-                      lookup[2]=tv
-                    end
-                    local tv=tables[lookup[3]]
-                    if tv then
-                      lookup[3]=tv
-                    end
-                  end
-                elseif what~="substitution" then
-                  for i=1,#list do
-                    local tv=tables[list[i]]
-                    if tv then
-                      list[i]=tv
-                    end
-                  end
-                end
-              end
-            end
-          end
-        end
-        local kerns=description.kerns
-        if kerns then
-          local tm=tables[kerns]
-          if tm then
-            description.kerns=tm
-            kerns=unpacked[tm]
-          end
-          if kerns then
-            for k,kern in next,kerns do
-              local tv=tables[kern]
-              if tv then
-                kerns[k]=tv
-              end
-            end
-          end
-        end
-        local math=description.math
-        if math then
-          local kerns=math.kerns
-          if kerns then
-            local tm=tables[kerns]
-            if tm then
-              math.kerns=tm
-              kerns=unpacked[tm]
-            end
-            if kerns then
-              for k,kern in next,kerns do
-                local tv=tables[kern]
-                if tv then
-                  kerns[k]=tv
-                end
-              end
-            end
-          end
-        end
-        local anchors=description.anchors
-        if anchors then
-          local ta=tables[anchors]
-          if ta then
-            description.anchors=ta
-            anchors=unpacked[ta]
-          end
-          if anchors then
-            for tag,anchor in next,anchors do
-              if tag=="baselig" then
-                for _,list in next,anchor do
-                  for i=1,#list do
-                    local tv=tables[list[i]]
-                    if tv then
-                      list[i]=tv
-                    end
-                  end
-                end
-              else
-                for a,data in next,anchor do
-                  local tv=tables[data]
-                  if tv then
-                    anchor[a]=tv
-                  end
-                end
-              end
-            end
-          end
-        end
-        local altuni=description.altuni
-        if altuni then
-          local altuni=tables[altuni]
-          if altuni then
-            description.altuni=altuni
-            for i=1,#altuni do
-              local tv=tables[altuni[i]]
-              if tv then
-                altuni[i]=tv
-              end
-            end
-          end
-        end
-      end
-      local lookups=data.lookups
-      if lookups then
-        for _,lookup in next,lookups do
-          local rules=lookup.rules
-          if rules then
-            for i=1,#rules do 
-              local rule=rules[i]
-              local before=rule.before
-              if before then
-                local tv=tables[before]
-                if tv then
-                  rule.before=tv
-                  before=unpacked[tv]
-                end
-                if before then
-                  for i=1,#before do
-                    local tv=tables[before[i]]
-                    if tv then
-                      before[i]=tv
-                    end
-                  end
-                end
-              end
-              local after=rule.after
-              if after then
-                local tv=tables[after]
-                if tv then
-                  rule.after=tv
-                  after=unpacked[tv]
-                end
-                if after then
-                  for i=1,#after do
-                    local tv=tables[after[i]]
-                    if tv then
-                      after[i]=tv
-                    end
-                  end
-                end
-              end
-              local current=rule.current
-              if current then
-                local tv=tables[current]
-                if tv then
-                  rule.current=tv
-                  current=unpacked[tv]
-                end
-                if current then
-                  for i=1,#current do
-                    local tv=tables[current[i]]
-                    if tv then
-                      current[i]=tv
-                    end
-                  end
-                end
-              end
-              local replacements=rule.replacements
-              if replacements then
-                local tv=tables[replacements]
-                if tv then
-                  rule.replacements=tv
-                end
-              end
-              local lookups=rule.lookups
-              if lookups then
-                local tv=tables[lookups]
-                if tv then
-                  rule.lookups=tv
-                end
-              end
-            end
-          end
-        end
-      end
-      local anchor_to_lookup=resources.anchor_to_lookup
-      if anchor_to_lookup then
-        for anchor,lookup in next,anchor_to_lookup do
-          local tv=tables[lookup]
-          if tv then
-            anchor_to_lookup[anchor]=tv
-          end
-        end
-      end
-      local lookup_to_anchor=resources.lookup_to_anchor
-      if lookup_to_anchor then
-        for lookup,anchor in next,lookup_to_anchor do
-          local tv=tables[anchor]
-          if tv then
-            lookup_to_anchor[lookup]=tv
-          end
-        end
-      end
-      local ls=resources.sequences
-      if ls then
-        for _,feature in next,ls do
-          local flags=feature.flags
-          if flags then
-            local tv=tables[flags]
-            if tv then
-              feature.flags=tv
-            end
-          end
-          local subtables=feature.subtables
-          if subtables then
-            local tv=tables[subtables]
-            if tv then
-              feature.subtables=tv
-            end
-          end
-          local features=feature.features
-          if features then
-            local tv=tables[features]
-            if tv then
-              feature.features=tv
-              features=unpacked[tv]
-            end
-            if features then
-              for script,data in next,features do
-                local tv=tables[data]
-                if tv then
-                  features[script]=tv
-                end
-              end
-            end
-          end
-          local order=feature.order
-          if order then
-            local tv=tables[order]
-            if tv then
-              feature.order=tv
-            end
-          end
-          local markclass=feature.markclass
-          if markclass then
-            local tv=tables[markclass]
-            if tv then
-              feature.markclass=tv
-            end
-          end
-        end
-      end
-      local lookups=resources.lookups
-      if lookups then
-        for _,lookup in next,lookups do
-          local flags=lookup.flags
-          if flags then
-            local tv=tables[flags]
-            if tv then
-              lookup.flags=tv
-            end
-          end
-          local subtables=lookup.subtables
-          if subtables then
-            local tv=tables[subtables]
-            if tv then
-              lookup.subtables=tv
-            end
-          end
-        end
-      end
-      local features=resources.features
-      if features then
-        for _,what in next,glists do
-          local feature=features[what]
-          if feature then
-            for tag,spec in next,feature do
-              local tv=tables[spec]
-              if tv then
-                feature[tag]=tv
-              end
-            end
-          end
-        end
-      end
-      data.tables=nil
-    end
-  end
-end
-if otf.enhancers.register then
-  otf.enhancers.register("pack",packdata)
-  otf.enhancers.register("unpack",unpackdata)
-end
-otf.enhancers.unpack=unpackdata 
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['luatex-fonts-lua']={
-  version=1.001,
-  comment="companion to luatex-*.tex",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-if context then
-  texio.write_nl("fatal error: this module is not for context")
-  os.exit()
-end
-local fonts=fonts
-fonts.formats.lua="lua"
-function fonts.readers.lua(specification)
-  local fullname=specification.filename or ""
-  if fullname=="" then
-    local forced=specification.forced or ""
-    if forced~="" then
-      fullname=specification.name.."."..forced
-    else
-      fullname=specification.name
-    end
-  end
-  local fullname=resolvers.findfile(fullname) or ""
-  if fullname~="" then
-    local loader=loadfile(fullname)
-    loader=loader and loader()
-    return loader and loader(specification)
-  end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['font-def']={
-  version=1.001,
-  comment="companion to font-ini.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local format,gmatch,match,find,lower,gsub=string.format,string.gmatch,string.match,string.find,string.lower,string.gsub
-local tostring,next=tostring,next
-local lpegmatch=lpeg.match
-local suffixonly,removesuffix=file.suffix,file.removesuffix
-local allocate=utilities.storage.allocate
-local trace_defining=false trackers .register("fonts.defining",function(v) trace_defining=v end)
-local directive_embedall=false directives.register("fonts.embedall",function(v) directive_embedall=v end)
-trackers.register("fonts.loading","fonts.defining","otf.loading","afm.loading","tfm.loading")
-trackers.register("fonts.all","fonts.*","otf.*","afm.*","tfm.*")
-local report_defining=logs.reporter("fonts","defining")
-local fonts=fonts
-local fontdata=fonts.hashes.identifiers
-local readers=fonts.readers
-local definers=fonts.definers
-local specifiers=fonts.specifiers
-local constructors=fonts.constructors
-local fontgoodies=fonts.goodies
-readers.sequence=allocate { 'otf','ttf','afm','tfm','lua' } 
-local variants=allocate()
-specifiers.variants=variants
-definers.methods=definers.methods or {}
-local internalized=allocate() 
-local lastdefined=nil 
-local loadedfonts=constructors.loadedfonts
-local designsizes=constructors.designsizes
-local resolvefile=fontgoodies and fontgoodies.filenames and fontgoodies.filenames.resolve or function(s) return s end
-local splitter,splitspecifiers=nil,"" 
-local P,C,S,Cc=lpeg.P,lpeg.C,lpeg.S,lpeg.Cc
-local left=P("(")
-local right=P(")")
-local colon=P(":")
-local space=P(" ")
-definers.defaultlookup="file"
-local prefixpattern=P(false)
-local function addspecifier(symbol)
-  splitspecifiers=splitspecifiers..symbol
-  local method=S(splitspecifiers)
-  local lookup=C(prefixpattern)*colon
-  local sub=left*C(P(1-left-right-method)^1)*right
-  local specification=C(method)*C(P(1)^1)
-  local name=C((1-sub-specification)^1)
-  splitter=P((lookup+Cc(""))*name*(sub+Cc(""))*(specification+Cc("")))
-end
-local function addlookup(str,default)
-  prefixpattern=prefixpattern+P(str)
-end
-definers.addlookup=addlookup
-addlookup("file")
-addlookup("name")
-addlookup("spec")
-local function getspecification(str)
-  return lpegmatch(splitter,str or "") 
-end
-definers.getspecification=getspecification
-function definers.registersplit(symbol,action,verbosename)
-  addspecifier(symbol)
-  variants[symbol]=action
-  if verbosename then
-    variants[verbosename]=action
-  end
-end
-local function makespecification(specification,lookup,name,sub,method,detail,size)
-  size=size or 655360
-  if not lookup or lookup=="" then
-    lookup=definers.defaultlookup
-  end
-  if trace_defining then
-    report_defining("specification %a, lookup %a, name %a, sub %a, method %a, detail %a",
-      specification,lookup,name,sub,method,detail)
-  end
-  local t={
-    lookup=lookup,
-    specification=specification,
-    size=size,
-    name=name,
-    sub=sub,
-    method=method,
-    detail=detail,
-    resolved="",
-    forced="",
-    features={},
-  }
-  return t
-end
-definers.makespecification=makespecification
-function definers.analyze(specification,size)
-  local lookup,name,sub,method,detail=getspecification(specification or "")
-  return makespecification(specification,lookup,name,sub,method,detail,size)
-end
-definers.resolvers=definers.resolvers or {}
-local resolvers=definers.resolvers
-function resolvers.file(specification)
-  local name=resolvefile(specification.name) 
-  local suffix=lower(suffixonly(name))
-  if fonts.formats[suffix] then
-    specification.forced=suffix
-    specification.forcedname=name
-    specification.name=removesuffix(name)
-  else
-    specification.name=name 
-  end
-end
-function resolvers.name(specification)
-  local resolve=fonts.names.resolve
-  if resolve then
-    local resolved,sub=resolve(specification.name,specification.sub,specification) 
-    if resolved then
-      specification.resolved=resolved
-      specification.sub=sub
-      local suffix=lower(suffixonly(resolved))
-      if fonts.formats[suffix] then
-        specification.forced=suffix
-        specification.forcedname=resolved
-        specification.name=removesuffix(resolved)
-      else
-        specification.name=resolved
-      end
-    end
-  else
-    resolvers.file(specification)
-  end
-end
-function resolvers.spec(specification)
-  local resolvespec=fonts.names.resolvespec
-  if resolvespec then
-    local resolved,sub=resolvespec(specification.name,specification.sub,specification) 
-    if resolved then
-      specification.resolved=resolved
-      specification.sub=sub
-      specification.forced=lower(suffixonly(resolved))
-      specification.forcedname=resolved
-      specification.name=removesuffix(resolved)
-    end
-  else
-    resolvers.name(specification)
-  end
-end
-function definers.resolve(specification)
-  if not specification.resolved or specification.resolved=="" then 
-    local r=resolvers[specification.lookup]
-    if r then
-      r(specification)
-    end
-  end
-  if specification.forced=="" then
-    specification.forced=nil
-    specification.forcedname=nil
-  end
-  specification.hash=lower(specification.name..' @ '..constructors.hashfeatures(specification))
-  if specification.sub and specification.sub~="" then
-    specification.hash=specification.sub..' @ '..specification.hash
-  end
-  return specification
-end
-function definers.applypostprocessors(tfmdata)
-  local postprocessors=tfmdata.postprocessors
-  if postprocessors then
-    local properties=tfmdata.properties
-    for i=1,#postprocessors do
-      local extrahash=postprocessors[i](tfmdata) 
-      if type(extrahash)=="string" and extrahash~="" then
-        extrahash=gsub(lower(extrahash),"[^a-z]","-")
-        properties.fullname=format("%s-%s",properties.fullname,extrahash)
-      end
-    end
-  end
-  return tfmdata
-end
-local function checkembedding(tfmdata)
-  local properties=tfmdata.properties
-  local embedding
-  if directive_embedall then
-    embedding="full"
-  elseif properties and properties.filename and constructors.dontembed[properties.filename] then
-    embedding="no"
-  else
-    embedding="subset"
-  end
-  if properties then
-    properties.embedding=embedding
-  else
-    tfmdata.properties={ embedding=embedding }
-  end
-  tfmdata.embedding=embedding
-end
-function definers.loadfont(specification)
-  local hash=constructors.hashinstance(specification)
-  local tfmdata=loadedfonts[hash] 
-  if not tfmdata then
-    local forced=specification.forced or ""
-    if forced~="" then
-      local reader=readers[lower(forced)] 
-      tfmdata=reader and reader(specification)
-      if not tfmdata then
-        report_defining("forced type %a of %a not found",forced,specification.name)
-      end
-    else
-      local sequence=readers.sequence 
-      for s=1,#sequence do
-        local reader=sequence[s]
-        if readers[reader] then 
-          if trace_defining then
-            report_defining("trying (reader sequence driven) type %a for %a with file %a",reader,specification.name,specification.filename)
-          end
-          tfmdata=readers[reader](specification)
-          if tfmdata then
-            break
-          else
-            specification.filename=nil
-          end
-        end
-      end
-    end
-    if tfmdata then
-      tfmdata=definers.applypostprocessors(tfmdata)
-      checkembedding(tfmdata) 
-      loadedfonts[hash]=tfmdata
-      designsizes[specification.hash]=tfmdata.parameters.designsize
-    end
-  end
-  if not tfmdata then
-    report_defining("font with asked name %a is not found using lookup %a",specification.name,specification.lookup)
-  end
-  return tfmdata
-end
-function constructors.checkvirtualids()
-end
-function constructors.readanddefine(name,size) 
-  local specification=definers.analyze(name,size)
-  local method=specification.method
-  if method and variants[method] then
-    specification=variants[method](specification)
-  end
-  specification=definers.resolve(specification)
-  local hash=constructors.hashinstance(specification)
-  local id=definers.registered(hash)
-  if not id then
-    local tfmdata=definers.loadfont(specification)
-    if tfmdata then
-      tfmdata.properties.hash=hash
-      constructors.checkvirtualids(tfmdata) 
-      id=font.define(tfmdata)
-      definers.register(tfmdata,id)
-    else
-      id=0 
-    end
-  end
-  return fontdata[id],id
-end
-function definers.current() 
-  return lastdefined
-end
-function definers.registered(hash)
-  local id=internalized[hash]
-  return id,id and fontdata[id]
-end
-function definers.register(tfmdata,id)
-  if tfmdata and id then
-    local hash=tfmdata.properties.hash
-    if not hash then
-      report_defining("registering font, id %a, name %a, invalid hash",id,tfmdata.properties.filename or "?")
-    elseif not internalized[hash] then
-      internalized[hash]=id
-      if trace_defining then
-        report_defining("registering font, id %s, hash %a",id,hash)
-      end
-      fontdata[id]=tfmdata
-    end
-  end
-end
-function definers.read(specification,size,id) 
-  statistics.starttiming(fonts)
-  if type(specification)=="string" then
-    specification=definers.analyze(specification,size)
-  end
-  local method=specification.method
-  if method and variants[method] then
-    specification=variants[method](specification)
-  end
-  specification=definers.resolve(specification)
-  local hash=constructors.hashinstance(specification)
-  local tfmdata=definers.registered(hash) 
-  if tfmdata then
-    if trace_defining then
-      report_defining("already hashed: %s",hash)
-    end
-  else
-    tfmdata=definers.loadfont(specification) 
-    if tfmdata then
-      if trace_defining then
-        report_defining("loaded and hashed: %s",hash)
-      end
-      tfmdata.properties.hash=hash
-      if id then
-        definers.register(tfmdata,id)
-      end
-    else
-      if trace_defining then
-        report_defining("not loaded and hashed: %s",hash)
-      end
-    end
-  end
-  lastdefined=tfmdata or id 
-  if not tfmdata then 
-    report_defining("unknown font %a, loading aborted",specification.name)
-  elseif trace_defining and type(tfmdata)=="table" then
-    local properties=tfmdata.properties or {}
-    local parameters=tfmdata.parameters or {}
-    report_defining("using %s font with id %a, name %a, size %a, bytes %a, encoding %a, fullname %a, filename %a",
-      properties.format,id,properties.name,parameters.size,properties.encodingbytes,
-      properties.encodingname,properties.fullname,file.basename(properties.filename))
-  end
-  statistics.stoptiming(fonts)
-  return tfmdata
-end
-function font.getfont(id)
-  return fontdata[id] 
-end
-callbacks.register('define_font',definers.read,"definition of fonts (tfmdata preparation)")
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['luatex-font-def']={
-  version=1.001,
-  comment="companion to luatex-*.tex",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-if context then
-  texio.write_nl("fatal error: this module is not for context")
-  os.exit()
-end
-local fonts=fonts
-fonts.constructors.namemode="specification"
-function fonts.definers.getspecification(str)
-  return "",str,"",":",str
-end
-local list={}
-local function issome ()  list.lookup='name'     end 
-local function isfile ()  list.lookup='file'     end
-local function isname ()  list.lookup='name'     end
-local function thename(s)  list.name=s        end
-local function issub (v)  list.sub=v        end
-local function iscrap (s)  list.crap=string.lower(s) end
-local function iskey (k,v) list[k]=v        end
-local function istrue (s)  list[s]=true      end
-local function isfalse(s)  list[s]=false      end
-local P,S,R,C=lpeg.P,lpeg.S,lpeg.R,lpeg.C
-local spaces=P(" ")^0
-local namespec=(1-S("/:("))^0 
-local crapspec=spaces*P("/")*(((1-P(":"))^0)/iscrap)*spaces
-local filename_1=P("file:")/isfile*(namespec/thename)
-local filename_2=P("[")*P(true)/isname*(((1-P("]"))^0)/thename)*P("]")
-local fontname_1=P("name:")/isname*(namespec/thename)
-local fontname_2=P(true)/issome*(namespec/thename)
-local sometext=(R("az","AZ","09")+S("+-."))^1
-local truevalue=P("+")*spaces*(sometext/istrue)
-local falsevalue=P("-")*spaces*(sometext/isfalse)
-local keyvalue=(C(sometext)*spaces*P("=")*spaces*C(sometext))/iskey
-local somevalue=sometext/istrue
-local subvalue=P("(")*(C(P(1-S("()"))^1)/issub)*P(")") 
-local option=spaces*(keyvalue+falsevalue+truevalue+somevalue)*spaces
-local options=P(":")*spaces*(P(";")^0*option)^0
-local pattern=(filename_1+filename_2+fontname_1+fontname_2)*subvalue^0*crapspec^0*options^0
-local function colonized(specification) 
-  list={}
-  lpeg.match(pattern,specification.specification)
-  list.crap=nil 
-  if list.name then
-    specification.name=list.name
-    list.name=nil
-  end
-  if list.lookup then
-    specification.lookup=list.lookup
-    list.lookup=nil
-  end
-  if list.sub then
-    specification.sub=list.sub
-    list.sub=nil
-  end
-  specification.features.normal=fonts.handlers.otf.features.normalize(list)
-  return specification
-end
-fonts.definers.registersplit(":",colonized,"cryptic")
-fonts.definers.registersplit("",colonized,"more cryptic") 
-function fonts.definers.applypostprocessors(tfmdata)
-  local postprocessors=tfmdata.postprocessors
-  if postprocessors then
-    for i=1,#postprocessors do
-      local extrahash=postprocessors[i](tfmdata) 
-      if type(extrahash)=="string" and extrahash~="" then
-        extrahash=string.gsub(lower(extrahash),"[^a-z]","-")
-        tfmdata.properties.fullname=format("%s-%s",tfmdata.properties.fullname,extrahash)
-      end
-    end
-  end
-  return tfmdata
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['luatex-fonts-ext']={
-  version=1.001,
-  comment="companion to luatex-*.tex",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-if context then
-  texio.write_nl("fatal error: this module is not for context")
-  os.exit()
-end
-local fonts=fonts
-local otffeatures=fonts.constructors.newfeatures("otf")
-local function initializeitlc(tfmdata,value)
-  if value then
-    local parameters=tfmdata.parameters
-    local italicangle=parameters.italicangle
-    if italicangle and italicangle~=0 then
-      local properties=tfmdata.properties
-      local factor=tonumber(value) or 1
-      properties.hasitalics=true
-      properties.autoitalicamount=factor*(parameters.uwidth or 40)/2
-    end
-  end
-end
-otffeatures.register {
-  name="itlc",
-  description="italic correction",
-  initializers={
-    base=initializeitlc,
-    node=initializeitlc,
-  }
-}
-local function initializeslant(tfmdata,value)
-  value=tonumber(value)
-  if not value then
-    value=0
-  elseif value>1 then
-    value=1
-  elseif value<-1 then
-    value=-1
-  end
-  tfmdata.parameters.slantfactor=value
-end
-otffeatures.register {
-  name="slant",
-  description="slant glyphs",
-  initializers={
-    base=initializeslant,
-    node=initializeslant,
-  }
-}
-local function initializeextend(tfmdata,value)
-  value=tonumber(value)
-  if not value then
-    value=0
-  elseif value>10 then
-    value=10
-  elseif value<-10 then
-    value=-10
-  end
-  tfmdata.parameters.extendfactor=value
-end
-otffeatures.register {
-  name="extend",
-  description="scale glyphs horizontally",
-  initializers={
-    base=initializeextend,
-    node=initializeextend,
-  }
-}
-fonts.protrusions=fonts.protrusions    or {}
-fonts.protrusions.setups=fonts.protrusions.setups or {}
-local setups=fonts.protrusions.setups
-local function initializeprotrusion(tfmdata,value)
-  if value then
-    local setup=setups[value]
-    if setup then
-      local factor,left,right=setup.factor or 1,setup.left or 1,setup.right or 1
-      local emwidth=tfmdata.parameters.quad
-      tfmdata.parameters.protrusion={
-        auto=true,
-      }
-      for i,chr in next,tfmdata.characters do
-        local v,pl,pr=setup[i],nil,nil
-        if v then
-          pl,pr=v[1],v[2]
-        end
-        if pl and pl~=0 then chr.left_protruding=left*pl*factor end
-        if pr and pr~=0 then chr.right_protruding=right*pr*factor end
-      end
-    end
-  end
-end
-otffeatures.register {
-  name="protrusion",
-  description="shift characters into the left and or right margin",
-  initializers={
-    base=initializeprotrusion,
-    node=initializeprotrusion,
-  }
-}
-fonts.expansions=fonts.expansions    or {}
-fonts.expansions.setups=fonts.expansions.setups or {}
-local setups=fonts.expansions.setups
-local function initializeexpansion(tfmdata,value)
-  if value then
-    local setup=setups[value]
-    if setup then
-      local factor=setup.factor or 1
-      tfmdata.parameters.expansion={
-        stretch=10*(setup.stretch or 0),
-        shrink=10*(setup.shrink or 0),
-        step=10*(setup.step  or 0),
-        auto=true,
-      }
-      for i,chr in next,tfmdata.characters do
-        local v=setup[i]
-        if v and v~=0 then
-          chr.expansion_factor=v*factor
-        else 
-          chr.expansion_factor=factor
-        end
-      end
-    end
-  end
-end
-otffeatures.register {
-  name="expansion",
-  description="apply hz optimization",
-  initializers={
-    base=initializeexpansion,
-    node=initializeexpansion,
-  }
-}
-function fonts.loggers.onetimemessage() end
-local byte=string.byte
-fonts.expansions.setups['default']={
-  stretch=2,shrink=2,step=.5,factor=1,
-  [byte('A')]=0.5,[byte('B')]=0.7,[byte('C')]=0.7,[byte('D')]=0.5,[byte('E')]=0.7,
-  [byte('F')]=0.7,[byte('G')]=0.5,[byte('H')]=0.7,[byte('K')]=0.7,[byte('M')]=0.7,
-  [byte('N')]=0.7,[byte('O')]=0.5,[byte('P')]=0.7,[byte('Q')]=0.5,[byte('R')]=0.7,
-  [byte('S')]=0.7,[byte('U')]=0.7,[byte('W')]=0.7,[byte('Z')]=0.7,
-  [byte('a')]=0.7,[byte('b')]=0.7,[byte('c')]=0.7,[byte('d')]=0.7,[byte('e')]=0.7,
-  [byte('g')]=0.7,[byte('h')]=0.7,[byte('k')]=0.7,[byte('m')]=0.7,[byte('n')]=0.7,
-  [byte('o')]=0.7,[byte('p')]=0.7,[byte('q')]=0.7,[byte('s')]=0.7,[byte('u')]=0.7,
-  [byte('w')]=0.7,[byte('z')]=0.7,
-  [byte('2')]=0.7,[byte('3')]=0.7,[byte('6')]=0.7,[byte('8')]=0.7,[byte('9')]=0.7,
-}
-fonts.protrusions.setups['default']={
-  factor=1,left=1,right=1,
-  [0x002C]={ 0,1  },
-  [0x002E]={ 0,1  },
-  [0x003A]={ 0,1  },
-  [0x003B]={ 0,1  },
-  [0x002D]={ 0,1  },
-  [0x2013]={ 0,0.50 },
-  [0x2014]={ 0,0.33 },
-  [0x3001]={ 0,1  },
-  [0x3002]={ 0,1  },
-  [0x060C]={ 0,1  },
-  [0x061B]={ 0,1  },
-  [0x06D4]={ 0,1  },
-}
-fonts.handlers.otf.features.normalize=function(t)
-  if t.rand then
-    t.rand="random"
-  end
-  return t
-end
-function fonts.helpers.nametoslot(name)
-  local t=type(name)
-  if t=="string" then
-    local tfmdata=fonts.hashes.identifiers[currentfont()]
-    local shared=tfmdata and tfmdata.shared
-    local fntdata=shared and shared.rawdata
-    return fntdata and fntdata.resources.unicodes[name]
-  elseif t=="number" then
-    return n
-  end
-end
-fonts.encodings=fonts.encodings or {}
-local reencodings={}
-fonts.encodings.reencodings=reencodings
-local function specialreencode(tfmdata,value)
-  local encoding=value and reencodings[value]
-  if encoding then
-    local temp={}
-    local char=tfmdata.characters
-    for k,v in next,encoding do
-      temp[k]=char[v]
-    end
-    for k,v in next,temp do
-      char[k]=temp[k]
-    end
-    return string.format("reencoded:%s",value)
-  end
-end
-local function reencode(tfmdata,value)
-  tfmdata.postprocessors=tfmdata.postprocessors or {}
-  table.insert(tfmdata.postprocessors,
-    function(tfmdata)
-      return specialreencode(tfmdata,value)
-    end
-  )
-end
-otffeatures.register {
-  name="reencode",
-  description="reencode characters",
-  manipulators={
-    base=reencode,
-    node=reencode,
-  }
-}
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['luatex-fonts-cbk']={
-  version=1.001,
-  comment="companion to luatex-*.tex",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-if context then
-  texio.write_nl("fatal error: this module is not for context")
-  os.exit()
-end
-local fonts=fonts
-local nodes=nodes
-local traverse_id=node.traverse_id
-local glyph_code=nodes.nodecodes.glyph
-function nodes.handlers.characters(head)
-  local fontdata=fonts.hashes.identifiers
-  if fontdata then
-    local usedfonts,done,prevfont={},false,nil
-    for n in traverse_id(glyph_code,head) do
-      local font=n.font
-      if font~=prevfont then
-        prevfont=font
-        local used=usedfonts[font]
-        if not used then
-          local tfmdata=fontdata[font] 
-          if tfmdata then
-            local shared=tfmdata.shared 
-            if shared then
-              local processors=shared.processes
-              if processors and #processors>0 then
-                usedfonts[font]=processors
-                done=true
-              end
-            end
-          end
-        end
-      end
-    end
-    if done then
-      for font,processors in next,usedfonts do
-        for i=1,#processors do
-          local h,d=processors[i](head,font,0)
-          head,done=h or head,done or d
-        end
-      end
-    end
-    return head,true
-  else
-    return head,false
-  end
-end
-function nodes.simple_font_handler(head)
-  head=nodes.handlers.characters(head)
-  nodes.injections.handler(head)
-  nodes.handlers.protectglyphs(head)
-  head=node.ligaturing(head)
-  head=node.kerning(head)
-  return head
-end
-
-end -- closure
diff --git a/src/luaotfload-configuration.lua b/src/luaotfload-configuration.lua
index 50ac0bd..b901824 100644
--- a/src/luaotfload-configuration.lua
+++ b/src/luaotfload-configuration.lua
@@ -135,7 +135,6 @@ local registered_loaders = {
   reference  = "reference",
   unpackaged = "unpackaged",
   context    = "context",
-  tl2014     = "tl2014",
 }
 
 local pick_fontloader = function (s)
diff --git a/src/luaotfload-database.lua b/src/luaotfload-database.lua
index 0f8e56b..b06f3d5 100644
--- a/src/luaotfload-database.lua
+++ b/src/luaotfload-database.lua
@@ -360,7 +360,6 @@ This is a sketch of the luaotfload db:
         conflicts       : { barename : int; basename : int }; // filename conflict with font at index; happens with subfonts
         familyname      : string;   // sanitized name of the font family the font belongs to, usually from the names table
         fontname        : string;   // sanitized name of the font
-        fontstyle_name  : string;   // the fontstyle_name field returned by fontloader.info()
         format          : string;   // "otf" | "ttf" | "dfont" | "pfa" | "pfb" | "afm"
         fullname        : string;   // sanitized full name of the font including style modifiers
         fullpath        : string;   // path to font in filesystem
diff --git a/src/luaotfload-features.lua b/src/luaotfload-features.lua
index 9817e0b..79f1416 100644
--- a/src/luaotfload-features.lua
+++ b/src/luaotfload-features.lua
@@ -1,5 +1,5 @@
 if not modules then modules = { } end modules ["features"] = {
-    version   = "2.6",
+    version   = "2.7",
     comment   = "companion to luaotfload-main.lua",
     author    = "Hans Hagen, Khaled Hosny, Elie Roux, Philipp Gesang",
     copyright = "PRAGMA ADE / ConTeXt Development Team",
diff --git a/src/luaotfload-init.lua b/src/luaotfload-init.lua
index 8b13fe6..bcc0e18 100644
--- a/src/luaotfload-init.lua
+++ b/src/luaotfload-init.lua
@@ -460,9 +460,6 @@ local init_main = function ()
       Now that things are sorted out we can finally load the
       fontloader.
 
-      For less current distibutions we ship the code from TL 2014 that
-      should be compatible with Luatex 0.76.
-
   --doc]]--
 
   local fontloader = config.luaotfload and config.luaotfload.run.fontloader
diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua
index 426aef7..3f1f602 100644
--- a/src/luaotfload-main.lua
+++ b/src/luaotfload-main.lua
@@ -13,7 +13,7 @@ local luaotfload                  = luaotfload
 luaotfload.log                    = luaotfload.log or { }
 luaotfload.version                = "2.7"
 luaotfload.loaders                = { }
-luaotfload.min_luatex_version     = 80             --- i. e. 0.80
+luaotfload.min_luatex_version     = 95             --- i. e. 0.80
 luaotfload.fontloader_package     = "reference"    --- default: from current Context
 
 local authors = "\z
@@ -30,7 +30,7 @@ local authors = "\z
 luaotfload.module = {
     name          = "luaotfload-main",
     version       = 2.70001,
-    date          = "2016/02/19",
+    date          = "2016/04/19",
     description   = "OpenType layout system.",
     author        = authors,
     copyright     = authors,
@@ -64,29 +64,6 @@ local type             = type
 
 luatexbase.provides_module (luaotfload.module)
 
---[[doc--
-
-     We set the minimum version requirement for \LUATEX to v0.76,
-     because the font loader requires recent features like direct
-     attribute indexing and \luafunction{node.end_of_math()} that aren’t
-     available in earlier versions.\footnote{%
-      See Taco’s announcement of v0.76:
-      \url{http://comments.gmane.org/gmane.comp.tex.luatex.user/4042}
-      and this commit by Hans that introduced those features.
-      \url{http://repo.or.cz/w/context.git/commitdiff/a51f6cf6ee087046a2ae5927ed4edff0a1acec1b}.
-    }
-
---doc]]--
-
-if tex.luatexversion < luaotfload.min_luatex_version then
-    warning ("LuaTeX v%.2f is old, v%.2f or later is recommended.",
-             tex.luatexversion  / 100,
-             luaotfload.min_luatex_version / 100)
-    warning ("using fallback fontloader -- newer functionality not available")
-    luaotfload.fontloader_package = "tl2014" --- TODO fallback should be configurable too
-    --- we install a fallback for older versions as a safety
-end
-
 --[[doc--
 
     \subsection{Module loading}
-- 
cgit v1.2.3