--[[info-----------------------------------------------------------------------
 Luaotfload fontloader package
 build 2017-02-11 18:16:05 by phg@phlegethon
-------------------------------------------------------------------------------
-- UF
texio.write_nl ("------------------")
texio.write_nl ("!!!!! UF: this fontloader uses an experimental font-oto.lua")
texio.write_nl ("------------------")
-- /UF


2017-07-14: UF exchanged font-oto-part to get around stix2 bug.

 © 2017 PRAGMA ADE / ConTeXt Development Team

 The code in this file is provided under the GPL v2.0 license. See the
 file COPYING in the Luaotfload repository for details.

 Report bugs to github.com/lualatex/luaotfload

 This file has been assembled from components taken from Context. See
 the Luaotfload documentation for details:

     $ texdoc luaotfload
     $ man 1 luaotfload-tool
     $ man 5 luaotfload.conf

 Included files:

   · fontloader-data-con.lua
   · fontloader-basics-nod.lua
   · fontloader-font-ini.lua
   · fontloader-font-con.lua
   · fontloader-fonts-enc.lua
   · fontloader-font-cid.lua
   · fontloader-font-map.lua
   · fontloader-font-oti.lua
   · fontloader-font-otr.lua
   · fontloader-font-cff.lua
   · fontloader-font-ttf.lua
   · fontloader-font-dsp.lua
   · fontloader-font-oup.lua
   · fontloader-font-otl.lua
   · fontloader-font-oto.lua
   · fontloader-font-otj.lua
   · fontloader-font-ota.lua
   · fontloader-font-ots.lua
   · fontloader-font-osd.lua
   · fontloader-font-ocl.lua
   · fontloader-font-otc.lua
   · fontloader-font-onr.lua
   · fontloader-font-one.lua
   · fontloader-font-afk.lua
   · fontloader-font-tfm.lua
   · fontloader-font-lua.lua
   · fontloader-font-def.lua
   · fontloader-fonts-ext.lua
   · fontloader-font-gbn.lua

--info]]-----------------------------------------------------------------------


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “data-con” d8982c834ed9acc6193eee23067b9d5d] ---

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,container.writable)
   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 --- [luaotfload, fontloader-2017-02-11.lua scope for “data-con”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “basics-nod” 9288471b8395bfb683aba0ff3964d950] ---

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={}
local glyphcodes=node.subtypes("glyph")
local disccodes=node.subtypes("disc")
for k,v in next,node.types() do
 v=string.gsub(v,"_","")
 nodecodes[k]=v
 nodecodes[v]=k
end
for i=0,#glyphcodes do
 glyphcodes[glyphcodes[i]]=i
end
for i=0,#disccodes do
 disccodes[disccodes[i]]=i
end
nodes.nodecodes=nodecodes
nodes.glyphcodes=glyphcodes
nodes.disccodes=disccodes
local flush_node=node.flush_node
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
     flush_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
local setfield=node.setfield
nodes.getfield=getfield
nodes.setfield=setfield
nodes.getattr=getfield
nodes.setattr=setfield
nodes.tostring=node.tostring or tostring
nodes.copy=node.copy
nodes.copy_node=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.flush=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.has_glyph=node.has_glyph or node.first_glyph
nodes.current_attr=node.current_attr
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.mlist_to_hlist=node.mlist_to_hlist
local direct=node.direct
local nuts={}
nodes.nuts=nuts
local tonode=direct.tonode
local tonut=direct.todirect
nodes.tonode=tonode
nodes.tonut=tonut
nuts.tonode=tonode
nuts.tonut=tonut
local getfield=direct.getfield
local setfield=direct.setfield
nuts.getfield=getfield
nuts.setfield=setfield
nuts.getnext=direct.getnext
nuts.setnext=direct.setnext
nuts.getprev=direct.getprev
nuts.setprev=direct.setprev
nuts.getboth=direct.getboth
nuts.setboth=direct.setboth
nuts.getid=direct.getid
nuts.getattr=direct.get_attribute or direct.has_attribute or getfield
nuts.setattr=setfield
nuts.getfont=direct.getfont
nuts.setfont=direct.setfont
nuts.getsubtype=direct.getsubtype
nuts.setsubtype=direct.setsubtype or function(n,s) setfield(n,"subtype",s) end
nuts.getchar=direct.getchar
nuts.setchar=direct.setchar
nuts.getdisc=direct.getdisc
nuts.setdisc=direct.setdisc
nuts.setlink=direct.setlink
nuts.getlist=direct.getlist
nuts.setlist=direct.setlist  or function(n,l) setfield(n,"list",l) end
nuts.getleader=direct.getleader
nuts.setleader=direct.setleader or function(n,l) setfield(n,"leader",l) end
if not direct.is_glyph then
 local getchar=direct.getchar
 local getid=direct.getid
 local getfont=direct.getfont
 local glyph_code=nodes.nodecodes.glyph
 function direct.is_glyph(n,f)
   local id=getid(n)
   if id==glyph_code then
     if f and getfont(n)==f then
       return getchar(n)
     else
       return false
     end
   else
     return nil,id
   end
 end
 function direct.is_char(n,f)
   local id=getid(n)
   if id==glyph_code then
     if getsubtype(n)>=256 then
       return false
     elseif f and getfont(n)==f then
       return getchar(n)
     else
       return false
     end
   else
     return nil,id
   end
 end
end
nuts.ischar=direct.is_char
nuts.is_char=direct.is_char
nuts.isglyph=direct.is_glyph
nuts.is_glyph=direct.is_glyph
nuts.insert_before=direct.insert_before
nuts.insert_after=direct.insert_after
nuts.delete=direct.delete
nuts.copy=direct.copy
nuts.copy_node=direct.copy
nuts.copy_list=direct.copy_list
nuts.tail=direct.tail
nuts.flush_list=direct.flush_list
nuts.flush_node=direct.flush_node
nuts.flush=direct.flush
nuts.free=direct.free
nuts.remove=direct.remove
nuts.is_node=direct.is_node
nuts.end_of_math=direct.end_of_math
nuts.traverse=direct.traverse
nuts.traverse_id=direct.traverse_id
nuts.traverse_char=direct.traverse_char
nuts.ligaturing=direct.ligaturing
nuts.kerning=direct.kerning
nuts.getprop=nuts.getattr
nuts.setprop=nuts.setattr
local new_nut=direct.new
nuts.new=new_nut
nuts.pool={}
function nuts.pool.kern(k)
 local n=new_nut("kern",1)
 setfield(n,"kern",k)
 return n
end
local propertydata=direct.get_properties_table()
nodes.properties={ data=propertydata }
direct.set_properties_mode(true,true)
function direct.set_properties_mode() end
nuts.getprop=function(n,k)
 local p=propertydata[n]
 if p then
   return p[k]
 end
end
nuts.setprop=function(n,k,v)
 if v then
   local p=propertydata[n]
   if p then
     p[k]=v
   else
     propertydata[n]={ [k]=v }
   end
 end
end
nodes.setprop=nodes.setproperty
nodes.getprop=nodes.getproperty

end --- [luaotfload, fontloader-2017-02-11.lua scope for “basics-nod”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ini” 10cb9a563a98e06ff79c35a8751e13dc] ---

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
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 --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ini”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-con” 7575a7b4e6d04816072945e27d7d0b33] ---

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,find=string.format,string.match,string.lower,string.gsub,string.find
local sort,insert,concat,sortedkeys,serialize,fastcopy=table.sort,table.insert,table.concat,table.sortedkeys,table.serialize,table.fastcopy
local derivetable=table.derive
local ioflush=io.flush
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.cacheintex=true
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
   local factor=constructors.factor
   if designsize then
     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,
 NoLimitSupFactor=true,
 NoLimitSubFactor=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
local function mathkerns(v,vdelta)
 local k={}
 for i=1,#v do
   local entry=v[i]
   local height=entry.height
   local kern=entry.kern
   k[i]={
     height=height and vdelta*height or 0,
     kern=kern  and vdelta*kern  or 0,
   }
 end
 return k
end
local psfake=0
local function fixedpsname(psname,fallback)
 local usedname=psname
 if psname and psname~="" then
   if find(psname," ") then
     usedname=gsub(psname,"[%s]+","-")
   else
   end
 elseif not fallback or fallback=="" then
   psfake=psfake+1
   psname="fakename-"..psfake
 else
   psname=fallback
   usedname=gsub(psname,"[^a-zA-Z0-9]+","-")
 end
 return usedname,psname~=usedname
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=fonts.mappings.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=units
 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
 target.cache=constructors.cacheintex and "yes" or "renew"
 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
 local psname,psfixed=fixedpsname(psname,fontname or fullname or file.nameonly(filename))
 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 haskerns=properties.haskerns   or properties.mode=="base"
 local hasligatures=properties.hasligatures or properties.mode=="base"
 local realdimensions=properties.realdimensions
 local writingmode=properties.writingmode or "horizontal"
 local identity=properties.identity or "horizontal"
 if changed and not next(changed) then
   changed=false
 end
 target.type=isvirtual and "virtual" or "real"
 target.writingmode=writingmode=="vertical" and "vertical" or "horizontal"
 target.identity=identity=="vertical" and "vertical" or "horizontal"
 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
 if hasmath then
   local mathitalics=properties.mathitalics
   if mathitalics==false then
     if trace_defining then
       report_defining("%s italics %s for font %a, fullname %a, filename %a","math",hasitalics and "ignored" or "disabled",name,fullname,filename)
     end
     hasitalics=false
     autoitalicamount=false
   end
 else
   local textitalics=properties.textitalics
   if textitalics==false then
     if trace_defining then
       report_defining("%s italics %s for font %a, fullname %a, filename %a","text",hasitalics and "ignored" or "disabled",name,fullname,filename)
     end
     hasitalics=false
     autoitalicamount=false
   end
 end
 if trace_defining then
   report_defining("defining tfm, name %a, fullname %a, filename %a, %spsname %a, hscale %a, vscale %a, math %a, italics %a",
     name,fullname,filename,psfixed and "(fixed) " or "",psname,hdelta,vdelta,
     hasmath and "enabled" or "disabled",hasitalics and "enabled" or "disabled")
 end
 constructors.beforecopyingcharacters(target,tfmdata)
 local sharedkerns={}
 for unicode,character in next,characters do
   local chr,description,index
   if changed then
     local c=changed[unicode]
     if c then
       description=descriptions[c] or descriptions[unicode] or character
       character=characters[c] or character
       index=description.index or c
     else
       description=descriptions[unicode] or character
       index=description.index or unicode
     end
   else
     description=descriptions[unicode] or character
     index=description.index or unicode
   end
   local width=description.width
   local height=description.height
   local depth=description.depth
   if realdimensions then
     if not height or height==0 then
       local bb=description.boundingbox
       local ht=bb[4]
       if ht~=0 then
         height=ht
       end
       if not depth or depth==0 then
         local dp=-bb[2]
         if dp~=0 then
           depth=dp
         end
       end
     elseif not depth or depth==0 then
       local dp=-description.boundingbox[2]
       if dp~=0 then
         depth=dp
       end
     end
   end
   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
   local isunicode=description.unicode
   if isunicode then
     chr.unicode=isunicode
     chr.tounicode=tounicode(isunicode)
   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 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 vi=character.vert_italic
     if vi and vi~=0 then
       chr.vert_italic=vi*hdelta
     end
     local va=character.accent
     if va then
       chr.top_accent=vdelta*va
     end
     if stackmath then
       local mk=character.mathkerns
       if mk then
         local tr,tl,br,bl=mk.topright,mk.topleft,mk.bottomright,mk.bottomleft
         chr.mathkern={
           top_right=tr and mathkerns(tr,vdelta) or nil,
           top_left=tl and mathkerns(tl,vdelta) or nil,
           bottom_right=br and mathkerns(br,vdelta) or nil,
           bottom_left=bl and mathkerns(bl,vdelta) or nil,
         }
       end
     end
     if hasitalics then
       local vi=character.italic
       if vi and vi~=0 then
         chr.italic=vi*hdelta
       end
     end
   elseif autoitalicamount then
     local vi=description.italic
     if not vi then
       local bb=description.boundingbox
       if bb then
         local vi=bb[3]-description.width+autoitalicamount
         if vi>0 then
           chr.italic=vi*hdelta
         end
       else
       end
     elseif vi~=0 then
       chr.italic=vi*hdelta
     end
   elseif hasitalics then
     local vi=character.italic
     if vi and vi~=0 then
       chr.italic=vi*hdelta
     end
   end
   if haskerns 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
   end
   if hasligatures then
     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
 properties.setitalics=hasitalics
 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
 local designsize=parameters.designsize
 if designsize then
   parameters.minsize=tfmdata.minsize or designsize
   parameters.maxsize=tfmdata.maxsize or designsize
 else
   designsize=factors.pt*10
   parameters.designsize=designsize
   parameters.minsize=designsize
   parameters.maxsize=designsize
 end
 parameters.minsize=tfmdata.minsize or parameters.designsize
 parameters.maxsize=tfmdata.maxsize or parameters.designsize
 if not parameters.units then
   parameters.units=tfmdata.units or 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,
     writingmode=tfmdata.writingmode  or "horizontal",
     identity=tfmdata.identity   or "horizontal",
   }
 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=nil
 tfmdata.units_per_em=nil
 tfmdata.cache=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..'='..tostring(v)
   end
 end
 if n>0 then
   sort(s)
   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)
do
 local function setindeed(mode,source,target,group,name,position)
   local action=source[mode]
   if not action then
     return
   end
   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 position=source.position
   setindeed("node",source,target,group,name,position)
   setindeed("base",source,target,group,name,position)
   setindeed("plug",source,target,group,name,position)
 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
 local newfeatures={}
 constructors.newfeatures=newfeatures
 constructors.features=newfeatures
 local function setnewfeatures(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={},plug={} },
       processors={ base={},node={},plug={} },
       manipulators={ base={},node={},plug={} },
     }
     features.register=function(specification) return register(features,specification) end
     handler.features=features
   end
   return features
 end
 setmetatable(newfeatures,{
   __call=function(t,k) local v=t[k] return v end,
   __index=function(t,k) local v=setnewfeatures(k) t[k]=v return v end,
 })
end
do
 local newhandler={}
 constructors.handlers=newhandler
 constructors.newhandler=newhandler
 local function setnewhandler(what)
   local handler=handlers[what]
   if not handler then
     handler={}
     handlers[what]=handler
   end
   return handler
 end
 setmetatable(newhandler,{
   __call=function(t,k) local v=t[k] return v end,
   __index=function(t,k) local v=setnewhandler(k) t[k]=v return v end,
 })
end
do
 local newenhancer={}
 constructors.enhancers=newenhancer
 constructors.newenhancer=newenhancer
 local function setnewenhancer(format)
   local handler=handlers[format]
   local enhancers=handler.enhancers
   if not enhancers then
     local actions=allocate()
     local before=allocate()
     local after=allocate()
     local order=allocate()
     local patches={ before=before,after=after }
     local trace=false
     local report=logs.reporter("fonts",format.." enhancing")
     trackers.register(format..".loading",function(v) trace=v end)
     local function enhance(name,data,filename,raw)
       local enhancer=actions[name]
       if enhancer then
         if trace then
           report("apply enhancement %a to file %a",name,filename)
           ioflush()
         end
         enhancer(data,filename,raw)
       else
       end
     end
     local function apply(data,filename,raw)
       local basename=file.basename(lower(filename))
       if trace then
         report("%s enhancing file %a","start",filename)
       end
       ioflush()
       for e=1,#order do
         local enhancer=order[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 then
         report("%s enhancing file %a","stop",filename)
       end
       ioflush()
     end
     local function register(what,action)
       if action then
         if actions[what] then
         else
           order[#order+1]=what
         end
         actions[what]=action
       else
         report("bad enhancer %a",what)
       end
     end
     local function patch(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
     enhancers={
       register=register,
       apply=apply,
       patch=patch,
       patches={ register=patch },
     }
     handler.enhancers=enhancers
   end
   return enhancers
 end
 setmetatable(newenhancer,{
   __call=function(t,k) local v=t[k] return v end,
   __index=function(t,k) local v=setnewenhancer(k) t[k]=v return v end,
 })
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 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
function constructors.addcoreunicodes(unicodes)
 if not unicodes then
   unicodes={}
 end
 unicodes.space=0x0020
 unicodes.hyphen=0x002D
 unicodes.zwj=0x200D
 unicodes.zwnj=0x200C
 return unicodes
end

end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-con”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “fonts-enc” a7ace7c1969cd64a5ca9888838f3edb6] ---

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
local encodings={}
fonts.encodings=encodings
encodings.agl={}
encodings.known={}
setmetatable(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"))
   encodings.agl={ unicodes=unicodes }
   return unicodes
 else
   return nil
 end
end })
encodings.cache=containers.define("fonts","enc",encodings.version,true)
function encodings.load(filename)
 local name=file.removesuffix(filename)
 local data=containers.read(encodings.cache,name)
 if data then
   return data
 end
 local vector,tag,hash,unicodes={},"",{},{}
 local foundname=resolvers.findfile(filename,'enc')
 if foundname and foundname~="" then
   local ok,encoding,size=resolvers.loadbinfile(foundname)
   if ok and encoding then
     encoding=string.gsub(encoding,"%%(.-)\n","")
     local unicoding=encodings.agl.unicodes
     local tag,vec=string.match(encoding,"/(%w+)%s*%[(.*)%]%s*def")
     local i=0
     for ch in string.gmatch(vec,"/([%a%d%.]+)") do
       if ch~=".notdef" then
         vector[i]=ch
         if not hash[ch] then
           hash[ch]=i
         else
         end
         local u=unicoding[ch]
         if u then
           unicodes[u]=i
         end
       end
       i=i+1
     end
   end
 end
 local data={
   name=name,
   tag=tag,
   vector=vector,
   hash=hash,
   unicodes=unicodes
 }
 return containers.write(encodings.cache,name,data)
end

end --- [luaotfload, fontloader-2017-02-11.lua scope for “fonts-enc”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-cid” 52421d1fdaa07ec4b1d936c6ff5079be] ---

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 lowername=lower(filename)
 local found=cidmap[lowername]
 if found then
   return found
 end
 if ordering=="Identity" then
   local found={
     supplement=supplement,
     registry=registry,
     ordering=ordering,
     filename=filename,
     unicodes={},
     names={},
   }
   cidmap[lowername]=found
   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 --- [luaotfload, fontloader-2017-02-11.lua scope for “font-cid”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-map” 8708bde7467785c4d3b7afdaf2f9333a] ---

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,next,type=tonumber,next,type
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 floor=math.floor
local formatters=string.formatters
local sortedhash,sortedkeys=table.sortedhash,table.sortedkeys
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_mapping=v end)
local report_fonts=logs.reporter("fonts","loading")
local force_ligatures=false directives.register("fonts.mapping.forceligatures",function(v) force_ligatures=v end)
local fonts=fonts or {}
local mappings=fonts.mappings or {}
fonts.mappings=mappings
local allocate=utilities.storage.allocate
local hex=R("AF","af","09")
local hexfour=(hex*hex*hex^-2)/function(s) return tonumber(s,16) end
local hexsix=(hex*hex*hex^-4)/function(s) return tonumber(s,16) end
local dec=(R("09")^1)/tonumber
local period=P(".")
local unicode=(P("uni")+P("UNI"))*(hexfour*(period+P(-1))*Cc(false)+Ct(hexfour^1)*Cc(true))
local ucode=(P("u")+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 f_single=formatters["%04X"]
local f_double=formatters["%04X%04X"]
local function tounicode16(unicode)
 if unicode<0xD7FF or (unicode>0xDFFF and unicode<=0xFFFF) then
   return f_single(unicode)
 else
   unicode=unicode-0x10000
   return f_double(floor(unicode/1024)+0xD800,unicode%1024+0xDC00)
 end
end
local function tounicode16sequence(unicodes)
 local t={}
 for l=1,#unicodes do
   local u=unicodes[l]
   if u<0xD7FF or (u>0xDFFF and u<=0xFFFF) then
     t[l]=f_single(u)
   else
     u=u-0x10000
     t[l]=f_double(floor(u/1024)+0xD800,u%1024+0xDC00)
   end
 end
 return concat(t)
end
local function tounicode(unicode,name)
 if type(unicode)=="table" then
   local t={}
   for l=1,#unicode do
     local u=unicode[l]
     if u<0xD7FF or (u>0xDFFF and u<=0xFFFF) then
       t[l]=f_single(u)
     else
       u=u-0x10000
       t[l]=f_double(floor(u/1024)+0xD800,u%1024+0xDC00)
     end
   end
   return concat(t)
 else
   if unicode<0xD7FF or (unicode>0xDFFF and unicode<=0xFFFF) then
     return f_single(unicode)
   else
     unicode=unicode-0x10000
     return f_double(floor(unicode/1024)+0xD800,unicode%1024+0xDC00)
   end
 end
end
local function fromunicode16(str)
 if #str==4 then
   return tonumber(str,16)
 else
   local l,r=match(str,"(....)(....)")
   return 0x10000+(tonumber(l,16)-0xD800)*0x400+tonumber(r,16)-0xDC00
 end
end
mappings.makenameparser=makenameparser
mappings.tounicode=tounicode
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)
do
 local overloads=allocate {
   IJ={ name="I_J",unicode={ 0x49,0x4A },mess=0x0132 },
   ij={ name="i_j",unicode={ 0x69,0x6A },mess=0x0133 },
   ff={ name="f_f",unicode={ 0x66,0x66 },mess=0xFB00 },
   fi={ name="f_i",unicode={ 0x66,0x69 },mess=0xFB01 },
   fl={ name="f_l",unicode={ 0x66,0x6C },mess=0xFB02 },
   ffi={ name="f_f_i",unicode={ 0x66,0x66,0x69 },mess=0xFB03 },
   ffl={ name="f_f_l",unicode={ 0x66,0x66,0x6C },mess=0xFB04 },
   fj={ name="f_j",unicode={ 0x66,0x6A } },
   fk={ name="f_k",unicode={ 0x66,0x6B } },
 }
 local o={}
 for k,v in next,overloads do
   local name=v.name
   local mess=v.mess
   if name then
     o[name]=v
   end
   if mess then
     o[mess]=v
   end
   o[k]=v
 end
 mappings.overloads=o
end
function mappings.addtounicode(data,filename,checklookups)
 local resources=data.resources
 local unicodes=resources.unicodes
 if not unicodes then
   if trace_mapping then
     report_fonts("no unicode list, quitting tounicode for %a",filename)
   end
   return
 end
 local properties=data.properties
 local descriptions=data.descriptions
 local overloads=mappings.overloads
 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 and fonts.constructors.privateoffset or 0xF0000
 local unicodevector=fonts.encodings.agl.unicodes or {}
 local contextvector=fonts.encodings.agl.ctxcodes or {}
 local missing={}
 local nofmissing=0
 local oparser=nil
 local cidnames=nil
 local cidcodes=nil
 local cidinfo=properties.cidinfo
 local usedmap=cidinfo and fonts.cid.getmap(cidinfo)
 local uparser=makenameparser()
 if usedmap then
    oparser=usedmap and makenameparser(cidinfo.ordering)
    cidnames=usedmap.names
    cidcodes=usedmap.unicodes
 end
 local ns=0
 local nl=0
 local dlist=sortedkeys(descriptions)
 for i=1,#dlist do
   local du=dlist[i]
   local glyph=descriptions[du]
   local name=glyph.name
   if name then
     local overload=overloads[name] or overloads[du]
     if overload then
       glyph.unicode=overload.unicode
     else
       local gu=glyph.unicode
       if not gu or gu==-1 or du>=private or (du>=0xE000 and du<=0xF8FF) or du==0xFFFE or du==0xFFFF then
         local unicode=unicodevector[name] or contextvector[name]
         if unicode then
           glyph.unicode=unicode
           ns=ns+1
         end
         if (not unicode) and usedmap then
           local foundindex=lpegmatch(oparser,name)
           if foundindex then
             unicode=cidcodes[foundindex]
             if unicode then
               glyph.unicode=unicode
               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
                     glyph.unicode=unicode
                     ns=ns+1
                   end
                 end
                 if not unicode or unicode=="" then
                   local foundcodes,multiple=lpegmatch(uparser,reference)
                   if foundcodes then
                     glyph.unicode=foundcodes
                     if multiple then
                       nl=nl+1
                       unicode=true
                     else
                       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
           if nsplit==0 then
           elseif nsplit==1 then
             local base=split[1]
             local u=unicodes[base] or unicodevector[base] or contextvector[name]
             if not u then
             elseif type(u)=="table" then
               if u[1]<private then
                 unicode=u
                 glyph.unicode=unicode
               end
             elseif u<private then
               unicode=u
               glyph.unicode=unicode
             end
           else
             local t,n={},0
             for l=1,nsplit do
               local base=split[l]
               local u=unicodes[base] or unicodevector[base] or contextvector[name]
               if not u then
                 break
               elseif type(u)=="table" then
                 if u[1]>=private then
                   break
                 end
                 n=n+1
                 t[n]=u[1]
               else
                 if u>=private then
                   break
                 end
                 n=n+1
                 t[n]=u
               end
             end
             if n>0 then
               if n==1 then
                 unicode=t[1]
               else
                 unicode=t
               end
               glyph.unicode=unicode
             end
           end
           nl=nl+1
         end
         if not unicode or unicode=="" then
           local foundcodes,multiple=lpegmatch(uparser,name)
           if foundcodes then
             glyph.unicode=foundcodes
             if multiple then
               nl=nl+1
               unicode=true
             else
               ns=ns+1
               unicode=foundcodes
             end
           end
         end
         local r=overloads[unicode]
         if r then
           unicode=r.unicode
           glyph.unicode=unicode
         end
         if not unicode then
           missing[du]=true
           nofmissing=nofmissing+1
         end
       end
     end
   else
     local overload=overloads[du]
     if overload then
       glyph.unicode=overload.unicode
     end
   end
 end
 if type(checklookups)=="function" then
   checklookups(data,missing,nofmissing)
 end
 local collected=false
 local unicoded=0
 for i=1,#dlist do
   local du=dlist[i]
   local glyph=descriptions[du]
   if glyph.class=="ligature" and (force_ligatures or not glyph.unicode) then
     if not collected then
       collected=fonts.handlers.otf.readers.getcomponents(data)
       if not collected then
         break
       end
     end
     local u=collected[du]
     if u then
       local n=#u
       for i=1,n do
         if u[i]>private then
           n=0
           break
         end
       end
       if n>0 then
         if n>1 then
           glyph.unicode=u
         else
           glyph.unicode=u[1]
         end
         unicoded=unicoded+1
       end
     end
   end
 end
 if trace_mapping and unicoded>0 then
   report_fonts("%n ligature tounicode mappings deduced from gsub ligature features",unicoded)
 end
 if trace_mapping then
   for i=1,#dlist do
     local du=dlist[i]
     local glyph=descriptions[du]
     local name=glyph.name or "-"
     local index=glyph.index or 0
     local unicode=glyph.unicode
     if unicode then
       if type(unicode)=="table" then
         local unicodes={}
         for i=1,#unicode do
           unicodes[i]=formatters("%U",unicode[i])
         end
         report_fonts("internal slot %U, name %a, unicode %U, tounicode % t",index,name,du,unicodes)
       else
         report_fonts("internal slot %U, name %a, unicode %U, tounicode %U",index,name,du,unicode)
       end
     else
       report_fonts("internal slot %U, name %a, unicode %U",index,name,du)
     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 --- [luaotfload, fontloader-2017-02-11.lua scope for “font-map”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-oti” 8f48c06a1d632febd7231ad5dfadfc53] ---

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.handlers.otf
local otffeatures=constructors.features.otf
local registerotffeature=otffeatures.register
local otftables=otf.tables or {}
otf.tables=otftables
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
otf.modeinitializer=setmode
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,
   plug=setmode,
 }
}
registerotffeature {
 name="language",
 description="language",
 initializers={
   base=setlanguage,
   node=setlanguage,
   plug=setlanguage,
 }
}
registerotffeature {
 name="script",
 description="script",
 initializers={
   base=setscript,
   node=setscript,
   plug=setscript,
 }
}
otftables.featuretypes=allocate {
 gpos_single="position",
 gpos_pair="position",
 gpos_cursive="position",
 gpos_mark2base="position",
 gpos_mark2ligature="position",
 gpos_mark2mark="position",
 gpos_context="position",
 gpos_contextchain="position",
 gsub_single="substitution",
 gsub_multiple="substitution",
 gsub_alternate="substitution",
 gsub_ligature="substitution",
 gsub_context="substitution",
 gsub_contextchain="substitution",
 gsub_reversecontextchain="substitution",
 gsub_reversesub="substitution",
}
function otffeatures.checkeddefaultscript(featuretype,autoscript,scripts)
 if featuretype=="position" then
   local default=scripts.dflt
   if default then
     if autoscript=="position" or autoscript==true then
       return default
     else
       report_otf("script feature %s not applied, enable default positioning")
     end
   else
   end
 elseif featuretype=="substitution" then
   local default=scripts.dflt
   if default then
     if autoscript=="substitution" or autoscript==true then
       return default
     end
   end
 end
end
function otffeatures.checkeddefaultlanguage(featuretype,autolanguage,languages)
 if featuretype=="position" then
   local default=languages.dflt
   if default then
     if autolanguage=="position" or autolanguage==true then
       return default
     else
       report_otf("language feature %s not applied, enable default positioning")
     end
   else
   end
 elseif featuretype=="substitution" then
   local default=languages.dflt
   if default then
     if autolanguage=="substitution" or autolanguage==true then
       return default
     end
   end
 end
end

end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-oti”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-otr” 2bd0085b78027f261218d63034f43474] ---

if not modules then modules={} end modules ['font-otr']={
 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,type,unpack=next,type,unpack
local byte,lower,char,strip,gsub=string.byte,string.lower,string.char,string.strip,string.gsub
local bittest=bit32.btest
local concat,remove,unpack,fastcopy=table.concat,table.remov,table.unpack,table.fastcopy
local floor,abs,sqrt,round=math.floor,math.abs,math.sqrt,math.round
local P,R,S,C,Cs,Cc,Ct,Carg,Cmt=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Ct,lpeg.Carg,lpeg.Cmt
local lpegmatch=lpeg.match
local setmetatableindex=table.setmetatableindex
local formatters=string.formatters
local sortedkeys=table.sortedkeys
local sortedhash=table.sortedhash
local stripstring=string.strip
local utf16_to_utf8_be=utf.utf16_to_utf8_be
local report=logs.reporter("otf reader")
local trace_cmap=false
fonts=fonts or {}
local handlers=fonts.handlers or {}
fonts.handlers=handlers
local otf=handlers.otf or {}
handlers.otf=otf
local readers=otf.readers or {}
otf.readers=readers
local streamreader=utilities.files
local streamwriter=utilities.files
readers.streamreader=streamreader
readers.streamwriter=streamwriter
local openfile=streamreader.open
local closefile=streamreader.close
local setposition=streamreader.setposition
local skipshort=streamreader.skipshort
local readbytes=streamreader.readbytes
local readstring=streamreader.readstring
local readbyte=streamreader.readcardinal1
local readushort=streamreader.readcardinal2
local readuint=streamreader.readcardinal3
local readulong=streamreader.readcardinal4
local readshort=streamreader.readinteger2
local readlong=streamreader.readinteger4
local readfixed=streamreader.readfixed4
local readfword=readshort
local readufword=readushort
local readoffset=readushort
local read2dot14=streamreader.read2dot14
function streamreader.readtag(f)
 return lower(strip(readstring(f,4)))
end
local function readlongdatetime(f)
 local a,b,c,d,e,f,g,h=readbytes(f,8)
 return 0x100000000*d+0x1000000*e+0x10000*f+0x100*g+h
end
local tableversion=0.004
readers.tableversion=tableversion
local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000
local reportedskipped={}
local function reportskippedtable(tag)
 if not reportedskipped[tag] then
   report("loading of table %a skipped (reported once only)",tag)
   reportedskipped[tag]=true
 end
end
local reservednames={ [0]="copyright",
 "family",
 "subfamily",
 "uniqueid",
 "fullname",
 "version",
 "postscriptname",
 "trademark",
 "manufacturer",
 "designer",
 "description",
 "vendorurl",
 "designerurl",
 "license",
 "licenseurl",
 "reserved",
 "typographicfamily",
 "typographicsubfamily",
 "compatiblefullname",
 "sampletext",
 "cidfindfontname",
 "wwsfamily",
 "wwssubfamily",
 "lightbackgroundpalette",
 "darkbackgroundpalette",
}
local platforms={ [0]="unicode",
 "macintosh",
 "iso",
 "windows",
 "custom",
}
local encodings={
 unicode={ [0]="unicode 1.0 semantics",
   "unicode 1.1 semantics",
   "iso/iec 10646",
   "unicode 2.0 bmp",
   "unicode 2.0 full",
   "unicode variation sequences",
   "unicode full repertoire",
 },
 macintosh={ [0]="roman","japanese","chinese (traditional)","korean","arabic","hebrew","greek","russian",
   "rsymbol","devanagari","gurmukhi","gujarati","oriya","bengali","tamil","telugu","kannada",
   "malayalam","sinhalese","burmese","khmer","thai","laotian","georgian","armenian",
   "chinese (simplified)","tibetan","mongolian","geez","slavic","vietnamese","sindhi",
   "uninterpreted",
 },
 iso={ [0]="7-bit ascii",
   "iso 10646",
   "iso 8859-1",
 },
 windows={ [0]="symbol",
   "unicode bmp",
   "shiftjis",
   "prc",
   "big5",
   "wansung",
   "johab",
   "reserved 7",
   "reserved 8",
   "reserved 9",
   "unicode ucs-4",
 },
 custom={
 }
}
local decoders={
 unicode={},
 macintosh={},
 iso={},
 windows={
   ["unicode semantics"]=utf16_to_utf8_be,
   ["unicode bmp"]=utf16_to_utf8_be,
   ["unicode full"]=utf16_to_utf8_be,
   ["unicode 1.0 semantics"]=utf16_to_utf8_be,
   ["unicode 1.1 semantics"]=utf16_to_utf8_be,
   ["unicode 2.0 bmp"]=utf16_to_utf8_be,
   ["unicode 2.0 full"]=utf16_to_utf8_be,
   ["unicode variation sequences"]=utf16_to_utf8_be,
   ["unicode full repertoire"]=utf16_to_utf8_be,
 },
 custom={},
}
local languages={
 unicode={
   [ 0]="english",
 },
 macintosh={
   [ 0]="english",
 },
 iso={},
 windows={
   [0x0409]="english - united states",
 },
 custom={},
}
local standardromanencoding={ [0]=
 "notdef",".null","nonmarkingreturn","space","exclam","quotedbl",
 "numbersign","dollar","percent","ampersand","quotesingle","parenleft",
 "parenright","asterisk","plus","comma","hyphen","period","slash",
 "zero","one","two","three","four","five","six","seven","eight",
 "nine","colon","semicolon","less","equal","greater","question","at",
 "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O",
 "P","Q","R","S","T","U","V","W","X","Y","Z","bracketleft",
 "backslash","bracketright","asciicircum","underscore","grave","a","b",
 "c","d","e","f","g","h","i","j","k","l","m","n","o","p","q",
 "r","s","t","u","v","w","x","y","z","braceleft","bar",
 "braceright","asciitilde","Adieresis","Aring","Ccedilla","Eacute",
 "Ntilde","Odieresis","Udieresis","aacute","agrave","acircumflex",
 "adieresis","atilde","aring","ccedilla","eacute","egrave",
 "ecircumflex","edieresis","iacute","igrave","icircumflex","idieresis",
 "ntilde","oacute","ograve","ocircumflex","odieresis","otilde","uacute",
 "ugrave","ucircumflex","udieresis","dagger","degree","cent","sterling",
 "section","bullet","paragraph","germandbls","registered","copyright",
 "trademark","acute","dieresis","notequal","AE","Oslash","infinity",
 "plusminus","lessequal","greaterequal","yen","mu","partialdiff",
 "summation","product","pi","integral","ordfeminine","ordmasculine",
 "Omega","ae","oslash","questiondown","exclamdown","logicalnot",
 "radical","florin","approxequal","Delta","guillemotleft",
 "guillemotright","ellipsis","nonbreakingspace","Agrave","Atilde",
 "Otilde","OE","oe","endash","emdash","quotedblleft","quotedblright",
 "quoteleft","quoteright","divide","lozenge","ydieresis","Ydieresis",
 "fraction","currency","guilsinglleft","guilsinglright","fi","fl",
 "daggerdbl","periodcentered","quotesinglbase","quotedblbase",
 "perthousand","Acircumflex","Ecircumflex","Aacute","Edieresis","Egrave",
 "Iacute","Icircumflex","Idieresis","Igrave","Oacute","Ocircumflex",
 "apple","Ograve","Uacute","Ucircumflex","Ugrave","dotlessi",
 "circumflex","tilde","macron","breve","dotaccent","ring","cedilla",
 "hungarumlaut","ogonek","caron","Lslash","lslash","Scaron","scaron",
 "Zcaron","zcaron","brokenbar","Eth","eth","Yacute","yacute","Thorn",
 "thorn","minus","multiply","onesuperior","twosuperior","threesuperior",
 "onehalf","onequarter","threequarters","franc","Gbreve","gbreve",
 "Idotaccent","Scedilla","scedilla","Cacute","cacute","Ccaron","ccaron",
 "dcroat",
}
local weights={
 [100]="thin",
 [200]="extralight",
 [300]="light",
 [400]="normal",
 [500]="medium",
 [600]="semibold",
 [700]="bold",
 [800]="extrabold",
 [900]="black",
}
local widths={
 [1]="ultracondensed",
 [2]="extracondensed",
 [3]="condensed",
 [4]="semicondensed",
 [5]="normal",
 [6]="semiexpanded",
 [7]="expanded",
 [8]="extraexpanded",
 [9]="ultraexpanded",
}
setmetatableindex(weights,function(t,k)
 local r=floor((k+50)/100)*100
 local v=(r>900 and "black") or rawget(t,r) or "normal"
 return v
end)
setmetatableindex(widths,function(t,k)
 return "normal"
end)
local panoseweights={
 [ 0]="normal",
 [ 1]="normal",
 [ 2]="verylight",
 [ 3]="light",
 [ 4]="thin",
 [ 5]="book",
 [ 6]="medium",
 [ 7]="demi",
 [ 8]="bold",
 [ 9]="heavy",
 [10]="black",
}
local panosewidths={
 [ 0]="normal",
 [ 1]="normal",
 [ 2]="normal",
 [ 3]="normal",
 [ 4]="normal",
 [ 5]="expanded",
 [ 6]="condensed",
 [ 7]="veryexpanded",
 [ 8]="verycondensed",
 [ 9]="monospaced",
}
local platformnames={
 postscriptname=true,
 fullname=true,
 family=true,
 subfamily=true,
 typographicfamily=true,
 typographicsubfamily=true,
 compatiblefullname=true,
}
function readers.name(f,fontdata,specification)
 local datatable=fontdata.tables.name
 if datatable then
   setposition(f,datatable.offset)
   local format=readushort(f)
   local nofnames=readushort(f)
   local offset=readushort(f)
   local start=datatable.offset+offset
   local namelists={
     unicode={},
     windows={},
     macintosh={},
   }
   for i=1,nofnames do
     local platform=platforms[readushort(f)]
     if platform then
       local namelist=namelists[platform]
       if namelist then
         local encoding=readushort(f)
         local language=readushort(f)
         local encodings=encodings[platform]
         local languages=languages[platform]
         if encodings and languages then
           local encoding=encodings[encoding]
           local language=languages[language]
           if encoding and language then
             local name=reservednames[readushort(f)]
             if name then
               namelist[#namelist+1]={
                 platform=platform,
                 encoding=encoding,
                 language=language,
                 name=name,
                 length=readushort(f),
                 offset=start+readushort(f),
               }
             else
               skipshort(f,2)
             end
           else
             skipshort(f,3)
           end
         else
           skipshort(f,3)
         end
       else
         skipshort(f,5)
       end
     else
       skipshort(f,5)
     end
   end
   local names={}
   local done={}
   local function filter(platform,e,l)
     local namelist=namelists[platform]
     for i=1,#namelist do
       local name=namelist[i]
       local nametag=name.name
       if not done[nametag] then
         local encoding=name.encoding
         local language=name.language
         if (not e or encoding==e) and (not l or language==l) then
           setposition(f,name.offset)
           local content=readstring(f,name.length)
           local decoder=decoders[platform]
           if decoder then
             decoder=decoder[encoding]
           end
           if decoder then
             content=decoder(content)
           end
           names[nametag]={
             content=content,
             platform=platform,
             encoding=encoding,
             language=language,
           }
           done[nametag]=true
         end
       end
     end
   end
   filter("windows","unicode bmp","english - united states")
   filter("macintosh","roman","english")
   filter("windows")
   filter("macintosh")
   filter("unicode")
   fontdata.names=names
   if specification.platformnames then
     local collected={}
     for platform,namelist in next,namelists do
       local filtered=false
       for i=1,#namelist do
         local entry=namelist[i]
         local name=entry.name
         if platformnames[name] then
           setposition(f,entry.offset)
           local content=readstring(f,entry.length)
           local encoding=entry.encoding
           local decoder=decoders[platform]
           if decoder then
             decoder=decoder[encoding]
           end
           if decoder then
             content=decoder(content)
           end
           if filtered then
             filtered[name]=content
           else
             filtered={ [name]=content }
           end
         end
       end
       if filtered then
         collected[platform]=filtered
       end
     end
     fontdata.platformnames=collected
   end
 else
   fontdata.names={}
 end
end
local validutf=lpeg.patterns.validutf8
local function getname(fontdata,key)
 local names=fontdata.names
 if names then
   local value=names[key]
   if value then
     local content=value.content
     return lpegmatch(validutf,content) and content or nil
   end
 end
end
readers["os/2"]=function(f,fontdata)
 local datatable=fontdata.tables["os/2"]
 if datatable then
   setposition(f,datatable.offset)
   local version=readushort(f)
   local windowsmetrics={
     version=version,
     averagewidth=readshort(f),
     weightclass=readushort(f),
     widthclass=readushort(f),
     fstype=readushort(f),
     subscriptxsize=readshort(f),
     subscriptysize=readshort(f),
     subscriptxoffset=readshort(f),
     subscriptyoffset=readshort(f),
     superscriptxsize=readshort(f),
     superscriptysize=readshort(f),
     superscriptxoffset=readshort(f),
     superscriptyoffset=readshort(f),
     strikeoutsize=readshort(f),
     strikeoutpos=readshort(f),
     familyclass=readshort(f),
     panose={ readbytes(f,10) },
     unicoderanges={ readulong(f),readulong(f),readulong(f),readulong(f) },
     vendor=readstring(f,4),
     fsselection=readushort(f),
     firstcharindex=readushort(f),
     lastcharindex=readushort(f),
     typoascender=readshort(f),
     typodescender=readshort(f),
     typolinegap=readshort(f),
     winascent=readushort(f),
     windescent=readushort(f),
   }
   if version>=1 then
     windowsmetrics.codepageranges={ readulong(f),readulong(f) }
   end
   if version>=3 then
     windowsmetrics.xheight=readshort(f)
     windowsmetrics.capheight=readshort(f)
     windowsmetrics.defaultchar=readushort(f)
     windowsmetrics.breakchar=readushort(f)
   end
   windowsmetrics.weight=windowsmetrics.weightclass and weights[windowsmetrics.weightclass]
   windowsmetrics.width=windowsmetrics.widthclass and widths [windowsmetrics.widthclass]
   windowsmetrics.panoseweight=panoseweights[windowsmetrics.panose[3]]
   windowsmetrics.panosewidth=panosewidths [windowsmetrics.panose[4]]
   fontdata.windowsmetrics=windowsmetrics
 else
   fontdata.windowsmetrics={}
 end
end
readers.head=function(f,fontdata)
 local datatable=fontdata.tables.head
 if datatable then
   setposition(f,datatable.offset)
   local fontheader={
     version=readfixed(f),
     revision=readfixed(f),
     checksum=readulong(f),
     magic=readulong(f),
     flags=readushort(f),
     units=readushort(f),
     created=readlongdatetime(f),
     modified=readlongdatetime(f),
     xmin=readshort(f),
     ymin=readshort(f),
     xmax=readshort(f),
     ymax=readshort(f),
     macstyle=readushort(f),
     smallpixels=readushort(f),
     directionhint=readshort(f),
     indextolocformat=readshort(f),
     glyphformat=readshort(f),
   }
   fontdata.fontheader=fontheader
 else
   fontdata.fontheader={}
 end
 fontdata.nofglyphs=0
end
readers.hhea=function(f,fontdata,specification)
 if specification.details then
   local datatable=fontdata.tables.hhea
   if datatable then
     setposition(f,datatable.offset)
     fontdata.horizontalheader={
       version=readfixed(f),
       ascender=readfword(f),
       descender=readfword(f),
       linegap=readfword(f),
       maxadvancewidth=readufword(f),
       minleftsidebearing=readfword(f),
       minrightsidebearing=readfword(f),
       maxextent=readfword(f),
       caretsloperise=readshort(f),
       caretsloperun=readshort(f),
       caretoffset=readshort(f),
       reserved_1=readshort(f),
       reserved_2=readshort(f),
       reserved_3=readshort(f),
       reserved_4=readshort(f),
       metricdataformat=readshort(f),
       nofmetrics=readushort(f),
     }
   else
     fontdata.horizontalheader={
       nofmetrics=0,
     }
   end
 end
end
readers.vhea=function(f,fontdata,specification)
 if specification.details then
   local datatable=fontdata.tables.vhea
   if datatable then
     setposition(f,datatable.offset)
     local version=readfixed(f)
     fontdata.verticalheader={
       version=version,
       ascender=readfword(f),
       descender=readfword(f),
       linegap=readfword(f),
       maxadvanceheight=readufword(f),
       mintopsidebearing=readfword(f),
       minbottomsidebearing=readfword(f),
       maxextent=readfword(f),
       caretsloperise=readshort(f),
       caretsloperun=readshort(f),
       caretoffset=readshort(f),
       reserved_1=readshort(f),
       reserved_2=readshort(f),
       reserved_3=readshort(f),
       reserved_4=readshort(f),
       metricdataformat=readshort(f),
       nofmetrics=readushort(f),
     }
   else
     fontdata.verticalheader={
       nofmetrics=0,
     }
   end
 end
end
readers.maxp=function(f,fontdata,specification)
 if specification.details then
   local datatable=fontdata.tables.maxp
   if datatable then
     setposition(f,datatable.offset)
     local version=readfixed(f)
     local nofglyphs=readushort(f)
     fontdata.nofglyphs=nofglyphs
     if version==0.5 then
       fontdata.maximumprofile={
         version=version,
         nofglyphs=nofglyphs,
       }
       return
     elseif version==1.0 then
       fontdata.maximumprofile={
         version=version,
         nofglyphs=nofglyphs,
         points=readushort(f),
         contours=readushort(f),
         compositepoints=readushort(f),
         compositecontours=readushort(f),
         zones=readushort(f),
         twilightpoints=readushort(f),
         storage=readushort(f),
         functiondefs=readushort(f),
         instructiondefs=readushort(f),
         stackelements=readushort(f),
         sizeofinstructions=readushort(f),
         componentelements=readushort(f),
         componentdepth=readushort(f),
       }
       return
     end
   end
   fontdata.maximumprofile={
     version=version,
     nofglyphs=0,
   }
 end
end
readers.hmtx=function(f,fontdata,specification)
 if specification.glyphs then
   local datatable=fontdata.tables.hmtx
   if datatable then
     setposition(f,datatable.offset)
     local horizontalheader=fontdata.horizontalheader
     local nofmetrics=horizontalheader.nofmetrics
     local glyphs=fontdata.glyphs
     local nofglyphs=fontdata.nofglyphs
     local width=0
     local leftsidebearing=0
     for i=0,nofmetrics-1 do
       local glyph=glyphs[i]
       width=readshort(f)
       leftsidebearing=readshort(f)
       if width~=0 then
         glyph.width=width
       end
     end
     for i=nofmetrics,nofglyphs-1 do
       local glyph=glyphs[i]
       if width~=0 then
         glyph.width=width
       end
     end
   end
 end
end
readers.vmtx=function(f,fontdata,specification)
 if specification.glyphs then
   local datatable=fontdata.tables.vmtx
   if datatable then
     setposition(f,datatable.offset)
     local verticalheader=fontdata.verticalheader
     local nofmetrics=verticalheader.nofmetrics
     local glyphs=fontdata.glyphs
     local nofglyphs=fontdata.nofglyphs
     local vheight=0
     local vdefault=verticalheader.ascender+verticalheader.descender
     local topsidebearing=0
     for i=0,nofmetrics-1 do
       local glyph=glyphs[i]
       vheight=readshort(f)
       topsidebearing=readshort(f)
       if vheight~=0 and vheight~=vdefault then
         glyph.vheight=vheight
       end
     end
     for i=nofmetrics,nofglyphs-1 do
       local glyph=glyphs[i]
       if vheight~=0 and vheight~=vdefault then
         glyph.vheight=vheight
       end
     end
   end
 end
end
readers.vorg=function(f,fontdata,specification)
 if specification.glyphs then
   local datatable=fontdata.tables.vorg
   if datatable then
     report("todo: %s","vorg")
   end
 end
end
readers.post=function(f,fontdata,specification)
 local datatable=fontdata.tables.post
 if datatable then
   setposition(f,datatable.offset)
   local version=readfixed(f)
   fontdata.postscript={
     version=version,
     italicangle=round(1000*readfixed(f))/1000,
     underlineposition=readfword(f),
     underlinethickness=readfword(f),
     monospaced=readulong(f),
     minmemtype42=readulong(f),
     maxmemtype42=readulong(f),
     minmemtype1=readulong(f),
     maxmemtype1=readulong(f),
   }
   if not specification.glyphs then
   elseif version==1.0 then
     for index=0,#standardromanencoding do
       glyphs[index].name=standardromanencoding[index]
     end
   elseif version==2.0 then
     local glyphs=fontdata.glyphs
     local nofglyphs=readushort(f)
     local indices={}
     local names={}
     local maxnames=0
     for i=0,nofglyphs-1 do
       local nameindex=readushort(f)
       if nameindex>=258 then
         maxnames=maxnames+1
         nameindex=nameindex-257
         indices[nameindex]=i
       else
         glyphs[i].name=standardromanencoding[nameindex]
       end
     end
     for i=1,maxnames do
       local mapping=indices[i]
       if not mapping then
         report("quit post name fetching at %a of %a: %s",i,maxnames,"no index")
         break
       else
         local length=readbyte(f)
         if length>0 then
           glyphs[mapping].name=readstring(f,length)
         else
           report("quit post name fetching at %a of %a: %s",i,maxnames,"overflow")
           break
         end
       end
     end
   elseif version==2.5 then
   elseif version==3.0 then
   end
 else
   fontdata.postscript={}
 end
end
readers.cff=function(f,fontdata,specification)
 if specification.glyphs then
   reportskippedtable("cff")
 end
end
local formatreaders={}
local duplicatestoo=true
local sequence={
 { 3,1,4 },
 { 3,10,12 },
 { 0,3,4 },
 { 0,1,4 },
 { 0,0,6 },
 { 3,0,6 },
 { 0,5,14 },
 { 3,10,13 },
}
local supported={}
for i=1,#sequence do
 local sp,se,sf=unpack(sequence[i])
 local p=supported[sp]
 if not p then
   p={}
   supported[sp]=p
 end
 local e=p[se]
 if not e then
   e={}
   p[se]=e
 end
 e[sf]=true
end
formatreaders[4]=function(f,fontdata,offset)
 setposition(f,offset+2)
 local length=readushort(f)
 local language=readushort(f)
 local nofsegments=readushort(f)/2
 skipshort(f,3)
 local endchars={}
 local startchars={}
 local deltas={}
 local offsets={}
 local indices={}
 local mapping=fontdata.mapping
 local glyphs=fontdata.glyphs
 local duplicates=fontdata.duplicates
 local nofdone=0
 for i=1,nofsegments do
   endchars[i]=readushort(f)
 end
 local reserved=readushort(f)
 for i=1,nofsegments do
   startchars[i]=readushort(f)
 end
 for i=1,nofsegments do
   deltas[i]=readshort(f)
 end
 for i=1,nofsegments do
   offsets[i]=readushort(f)
 end
 local size=(length-2*2-5*2-4*nofsegments*2)/2
 for i=1,size-1 do
   indices[i]=readushort(f)
 end
 for segment=1,nofsegments do
   local startchar=startchars[segment]
   local endchar=endchars[segment]
   local offset=offsets[segment]
   local delta=deltas[segment]
   if startchar==0xFFFF and endchar==0xFFFF then
   elseif startchar==0xFFFF and offset==0 then
   elseif offset==0xFFFF then
   elseif offset==0 then
     if trace_cmap then
       report("format 4.%i segment %2i from %C upto %C at index %H",1,segment,startchar,endchar,(startchar+delta)%65536)
     end
     for unicode=startchar,endchar do
       local index=(unicode+delta)%65536
       if index and index>0 then
         local glyph=glyphs[index]
         if glyph then
           local gu=glyph.unicode
           if not gu then
             glyph.unicode=unicode
             nofdone=nofdone+1
           elseif gu~=unicode then
             if duplicatestoo then
               local d=duplicates[gu]
               if d then
                 d[unicode]=true
               else
                 duplicates[gu]={ [unicode]=true }
               end
             else
               report("duplicate case 1: %C %04i %s",unicode,index,glyphs[index].name)
             end
           end
           if not mapping[index] then
             mapping[index]=unicode
           end
         end
       end
     end
   else
     local shift=(segment-nofsegments+offset/2)-startchar
     if trace_cmap then
       report("format 4.%i segment %2i from %C upto %C at index %H",0,segment,startchar,endchar,(startchar+delta)%65536)
     end
     for unicode=startchar,endchar do
       local slot=shift+unicode
       local index=indices[slot]
       if index and index>0 then
         index=(index+delta)%65536
         local glyph=glyphs[index]
         if glyph then
           local gu=glyph.unicode
           if not gu then
             glyph.unicode=unicode
             nofdone=nofdone+1
           elseif gu~=unicode then
             if duplicatestoo then
               local d=duplicates[gu]
               if d then
                 d[unicode]=true
               else
                 duplicates[gu]={ [unicode]=true }
               end
             else
               report("duplicate case 2: %C %04i %s",unicode,index,glyphs[index].name)
             end
           end
           if not mapping[index] then
             mapping[index]=unicode
           end
         end
       end
     end
   end
 end
 return nofdone
end
formatreaders[6]=function(f,fontdata,offset)
 setposition(f,offset)
 local format=readushort(f)
 local length=readushort(f)
 local language=readushort(f)
 local mapping=fontdata.mapping
 local glyphs=fontdata.glyphs
 local duplicates=fontdata.duplicates
 local start=readushort(f)
 local count=readushort(f)
 local stop=start+count-1
 local nofdone=0
 if trace_cmap then
   report("format 6 from %C to %C",2,start,stop)
 end
 for unicode=start,stop do
   local index=readushort(f)
   if index>0 then
     local glyph=glyphs[index]
     if glyph then
       local gu=glyph.unicode
       if not gu then
         glyph.unicode=unicode
         nofdone=nofdone+1
       elseif gu~=unicode then
       end
       if not mapping[index] then
         mapping[index]=unicode
       end
     end
   end
 end
 return nofdone
end
formatreaders[12]=function(f,fontdata,offset)
 setposition(f,offset+2+2+4+4)
 local mapping=fontdata.mapping
 local glyphs=fontdata.glyphs
 local duplicates=fontdata.duplicates
 local nofgroups=readulong(f)
 local nofdone=0
 for i=1,nofgroups do
   local first=readulong(f)
   local last=readulong(f)
   local index=readulong(f)
   if trace_cmap then
     report("format 12 from %C to %C starts at index %i",first,last,index)
   end
   for unicode=first,last do
     local glyph=glyphs[index]
     if glyph then
       local gu=glyph.unicode
       if not gu then
         glyph.unicode=unicode
         nofdone=nofdone+1
       elseif gu~=unicode then
         local d=duplicates[gu]
         if d then
           d[unicode]=true
         else
           duplicates[gu]={ [unicode]=true }
         end
       end
       if not mapping[index] then
         mapping[index]=unicode
       end
     end
     index=index+1
   end
 end
 return nofdone
end
formatreaders[13]=function(f,fontdata,offset)
 setposition(f,offset+2+2+4+4)
 local mapping=fontdata.mapping
 local glyphs=fontdata.glyphs
 local duplicates=fontdata.duplicates
 local nofgroups=readulong(f)
 local nofdone=0
 for i=1,nofgroups do
   local first=readulong(f)
   local last=readulong(f)
   local index=readulong(f)
   if first<privateoffset then
     if trace_cmap then
       report("format 13 from %C to %C get index %i",first,last,index)
     end
     local glyph=glyphs[index]
     local unicode=glyph.unicode
     if not unicode then
       unicode=first
       glyph.unicode=unicode
       first=first+1
     end
     local list=duplicates[unicode]
     mapping[index]=unicode
     if not list then
       list={}
       duplicates[unicode]=list
     end
     if last>=privateoffset then
       local limit=privateoffset-1
       report("format 13 from %C to %C pruned to %C",first,last,limit)
       last=limit
     end
     for unicode=first,last do
       list[unicode]=true
     end
     nofdone=nofdone+last-first+1
   else
     report("format 13 from %C to %C ignored",first,last)
   end
 end
 return nofdone
end
formatreaders[14]=function(f,fontdata,offset)
 if offset and offset~=0 then
   setposition(f,offset)
   local format=readushort(f)
   local length=readulong(f)
   local nofrecords=readulong(f)
   local records={}
   local variants={}
   local nofdone=0
   fontdata.variants=variants
   for i=1,nofrecords do
     records[i]={
       selector=readuint(f),
       default=readulong(f),
       other=readulong(f),
     }
   end
   for i=1,nofrecords do
     local record=records[i]
     local selector=record.selector
     local default=record.default
     local other=record.other
     local other=record.other
     if other~=0 then
       setposition(f,offset+other)
       local mapping={}
       local count=readulong(f)
       for i=1,count do
         mapping[readuint(f)]=readushort(f)
       end
       nofdone=nofdone+count
       variants[selector]=mapping
     end
   end
   return nofdone
 else
   return 0
 end
end
local function checkcmap(f,fontdata,records,platform,encoding,format)
 local data=records[platform]
 if not data then
   return 0
 end
 data=data[encoding]
 if not data then
   return 0
 end
 data=data[format]
 if not data then
   return 0
 end
 local reader=formatreaders[format]
 if not reader then
   return 0
 end
 local p=platforms[platform]
 local e=encodings[p]
 local n=reader(f,fontdata,data) or 0
 report("cmap checked: platform %i (%s), encoding %i (%s), format %i, new unicodes %i",platform,p,encoding,e and e[encoding] or "?",format,n)
 return n
end
function readers.cmap(f,fontdata,specification)
 if specification.glyphs then
   local datatable=fontdata.tables.cmap
   if datatable then
     local tableoffset=datatable.offset
     setposition(f,tableoffset)
     local version=readushort(f)
     local noftables=readushort(f)
     local records={}
     local unicodecid=false
     local variantcid=false
     local variants={}
     local duplicates=fontdata.duplicates or {}
     fontdata.duplicates=duplicates
     for i=1,noftables do
       local platform=readushort(f)
       local encoding=readushort(f)
       local offset=readulong(f)
       local record=records[platform]
       if not record then
         records[platform]={
           [encoding]={
             offsets={ offset },
             formats={},
           }
         }
       else
         local subtables=record[encoding]
         if not subtables then
           record[encoding]={
             offsets={ offset },
             formats={},
           }
         else
           local offsets=subtables.offsets
           offsets[#offsets+1]=offset
         end
       end
     end
     report("found cmaps:")
     for platform,record in sortedhash(records) do
       local p=platforms[platform]
       local e=encodings[p]
       local sp=supported[platform]
       local ps=p or "?"
       if sp then
         report("  platform %i: %s",platform,ps)
       else
         report("  platform %i: %s (unsupported)",platform,ps)
       end
       for encoding,subtables in sortedhash(record) do
         local se=sp and sp[encoding]
         local es=e and e[encoding] or "?"
         if se then
           report("    encoding %i: %s",encoding,es)
         else
           report("    encoding %i: %s (unsupported)",encoding,es)
         end
         local offsets=subtables.offsets
         local formats=subtables.formats
         for i=1,#offsets do
           local offset=tableoffset+offsets[i]
           setposition(f,offset)
           formats[readushort(f)]=offset
         end
         record[encoding]=formats
         local list=sortedkeys(formats)
         for i=1,#list do
           if not (se and se[list[i]]) then
             list[i]=list[i].." (unsupported)"
           end
         end
         report("      formats: % t",list)
       end
     end
     local ok=false
     for i=1,#sequence do
       local sp,se,sf=unpack(sequence[i])
       if checkcmap(f,fontdata,records,sp,se,sf)>0 then
         ok=true
       end
     end
     if not ok then
       report("no useable unicode cmap found")
     end
     fontdata.cidmaps={
       version=version,
       noftables=noftables,
       records=records,
     }
   else
     fontdata.cidmaps={}
   end
 end
end
function readers.loca(f,fontdata,specification)
 if specification.glyphs then
   reportskippedtable("loca")
 end
end
function readers.glyf(f,fontdata,specification)
 if specification.glyphs then
   reportskippedtable("glyf")
 end
end
function readers.colr(f,fontdata,specification)
 if specification.glyphs then
   reportskippedtable("colr")
 end
end
function readers.cpal(f,fontdata,specification)
 if specification.glyphs then
   reportskippedtable("cpal")
 end
end
function readers.svg(f,fontdata,specification)
 if specification.glyphs then
   reportskippedtable("svg")
 end
end
function readers.kern(f,fontdata,specification)
 if specification.kerns then
   local datatable=fontdata.tables.kern
   if datatable then
     setposition(f,datatable.offset)
     local version=readushort(f)
     local noftables=readushort(f)
     for i=1,noftables do
       local version=readushort(f)
       local length=readushort(f)
       local coverage=readushort(f)
       local format=bit32.rshift(coverage,8)
       if format==0 then
         local nofpairs=readushort(f)
         local searchrange=readushort(f)
         local entryselector=readushort(f)
         local rangeshift=readushort(f)
         local kerns={}
         local glyphs=fontdata.glyphs
         for i=1,nofpairs do
           local left=readushort(f)
           local right=readushort(f)
           local kern=readfword(f)
           local glyph=glyphs[left]
           local kerns=glyph.kerns
           if kerns then
             kerns[right]=kern
           else
             glyph.kerns={ [right]=kern }
           end
         end
       elseif format==2 then
         report("todo: kern classes")
       else
         report("todo: kerns")
       end
     end
   end
 end
end
function readers.gdef(f,fontdata,specification)
 if specification.details then
   reportskippedtable("gdef")
 end
end
function readers.gsub(f,fontdata,specification)
 if specification.details then
   reportskippedtable("gsub")
 end
end
function readers.gpos(f,fontdata,specification)
 if specification.details then
   reportskippedtable("gpos")
 end
end
function readers.math(f,fontdata,specification)
 if specification.glyphs then
   reportskippedtable("math")
 end
end
local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo)
 local fontdata=sub and maindata.subfonts and maindata.subfonts[sub] or maindata
 local names=fontdata.names
 local info=nil
 if names then
   local metrics=fontdata.windowsmetrics or {}
   local postscript=fontdata.postscript   or {}
   local fontheader=fontdata.fontheader   or {}
   local cffinfo=fontdata.cffinfo    or {}
   local filename=fontdata.filename
   local weight=getname(fontdata,"weight") or (cffinfo and cffinfo.weight) or (metrics and metrics.weight)
   local width=getname(fontdata,"width") or (cffinfo and cffinfo.width ) or (metrics and metrics.width )
   local fontname=getname(fontdata,"postscriptname")
   local fullname=getname(fontdata,"fullname")
   local family=getname(fontdata,"family")
   local subfamily=getname(fontdata,"subfamily")
   local familyname=getname(fontdata,"typographicfamily")
   local subfamilyname=getname(fontdata,"typographicsubfamily")
   local compatiblename=getname(fontdata,"compatiblefullname")
   if rawfamilynames then
   else
     if not  familyname then  familyname=family end
     if not subfamilyname then subfamilyname=subfamily end
   end
   info={
     subfontindex=fontdata.subfontindex or sub or 0,
     version=getname(fontdata,"version"),
     fontname=fontname,
     fullname=fullname,
     family=family,
     subfamily=subfamily,
     familyname=familyname,
     subfamilyname=subfamilyname,
     compatiblename=compatiblename,
     weight=weight and lower(weight),
     width=width and lower(width),
     pfmweight=metrics.weightclass or 400,
     pfmwidth=metrics.widthclass or 5,
     panosewidth=metrics.panosewidth,
     panoseweight=metrics.panoseweight,
     italicangle=postscript.italicangle or 0,
     units=fontheader.units or 0,
     designsize=fontdata.designsize,
     minsize=fontdata.minsize,
     maxsize=fontdata.maxsize,
     monospaced=(tonumber(postscript.monospaced or 0)>0) or metrics.panosewidth=="monospaced",
     averagewidth=metrics.averagewidth,
     xheight=metrics.xheight,
     capheight=metrics.capheight,
     ascender=metrics.typoascender,
     descender=metrics.typodescender,
     platformnames=platformnames and fontdata.platformnames or nil,
   }
   if metricstoo then
     local keys={
       "version",
       "ascender","descender","linegap",
       "maxadvancewidth","maxadvanceheight","maxextent",
       "minbottomsidebearing","mintopsidebearing",
     }
     local h=fontdata.horizontalheader or {}
     local v=fontdata.verticalheader  or {}
     if h then
       local th={}
       local tv={}
       for i=1,#keys do
         local key=keys[i]
         th[key]=h[key] or 0
         tv[key]=v[key] or 0
       end
       info.horizontalmetrics=th
       info.verticalmetrics=tv
     end
   end
 elseif n then
   info={
     filename=fontdata.filename,
     comment="there is no info for subfont "..n,
   }
 else
   info={
     filename=fontdata.filename,
     comment="there is no info",
   }
 end
 return info
end
local function loadtables(f,specification,offset)
 if offset then
   setposition(f,offset)
 end
 local tables={}
 local basename=file.basename(specification.filename)
 local filesize=specification.filesize
 local filetime=specification.filetime
 local fontdata={
   filename=basename,
   filesize=filesize,
   filetime=filetime,
   version=readstring(f,4),
   noftables=readushort(f),
   searchrange=readushort(f),
   entryselector=readushort(f),
   rangeshift=readushort(f),
   tables=tables,
 }
 for i=1,fontdata.noftables do
   local tag=lower(stripstring(readstring(f,4)))
   local checksum=readulong(f)
   local offset=readulong(f)
   local length=readulong(f)
   if offset+length>filesize then
     report("bad %a table in file %a",tag,basename)
   end
   tables[tag]={
     checksum=checksum,
     offset=offset,
     length=length,
   }
 end
 if tables.cff then
   fontdata.format="opentype"
 else
   fontdata.format="truetype"
 end
 return fontdata
end
local function prepareglyps(fontdata)
 local glyphs=setmetatableindex(function(t,k)
   local v={
     index=k,
   }
   t[k]=v
   return v
 end)
 fontdata.glyphs=glyphs
 fontdata.mapping={}
end
local function readdata(f,offset,specification)
 local fontdata=loadtables(f,specification,offset)
 if specification.glyphs then
   prepareglyps(fontdata)
 end
 readers["name"](f,fontdata,specification)
 local askedname=specification.askedname
 if askedname then
   local fullname=getname(fontdata,"fullname") or ""
   local cleanname=gsub(askedname,"[^a-zA-Z0-9]","")
   local foundname=gsub(fullname,"[^a-zA-Z0-9]","")
   if lower(cleanname)~=lower(foundname) then
     return
   end
 end
 readers["os/2"](f,fontdata,specification)
 readers["head"](f,fontdata,specification)
 readers["maxp"](f,fontdata,specification)
 readers["hhea"](f,fontdata,specification)
 readers["vhea"](f,fontdata,specification)
 readers["hmtx"](f,fontdata,specification)
 readers["vmtx"](f,fontdata,specification)
 readers["vorg"](f,fontdata,specification)
 readers["post"](f,fontdata,specification)
 readers["cff" ](f,fontdata,specification)
 readers["cmap"](f,fontdata,specification)
 readers["loca"](f,fontdata,specification)
 readers["glyf"](f,fontdata,specification)
 readers["colr"](f,fontdata,specification)
 readers["cpal"](f,fontdata,specification)
 readers["svg" ](f,fontdata,specification)
 readers["kern"](f,fontdata,specification)
 readers["gdef"](f,fontdata,specification)
 readers["gsub"](f,fontdata,specification)
 readers["gpos"](f,fontdata,specification)
 readers["math"](f,fontdata,specification)
 fontdata.locations=nil
 fontdata.tables=nil
 fontdata.cidmaps=nil
 fontdata.dictionaries=nil
 return fontdata
end
local function loadfontdata(specification)
 local filename=specification.filename
 local fileattr=lfs.attributes(filename)
 local filesize=fileattr and fileattr.size or 0
 local filetime=fileattr and fileattr.modification or 0
 local f=openfile(filename,true)
 if not f then
   report("unable to open %a",filename)
 elseif filesize==0 then
   report("empty file %a",filename)
   closefile(f)
 else
   specification.filesize=filesize
   specification.filetime=filetime
   local version=readstring(f,4)
   local fontdata=nil
   if version=="OTTO" or version=="true" or version=="\0\1\0\0" then
     fontdata=readdata(f,0,specification)
   elseif version=="ttcf" then
     local subfont=tonumber(specification.subfont)
     local offsets={}
     local ttcversion=readulong(f)
     local nofsubfonts=readulong(f)
     for i=1,nofsubfonts do
       offsets[i]=readulong(f)
     end
     if subfont then
       if subfont>=1 and subfont<=nofsubfonts then
         fontdata=readdata(f,offsets[subfont],specification)
       else
         report("no subfont %a in file %a",subfont,filename)
       end
     else
       subfont=specification.subfont
       if type(subfont)=="string" and subfont~="" then
         specification.askedname=subfont
         for i=1,nofsubfonts do
           fontdata=readdata(f,offsets[i],specification)
           if fontdata then
             fontdata.subfontindex=i
             report("subfont named %a has index %a",subfont,i)
             break
           end
         end
         if not fontdata then
           report("no subfont named %a",subfont)
         end
       else
         local subfonts={}
         fontdata={
           filename=filename,
           filesize=filesize,
           filetime=filetime,
           version=version,
           subfonts=subfonts,
           ttcversion=ttcversion,
           nofsubfonts=nofsubfonts,
         }
         for i=1,nofsubfonts do
           subfonts[i]=readdata(f,offsets[i],specification)
         end
       end
     end
   else
     report("unknown version %a in file %a",version,filename)
   end
   closefile(f)
   return fontdata or {}
 end
end
local function loadfont(specification,n)
 if type(specification)=="string" then
   specification={
     filename=specification,
     info=true,
     details=true,
     glyphs=true,
     shapes=true,
     kerns=true,
     globalkerns=true,
     lookups=true,
     subfont=n or true,
     tounicode=false,
   }
 end
 if specification.shapes or specification.lookups or specification.kerns then
   specification.glyphs=true
 end
 if specification.glyphs then
   specification.details=true
 end
 if specification.details then
   specification.info=true
 end
 if specification.platformnames then
   specification.platformnames=true
 end
 local function message(str)
   report("fatal error in file %a: %s\n%s",specification.filename,str,debug.traceback())
 end
 local ok,result=xpcall(loadfontdata,message,specification)
 if ok then
   return result
 end
end
function readers.loadshapes(filename,n)
 local fontdata=loadfont {
   filename=filename,
   shapes=true,
   subfont=n,
 }
 if fontdata then
   for k,v in next,fontdata.glyphs do
     v.class=nil
     v.index=nil
     v.math=nil
   end
 end
 return fontdata and {
   filename=filename,
   format=fontdata.format,
   glyphs=fontdata.glyphs,
   units=fontdata.fontheader.units,
 } or {
   filename=filename,
   format="unknown",
   glyphs={},
   units=0,
 }
end
function readers.loadfont(filename,n)
 local fontdata=loadfont {
   filename=filename,
   glyphs=true,
   shapes=false,
   lookups=true,
   subfont=n,
 }
 if fontdata then
   return {
     tableversion=tableversion,
     creator="context mkiv",
     size=fontdata.filesize,
     time=fontdata.filetime,
     glyphs=fontdata.glyphs,
     descriptions=fontdata.descriptions,
     format=fontdata.format,
     goodies={},
     metadata=getinfo(fontdata,n,false,false,true),
     properties={
       hasitalics=fontdata.hasitalics or false,
       maxcolorclass=fontdata.maxcolorclass,
       hascolor=fontdata.hascolor or false,
     },
     resources={
       filename=filename,
       private=privateoffset,
       duplicates=fontdata.duplicates or {},
       features=fontdata.features  or {},
       sublookups=fontdata.sublookups or {},
       marks=fontdata.marks    or {},
       markclasses=fontdata.markclasses or {},
       marksets=fontdata.marksets  or {},
       sequences=fontdata.sequences  or {},
       variants=fontdata.variants,
       version=getname(fontdata,"version"),
       cidinfo=fontdata.cidinfo,
       mathconstants=fontdata.mathconstants,
       colorpalettes=fontdata.colorpalettes,
       svgshapes=fontdata.svgshapes,
     },
   }
 end
end
function readers.getinfo(filename,specification)
 local subfont=nil
 local platformnames=false
 local rawfamilynames=false
 if type(specification)=="table" then
   subfont=tonumber(specification.subfont)
   platformnames=specification.platformnames
   rawfamilynames=specification.rawfamilynames
 else
   subfont=tonumber(specification)
 end
 local fontdata=loadfont {
   filename=filename,
   details=true,
   platformnames=platformnames,
 }
 if fontdata then
   local subfonts=fontdata.subfonts
   if not subfonts then
     return getinfo(fontdata,nil,platformnames,rawfamilynames)
   elseif not subfont then
     local info={}
     for i=1,#subfonts do
       info[i]=getinfo(fontdata,i,platformnames,rawfamilynames)
     end
     return info
   elseif subfont>=1 and subfont<=#subfonts then
     return getinfo(fontdata,subfont,platformnames,rawfamilynames)
   else
     return {
       filename=filename,
       comment="there is no subfont "..subfont.." in this file"
     }
   end
 else
   return {
     filename=filename,
     comment="the file cannot be opened for reading",
   }
 end
end
function readers.rehash(fontdata,hashmethod)
 report("the %a helper is not yet implemented","rehash")
end
function readers.checkhash(fontdata)
 report("the %a helper is not yet implemented","checkhash")
end
function readers.pack(fontdata,hashmethod)
 report("the %a helper is not yet implemented","pack")
end
function readers.unpack(fontdata)
 report("the %a helper is not yet implemented","unpack")
end
function readers.expand(fontdata)
 report("the %a helper is not yet implemented","unpack")
end
function readers.compact(fontdata)
 report("the %a helper is not yet implemented","compact")
end
local extenders={}
function readers.registerextender(extender)
 extenders[#extenders+1]=extender
end
function readers.extend(fontdata)
 for i=1,#extenders do
   local extender=extenders[i]
   local name=extender.name or "unknown"
   local action=extender.action
   if action then
     action(fontdata)
   end
 end
end

end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-otr”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-cff” f3fc74e8629f7a2825c34a34550c790d] ---

if not modules then modules={} end modules ['font-cff']={
 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,type,tonumber=next,type,tonumber
local byte=string.byte
local concat,remove=table.concat,table.remove
local floor,abs,round,ceil=math.floor,math.abs,math.round,math.ceil
local P,C,R,S,C,Cs,Ct=lpeg.P,lpeg.C,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Ct
local lpegmatch=lpeg.match
local formatters=string.formatters
local readers=fonts.handlers.otf.readers
local streamreader=readers.streamreader
local readbytes=streamreader.readbytes
local readstring=streamreader.readstring
local readbyte=streamreader.readcardinal1
local readushort=streamreader.readcardinal2
local readuint=streamreader.readcardinal3
local readulong=streamreader.readcardinal4
local setposition=streamreader.setposition
local getposition=streamreader.getposition
local setmetatableindex=table.setmetatableindex
local trace_charstrings=false trackers.register("fonts.cff.charstrings",function(v) trace_charstrings=v end)
local report=logs.reporter("otf reader","cff")
local parsedictionaries
local parsecharstring
local parsecharstrings
local resetcharstrings
local parseprivates
local defaultstrings={ [0]=
 ".notdef","space","exclam","quotedbl","numbersign","dollar","percent",
 "ampersand","quoteright","parenleft","parenright","asterisk","plus",
 "comma","hyphen","period","slash","zero","one","two","three","four",
 "five","six","seven","eight","nine","colon","semicolon","less",
 "equal","greater","question","at","A","B","C","D","E","F","G","H",
 "I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W",
 "X","Y","Z","bracketleft","backslash","bracketright","asciicircum",
 "underscore","quoteleft","a","b","c","d","e","f","g","h","i","j",
 "k","l","m","n","o","p","q","r","s","t","u","v","w","x","y",
 "z","braceleft","bar","braceright","asciitilde","exclamdown","cent",
 "sterling","fraction","yen","florin","section","currency",
 "quotesingle","quotedblleft","guillemotleft","guilsinglleft",
 "guilsinglright","fi","fl","endash","dagger","daggerdbl",
 "periodcentered","paragraph","bullet","quotesinglbase","quotedblbase",
 "quotedblright","guillemotright","ellipsis","perthousand","questiondown",
 "grave","acute","circumflex","tilde","macron","breve","dotaccent",
 "dieresis","ring","cedilla","hungarumlaut","ogonek","caron","emdash",
 "AE","ordfeminine","Lslash","Oslash","OE","ordmasculine","ae",
 "dotlessi","lslash","oslash","oe","germandbls","onesuperior",
 "logicalnot","mu","trademark","Eth","onehalf","plusminus","Thorn",
 "onequarter","divide","brokenbar","degree","thorn","threequarters",
 "twosuperior","registered","minus","eth","multiply","threesuperior",
 "copyright","Aacute","Acircumflex","Adieresis","Agrave","Aring",
 "Atilde","Ccedilla","Eacute","Ecircumflex","Edieresis","Egrave",
 "Iacute","Icircumflex","Idieresis","Igrave","Ntilde","Oacute",
 "Ocircumflex","Odieresis","Ograve","Otilde","Scaron","Uacute",
 "Ucircumflex","Udieresis","Ugrave","Yacute","Ydieresis","Zcaron",
 "aacute","acircumflex","adieresis","agrave","aring","atilde",
 "ccedilla","eacute","ecircumflex","edieresis","egrave","iacute",
 "icircumflex","idieresis","igrave","ntilde","oacute","ocircumflex",
 "odieresis","ograve","otilde","scaron","uacute","ucircumflex",
 "udieresis","ugrave","yacute","ydieresis","zcaron","exclamsmall",
 "Hungarumlautsmall","dollaroldstyle","dollarsuperior","ampersandsmall",
 "Acutesmall","parenleftsuperior","parenrightsuperior","twodotenleader",
 "onedotenleader","zerooldstyle","oneoldstyle","twooldstyle",
 "threeoldstyle","fouroldstyle","fiveoldstyle","sixoldstyle",
 "sevenoldstyle","eightoldstyle","nineoldstyle","commasuperior",
 "threequartersemdash","periodsuperior","questionsmall","asuperior",
 "bsuperior","centsuperior","dsuperior","esuperior","isuperior",
 "lsuperior","msuperior","nsuperior","osuperior","rsuperior","ssuperior",
 "tsuperior","ff","ffi","ffl","parenleftinferior","parenrightinferior",
 "Circumflexsmall","hyphensuperior","Gravesmall","Asmall","Bsmall",
 "Csmall","Dsmall","Esmall","Fsmall","Gsmall","Hsmall","Ismall",
 "Jsmall","Ksmall","Lsmall","Msmall","Nsmall","Osmall","Psmall",
 "Qsmall","Rsmall","Ssmall","Tsmall","Usmall","Vsmall","Wsmall",
 "Xsmall","Ysmall","Zsmall","colonmonetary","onefitted","rupiah",
 "Tildesmall","exclamdownsmall","centoldstyle","Lslashsmall",
 "Scaronsmall","Zcaronsmall","Dieresissmall","Brevesmall","Caronsmall",
 "Dotaccentsmall","Macronsmall","figuredash","hypheninferior",
 "Ogoneksmall","Ringsmall","Cedillasmall","questiondownsmall","oneeighth",
 "threeeighths","fiveeighths","seveneighths","onethird","twothirds",
 "zerosuperior","foursuperior","fivesuperior","sixsuperior",
 "sevensuperior","eightsuperior","ninesuperior","zeroinferior",
 "oneinferior","twoinferior","threeinferior","fourinferior",
 "fiveinferior","sixinferior","seveninferior","eightinferior",
 "nineinferior","centinferior","dollarinferior","periodinferior",
 "commainferior","Agravesmall","Aacutesmall","Acircumflexsmall",
 "Atildesmall","Adieresissmall","Aringsmall","AEsmall","Ccedillasmall",
 "Egravesmall","Eacutesmall","Ecircumflexsmall","Edieresissmall",
 "Igravesmall","Iacutesmall","Icircumflexsmall","Idieresissmall",
 "Ethsmall","Ntildesmall","Ogravesmall","Oacutesmall","Ocircumflexsmall",
 "Otildesmall","Odieresissmall","OEsmall","Oslashsmall","Ugravesmall",
 "Uacutesmall","Ucircumflexsmall","Udieresissmall","Yacutesmall",
 "Thornsmall","Ydieresissmall","001.000","001.001","001.002","001.003",
 "Black","Bold","Book","Light","Medium","Regular","Roman","Semibold",
}
local cffreaders={
 readbyte,
 readushort,
 readuint,
 readulong,
}
local function readheader(f)
 local offset=getposition(f)
 local header={
   offset=offset,
   major=readbyte(f),
   minor=readbyte(f),
   size=readbyte(f),
   osize=readbyte(f),
 }
 setposition(f,offset+header.size)
 return header
end
local function readlengths(f)
 local count=readushort(f)
 if count==0 then
   return {}
 end
 local osize=readbyte(f)
 local read=cffreaders[osize]
 if not read then
   report("bad offset size: %i",osize)
   return {}
 end
 local lengths={}
 local previous=read(f)
 for i=1,count do
   local offset=read(f)
   lengths[i]=offset-previous
   previous=offset
 end
 return lengths
end
local function readfontnames(f)
 local names=readlengths(f)
 for i=1,#names do
   names[i]=readstring(f,names[i])
 end
 return names
end
local function readtopdictionaries(f)
 local dictionaries=readlengths(f)
 for i=1,#dictionaries do
   dictionaries[i]=readstring(f,dictionaries[i])
 end
 return dictionaries
end
local function readstrings(f)
 local lengths=readlengths(f)
 local strings=setmetatableindex({},defaultstrings)
 local index=#defaultstrings
 for i=1,#lengths do
   index=index+1
   strings[index]=readstring(f,lengths[i])
 end
 return strings
end
do
 local stack={}
 local top=0
 local result={}
 local strings={}
 local p_single=P("\00")/function()
     result.version=strings[stack[top]] or "unset"
     top=0
   end+P("\01")/function()
     result.notice=strings[stack[top]] or "unset"
     top=0
   end+P("\02")/function()
     result.fullname=strings[stack[top]] or "unset"
     top=0
   end+P("\03")/function()
     result.familyname=strings[stack[top]] or "unset"
     top=0
   end+P("\04")/function()
     result.weight=strings[stack[top]] or "unset"
     top=0
   end+P("\05")/function()
     result.fontbbox={ unpack(stack,1,4) }
     top=0
   end
+P("\13")/function()
     result.uniqueid=stack[top]
     top=0
   end+P("\14")/function()
     result.xuid=concat(stack,"",1,top)
     top=0
   end+P("\15")/function()
     result.charset=stack[top]
     top=0
   end+P("\16")/function()
     result.encoding=stack[top]
     top=0
   end+P("\17")/function()
     result.charstrings=stack[top]
     top=0
   end+P("\18")/function()
     result.private={
       size=stack[top-1],
       offset=stack[top],
     }
     top=0
   end+P("\19")/function()
     result.subroutines=stack[top]
   end+P("\20")/function()
     result.defaultwidthx=stack[top]
   end+P("\21")/function()
     result.nominalwidthx=stack[top]
   end
 local p_double=P("\12")*(
   P("\00")/function()
     result.copyright=stack[top]
     top=0
   end+P("\01")/function()
     result.monospaced=stack[top]==1 and true or false
     top=0
   end+P("\02")/function()
     result.italicangle=stack[top]
     top=0
   end+P("\03")/function()
     result.underlineposition=stack[top]
     top=0
   end+P("\04")/function()
     result.underlinethickness=stack[top]
     top=0
   end+P("\05")/function()
     result.painttype=stack[top]
     top=0
   end+P("\06")/function()
     result.charstringtype=stack[top]
     top=0
   end+P("\07")/function()
     result.fontmatrix={ unpack(stack,1,6) }
     top=0
   end+P("\08")/function()
     result.strokewidth=stack[top]
     top=0
   end+P("\20")/function()
     result.syntheticbase=stack[top]
     top=0
   end+P("\21")/function()
     result.postscript=strings[stack[top]] or "unset"
     top=0
   end+P("\22")/function()
     result.basefontname=strings[stack[top]] or "unset"
     top=0
   end+P("\21")/function()
     result.basefontblend=stack[top]
     top=0
   end+P("\30")/function()
     result.cid.registry=strings[stack[top-2]] or "unset"
     result.cid.ordering=strings[stack[top-1]] or "unset"
     result.cid.supplement=stack[top]
     top=0
   end+P("\31")/function()
     result.cid.fontversion=stack[top]
     top=0
   end+P("\32")/function()
     result.cid.fontrevision=stack[top]
     top=0
   end+P("\33")/function()
     result.cid.fonttype=stack[top]
     top=0
   end+P("\34")/function()
     result.cid.count=stack[top]
     top=0
   end+P("\35")/function()
     result.cid.uidbase=stack[top]
     top=0
   end+P("\36")/function()
     result.cid.fdarray=stack[top]
     top=0
   end+P("\37")/function()
     result.cid.fdselect=stack[top]
     top=0
   end+P("\38")/function()
     result.cid.fontname=strings[stack[top]] or "unset"
     top=0
   end
 )
 local p_last=P("\x0F")/"0"+P("\x1F")/"1"+P("\x2F")/"2"+P("\x3F")/"3"+P("\x4F")/"4"+P("\x5F")/"5"+P("\x6F")/"6"+P("\x7F")/"7"+P("\x8F")/"8"+P("\x9F")/"9"+P("\xAF")/""+P("\xBF")/""+P("\xCF")/""+P("\xDF")/""+P("\xEF")/""+R("\xF0\xFF")/""
 local remap={
   ["\x00"]="00",["\x01"]="01",["\x02"]="02",["\x03"]="03",["\x04"]="04",["\x05"]="05",["\x06"]="06",["\x07"]="07",["\x08"]="08",["\x09"]="09",["\x0A"]="0.",["\x0B"]="0E",["\x0C"]="0E-",["\x0D"]="0",["\x0E"]="0-",["\x0F"]="0",
   ["\x10"]="10",["\x11"]="11",["\x12"]="12",["\x13"]="13",["\x14"]="14",["\x15"]="15",["\x16"]="16",["\x17"]="17",["\x18"]="18",["\x19"]="19",["\x1A"]="0.",["\x1B"]="0E",["\x1C"]="0E-",["\x1D"]="0",["\x1E"]="0-",["\x1F"]="0",
   ["\x20"]="20",["\x21"]="21",["\x22"]="22",["\x23"]="23",["\x24"]="24",["\x25"]="25",["\x26"]="26",["\x27"]="27",["\x28"]="28",["\x29"]="29",["\x2A"]="0.",["\x2B"]="0E",["\x2C"]="0E-",["\x2D"]="0",["\x2E"]="0-",["\x2F"]="0",
   ["\x30"]="30",["\x31"]="31",["\x32"]="32",["\x33"]="33",["\x34"]="34",["\x35"]="35",["\x36"]="36",["\x37"]="37",["\x38"]="38",["\x39"]="39",["\x3A"]="0.",["\x3B"]="0E",["\x3C"]="0E-",["\x3D"]="0",["\x3E"]="0-",["\x3F"]="0",
   ["\x40"]="40",["\x41"]="41",["\x42"]="42",["\x43"]="43",["\x44"]="44",["\x45"]="45",["\x46"]="46",["\x47"]="47",["\x48"]="48",["\x49"]="49",["\x4A"]="0.",["\x4B"]="0E",["\x4C"]="0E-",["\x4D"]="0",["\x4E"]="0-",["\x4F"]="0",
   ["\x50"]="50",["\x51"]="51",["\x52"]="52",["\x53"]="53",["\x54"]="54",["\x55"]="55",["\x56"]="56",["\x57"]="57",["\x58"]="58",["\x59"]="59",["\x5A"]="0.",["\x5B"]="0E",["\x5C"]="0E-",["\x5D"]="0",["\x5E"]="0-",["\x5F"]="0",
   ["\x60"]="60",["\x61"]="61",["\x62"]="62",["\x63"]="63",["\x64"]="64",["\x65"]="65",["\x66"]="66",["\x67"]="67",["\x68"]="68",["\x69"]="69",["\x6A"]="0.",["\x6B"]="0E",["\x6C"]="0E-",["\x6D"]="0",["\x6E"]="0-",["\x6F"]="0",
   ["\x70"]="70",["\x71"]="71",["\x72"]="72",["\x73"]="73",["\x74"]="74",["\x75"]="75",["\x76"]="76",["\x77"]="77",["\x78"]="78",["\x79"]="79",["\x7A"]="0.",["\x7B"]="0E",["\x7C"]="0E-",["\x7D"]="0",["\x7E"]="0-",["\x7F"]="0",
   ["\x80"]="80",["\x81"]="81",["\x82"]="82",["\x83"]="83",["\x84"]="84",["\x85"]="85",["\x86"]="86",["\x87"]="87",["\x88"]="88",["\x89"]="89",["\x8A"]="0.",["\x8B"]="0E",["\x8C"]="0E-",["\x8D"]="0",["\x8E"]="0-",["\x8F"]="0",
   ["\x90"]="90",["\x91"]="91",["\x92"]="92",["\x93"]="93",["\x94"]="94",["\x95"]="95",["\x96"]="96",["\x97"]="97",["\x98"]="98",["\x99"]="99",["\x9A"]="0.",["\x9B"]="0E",["\x9C"]="0E-",["\x9D"]="0",["\x9E"]="0-",["\x9F"]="0",
   ["\xA0"]=".0",["\xA1"]=".1",["\xA2"]=".2",["\xA3"]=".3",["\xA4"]=".4",["\xA5"]=".5",["\xA6"]=".6",["\xA7"]=".7",["\xA8"]=".8",["\xA9"]=".9",["\xAA"]="..",["\xAB"]=".E",["\xAC"]=".E-",["\xAD"]=".",["\xAE"]=".-",["\xAF"]=".",
   ["\xB0"]="E0",["\xB1"]="E1",["\xB2"]="E2",["\xB3"]="E3",["\xB4"]="E4",["\xB5"]="E5",["\xB6"]="E6",["\xB7"]="E7",["\xB8"]="E8",["\xB9"]="E9",["\xBA"]="E.",["\xBB"]="EE",["\xBC"]="EE-",["\xBD"]="E",["\xBE"]="E-",["\xBF"]="E",
   ["\xC0"]="E-0",["\xC1"]="E-1",["\xC2"]="E-2",["\xC3"]="E-3",["\xC4"]="E-4",["\xC5"]="E-5",["\xC6"]="E-6",["\xC7"]="E-7",["\xC8"]="E-8",["\xC9"]="E-9",["\xCA"]="E-.",["\xCB"]="E-E",["\xCC"]="E-E-",["\xCD"]="E-",["\xCE"]="E--",["\xCF"]="E-",
   ["\xD0"]="-0",["\xD1"]="-1",["\xD2"]="-2",["\xD3"]="-3",["\xD4"]="-4",["\xD5"]="-5",["\xD6"]="-6",["\xD7"]="-7",["\xD8"]="-8",["\xD9"]="-9",["\xDA"]="-.",["\xDB"]="-E",["\xDC"]="-E-",["\xDD"]="-",["\xDE"]="--",["\xDF"]="-",
 }
 local p_nibbles=P("\30")*Cs(((1-p_last)/remap)^0+p_last)/function(n)
   top=top+1
   stack[top]=tonumber(n) or 0
 end
 local p_byte=C(R("\32\246"))/function(b0)
   top=top+1
   stack[top]=byte(b0)-139
 end
 local p_positive=C(R("\247\250"))*C(1)/function(b0,b1)
   top=top+1
   stack[top]=(byte(b0)-247)*256+byte(b1)+108
 end
 local p_negative=C(R("\251\254"))*C(1)/function(b0,b1)
   top=top+1
   stack[top]=-(byte(b0)-251)*256-byte(b1)-108
 end
 local p_short=P("\28")*C(1)*C(1)/function(b1,b2)
   top=top+1
   local n=0x100*byte(b1)+byte(b2)
   if n>=0x8000 then
     stack[top]=n-0xFFFF-1
   else
     stack[top]=n
   end
 end
 local p_long=P("\29")*C(1)*C(1)*C(1)*C(1)/function(b1,b2,b3,b4)
   top=top+1
   local n=0x1000000*byte(b1)+0x10000*byte(b2)+0x100*byte(b3)+byte(b4)
   if n>=0x8000000 then
     stack[top]=n-0xFFFFFFFF-1
   else
     stack[top]=n
   end
 end
 local p_unsupported=P(1)/function(detail)
   top=0
 end
 local p_dictionary=(
   p_byte+p_positive+p_negative+p_short+p_long+p_nibbles+p_single+p_double+p_unsupported
 )^1
 parsedictionaries=function(data,dictionaries)
   stack={}
   strings=data.strings
   for i=1,#dictionaries do
     top=0
     result={
       monospaced=false,
       italicangle=0,
       underlineposition=-100,
       underlinethickness=50,
       painttype=0,
       charstringtype=2,
       fontmatrix={ 0.001,0,0,0.001,0,0 },
       fontbbox={ 0,0,0,0 },
       strokewidth=0,
       charset=0,
       encoding=0,
       cid={
         fontversion=0,
         fontrevision=0,
         fonttype=0,
         count=8720,
       }
     }
     lpegmatch(p_dictionary,dictionaries[i])
     dictionaries[i]=result
   end
   result={}
   top=0
   stack={}
 end
 parseprivates=function(data,dictionaries)
   stack={}
   strings=data.strings
   for i=1,#dictionaries do
     local private=dictionaries[i].private
     if private and private.data then
       top=0
       result={
         forcebold=false,
         languagegroup=0,
         expansionfactor=0.06,
         initialrandomseed=0,
         subroutines=0,
         defaultwidthx=0,
         nominalwidthx=0,
         cid={
         },
       }
       lpegmatch(p_dictionary,private.data)
       private.data=result
     end
   end
   result={}
   top=0
   stack={}
 end
 local x=0
 local y=0
 local width=false
 local r=0
 local stems=0
 local globalbias=0
 local localbias=0
 local globals=false
 local locals=false
 local depth=1
 local xmin=0
 local xmax=0
 local ymin=0
 local ymax=0
 local checked=false
 local keepcurve=false
 local version=2
 local function showstate(where)
   report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top)
 end
 local function showvalue(where,value,showstack)
   if showstack then
     report("%w%-10s : %s : [%s] n=%i",depth*2,where,tostring(value),concat(stack," ",1,top),top)
   else
     report("%w%-10s : %s",depth*2,where,tostring(value))
   end
 end
 local function moveto(x,y)
   if keepcurve then
     r=r+1
     result[r]={ x,y,"m" }
   end
   if checked then
     if x<xmin then xmin=x elseif x>xmax then xmax=x end
     if y<ymin then ymin=y elseif y>ymax then ymax=y end
   else
     xmin=x
     ymin=y
     xmax=x
     ymax=y
     checked=true
   end
 end
 local function lineto(x,y)
   if keepcurve then
     r=r+1
     result[r]={ x,y,"l" }
   end
   if checked then
     if x<xmin then xmin=x elseif x>xmax then xmax=x end
     if y<ymin then ymin=y elseif y>ymax then ymax=y end
   else
     xmin=x
     ymin=y
     xmax=x
     ymax=y
     checked=true
   end
 end
 local function curveto(x1,y1,x2,y2,x3,y3)
   if keepcurve then
     r=r+1
     result[r]={ x1,y1,x2,y2,x3,y3,"c" }
   end
   if checked then
     if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end
     if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end
   else
     xmin=x1
     ymin=y1
     xmax=x1
     ymax=y1
     checked=true
   end
   if x2<xmin then xmin=x2 elseif x2>xmax then xmax=x2 end
   if y2<ymin then ymin=y2 elseif y2>ymax then ymax=y2 end
   if x3<xmin then xmin=x3 elseif x3>xmax then xmax=x3 end
   if y3<ymin then ymin=y3 elseif y3>ymax then ymax=y3 end
 end
 local function rmoveto()
   if top>2 then
     if not width then
       width=stack[1]
       if trace_charstrings then
         showvalue("width",width)
       end
     end
   elseif not width then
     width=true
   end
   if trace_charstrings then
     showstate("rmoveto")
   end
   x=x+stack[top-1]
   y=y+stack[top]
   top=0
   moveto(x,y)
 end
 local function hmoveto()
   if top>1 then
     if not width then
       width=stack[1]
       if trace_charstrings then
         showvalue("width",width)
       end
     end
   elseif not width then
     width=true
   end
   if trace_charstrings then
     showstate("hmoveto")
   end
   x=x+stack[top]
   top=0
   moveto(x,y)
 end
 local function vmoveto()
   if top>1 then
     if not width then
       width=stack[1]
       if trace_charstrings then
         showvalue("width",width)
       end
     end
   elseif not width then
     width=true
   end
   if trace_charstrings then
     showstate("vmoveto")
   end
   y=y+stack[top]
   top=0
   moveto(x,y)
 end
 local function rlineto()
   if trace_charstrings then
     showstate("rlineto")
   end
   for i=1,top,2 do
     x=x+stack[i]
     y=y+stack[i+1]
     lineto(x,y)
   end
   top=0
 end
 local function xlineto(swap)
   for i=1,top do
     if swap then
       x=x+stack[i]
       swap=false
     else
       y=y+stack[i]
       swap=true
     end
     lineto(x,y)
   end
   top=0
 end
 local function hlineto()
   if trace_charstrings then
     showstate("hlineto")
   end
   xlineto(true)
 end
 local function vlineto()
   if trace_charstrings then
     showstate("vlineto")
   end
   xlineto(false)
 end
 local function rrcurveto()
   if trace_charstrings then
     showstate("rrcurveto")
   end
   for i=1,top,6 do
     local ax=x+stack[i]
     local ay=y+stack[i+1]
     local bx=ax+stack[i+2]
     local by=ay+stack[i+3]
     x=bx+stack[i+4]
     y=by+stack[i+5]
     curveto(ax,ay,bx,by,x,y)
   end
   top=0
 end
 local function hhcurveto()
   if trace_charstrings then
     showstate("hhcurveto")
   end
   local s=1
   if top%2~=0 then
     y=y+stack[1]
     s=2
   end
   for i=s,top,4 do
     local ax=x+stack[i]
     local ay=y
     local bx=ax+stack[i+1]
     local by=ay+stack[i+2]
     x=bx+stack[i+3]
     y=by
     curveto(ax,ay,bx,by,x,y)
   end
   top=0
 end
 local function vvcurveto()
   if trace_charstrings then
     showstate("vvcurveto")
   end
   local s=1
   local d=0
   if top%2~=0 then
     d=stack[1]
     s=2
   end
   for i=s,top,4 do
     local ax=x+d
     local ay=y+stack[i]
     local bx=ax+stack[i+1]
     local by=ay+stack[i+2]
     x=bx
     y=by+stack[i+3]
     curveto(ax,ay,bx,by,x,y)
     d=0
   end
   top=0
 end
 local function xxcurveto(swap)
   local last=top%4~=0 and stack[top]
   if last then
     top=top-1
   end
   local sw=swap
   for i=1,top,4 do
     local ax,ay,bx,by
     if swap then
       ax=x+stack[i]
       ay=y
       bx=ax+stack[i+1]
       by=ay+stack[i+2]
       y=by+stack[i+3]
       if last and i+3==top then
         x=bx+last
       else
         x=bx
       end
       swap=false
     else
       ax=x
       ay=y+stack[i]
       bx=ax+stack[i+1]
       by=ay+stack[i+2]
       x=bx+stack[i+3]
       if last and i+3==top then
         y=by+last
       else
         y=by
       end
       swap=true
     end
     curveto(ax,ay,bx,by,x,y)
   end
   top=0
 end
 local function hvcurveto()
   if trace_charstrings then
     showstate("hvcurveto")
   end
   xxcurveto(true)
 end
 local function vhcurveto()
   if trace_charstrings then
     showstate("vhcurveto")
   end
   xxcurveto(false)
 end
 local function rcurveline()
   if trace_charstrings then
     showstate("rcurveline")
   end
   for i=1,top-2,6 do
     local ax=x+stack[i]
     local ay=y+stack[i+1]
     local bx=ax+stack[i+2]
     local by=ay+stack[i+3]
     x=bx+stack[i+4]
     y=by+stack[i+5]
     curveto(ax,ay,bx,by,x,y)
   end
   x=x+stack[top-1]
   y=y+stack[top]
   lineto(x,y)
   top=0
 end
 local function rlinecurve()
   if trace_charstrings then
     showstate("rlinecurve")
   end
   if top>6 then
     for i=1,top-6,2 do
       x=x+stack[i]
       y=y+stack[i+1]
       lineto(x,y)
     end
   end
   local ax=x+stack[top-5]
   local ay=y+stack[top-4]
   local bx=ax+stack[top-3]
   local by=ay+stack[top-2]
   x=bx+stack[top-1]
   y=by+stack[top]
   curveto(ax,ay,bx,by,x,y)
   top=0
 end
 local function flex()
   if trace_charstrings then
     showstate("flex")
   end
   local ax=x+stack[1]
   local ay=y+stack[2]
   local bx=ax+stack[3]
   local by=ay+stack[4]
   local cx=bx+stack[5]
   local cy=by+stack[6]
   curveto(ax,ay,bx,by,cx,cy)
   local dx=cx+stack[7]
   local dy=cy+stack[8]
   local ex=dx+stack[9]
   local ey=dy+stack[10]
   x=ex+stack[11]
   y=ey+stack[12]
   curveto(dx,dy,ex,ey,x,y)
   top=0
 end
 local function hflex()
   if trace_charstrings then
     showstate("hflex")
   end
   local ax=x+stack[1]
   local ay=y
   local bx=ax+stack[2]
   local by=ay+stack[3]
   local cx=bx+stack[4]
   local cy=by
   curveto(ax,ay,bx,by,cx,cy)
   local dx=cx+stack[5]
   local dy=by
   local ex=dx+stack[6]
   local ey=y
   x=ex+stack[7]
   curveto(dx,dy,ex,ey,x,y)
   top=0
 end
 local function hflex1()
   if trace_charstrings then
     showstate("hflex1")
   end
   local ax=x+stack[1]
   local ay=y+stack[2]
   local bx=ax+stack[3]
   local by=ay+stack[4]
   local cx=bx+stack[5]
   local cy=by
   curveto(ax,ay,bx,by,cx,cy)
   local dx=cx+stack[6]
   local dy=by
   local ex=dx+stack[7]
   local ey=dy+stack[8]
   x=ex+stack[9]
   curveto(dx,dy,ex,ey,x,y)
   top=0
 end
 local function flex1()
   if trace_charstrings then
     showstate("flex1")
   end
   local ax=x+stack[1]
   local ay=y+stack[2]
   local bx=ax+stack[3]
   local by=ay+stack[4]
   local cx=bx+stack[5]
   local cy=by+stack[6]
   curveto(ax,ay,bx,by,cx,cy)
   local dx=cx+stack[7]
   local dy=cy+stack[8]
   local ex=dx+stack[9]
   local ey=dy+stack[10]
   if abs(ex-x)>abs(ey-y) then
     x=ex+stack[11]
   else
     y=ey+stack[11]
   end
   curveto(dx,dy,ex,ey,x,y)
   top=0
 end
 local function getstem()
   if top==0 then
   elseif top%2~=0 then
     if width then
       remove(stack,1)
     else
       width=remove(stack,1)
       if trace_charstrings then
         showvalue("width",width)
       end
     end
     top=top-1
   end
   if trace_charstrings then
     showstate("stem")
   end
   stems=stems+top/2
   top=0
 end
 local function getmask()
   if top==0 then
   elseif top%2~=0 then
     if width then
       remove(stack,1)
     else
       width=remove(stack,1)
       if trace_charstrings then
         showvalue("width",width)
       end
     end
     top=top-1
   end
   if trace_charstrings then
     showstate(operator==19 and "hintmark" or "cntrmask")
   end
   stems=stems+top/2
   top=0
   if stems==0 then
   elseif stems<=8 then
     return 1
   else
     return floor((stems+7)/8)
   end
 end
 local function unsupported(t)
   if trace_charstrings then
     showstate("unsupported "..t)
   end
   top=0
 end
 local function unsupportedsub(t)
   if trace_charstrings then
     showstate("unsupported sub "..t)
   end
   top=0
 end
 local function getstem3()
   if trace_charstrings then
     showstate("stem3")
   end
   top=0
 end
 local function divide()
   if version==1 then
     local d=stack[top]
     top=top-1
     stack[top]=stack[top]/d
   end
 end
 local function closepath()
   if version==1 then
     if trace_charstrings then
       showstate("closepath")
     end
   end
   top=0
 end
 local function hsbw()
   if version==1 then
     if trace_charstrings then
       showstate("dotsection")
     end
     width=stack[top]
   end
   top=0
 end
 local function seac()
   if version==1 then
     if trace_charstrings then
       showstate("seac")
     end
   end
   top=0
 end
 local function sbw()
   if version==1 then
     if trace_charstrings then
       showstate("sbw")
     end
     width=stack[top-1]
   end
   top=0
 end
 local function callothersubr()
   if version==1 then
     if trace_charstrings then
       showstate("callothersubr (unsupported)")
     end
   end
   top=0
 end
 local function pop()
   if version==1 then
     if trace_charstrings then
       showstate("pop (unsupported)")
     end
     top=top+1
     stack[top]=0
   else
     top=0
   end
 end
 local function setcurrentpoint()
   if version==1 then
     if trace_charstrings then
       showstate("pop (unsupported)")
     end
     x=x+stack[top-1]
     y=y+stack[top]
   end
   top=0
 end
 local actions={ [0]=unsupported,
   getstem,
   unsupported,
   getstem,
   vmoveto,
   rlineto,
   hlineto,
   vlineto,
   rrcurveto,
   unsupported,
   unsupported,
   unsupported,
   unsupported,
   hsbw,
   unsupported,
   unsupported,
   unsupported,
   unsupported,
   getstem,
   getmask,
   getmask,
   rmoveto,
   hmoveto,
   getstem,
   rcurveline,
   rlinecurve,
   vvcurveto,
   hhcurveto,
   unsupported,
   unsupported,
   vhcurveto,
   hvcurveto,
 }
 local subactions={
   [000]=dotsection,
   [001]=getstem3,
   [002]=getstem3,
   [006]=seac,
   [007]=sbw,
   [012]=divide,
   [016]=callothersubr,
   [017]=pop,
   [033]=setcurrentpoint,
   [034]=hflex,
   [035]=flex,
   [036]=hflex1,
   [037]=flex1,
 }
 local p_bytes=Ct((P(1)/byte)^0)
 local function call(scope,list,bias,process)
   depth=depth+1
   if top==0 then
     showstate(formatters["unknown %s call"](scope))
     top=0
   else
     local index=stack[top]+bias
     top=top-1
     if trace_charstrings then
       showvalue(scope,index,true)
     end
     local tab=list[index]
     if tab then
       if type(tab)=="string" then
         tab=lpegmatch(p_bytes,tab)
         list[index]=tab
       end
       process(tab)
     else
       showstate(formatters["unknown %s call %i"](scope,index))
       top=0
     end
   end
   depth=depth-1
 end
 local function process(tab)
   local i=1
   local n=#tab
   while i<=n do
     local t=tab[i]
     if t>=32 and t<=246 then
       top=top+1
       stack[top]=t-139
       i=i+1
     elseif t>=247 and t<=250 then
       top=top+1
       stack[top]=(t-247)*256+tab[i+1]+108
       i=i+2
     elseif t>=251 and t<=254 then
       top=top+1
       stack[top]=-(t-251)*256-tab[i+1]-108
       i=i+2
     elseif t==28 then
       top=top+1
       local n=0x100*tab[i+1]+tab[i+2]
       if n>=0x8000 then
         stack[top]=n-0xFFFF-1
       else
         stack[top]=n
       end
       i=i+3
     elseif t==255 then
       local n=0x100*tab[i+1]+tab[i+2]
       top=top+1
       if n>=0x8000 then
         stack[top]=n-0xFFFF-1+(0x100*tab[i+3]+tab[i+4])/0xFFFF
       else
         stack[top]=n+(0x100*tab[i+3]+tab[i+4])/0xFFFF
       end
       i=i+5
     elseif t==11 then
       if trace_charstrings then
         showstate("return")
       end
       return
     elseif t==10 then
       call("local",locals,localbias,process)
       i=i+1
      elseif t==14 then
       if width then
       elseif top>0 then
         width=stack[1]
         if trace_charstrings then
           showvalue("width",width)
         end
       else
         width=true
       end
       if trace_charstrings then
         showstate("endchar")
       end
       return
     elseif t==29 then
       call("global",globals,globalbias,process)
       i=i+1
     elseif t==12 then
       i=i+1
       local t=tab[i]
       local a=subactions[t]
       if a then
         a(t)
       else
         if trace_charstrings then
           showvalue("<subaction>",t)
         end
         top=0
       end
       i=i+1
     else
       local a=actions[t]
       if a then
         local s=a(t)
         if s then
           i=i+s
         end
       else
         if trace_charstrings then
           showvalue("<action>",t)
         end
         top=0
       end
       i=i+1
     end
   end
 end
 local function setbias(globals,locals)
   if version==1 then
     return
       false,
       false
   else
     local g,l=#globals,#locals
     return
       ((g<1240 and 107) or (g<33900 and 1131) or 32768)+1,
       ((l<1240 and 107) or (l<33900 and 1131) or 32768)+1
   end
 end
 parsecharstrings=function(data,glyphs,doshapes,tversion)
   local dictionary=data.dictionaries[1]
   local charstrings=dictionary.charstrings
   local charset=dictionary.charset
   local private=dictionary.private or { data={} }
   keepcurve=doshapes
   version=tversion
   stack={}
   glyphs=glyphs or {}
   strings=data.strings
   globals=data.routines or {}
   locals=dictionary.subroutines or {}
   globalbias,localbias=setbias(globals,locals)
   local nominalwidth=private.data.nominalwidthx or 0
   local defaultwidth=private.data.defaultwidthx or 0
   for i=1,#charstrings do
     local tab=charstrings[i]
     if type(tab)=="string" then
       tab=lpegmatch(p_bytes,tab)
     end
     local index=i-1
     x=0
     y=0
     width=false
     r=0
     top=0
     stems=0
     result={}
     xmin=0
     xmax=0
     ymin=0
     ymax=0
     checked=false
     if trace_charstrings then
       report("glyph: %i",index)
       report("data: % t",tab)
     end
     process(tab)
     local boundingbox={ round(xmin),round(ymin),round(xmax),round(ymax) }
     if width==true or width==false then
       width=defaultwidth
     else
       width=nominalwidth+width
     end
     local glyph=glyphs[index]
     if not glyph then
       glyphs[index]={
         segments=doshapes~=false and result or nil,
         boundingbox=boundingbox,
         width=width,
         name=charset[index],
       }
     else
       glyph.segments=doshapes~=false and result or nil
       glyph.boundingbox=boundingbox
       if not glyph.width then
         glyph.width=width
       end
       if charset and not glyph.name then
         glyph.name=charset[index]
       end
     end
     if trace_charstrings then
       report("width: %s",tostring(width))
       report("boundingbox: % t",boundingbox)
     end
     charstrings[i]=nil
   end
   return glyphs
 end
 parsecharstring=function(data,dictionary,tab,glyphs,index,doshapes,tversion)
   local private=dictionary.private
   keepcurve=doshapes
   version=tversion
   strings=data.strings
   locals=dictionary.subroutines or {}
   globals=data.routines or {}
   globalbias,localbias=setbias(globals,locals)
   local nominalwidth=private and private.data.nominalwidthx or 0
   local defaultwidth=private and private.data.defaultwidthx or 0
   if type(tab)=="string" then
     tab=lpegmatch(p_bytes,tab)
   end
   x=0
   y=0
   width=false
   r=0
   top=0
   stems=0
   result={}
   xmin=0
   xmax=0
   ymin=0
   ymax=0
   checked=false
   if trace_charstrings then
     report("glyph: %i",index)
     report("data: % t",tab)
   end
   process(tab)
   local boundingbox={ xmin,ymin,xmax,ymax }
   if width==true or width==false then
     width=defaultwidth
   else
     width=nominalwidth+width
   end
   index=index-1
   local glyph=glyphs[index]
   if not glyph then
     glyphs[index]={
       segments=doshapes~=false and result or nil,
       boundingbox=boundingbox,
       width=width,
       name=charset[index],
     }
   else
     glyph.segments=doshapes~=false and result or nil
     glyph.boundingbox=boundingbox
     if not glyph.width then
       glyph.width=width
     end
     if charset and not glyph.name then
       glyph.name=charset[index]
     end
   end
   if trace_charstrings then
     report("width: %s",tostring(width))
     report("boundingbox: % t",boundingbox)
   end
 end
 resetcharstrings=function()
   result={}
   top=0
   stack={}
 end
end
local function readglobals(f,data)
 local routines=readlengths(f)
 for i=1,#routines do
   routines[i]=readstring(f,routines[i])
 end
 data.routines=routines
end
local function readencodings(f,data)
 data.encodings={}
end
local function readcharsets(f,data,dictionary)
 local header=data.header
 local strings=data.strings
 local nofglyphs=data.nofglyphs
 local charsetoffset=dictionary.charset
 if charsetoffset~=0 then
   setposition(f,header.offset+charsetoffset)
   local format=readbyte(f)
   local charset={ [0]=".notdef" }
   dictionary.charset=charset
   if format==0 then
     for i=1,nofglyphs do
       charset[i]=strings[readushort(f)]
     end
   elseif format==1 or format==2 then
     local readcount=format==1 and readbyte or readushort
     local i=1
     while i<=nofglyphs do
       local sid=readushort(f)
       local n=readcount(f)
       for s=sid,sid+n do
         charset[i]=strings[s]
         i=i+1
         if i>nofglyphs then
           break
         end
       end
     end
   else
     report("cff parser: unsupported charset format %a",format)
   end
 end
end
local function readprivates(f,data)
 local header=data.header
 local dictionaries=data.dictionaries
 local private=dictionaries[1].private
 if private then
   setposition(f,header.offset+private.offset)
   private.data=readstring(f,private.size)
 end
end
local function readlocals(f,data,dictionary)
 local header=data.header
 local private=dictionary.private
 if private then
   local subroutineoffset=private.data.subroutines
   if subroutineoffset~=0 then
     setposition(f,header.offset+private.offset+subroutineoffset)
     local subroutines=readlengths(f)
     for i=1,#subroutines do
       subroutines[i]=readstring(f,subroutines[i])
     end
     dictionary.subroutines=subroutines
     private.data.subroutines=nil
   else
     dictionary.subroutines={}
   end
 else
   dictionary.subroutines={}
 end
end
local function readcharstrings(f,data)
 local header=data.header
 local dictionaries=data.dictionaries
 local dictionary=dictionaries[1]
 local type=dictionary.charstringtype
 local offset=dictionary.charstrings
 if type==2 then
   setposition(f,header.offset+offset)
   local charstrings=readlengths(f)
   local nofglyphs=#charstrings
   for i=1,nofglyphs do
     charstrings[i]=readstring(f,charstrings[i])
   end
   data.nofglyphs=nofglyphs
   dictionary.charstrings=charstrings
 else
   report("unsupported charstr type %i",type)
   data.nofglyphs=0
   dictionary.charstrings={}
 end
end
local function readcidprivates(f,data)
 local header=data.header
 local dictionaries=data.dictionaries[1].cid.dictionaries
 for i=1,#dictionaries do
   local dictionary=dictionaries[i]
   local private=dictionary.private
   if private then
     setposition(f,header.offset+private.offset)
     private.data=readstring(f,private.size)
   end
 end
 parseprivates(data,dictionaries)
end
local function readnoselect(f,data,glyphs,doshapes,version)
 local dictionaries=data.dictionaries
 local dictionary=dictionaries[1]
 readglobals(f,data)
 readcharstrings(f,data)
 readencodings(f,data)
 readcharsets(f,data,dictionary)
 readprivates(f,data)
 parseprivates(data,data.dictionaries)
 readlocals(f,data,dictionary)
 parsecharstrings(data,glyphs,doshapes,version)
 resetcharstrings()
end
readers.parsecharstrings=parsecharstrings
local function readfdselect(f,data,glyphs,doshapes,version)
 local header=data.header
 local dictionaries=data.dictionaries
 local dictionary=dictionaries[1]
 local cid=dictionary.cid
 local cidselect=cid and cid.fdselect
 readglobals(f,data)
 readcharstrings(f,data)
 readencodings(f,data)
 local charstrings=dictionary.charstrings
 local fdindex={}
 local nofglyphs=data.nofglyphs
 local maxindex=-1
 setposition(f,header.offset+cidselect)
 local format=readbyte(f)
 if format==1 then
   for i=0,nofglyphs do
     local index=readbyte(i)
     fdindex[i]=index
     if index>maxindex then
       maxindex=index
     end
   end
 elseif format==3 then
   local nofranges=readushort(f)
   local first=readushort(f)
   local index=readbyte(f)
   while true do
     local last=readushort(f)
     if index>maxindex then
       maxindex=index
     end
     for i=first,last do
       fdindex[i]=index
     end
     if last>=nofglyphs then
       break
     else
       first=last+1
       index=readbyte(f)
     end
   end
 else
 end
 if maxindex>=0 then
   local cidarray=cid.fdarray
   setposition(f,header.offset+cidarray)
   local dictionaries=readlengths(f)
   for i=1,#dictionaries do
     dictionaries[i]=readstring(f,dictionaries[i])
   end
   parsedictionaries(data,dictionaries)
   cid.dictionaries=dictionaries
   readcidprivates(f,data)
   for i=1,#dictionaries do
     readlocals(f,data,dictionaries[i])
   end
   for i=1,#charstrings do
     parsecharstring(data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes,version)
   end
   resetcharstrings()
 end
end
function readers.cff(f,fontdata,specification)
 if specification.details then
   local datatable=fontdata.tables.cff
   if datatable then
     local offset=datatable.offset
     local glyphs=fontdata.glyphs
     if not f then
       report("invalid filehandle")
       return
     end
     if offset then
       setposition(f,offset)
     end
     local header=readheader(f)
     if header.major>1 then
       report("version mismatch")
       return
     end
     local names=readfontnames(f)
     local dictionaries=readtopdictionaries(f)
     local strings=readstrings(f)
     local data={
       header=header,
       names=names,
       dictionaries=dictionaries,
       strings=strings,
       nofglyphs=fontdata.nofglyphs,
     }
     parsedictionaries(data,data.dictionaries)
     local d=dictionaries[1]
     local c=d.cid
     fontdata.cffinfo={
       familynamename=d.familyname,
       fullname=d.fullname,
       boundingbox=d.boundingbox,
       weight=d.weight,
       italicangle=d.italicangle,
       underlineposition=d.underlineposition,
       underlinethickness=d.underlinethickness,
       monospaced=d.monospaced,
     }
     fontdata.cidinfo=c and {
       registry=c.registry,
       ordering=c.ordering,
       supplement=c.supplement,
     }
     if not specification.glyphs then
     else
       local cid=d.cid
       if cid and cid.fdselect then
         readfdselect(f,data,glyphs,specification.shapes or false)
       else
         readnoselect(f,data,glyphs,specification.shapes or false)
       end
     end
   end
 end
end

end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-cff”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ttf” e0893de6d0f3f421ee4386fa90429db8] ---

if not modules then modules={} end modules ['font-ttf']={
 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,type,unpack=next,type,unpack
local bittest=bit32.btest
local sqrt=math.sqrt
local report=logs.reporter("otf reader","ttf")
local readers=fonts.handlers.otf.readers
local streamreader=readers.streamreader
local setposition=streamreader.setposition
local getposition=streamreader.getposition
local skipbytes=streamreader.skip
local readbyte=streamreader.readcardinal1
local readushort=streamreader.readcardinal2
local readulong=streamreader.readcardinal4
local readchar=streamreader.readinteger1
local readshort=streamreader.readinteger2
local read2dot14=streamreader.read2dot14
local function mergecomposites(glyphs,shapes)
 local function merge(index,shape,components)
   local contours={}
   local nofcontours=0
   for i=1,#components do
     local component=components[i]
     local subindex=component.index
     local subshape=shapes[subindex]
     local subcontours=subshape.contours
     if not subcontours then
       local subcomponents=subshape.components
       if subcomponents then
         subcontours=merge(subindex,subshape,subcomponents)
       end
     end
     if subcontours then
       local matrix=component.matrix
       local xscale=matrix[1]
       local xrotate=matrix[2]
       local yrotate=matrix[3]
       local yscale=matrix[4]
       local xoffset=matrix[5]
       local yoffset=matrix[6]
       for i=1,#subcontours do
         local points=subcontours[i]
         local result={}
         for i=1,#points do
           local p=points[i]
           local x=p[1]
           local y=p[2]
           result[i]={
             xscale*x+xrotate*y+xoffset,
             yscale*y+yrotate*x+yoffset,
             p[3]
           }
         end
         nofcontours=nofcontours+1
         contours[nofcontours]=result
       end
     else
       report("missing contours composite %s, component %s of %s, glyph %s",index,i,#components,subindex)
     end
   end
   shape.contours=contours
   shape.components=nil
   return contours
 end
 for index=1,#glyphs do
   local shape=shapes[index]
   local components=shape.components
   if components then
     merge(index,shape,components)
   end
 end
end
local function readnothing(f,nofcontours)
 return {
   type="nothing",
 }
end
local function curveto(m_x,m_y,l_x,l_y,r_x,r_y)
 return {
   l_x+2/3*(m_x-l_x),l_y+2/3*(m_y-l_y),
   r_x+2/3*(m_x-r_x),r_y+2/3*(m_y-r_y),
   r_x,r_y,"c"
 }
end
local function contours2outlines(glyphs,shapes)
 local quadratic=true
 for index=1,#glyphs do
   local glyph=glyphs[index]
   local shape=shapes[index]
   local contours=shape.contours
   if contours then
     local nofcontours=#contours
     local segments={}
     local nofsegments=0
     glyph.segments=segments
     if nofcontours>0 then
       for i=1,nofcontours do
         local contour=contours[i]
         local nofcontour=#contour
         if nofcontour>0 then
           local first_pt=contour[1]
           local first_on=first_pt[3]
           if nofcontour==1 then
             first_pt[3]="m"
             nofsegments=nofsegments+1
             segments[nofsegments]=first_pt
           else
             local first_on=first_pt[3]
             local last_pt=contour[nofcontour]
             local last_on=last_pt[3]
             local start=1
             local control_pt=false
             if first_on then
               start=2
             else
               if last_on then
                 first_pt=last_pt
               else
                 first_pt={ (first_pt[1]+last_pt[1])/2,(first_pt[2]+last_pt[2])/2,false }
               end
               control_pt=first_pt
             end
             nofsegments=nofsegments+1
             segments[nofsegments]={ first_pt[1],first_pt[2],"m" }
             local previous_pt=first_pt
             for i=start,nofcontour do
               local current_pt=contour[i]
               local current_on=current_pt[3]
               local previous_on=previous_pt[3]
               if previous_on then
                 if current_on then
                   nofsegments=nofsegments+1
                   segments[nofsegments]={ current_pt[1],current_pt[2],"l" }
                 else
                   control_pt=current_pt
                 end
               elseif current_on then
                 local ps=segments[nofsegments]
                 nofsegments=nofsegments+1
                 if quadratic then
                   segments[nofsegments]={ control_pt[1],control_pt[2],current_pt[1],current_pt[2],"q" }
                 else
                   local p=segments[nofsegments-1] local n=#p
                   segments[nofsegments]=curveto(control_pt[1],control_pt[2],p[n-2],p[n-1],current_pt[1],current_pt[2])
                 end
                 control_pt=false
               else
                 nofsegments=nofsegments+1
                 local halfway_x=(previous_pt[1]+current_pt[1])/2
                 local halfway_y=(previous_pt[2]+current_pt[2])/2
                 if quadratic then
                   segments[nofsegments]={ control_pt[1],control_pt[2],halfway_x,halfway_y,"q" }
                 else
                   local p=segments[nofsegments-1] local n=#p
                   segments[nofsegments]=curveto(control_pt[1],control_pt[2],p[n-2],p[n-1],halfway_x,halfway_y)
                 end
                 control_pt=current_pt
               end
               previous_pt=current_pt
             end
             if first_pt==last_pt then
             else
               nofsegments=nofsegments+1
               if not control_pt then
                 segments[nofsegments]={ first_pt[1],first_pt[2],"l" }
               elseif quadratic then
                 segments[nofsegments]={ control_pt[1],control_pt[2],first_pt[1],first_pt[2],"q" }
               else
                 local p=last_pt local n=#p
                 segments[nofsegments]=curveto(control_pt[1],control_pt[2],p[n-2],p[n-1],first_pt[1],first_pt[2])
               end
             end
           end
         end
       end
     end
   end
 end
end
local function readglyph(f,nofcontours)
 local points={}
 local endpoints={}
 local instructions={}
 local flags={}
 for i=1,nofcontours do
   endpoints[i]=readshort(f)+1
 end
 local nofpoints=endpoints[nofcontours]
 local nofinstructions=readushort(f)
 skipbytes(f,nofinstructions)
 local i=1
 while i<=nofpoints do
   local flag=readbyte(f)
   flags[i]=flag
   if bittest(flag,0x0008) then
     for j=1,readbyte(f) do
       i=i+1
       flags[i]=flag
     end
   end
   i=i+1
 end
 local x=0
 for i=1,nofpoints do
   local flag=flags[i]
   local short=bittest(flag,0x0002)
   local same=bittest(flag,0x0010)
   if short then
     if same then
       x=x+readbyte(f)
     else
       x=x-readbyte(f)
     end
   elseif same then
   else
     x=x+readshort(f)
   end
   points[i]={ x,y,bittest(flag,0x0001) }
 end
 local y=0
 for i=1,nofpoints do
   local flag=flags[i]
   local short=bittest(flag,0x0004)
   local same=bittest(flag,0x0020)
   if short then
     if same then
       y=y+readbyte(f)
     else
       y=y-readbyte(f)
     end
   elseif same then
   else
     y=y+readshort(f)
   end
   points[i][2]=y
 end
 local first=1
 for i=1,#endpoints do
   local last=endpoints[i]
   endpoints[i]={ unpack(points,first,last) }
   first=last+1
 end
 return {
   type="glyph",
   contours=endpoints,
 }
end
local function readcomposite(f)
 local components={}
 local nofcomponents=0
 local instructions=false
 while true do
   local flags=readushort(f)
   local index=readushort(f)
   local f_xyarg=bittest(flags,0x0002)
   local f_offset=bittest(flags,0x0800)
   local xscale=1
   local xrotate=0
   local yrotate=0
   local yscale=1
   local xoffset=0
   local yoffset=0
   local base=false
   local reference=false
   if f_xyarg then
     if bittest(flags,0x0001) then
       xoffset=readshort(f)
       yoffset=readshort(f)
     else
       xoffset=readchar(f)
       yoffset=readchar(f)
     end
   else
     if bittest(flags,0x0001) then
       base=readshort(f)
       reference=readshort(f)
     else
       base=readchar(f)
       reference=readchar(f)
     end
   end
   if bittest(flags,0x0008) then
     xscale=read2dot14(f)
     yscale=xscale
     if f_xyarg and f_offset then
       xoffset=xoffset*xscale
       yoffset=yoffset*yscale
     end
   elseif bittest(flags,0x0040) then
     xscale=read2dot14(f)
     yscale=read2dot14(f)
     if f_xyarg and f_offset then
       xoffset=xoffset*xscale
       yoffset=yoffset*yscale
     end
   elseif bittest(flags,0x0080) then
     xscale=read2dot14(f)
     xrotate=read2dot14(f)
     yrotate=read2dot14(f)
     yscale=read2dot14(f)
     if f_xyarg and f_offset then
       xoffset=xoffset*sqrt(xscale^2+xrotate^2)
       yoffset=yoffset*sqrt(yrotate^2+yscale^2)
     end
   end
   nofcomponents=nofcomponents+1
   components[nofcomponents]={
     index=index,
     usemine=bittest(flags,0x0200),
     round=bittest(flags,0x0006),
     base=base,
     reference=reference,
     matrix={ xscale,xrotate,yrotate,yscale,xoffset,yoffset },
   }
   if bittest(flags,0x0100) then
     instructions=true
   end
   if not bittest(flags,0x0020) then
     break
   end
 end
 return {
   type="composite",
   components=components,
 }
end
function readers.loca(f,fontdata,specification)
 if specification.glyphs then
   local datatable=fontdata.tables.loca
   if datatable then
     local offset=fontdata.tables.glyf.offset
     local format=fontdata.fontheader.indextolocformat
     local locations={}
     setposition(f,datatable.offset)
     if format==1 then
       local nofglyphs=datatable.length/4-1
     -1
       for i=0,nofglyphs do
         locations[i]=offset+readulong(f)
       end
       fontdata.nofglyphs=nofglyphs
     else
       local nofglyphs=datatable.length/2-1
     -1
       for i=0,nofglyphs do
         locations[i]=offset+readushort(f)*2
       end
       fontdata.nofglyphs=nofglyphs
     end
     fontdata.locations=locations
   end
 end
end
function readers.glyf(f,fontdata,specification)
 if specification.glyphs then
   local datatable=fontdata.tables.glyf
   if datatable then
     local locations=fontdata.locations
     if locations then
       local glyphs=fontdata.glyphs
       local nofglyphs=fontdata.nofglyphs
       local filesize=fontdata.filesize
       local nothing={ 0,0,0,0 }
       local shapes={}
       local loadshapes=specification.shapes
       for index=0,nofglyphs do
         local location=locations[index]
         if location>=filesize then
           report("discarding %s glyphs due to glyph location bug",nofglyphs-index+1)
           fontdata.nofglyphs=index-1
           fontdata.badfont=true
           break
         elseif location>0 then
           setposition(f,location)
           local nofcontours=readshort(f)
           glyphs[index].boundingbox={
             readshort(f),
             readshort(f),
             readshort(f),
             readshort(f),
           }
           if not loadshapes then
           elseif nofcontours==0 then
             shapes[index]=readnothing(f,nofcontours)
           elseif nofcontours>0 then
             shapes[index]=readglyph(f,nofcontours)
           else
             shapes[index]=readcomposite(f,nofcontours)
           end
         else
           if loadshapes then
             shapes[index]={}
           end
           glyphs[index].boundingbox=nothing
         end
       end
       if loadshapes then
         mergecomposites(glyphs,shapes)
         contours2outlines(glyphs,shapes)
       end
     end
   end
 end
end

end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ttf”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-dsp” 4a5266ada979d5c2d48867dc3ffaefea] ---

if not modules then modules={} end modules ['font-dsp']={
 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,type=next,type
local bittest=bit32.btest
local rshift=bit32.rshift
local concat=table.concat
local lower=string.lower
local copy=table.copy
local sub=string.sub
local strip=string.strip
local tohash=table.tohash
local reversed=table.reversed
local setmetatableindex=table.setmetatableindex
local formatters=string.formatters
local sortedkeys=table.sortedkeys
local sortedhash=table.sortedhash
local report=logs.reporter("otf reader")
local readers=fonts.handlers.otf.readers
local streamreader=readers.streamreader
local setposition=streamreader.setposition
local getposition=streamreader.getposition
local skipshort=streamreader.skipshort
local readushort=streamreader.readcardinal2
local readulong=streamreader.readcardinal4
local readshort=streamreader.readinteger2
local readfword=readshort
local readstring=streamreader.readstring
local readtag=streamreader.readtag
local readbytes=streamreader.readbytes
local gsubhandlers={}
local gposhandlers={}
local lookupidoffset=-1
local classes={
 "base",
 "ligature",
 "mark",
 "component",
}
local gsubtypes={
 "single",
 "multiple",
 "alternate",
 "ligature",
 "context",
 "chainedcontext",
 "extension",
 "reversechainedcontextsingle",
}
local gpostypes={
 "single",
 "pair",
 "cursive",
 "marktobase",
 "marktoligature",
 "marktomark",
 "context",
 "chainedcontext",
 "extension",
}
local chaindirections={
 context=0,
 chainedcontext=1,
 reversechainedcontextsingle=-1,
}
local lookupnames={
 gsub={
   single="gsub_single",
   multiple="gsub_multiple",
   alternate="gsub_alternate",
   ligature="gsub_ligature",
   context="gsub_context",
   chainedcontext="gsub_contextchain",
   reversechainedcontextsingle="gsub_reversecontextchain",
 },
 gpos={
   single="gpos_single",
   pair="gpos_pair",
   cursive="gpos_cursive",
   marktobase="gpos_mark2base",
   marktoligature="gpos_mark2ligature",
   marktomark="gpos_mark2mark",
   context="gpos_context",
   chainedcontext="gpos_contextchain",
 }
}
local lookupflags=setmetatableindex(function(t,k)
 local v={
   bittest(k,0x0008) and true or false,
   bittest(k,0x0004) and true or false,
   bittest(k,0x0002) and true or false,
   bittest(k,0x0001) and true or false,
 }
 t[k]=v
 return v
end)
local function readcoverage(f,offset,simple)
 setposition(f,offset)
 local coverageformat=readushort(f)
 local coverage={}
 if coverageformat==1 then
   local nofcoverage=readushort(f)
   if simple then
     for i=1,nofcoverage do
       coverage[i]=readushort(f)
     end
   else
     for i=0,nofcoverage-1 do
       coverage[readushort(f)]=i
     end
   end
 elseif coverageformat==2 then
   local nofranges=readushort(f)
   local n=simple and 1 or 0
   for i=1,nofranges do
     local firstindex=readushort(f)
     local lastindex=readushort(f)
     local coverindex=readushort(f)
     if simple then
       for i=firstindex,lastindex do
         coverage[n]=i
         n=n+1
       end
     else
       for i=firstindex,lastindex do
         coverage[i]=n
         n=n+1
       end
     end
   end
 else
   report("unknown coverage format %a ",coverageformat)
 end
 return coverage
end
local function readclassdef(f,offset,preset)
 setposition(f,offset)
 local classdefformat=readushort(f)
 local classdef={}
 if type(preset)=="number" then
   for k=0,preset-1 do
     classdef[k]=1
   end
 end
 if classdefformat==1 then
   local index=readushort(f)
   local nofclassdef=readushort(f)
   for i=1,nofclassdef do
     classdef[index]=readushort(f)+1
     index=index+1
   end
 elseif classdefformat==2 then
   local nofranges=readushort(f)
   local n=0
   for i=1,nofranges do
     local firstindex=readushort(f)
     local lastindex=readushort(f)
     local class=readushort(f)+1
     for i=firstindex,lastindex do
       classdef[i]=class
     end
   end
 else
   report("unknown classdef format %a ",classdefformat)
 end
 if type(preset)=="table" then
   for k in next,preset do
     if not classdef[k] then
       classdef[k]=1
     end
   end
 end
 return classdef
end
local function classtocoverage(defs)
 if defs then
   local list={}
   for index,class in next,defs do
     local c=list[class]
     if c then
       c[#c+1]=index
     else
       list[class]={ index }
     end
   end
   return list
 end
end
local function readposition(f,format)
 if format==0 then
   return nil
 end
 local x=bittest(format,0x0001) and readshort(f) or 0
 local y=bittest(format,0x0002) and readshort(f) or 0
 local h=bittest(format,0x0004) and readshort(f) or 0
 local v=bittest(format,0x0008) and readshort(f) or 0
 if x==0 and y==0 and h==0 and v==0 then
   return nil
 else
   return { x,y,h,v }
 end
end
local function readanchor(f,offset)
 if not offset or offset==0 then
   return nil
 end
 setposition(f,offset)
 local format=readshort(f)
 if format==0 then
   report("invalid anchor format %i @ position %i",format,offset)
   return false
 elseif format>3 then
   report("unsupported anchor format %i @ position %i",format,offset)
   return false
 end
 return { readshort(f),readshort(f) }
end
local function readfirst(f,offset)
 if offset then
   setposition(f,offset)
 end
 return { readushort(f) }
end
local function readarray(f,offset,first)
 if offset then
   setposition(f,offset)
 end
 local n=readushort(f)
 if first then
   local t={ first }
   for i=2,n do
     t[i]=readushort(f)
   end
   return t,n
 elseif n>0 then
   local t={}
   for i=1,n do
     t[i]=readushort(f)
   end
   return t,n
 end
end
local function readcoveragearray(f,offset,t,simple)
 if not t then
   return nil
 end
 local n=#t
 if n==0 then
   return nil
 end
 for i=1,n do
   t[i]=readcoverage(f,offset+t[i],simple)
 end
 return t
end
local function covered(subset,all)
 local used,u
 for i=1,#subset do
   local s=subset[i]
   if all[s] then
     if used then
       u=u+1
       used[u]=s
     else
       u=1
       used={ s }
     end
   end
 end
 return used
end
local function readlookuparray(f,noflookups,nofcurrent)
 local lookups={}
 if noflookups>0 then
   local length=0
   for i=1,noflookups do
     local index=readushort(f)+1
     if index>length then
       length=index
     end
     lookups[index]=readushort(f)+1
   end
   for index=1,length do
     if not lookups[index] then
       lookups[index]=false
     end
   end
 end
 return lookups
end
local function unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,what)
 local tableoffset=lookupoffset+offset
 setposition(f,tableoffset)
 local subtype=readushort(f)
 if subtype==1 then
   local coverage=readushort(f)
   local subclasssets=readarray(f)
   local rules={}
   if subclasssets then
     coverage=readcoverage(f,tableoffset+coverage,true)
     for i=1,#subclasssets do
       local offset=subclasssets[i]
       if offset>0 then
         local firstcoverage=coverage[i]
         local rulesoffset=tableoffset+offset
         local subclassrules=readarray(f,rulesoffset)
         for rule=1,#subclassrules do
           setposition(f,rulesoffset+subclassrules[rule])
           local nofcurrent=readushort(f)
           local noflookups=readushort(f)
           local current={ { firstcoverage } }
           for i=2,nofcurrent do
             current[i]={ readushort(f) }
           end
           local lookups=readlookuparray(f,noflookups,nofcurrent)
           rules[#rules+1]={
             current=current,
             lookups=lookups
           }
         end
       end
     end
   else
     report("empty subclassset in %a subtype %i","unchainedcontext",subtype)
   end
   return {
     format="glyphs",
     rules=rules,
   }
 elseif subtype==2 then
   local coverage=readushort(f)
   local currentclassdef=readushort(f)
   local subclasssets=readarray(f)
   local rules={}
   if subclasssets then
     coverage=readcoverage(f,tableoffset+coverage)
     currentclassdef=readclassdef(f,tableoffset+currentclassdef,coverage)
     local currentclasses=classtocoverage(currentclassdef,fontdata.glyphs)
     for class=1,#subclasssets do
       local offset=subclasssets[class]
       if offset>0 then
         local firstcoverage=currentclasses[class]
         if firstcoverage then
           firstcoverage=covered(firstcoverage,coverage)
           if firstcoverage then
             local rulesoffset=tableoffset+offset
             local subclassrules=readarray(f,rulesoffset)
             for rule=1,#subclassrules do
               setposition(f,rulesoffset+subclassrules[rule])
               local nofcurrent=readushort(f)
               local noflookups=readushort(f)
               local current={ firstcoverage }
               for i=2,nofcurrent do
                 current[i]=currentclasses[readushort(f)+1]
               end
               local lookups=readlookuparray(f,noflookups,nofcurrent)
               rules[#rules+1]={
                 current=current,
                 lookups=lookups
               }
             end
           else
             report("no coverage")
           end
         else
           report("no coverage class")
         end
       end
     end
   else
     report("empty subclassset in %a subtype %i","unchainedcontext",subtype)
   end
   return {
     format="class",
     rules=rules,
   }
 elseif subtype==3 then
   local current=readarray(f)
   local noflookups=readushort(f)
   local lookups=readlookuparray(f,noflookups,#current)
   current=readcoveragearray(f,tableoffset,current,true)
   return {
     format="coverage",
     rules={
       {
         current=current,
         lookups=lookups,
       }
     }
   }
 else
   report("unsupported subtype %a in %a %s",subtype,"unchainedcontext",what)
 end
end
local function chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,what)
 local tableoffset=lookupoffset+offset
 setposition(f,tableoffset)
 local subtype=readushort(f)
 if subtype==1 then
   local coverage=readushort(f)
   local subclasssets=readarray(f)
   local rules={}
   if subclasssets then
     coverage=readcoverage(f,tableoffset+coverage,true)
     for i=1,#subclasssets do
       local offset=subclasssets[i]
       if offset>0 then
         local firstcoverage=coverage[i]
         local rulesoffset=tableoffset+offset
         local subclassrules=readarray(f,rulesoffset)
         for rule=1,#subclassrules do
           setposition(f,rulesoffset+subclassrules[rule])
           local nofbefore=readushort(f)
           local before
           if nofbefore>0 then
             before={}
             for i=1,nofbefore do
               before[i]={ readushort(f) }
             end
           end
           local nofcurrent=readushort(f)
           local current={ { firstcoverage } }
           for i=2,nofcurrent do
             current[i]={ readushort(f) }
           end
           local nofafter=readushort(f)
           local after
           if nofafter>0 then
             after={}
             for i=1,nofafter do
               after[i]={ readushort(f) }
             end
           end
           local noflookups=readushort(f)
           local lookups=readlookuparray(f,noflookups,nofcurrent)
           rules[#rules+1]={
             before=before,
             current=current,
             after=after,
             lookups=lookups,
           }
         end
       end
     end
   else
     report("empty subclassset in %a subtype %i","chainedcontext",subtype)
   end
   return {
     format="glyphs",
     rules=rules,
   }
 elseif subtype==2 then
   local coverage=readushort(f)
   local beforeclassdef=readushort(f)
   local currentclassdef=readushort(f)
   local afterclassdef=readushort(f)
   local subclasssets=readarray(f)
   local rules={}
   if subclasssets then
     local coverage=readcoverage(f,tableoffset+coverage)
     local beforeclassdef=readclassdef(f,tableoffset+beforeclassdef,nofglyphs)
     local currentclassdef=readclassdef(f,tableoffset+currentclassdef,coverage)
     local afterclassdef=readclassdef(f,tableoffset+afterclassdef,nofglyphs)
     local beforeclasses=classtocoverage(beforeclassdef,fontdata.glyphs)
     local currentclasses=classtocoverage(currentclassdef,fontdata.glyphs)
     local afterclasses=classtocoverage(afterclassdef,fontdata.glyphs)
     for class=1,#subclasssets do
       local offset=subclasssets[class]
       if offset>0 then
         local firstcoverage=currentclasses[class]
         if firstcoverage then
           firstcoverage=covered(firstcoverage,coverage)
           if firstcoverage then
             local rulesoffset=tableoffset+offset
             local subclassrules=readarray(f,rulesoffset)
             for rule=1,#subclassrules do
               setposition(f,rulesoffset+subclassrules[rule])
               local nofbefore=readushort(f)
               local before
               if nofbefore>0 then
                 before={}
                 for i=1,nofbefore do
                   before[i]=beforeclasses[readushort(f)+1]
                 end
               end
               local nofcurrent=readushort(f)
               local current={ firstcoverage }
               for i=2,nofcurrent do
                 current[i]=currentclasses[readushort(f)+1]
               end
               local nofafter=readushort(f)
               local after
               if nofafter>0 then
                 after={}
                 for i=1,nofafter do
                   after[i]=afterclasses[readushort(f)+1]
                 end
               end
               local noflookups=readushort(f)
               local lookups=readlookuparray(f,noflookups,nofcurrent)
               rules[#rules+1]={
                 before=before,
                 current=current,
                 after=after,
                 lookups=lookups,
               }
             end
           else
             report("no coverage")
           end
         else
           report("class is not covered")
         end
       end
     end
   else
     report("empty subclassset in %a subtype %i","chainedcontext",subtype)
   end
   return {
     format="class",
     rules=rules,
   }
 elseif subtype==3 then
   local before=readarray(f)
   local current=readarray(f)
   local after=readarray(f)
   local noflookups=readushort(f)
   local lookups=readlookuparray(f,noflookups,#current)
   before=readcoveragearray(f,tableoffset,before,true)
   current=readcoveragearray(f,tableoffset,current,true)
   after=readcoveragearray(f,tableoffset,after,true)
   return {
     format="coverage",
     rules={
       {
         before=before,
         current=current,
         after=after,
         lookups=lookups,
       }
     }
   }
 else
   report("unsupported subtype %a in %a %s",subtype,"chainedcontext",what)
 end
end
local function extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,types,handlers,what)
 local tableoffset=lookupoffset+offset
 setposition(f,tableoffset)
 local subtype=readushort(f)
 if subtype==1 then
   local lookuptype=types[readushort(f)]
   local faroffset=readulong(f)
   local handler=handlers[lookuptype]
   if handler then
     return handler(f,fontdata,lookupid,tableoffset+faroffset,0,glyphs,nofglyphs),lookuptype
   else
     report("no handler for lookuptype %a subtype %a in %s %s",lookuptype,subtype,what,"extension")
   end
 else
   report("unsupported subtype %a in %s %s",subtype,what,"extension")
 end
end
function gsubhandlers.single(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
 local tableoffset=lookupoffset+offset
 setposition(f,tableoffset)
 local subtype=readushort(f)
 if subtype==1 then
   local coverage=readushort(f)
   local delta=readshort(f)
   local coverage=readcoverage(f,tableoffset+coverage)
   for index in next,coverage do
     local newindex=index+delta
     if index>nofglyphs or newindex>nofglyphs then
       report("invalid index in %s format %i: %i -> %i (max %i)","single",subtype,index,newindex,nofglyphs)
       coverage[index]=nil
     else
       coverage[index]=newindex
     end
   end
   return {
     coverage=coverage
   }
 elseif subtype==2 then
   local coverage=readushort(f)
   local nofreplacements=readushort(f)
   local replacements={}
   for i=1,nofreplacements do
     replacements[i]=readushort(f)
   end
   local coverage=readcoverage(f,tableoffset+coverage)
   for index,newindex in next,coverage do
     newindex=newindex+1
     if index>nofglyphs or newindex>nofglyphs then
       report("invalid index in %s format %i: %i -> %i (max %i)","single",subtype,index,newindex,nofglyphs)
       coverage[index]=nil
     else
       coverage[index]=replacements[newindex]
     end
   end
   return {
     coverage=coverage
   }
 else
   report("unsupported subtype %a in %a substitution",subtype,"single")
 end
end
local function sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,what)
 local tableoffset=lookupoffset+offset
 setposition(f,tableoffset)
 local subtype=readushort(f)
 if subtype==1 then
   local coverage=readushort(f)
   local nofsequence=readushort(f)
   local sequences={}
   for i=1,nofsequence do
     sequences[i]=readushort(f)
   end
   for i=1,nofsequence do
     setposition(f,tableoffset+sequences[i])
     local n=readushort(f)
     local s={}
     for i=1,n do
       s[i]=readushort(f)
     end
     sequences[i]=s
   end
   local coverage=readcoverage(f,tableoffset+coverage)
   for index,newindex in next,coverage do
     newindex=newindex+1
     if index>nofglyphs or newindex>nofglyphs then
       report("invalid index in %s format %i: %i -> %i (max %i)",what,subtype,index,newindex,nofglyphs)
       coverage[index]=nil
     else
       coverage[index]=sequences[newindex]
     end
   end
   return {
     coverage=coverage
   }
 else
   report("unsupported subtype %a in %a substitution",subtype,what)
 end
end
function gsubhandlers.multiple(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
 return sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"multiple")
end
function gsubhandlers.alternate(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
 return sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"alternate")
end
function gsubhandlers.ligature(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
 local tableoffset=lookupoffset+offset
 setposition(f,tableoffset)
 local subtype=readushort(f)
 if subtype==1 then
   local coverage=readushort(f)
   local nofsets=readushort(f)
   local ligatures={}
   for i=1,nofsets do
     ligatures[i]=readushort(f)
   end
   for i=1,nofsets do
     local offset=lookupoffset+offset+ligatures[i]
     setposition(f,offset)
     local n=readushort(f)
     local l={}
     for i=1,n do
       l[i]=offset+readushort(f)
     end
     ligatures[i]=l
   end
   local coverage=readcoverage(f,tableoffset+coverage)
   for index,newindex in next,coverage do
     local hash={}
     local ligatures=ligatures[newindex+1]
     for i=1,#ligatures do
       local offset=ligatures[i]
       setposition(f,offset)
       local lig=readushort(f)
       local cnt=readushort(f)
       local hsh=hash
       for i=2,cnt do
         local c=readushort(f)
         local h=hsh[c]
         if not h then
           h={}
           hsh[c]=h
         end
         hsh=h
       end
       hsh.ligature=lig
     end
     coverage[index]=hash
   end
   return {
     coverage=coverage
   }
 else
   report("unsupported subtype %a in %a substitution",subtype,"ligature")
 end
end
function gsubhandlers.context(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
 return unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"substitution"),"context"
end
function gsubhandlers.chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
 return chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"substitution"),"chainedcontext"
end
function gsubhandlers.extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
 return extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,gsubtypes,gsubhandlers,"substitution")
end
function gsubhandlers.reversechainedcontextsingle(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
 local tableoffset=lookupoffset+offset
 setposition(f,tableoffset)
 local subtype=readushort(f)
 if subtype==1 then
   local current=readfirst(f)
   local before=readarray(f)
   local after=readarray(f)
   local replacements=readarray(f)
   current=readcoveragearray(f,tableoffset,current,true)
   before=readcoveragearray(f,tableoffset,before,true)
   after=readcoveragearray(f,tableoffset,after,true)
   return {
     coverage={
       format="reversecoverage",
       before=before,
       current=current,
       after=after,
       replacements=replacements,
     }
   },"reversechainedcontextsingle"
 else
   report("unsupported subtype %a in %a substitution",subtype,"reversechainedcontextsingle")
 end
end
local function readpairsets(f,tableoffset,sets,format1,format2)
 local done={}
 for i=1,#sets do
   local offset=sets[i]
   local reused=done[offset]
   if not reused then
     setposition(f,tableoffset+offset)
     local n=readushort(f)
     reused={}
     for i=1,n do
       reused[i]={
         readushort(f),
         readposition(f,format1),
         readposition(f,format2)
       }
     end
     done[offset]=reused
   end
   sets[i]=reused
 end
 return sets
end
local function readpairclasssets(f,nofclasses1,nofclasses2,format1,format2)
 local classlist1={}
 for i=1,nofclasses1 do
   local classlist2={}
   classlist1[i]=classlist2
   for j=1,nofclasses2 do
     local one=readposition(f,format1)
     local two=readposition(f,format2)
     if one or two then
       classlist2[j]={ one,two }
     else
       classlist2[j]=false
     end
   end
 end
 return classlist1
end
function gposhandlers.single(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
 local tableoffset=lookupoffset+offset
 setposition(f,tableoffset)
 local subtype=readushort(f)
 if subtype==1 then
   local coverage=readushort(f)
   local format=readushort(f)
   local value=readposition(f,format)
   local coverage=readcoverage(f,tableoffset+coverage)
   for index,newindex in next,coverage do
     coverage[index]=value
   end
   return {
     format="pair",
     coverage=coverage
   }
 elseif subtype==2 then
   local coverage=readushort(f)
   local format=readushort(f)
   local values={}
   local nofvalues=readushort(f)
   for i=1,nofvalues do
     values[i]=readposition(f,format)
   end
   local coverage=readcoverage(f,tableoffset+coverage)
   for index,newindex in next,coverage do
     coverage[index]=values[newindex+1]
   end
   return {
     format="pair",
     coverage=coverage
   }
 else
   report("unsupported subtype %a in %a positioning",subtype,"single")
 end
end
function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
 local tableoffset=lookupoffset+offset
 setposition(f,tableoffset)
 local subtype=readushort(f)
 if subtype==1 then
   local coverage=readushort(f)
   local format1=readushort(f)
   local format2=readushort(f)
   local sets=readarray(f)
      sets=readpairsets(f,tableoffset,sets,format1,format2)
      coverage=readcoverage(f,tableoffset+coverage)
   for index,newindex in next,coverage do
     local set=sets[newindex+1]
     local hash={}
     for i=1,#set do
       local value=set[i]
       if value then
         local other=value[1]
         local first=value[2]
         local second=value[3]
         if first or second then
           hash[other]={ first,second }
         else
           hash[other]=nil
         end
       end
     end
     coverage[index]=hash
   end
   return {
     format="pair",
     coverage=coverage
   }
 elseif subtype==2 then
   local coverage=readushort(f)
   local format1=readushort(f)
   local format2=readushort(f)
   local classdef1=readushort(f)
   local classdef2=readushort(f)
   local nofclasses1=readushort(f)
   local nofclasses2=readushort(f)
   local classlist=readpairclasssets(f,nofclasses1,nofclasses2,format1,format2)
      coverage=readcoverage(f,tableoffset+coverage)
      classdef1=readclassdef(f,tableoffset+classdef1,coverage)
      classdef2=readclassdef(f,tableoffset+classdef2,nofglyphs)
   local usedcoverage={}
   for g1,c1 in next,classdef1 do
     if coverage[g1] then
       local l1=classlist[c1]
       if l1 then
         local hash={}
         for paired,class in next,classdef2 do
           local offsets=l1[class]
           if offsets then
             local first=offsets[1]
             local second=offsets[2]
             if first or second then
               hash[paired]={ first,second }
             else
             end
           end
         end
         usedcoverage[g1]=hash
       end
     end
   end
   return {
     format="pair",
     coverage=usedcoverage
   }
 elseif subtype==3 then
   report("yet unsupported subtype %a in %a positioning",subtype,"pair")
 else
   report("unsupported subtype %a in %a positioning",subtype,"pair")
 end
end
function gposhandlers.cursive(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
 local tableoffset=lookupoffset+offset
 setposition(f,tableoffset)
 local subtype=readushort(f)
 if subtype==1 then
   local coverage=tableoffset+readushort(f)
   local nofrecords=readushort(f)
   local records={}
   for i=1,nofrecords do
     local entry=readushort(f)
     local exit=readushort(f)
     records[i]={
       entry=entry~=0 and (tableoffset+entry) or false,
       exit=exit~=0 and (tableoffset+exit ) or false,
     }
   end
   coverage=readcoverage(f,coverage)
   for i=1,nofrecords do
     local r=records[i]
     records[i]={
       1,
       readanchor(f,r.entry) or nil,
       readanchor(f,r.exit ) or nil,
     }
   end
   for index,newindex in next,coverage do
     coverage[index]=records[newindex+1]
   end
   return {
     coverage=coverage
   }
 else
   report("unsupported subtype %a in %a positioning",subtype,"cursive")
 end
end
local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,ligature)
 local tableoffset=lookupoffset+offset
 setposition(f,tableoffset)
 local subtype=readushort(f)
 if subtype==1 then
   local markcoverage=tableoffset+readushort(f)
   local basecoverage=tableoffset+readushort(f)
   local nofclasses=readushort(f)
   local markoffset=tableoffset+readushort(f)
   local baseoffset=tableoffset+readushort(f)
   local markcoverage=readcoverage(f,markcoverage)
   local basecoverage=readcoverage(f,basecoverage,true)
   setposition(f,markoffset)
   local markclasses={}
   local nofmarkclasses=readushort(f)
   local lastanchor=fontdata.lastanchor or 0
   local usedanchors={}
   for i=1,nofmarkclasses do
     local class=readushort(f)+1
     local offset=readushort(f)
     if offset==0 then
       markclasses[i]=false
     else
       markclasses[i]={ class,markoffset+offset }
     end
     usedanchors[class]=true
   end
   for i=1,nofmarkclasses do
     local mc=markclasses[i]
     if mc then
       mc[2]=readanchor(f,mc[2])
     end
   end
   setposition(f,baseoffset)
   local nofbaserecords=readushort(f)
   local baserecords={}
   if ligature then
     for i=1,nofbaserecords do
       local offset=readushort(f)
       if offset==0 then
         baserecords[i]=false
       else
         baserecords[i]=baseoffset+offset
       end
     end
     for i=1,nofbaserecords do
       local recordoffset=baserecords[i]
       if recordoffset then
         setposition(f,recordoffset)
         local nofcomponents=readushort(f)
         local components={}
         for i=1,nofcomponents do
           local classes={}
           for i=1,nofclasses do
             local offset=readushort(f)
             if offset~=0 then
               classes[i]=recordoffset+offset
             else
               classes[i]=false
             end
           end
           components[i]=classes
         end
         baserecords[i]=components
       end
     end
     local baseclasses={}
     for i=1,nofclasses do
       baseclasses[i]={}
     end
     for i=1,nofbaserecords do
       local components=baserecords[i]
       if components then
         local b=basecoverage[i]
         for c=1,#components do
           local classes=components[c]
           if classes then
             for i=1,nofclasses do
               local anchor=readanchor(f,classes[i])
               local bclass=baseclasses[i]
               local bentry=bclass[b]
               if bentry then
                 bentry[c]=anchor
               else
                 bclass[b]={ [c]=anchor }
               end
             end
           end
         end
       end
     end
     for index,newindex in next,markcoverage do
       markcoverage[index]=markclasses[newindex+1] or nil
     end
     return {
       format="ligature",
       baseclasses=baseclasses,
       coverage=markcoverage,
     }
   else
     for i=1,nofbaserecords do
       local r={}
       for j=1,nofclasses do
         local offset=readushort(f)
         if offset==0 then
           r[j]=false
         else
           r[j]=baseoffset+offset
         end
       end
       baserecords[i]=r
     end
     local baseclasses={}
     for i=1,nofclasses do
       baseclasses[i]={}
     end
     for i=1,nofbaserecords do
       local r=baserecords[i]
       local b=basecoverage[i]
       for j=1,nofclasses do
         baseclasses[j][b]=readanchor(f,r[j])
       end
     end
     for index,newindex in next,markcoverage do
       markcoverage[index]=markclasses[newindex+1] or nil
     end
     return {
       format="base",
       baseclasses=baseclasses,
       coverage=markcoverage,
     }
   end
 else
   report("unsupported subtype %a in",subtype)
 end
end
function gposhandlers.marktobase(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
 return handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
end
function gposhandlers.marktoligature(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
 return handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,true)
end
function gposhandlers.marktomark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
 return handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
end
function gposhandlers.context(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
 return unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"positioning"),"context"
end
function gposhandlers.chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
 return chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"positioning"),"chainedcontext"
end
function gposhandlers.extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
 return extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,gpostypes,gposhandlers,"positioning")
end
do
 local plugins={}
 function plugins.size(f,fontdata,tableoffset,feature)
   if fontdata.designsize then
   else
     local function check(offset)
       setposition(f,offset)
       local designsize=readushort(f)
       if designsize>0 then
         local fontstyle=readushort(f)
         local guimenuid=readushort(f)
         local minsize=readushort(f)
         local maxsize=readushort(f)
         if minsize==0 and maxsize==0 and fontstyleid==0 and guimenuid==0 then
           minsize=designsize
           maxsize=designsize
         end
         if designsize>=minsize and designsize<=maxsize then
           return minsize,maxsize,designsize
         end
       end
     end
     local minsize,maxsize,designsize=check(tableoffset+feature.offset+feature.parameters)
     if not designsize then
       minsize,maxsize,designsize=check(tableoffset+feature.parameters)
       if designsize then
         report("bad size feature in %a, falling back to wrong offset",fontdata.filename or "?")
       else
         report("bad size feature in %a,",fontdata.filename or "?")
       end
     end
     if designsize then
       fontdata.minsize=minsize
       fontdata.maxsize=maxsize
       fontdata.designsize=designsize
     end
   end
 end
 local function reorderfeatures(fontdata,scripts,features)
   local scriptlangs={}
   local featurehash={}
   local featureorder={}
   for script,languages in next,scripts do
     for language,record in next,languages do
       local hash={}
       local list=record.featureindices
       for k=1,#list do
         local index=list[k]
         local feature=features[index]
         local lookups=feature.lookups
         local tag=feature.tag
         if tag then
           hash[tag]=true
         end
         if lookups then
           for i=1,#lookups do
             local lookup=lookups[i]
             local o=featureorder[lookup]
             if o then
               local okay=true
               for i=1,#o do
                 if o[i]==tag then
                   okay=false
                   break
                 end
               end
               if okay then
                 o[#o+1]=tag
               end
             else
               featureorder[lookup]={ tag }
             end
             local f=featurehash[lookup]
             if f then
               local h=f[tag]
               if h then
                 local s=h[script]
                 if s then
                   s[language]=true
                 else
                   h[script]={ [language]=true }
                 end
               else
                 f[tag]={ [script]={ [language]=true } }
               end
             else
               featurehash[lookup]={ [tag]={ [script]={ [language]=true } } }
             end
             local h=scriptlangs[tag]
             if h then
               local s=h[script]
               if s then
                 s[language]=true
               else
                 h[script]={ [language]=true }
               end
             else
               scriptlangs[tag]={ [script]={ [language]=true } }
             end
           end
         end
       end
     end
   end
   return scriptlangs,featurehash,featureorder
 end
 local function readscriplan(f,fontdata,scriptoffset)
   setposition(f,scriptoffset)
   local nofscripts=readushort(f)
   local scripts={}
   for i=1,nofscripts do
     scripts[readtag(f)]=scriptoffset+readushort(f)
   end
   local languagesystems=setmetatableindex("table")
   for script,offset in next,scripts do
     setposition(f,offset)
     local defaultoffset=readushort(f)
     local noflanguages=readushort(f)
     local languages={}
     if defaultoffset>0 then
       languages.dflt=languagesystems[offset+defaultoffset]
     end
     for i=1,noflanguages do
       local language=readtag(f)
       local offset=offset+readushort(f)
       languages[language]=languagesystems[offset]
     end
     scripts[script]=languages
   end
   for offset,usedfeatures in next,languagesystems do
     if offset>0 then
       setposition(f,offset)
       local featureindices={}
       usedfeatures.featureindices=featureindices
       usedfeatures.lookuporder=readushort(f)
       usedfeatures.requiredindex=readushort(f)
       local noffeatures=readushort(f)
       for i=1,noffeatures do
         featureindices[i]=readushort(f)+1
       end
     end
   end
   return scripts
 end
 local function readfeatures(f,fontdata,featureoffset)
   setposition(f,featureoffset)
   local features={}
   local noffeatures=readushort(f)
   for i=1,noffeatures do
     features[i]={
       tag=readtag(f),
       offset=readushort(f)
     }
   end
   for i=1,noffeatures do
     local feature=features[i]
     local offset=featureoffset+feature.offset
     setposition(f,offset)
     local parameters=readushort(f)
     local noflookups=readushort(f)
     if noflookups>0 then
       local lookups={}
       feature.lookups=lookups
       for j=1,noflookups do
         lookups[j]=readushort(f)+1
       end
     end
     if parameters>0 then
       feature.parameters=parameters
       local plugin=plugins[feature.tag]
       if plugin then
         plugin(f,fontdata,featureoffset,feature)
       end
     end
   end
   return features
 end
 local function readlookups(f,lookupoffset,lookuptypes,featurehash,featureorder)
   setposition(f,lookupoffset)
   local lookups={}
   local noflookups=readushort(f)
   for i=1,noflookups do
     lookups[i]=readushort(f)
   end
   for lookupid=1,noflookups do
     local index=lookups[lookupid]
     setposition(f,lookupoffset+index)
     local subtables={}
     local typebits=readushort(f)
     local flagbits=readushort(f)
     local lookuptype=lookuptypes[typebits]
     local lookupflags=lookupflags[flagbits]
     local nofsubtables=readushort(f)
     for j=1,nofsubtables do
       local offset=readushort(f)
       subtables[j]=offset+index
     end
     local markclass=bittest(flagbits,0x0010)
     if markclass then
       markclass=readushort(f)
     end
     local markset=rshift(flagbits,8)
     if markset>0 then
       markclass=markset
     end
     lookups[lookupid]={
       type=lookuptype,
       flags=lookupflags,
       name=lookupid,
       subtables=subtables,
       markclass=markclass,
       features=featurehash[lookupid],
       order=featureorder[lookupid],
     }
   end
   return lookups
 end
 local function readscriptoffsets(f,fontdata,tableoffset)
   if not tableoffset then
     return
   end
   setposition(f,tableoffset)
   local version=readulong(f)
   if version~=0x00010000 then
     report("table version %a of %a is not supported (yet), maybe font %s is bad",version,what,fontdata.filename)
     return
   end
   return tableoffset+readushort(f),tableoffset+readushort(f),tableoffset+readushort(f)
 end
 local f_lookupname=formatters["%s_%s_%s"]
 local function resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what)
   local sequences=fontdata.sequences  or {}
   local sublookuplist=fontdata.sublookups or {}
   fontdata.sequences=sequences
   fontdata.sublookups=sublookuplist
   local nofsublookups=#sublookuplist
   local nofsequences=#sequences
   local lastsublookup=nofsublookups
   local lastsequence=nofsequences
   local lookupnames=lookupnames[what]
   local sublookuphash={}
   local sublookupcheck={}
   local glyphs=fontdata.glyphs
   local nofglyphs=fontdata.nofglyphs or #glyphs
   local noflookups=#lookups
   local lookupprefix=sub(what,2,2)
   for lookupid=1,noflookups do
     local lookup=lookups[lookupid]
     local lookuptype=lookup.type
     local subtables=lookup.subtables
     local features=lookup.features
     local handler=lookuphandlers[lookuptype]
     if handler then
       local nofsubtables=#subtables
       local order=lookup.order
       local flags=lookup.flags
       if flags[1] then flags[1]="mark" end
       if flags[2] then flags[2]="ligature" end
       if flags[3] then flags[3]="base" end
       local markclass=lookup.markclass
       if nofsubtables>0 then
         local steps={}
         local nofsteps=0
         local oldtype=nil
         for s=1,nofsubtables do
           local step,lt=handler(f,fontdata,lookupid,lookupoffset,subtables[s],glyphs,nofglyphs)
           if lt then
             lookuptype=lt
             if oldtype and lt~=oldtype then
               report("messy %s lookup type %a and %a",what,lookuptype,oldtype)
             end
             oldtype=lookuptype
           end
           if not step then
             report("unsupported %s lookup type %a",what,lookuptype)
           else
             nofsteps=nofsteps+1
             steps[nofsteps]=step
             local rules=step.rules
             if rules then
               for i=1,#rules do
                 local rule=rules[i]
                 local before=rule.before
                 local current=rule.current
                 local after=rule.after
                 if before then
                   for i=1,#before do
                     before[i]=tohash(before[i])
                   end
                   rule.before=reversed(before)
                 end
                 if current then
                   for i=1,#current do
                     current[i]=tohash(current[i])
                   end
                 end
                 if after then
                   for i=1,#after do
                     after[i]=tohash(after[i])
                   end
                 end
               end
             end
           end
         end
         if nofsteps~=nofsubtables then
           report("bogus subtables removed in %s lookup type %a",what,lookuptype)
         end
         lookuptype=lookupnames[lookuptype] or lookuptype
         if features then
           nofsequences=nofsequences+1
           local l={
             index=nofsequences,
             name=f_lookupname(lookupprefix,"s",lookupid+lookupidoffset),
             steps=steps,
             nofsteps=nofsteps,
             type=lookuptype,
             markclass=markclass or nil,
             flags=flags,
             order=order,
             features=features,
           }
           sequences[nofsequences]=l
           lookup.done=l
         else
           nofsublookups=nofsublookups+1
           local l={
             index=nofsublookups,
             name=f_lookupname(lookupprefix,"l",lookupid+lookupidoffset),
             steps=steps,
             nofsteps=nofsteps,
             type=lookuptype,
             markclass=markclass or nil,
             flags=flags,
           }
           sublookuplist[nofsublookups]=l
           sublookuphash[lookupid]=nofsublookups
           sublookupcheck[lookupid]=0
           lookup.done=l
         end
       else
         report("no subtables for lookup %a",lookupid)
       end
     else
       report("no handler for lookup %a with type %a",lookupid,lookuptype)
     end
   end
   local reported={}
   local function report_issue(i,what,sequence,kind)
     local name=sequence.name
     if not reported[name] then
       report("rule %i in %s lookup %a has %s lookups",i,what,name,kind)
       reported[name]=true
     end
   end
   for i=lastsequence+1,nofsequences do
     local sequence=sequences[i]
     local steps=sequence.steps
     for i=1,#steps do
       local step=steps[i]
       local rules=step.rules
       if rules then
         for i=1,#rules do
           local rule=rules[i]
           local rlookups=rule.lookups
           if not rlookups then
             report_issue(i,what,sequence,"no")
           elseif not next(rlookups) then
             report_issue(i,what,sequence,"empty")
             rule.lookups=nil
           else
             local length=#rlookups
             for index=1,length do
               local lookupid=rlookups[index]
               if lookupid then
                 local h=sublookuphash[lookupid]
                 if not h then
                   local lookup=lookups[lookupid]
                   if lookup then
                     local d=lookup.done
                     if d then
                       nofsublookups=nofsublookups+1
                       h={
                         index=nofsublookups,
                         name=f_lookupname(lookupprefix,"d",lookupid+lookupidoffset),
                         derived=true,
                         steps=d.steps,
                         nofsteps=d.nofsteps,
                         type=d.lookuptype,
                         markclass=d.markclass or nil,
                         flags=d.flags,
                       }
                       sublookuplist[nofsublookups]=copy(h)
                       sublookuphash[lookupid]=nofsublookups
                       sublookupcheck[lookupid]=1
                       h=nofsublookups
                     else
                       report_issue(i,what,sequence,"missing")
                       rule.lookups=nil
                       break
                     end
                   else
                     report_issue(i,what,sequence,"bad")
                     rule.lookups=nil
                     break
                   end
                 else
                   sublookupcheck[lookupid]=sublookupcheck[lookupid]+1
                 end
                 rlookups[index]=h or false
               else
                 rlookups[index]=false
               end
             end
           end
         end
       end
     end
   end
   for i,n in sortedhash(sublookupcheck) do
     local l=lookups[i]
     local t=l.type
     if n==0 and t~="extension" then
       local d=l.done
       report("%s lookup %s of type %a is not used",what,d and d.name or l.name,t)
     end
   end
 end
 local function readscripts(f,fontdata,what,lookuptypes,lookuphandlers,lookupstoo)
   local datatable=fontdata.tables[what]
   if not datatable then
     return
   end
   local tableoffset=datatable.offset
   if not tableoffset then
     return
   end
   local scriptoffset,featureoffset,lookupoffset=readscriptoffsets(f,fontdata,tableoffset)
   if not scriptoffset then
     return
   end
   local scripts=readscriplan(f,fontdata,scriptoffset)
   local features=readfeatures(f,fontdata,featureoffset)
   local scriptlangs,featurehash,featureorder=reorderfeatures(fontdata,scripts,features)
   if fontdata.features then
     fontdata.features[what]=scriptlangs
   else
     fontdata.features={ [what]=scriptlangs }
   end
   if not lookupstoo then
     return
   end
   local lookups=readlookups(f,lookupoffset,lookuptypes,featurehash,featureorder)
   if lookups then
     resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what)
   end
 end
 local function checkkerns(f,fontdata,specification)
   local datatable=fontdata.tables.kern
   if not datatable then
     return
   end
   local features=fontdata.features
   local gposfeatures=features and features.gpos
   local name
   if not gposfeatures or not gposfeatures.kern then
     name="kern"
   elseif specification.globalkerns then
     name="globalkern"
   else
     report("ignoring global kern table using gpos kern feature")
     return
   end
   report("adding global kern table as gpos feature %a",name)
   setposition(f,datatable.offset)
   local version=readushort(f)
   local noftables=readushort(f)
   local kerns=setmetatableindex("table")
   for i=1,noftables do
     local version=readushort(f)
     local length=readushort(f)
     local coverage=readushort(f)
     local format=bit32.rshift(coverage,8)
     if format==0 then
       local nofpairs=readushort(f)
       local searchrange=readushort(f)
       local entryselector=readushort(f)
       local rangeshift=readushort(f)
       for i=1,nofpairs do
         kerns[readushort(f)][readushort(f)]=readfword(f)
       end
     elseif format==2 then
     else
     end
   end
   local feature={ dflt={ dflt=true } }
   if not features then
     fontdata.features={ gpos={ [name]=feature } }
   elseif not gposfeatures then
     fontdata.features.gpos={ [name]=feature }
   else
     gposfeatures[name]=feature
   end
   local sequences=fontdata.sequences
   if not sequences then
     sequences={}
     fontdata.sequences=sequences
   end
   local nofsequences=#sequences+1
   sequences[nofsequences]={
     index=nofsequences,
     name=name,
     steps={
       {
         coverage=kerns,
         format="kern",
       },
     },
     nofsteps=1,
     type="gpos_pair",
     flags={ false,false,false,false },
     order={ name },
     features={ [name]=feature },
   }
 end
 function readers.gsub(f,fontdata,specification)
   if specification.details then
     readscripts(f,fontdata,"gsub",gsubtypes,gsubhandlers,specification.lookups)
   end
 end
 function readers.gpos(f,fontdata,specification)
   if specification.details then
     readscripts(f,fontdata,"gpos",gpostypes,gposhandlers,specification.lookups)
     if specification.lookups then
       checkkerns(f,fontdata,specification)
     end
   end
 end
end
function readers.gdef(f,fontdata,specification)
 if specification.glyphs then
   local datatable=fontdata.tables.gdef
   if datatable then
     local tableoffset=datatable.offset
     setposition(f,tableoffset)
     local version=readulong(f)
     local classoffset=tableoffset+readushort(f)
     local attachmentoffset=tableoffset+readushort(f)
     local ligaturecarets=tableoffset+readushort(f)
     local markclassoffset=tableoffset+readushort(f)
     local marksetsoffset=version==0x00010002 and (tableoffset+readushort(f))
     local glyphs=fontdata.glyphs
     local marks={}
     local markclasses=setmetatableindex("table")
     local marksets=setmetatableindex("table")
     fontdata.marks=marks
     fontdata.markclasses=markclasses
     fontdata.marksets=marksets
     setposition(f,classoffset)
     local classformat=readushort(f)
     if classformat==1 then
       local firstindex=readushort(f)
       local lastindex=firstindex+readushort(f)-1
       for index=firstindex,lastindex do
         local class=classes[readushort(f)]
         if class=="mark" then
           marks[index]=true
         end
         glyphs[index].class=class
       end
     elseif classformat==2 then
       local nofranges=readushort(f)
       for i=1,nofranges do
         local firstindex=readushort(f)
         local lastindex=readushort(f)
         local class=classes[readushort(f)]
         if class then
           for index=firstindex,lastindex do
             glyphs[index].class=class
             if class=="mark" then
               marks[index]=true
             end
           end
         end
       end
     end
     setposition(f,markclassoffset)
     local classformat=readushort(f)
     if classformat==1 then
       local firstindex=readushort(f)
       local lastindex=firstindex+readushort(f)-1
       for index=firstindex,lastindex do
         markclasses[readushort(f)][index]=true
       end
     elseif classformat==2 then
       local nofranges=readushort(f)
       for i=1,nofranges do
         local firstindex=readushort(f)
         local lastindex=readushort(f)
         local class=markclasses[readushort(f)]
         for index=firstindex,lastindex do
           class[index]=true
         end
       end
     end
     if marksetsoffset and marksetsoffset>tableoffset then
       setposition(f,marksetsoffset)
       local format=readushort(f)
       if format==1 then
         local nofsets=readushort(f)
         local sets={}
         for i=1,nofsets do
           sets[i]=readulong(f)
         end
         for i=1,nofsets do
           local offset=sets[i]
           if offset~=0 then
             marksets[i]=readcoverage(f,marksetsoffset+offset)
           end
         end
       end
     end
   end
 end
end
local function readmathvalue(f)
 local v=readshort(f)
 skipshort(f,1)
 return v
end
local function readmathconstants(f,fontdata,offset)
 setposition(f,offset)
 fontdata.mathconstants={
   ScriptPercentScaleDown=readshort(f),
   ScriptScriptPercentScaleDown=readshort(f),
   DelimitedSubFormulaMinHeight=readushort(f),
   DisplayOperatorMinHeight=readushort(f),
   MathLeading=readmathvalue(f),
   AxisHeight=readmathvalue(f),
   AccentBaseHeight=readmathvalue(f),
   FlattenedAccentBaseHeight=readmathvalue(f),
   SubscriptShiftDown=readmathvalue(f),
   SubscriptTopMax=readmathvalue(f),
   SubscriptBaselineDropMin=readmathvalue(f),
   SuperscriptShiftUp=readmathvalue(f),
   SuperscriptShiftUpCramped=readmathvalue(f),
   SuperscriptBottomMin=readmathvalue(f),
   SuperscriptBaselineDropMax=readmathvalue(f),
   SubSuperscriptGapMin=readmathvalue(f),
   SuperscriptBottomMaxWithSubscript=readmathvalue(f),
   SpaceAfterScript=readmathvalue(f),
   UpperLimitGapMin=readmathvalue(f),
   UpperLimitBaselineRiseMin=readmathvalue(f),
   LowerLimitGapMin=readmathvalue(f),
   LowerLimitBaselineDropMin=readmathvalue(f),
   StackTopShiftUp=readmathvalue(f),
   StackTopDisplayStyleShiftUp=readmathvalue(f),
   StackBottomShiftDown=readmathvalue(f),
   StackBottomDisplayStyleShiftDown=readmathvalue(f),
   StackGapMin=readmathvalue(f),
   StackDisplayStyleGapMin=readmathvalue(f),
   StretchStackTopShiftUp=readmathvalue(f),
   StretchStackBottomShiftDown=readmathvalue(f),
   StretchStackGapAboveMin=readmathvalue(f),
   StretchStackGapBelowMin=readmathvalue(f),
   FractionNumeratorShiftUp=readmathvalue(f),
   FractionNumeratorDisplayStyleShiftUp=readmathvalue(f),
   FractionDenominatorShiftDown=readmathvalue(f),
   FractionDenominatorDisplayStyleShiftDown=readmathvalue(f),
   FractionNumeratorGapMin=readmathvalue(f),
   FractionNumeratorDisplayStyleGapMin=readmathvalue(f),
   FractionRuleThickness=readmathvalue(f),
   FractionDenominatorGapMin=readmathvalue(f),
   FractionDenominatorDisplayStyleGapMin=readmathvalue(f),
   SkewedFractionHorizontalGap=readmathvalue(f),
   SkewedFractionVerticalGap=readmathvalue(f),
   OverbarVerticalGap=readmathvalue(f),
   OverbarRuleThickness=readmathvalue(f),
   OverbarExtraAscender=readmathvalue(f),
   UnderbarVerticalGap=readmathvalue(f),
   UnderbarRuleThickness=readmathvalue(f),
   UnderbarExtraDescender=readmathvalue(f),
   RadicalVerticalGap=readmathvalue(f),
   RadicalDisplayStyleVerticalGap=readmathvalue(f),
   RadicalRuleThickness=readmathvalue(f),
   RadicalExtraAscender=readmathvalue(f),
   RadicalKernBeforeDegree=readmathvalue(f),
   RadicalKernAfterDegree=readmathvalue(f),
   RadicalDegreeBottomRaisePercent=readshort(f),
 }
end
local function readmathglyphinfo(f,fontdata,offset)
 setposition(f,offset)
 local italics=readushort(f)
 local accents=readushort(f)
 local extensions=readushort(f)
 local kerns=readushort(f)
 local glyphs=fontdata.glyphs
 if italics~=0 then
   setposition(f,offset+italics)
   local coverage=readushort(f)
   local nofglyphs=readushort(f)
   coverage=readcoverage(f,offset+italics+coverage,true)
   setposition(f,offset+italics+4)
   for i=1,nofglyphs do
     local italic=readmathvalue(f)
     if italic~=0 then
       local glyph=glyphs[coverage[i]]
       local math=glyph.math
       if not math then
         glyph.math={ italic=italic }
       else
         math.italic=italic
       end
     end
   end
   fontdata.hasitalics=true
 end
 if accents~=0 then
   setposition(f,offset+accents)
   local coverage=readushort(f)
   local nofglyphs=readushort(f)
   coverage=readcoverage(f,offset+accents+coverage,true)
   setposition(f,offset+accents+4)
   for i=1,nofglyphs do
     local accent=readmathvalue(f)
     if accent~=0 then
       local glyph=glyphs[coverage[i]]
       local math=glyph.math
       if not math then
         glyph.math={ accent=accent }
       else
         math.accent=accent
       end
     end
   end
 end
 if extensions~=0 then
   setposition(f,offset+extensions)
 end
 if kerns~=0 then
   local kernoffset=offset+kerns
   setposition(f,kernoffset)
   local coverage=readushort(f)
   local nofglyphs=readushort(f)
   if nofglyphs>0 then
     local function get(offset)
       setposition(f,kernoffset+offset)
       local n=readushort(f)
       if n==0 then
         local k=readmathvalue(f)
         if k==0 then
         else
           return { { kern=k } }
         end
       else
         local l={}
         for i=1,n do
           l[i]={ height=readmathvalue(f) }
         end
         for i=1,n do
           l[i].kern=readmathvalue(f)
         end
         l[n+1]={ kern=readmathvalue(f) }
         return l
       end
     end
     local kernsets={}
     for i=1,nofglyphs do
       local topright=readushort(f)
       local topleft=readushort(f)
       local bottomright=readushort(f)
       local bottomleft=readushort(f)
       kernsets[i]={
         topright=topright~=0 and topright  or nil,
         topleft=topleft~=0 and topleft   or nil,
         bottomright=bottomright~=0 and bottomright or nil,
         bottomleft=bottomleft~=0 and bottomleft or nil,
       }
     end
     coverage=readcoverage(f,kernoffset+coverage,true)
     for i=1,nofglyphs do
       local kernset=kernsets[i]
       if next(kernset) then
         local k=kernset.topright  if k then kernset.topright=get(k) end
         local k=kernset.topleft   if k then kernset.topleft=get(k) end
         local k=kernset.bottomright if k then kernset.bottomright=get(k) end
         local k=kernset.bottomleft if k then kernset.bottomleft=get(k) end
         if next(kernset) then
           local glyph=glyphs[coverage[i]]
           local math=glyph.math
           if math then
             math.kerns=kernset
           else
             glyph.math={ kerns=kernset }
           end
         end
       end
     end
   end
 end
end
local function readmathvariants(f,fontdata,offset)
 setposition(f,offset)
 local glyphs=fontdata.glyphs
 local minoverlap=readushort(f)
 local vcoverage=readushort(f)
 local hcoverage=readushort(f)
 local vnofglyphs=readushort(f)
 local hnofglyphs=readushort(f)
 local vconstruction={}
 local hconstruction={}
 for i=1,vnofglyphs do
   vconstruction[i]=readushort(f)
 end
 for i=1,hnofglyphs do
   hconstruction[i]=readushort(f)
 end
 fontdata.mathconstants.MinConnectorOverlap=minoverlap
 local function get(offset,coverage,nofglyphs,construction,kvariants,kparts,kitalic)
   if coverage~=0 and nofglyphs>0 then
     local coverage=readcoverage(f,offset+coverage,true)
     for i=1,nofglyphs do
       local c=construction[i]
       if c~=0 then
         local index=coverage[i]
         local glyph=glyphs[index]
         local math=glyph.math
         setposition(f,offset+c)
         local assembly=readushort(f)
         local nofvariants=readushort(f)
         if nofvariants>0 then
           local variants,v=nil,0
           for i=1,nofvariants do
             local variant=readushort(f)
             if variant==index then
             elseif variants then
               v=v+1
               variants[v]=variant
             else
               v=1
               variants={ variant }
             end
             skipshort(f)
           end
           if not variants then
           elseif not math then
             math={ [kvariants]=variants }
             glyph.math=math
           else
             math[kvariants]=variants
           end
         end
         if assembly~=0 then
           setposition(f,offset+c+assembly)
           local italic=readmathvalue(f)
           local nofparts=readushort(f)
           local parts={}
           for i=1,nofparts do
             local p={
               glyph=readushort(f),
               start=readushort(f),
               ["end"]=readushort(f),
               advance=readushort(f),
             }
             local flags=readushort(f)
             if bittest(flags,0x0001) then
               p.extender=1
             end
             parts[i]=p
           end
           if not math then
             math={
               [kparts]=parts
             }
             glyph.math=math
           else
             math[kparts]=parts
           end
           if italic and italic~=0 then
             math[kitalic]=italic
           end
         end
       end
     end
   end
 end
 get(offset,vcoverage,vnofglyphs,vconstruction,"vvariants","vparts","vitalic")
 get(offset,hcoverage,hnofglyphs,hconstruction,"hvariants","hparts","hitalic")
end
function readers.math(f,fontdata,specification)
 if specification.glyphs then
   local datatable=fontdata.tables.math
   if datatable then
     local tableoffset=datatable.offset
     setposition(f,tableoffset)
     local version=readulong(f)
     if version~=0x00010000 then
       report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"math",fontdata.filename)
       return
     end
     local constants=readushort(f)
     local glyphinfo=readushort(f)
     local variants=readushort(f)
     if constants==0 then
       report("the math table of %a has no constants",fontdata.filename)
     else
       readmathconstants(f,fontdata,tableoffset+constants)
     end
     if glyphinfo~=0 then
       readmathglyphinfo(f,fontdata,tableoffset+glyphinfo)
     end
     if variants~=0 then
       readmathvariants(f,fontdata,tableoffset+variants)
     end
   end
 end
end
function readers.colr(f,fontdata,specification)
 local datatable=fontdata.tables.colr
 if datatable then
   if specification.glyphs then
     local tableoffset=datatable.offset
     setposition(f,tableoffset)
     local version=readushort(f)
     if version~=0 then
       report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"colr",fontdata.filename)
       return
     end
     if not fontdata.tables.cpal then
       report("color table %a in font %a has no mandate %a table","colr",fontdata.filename,"cpal")
       fontdata.colorpalettes={}
     end
     local glyphs=fontdata.glyphs
     local nofglyphs=readushort(f)
     local baseoffset=readulong(f)
     local layeroffset=readulong(f)
     local noflayers=readushort(f)
     local layerrecords={}
     local maxclass=0
     setposition(f,tableoffset+layeroffset)
     for i=1,noflayers do
       local slot=readushort(f)
       local class=readushort(f)
       if class<0xFFFF then
         class=class+1
         if class>maxclass then
           maxclass=class
         end
       end
       layerrecords[i]={
         slot=slot,
         class=class,
       }
     end
     fontdata.maxcolorclass=maxclass
     setposition(f,tableoffset+baseoffset)
     for i=0,nofglyphs-1 do
       local glyphindex=readushort(f)
       local firstlayer=readushort(f)
       local noflayers=readushort(f)
       local t={}
       for i=1,noflayers do
         t[i]=layerrecords[firstlayer+i]
       end
       glyphs[glyphindex].colors=t
     end
   end
   fontdata.hascolor=true
 end
end
function readers.cpal(f,fontdata,specification)
 if specification.glyphs then
   local datatable=fontdata.tables.cpal
   if datatable then
     local tableoffset=datatable.offset
     setposition(f,tableoffset)
     local version=readushort(f)
     if version>1 then
       report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"cpal",fontdata.filename)
       return
     end
     local nofpaletteentries=readushort(f)
     local nofpalettes=readushort(f)
     local nofcolorrecords=readushort(f)
     local firstcoloroffset=readulong(f)
     local colorrecords={}
     local palettes={}
     for i=1,nofpalettes do
       palettes[i]=readushort(f)
     end
     if version==1 then
       local palettettypesoffset=readulong(f)
       local palettelabelsoffset=readulong(f)
       local paletteentryoffset=readulong(f)
     end
     setposition(f,tableoffset+firstcoloroffset)
     for i=1,nofcolorrecords do
       local b,g,r,a=readbytes(f,4)
       colorrecords[i]={
         r,g,b,a~=255 and a or nil,
       }
     end
     for i=1,nofpalettes do
       local p={}
       local o=palettes[i]
       for j=1,nofpaletteentries do
         p[j]=colorrecords[o+j]
       end
       palettes[i]=p
     end
     fontdata.colorpalettes=palettes
   end
 end
end
function readers.svg(f,fontdata,specification)
 local datatable=fontdata.tables.svg
 if datatable then
   if specification.glyphs then
     local tableoffset=datatable.offset
     setposition(f,tableoffset)
     local version=readushort(f)
     if version~=0 then
       report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"svg",fontdata.filename)
       return
     end
     local glyphs=fontdata.glyphs
     local indexoffset=tableoffset+readulong(f)
     local reserved=readulong(f)
     setposition(f,indexoffset)
     local nofentries=readushort(f)
     local entries={}
     for i=1,nofentries do
       entries[i]={
         first=readushort(f),
         last=readushort(f),
         offset=indexoffset+readulong(f),
         length=readulong(f),
       }
     end
     for i=1,nofentries do
       local entry=entries[i]
       setposition(f,entry.offset)
       entries[i]={
         first=entry.first,
         last=entry.last,
         data=readstring(f,entry.length)
       }
     end
     fontdata.svgshapes=entries
   end
   fontdata.hascolor=true
 end
end

end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-dsp”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-oup” f7237130b648a4c2b477dabedc7f90e8] ---

if not modules then modules={} end modules ['font-oup']={
 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,type=next,type
local P,R,S=lpeg.P,lpeg.R,lpeg.S
local lpegmatch=lpeg.match
local insert,remove,copy,unpack=table.insert,table.remove,table.copy,table.unpack
local formatters=string.formatters
local sortedkeys=table.sortedkeys
local sortedhash=table.sortedhash
local tohash=table.tohash
local report=logs.reporter("otf reader")
local trace_markwidth=false trackers.register("otf.markwidth",function(v) trace_markwidth=v end)
local readers=fonts.handlers.otf.readers
local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000
local f_private=formatters["P%05X"]
local f_unicode=formatters["U%05X"]
local f_index=formatters["I%05X"]
local f_character_y=formatters["%C"]
local f_character_n=formatters["[ %C ]"]
local check_duplicates=true
local check_soft_hyphen=false
directives.register("otf.checksofthyphen",function(v)
 check_soft_hyphen=v
end)
local function replaced(list,index,replacement)
 if type(list)=="number" then
   return replacement
 elseif type(replacement)=="table" then
   local t={}
   local n=index-1
   for i=1,n do
     t[i]=list[i]
   end
   for i=1,#replacement do
     n=n+1
     t[n]=replacement[i]
   end
   for i=index+1,#list do
     n=n+1
     t[n]=list[i]
   end
 else
   list[index]=replacement
   return list
 end
end
local function unifyresources(fontdata,indices)
 local descriptions=fontdata.descriptions
 local resources=fontdata.resources
 if not descriptions or not resources then
   return
 end
 local variants=fontdata.resources.variants
 if variants then
   for selector,unicodes in next,variants do
     for unicode,index in next,unicodes do
       unicodes[unicode]=indices[index]
     end
   end
 end
 local function remark(marks)
   if marks then
     local newmarks={}
     for k,v in next,marks do
       local u=indices[k]
       if u then
         newmarks[u]=v
       else
         report("discarding mark %i",k)
       end
     end
     return newmarks
   end
 end
 local marks=resources.marks
 if marks then
   resources.marks=remark(marks)
 end
 local markclasses=resources.markclasses
 if markclasses then
   for class,marks in next,markclasses do
     markclasses[class]=remark(marks)
   end
 end
 local marksets=resources.marksets
 if marksets then
   for class,marks in next,marksets do
     marksets[class]=remark(marks)
   end
 end
 local done={}
 local duplicates=check_duplicates and resources.duplicates
 if duplicates and not next(duplicates) then
   duplicates=false
 end
 local function recover(cover)
   for i=1,#cover do
     local c=cover[i]
     if not done[c] then
       local t={}
       for k,v in next,c do
         t[indices[k]]=v
       end
       cover[i]=t
       done[c]=d
     end
   end
 end
 local function recursed(c)
   local t={}
   for g,d in next,c do
     if type(d)=="table" then
       t[indices[g]]=recursed(d)
     else
       t[g]=indices[d]
     end
   end
   return t
 end
 local function unifythem(sequences)
   if not sequences then
     return
   end
   for i=1,#sequences do
     local sequence=sequences[i]
     local kind=sequence.type
     local steps=sequence.steps
     local features=sequence.features
     if steps then
       for i=1,#steps do
         local step=steps[i]
         if kind=="gsub_single" then
           local c=step.coverage
           if c then
             local t1=done[c]
             if not t1 then
               t1={}
               if duplicates then
                 for g1,d1 in next,c do
                   local ug1=indices[g1]
                   local ud1=indices[d1]
                   t1[ug1]=ud1
                   local dg1=duplicates[ug1]
                   if dg1 then
                     for u in next,dg1 do
                       t1[u]=ud1
                     end
                   end
                 end
               else
                 for g1,d1 in next,c do
                   t1[indices[g1]]=indices[d1]
                 end
               end
               done[c]=t1
             end
             step.coverage=t1
           end
         elseif kind=="gpos_pair" then
           local c=step.coverage
           if c then
             local t1=done[c]
             if not t1 then
               t1={}
               for g1,d1 in next,c do
                 local t2=done[d1]
                 if not t2 then
                   t2={}
                   for g2,d2 in next,d1 do
                     t2[indices[g2]]=d2
                   end
                   done[d1]=t2
                 end
                 t1[indices[g1]]=t2
               end
               done[c]=t1
             end
             step.coverage=t1
           end
         elseif kind=="gsub_ligature" then
           local c=step.coverage
           if c then
             step.coverage=recursed(c)
           end
         elseif kind=="gsub_alternate" or kind=="gsub_multiple" then
           local c=step.coverage
           if c then
             local t1=done[c]
             if not t1 then
               t1={}
               if duplicates then
                 for g1,d1 in next,c do
                   for i=1,#d1 do
                     d1[i]=indices[d1[i]]
                   end
                   local ug1=indices[g1]
                   t1[ug1]=d1
                   local dg1=duplicates[ug1]
                   if dg1 then
                     for u in next,dg1 do
                       t1[u]=copy(d1)
                     end
                   end
                 end
               else
                 for g1,d1 in next,c do
                   for i=1,#d1 do
                     d1[i]=indices[d1[i]]
                   end
                   t1[indices[g1]]=d1
                 end
               end
               done[c]=t1
             end
             step.coverage=t1
           end
         elseif kind=="gpos_mark2base" or kind=="gpos_mark2mark" or kind=="gpos_mark2ligature" then
           local c=step.coverage
           if c then
             local t1=done[c]
             if not t1 then
               t1={}
               for g1,d1 in next,c do
                 t1[indices[g1]]=d1
               end
               done[c]=t1
             end
             step.coverage=t1
           end
           local c=step.baseclasses
           if c then
             local t1=done[c]
             if not t1 then
               for g1,d1 in next,c do
                 local t2=done[d1]
                 if not t2 then
                   t2={}
                   for g2,d2 in next,d1 do
                     t2[indices[g2]]=d2
                   end
                   done[d1]=t2
                 end
                 c[g1]=t2
               end
               done[c]=c
             end
           end
         elseif kind=="gpos_single" then
           local c=step.coverage
           if c then
             local t1=done[c]
             if not t1 then
               t1={}
               if duplicates then
                 for g1,d1 in next,c do
                   local ug1=indices[g1]
                   t1[ug1]=d1
                   local dg1=duplicates[ug1]
                   if dg1 then
                     for u in next,dg1 do
                       t1[u]=d1
                     end
                   end
                 end
               else
                 for g1,d1 in next,c do
                   t1[indices[g1]]=d1
                 end
               end
               done[c]=t1
             end
             step.coverage=t1
           end
         elseif kind=="gpos_cursive" then
           local c=step.coverage
           if c then
             local t1=done[c]
             if not t1 then
               t1={}
               if duplicates then
                 for g1,d1 in next,c do
                   local ug1=indices[g1]
                   t1[ug1]=d1
                   local dg1=duplicates[ug1]
                   if dg1 then
                     for u in next,dg1 do
                       t1[u]=copy(d1)
                     end
                   end
                 end
               else
                 for g1,d1 in next,c do
                   t1[indices[g1]]=d1
                 end
               end
               done[c]=t1
             end
             step.coverage=t1
           end
         end
         local rules=step.rules
         if rules then
           for i=1,#rules do
             local rule=rules[i]
             local before=rule.before  if before then recover(before) end
             local after=rule.after  if after  then recover(after)  end
             local current=rule.current if current then recover(current) end
             local replacements=rule.replacements
             if replacements then
               if not done[replacements] then
                 local r={}
                 for k,v in next,replacements do
                   r[indices[k]]=indices[v]
                 end
                 rule.replacements=r
                 done[replacements]=r
               end
             end
           end
         end
       end
     end
   end
 end
 unifythem(resources.sequences)
 unifythem(resources.sublookups)
end
local function copyduplicates(fontdata)
 if check_duplicates then
   local descriptions=fontdata.descriptions
   local resources=fontdata.resources
   local duplicates=resources.duplicates
   if check_soft_hyphen then
     local ds=descriptions[0xAD]
     if not ds or ds.width==0 then
       if ds then
         descriptions[0xAD]=nil
         report("patching soft hyphen")
       else
         report("adding soft hyphen")
       end
       if not duplicates then
         duplicates={}
         resources.duplicates=duplicates
       end
       local dh=duplicates[0x2D]
       if dh then
         dh[#dh+1]={ [0xAD]=true }
       else
         duplicates[0x2D]={ [0xAD]=true }
       end
     end
   end
   if duplicates then
     for u,d in next,duplicates do
       local du=descriptions[u]
       if du then
         local t={ f_character_y(u),"@",f_index(du.index),"->" }
         local n=0
         local m=25
         for u in next,d do
           if descriptions[u] then
             if n<m then
               t[n+4]=f_character_n(u)
             end
           else
             local c=copy(du)
             c.unicode=u
             descriptions[u]=c
             if n<m then
               t[n+4]=f_character_y(u)
             end
           end
           n=n+1
         end
         if n<=m then
           report("duplicates: %i : % t",n,t)
         else
           report("duplicates: %i : % t ...",n,t)
         end
       else
       end
     end
   end
 end
end
local ignore={
 ["notdef"]=true,
 [".notdef"]=true,
 ["null"]=true,
 [".null"]=true,
 ["nonmarkingreturn"]=true,
}
local function checklookups(fontdata,missing,nofmissing)
 local descriptions=fontdata.descriptions
 local resources=fontdata.resources
 if missing and nofmissing and nofmissing<=0 then
   return
 end
 local singles={}
 local alternates={}
 local ligatures={}
 if not missing then
   missing={}
   nofmissing=0
   for u,d in next,descriptions do
     if not d.unicode then
       nofmissing=nofmissing+1
       missing[u]=true
     end
   end
 end
 local function collectthem(sequences)
   if not sequences then
     return
   end
   for i=1,#sequences do
     local sequence=sequences[i]
     local kind=sequence.type
     local steps=sequence.steps
     if steps then
       for i=1,#steps do
         local step=steps[i]
         if kind=="gsub_single" then
           local c=step.coverage
           if c then
             singles[#singles+1]=c
           end
         elseif kind=="gsub_alternate" then
           local c=step.coverage
           if c then
             alternates[#alternates+1]=c
           end
         elseif kind=="gsub_ligature" then
           local c=step.coverage
           if c then
             ligatures[#ligatures+1]=c
           end
         end
       end
     end
   end
 end
 collectthem(resources.sequences)
 collectthem(resources.sublookups)
 local loops=0
 while true do
   loops=loops+1
   local old=nofmissing
   for i=1,#singles do
     local c=singles[i]
     for g1,g2 in next,c do
       if missing[g1] then
         local u2=descriptions[g2].unicode
         if u2 then
           missing[g1]=false
           descriptions[g1].unicode=u2
           nofmissing=nofmissing-1
         end
       end
       if missing[g2] then
         local u1=descriptions[g1].unicode
         if u1 then
           missing[g2]=false
           descriptions[g2].unicode=u1
           nofmissing=nofmissing-1
         end
       end
     end
   end
   for i=1,#alternates do
     local c=alternates[i]
     for g1,d1 in next,c do
       if missing[g1] then
         for i=1,#d1 do
           local g2=d1[i]
           local u2=descriptions[g2].unicode
           if u2 then
             missing[g1]=false
             descriptions[g1].unicode=u2
             nofmissing=nofmissing-1
           end
         end
       end
       if not missing[g1] then
         for i=1,#d1 do
           local g2=d1[i]
           if missing[g2] then
             local u1=descriptions[g1].unicode
             if u1 then
               missing[g2]=false
               descriptions[g2].unicode=u1
               nofmissing=nofmissing-1
             end
           end
         end
       end
     end
   end
   if nofmissing<=0 then
     report("all done in %s loops",loops)
     return
   elseif old==nofmissing then
     break
   end
 end
 local t,n
 local function recursed(c)
   for g,d in next,c do
     if g~="ligature" then
       local u=descriptions[g].unicode
       if u then
         n=n+1
         t[n]=u
         recursed(d)
         n=n-1
       end
     elseif missing[d] then
       local l={}
       local m=0
       for i=1,n do
         local u=t[i]
         if type(u)=="table" then
           for i=1,#u do
             m=m+1
             l[m]=u[i]
           end
         else
           m=m+1
           l[m]=u
         end
       end
       missing[d]=false
       descriptions[d].unicode=l
       nofmissing=nofmissing-1
     end
   end
 end
 if nofmissing>0 then
   t={}
   n=0
   local loops=0
   while true do
     loops=loops+1
     local old=nofmissing
     for i=1,#ligatures do
       recursed(ligatures[i])
     end
     if nofmissing<=0 then
       report("all done in %s loops",loops)
       return
     elseif old==nofmissing then
       break
     end
   end
   t=nil
   n=0
 end
 if nofmissing>0 then
   local done={}
   for i,r in next,missing do
     if r then
       local data=descriptions[i]
       local name=data and data.name or f_index(i)
       if not ignore[name] then
         done[name]=true
       end
     end
   end
   if next(done) then
     report("not unicoded: % t",table.sortedkeys(done))
   end
 end
end
local function unifymissing(fontdata)
 if not fonts.mappings then
   require("font-map")
   require("font-agl")
 end
 local unicodes={}
 local private=fontdata.private
 local resources=fontdata.resources
 resources.unicodes=unicodes
 for unicode,d in next,fontdata.descriptions do
   if unicode<privateoffset then
     local name=d.name
     if name then
       unicodes[name]=unicode
     end
   end
 end
 fonts.mappings.addtounicode(fontdata,fontdata.filename,checklookups)
 resources.unicodes=nil
end
local function unifyglyphs(fontdata,usenames)
 local private=fontdata.private or privateoffset
 local glyphs=fontdata.glyphs
 local indices={}
 local descriptions={}
 local names=usenames and {}
 local resources=fontdata.resources
 local zero=glyphs[0]
 local zerocode=zero.unicode
 if not zerocode then
   zerocode=private
   zero.unicode=zerocode
   private=private+1
 end
 descriptions[zerocode]=zero
 if names then
   local name=glyphs[0].name or f_private(zerocode)
   indices[0]=name
   names[name]=zerocode
 else
   indices[0]=zerocode
 end
 for index=1,#glyphs do
   local glyph=glyphs[index]
   local unicode=glyph.unicode
   if not unicode then
     unicode=private
     if names then
       local name=glyph.name or f_private(unicode)
       indices[index]=name
       names[name]=unicode
     else
       indices[index]=unicode
     end
     private=private+1
   elseif descriptions[unicode] then
     report("assigning private unicode %U to glyph indexed %05X (%C)",private,index,unicode)
     unicode=private
     if names then
       local name=glyph.name or f_private(unicode)
       indices[index]=name
       names[name]=unicode
     else
       indices[index]=unicode
     end
     private=private+1
   else
     if names then
       local name=glyph.name or f_unicode(unicode)
       indices[index]=name
       names[name]=unicode
     else
       indices[index]=unicode
     end
   end
   descriptions[unicode]=glyph
 end
 for index=1,#glyphs do
   local math=glyphs[index].math
   if math then
     local list=math.vparts
     if list then
       for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end
     end
     local list=math.hparts
     if list then
       for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end
     end
     local list=math.vvariants
     if list then
       for i=1,#list do list[i]=indices[list[i]] end
     end
     local list=math.hvariants
     if list then
       for i=1,#list do list[i]=indices[list[i]] end
     end
   end
 end
 local colorpalettes=resources.colorpalettes
 if colorpalettes then
   for index=1,#glyphs do
     local colors=glyphs[index].colors
     if colors then
       for i=1,#colors do
         local c=colors[i]
         c.slot=indices[c.slot]
       end
     end
   end
 end
 fontdata.private=private
 fontdata.glyphs=nil
 fontdata.names=names
 fontdata.descriptions=descriptions
 fontdata.hashmethod=hashmethod
 return indices,names
end
local p_bogusname=(
 (P("uni")+P("UNI")+P("Uni")+P("U")+P("u"))*S("Xx")^0*R("09","AF")^1+(P("identity")+P("Identity")+P("IDENTITY"))*R("09","AF")^1+(P("index")+P("Index")+P("INDEX"))*R("09")^1
)*P(-1)
local function stripredundant(fontdata)
 local descriptions=fontdata.descriptions
 if descriptions then
   local n=0
   local c=0
   for unicode,d in next,descriptions do
     local name=d.name
     if name and lpegmatch(p_bogusname,name) then
       d.name=nil
       n=n+1
     end
     if d.class=="base" then
       d.class=nil
       c=c+1
     end
   end
   if n>0 then
     report("%s bogus names removed (verbose unicode)",n)
   end
   if c>0 then
     report("%s base class tags removed (default is base)",c)
   end
 end
end
function readers.getcomponents(fontdata)
 local resources=fontdata.resources
 if resources then
   local sequences=resources.sequences
   if sequences then
     local collected={}
     for i=1,#sequences do
       local sequence=sequences[i]
       if sequence.type=="gsub_ligature" then
         local steps=sequence.steps
         if steps then
           local l={}
           local function traverse(p,k,v)
             if k=="ligature" then
               collected[v]={ unpack(l) }
             else
               insert(l,k)
               for k,vv in next,v do
                 traverse(p,k,vv)
               end
               remove(l)
             end
           end
           for i=1,#steps do
             local coverage=steps[i].coverage
             if coverage then
               for k,v in next,coverage do
                 traverse(k,k,v)
               end
             end
           end
         end
       end
     end
     if next(collected) then
       while true do
         local done=false
         for k,v in next,collected do
           for i=1,#v do
             local vi=v[i]
             if vi==k then
               collected[k]=nil
               break
             else
               local c=collected[vi]
               if c then
                 done=true
                 local t={}
                 local n=i-1
                 for j=1,n do
                   t[j]=v[j]
                 end
                 for j=1,#c do
                   n=n+1
                   t[n]=c[j]
                 end
                 for j=i+1,#v do
                   n=n+1
                   t[n]=v[j]
                 end
                 collected[k]=t
                 break
               end
             end
           end
         end
         if not done then
           break
         end
       end
       return collected
     end
   end
 end
end
readers.unifymissing=unifymissing
function readers.rehash(fontdata,hashmethod)
 if not (fontdata and fontdata.glyphs) then
   return
 end
 if hashmethod=="indices" then
   fontdata.hashmethod="indices"
 elseif hashmethod=="names" then
   fontdata.hashmethod="names"
   local indices=unifyglyphs(fontdata,true)
   unifyresources(fontdata,indices)
   copyduplicates(fontdata)
   unifymissing(fontdata)
 else
   fontdata.hashmethod="unicode"
   local indices=unifyglyphs(fontdata)
   unifyresources(fontdata,indices)
   copyduplicates(fontdata)
   unifymissing(fontdata)
   stripredundant(fontdata)
 end
end
function readers.checkhash(fontdata)
 local hashmethod=fontdata.hashmethod
 if hashmethod=="unicodes" then
   fontdata.names=nil
 elseif hashmethod=="names" and fontdata.names then
   unifyresources(fontdata,fontdata.names)
   copyduplicates(fontdata)
   fontdata.hashmethod="unicode"
   fontdata.names=nil
 else
   readers.rehash(fontdata,"unicode")
 end
end
function readers.addunicodetable(fontdata)
 local resources=fontdata.resources
 local unicodes=resources.unicodes
 if not unicodes then
   local descriptions=fontdata.descriptions
   if descriptions then
     unicodes={}
     resources.unicodes=unicodes
     for u,d in next,descriptions do
       local n=d.name
       if n then
         unicodes[n]=u
       end
     end
   end
 end
end
local concat,sort=table.concat,table.sort
local next,type,tostring=next,type,tostring
local criterium=1
local threshold=0
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")
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
function readers.pack(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 sequences=resources.sequences
   local sublookups=resources.sublookups
   local features=resources.features
   local palettes=resources.colorpalettes
   local chardata=characters and characters.data
   local descriptions=data.descriptions or data.glyphs
   if not descriptions then
     return
   end
   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,descriptions do
       local boundingbox=description.boundingbox
       if boundingbox then
         description.boundingbox=pack_indexed(boundingbox)
       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
     end
     local function packthem(sequences)
       for i=1,#sequences do
         local sequence=sequences[i]
         local kind=sequence.type
         local steps=sequence.steps
         local order=sequence.order
         local features=sequence.features
         local flags=sequence.flags
         if steps then
           for i=1,#steps do
             local step=steps[i]
             if kind=="gpos_pair" then
               local c=step.coverage
               if c then
                 if step.format=="kern" then
                   for g1,d1 in next,c do
                     c[g1]=pack_normal(d1)
                   end
                 else
                   for g1,d1 in next,c do
                     for g2,d2 in next,d1 do
                       local f=d2[1] if f then d2[1]=pack_indexed(f) end
                       local s=d2[2] if s then d2[2]=pack_indexed(s) end
                     end
                   end
                 end
               end
             elseif kind=="gpos_single" then
               local c=step.coverage
               if c then
                 if step.format=="kern" then
                   step.coverage=pack_normal(c)
                 else
                   for g1,d1 in next,c do
                     c[g1]=pack_indexed(d1)
                   end
                 end
               end
             elseif kind=="gpos_cursive" then
               local c=step.coverage
               if c then
                 for g1,d1 in next,c do
                   local f=d1[2] if f then d1[2]=pack_indexed(f) end
                   local s=d1[3] if s then d1[3]=pack_indexed(s) end
                 end
               end
             elseif kind=="gpos_mark2base" or kind=="gpos_mark2mark" then
               local c=step.baseclasses
               if c then
                 for g1,d1 in next,c do
                   for g2,d2 in next,d1 do
                     d1[g2]=pack_indexed(d2)
                   end
                 end
               end
               local c=step.coverage
               if c then
                 for g1,d1 in next,c do
                   d1[2]=pack_indexed(d1[2])
                 end
               end
             elseif kind=="gpos_mark2ligature" then
               local c=step.baseclasses
               if c then
                 for g1,d1 in next,c do
                   for g2,d2 in next,d1 do
                     for g3,d3 in next,d2 do
                       d2[g3]=pack_indexed(d3)
                     end
                   end
                 end
               end
               local c=step.coverage
               if c then
                 for g1,d1 in next,c do
                   d1[2]=pack_indexed(d1[2])
                 end
               end
             end
             local rules=step.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.lookups   if r then rule.lookups=pack_mixed (r)  end
                 local r=rule.replacements if r then rule.replacements=pack_flat  (r)  end
               end
             end
           end
         end
         if order then
           sequence.order=pack_indexed(order)
         end
         if features then
           for script,feature in next,features do
             features[script]=pack_normal(feature)
           end
         end
         if flags then
           sequence.flags=pack_normal(flags)
         end
       end
     end
     if sequences then
       packthem(sequences)
     end
     if sublookups then
       packthem(sublookups)
     end
     if features then
       for k,list in next,features do
         for feature,spec in next,list do
           list[feature]=pack_normal(spec)
         end
       end
     end
     if palettes then
       for i=1,#palettes do
         local p=palettes[i]
         for j=1,#p do
           p[j]=pack_indexed(p[j])
         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,descriptions do
         local math=description.math
         if math then
           local kerns=math.kerns
           if kerns then
             math.kerns=pack_normal(kerns)
           end
         end
       end
       local function packthem(sequences)
         for i=1,#sequences do
           local sequence=sequences[i]
           local kind=sequence.type
           local steps=sequence.steps
           local features=sequence.features
           if steps then
             for i=1,#steps do
               local step=steps[i]
               if kind=="gpos_pair" then
                 local c=step.coverage
                 if c then
                   if step.format=="kern" then
                   else
                     for g1,d1 in next,c do
                       for g2,d2 in next,d1 do
                         d1[g2]=pack_normal(d2)
                       end
                     end
                   end
                 end
               end
               local rules=step.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
           if features then
             sequence.features=pack_normal(features)
           end
         end
       end
       if sequences then
         packthem(sequences)
       end
       if sublookups then
         packthem(sublookups)
       end
       if not success(2,pass) then
       end
     end
     for pass=1,2 do
       if trace_packing then
         report_otf("start packing: stage 3, pass %s",pass)
       end
       local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed=packers(pass)
       local function packthem(sequences)
         for i=1,#sequences do
           local sequence=sequences[i]
           local kind=sequence.type
           local steps=sequence.steps
           local features=sequence.features
           if steps then
             for i=1,#steps do
               local step=steps[i]
               if kind=="gpos_pair" then
                 local c=step.coverage
                 if c then
                   if step.format=="kern" then
                   else
                     for g1,d1 in next,c do
                       c[g1]=pack_normal(d1)
                     end
                   end
                 end
               end
             end
           end
         end
       end
       if sequences then
         packthem(sequences)
       end
       if sublookups then
         packthem(sublookups)
       end
     end
   end
 end
end
local unpacked_mt={
 __index=function(t,k)
     t[k]=false
     return k
   end
}
function readers.unpack(data)
 if data then
   local tables=data.tables
   if tables then
     local resources=data.resources
     local descriptions=data.descriptions or data.glyphs
     local sequences=resources.sequences
     local sublookups=resources.sublookups
     local features=resources.features
     local palettes=resources.colorpalettes
     local unpacked={}
     setmetatable(unpacked,unpacked_mt)
     for unicode,description in next,descriptions do
       local tv=tables[description.boundingbox]
       if tv then
         description.boundingbox=tv
       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
     end
     local function unpackthem(sequences)
       for i=1,#sequences do
         local sequence=sequences[i]
         local kind=sequence.type
         local steps=sequence.steps
         local order=sequence.order
         local features=sequence.features
         local flags=sequence.flags
         local markclass=sequence.markclass
         if steps then
           for i=1,#steps do
             local step=steps[i]
             if kind=="gpos_pair" then
               local c=step.coverage
               if c then
                 if step.format=="kern" then
                   for g1,d1 in next,c do
                     local tv=tables[d1]
                     if tv then
                       c[g1]=tv
                     end
                   end
                 else
                   for g1,d1 in next,c do
                     local tv=tables[d1]
                     if tv then
                       c[g1]=tv
                       d1=tv
                     end
                     for g2,d2 in next,d1 do
                       local tv=tables[d2]
                       if tv then
                         d1[g2]=tv
                         d2=tv
                       end
                       local f=tables[d2[1]] if f then d2[1]=f end
                       local s=tables[d2[2]] if s then d2[2]=s end
                     end
                   end
                 end
               end
             elseif kind=="gpos_single" then
               local c=step.coverage
               if c then
                 if step.format=="kern" then
                   local tv=tables[c]
                   if tv then
                     step.coverage=tv
                   end
                 else
                   for g1,d1 in next,c do
                     local tv=tables[d1]
                     if tv then
                       c[g1]=tv
                     end
                   end
                 end
               end
             elseif kind=="gpos_cursive" then
               local c=step.coverage
               if c then
                 for g1,d1 in next,c do
                   local f=tables[d1[2]] if f then d1[2]=f end
                   local s=tables[d1[3]] if s then d1[3]=s end
                 end
               end
             elseif kind=="gpos_mark2base" or kind=="gpos_mark2mark" then
               local c=step.baseclasses
               if c then
                 for g1,d1 in next,c do
                   for g2,d2 in next,d1 do
                     local tv=tables[d2]
                     if tv then
                       d1[g2]=tv
                     end
                   end
                 end
               end
               local c=step.coverage
               if c then
                 for g1,d1 in next,c do
                   local tv=tables[d1[2]]
                   if tv then
                     d1[2]=tv
                   end
                 end
               end
             elseif kind=="gpos_mark2ligature" then
               local c=step.baseclasses
               if c then
                 for g1,d1 in next,c do
                   for g2,d2 in next,d1 do
                     for g3,d3 in next,d2 do
                       local tv=tables[d2[g3]]
                       if tv then
                         d2[g3]=tv
                       end
                     end
                   end
                 end
               end
               local c=step.coverage
               if c then
                 for g1,d1 in next,c do
                   local tv=tables[d1[2]]
                   if tv then
                     d1[2]=tv
                   end
                 end
               end
             end
             local rules=step.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=tv
                   end
                   for i=1,#before do
                     local tv=tables[before[i]]
                     if tv then
                       before[i]=tv
                     end
                   end
                 end
                 local after=rule.after
                 if after then
                   local tv=tables[after]
                   if tv then
                     rule.after=tv
                     after=tv
                   end
                   for i=1,#after do
                     local tv=tables[after[i]]
                     if tv then
                       after[i]=tv
                     end
                   end
                 end
                 local current=rule.current
                 if current then
                   local tv=tables[current]
                   if tv then
                     rule.current=tv
                     current=tv
                   end
                   for i=1,#current do
                     local tv=tables[current[i]]
                     if tv then
                       current[i]=tv
                     end
                   end
                 end
                 local lookups=rule.lookups
                 if lookups then
                   local tv=tables[lookups]
                   if tv then
                     rule.lookups=tv
                   end
                 end
                 local replacements=rule.replacements
                 if replacements then
                   local tv=tables[replacements]
                   if tv then
                     rule.replacements=tv
                   end
                 end
               end
             end
           end
         end
         if features then
           local tv=tables[features]
           if tv then
             sequence.features=tv
             features=tv
           end
           for script,feature in next,features do
             local tv=tables[feature]
             if tv then
               features[script]=tv
             end
           end
         end
         if order then
           local tv=tables[order]
           if tv then
             sequence.order=tv
           end
         end
         if flags then
           local tv=tables[flags]
           if tv then
             sequence.flags=tv
           end
         end
       end
     end
     if sequences then
       unpackthem(sequences)
     end
     if sublookups then
       unpackthem(sublookups)
     end
     if features then
       for k,list in next,features do
         for feature,spec in next,list do
           local tv=tables[spec]
           if tv then
             list[feature]=tv
           end
         end
       end
     end
     if palettes then
       for i=1,#palettes do
         local p=palettes[i]
         for j=1,#p do
           local tv=tables[p[j]]
           if tv then
             p[j]=tv
           end
         end
       end
     end
     data.tables=nil
   end
 end
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
}
local function sameformat(sequence,steps,first,nofsteps,kind)
 return true
end
local function mergesteps_1(lookup,strict)
 local steps=lookup.steps
 local nofsteps=lookup.nofsteps
 local first=steps[1]
 if strict then
   local f=first.format
   for i=2,nofsteps do
     if steps[i].format~=f then
       report("not merging %a steps of %a lookup %a, different formats",nofsteps,lookup.type,lookup.name)
       return 0
     end
   end
 end
 report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
 local target=first.coverage
 for i=2,nofsteps do
   for k,v in next,steps[i].coverage do
     if not target[k] then
       target[k]=v
     end
   end
 end
 lookup.nofsteps=1
 lookup.merged=true
 lookup.steps={ first }
 return nofsteps-1
end
local function mergesteps_2(lookup,strict)
 local steps=lookup.steps
 local nofsteps=lookup.nofsteps
 local first=steps[1]
 if strict then
   local f=first.format
   for i=2,nofsteps do
     if steps[i].format~=f then
       report("not merging %a steps of %a lookup %a, different formats",nofsteps,lookup.type,lookup.name)
       return 0
     end
   end
 end
 report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
 local target=first.coverage
 for i=2,nofsteps do
   for k,v in next,steps[i].coverage do
     local tk=target[k]
     if tk then
       for k,v in next,v do
         if not tk[k] then
           tk[k]=v
         end
       end
     else
       target[k]=v
     end
   end
 end
 lookup.nofsteps=1
 lookup.steps={ first }
 return nofsteps-1
end
local function mergesteps_3(lookup,strict)
 local steps=lookup.steps
 local nofsteps=lookup.nofsteps
 local first=steps[1]
 report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
 local baseclasses={}
 local coverage={}
 local used={}
 for i=1,nofsteps do
   local offset=i*10
   local step=steps[i]
   for k,v in sortedhash(step.baseclasses) do
     baseclasses[offset+k]=v
   end
   for k,v in next,step.coverage do
     local tk=coverage[k]
     if tk then
       for k,v in next,v do
         if not tk[k] then
           tk[k]=v
           local c=offset+v[1]
           v[1]=c
           if not used[c] then
             used[c]=true
           end
         end
       end
     else
       coverage[k]=v
       local c=offset+v[1]
       v[1]=c
       if not used[c] then
         used[c]=true
       end
     end
   end
 end
 for k,v in next,baseclasses do
   if not used[k] then
     baseclasses[k]=nil
     report("discarding not used baseclass %i",k)
   end
 end
 first.baseclasses=baseclasses
 first.coverage=coverage
 lookup.nofsteps=1
 lookup.steps={ first }
 return nofsteps-1
end
local function nested(old,new)
 for k,v in next,old do
   if k=="ligature" then
     if not new.ligature then
       new.ligature=v
     end
   else
     local n=new[k]
     if n then
       nested(v,n)
     else
       new[k]=v
     end
   end
 end
end
local function mergesteps_4(lookup)
 local steps=lookup.steps
 local nofsteps=lookup.nofsteps
 local first=steps[1]
 report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
 local target=first.coverage
 for i=2,nofsteps do
   for k,v in next,steps[i].coverage do
     local tk=target[k]
     if tk then
       nested(v,tk)
     else
       target[k]=v
     end
   end
 end
 lookup.nofsteps=1
 lookup.steps={ first }
 return nofsteps-1
end
local function checkkerns(lookup)
 local steps=lookup.steps
 local nofsteps=lookup.nofsteps
 for i=1,nofsteps do
   local step=steps[i]
   if step.format=="pair" then
     local coverage=step.coverage
     local kerns=true
     for g1,d1 in next,coverage do
       if d1[1]~=0 or d1[2]~=0 or d1[4]~=0 then
         kerns=false
         break
       end
     end
     if kerns then
       report("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name)
       for g1,d1 in next,coverage do
         coverage[g1]=d1[3]
       end
       step.format="kern"
     end
   end
 end
end
local function checkpairs(lookup)
 local steps=lookup.steps
 local nofsteps=lookup.nofsteps
 local kerned=0
 for i=1,nofsteps do
   local step=steps[i]
   if step.format=="pair" then
     local coverage=step.coverage
     local kerns=true
     for g1,d1 in next,coverage do
       for g2,d2 in next,d1 do
         if d2[2] then
           kerns=false
           break
         else
           local v=d2[1]
           if v[1]~=0 or v[2]~=0 or v[4]~=0 then
             kerns=false
             break
           end
         end
       end
     end
     if kerns then
       report("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name)
       for g1,d1 in next,coverage do
         for g2,d2 in next,d1 do
           d1[g2]=d2[1][3]
         end
       end
       step.format="kern"
       kerned=kerned+1
     end
   end
 end
 return kerned
end
function readers.compact(data)
 if not data or data.compacted then
   return
 else
   data.compacted=true
 end
 local resources=data.resources
 local merged=0
 local kerned=0
 local allsteps=0
 local function compact(what)
   local lookups=resources[what]
   if lookups then
     for i=1,#lookups do
       local lookup=lookups[i]
       local nofsteps=lookup.nofsteps
       allsteps=allsteps+nofsteps
       if nofsteps>1 then
         local kind=lookup.type
         if kind=="gsub_single" or kind=="gsub_alternate" or kind=="gsub_multiple" then
           merged=merged+mergesteps_1(lookup)
         elseif kind=="gsub_ligature" then
           merged=merged+mergesteps_4(lookup)
         elseif kind=="gpos_single" then
           merged=merged+mergesteps_1(lookup,true)
           checkkerns(lookup)
         elseif kind=="gpos_pair" then
           merged=merged+mergesteps_2(lookup,true)
           kerned=kerned+checkpairs(lookup)
         elseif kind=="gpos_cursive" then
           merged=merged+mergesteps_2(lookup)
         elseif kind=="gpos_mark2mark" or kind=="gpos_mark2base" or kind=="gpos_mark2ligature" then
           merged=merged+mergesteps_3(lookup)
         end
       end
     end
   else
     report("no lookups in %a",what)
   end
 end
 compact("sequences")
 compact("sublookups")
 if merged>0 then
   report("%i steps of %i removed due to merging",merged,allsteps)
 end
 if kerned>0 then
   report("%i steps of %i steps turned from pairs into kerns",kerned,allsteps)
 end
end
function readers.expand(data)
 if not data or data.expanded then
   return
 else
   data.expanded=true
 end
 local resources=data.resources
 local sublookups=resources.sublookups
 local sequences=resources.sequences
 local markclasses=resources.markclasses
 local descriptions=data.descriptions
 if descriptions then
   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(resources.filename)
   for u,d in next,descriptions do
     local bb=d.boundingbox
     local wd=d.width
     if not wd then
       d.width=defaultwidth
     elseif trace_markwidth and wd~=0 and d.class=="mark" then
       report("mark %a with width %b found in %a",d.name or "<noname>",wd,basename)
     end
     if bb then
       local ht=bb[4]
       local dp=-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
 local function expandlookups(sequences)
   if sequences then
     for i=1,#sequences do
       local sequence=sequences[i]
       local steps=sequence.steps
       if steps then
         local kind=sequence.type
         local markclass=sequence.markclass
         if markclass then
           if not markclasses then
             report_warning("missing markclasses")
             sequence.markclass=false
           else
             sequence.markclass=markclasses[markclass]
           end
         end
         for i=1,sequence.nofsteps do
           local step=steps[i]
           local baseclasses=step.baseclasses
           if baseclasses then
             local coverage=step.coverage
             for k,v in next,coverage do
               v[1]=baseclasses[v[1]]
             end
           elseif kind=="gpos_cursive" then
             local coverage=step.coverage
             for k,v in next,coverage do
               v[1]=coverage
             end
           end
           local rules=step.rules
           if rules then
             local rulehash={}
             local rulesize=0
             local coverage={}
             local lookuptype=sequence.type
             step.coverage=coverage
             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 or false
               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
               local lookups=rule.lookups or false
               local subtype=nil
               if lookups then
                 for k,v in next,lookups do
                   local lookup=sublookups[v]
                   if lookup then
                     lookups[k]=lookup
                     if not subtype then
                       subtype=lookup.type
                     end
                   else
                   end
                 end
               end
               if sequence[1] then
                 rulesize=rulesize+1
                 rulehash[rulesize]={
                   nofrules,
                   lookuptype,
                   sequence,
                   start,
                   stop,
                   lookups,
                   replacements,
                   subtype,
                 }
                 for unic in next,sequence[start] do
                   local cu=coverage[unic]
                   if not cu then
                     coverage[unic]=rulehash
                   end
                 end
               end
             end
           end
         end
       end
     end
   end
 end
 expandlookups(sequences)
 expandlookups(sublookups)
end

end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-oup”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-otl” 2e7c8d9a331c46826211bd507f8e488a] ---

if not modules then modules={} end modules ['font-otl']={
 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 gmatch,find,match,lower,strip=string.gmatch,string.find,string.match,string.lower,string.strip
local type,next,tonumber,tostring,unpack=type,next,tonumber,tostring,unpack
local abs=math.abs
local derivetable=table.derive
local formatters=string.formatters
local setmetatableindex=table.setmetatableindex
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_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_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.version=3.027
otf.cache=containers.define("fonts","otl",otf.version,true)
otf.svgcache=containers.define("fonts","svg",otf.version,true)
otf.pdfcache=containers.define("fonts","pdf",otf.version,true)
otf.svgenabled=false
local otfreaders=otf.readers
local hashes=fonts.hashes
local definers=fonts.definers
local readers=fonts.readers
local constructors=fonts.constructors
local otffeatures=constructors.features.otf
local registerotffeature=otffeatures.register
local otfenhancers=constructors.enhancers.otf
local registerotfenhancer=otfenhancers.register
local forceload=false
local cleanup=0
local syncspace=true
local forcenotdef=false
local applyruntimefixes=fonts.treatments and fonts.treatments.applyfixes
local wildcard="*"
local default="dflt"
local formats=fonts.formats
formats.otf="opentype"
formats.ttf="truetype"
formats.ttc="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.syncspace",function(v) syncspace=v end)
registerdirective("fonts.otf.loader.forcenotdef",function(v) forcenotdef=v end)
registerotfenhancer("check extra features",function() end)
function otf.load(filename,sub,featurefile)
 local featurefile=nil
 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 or data.tableversion~=otfreaders.tableversion
 if forceload then
   report_otf("forced reload of %a due to hard coded flag",filename)
   reload=true
 end
  if reload then
   report_otf("loading %a, hash %a",filename,hash)
   starttiming(otfreaders)
   data=otfreaders.loadfont(filename,sub or 1)
   if data then
     local resources=data.resources
     local svgshapes=resources.svgshapes
     if svgshapes then
       resources.svgshapes=nil
       if otf.svgenabled then
         local timestamp=os.date()
         containers.write(otf.svgcache,hash,{
           svgshapes=svgshapes,
           timestamp=timestamp,
         })
         data.properties.svg={
           hash=hash,
           timestamp=timestamp,
         }
       end
     end
     otfreaders.compact(data)
     otfreaders.rehash(data,"unicodes")
     otfreaders.addunicodetable(data)
     otfreaders.extend(data)
     otfreaders.pack(data)
     report_otf("loading done")
     report_otf("saving %a in cache",filename)
     data=containers.write(otf.cache,hash,data)
     if cleanup>1 then
       collectgarbage("collect")
     end
     stoptiming(otfreaders)
     if elapsedtime then
       report_otf("loading, optimizing, packing and caching time %s",elapsedtime(otfreaders))
     end
     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
   otfreaders.unpack(data)
   otfreaders.expand(data)
   otfreaders.addunicodetable(data)
   otfenhancers.apply(data,filename,data)
   if applyruntimefixes then
     applyruntimefixes(filename,data)
   end
   data.metadata.math=data.resources.mathconstants
 end
 return data
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 properties=derivetable(data.properties)
   local descriptions=derivetable(data.descriptions)
   local goodies=derivetable(data.goodies)
   local characters={}
   local parameters={}
   local mathparameters={}
   local resources=data.resources
   local unicodes=resources.unicodes
   local spaceunits=500
   local spacer="space"
   local designsize=metadata.designsize or 100
   local minsize=metadata.minsize or designsize
   local maxsize=metadata.maxsize or designsize
   local mathspecs=metadata.math
   if designsize==0 then
     designsize=100
     minsize=100
     maxsize=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 italic=m.italic
         local vitalic=m.vitalic
         local variants=m.hvariants
         local parts=m.hparts
         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
           italic=m.hitalic
         end
         local variants=m.vvariants
         local parts=m.vparts
         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
         if italic and italic~=0 then
           character.italic=italic
         end
         if vitalic and vitalic~=0 then
           character.vert_italic=vitalic
         end
         local accent=m.accent
         if accent then
           character.accent=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 psname=fontname or fullname
   local units=metadata.units or 1000
   if units==0 then
     units=1000
     metadata.units=1000
     report_otf("changing %a units to %a",0,units)
   end
   local monospaced=metadata.monospaced
   local charwidth=metadata.averagewidth
   local charxheight=metadata.xheight
   local italicangle=metadata.italicangle
   local hasitalics=metadata.hasitalics
   properties.monospaced=monospaced
   properties.hasitalics=hasitalics
   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 units/2
   parameters.slant=0
   parameters.space=spaceunits
   parameters.space_stretch=1*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=0x0078
     if x then
       local x=descriptions[x]
       if x then
         parameters.x_height=x.height
       end
     end
   end
   parameters.designsize=(designsize/10)*65536
   parameters.minsize=(minsize/10)*65536
   parameters.maxsize=(maxsize/10)*65536
   parameters.ascender=abs(metadata.ascender or 0)
   parameters.descender=abs(metadata.descender or 0)
   parameters.units=units
   properties.space=spacer
   properties.encodingbytes=2
   properties.format=data.format or formats.otf
   properties.noglyphnames=true
   properties.filename=filename
   properties.fontname=fontname
   properties.fullname=fullname
   properties.psname=psname
   properties.name=filename or fullname
   return {
     characters=characters,
     descriptions=descriptions,
     parameters=parameters,
     mathparameters=mathparameters,
     resources=resources,
     properties=properties,
     goodies=goodies,
   }
 end
end
local converters={
 woff={
   cachename="webfonts",
   action=otf.readers.woff2otf,
 }
}
local function checkconversion(specification)
 local filename=specification.filename
 local converter=converters[lower(file.suffix(filename))]
 if converter then
   local base=file.basename(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 size>0 then
     local cleanname=containers.cleanname(name)
     local cachename=caches.setfirstwritablefile(cleanname,converter.cachename)
     if not io.exists(cachename) or (time~=lfs.attributes(cachename).modification) then
       report_otf("caching font %a in %a",filename,cachename)
       converter.action(filename,cachename)
       lfs.touch(cachename,time,time)
     end
     specification.filename=cachename
   end
 end
end
local function otftotfm(specification)
 local cache_id=specification.hash
 local tfmdata=containers.read(constructors.cache,cache_id)
 if not tfmdata then
   checkconversion(specification)
   local name=specification.name
   local sub=specification.sub
   local subindex=specification.subindex
   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
     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)
 if not kind then
   return
 end
 if not script then
   script=default
 end
 if not language then
   language=default
 end
 local lookupcache=rawdata.lookupcache
 if not lookupcache then
   lookupcache={}
   rawdata.lookupcache=lookupcache
 end
 local kindlookup=lookupcache[kind]
 if not kindlookup then
   kindlookup={}
   lookupcache[kind]=kindlookup
 end
 local scriptlookup=kindlookup[script]
 if not scriptlookup then
   scriptlookup={}
   kindlookup[script]=scriptlookup
 end
 local languagelookup=scriptlookup[language]
 if not languagelookup then
   local sequences=rawdata.resources.sequences
   local featuremap={}
   local featurelist={}
   if sequences then
     for s=1,#sequences do
       local sequence=sequences[s]
       local features=sequence.features
       if features then
         features=features[kind]
         if features then
           features=features[script] or features[wildcard]
           if features then
             features=features[language] or features[wildcard]
             if features then
               if not featuremap[sequence] then
                 featuremap[sequence]=true
                 featurelist[#featurelist+1]=sequence
               end
             end
           end
         end
       end
     end
     if #featurelist==0 then
       featuremap,featurelist=false,false
     end
   else
     featuremap,featurelist=false,false
   end
   languagelookup={ featuremap,featurelist }
   scriptlookup[language]=languagelookup
 end
 return unpack(languagelookup)
end
local function getgsub(tfmdata,k,kind,value)
 local shared=tfmdata.shared
 local rawdata=shared and shared.rawdata
 if rawdata then
   local sequences=rawdata.resources.sequences
   if sequences then
     local properties=tfmdata.properties
     local validlookups,lookuplist=otf.collectlookups(rawdata,kind,properties.script,properties.language)
     if validlookups then
       for i=1,#lookuplist do
         local lookup=lookuplist[i]
         local steps=lookup.steps
         local nofsteps=lookup.nofsteps
         for i=1,nofsteps do
           local coverage=steps[i].coverage
           if coverage then
             local found=coverage[k]
             if found then
               return found,lookup.type
             end
           end
         end
       end
     end
   end
 end
end
otf.getgsub=getgsub
function otf.getsubstitution(tfmdata,k,kind,value)
 local found,kind=getgsub(tfmdata,k,kind,value)
 if not found then
 elseif kind=="gsub_single" then
   return found
 elseif kind=="gsub_alternate" then
   local choice=tonumber(value) or 1
   return found[choice] or found[1] or k
 end
 return k
end
otf.getalternate=otf.getsubstitution
function otf.getmultiple(tfmdata,k,kind)
 local found,kind=getgsub(tfmdata,k,kind)
 if found and kind=="gsub_multiple" then
   return found
 end
 return { k }
end
function otf.getkern(tfmdata,left,right,kind)
 local kerns=getgsub(tfmdata,left,kind or "kern",true)
 if kerns then
   local found=kerns[right]
   local kind=type(found)
   if kind=="table" then
     found=found[1][3]
   elseif kind~="number" then
     found=false
   end
   if found then
     return found*tfmdata.parameters.factor
   end
 end
 return 0
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.woff(specification)
 checkconversion(specification)
 opentypereader(specification,"")
end
function otf.scriptandlanguage(tfmdata,attr)
 local properties=tfmdata.properties
 return properties.script or "dflt",properties.language or "dflt"
end
local function justset(coverage,unicode,replacement)
 coverage[unicode]=replacement
end
otf.coverup={
 stepkey="steps",
 actions={
   chainsubstitution=justset,
   chainposition=justset,
   substitution=justset,
   alternate=justset,
   multiple=justset,
   kern=justset,
   pair=justset,
   ligature=function(coverage,unicode,ligature)
     local first=ligature[1]
     local tree=coverage[first]
     if not tree then
       tree={}
       coverage[first]=tree
     end
     for i=2,#ligature do
       local l=ligature[i]
       local t=tree[l]
       if not t then
         t={}
         tree[l]=t
       end
       tree=t
     end
     tree.ligature=unicode
   end,
 },
 register=function(coverage,featuretype,format)
   return {
     format=format,
     coverage=coverage,
   }
 end
}

end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-otl”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-oto” 5fbdd899624d4eef639f81b580afe9aa] ---

if not modules then modules = { } end modules ['font-oto'] = { -- original tex
   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, unpack = table.concat, table.unpack
local insert, remove = table.insert, table.remove
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, rawget = type, next, tonumber, tostring, rawget

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)
----- 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" -- first last

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 -- first is likely a key
               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,sequence)
   return formatters["feature %a, type %a, chain lookup %a"](feature,sequence.type,sequence.name)
end

local function report_substitution(feature,sequence,descriptions,unicode,substitution)
   if unicode == substitution then
       report_prepare("%s: base substitution %s maps onto itself",
           cref(feature,sequence),
           gref(descriptions,unicode))
   else
       report_prepare("%s: base substitution %s => %S",
           cref(feature,sequence),
           gref(descriptions,unicode),
           gref(descriptions,substitution))
   end
end

local function report_alternate(feature,sequence,descriptions,unicode,replacement,value,comment)
   if unicode == replacement then
       report_prepare("%s: base alternate %s maps onto itself",
           cref(feature,sequence),
           gref(descriptions,unicode))
   else
       report_prepare("%s: base alternate %s => %s (%S => %S)",
           cref(feature,sequence),
           gref(descriptions,unicode),
           replacement and gref(descriptions,replacement),
           value,
           comment)
   end
end

local function report_ligature(feature,sequence,descriptions,unicode,ligature)
   report_prepare("%s: base ligature %s => %S",
       cref(feature,sequence),
       gref(descriptions,ligature),
       gref(descriptions,unicode))
end

local function report_kern(feature,sequence,descriptions,unicode,otherunicode,value)
   report_prepare("%s: base kern %s + %s => %S",
       cref(feature,sequence),
       gref(descriptions,unicode),
       gref(descriptions,otherunicode),
       value)
end

-- We need to make sure that luatex sees the difference between base fonts that have
-- different glyphs in the same slots in fonts that have the same fullname (or filename).
-- LuaTeX will merge fonts eventually (and subset later on). If needed we can use a more
-- verbose name as long as we don't use <()<>[]{}/%> and the length is < 128.

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 or properties.name) .. "-" .. base
-- report_prepare("fullname base hash '%a, featureset %a",tfmdata.properties.fullname,hash)
   applied = { }
end

local function registerbasefeature(feature,value)
   applied[#applied+1] = feature  .. "=" .. tostring(value)
end

-- The original basemode ligature builder used the names of components and did some expression
-- juggling to get the chain right. The current variant starts with unicodes but still uses
-- names to make the chain. This is needed because we have to create intermediates when needed
-- but use predefined snippets when available. To some extend the current builder is more stupid
-- but I don't worry that much about it as ligatures are rather predicatable.
--
-- Personally I think that an ff + i == ffi rule as used in for instance latin modern is pretty
-- weird as no sane person will key that in and expect a glyph for that ligature plus the following
-- character. Anyhow, as we need to deal with this, we do, but no guarantes are given.
--
--         latin modern       dejavu
--
-- f+f       102 102             102 102
-- f+i       102 105             102 105
-- f+l       102 108             102 108
-- f+f+i                         102 102 105
-- f+f+l     102 102 108         102 102 108
-- ff+i    64256 105           64256 105
-- ff+l                        64256 108
--
-- As you can see here, latin modern is less complete than dejavu but
-- in practice one will not notice it.
--
-- The while loop is needed because we need to resolve for instance pseudo names like
-- hyphen_hyphen to endash so in practice we end up with a bit too many definitions but the
-- overhead is neglectable. We can have changed[first] or changed[second] but it quickly becomes
-- messy if we need to take that into account.

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)
   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",sequence.name,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[name]
               if not d then
                   done[name] = { "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)
       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 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

   -- A chain of changes is handled in font-con which is clesner because
   -- we can have shared changes and such.

   if not changed then
       changed = { }
       tfmdata.changed = changed
   end

   for i=1,#lookuplist do
       local sequence = lookuplist[i]
       local steps    = sequence.steps
       local kind     = sequence.type
       if kind == "gsub_single" then
           for i=1,#steps do
               for unicode, data in next, steps[i].coverage do
                   if unicode ~= data then
                       changed[unicode] = data
                   end
                   if trace_singles then
                       report_substitution(feature,sequence,descriptions,unicode,data)
                   end
               end
           end
       elseif kind == "gsub_alternate" then
           for i=1,#steps do
               for unicode, data in next, steps[i].coverage do
                   local replacement = data[alternate]
                   if replacement then
                       if unicode ~= replacement then
                           changed[unicode] = replacement
                       end
                       if trace_alternatives then
                           report_alternate(feature,sequence,descriptions,unicode,replacement,value,"normal")
                       end
                   elseif defaultalt == "first" then
                       replacement = data[1]
                       if unicode ~= replacement then
                           changed[unicode] = replacement
                       end
                       if trace_alternatives then
                           report_alternate(feature,sequence,descriptions,unicode,replacement,value,defaultalt)
                       end
                   elseif defaultalt == "last" then
                       replacement = data[#data]
                       if unicode ~= replacement then
                           changed[unicode] = replacement
                       end
                       if trace_alternatives then
                           report_alternate(feature,sequence,descriptions,unicode,replacement,value,defaultalt)
                       end
                   else
                       if trace_alternatives then
                           report_alternate(feature,sequence,descriptions,unicode,replacement,value,"unknown")
                       end
                   end
               end
           end
       elseif kind == "gsub_ligature" then
           for i=1,#steps do
               for unicode, data in next, steps[i].coverage do
                   ligatures[#ligatures+1] = { unicode, data, "" } -- lookupname }
                   if trace_ligatures then
                       report_ligature(feature,sequence,descriptions,unicode,data)
                   end
               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,sequence)
       end

   end

end

local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist)
   local characters   = tfmdata.characters
   local descriptions = tfmdata.descriptions
   local resources    = tfmdata.resources
   local properties   = tfmdata.properties
   local traceindeed  = trace_baseinit and trace_kerns
   -- check out this sharedkerns trickery
   for i=1,#lookuplist do
       local sequence = lookuplist[i]
       local steps    = sequence.steps
       local kind     = sequence.type
       local format   = sequence.format
       if kind == "gpos_pair" then
           for i=1,#steps do
               local step = steps[i]
               if step.format == "kern" then
                   for unicode, data in next, steps[i].coverage 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,sequence,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
               else
                   for unicode, data in next, steps[i].coverage do
                       local character = characters[unicode]
                       local kerns     = character.kerns
                       for otherunicode, kern in next, data do
                           if not kern[2] and not (kerns and kerns[otherunicode]) then
                               local kern = kern[1]
                               if kern[1] ~= 0 or kern[2] ~= 0 or kern[4] ~= 0 then
                                   -- a complex pair not suitable for basemode
                               else
                                   kern = kern[3]
                                   if kern ~= 0 then
                                       if kerns then
                                           kerns[otherunicode] = kern
                                       else
                                           kerns = { [otherunicode] = kern }
                                           character.kerns = kerns
                                       end
                                       if traceindeed then
                                           report_kern(feature,sequence,descriptions,unicode,otherunicode,kern)
                                       end
                                   end
                               end
                           end
                       end
                   end
               end
           end
       end
   end

end

local function initializehashes(tfmdata)
   -- already done
end

local function checkmathreplacements(tfmdata,fullname)
   if tfmdata.mathparameters then
       local characters = tfmdata.characters
       local changed    = tfmdata.changed
       if next(changed) then
           if trace_preparing or trace_baseinit then
               report_prepare("checking math replacements for %a",fullname)
           end
           for unicode, replacement in next, changed do
               local u = characters[unicode]
               local r = characters[replacement]
               local n = u.next
               local v = u.vert_variants
               local h = u.horiz_variants
               if n and not r.next then
                   if trace_preparing then
                       report_prepare("forcing %s for %C substituted by %U","incremental step",unicode,replacement)
                   end
                   r.next = n
               end
               if v and not r.vert_variants then
                   if trace_preparing then
                       report_prepare("forcing %s for %C substituted by %U","vertical variants",unicode,replacement)
                   end
                   r.vert_variants = v
               end
               if h and not r.horiz_variants then
                   if trace_preparing then
                       report_prepare("forcing %s for %C substituted by %U","horizontal variants",unicode,replacement)
                   end
                   r.horiz_variants = h
               end
           end
       end
   end
end

local function featuresinitializer(tfmdata,value)
   if true then -- value then
       local starttime = trace_preparing and os.clock()
       local features  = tfmdata.shared.features
       local fullname  = tfmdata.properties.fullname or "?"
       if features then
           initializehashes(tfmdata)
           local collectlookups    = otf.collectlookups
           local rawdata           = tfmdata.shared.rawdata
           local properties        = tfmdata.properties
           local script            = properties.script
           local language          = properties.language
           local rawresources      = rawdata.resources
           local rawfeatures       = rawresources and rawresources.features
           local basesubstitutions = rawfeatures and rawfeatures.gsub
           local basepositionings  = rawfeatures and rawfeatures.gpos
           local substitutionsdone = false
           local positioningsdone  = false
           --
           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
                                       -- skip
                                   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
                                       preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist)
                                       registerbasefeature(feature,value)
                                       substitutionsdone = true
                                   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
                                       preparepositionings(tfmdata,feature,value,validlookups,lookuplist)
                                       registerbasefeature(feature,value)
                                       positioningsdone = true
                                   end
                               end
                           end
                       end
                   end
               end
           end
           --
           if substitutionsdone then
               checkmathreplacements(tfmdata,fullname)
           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 = {
    -- position = 1, -- after setscript (temp hack ... we need to force script / language to 1
       base     = featuresinitializer,
   }
}

otf.basemodeinitializer = featuresinitializer


end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-oto”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-otj” 5ea70db9f1990dc1459425853c79f663] ---

if not modules then modules={} end modules ['font-otj']={
 version=1.001,
 comment="companion to font-lib.mkiv",
 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
 copyright="PRAGMA ADE / ConTeXt Development Team",
 license="see context related readme files",
}
if not nodes.properties then return end
local next,rawget=next,rawget
local fastcopy=table.fastcopy
local registertracker=trackers.register
local trace_injections=false registertracker("fonts.injections",function(v) trace_injections=v end)
local trace_marks=false registertracker("fonts.injections.marks",function(v) trace_marks=v end)
local trace_cursive=false registertracker("fonts.injections.cursive",function(v) trace_cursive=v end)
local trace_spaces=false registertracker("fonts.injections.spaces",function(v) trace_spaces=v end)
local use_advance=false directives.register("fonts.injections.advance",function(v) use_advance=v end)
local report_injections=logs.reporter("fonts","injections")
local report_spaces=logs.reporter("fonts","spaces")
local attributes,nodes,node=attributes,nodes,node
fonts=fonts
local hashes=fonts.hashes
local fontdata=hashes.identifiers
nodes.injections=nodes.injections or {}
local injections=nodes.injections
local tracers=nodes.tracers
local setcolor=tracers and tracers.colors.set
local resetcolor=tracers and tracers.colors.reset
local nodecodes=nodes.nodecodes
local glyph_code=nodecodes.glyph
local disc_code=nodecodes.disc
local kern_code=nodecodes.kern
local glue_code=nodecodes.glue
local nuts=nodes.nuts
local nodepool=nuts.pool
local newkern=nodepool.kern
local tonode=nuts.tonode
local tonut=nuts.tonut
local getfield=nuts.getfield
local setfield=nuts.setfield
local getnext=nuts.getnext
local getprev=nuts.getprev
local getid=nuts.getid
local getfont=nuts.getfont
local getsubtype=nuts.getsubtype
local getchar=nuts.getchar
local getboth=nuts.getboth
local ischar=nuts.is_char
local getdisc=nuts.getdisc
local setdisc=nuts.setdisc
local traverse_id=nuts.traverse_id
local traverse_char=nuts.traverse_char
local insert_node_before=nuts.insert_before
local insert_node_after=nuts.insert_after
local properties=nodes.properties.data
function injections.installnewkern(nk)
 newkern=nk or newkern
end
local nofregisteredkerns=0
local nofregisteredpairs=0
local nofregisteredmarks=0
local nofregisteredcursives=0
local keepregisteredcounts=false
function injections.keepcounts()
 keepregisteredcounts=true
end
function injections.resetcounts()
 nofregisteredkerns=0
 nofregisteredpairs=0
 nofregisteredmarks=0
 nofregisteredcursives=0
 keepregisteredcounts=false
end
function injections.reset(n)
 local p=rawget(properties,n)
 if p then
   p.injections=false
 else
   properties[n]=false
 end
end
function injections.copy(target,source)
 local sp=rawget(properties,source)
 if sp then
   local tp=rawget(properties,target)
   local si=sp.injections
   if si then
     si=fastcopy(si)
     if tp then
       tp.injections=si
     else
       propertydata[target]={
         injections=si,
       }
     end
   elseif tp then
     tp.injections=false
   else
     properties[target]={ injections={} }
   end
 else
   local tp=rawget(properties,target)
   if tp then
     tp.injections=false
   else
     properties[target]=false
   end
 end
end
function injections.setligaindex(n,index)
 local p=rawget(properties,n)
 if p then
   local i=p.injections
   if i then
     i.ligaindex=index
   else
     p.injections={
       ligaindex=index
     }
   end
 else
   properties[n]={
     injections={
       ligaindex=index
     }
   }
 end
end
function injections.getligaindex(n,default)
 local p=rawget(properties,n)
 if p then
   local i=p.injections
   if i then
     return i.ligaindex or default
   end
 end
 return default
end
function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
 local dx=factor*(exit[1]-entry[1])
 local dy=-factor*(exit[2]-entry[2])
 local ws=tfmstart.width
 local wn=tfmnext.width
 nofregisteredcursives=nofregisteredcursives+1
 if rlmode<0 then
   dx=-(dx+wn)
 else
   dx=dx-ws
 end
 if dx==0 then
   dx=0
 end
 local p=rawget(properties,start)
 if p then
   local i=p.injections
   if i then
     i.cursiveanchor=true
   else
     p.injections={
       cursiveanchor=true,
     }
   end
 else
   properties[start]={
     injections={
       cursiveanchor=true,
     },
   }
 end
 local p=rawget(properties,nxt)
 if p then
   local i=p.injections
   if i then
     i.cursivex=dx
     i.cursivey=dy
   else
     p.injections={
       cursivex=dx,
       cursivey=dy,
     }
   end
 else
   properties[nxt]={
     injections={
       cursivex=dx,
       cursivey=dy,
     },
   }
 end
 return dx,dy,nofregisteredcursives
end
function injections.setpair(current,factor,rlmode,r2lflag,spec,injection)
 local x=factor*spec[1]
 local y=factor*spec[2]
 local w=factor*spec[3]
 local h=factor*spec[4]
 if x~=0 or w~=0 or y~=0 or h~=0 then
   local yoffset=y-h
   local leftkern=x
   local rightkern=w-x
   if leftkern~=0 or rightkern~=0 or yoffset~=0 then
     nofregisteredpairs=nofregisteredpairs+1
     if rlmode and rlmode<0 then
       leftkern,rightkern=rightkern,leftkern
     end
     if not injection then
       injection="injections"
     end
     local p=rawget(properties,current)
     if p then
       local i=rawget(p,injection)
       if i then
         if leftkern~=0 then
           i.leftkern=(i.leftkern or 0)+leftkern
         end
         if rightkern~=0 then
           i.rightkern=(i.rightkern or 0)+rightkern
         end
         if yoffset~=0 then
           i.yoffset=(i.yoffset or 0)+yoffset
         end
       elseif leftkern~=0 or rightkern~=0 then
         p[injection]={
           leftkern=leftkern,
           rightkern=rightkern,
           yoffset=yoffset,
         }
       else
         p[injection]={
           yoffset=yoffset,
         }
       end
     elseif leftkern~=0 or rightkern~=0 then
       properties[current]={
         [injection]={
           leftkern=leftkern,
           rightkern=rightkern,
           yoffset=yoffset,
         },
       }
     else
       properties[current]={
         [injection]={
           yoffset=yoffset,
         },
       }
     end
     return x,y,w,h,nofregisteredpairs
    end
 end
 return x,y,w,h
end
function injections.setkern(current,factor,rlmode,x,injection)
 local dx=factor*x
 if dx~=0 then
   nofregisteredkerns=nofregisteredkerns+1
   local p=rawget(properties,current)
   if not injection then
     injection="injections"
   end
   if p then
     local i=rawget(p,injection)
     if i then
       i.leftkern=dx+(i.leftkern or 0)
     else
       p[injection]={
         leftkern=dx,
       }
     end
   else
     properties[current]={
       [injection]={
         leftkern=dx,
       },
     }
   end
   return dx,nofregisteredkerns
 else
   return 0,0
 end
end
function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk,checkmark)
 local dx,dy=factor*(ba[1]-ma[1]),factor*(ba[2]-ma[2])
 nofregisteredmarks=nofregisteredmarks+1
 if rlmode>=0 then
   dx=tfmbase.width-dx
 end
 local p=rawget(properties,start)
 if p then
   local i=p.injections
   if i then
     if i.markmark then
     else
       i.markx=dx
       i.marky=dy
       i.markdir=rlmode or 0
       i.markbase=nofregisteredmarks
       i.markbasenode=base
       i.markmark=mkmk
       i.checkmark=checkmark
     end
   else
     p.injections={
       markx=dx,
       marky=dy,
       markdir=rlmode or 0,
       markbase=nofregisteredmarks,
       markbasenode=base,
       markmark=mkmk,
       checkmark=checkmark,
     }
   end
 else
   properties[start]={
     injections={
       markx=dx,
       marky=dy,
       markdir=rlmode or 0,
       markbase=nofregisteredmarks,
       markbasenode=base,
       markmark=mkmk,
       checkmark=checkmark,
     },
   }
 end
 return dx,dy,nofregisteredmarks
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 showchar(n,nested)
 local char=getchar(n)
 report_injections("%wfont %s, char %U, glyph %c",nested and 2 or 0,getfont(n),char,char)
end
local function show(n,what,nested,symbol)
 if n then
   local p=rawget(properties,n)
   if p then
     local i=rawget(p,what)
     if i then
       local leftkern=i.leftkern or 0
       local rightkern=i.rightkern or 0
       local yoffset=i.yoffset  or 0
       local markx=i.markx   or 0
       local marky=i.marky   or 0
       local markdir=i.markdir  or 0
       local markbase=i.markbase or 0
       local cursivex=i.cursivex or 0
       local cursivey=i.cursivey or 0
       local ligaindex=i.ligaindex or 0
       local cursbase=i.cursiveanchor
       local margin=nested and 4 or 2
       if rightkern~=0 or yoffset~=0 then
         report_injections("%w%s pair: lx %p, rx %p, dy %p",margin,symbol,leftkern,rightkern,yoffset)
       elseif leftkern~=0 then
         report_injections("%w%s kern: dx %p",margin,symbol,leftkern)
       end
       if markx~=0 or marky~=0 or markbase~=0 then
         report_injections("%w%s mark: dx %p, dy %p, dir %s, base %s",margin,symbol,markx,marky,markdir,markbase~=0 and "yes" or "no")
       end
       if cursivex~=0 or cursivey~=0 then
         if cursbase then
           report_injections("%w%s curs: base dx %p, dy %p",margin,symbol,cursivex,cursivey)
         else
           report_injections("%w%s curs: dx %p, dy %p",margin,symbol,cursivex,cursivey)
         end
       elseif cursbase then
         report_injections("%w%s curs: base",margin,symbol)
       end
       if ligaindex~=0 then
         report_injections("%w%s liga: index %i",margin,symbol,ligaindex)
       end
     end
   end
 end
end
local function showsub(n,what,where)
 report_injections("begin subrun: %s",where)
 for n in traverse_id(glyph_code,n) do
   showchar(n,where)
   show(n,what,where," ")
 end
 report_injections("end subrun")
end
local function trace(head,where)
 report_injections("begin run %s: %s kerns, %s pairs, %s marks and %s cursives registered",
   where or "",nofregisteredkerns,nofregisteredpairs,nofregisteredmarks,nofregisteredcursives)
 local n=head
 while n do
   local id=getid(n)
   if id==glyph_code then
     showchar(n)
     show(n,"injections",false," ")
     show(n,"preinjections",false,"<")
     show(n,"postinjections",false,">")
     show(n,"replaceinjections",false,"=")
     show(n,"emptyinjections",false,"*")
   elseif id==disc_code then
     local pre,post,replace=getdisc(n)
     if pre then
       showsub(pre,"preinjections","pre")
     end
     if post then
       showsub(post,"postinjections","post")
     end
     if replace then
       showsub(replace,"replaceinjections","replace")
     end
     show(n,"emptyinjections",false,"*")
   end
   n=getnext(n)
 end
 report_injections("end run")
end
local function show_result(head)
 local current=head
 local skipping=false
 while current do
   local id=getid(current)
   if id==glyph_code then
     report_injections("char: %C, width %p, xoffset %p, yoffset %p",
       getchar(current),getfield(current,"width"),getfield(current,"xoffset"),getfield(current,"yoffset"))
     skipping=false
   elseif id==kern_code then
     report_injections("kern: %p",getfield(current,"kern"))
     skipping=false
   elseif not skipping then
     report_injections()
     skipping=true
   end
   current=getnext(current)
 end
end
local function inject_kerns_only(head,where)
 head=tonut(head)
 if trace_injections then
   trace(head,"kerns")
 end
 local current=head
 local prev=nil
 local next=nil
 local prevdisc=nil
 local prevglyph=nil
 local pre=nil
 local post=nil
 local replace=nil
 local pretail=nil
 local posttail=nil
 local replacetail=nil
 while current do
   local id=getid(current)
   local next=getnext(current)
   if id==glyph_code then
     if getsubtype(current)<256 then
       local p=rawget(properties,current)
       if p then
         local i=p.injections
         if i then
           local leftkern=i.leftkern
           if leftkern and leftkern~=0 then
             if use_advance then
               setfield(current,"xoffset",leftkern)
               setfield(current,"xadvance",leftkern)
             else
               insert_node_before(head,current,newkern(leftkern))
             end
           end
         end
         if prevdisc then
           local done=false
           if post then
             local i=p.postinjections
             if i then
               local leftkern=i.leftkern
               if leftkern and leftkern~=0 then
                 if use_advance then
                   setfield(post,"xadvance",leftkern)
                 else
                   insert_node_after(post,posttail,newkern(leftkern))
                   done=true
                 end
               end
             end
           end
           if replace then
             local i=p.replaceinjections
             if i then
               local leftkern=i.leftkern
               if leftkern and leftkern~=0 then
                 if use_advance then
                   setfield(replace,"xadvance",leftkern)
                 else
                   insert_node_after(replace,replacetail,newkern(leftkern))
                   done=true
                 end
               end
             end
           else
             local i=p.emptyinjections
             if i then
               local leftkern=i.leftkern
               if leftkern and leftkern~=0 then
                 setfield(prev,"replace",newkern(leftkern))
               end
             end
           end
           if done then
             setdisc(prevdisc,pre,post,replace)
           end
         end
       end
     end
     prevdisc=nil
     prevglyph=current
   elseif id==disc_code then
     pre,post,replace,pretail,posttail,replacetail=getdisc(current,true)
     local done=false
     if pre then
       for n in traverse_char(pre) do
         local p=rawget(properties,n)
         if p then
           local i=p.injections or p.preinjections
           if i then
             local leftkern=i.leftkern
             if leftkern and leftkern~=0 then
               if use_advance then
                 setfield(pre,"xoffset",leftkern)
                 setfield(pre,"xadvance",leftkern)
               else
                 pre=insert_node_before(pre,n,newkern(leftkern))
                 done=true
               end
             end
           end
         end
       end
     end
     if post then
       for n in traverse_char(post) do
         local p=rawget(properties,n)
         if p then
           local i=p.injections or p.postinjections
           if i then
             local leftkern=i.leftkern
             if leftkern and leftkern~=0 then
               if use_advance then
                 setfield(post,"xoffset",leftkern)
                 setfield(post,"xadvance",leftkern)
               else
                 post=insert_node_before(post,n,newkern(leftkern))
                 done=true
               end
             end
           end
         end
       end
     end
     if replace then
       for n in traverse_char(replace) do
         local p=rawget(properties,n)
         if p then
           local i=p.injections or p.replaceinjections
           if i then
             local leftkern=i.leftkern
             if leftkern and leftkern~=0 then
               if use_advance then
                 setfield(replace,"xoffset",leftkern)
                 setfield(replace,"xadvance",leftkern)
               else
                 replace=insert_node_before(replace,n,newkern(leftkern))
                 done=true
               end
             end
           end
         end
       end
     end
     if done then
       setdisc(current,pre,post,replace)
     end
     prevglyph=nil
     prevdisc=current
   else
     prevglyph=nil
     prevdisc=nil
   end
   prev=current
   current=next
 end
 if keepregisteredcounts then
   keepregisteredcounts=false
 else
   nofregisteredkerns=0
 end
 return tonode(head),true
end
local function inject_pairs_only(head,where)
 head=tonut(head)
 if trace_injections then
   trace(head,"pairs")
 end
 local current=head
 local prev=nil
 local next=nil
 local prevdisc=nil
 local prevglyph=nil
 local pre=nil
 local post=nil
 local replace=nil
 local pretail=nil
 local posttail=nil
 local replacetail=nil
 while current do
   local id=getid(current)
   local next=getnext(current)
   if id==glyph_code then
     if getsubtype(current)<256 then
       local p=rawget(properties,current)
       if p then
         local i=p.injections
         if i then
           local yoffset=i.yoffset
           if yoffset and yoffset~=0 then
             setfield(current,"yoffset",yoffset)
           end
           local leftkern=i.leftkern
           if leftkern and leftkern~=0 then
             head=insert_node_before(head,current,newkern(leftkern))
           end
           local rightkern=i.rightkern
           if rightkern and rightkern~=0 then
             insert_node_after(head,current,newkern(rightkern))
           end
         else
           local i=p.emptyinjections
           if i then
             local rightkern=i.rightkern
             if rightkern and rightkern~=0 then
               if next and getid(next)==disc_code then
                 if replace then
                 else
                   setfield(next,"replace",newkern(rightkern))
                 end
               end
             end
           end
         end
         if prevdisc then
           local done=false
           if post then
             local i=p.postinjections
             if i then
               local leftkern=i.leftkern
               if leftkern and leftkern~=0 then
                 insert_node_after(post,posttail,newkern(leftkern))
                 done=true
               end
             end
           end
           if replace then
             local i=p.replaceinjections
             if i then
               local leftkern=i.leftkern
               if leftkern and leftkern~=0 then
                 insert_node_after(replace,replacetail,newkern(leftkern))
                 done=true
               end
             end
           else
             local i=p.emptyinjections
             if i then
               local leftkern=i.leftkern
               if leftkern and leftkern~=0 then
                 setfield(prev,"replace",newkern(leftkern))
               end
             end
           end
           if done then
             setdisc(prevdisc,pre,post,replace)
           end
         end
       end
     end
     prevdisc=nil
     prevglyph=current
   elseif id==disc_code then
     pre,post,replace,pretail,posttail,replacetail=getdisc(current,true)
     local done=false
     if pre then
       for n in traverse_char(pre) do
         local p=rawget(properties,n)
         if p then
           local i=p.injections or p.preinjections
           if i then
             local yoffset=i.yoffset
             if yoffset and yoffset~=0 then
               setfield(n,"yoffset",yoffset)
             end
             local leftkern=i.leftkern
             if leftkern and leftkern~=0 then
               pre=insert_node_before(pre,n,newkern(leftkern))
               done=true
             end
             local rightkern=i.rightkern
             if rightkern and rightkern~=0 then
               insert_node_after(pre,n,newkern(rightkern))
               done=true
             end
           end
         end
       end
     end
     if post then
       for n in traverse_char(post) do
         local p=rawget(properties,n)
         if p then
           local i=p.injections or p.postinjections
           if i then
             local yoffset=i.yoffset
             if yoffset and yoffset~=0 then
               setfield(n,"yoffset",yoffset)
             end
             local leftkern=i.leftkern
             if leftkern and leftkern~=0 then
               post=insert_node_before(post,n,newkern(leftkern))
               done=true
             end
             local rightkern=i.rightkern
             if rightkern and rightkern~=0 then
               insert_node_after(post,n,newkern(rightkern))
               done=true
             end
           end
         end
       end
     end
     if replace then
       for n in traverse_char(replace) do
         local p=rawget(properties,n)
         if p then
           local i=p.injections or p.replaceinjections
           if i then
             local yoffset=i.yoffset
             if yoffset and yoffset~=0 then
               setfield(n,"yoffset",yoffset)
             end
             local leftkern=i.leftkern
             if leftkern and leftkern~=0 then
               replace=insert_node_before(replace,n,newkern(leftkern))
               done=true
             end
             local rightkern=i.rightkern
             if rightkern and rightkern~=0 then
               insert_node_after(replace,n,newkern(rightkern))
               done=true
             end
           end
         end
       end
     end
     if prevglyph then
       if pre then
         local p=rawget(properties,prevglyph)
         if p then
           local i=p.preinjections
           if i then
             local rightkern=i.rightkern
             if rightkern and rightkern~=0 then
               pre=insert_node_before(pre,pre,newkern(rightkern))
               done=true
             end
           end
         end
       end
       if replace then
         local p=rawget(properties,prevglyph)
         if p then
           local i=p.replaceinjections
           if i then
             local rightkern=i.rightkern
             if rightkern and rightkern~=0 then
               replace=insert_node_before(replace,replace,newkern(rightkern))
               done=true
             end
           end
         end
       end
     end
     if done then
       setdisc(current,pre,post,replace)
     end
     prevglyph=nil
     prevdisc=current
   else
     prevglyph=nil
     prevdisc=nil
   end
   prev=current
   current=next
 end
 if keepregisteredcounts then
   keepregisteredcounts=false
 else
   nofregisteredkerns=0
 end
 return tonode(head),true
end
local function showoffset(n,flag)
 local o=getfield(n,"xoffset")
 if o==0 then
   o=getfield(n,"yoffset")
 end
 if o~=0 then
   setcolor(n,flag and "darkred" or "darkgreen")
 else
   resetcolor(n)
 end
end
local function inject_everything(head,where)
 head=tonut(head)
 if trace_injections then
   trace(head,"everything")
 end
 local hascursives=nofregisteredcursives>0
 local hasmarks=nofregisteredmarks>0
 local current=head
 local last=nil
 local font=font
 local markdata=nil
 local prev=nil
 local next=nil
 local prevdisc=nil
 local prevglyph=nil
 local pre=nil
 local post=nil
 local replace=nil
 local pretail=nil
 local posttail=nil
 local replacetail=nil
 local cursiveanchor=nil
 local minc=0
 local maxc=0
 local glyphs={}
 local marks={}
 local nofmarks=0
 local function processmark(p,n,pn)
   local px=getfield(p,"xoffset")
   local ox=0
   local rightkern=nil
   local pp=rawget(properties,p)
   if pp then
     pp=pp.injections
     if pp then
       rightkern=pp.rightkern
     end
   end
   if rightkern then
     if pn.markdir<0 then
       ox=px-pn.markx-rightkern
     else
       if false then
         local leftkern=pp.leftkern
         if leftkern then
           ox=px-pn.markx-leftkern
         else
           ox=px-pn.markx
         end
       else
         ox=px-pn.markx
       end
     end
   else
       ox=px-pn.markx
     if pn.checkmark then
       local wn=getfield(n,"width")
       if wn~=0 then
         wn=wn/2
         if trace_injections then
           report_injections("correcting non zero width mark %C",getchar(n))
         end
         insert_node_before(n,n,newkern(-wn))
         insert_node_after(n,n,newkern(-wn))
       end
     end
   end
   local oy=getfield(n,"yoffset")+getfield(p,"yoffset")+pn.marky
   setfield(n,"xoffset",ox)
   setfield(n,"yoffset",oy)
   if trace_marks then
     showoffset(n,true)
   end
 end
 while current do
   local id=getid(current)
   local next=getnext(current)
   if id==glyph_code then
     if getsubtype(current)<256 then
       local p=rawget(properties,current)
       if p then
         local i=p.injections
         if i then
           local pm=i.markbasenode
           if pm then
             nofmarks=nofmarks+1
             marks[nofmarks]=current
           else
             local yoffset=i.yoffset
             if yoffset and yoffset~=0 then
               setfield(current,"yoffset",yoffset)
             end
             if hascursives then
               local cursivex=i.cursivex
               if cursivex then
                 if cursiveanchor then
                   if cursivex~=0 then
                     i.leftkern=(i.leftkern or 0)+cursivex
                   end
                   if maxc==0 then
                     minc=1
                     maxc=1
                     glyphs[1]=cursiveanchor
                   else
                     maxc=maxc+1
                     glyphs[maxc]=cursiveanchor
                   end
                   properties[cursiveanchor].cursivedy=i.cursivey
                   last=current
                 else
                   maxc=0
                 end
               elseif maxc>0 then
                 local ny=getfield(current,"yoffset")
                 for i=maxc,minc,-1 do
                   local ti=glyphs[i]
                   ny=ny+properties[ti].cursivedy
                   setfield(ti,"yoffset",ny)
                   if trace_cursive then
                     showoffset(ti)
                   end
                 end
                 maxc=0
                 cursiveanchor=nil
               end
               if i.cursiveanchor then
                 cursiveanchor=current
               else
                 if maxc>0 then
                   local ny=getfield(current,"yoffset")
                   for i=maxc,minc,-1 do
                     local ti=glyphs[i]
                     ny=ny+properties[ti].cursivedy
                     setfield(ti,"yoffset",ny)
                     if trace_cursive then
                       showoffset(ti)
                     end
                   end
                   maxc=0
                 end
                 cursiveanchor=nil
               end
             end
             local leftkern=i.leftkern
             if leftkern and leftkern~=0 then
               insert_node_before(head,current,newkern(leftkern))
             end
             local rightkern=i.rightkern
             if rightkern and rightkern~=0 then
               insert_node_after(head,current,newkern(rightkern))
             end
           end
         else
           local i=p.emptyinjections
           if i then
             local rightkern=i.rightkern
             if rightkern and rightkern~=0 then
               if next and getid(next)==disc_code then
                 if replace then
                 else
                   setfield(next,"replace",newkern(rightkern))
                 end
               end
             end
           end
         end
         if prevdisc then
           if p then
             local done=false
             if post then
               local i=p.postinjections
               if i then
                 local leftkern=i.leftkern
                 if leftkern and leftkern~=0 then
                   insert_node_after(post,posttail,newkern(leftkern))
                   done=true
                 end
               end
             end
             if replace then
               local i=p.replaceinjections
               if i then
                 local leftkern=i.leftkern
                 if leftkern and leftkern~=0 then
                   insert_node_after(replace,replacetail,newkern(leftkern))
                   done=true
                 end
               end
             else
               local i=p.emptyinjections
               if i then
                 local leftkern=i.leftkern
                 if leftkern and leftkern~=0 then
                   setfield(prev,"replace",newkern(leftkern))
                 end
               end
             end
             if done then
               setdisc(prevdisc,pre,post,replace)
             end
           end
         end
       else
         if hascursives and maxc>0 then
           local ny=getfield(current,"yoffset")
           for i=maxc,minc,-1 do
             local ti=glyphs[i]
             ny=ny+properties[ti].cursivedy
             setfield(ti,"yoffset",getfield(ti,"yoffset")+ny)
           end
           maxc=0
           cursiveanchor=nil
         end
       end
     end
     prevdisc=nil
     prevglyph=current
   elseif id==disc_code then
     pre,post,replace,pretail,posttail,replacetail=getdisc(current,true)
     local done=false
     if pre then
       for n in traverse_char(pre) do
         local p=rawget(properties,n)
         if p then
           local i=p.injections or p.preinjections
           if i then
             local yoffset=i.yoffset
             if yoffset and yoffset~=0 then
               setfield(n,"yoffset",yoffset)
             end
             local leftkern=i.leftkern
             if leftkern and leftkern~=0 then
               pre=insert_node_before(pre,n,newkern(leftkern))
               done=true
             end
             local rightkern=i.rightkern
             if rightkern and rightkern~=0 then
               insert_node_after(pre,n,newkern(rightkern))
               done=true
             end
             if hasmarks then
               local pm=i.markbasenode
               if pm then
                 processmark(pm,current,i)
               end
             end
           end
         end
       end
     end
     if post then
       for n in traverse_char(post) do
         local p=rawget(properties,n)
         if p then
           local i=p.injections or p.postinjections
           if i then
             local yoffset=i.yoffset
             if yoffset and yoffset~=0 then
               setfield(n,"yoffset",yoffset)
             end
             local leftkern=i.leftkern
             if leftkern and leftkern~=0 then
               post=insert_node_before(post,n,newkern(leftkern))
               done=true
             end
             local rightkern=i.rightkern
             if rightkern and rightkern~=0 then
               insert_node_after(post,n,newkern(rightkern))
               done=true
             end
             if hasmarks then
               local pm=i.markbasenode
               if pm then
                 processmark(pm,current,i)
               end
             end
           end
         end
       end
     end
     if replace then
       for n in traverse_char(replace) do
         local p=rawget(properties,n)
         if p then
           local i=p.injections or p.replaceinjections
           if i then
             local yoffset=i.yoffset
             if yoffset and yoffset~=0 then
               setfield(n,"yoffset",yoffset)
             end
             local leftkern=i.leftkern
             if leftkern and leftkern~=0 then
               replace=insert_node_before(replace,n,newkern(leftkern))
               done=true
             end
             local rightkern=i.rightkern
             if rightkern and rightkern~=0 then
               insert_node_after(replace,n,newkern(rightkern))
               done=true
             end
             if hasmarks then
               local pm=i.markbasenode
               if pm then
                 processmark(pm,current,i)
               end
             end
           end
         end
       end
     end
     if prevglyph then
       if pre then
         local p=rawget(properties,prevglyph)
         if p then
           local i=p.preinjections
           if i then
             local rightkern=i.rightkern
             if rightkern and rightkern~=0 then
               pre=insert_node_before(pre,pre,newkern(rightkern))
               done=true
             end
           end
         end
       end
       if replace then
         local p=rawget(properties,prevglyph)
         if p then
           local i=p.replaceinjections
           if i then
             local rightkern=i.rightkern
             if rightkern and rightkern~=0 then
               replace=insert_node_before(replace,replace,newkern(rightkern))
               done=true
             end
           end
         end
       end
     end
     if done then
       setdisc(current,pre,post,replace)
     end
     prevglyph=nil
     prevdisc=current
   else
     prevglyph=nil
     prevdisc=nil
   end
   prev=current
   current=next
 end
 if hascursives and maxc>0 then
   local ny=getfield(last,"yoffset")
   for i=maxc,minc,-1 do
     local ti=glyphs[i]
     ny=ny+properties[ti].cursivedy
     setfield(ti,"yoffset",ny)
     if trace_cursive then
       showoffset(ti)
     end
   end
 end
 if nofmarks>0 then
   for i=1,nofmarks do
     local m=marks[i]
     local p=rawget(properties,m)
     local i=p.injections
     local b=i.markbasenode
     processmark(b,m,i)
   end
 elseif hasmarks then
 end
 if keepregisteredcounts then
   keepregisteredcounts=false
 else
   nofregisteredkerns=0
   nofregisteredpairs=0
   nofregisteredmarks=0
   nofregisteredcursives=0
 end
 return tonode(head),true
end
local triggers=false
function nodes.injections.setspacekerns(font,sequence)
 if triggers then
   triggers[font]=sequence
 else
   triggers={ [font]=sequence }
 end
end
local getthreshold
if context then
 local threshold=1
 local parameters=fonts.hashes.parameters
 directives.register("otf.threshold",function(v) threshold=tonumber(v) or 1 end)
 getthreshold=function(font)
   local p=parameters[font]
   local f=p.factor
   local s=p.spacing
   local t=threshold*(s and s.width or p.space or 0)-2
   return t>0 and t or 0,f
 end
else
 injections.threshold=0
 getthreshold=function(font)
   local p=fontdata[font].parameters
   local f=p.factor
   local s=p.spacing
   local t=injections.threshold*(s and s.width or p.space or 0)-2
   return t>0 and t or 0,f
 end
end
injections.getthreshold=getthreshold
function injections.isspace(n,threshold)
 if getid(n)==glue_code then
   local w=getfield(n,"width")
   if threshold and w>threshold then
     return 32
   end
 end
end
local function injectspaces(head)
 if not triggers then
   return head,false
 end
 local lastfont=nil
 local spacekerns=nil
 local leftkerns=nil
 local rightkerns=nil
 local factor=0
 local threshold=0
 local leftkern=false
 local rightkern=false
 local function updatefont(font,trig)
   leftkerns=trig.left
   rightkerns=trig.right
   lastfont=font
   threshold,
   factor=getthreshold(font)
 end
 for n in traverse_id(glue_code,tonut(head)) do
   local prev,next=getboth(n)
   local prevchar=ischar(prev)
   local nextchar=ischar(next)
   if nextchar then
     local font=getfont(next)
     local trig=triggers[font]
     if trig then
       if lastfont~=font then
         updatefont(font,trig)
       end
       if rightkerns then
         rightkern=rightkerns[nextchar]
       end
     end
   end
   if prevchar then
     local font=getfont(prev)
     local trig=triggers[font]
     if trig then
       if lastfont~=font then
         updatefont(font,trig)
       end
       if leftkerns then
         leftkern=leftkerns[prevchar]
       end
     end
   end
   if leftkern then
     local old=getfield(n,"width")
     if old>threshold then
       if rightkern then
         local new=old+(leftkern+rightkern)*factor
         if trace_spaces then
           report_spaces("%C [%p -> %p] %C",prevchar,old,new,nextchar)
         end
         setfield(n,"width",new)
         leftkern=false
       else
         local new=old+leftkern*factor
         if trace_spaces then
           report_spaces("%C [%p -> %p]",prevchar,old,new)
         end
         setfield(n,"width",new)
       end
     end
     leftkern=false
   elseif rightkern then
     local old=getfield(n,"width")
     if old>threshold then
       local new=old+rightkern*factor
       if trace_spaces then
         report_spaces("[%p -> %p] %C",nextchar,old,new)
       end
       setfield(n,"width",new)
     end
     rightkern=false
   end
 end
 triggers=false
 return head,true
end
function injections.handler(head,where)
 if triggers then
   head=injectspaces(head)
 end
 if nofregisteredmarks>0 or nofregisteredcursives>0 then
   if trace_injections then
     report_injections("injection variant %a","everything")
   end
   return inject_everything(head,where)
 elseif nofregisteredpairs>0 then
   if trace_injections then
     report_injections("injection variant %a","pairs")
   end
   return inject_pairs_only(head,where)
 elseif nofregisteredkerns>0 then
   if trace_injections then
     report_injections("injection variant %a","kerns")
   end
   return inject_kerns_only(head,where)
 else
   return head,false
 end
end

end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-otj”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ota” c281d18dfc89a8ca18af64f55e9fa92b] ---

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
local a_state=attributes.private('state')
local nuts=nodes.nuts
local tonut=nuts.tonut
local getfield=nuts.getfield
local getnext=nuts.getnext
local getprev=nuts.getprev
local getprev=nuts.getprev
local getprop=nuts.getprop
local setprop=nuts.setprop
local getfont=nuts.getfont
local getsubtype=nuts.getsubtype
local getchar=nuts.getchar
local ischar=nuts.is_char
local traverse_id=nuts.traverse_id
local end_of_math=nuts.end_of_math
local nodecodes=nodes.nodecodes
local disc_code=nodecodes.disc
local math_code=nodecodes.math
local fontdata=fonts.hashes.identifiers
local categories=characters and characters.categories or {}
local chardata=characters and characters.data
local otffeatures=fonts.constructors.features.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,
 med2=s_medi,
 fina=s_fina,
 fin2=s_fina,
 fin3=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,
 med2=s_medi,
 fina=s_fina,
 fin2=s_fina,
 fin3=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
analyzers.useunicodemarks=false
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
 current=tonut(current)
 while current do
   local char,id=ischar(current,font)
   if char and not getprop(current,a_state) then
     done=true
     local d=descriptions[char]
     if d then
       if d.class=="mark" then
         done=true
         setprop(current,a_state,s_mark)
       elseif useunicodemarks and categories[char]=="mn" then
         done=true
         setprop(current,a_state,s_mark)
       elseif n==0 then
         first,last,n=current,current,1
         setprop(current,a_state,s_init)
       else
         last,n=current,n+1
         setprop(current,a_state,s_medi)
       end
     else
       if first and first==last then
         setprop(last,a_state,s_isol)
       elseif last then
         setprop(last,a_state,s_fina)
       end
       first,last,n=nil,nil,0
     end
   elseif char==false then
     if first and first==last then
       setprop(last,a_state,s_isol)
     elseif last then
       setprop(last,a_state,s_fina)
     end
     first,last,n=nil,nil,0
     if id==math_code then
       current=end_of_math(current)
     end
   elseif id==disc_code then
     setprop(current,a_state,s_medi)
     last=current
   else
     if first and first==last then
       setprop(last,a_state,s_isol)
     elseif last then
       setprop(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=getnext(current)
 end
 if first and first==last then
   setprop(last,a_state,s_isol)
 elseif last then
   setprop(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 arab_warned={}
local function warning(current,what)
 local char=getchar(current)
 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 mappers={
 l=s_init,
 d=s_medi,
 c=s_medi,
 r=s_fina,
 u=s_isol,
}
local classifiers=characters.classifiers
if not classifiers then
 local f_arabic,l_arabic=characters.blockrange("arabic")
 local f_syriac,l_syriac=characters.blockrange("syriac")
 local f_mandiac,l_mandiac=characters.blockrange("mandiac")
 local f_nko,l_nko=characters.blockrange("nko")
 local f_ext_a,l_ext_a=characters.blockrange("arabicextendeda")
 classifiers=table.setmetatableindex(function(t,k)
   if type(k)=="number" then
     local c=chardata[k]
     local v=false
     if c then
       local arabic=c.arabic
       if arabic then
         v=mappers[arabic]
         if not v then
           log.report("analyze","error in mapping arabic %C",k)
           v=false
         end
       elseif (k>=f_arabic and k<=l_arabic) or
           (k>=f_syriac and k<=l_syriac) or
           (k>=f_mandiac and k<=l_mandiac) or
           (k>=f_nko   and k<=l_nko)   or
           (k>=f_ext_a  and k<=l_ext_a)  then
         if categories[k]=="mn" then
           v=s_mark
         else
           v=s_rest
         end
       end
     end
     t[k]=v
     return v
   end
 end)
 characters.classifiers=classifiers
end
function methods.arab(head,font,attr)
 local first,last=nil,nil
 local c_first,c_last=nil,nil
 local current,done=head,false
 current=tonut(current)
 while current do
   local char,id=ischar(current,font)
   if char and not getprop(current,a_state) then
     done=true
     local classifier=classifiers[char]
     if not classifier then
       if last then
         if c_last==s_medi or c_last==s_fina then
           setprop(last,a_state,s_fina)
         else
           warning(last,"fina")
           setprop(last,a_state,s_error)
         end
         first,last=nil,nil
       elseif first then
         if c_first==s_medi or c_first==s_fina then
           setprop(first,a_state,s_isol)
         else
           warning(first,"isol")
           setprop(first,a_state,s_error)
         end
         first=nil
       end
     elseif classifier==s_mark then
       setprop(current,a_state,s_mark)
     elseif classifier==s_isol then
       if last then
         if c_last==s_medi or c_last==s_fina then
           setprop(last,a_state,s_fina)
         else
           warning(last,"fina")
           setprop(last,a_state,s_error)
         end
         first,last=nil,nil
       elseif first then
         if c_first==s_medi or c_first==s_fina then
           setprop(first,a_state,s_isol)
         else
           warning(first,"isol")
           setprop(first,a_state,s_error)
         end
         first=nil
       end
       setprop(current,a_state,s_isol)
     elseif classifier==s_medi then
       if first then
         last=current
         c_last=classifier
         setprop(current,a_state,s_medi)
       else
         setprop(current,a_state,s_init)
         first=current
         c_first=classifier
       end
     elseif classifier==s_fina then
       if last then
         if getprop(last,a_state)~=s_init then
           setprop(last,a_state,s_medi)
         end
         setprop(current,a_state,s_fina)
         first,last=nil,nil
       elseif first then
         setprop(current,a_state,s_fina)
         first=nil
       else
         setprop(current,a_state,s_isol)
       end
     else
       setprop(current,a_state,s_rest)
       if last then
         if c_last==s_medi or c_last==s_fina then
           setprop(last,a_state,s_fina)
         else
           warning(last,"fina")
           setprop(last,a_state,s_error)
         end
         first,last=nil,nil
       elseif first then
         if c_first==s_medi or c_first==s_fina then
           setprop(first,a_state,s_isol)
         else
           warning(first,"isol")
           setprop(first,a_state,s_error)
         end
         first=nil
       end
     end
   else
     if last then
       if c_last==s_medi or c_last==s_fina then
         setprop(last,a_state,s_fina)
       else
         warning(last,"fina")
         setprop(last,a_state,s_error)
       end
       first,last=nil,nil
     elseif first then
       if c_first==s_medi or c_first==s_fina then
         setprop(first,a_state,s_isol)
       else
         warning(first,"isol")
         setprop(first,a_state,s_error)
       end
       first=nil
     end
     if id==math_code then
       current=end_of_math(current)
     end
   end
   current=getnext(current)
 end
 if last then
   if c_last==s_medi or c_last==s_fina then
     setprop(last,a_state,s_fina)
   else
     warning(last,"fina")
     setprop(last,a_state,s_error)
   end
 elseif first then
   if c_first==s_medi or c_first==s_fina then
     setprop(first,a_state,s_isol)
   else
     warning(first,"isol")
     setprop(first,a_state,s_error)
   end
 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 --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ota”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ots” 7e1e55f9f728474372665e4a64a43f5a] ---

if not modules then modules={} end modules ['font-ots']={
 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 type,next,tonumber=type,next,tonumber
local random=math.random
local formatters=string.formatters
local insert=table.insert
local logs,trackers,nodes,attributes=logs,trackers,nodes,attributes
local registertracker=trackers.register
local registerdirective=directives.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_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 trace_plugins=false registertracker("otf.plugins",function(v) trace_plugins=v end)
local trace_kernruns=false registertracker("otf.kernruns",function(v) trace_kernruns=v end)
local trace_discruns=false registertracker("otf.discruns",function(v) trace_discruns=v end)
local trace_compruns=false registertracker("otf.compruns",function(v) trace_compruns=v end)
local trace_testruns=false registertracker("otf.testruns",function(v) trace_testruns=v end)
local optimizekerns=true
local alwaysdisc=true  registerdirective("otf.alwaysdisc",function(v) alwaysdisc=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_warning=logs.reporter("fonts","otf warning")
local report_run=logs.reporter("fonts","otf run")
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 nuts=nodes.nuts
local tonode=nuts.tonode
local tonut=nuts.tonut
local getfield=nuts.getfield
local setfield=nuts.setfield
local getnext=nuts.getnext
local setnext=nuts.setnext
local getprev=nuts.getprev
local setprev=nuts.setprev
local getboth=nuts.getboth
local setboth=nuts.setboth
local getid=nuts.getid
local getattr=nuts.getattr
local setattr=nuts.setattr
local getprop=nuts.getprop
local setprop=nuts.setprop
local getfont=nuts.getfont
local getsubtype=nuts.getsubtype
local setsubtype=nuts.setsubtype
local getchar=nuts.getchar
local setchar=nuts.setchar
local getdisc=nuts.getdisc
local setdisc=nuts.setdisc
local setlink=nuts.setlink
local ischar=nuts.is_char
local insert_node_after=nuts.insert_after
local copy_node=nuts.copy
local copy_node_list=nuts.copy_list
local find_node_tail=nuts.tail
local flush_node_list=nuts.flush_list
local flush_node=nuts.flush_node
local end_of_math=nuts.end_of_math
local traverse_nodes=nuts.traverse
local traverse_id=nuts.traverse_id
local remove_node=nuts.remove
local setmetatableindex=table.setmetatableindex
local zwnj=0x200C
local zwj=0x200D
local wildcard="*"
local default="dflt"
local nodecodes=nodes.nodecodes
local glyphcodes=nodes.glyphcodes
local disccodes=nodes.disccodes
local glyph_code=nodecodes.glyph
local glue_code=nodecodes.glue
local disc_code=nodecodes.disc
local math_code=nodecodes.math
local dir_code=nodecodes.dir
local localpar_code=nodecodes.localpar
local discretionary_code=disccodes.discretionary
local ligature_code=glyphcodes.ligature
local privateattribute=attributes.private
local a_state=privateattribute('state')
local injections=nodes.injections
local setmark=injections.setmark
local setcursive=injections.setcursive
local setkern=injections.setkern
local setpair=injections.setpair
local resetinjection=injections.reset
local copyinjection=injections.copy
local setligaindex=injections.setligaindex
local getligaindex=injections.getligaindex
local cursonce=true
local fonthashes=fonts.hashes
local fontdata=fonthashes.identifiers
local fontfeatures=fonthashes.features
local otffeatures=fonts.constructors.features.otf
local registerotffeature=otffeatures.register
local onetimemessage=fonts.loggers.onetimemessage or function() end
local getrandom=utilities and utilities.randomizer and utilities.randomizer.get
otf.defaultnodealternate="none"
local tfmdata=false
local characters=false
local descriptions=false
local marks=false
local currentfont=false
local factor=0
local threshold=0
local checkmarks=false
local sweepnode=nil
local sweepprev=nil
local sweepnext=nil
local sweephead={}
local notmatchpre={}
local notmatchpost={}
local notmatchreplace={}
local handlers={}
local isspace=injections.isspace
local getthreshold=injections.getthreshold
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 checkdisccontent(d)
 local pre,post,replace=getdisc(d)
 if pre   then for n in traverse_id(glue_code,pre)   do print("pre",nodes.idstostring(pre))   break end end
 if post  then for n in traverse_id(glue_code,post)  do print("pos",nodes.idstostring(post))  break end end
 if replace then for n in traverse_id(glue_code,replace) do print("rep",nodes.idstostring(replace)) break end end
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(dataset,sequence,index)
 if not dataset then
   return "no valid dataset"
 elseif index then
   return formatters["feature %a, type %a, chain lookup %a, index %a"](dataset[4],sequence.type,sequence.name,index)
 else
   return formatters["feature %a, type %a, chain lookup %a"](dataset[4],sequence.type,sequence.name)
 end
end
local function pref(dataset,sequence)
 return formatters["feature %a, type %a, lookup %a"](dataset[4],sequence.type,sequence.name)
end
local function mref(rlmode)
 if not rlmode or rlmode==0 then
   return "---"
 elseif rlmode==-1 or rlmode=="+TRT" then
   return "r2l"
 else
   return "l2r"
 end
end
local function copy_glyph(g)
 local components=getfield(g,"components")
 if components then
   setfield(g,"components")
   local n=copy_node(g)
   copyinjection(n,g)
   setfield(g,"components",components)
   return n
 else
   local n=copy_node(g)
   copyinjection(n,g)
   return n
 end
end
local function flattendisk(head,disc)
 local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true)
 local prev,next=getboth(disc)
 local ishead=head==disc
 setdisc(disc)
 flush_node(disc)
 if pre then
   flush_node_list(pre)
 end
 if post then
   flush_node_list(post)
 end
 if ishead then
   if replace then
     if next then
       setlink(replacetail,next)
     end
     return replace,replace
   elseif next then
     return next,next
   else
     return
   end
 else
   if replace then
     if next then
       setlink(replacetail,next)
     end
     setlink(prev,replace)
     return head,replace
   else
     setlink(prev,next)
     return head,next
   end
 end
end
local function appenddisc(disc,list)
 local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true)
 local posthead=list
 local replacehead=copy_node_list(list)
 if post then
   setlink(posttail,posthead)
 else
   post=phead
 end
 if replace then
   setlink(replacetail,replacehead)
 else
   replace=rhead
 end
 setdisc(disc,pre,post,replace)
end
local function markstoligature(head,start,stop,char)
 if start==stop and getchar(start)==char then
   return head,start
 else
   local prev=getprev(start)
   local next=getnext(stop)
   setprev(start)
   setnext(stop)
   local base=copy_glyph(start)
   if head==start then
     head=base
   end
   resetinjection(base)
   setchar(base,char)
   setsubtype(base,ligature_code)
   setfield(base,"components",start)
   setlink(prev,base)
   setlink(base,next)
   return head,base
 end
end
local function getcomponentindex(start)
 if getid(start)~=glyph_code then
   return 0
 elseif getsubtype(start)==ligature_code then
   local i=0
   local components=getfield(start,"components")
   while components do
     i=i+getcomponentindex(components)
     components=getnext(components)
   end
   return i
 elseif not marks[getchar(start)] then
   return 1
 else
   return 0
 end
end
local a_noligature=attributes.private("noligature")
local function toligature(head,start,stop,char,dataset,sequence,markflag,discfound)
 if getattr(start,a_noligature)==1 then
   return head,start
 end
 if start==stop and getchar(start)==char then
   resetinjection(start)
   setchar(start,char)
   return head,start
 end
 local components=getfield(start,"components")
 if components then
 end
 local prev=getprev(start)
 local next=getnext(stop)
 local comp=start
 setprev(start)
 setnext(stop)
 local base=copy_glyph(start)
 if start==head then
   head=base
 end
 resetinjection(base)
 setchar(base,char)
 setsubtype(base,ligature_code)
 setfield(base,"components",comp)
 if prev then
   setnext(prev,base)
 end
 if next then
   setprev(next,base)
 end
 setboth(base,prev,next)
 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=getchar(start)
     if not marks[char] then
       baseindex=baseindex+componentindex
       componentindex=getcomponentindex(start)
     elseif not deletemarks then
       setligaindex(start,baseindex+getligaindex(start,componentindex))
       if trace_marks then
         logwarning("%s: keep mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start))
       end
       local n=copy_node(start)
       copyinjection(n,start)
       head,current=insert_node_after(head,current,n)
     elseif trace_marks then
       logwarning("%s: delete mark %s",pref(dataset,sequence),gref(char))
     end
     start=getnext(start)
   end
   local start=getnext(current)
   while start do
     local char=ischar(start)
     if char then
       if marks[char] then
         setligaindex(start,baseindex+getligaindex(start,componentindex))
         if trace_marks then
           logwarning("%s: set mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start))
         end
         start=getnext(start)
       else
         break
       end
     else
       break
     end
   end
 else
   local discprev,discnext=getboth(discfound)
   if discprev and discnext then
     local pre,post,replace,pretail,posttail,replacetail=getdisc(discfound,true)
     if not replace then
       local prev=getprev(base)
       local current=comp
       local previous=nil
       local copied=nil
       while current do
         if getid(current)==glyph_code then
           local n=copy_node(current)
           if copied then
             setlink(previous,n)
           else
             copied=n
           end
           previous=n
         end
         current=getnext(current)
       end
       setprev(discnext)
       setnext(discprev)
       if pre then
         setlink(discprev,pre)
       end
       pre=comp
       if post then
         setlink(posttail,discnext)
         setprev(post)
       else
         post=discnext
       end
       setlink(prev,discfound)
       setlink(discfound,next)
       setboth(base)
       setfield(base,"components",copied)
       setdisc(discfound,pre,post,base)
       base=prev
     end
   end
 end
 return head,base
end
local function multiple_glyphs(head,start,multiple,ignoremarks,what)
 local nofmultiples=#multiple
 if nofmultiples>0 then
   resetinjection(start)
   setchar(start,multiple[1])
   if nofmultiples>1 then
     local sn=getnext(start)
     for k=2,nofmultiples do
       local n=copy_node(start)
       resetinjection(n)
       setchar(n,multiple[k])
       insert_node_after(head,start,n)
       start=n
     end
     if what==true then
     elseif what>1 then
       local m=multiple[nofmultiples]
       for i=2,what do
         local n=copy_node(start)
         resetinjection(n)
         setchar(n,m)
         insert_node_after(head,start,n)
         start=n
       end
     end
   end
   return head,start,true
 else
   if trace_multiples then
     logprocess("no multiple for %s",gref(getchar(start)))
   end
   return head,start,false
 end
end
local function get_alternative_glyph(start,alternatives,value)
 local n=#alternatives
 if value=="random" then
   local r=getrandom and getrandom("glyph",1,n) or 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)
 end
 value=value==true and 1 or tonumber(value)
 if type(value)~="number" then
   return alternatives[1],trace_alternatives and formatters["invalid value %s, taking %a"](value,1)
 end
 if 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 getchar(start),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
function handlers.gsub_single(head,start,dataset,sequence,replacement)
 if trace_singles then
   logprocess("%s: replacing %s by single %s",pref(dataset,sequence),gref(getchar(start)),gref(replacement))
 end
 resetinjection(start)
 setchar(start,replacement)
 return head,start,true
end
function handlers.gsub_alternate(head,start,dataset,sequence,alternative)
 local kind=dataset[4]
 local what=dataset[1]
 local value=what==true and tfmdata.shared.features[kind] or what
 local choice,comment=get_alternative_glyph(start,alternative,value)
 if choice then
   if trace_alternatives then
     logprocess("%s: replacing %s by alternative %a to %s, %s",pref(dataset,sequence),gref(getchar(start)),gref(choice),comment)
   end
   resetinjection(start)
   setchar(start,choice)
 else
   if trace_alternatives then
     logwarning("%s: no variant %a for %s, %s",pref(dataset,sequence),value,gref(getchar(start)),comment)
   end
 end
 return head,start,true
end
function handlers.gsub_multiple(head,start,dataset,sequence,multiple)
 if trace_multiples then
   logprocess("%s: replacing %s by multiple %s",pref(dataset,sequence),gref(getchar(start)),gref(multiple))
 end
 return multiple_glyphs(head,start,multiple,sequence.flags[1],dataset[1])
end
function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
 local current=getnext(start)
 if not current then
   return head,start,false,nil
 end
 local stop=nil
 local startchar=getchar(start)
 if marks[startchar] then
   while current do
     local char=ischar(current,currentfont)
     if char then
       local lg=ligature[char]
       if lg then
         stop=current
         ligature=lg
         current=getnext(current)
       else
         break
       end
     else
       break
     end
   end
   if stop then
     local lig=ligature.ligature
     if lig then
       if trace_ligatures then
         local stopchar=getchar(stop)
         head,start=markstoligature(head,start,stop,lig)
         logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(getchar(start)))
       else
         head,start=markstoligature(head,start,stop,lig)
       end
       return head,start,true,false
     else
     end
   end
 else
   local skipmark=sequence.flags[1]
   local discfound=false
   local lastdisc=nil
   while current do
     local char,id=ischar(current,currentfont)
     if char then
       if skipmark and marks[char] then
         current=getnext(current)
       else
         local lg=ligature[char]
         if lg then
           if not discfound and lastdisc then
             discfound=lastdisc
             lastdisc=nil
           end
           stop=current
           ligature=lg
           current=getnext(current)
         else
           break
         end
       end
     elseif char==false then
       break
     elseif id==disc_code then
       local replace=getfield(current,"replace")
       if replace then
         while replace do
           local char,id=ischar(replace,currentfont)
           if char then
             local lg=ligature[char]
             if lg then
               ligature=lg
               replace=getnext(replace)
             else
               return head,start,false,false
             end
           else
             return head,start,false,false
           end
         end
         stop=current
       end
       lastdisc=current
       current=getnext(current)
     else
       break
     end
   end
   local lig=ligature.ligature
   if lig then
     if stop then
       if trace_ligatures then
         local stopchar=getchar(stop)
         head,start=toligature(head,start,stop,lig,dataset,sequence,skipmark,discfound)
         logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(lig))
       else
         head,start=toligature(head,start,stop,lig,dataset,sequence,skipmark,discfound)
       end
     else
       resetinjection(start)
       setchar(start,lig)
       if trace_ligatures then
         logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(dataset,sequence),gref(startchar),gref(lig))
       end
     end
     return head,start,true,discfound
   else
   end
 end
 return head,start,false,discfound
end
function handlers.gpos_single(head,start,dataset,sequence,kerns,rlmode,step,i,injection)
 local startchar=getchar(start)
 if step.format=="pair" then
   local dx,dy,w,h=setpair(start,factor,rlmode,sequence.flags[4],kerns,injection)
   if trace_kerns then
     logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(dataset,sequence),gref(startchar),dx,dy,w,h)
   end
 else
   local k=setkern(start,factor,rlmode,kerns,injection)
   if trace_kerns then
     logprocess("%s: shifting single %s by %p",pref(dataset,sequence),gref(startchar),k)
   end
 end
 return head,start,false
end
function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,injection)
 local snext=getnext(start)
 if not snext then
   return head,start,false
 else
   local prev=start
   local done=false
   while snext do
     local nextchar=ischar(snext,currentfont)
     if nextchar then
       local krn=kerns[nextchar]
       if not krn and marks[nextchar] then
         prev=snext
         snext=getnext(snext)
       elseif not krn then
         break
       elseif step.format=="pair" then
         local a,b=krn[1],krn[2]
         if optimizekerns then
           if not b and a[1]==0 and a[2]==0 and a[4]==0 then
             local k=setkern(snext,factor,rlmode,a[3],injection)
             if trace_kerns then
               logprocess("%s: shifting single %s by %p",pref(dataset,sequence),gref(nextchar),k)
             end
             done=true
             break
           end
         end
         if a and #a>0 then
           local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,injection)
           if trace_kerns then
             local startchar=getchar(start)
             logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections")
           end
         end
         if b and #b>0 then
           local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,injection)
           if trace_kerns then
             local startchar=getchar(snext)
             logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections")
           end
         end
         done=true
         break
       elseif krn~=0 then
         local k=setkern(snext,factor,rlmode,krn,injection)
         if trace_kerns then
           logprocess("%s: inserting kern %p between %s and %s as %s",pref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar),injection or "injections")
         end
         done=true
         break
       else
         break
       end
     else
       break
     end
   end
   return head,start,done
 end
end
function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode)
 local markchar=getchar(start)
 if marks[markchar] then
   local base=getprev(start)
   if base then
     local basechar=ischar(base,currentfont)
     if basechar then
       if marks[basechar] then
         while base do
           base=getprev(base)
           if base then
             basechar=ischar(base,currentfont)
             if basechar then
               if not marks[basechar] then
                 break
               end
             else
               if trace_bugs then
                 logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1)
               end
               return head,start,false
             end
           else
             if trace_bugs then
               logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2)
             end
             return head,start,false
           end
         end
       end
       local ba=markanchors[1][basechar]
       if ba then
         local ma=markanchors[2]
         local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
         if trace_marks then
           logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)",
             pref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
         end
         return head,start,true
       end
     elseif trace_bugs then
       logwarning("%s: nothing preceding, case %i",pref(dataset,sequence),1)
     end
   elseif trace_bugs then
     logwarning("%s: nothing preceding, case %i",pref(dataset,sequence),2)
   end
 elseif trace_bugs then
   logwarning("%s: mark %s is no mark",pref(dataset,sequence),gref(markchar))
 end
 return head,start,false
end
function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlmode)
 local markchar=getchar(start)
 if marks[markchar] then
   local base=getprev(start)
   if base then
     local basechar=ischar(base,currentfont)
     if basechar then
       if marks[basechar] then
         while base do
           base=getprev(base)
           if base then
             basechar=ischar(base,currentfont)
             if basechar then
               if not marks[basechar] then
                 break
               end
             else
               if trace_bugs then
                 logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1)
               end
               return head,start,false
             end
           else
             if trace_bugs then
               logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2)
             end
             return head,start,false
           end
         end
       end
       local ba=markanchors[1][basechar]
       if ba then
         local ma=markanchors[2]
         if ma then
           local index=getligaindex(start)
           ba=ba[index]
           if ba then
             local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
             if trace_marks then
               logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)",
                 pref(dataset,sequence),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(dataset,sequence),gref(markchar),gref(basechar),index)
             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, case %i",pref(dataset,sequence),1)
     end
   elseif trace_bugs then
     logwarning("%s: prev node is no char, case %i",pref(dataset,sequence),2)
   end
 elseif trace_bugs then
   logwarning("%s: mark %s is no mark",pref(dataset,sequence),gref(markchar))
 end
 return head,start,false
end
function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode)
 local markchar=getchar(start)
 if marks[markchar] then
   local base=getprev(start)
   local slc=getligaindex(start)
   if slc then
     while base do
       local blc=getligaindex(base)
       if blc and blc~=slc then
         base=getprev(base)
       else
         break
       end
     end
   end
   if base then
     local basechar=ischar(base,currentfont)
     if basechar then
       local ba=markanchors[1][basechar]
       if ba then
         local ma=markanchors[2]
         local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks)
         if trace_marks then
           logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
             pref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
         end
         return head,start,true
       end
     end
   end
 elseif trace_bugs then
   logwarning("%s: mark %s is no mark",pref(dataset,sequence),gref(markchar))
 end
 return head,start,false
end
function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,step,i)
 local done=false
 local startchar=getchar(start)
 if marks[startchar] then
   if trace_cursive then
     logprocess("%s: ignoring cursive for mark %s",pref(dataset,sequence),gref(startchar))
   end
 else
   local nxt=getnext(start)
   while not done and nxt do
     local nextchar=ischar(nxt,currentfont)
     if not nextchar then
       break
     elseif marks[nextchar] then
       nxt=getnext(nxt)
     else
       local exit=exitanchors[3]
       if exit then
         local entry=exitanchors[1][nextchar]
         if entry then
           entry=entry[2]
           if entry then
             local dx,dy,bound=setcursive(start,nxt,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 %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,anchor,bound,mref(rlmode))
             end
             done=true
           end
         end
       end
       break
     end
   end
 end
 return head,start,done
end
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
local function reversesub(head,start,stop,dataset,sequence,replacements,rlmode)
 local char=getchar(start)
 local replacement=replacements[char]
 if replacement then
   if trace_singles then
     logprocess("%s: single reverse replacement of %s by %s",cref(dataset,sequence),gref(char),gref(replacement))
   end
   resetinjection(start)
   setchar(start,replacement)
   return head,start,true
 else
   return head,start,false
 end
end
chainprocs.reversesub=reversesub
local function reportmoresteps(dataset,sequence)
 logwarning("%s: more than 1 step",cref(dataset,sequence))
end
function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,chainindex)
 local steps=currentlookup.steps
 local nofsteps=currentlookup.nofsteps
 if nofsteps>1 then
   reportmoresteps(dataset,sequence)
 end
 local current=start
 while current do
   local currentchar=ischar(current)
   if currentchar then
     local replacement=steps[1].coverage[currentchar]
     if not replacement or replacement=="" then
       if trace_bugs then
         logwarning("%s: no single for %s",cref(dataset,sequence,chainindex),gref(currentchar))
       end
     else
       if trace_singles then
         logprocess("%s: replacing single %s by %s",cref(dataset,sequence,chainindex),gref(currentchar),gref(replacement))
       end
       resetinjection(current)
       setchar(current,replacement)
     end
     return head,start,true
   elseif currentchar==false then
     break
   elseif current==stop then
     break
   else
     current=getnext(current)
   end
 end
 return head,start,false
end
function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup)
 local steps=currentlookup.steps
 local nofsteps=currentlookup.nofsteps
 if nofsteps>1 then
   reportmoresteps(dataset,sequence)
 end
 local startchar=getchar(start)
 local replacement=steps[1].coverage[startchar]
 if not replacement or replacement=="" then
   if trace_bugs then
     logwarning("%s: no multiple for %s",cref(dataset,sequence),gref(startchar))
   end
 else
   if trace_multiples then
     logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement))
   end
   return multiple_glyphs(head,start,replacement,sequence.flags[1],dataset[1])
 end
 return head,start,false
end
function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlookup)
 local steps=currentlookup.steps
 local nofsteps=currentlookup.nofsteps
 if nofsteps>1 then
   reportmoresteps(dataset,sequence)
 end
 local kind=dataset[4]
 local what=dataset[1]
 local value=what==true and tfmdata.shared.features[kind] or what
 local current=start
 while current do
   local currentchar=ischar(current)
   if currentchar then
     local alternatives=steps[1].coverage[currentchar]
     if alternatives then
       local choice,comment=get_alternative_glyph(current,alternatives,value)
       if choice then
         if trace_alternatives then
           logprocess("%s: replacing %s by alternative %a to %s, %s",cref(dataset,sequence),gref(char),choice,gref(choice),comment)
         end
         resetinjection(start)
         setchar(start,choice)
       else
         if trace_alternatives then
           logwarning("%s: no variant %a for %s, %s",cref(dataset,sequence),value,gref(char),comment)
         end
       end
     end
     return head,start,true
   elseif currentchar==false then
     break
   elseif current==stop then
     break
   else
     current=getnext(current)
   end
 end
 return head,start,false
end
function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup,chainindex)
 local steps=currentlookup.steps
 local nofsteps=currentlookup.nofsteps
 if nofsteps>1 then
   reportmoresteps(dataset,sequence)
 end
 local startchar=getchar(start)
 local ligatures=steps[1].coverage[startchar]
 if not ligatures then
   if trace_bugs then
     logwarning("%s: no ligatures starting with %s",cref(dataset,sequence,chainindex),gref(startchar))
   end
 else
   local current=getnext(start)
   local discfound=false
   local last=stop
   local nofreplacements=1
   local skipmark=currentlookup.flags[1]
   while current do
     local id=getid(current)
     if id==disc_code then
       if not discfound then
         discfound=current
       end
       if current==stop then
         break
       else
         current=getnext(current)
       end
     else
       local schar=getchar(current)
       if skipmark and marks[schar] then
           current=getnext(current)
       else
         local lg=ligatures[schar]
         if lg then
           ligatures=lg
           last=current
           nofreplacements=nofreplacements+1
           if current==stop then
             break
           else
             current=getnext(current)
           end
         else
           break
         end
       end
     end
   end
   local ligature=ligatures.ligature
   if ligature 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(dataset,sequence,chainindex),gref(startchar),gref(ligature))
       else
         logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)),gref(ligature))
       end
     end
     head,start=toligature(head,start,stop,ligature,dataset,sequence,skipmark,discfound)
     return head,start,true,nofreplacements,discfound
   elseif trace_bugs then
     if start==stop then
       logwarning("%s: replacing character %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar))
     else
       logwarning("%s: replacing character %s upto %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)))
     end
   end
 end
 return head,start,false,0,false
end
function chainprocs.gpos_single(head,start,stop,dataset,sequence,currentlookup,rlmode,chainindex)
 local steps=currentlookup.steps
 local nofsteps=currentlookup.nofsteps
 if nofsteps>1 then
   reportmoresteps(dataset,sequence)
 end
 local startchar=getchar(start)
 local step=steps[1]
 local kerns=step.coverage[startchar]
 if not kerns then
 elseif step.format=="pair" then
   local dx,dy,w,h=setpair(start,factor,rlmode,sequence.flags[4],kerns)
   if trace_kerns then
     logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),dx,dy,w,h)
   end
 else
   local k=setkern(start,factor,rlmode,kerns,injection)
   if trace_kerns then
     logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k)
   end
 end
 return head,start,false
end
function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlmode,chainindex)
 local steps=currentlookup.steps
 local nofsteps=currentlookup.nofsteps
 if nofsteps>1 then
   reportmoresteps(dataset,sequence)
 end
 local snext=getnext(start)
 if snext then
   local startchar=getchar(start)
   local step=steps[1]
   local kerns=step.coverage[startchar]
   if kerns then
     local prev=start
     local done=false
     while snext do
       local nextchar=ischar(snext,currentfont)
       if not nextchar then
         break
       end
       local krn=kerns[nextchar]
       if not krn and marks[nextchar] then
         prev=snext
         snext=getnext(snext)
       elseif not krn then
         break
       elseif step.format=="pair" then
         local a,b=krn[1],krn[2]
         if optimizekerns then
           if not b and a[1]==0 and a[2]==0 and a[4]==0 then
             local k=setkern(snext,factor,rlmode,a[3],"injections")
             if trace_kerns then
               logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k)
             end
             done=true
             break
           end
         end
         if a and #a>0 then
           local startchar=getchar(start)
           local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,"injections")
           if trace_kerns then
             logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h)
           end
         end
         if b and #b>0 then
           local startchar=getchar(start)
           local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,"injections")
           if trace_kerns then
             logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h)
           end
         end
         done=true
         break
       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(dataset,sequence),k,gref(getchar(prev)),gref(nextchar))
         end
         done=true
         break
       else
         break
       end
     end
     return head,start,done
   end
 end
 return head,start,false
end
function chainprocs.gpos_mark2base(head,start,stop,dataset,sequence,currentlookup,rlmode)
 local steps=currentlookup.steps
 local nofsteps=currentlookup.nofsteps
 if nofsteps>1 then
   reportmoresteps(dataset,sequence)
 end
 local markchar=getchar(start)
 if marks[markchar] then
   local markanchors=steps[1].coverage[markchar]
   if markanchors then
     local base=getprev(start)
     if base then
       local basechar=ischar(base,currentfont)
       if basechar then
         if marks[basechar] then
           while base do
             base=getprev(base)
             if base then
               local basechar=ischar(base,currentfont)
               if basechar then
                 if not marks[basechar] then
                   break
                 end
               else
                 if trace_bugs then
                   logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1)
                 end
                 return head,start,false
               end
             else
               if trace_bugs then
                 logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2)
               end
               return head,start,false
             end
           end
         end
         local ba=markanchors[1][basechar]
         if ba then
           local ma=markanchors[2]
           if ma then
             local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
             if trace_marks then
               logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)",
                 cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
             end
             return head,start,true
           end
         end
       elseif trace_bugs then
         logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),1)
       end
     elseif trace_bugs then
       logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),2)
     end
   elseif trace_bugs then
     logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar))
   end
 elseif trace_bugs then
   logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar))
 end
 return head,start,false
end
function chainprocs.gpos_mark2ligature(head,start,stop,dataset,sequence,currentlookup,rlmode)
 local steps=currentlookup.steps
 local nofsteps=currentlookup.nofsteps
 if nofsteps>1 then
   reportmoresteps(dataset,sequence)
 end
 local markchar=getchar(start)
 if marks[markchar] then
   local markanchors=steps[1].coverage[markchar]
   if markanchors then
     local base=getprev(start)
     if base then
       local basechar=ischar(base,currentfont)
       if basechar then
         if marks[basechar] then
           while base do
             base=getprev(base)
             if base then
               local basechar=ischar(base,currentfont)
               if basechar then
                 if not marks[basechar] then
                   break
                 end
               else
                 if trace_bugs then
                   logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,1)
                 end
                 return head,start,false
               end
             else
               if trace_bugs then
                 logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,2)
               end
               return head,start,false
             end
           end
         end
         local ba=markanchors[1][basechar]
         if ba then
           local ma=markanchors[2]
           if ma then
             local index=getligaindex(start)
             ba=ba[index]
             if ba then
               local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
               if trace_marks then
                 logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)",
                   cref(dataset,sequence),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy)
               end
               return head,start,true
             end
           end
         end
       elseif trace_bugs then
         logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),1)
       end
     elseif trace_bugs then
       logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),2)
     end
   elseif trace_bugs then
     logwarning("%s, mark %s has no anchors",cref(dataset,sequence),gref(markchar))
   end
 elseif trace_bugs then
   logwarning("%s, mark %s is no mark",cref(dataset,sequence),gref(markchar))
 end
 return head,start,false
end
function chainprocs.gpos_mark2mark(head,start,stop,dataset,sequence,currentlookup,rlmode)
 local steps=currentlookup.steps
 local nofsteps=currentlookup.nofsteps
 if nofsteps>1 then
   reportmoresteps(dataset,sequence)
 end
 local markchar=getchar(start)
 if marks[markchar] then
   local markanchors=steps[1].coverage[markchar]
   if markanchors then
     local base=getprev(start)
     local slc=getligaindex(start)
     if slc then
       while base do
         local blc=getligaindex(base)
         if blc and blc~=slc then
           base=getprev(base)
         else
           break
         end
       end
     end
     if base then
       local basechar=ischar(base,currentfont)
       if basechar then
         local ba=markanchors[1][basechar]
         if ba then
           local ma=markanchors[2]
           if ma then
             local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks)
             if trace_marks then
               logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
                 cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
             end
             return head,start,true
           end
         end
       elseif trace_bugs then
         logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),1)
       end
     elseif trace_bugs then
       logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),2)
     end
   elseif trace_bugs then
     logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar))
   end
 elseif trace_bugs then
   logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar))
 end
 return head,start,false
end
function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup,rlmode)
 local steps=currentlookup.steps
 local nofsteps=currentlookup.nofsteps
 if nofsteps>1 then
   reportmoresteps(dataset,sequence)
 end
 local startchar=getchar(start)
 local exitanchors=steps[1].coverage[startchar]
 if exitanchors then
   local done=false
   if marks[startchar] then
     if trace_cursive then
       logprocess("%s: ignoring cursive for mark %s",pref(dataset,sequence),gref(startchar))
     end
   else
     local nxt=getnext(start)
     while not done and nxt do
       local nextchar=ischar(nxt,currentfont)
       if not nextchar then
         break
       elseif marks[nextchar] then
         nxt=getnext(nxt)
       else
         local exit=exitanchors[3]
         if exit then
           local entry=exitanchors[1][nextchar]
           if entry then
             entry=entry[2]
             if entry then
               local dx,dy,bound=setcursive(start,nxt,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 %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,anchor,bound,mref(rlmode))
               end
               done=true
               break
             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(dataset,sequence),gref(getchar(start)),alreadydone)
   end
   return head,start,false
 end
end
local function show_skip(dataset,sequence,char,ck,class)
 logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(dataset,sequence),gref(char),class,ck[1],ck[8] or ck[2])
end
local new_kern=nuts.pool.kern
local function checked(head)
 local current=head
 while current do
   if getid(current)==glue_code then
     local kern=new_kern(getfield(current,"width"))
     if head==current then
       local next=getnext(current)
       if next then
         setlink(kern,next)
       end
       flush_node(current)
       head=kern
       current=next
     else
       local prev,next=getboth(current)
       setlink(prev,kern)
       setlink(kern,next)
       flush_node(current)
       current=next
     end
   else
     current=getnext(current)
   end
 end
 return head
end
local function setdiscchecked(d,pre,post,replace)
 if pre   then pre=checked(pre)   end
 if post  then post=checked(post)  end
 if replace then replace=checked(replace) end
 setdisc(d,pre,post,replace)
end
local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,ck,chainproc)
 if not start then
   return head,start,false
 end
 local startishead=start==head
 local seq=ck[3]
 local f=ck[4]
 local l=ck[5]
 local s=#seq
 local done=false
 local sweepnode=sweepnode
 local sweeptype=sweeptype
 local sweepoverflow=false
 local checkdisc=getprev(head)
 local keepdisc=not sweepnode
 local lookaheaddisc=nil
 local backtrackdisc=nil
 local current=start
 local last=start
 local prev=getprev(start)
 local hasglue=false
 local i=f
 while i<=l do
   local id=getid(current)
   if id==glyph_code then
     i=i+1
     last=current
     current=getnext(current)
   elseif id==glue_code then
     i=i+1
     last=current
     current=getnext(current)
     hasglue=true
   elseif id==disc_code then
     if keepdisc then
       keepdisc=false
       if notmatchpre[current]~=notmatchreplace[current] then
         lookaheaddisc=current
       end
       local replace=getfield(current,"replace")
       while replace and i<=l do
         if getid(replace)==glyph_code then
           i=i+1
         end
         replace=getnext(replace)
       end
       last=current
       current=getnext(c)
     else
       head,current=flattendisk(head,current)
     end
   else
     last=current
     current=getnext(current)
   end
   if current then
   elseif sweepoverflow then
     break
   elseif sweeptype=="post" or sweeptype=="replace" then
     current=getnext(sweepnode)
     if current then
       sweeptype=nil
       sweepoverflow=true
     else
       break
     end
   else
     break
   end
 end
 if sweepoverflow then
   local prev=current and getprev(current)
   if not current or prev~=sweepnode then
     local head=getnext(sweepnode)
     local tail=nil
     if prev then
       tail=prev
       setprev(current,sweepnode)
     else
       tail=find_node_tail(head)
     end
     setnext(sweepnode,current)
     setprev(head)
     setnext(tail)
     appenddisc(sweepnode,head)
   end
 end
 if l<s then
   local i=l
   local t=sweeptype=="post" or sweeptype=="replace"
   while current and i<s do
     local id=getid(current)
     if id==glyph_code then
       i=i+1
       current=getnext(current)
     elseif id==glue_code then
       i=i+1
       current=getnext(current)
       hasglue=true
     elseif id==disc_code then
       if keepdisc then
         keepdisc=false
         if notmatchpre[current]~=notmatchreplace[current] then
           lookaheaddisc=current
         end
         local replace=getfield(c,"replace")
         while replace and i<s do
           if getid(replace)==glyph_code then
             i=i+1
           end
           replace=getnext(replace)
         end
         current=getnext(current)
       elseif notmatchpre[current]~=notmatchreplace[current] then
         head,current=flattendisk(head,current)
       else
         current=getnext(current)
       end
     else
       current=getnext(current)
     end
     if not current and t then
       current=getnext(sweepnode)
       if current then
         sweeptype=nil
       end
     end
   end
 end
 if f>1 then
   local current=prev
   local i=f
   local t=sweeptype=="pre" or sweeptype=="replace"
   if not current and t and current==checkdisk then
     current=getprev(sweepnode)
   end
   while current and i>1 do
     local id=getid(current)
     if id==glyph_code then
       i=i-1
     elseif id==glue_code then
       i=i-1
       hasglue=true
     elseif id==disc_code then
       if keepdisc then
         keepdisc=false
         if notmatchpost[current]~=notmatchreplace[current] then
           backtrackdisc=current
         end
         local replace=getfield(current,"replace")
         while replace and i>1 do
           if getid(replace)==glyph_code then
             i=i-1
           end
           replace=getnext(replace)
         end
       elseif notmatchpost[current]~=notmatchreplace[current] then
         head,current=flattendisk(head,current)
       end
     end
     current=getprev(current)
     if t and current==checkdisk then
       current=getprev(sweepnode)
     end
   end
 end
 local ok=false
 if lookaheaddisc then
   local cf=start
   local cl=getprev(lookaheaddisc)
   local cprev=getprev(start)
   local insertedmarks=0
   while cprev do
     local char=ischar(cf,currentfont)
     if char and marks[char] then
       insertedmarks=insertedmarks+1
       cf=cprev
       startishead=cf==head
       cprev=getprev(cprev)
     else
       break
     end
   end
   setprev(lookaheaddisc,cprev)
   if cprev then
     setnext(cprev,lookaheaddisc)
   end
   setprev(cf)
   setnext(cl)
   if startishead then
     head=lookaheaddisc
   end
   local pre,post,replace=getdisc(lookaheaddisc)
   local new=copy_node_list(cf)
   local cnew=new
   for i=1,insertedmarks do
     cnew=getnext(cnew)
   end
   local clast=cnew
   for i=f,l do
     clast=getnext(clast)
   end
   if not notmatchpre[lookaheaddisc] then
     cf,start,ok=chainproc(cf,start,last,dataset,sequence,chainlookup,rlmode,k)
   end
   if not notmatchreplace[lookaheaddisc] then
     new,cnew,ok=chainproc(new,cnew,clast,dataset,sequence,chainlookup,rlmode,k)
   end
   if pre then
     setlink(cl,pre)
   end
   if replace then
     local tail=find_node_tail(new)
     setlink(tail,replace)
   end
   if hasglue then
     setdiscchecked(lookaheaddisc,cf,post,new)
   else
     setdisc(lookaheaddisc,cf,post,new)
   end
   start=getprev(lookaheaddisc)
   sweephead[cf]=getnext(clast)
   sweephead[new]=getnext(last)
 elseif backtrackdisc then
   local cf=getnext(backtrackdisc)
   local cl=start
   local cnext=getnext(start)
   local insertedmarks=0
   while cnext do
     local char=ischar(cnext,currentfont)
     if char and marks[char] then
       insertedmarks=insertedmarks+1
       cl=cnext
       cnext=getnext(cnext)
     else
       break
     end
   end
   if cnext then
     setprev(cnext,backtrackdisc)
   end
   setnext(backtrackdisc,cnext)
   setprev(cf)
   setnext(cl)
   local pre,post,replace,pretail,posttail,replacetail=getdisc(backtrackdisc,true)
   local new=copy_node_list(cf)
   local cnew=find_node_tail(new)
   for i=1,insertedmarks do
     cnew=getprev(cnew)
   end
   local clast=cnew
   for i=f,l do
     clast=getnext(clast)
   end
   if not notmatchpost[backtrackdisc] then
     cf,start,ok=chainproc(cf,start,last,dataset,sequence,chainlookup,rlmode,k)
   end
   if not notmatchreplace[backtrackdisc] then
     new,cnew,ok=chainproc(new,cnew,clast,dataset,sequence,chainlookup,rlmode,k)
   end
   if post then
     setlink(posttail,cf)
   else
     post=cf
   end
   if replace then
     setlink(replacetail,new)
   else
     replace=new
   end
   if hasglue then
     setdiscchecked(backtrackdisc,pre,post,replace)
   else
     setdisc(backtrackdisc,pre,post,replace)
   end
   start=getprev(backtrackdisc)
   sweephead[post]=getnext(clast)
   sweephead[replace]=getnext(last)
 else
   head,start,ok=chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,k)
 end
 return head,start,ok
end
local noflags={ false,false,false,false }
local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
 local sweepnode=sweepnode
 local sweeptype=sweeptype
 local currentfont=currentfont
 local diskseen=false
 local checkdisc=getprev(head)
 local flags=sequence.flags or noflags
 local done=false
 local skipmark=flags[1]
 local skipligature=flags[2]
 local skipbase=flags[3]
 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
   local size=1
   if s==1 then
     local char=ischar(current,currentfont)
     if char then
       match=seq[1][char]
     end
   else
     local f=ck[4]
     local l=ck[5]
     size=l-f+1
     if size>1 then
       local discfound=nil
       local n=f+1
       last=getnext(last)
       while n<=l do
         if not last and (sweeptype=="post" or sweeptype=="replace") then
           last=getnext(sweepnode)
           sweeptype=nil
         end
         if last then
           local char,id=ischar(last,currentfont)
           if char then
             local ccd=descriptions[char]
             if ccd then
               local class=ccd.class or "base"
               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(dataset,sequence,char,ck,class)
                 end
                 last=getnext(last)
               elseif seq[n][char] then
                 if n<l then
                   last=getnext(last)
                 end
                 n=n+1
               else
                 if discfound then
                   notmatchreplace[discfound]=true
                   match=not notmatchpre[discfound]
                 else
                   match=false
                 end
                 break
               end
             else
               if discfound then
                 notmatchreplace[discfound]=true
                 match=not notmatchpre[discfound]
               else
                 match=false
               end
               break
             end
           elseif char==false then
             if discfound then
               notmatchreplace[discfound]=true
               match=not notmatchpre[discfound]
             else
               match=false
             end
             break
           elseif id==disc_code then
             diskseen=true
             discfound=last
             notmatchpre[last]=nil
             notmatchpost[last]=true
             notmatchreplace[last]=nil
             local pre,post,replace=getdisc(last)
             if pre then
               local n=n
               while pre do
                 if seq[n][getchar(pre)] then
                   n=n+1
                   pre=getnext(pre)
                   if n>l then
                     break
                   end
                 else
                   notmatchpre[last]=true
                   break
                 end
               end
               if n<=l then
                 notmatchpre[last]=true
               end
             else
               notmatchpre[last]=true
             end
             if replace then
               while replace do
                 if seq[n][getchar(replace)] then
                   n=n+1
                   replace=getnext(replace)
                   if n>l then
                     break
                   end
                 else
                   notmatchreplace[last]=true
                   match=not notmatchpre[last]
                   break
                 end
               end
               match=not notmatchpre[last]
             end
             last=getnext(last)
           else
             match=false
             break
           end
         else
           match=false
           break
         end
       end
     end
     if match and f>1 then
       local prev=getprev(start)
       if prev then
         if prev==checkdisc and (sweeptype=="pre" or sweeptype=="replace") then
           prev=getprev(sweepnode)
         end
         if prev then
           local discfound=nil
           local n=f-1
           while n>=1 do
             if prev then
               local char,id=ischar(prev,currentfont)
               if char then
                 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(dataset,sequence,char,ck,class)
                     end
                     prev=getprev(prev)
                   elseif seq[n][char] then
                     if n>1 then
                       prev=getprev(prev)
                     end
                     n=n-1
                   else
                     if discfound then
                       notmatchreplace[discfound]=true
                       match=not notmatchpost[discfound]
                     else
                       match=false
                     end
                     break
                   end
                 else
                   if discfound then
                     notmatchreplace[discfound]=true
                     match=not notmatchpost[discfound]
                   else
                     match=false
                   end
                   break
                 end
               elseif char==false then
                 if discfound then
                   notmatchreplace[discfound]=true
                   match=not notmatchpost[discfound]
                 else
                   match=false
                 end
                 break
               elseif id==disc_code then
                 diskseen=true
                 discfound=prev
                 notmatchpre[prev]=true
                 notmatchpost[prev]=nil
                 notmatchreplace[prev]=nil
                 local pre,post,replace,pretail,posttail,replacetail=getdisc(prev,true)
                 if pre~=start and post~=start and replace~=start then
                   if post then
                     local n=n
                     while posttail do
                       if seq[n][getchar(posttail)] then
                         n=n-1
                         if posttail==post then
                           break
                         else
                           posttail=getprev(posttail)
                           if n<1 then
                             break
                           end
                         end
                       else
                         notmatchpost[prev]=true
                         break
                       end
                     end
                     if n>=1 then
                       notmatchpost[prev]=true
                     end
                   else
                     notmatchpost[prev]=true
                   end
                   if replace then
                     while replacetail do
                       if seq[n][getchar(replacetail)] then
                         n=n-1
                         if replacetail==replace then
                           break
                         else
                           replacetail=getprev(replacetail)
                           if n<1 then
                             break
                           end
                         end
                       else
                         notmatchreplace[prev]=true
                         match=not notmatchpost[prev]
                         break
                       end
                     end
                     if not match then
                       break
                     end
                   end
                 end
                 prev=getprev(prev)
               elseif seq[n][32] and isspace(prev,threshold) then
                 n=n-1
                 prev=getprev(prev)
               else
                 match=false
                 break
               end
             else
               match=false
               break
             end
           end
         else
           match=false
         end
       else
         match=false
       end
     end
     if match and s>l then
       local current=last and getnext(last)
       if not current then
         if sweeptype=="post" or sweeptype=="replace" then
           current=getnext(sweepnode)
         end
       end
       if current then
         local discfound=nil
         local n=l+1
         while n<=s do
           if current then
             local char,id=ischar(current,currentfont)
             if char then
               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(dataset,sequence,char,ck,class)
                   end
                   current=getnext(current)
                 elseif seq[n][char] then
                   if n<s then
                     current=getnext(current)
                   end
                   n=n+1
                 else
                   if discfound then
                     notmatchreplace[discfound]=true
                     match=not notmatchpre[discfound]
                   else
                     match=false
                   end
                   break
                 end
               else
                 if discfound then
                   notmatchreplace[discfound]=true
                   match=not notmatchpre[discfound]
                 else
                   match=false
                 end
                 break
               end
             elseif char==false then
               if discfound then
                 notmatchreplace[discfound]=true
                 match=not notmatchpre[discfound]
               else
                 match=false
               end
               break
             elseif id==disc_code then
               diskseen=true
               discfound=current
               notmatchpre[current]=nil
               notmatchpost[current]=true
               notmatchreplace[current]=nil
               local pre,post,replace=getdisc(current)
               if pre then
                 local n=n
                 while pre do
                   if seq[n][getchar(pre)] then
                     n=n+1
                     pre=getnext(pre)
                     if n>s then
                       break
                     end
                   else
                     notmatchpre[current]=true
                     break
                   end
                 end
                 if n<=s then
                   notmatchpre[current]=true
                 end
               else
                 notmatchpre[current]=true
               end
               if replace then
                 while replace do
                   if seq[n][getchar(replace)] then
                     n=n+1
                     replace=getnext(replace)
                     if n>s then
                       break
                     end
                   else
                     notmatchreplace[current]=true
                     match=notmatchpre[current]
                     break
                   end
                 end
                 if not match then
                   break
                 end
               else
               end
               current=getnext(current)
             elseif seq[n][32] and isspace(current,threshold) then
               n=n+1
               current=getnext(current)
             else
               match=false
               break
             end
           else
             match=false
             break
           end
         end
       else
         match=false
       end
     end
   end
   if match then
     local diskchain=diskseen or sweepnode
     if trace_contexts then
       local rule=ck[1]
       local lookuptype=ck[8] or ck[2]
       local first=ck[4]
       local last=ck[5]
       local char=getchar(start)
       logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a",
         cref(dataset,sequence),rule,gref(char),first-1,last-first+1,s-last,lookuptype)
     end
     local chainlookups=ck[6]
     if chainlookups then
       local nofchainlookups=#chainlookups
       if size==1 then
         local chainlookup=chainlookups[1]
         local chainkind=chainlookup.type
         local chainproc=chainprocs[chainkind]
         if chainproc then
           local ok
           if diskchain then
             head,start,ok=chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,1,ck,chainproc)
           else
             head,start,ok=chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,1)
           end
           if ok then
             done=true
           end
         else
           logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind)
         end
        else
         local i=1
         while start do
           if skipped then
             while start do
               local char=getchar(start)
               local ccd=descriptions[char]
               if ccd then
                 local class=ccd.class or "base"
                 if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then
                   start=getnext(start)
                 else
                   break
                 end
               else
                 break
               end
             end
           end
           local chainlookup=chainlookups[i]
           if chainlookup then
             local chainkind=chainlookup.type
             local chainproc=chainprocs[chainkind]
             if chainproc then
               local ok,n
               if diskchain then
                 head,start,ok=chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,i,ck,chainproc)
               else
                 head,start,ok,n=chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,i)
               end
               if ok then
                 done=true
                 if n and n>1 and i+n>nofchainlookups then
                   break
                 end
               end
             else
               logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind)
             end
           end
           i=i+1
           if i>size or not start then
             break
           elseif start then
             start=getnext(start)
           end
         end
       end
     else
       local replacements=ck[7]
       if replacements then
         head,start,done=reversesub(head,start,last,dataset,sequence,replacements,rlmode)
       else
         done=true
         if trace_contexts then
           logprocess("%s: skipping match",cref(dataset,sequence))
         end
       end
     end
     if done then
       break
     end
   end
 end
 if diskseen then
   notmatchpre={}
   notmatchpost={}
   notmatchreplace={}
 end
 return head,start,done
end
handlers.gsub_context=handle_contextchain
handlers.gsub_contextchain=handle_contextchain
handlers.gsub_reversecontextchain=handle_contextchain
handlers.gpos_contextchain=handle_contextchain
handlers.gpos_context=handle_contextchain
local function chained_contextchain(head,start,stop,dataset,sequence,currentlookup,rlmode)
 local steps=currentlookup.steps
 local nofsteps=currentlookup.nofsteps
 if nofsteps>1 then
   reportmoresteps(dataset,sequence)
 end
 return handle_contextchain(head,start,dataset,sequence,currentlookup,rlmode)
end
chainprocs.gsub_context=chained_contextchain
chainprocs.gsub_contextchain=chained_contextchain
chainprocs.gsub_reversecontextchain=chained_contextchain
chainprocs.gpos_contextchain=chained_contextchain
chainprocs.gpos_context=chained_contextchain
local missing=setmetatableindex("table")
local function logprocess(...)
 if trace_steps then
   registermessage(...)
 end
 report_process(...)
end
local logwarning=report_process
local function report_missing_coverage(dataset,sequence)
 local t=missing[currentfont]
 if not t[sequence] then
   t[sequence]=true
   logwarning("missing coverage for feature %a, lookup %a, type %a, font %a, name %a",
     dataset[4],sequence.name,sequence.type,currentfont,tfmdata.properties.fullname)
 end
end
local resolved={}
local sequencelists=setmetatableindex(function(t,font)
 local sequences=fontdata[font].resources.sequences
 if not sequences or not next(sequences) then
   sequences=false
 end
 t[font]=sequences
 return sequences
end)
local autofeatures=fonts.analyzers.features
local featuretypes=otf.tables.featuretypes
local defaultscript=otf.features.checkeddefaultscript
local defaultlanguage=otf.features.checkeddefaultlanguage
local function initialize(sequence,script,language,enabled,autoscript,autolanguage)
 local features=sequence.features
 if features then
   local order=sequence.order
   if order then
     local featuretype=featuretypes[sequence.type or "unknown"]
     for i=1,#order do
       local kind=order[i]
       local valid=enabled[kind]
       if valid then
         local scripts=features[kind]
         local languages=scripts and (
           scripts[script] or
           scripts[wildcard] or
           (autoscript and defaultscript(featuretype,autoscript,scripts))
         )
         local enabled=languages and (
           languages[language] or
           languages[wildcard] or
           (autolanguage and defaultlanguage(featuretype,autolanguage,languages))
         )
         if enabled then
           return { valid,autofeatures[kind] or false,sequence,kind }
         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 autoscript=enabled and enabled.autoscript
 local autolanguage=enabled and enabled.autolanguage
 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
   if sequences then
     for s=1,#sequences do
       local v=enabled and initialize(sequences[s],script,language,enabled,autoscript,autolanguage)
       if v then
         rl[#rl+1]=v
       end
     end
   end
 end
 return rl
end
local function report_disc(what,n)
 report_run("%s: %s > %s",what,n,languages.serializediscretionary(n))
end
local function kernrun(disc,k_run,font,attr,...)
 if trace_kernruns then
   report_disc("kern",disc)
 end
 local prev,next=getboth(disc)
 local nextstart=next
 local done=false
 local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true)
 local prevmarks=prev
 while prevmarks do
   local char=ischar(prevmarks,font)
   if char and marks[char] then
     prevmarks=getprev(prevmarks)
   else
     break
   end
 end
 if prev and not ischar(prev,font) then
   prev=false
 end
 if next and not ischar(next,font) then
   next=false
 end
 if pre then
   if k_run(pre,"injections",nil,font,attr,...) then
     done=true
   end
   if prev then
     local nest=getprev(pre)
     setlink(prev,pre)
     if k_run(prevmarks,"preinjections",pre,font,attr,...) then
       done=true
     end
     setprev(pre,nest)
     setnext(prev,disc)
   end
 end
 if post then
   if k_run(post,"injections",nil,font,attr,...) then
     done=true
   end
   if next then
     setlink(posttail,next)
     if k_run(posttail,"postinjections",next,font,attr,...) then
       done=true
     end
     setnext(posttail)
     setprev(next,disc)
   end
 end
 if replace then
   if k_run(replace,"injections",nil,font,attr,...) then
     done=true
   end
   if prev then
     local nest=getprev(replace)
     setlink(prev,replace)
     if k_run(prevmarks,"replaceinjections",replace,font,attr,...) then
       done=true
     end
     setprev(replace,nest)
     setnext(prev,disc)
   end
   if next then
     setlink(replacetail,next)
     if k_run(replacetail,"replaceinjections",next,font,attr,...) then
       done=true
     end
     setnext(replacetail)
     setprev(next,disc)
   end
 elseif prev and next then
   setlink(prev,next)
   if k_run(prevmarks,"emptyinjections",next,font,attr,...) then
     done=true
   end
   setlink(prev,disc)
   setlink(disc,next)
 end
 return nextstart,done
end
local function comprun(disc,c_run,...)
 if trace_compruns then
   report_disc("comp",disc)
 end
 local pre,post,replace=getdisc(disc)
 local renewed=false
 if pre then
   sweepnode=disc
   sweeptype="pre"
   local new,done=c_run(pre,...)
   if done then
     pre=new
     renewed=true
   end
 end
 if post then
   sweepnode=disc
   sweeptype="post"
   local new,done=c_run(post,...)
   if done then
     post=new
     renewed=true
   end
 end
 if replace then
   sweepnode=disc
   sweeptype="replace"
   local new,done=c_run(replace,...)
   if done then
     replace=new
     renewed=true
   end
 end
 sweepnode=nil
 sweeptype=nil
 if renewed then
   setdisc(disc,pre,post,replace)
 end
 return getnext(disc),renewed
end
local function testrun(disc,t_run,c_run,...)
 if trace_testruns then
   report_disc("test",disc)
 end
 local prev,next=getboth(disc)
 if not next then
   return
 end
 local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true)
 local done=false
 if replace and prev then
   setlink(replacetail,next)
   local ok,overflow=t_run(replace,next,...)
   if ok and overflow then
     setfield(disc,"replace")
     setlink(prev,replace)
     setboth(disc)
     flush_node_list(disc)
     return replace,true
   else
     setnext(replacetail)
     setprev(next,disc)
   end
 end
 local renewed=false
 if pre then
   sweepnode=disc
   sweeptype="pre"
   local new,ok=c_run(pre,...)
   if ok then
     pre=new
     renewed=true
   end
 end
 if post then
   sweepnode=disc
   sweeptype="post"
   local new,ok=c_run(post,...)
   if ok then
     post=new
     renewed=true
   end
 end
 if replace then
   sweepnode=disc
   sweeptype="replace"
   local new,ok=c_run(replace,...)
   if ok then
     replace=new
     renewed=true
   end
 end
 sweepnode=nil
 sweeptype=nil
 if renewed then
   setdisc(disc,pre,post,replace)
   return next,true
 else
   return next,done
 end
end
local nesting=0
local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
 local done=false
 local sweep=sweephead[head]
 if sweep then
   start=sweep
   sweephead[head]=nil
 else
   start=head
 end
 while start do
   local char=ischar(start,font)
   if char then
     local a=attr and getattr(start,0)
     if not a or (a==attr) then
       local lookupmatch=lookupcache[char]
       if lookupmatch then
         local ok
         head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1)
         if ok then
           done=true
         end
       end
       if start then
         start=getnext(start)
       end
     else
       start=getnext(start)
     end
   elseif char==false then
     return head,done
   elseif sweep then
     return head,done
   else
     start=getnext(start)
   end
 end
 return head,done
end
local function t_run_single(start,stop,font,attr,lookupcache)
 while start~=stop do
   local char=ischar(start,font)
   if char then
     local a=attr and getattr(start,0)
     if not a or (a==attr) then
       local lookupmatch=lookupcache[char]
       if lookupmatch then
         local s=getnext(start)
         local l=nil
         local d=0
         while s do
           if s==stop then
             d=1
           elseif d>0 then
             d=d+1
           end
           local lg=lookupmatch[getchar(s)]
           if lg then
             l=lg
             s=getnext(s)
           else
             break
           end
         end
         if l and l.ligature then
           return true,d>1
         end
       end
     else
     end
     start=getnext(start)
   else
     break
   end
 end
end
local function k_run_single(sub,injection,last,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
 local a=attr and getattr(sub,0)
 if not a or (a==attr) then
   for n in traverse_nodes(sub) do
     if n==last then
       break
     end
     local char=ischar(n)
     if char then
       local lookupmatch=lookupcache[char]
       if lookupmatch then
         local h,d,ok=handler(sub,n,dataset,sequence,lookupmatch,rlmode,step,1,injection)
         if ok then
           return true
         end
       end
     end
   end
 end
end
local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
 local done=false
 local sweep=sweephead[head]
 if sweep then
   start=sweep
   sweephead[head]=nil
 else
   start=head
 end
 while start do
   local char=ischar(start,font)
   if char then
     local a=attr and getattr(start,0)
     if not a or (a==attr) then
       for i=1,nofsteps do
         local step=steps[i]
         local lookupcache=step.coverage
         if lookupcache then
           local lookupmatch=lookupcache[char]
           if lookupmatch then
             local ok
             head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
             if ok then
               done=true
               break
             elseif not start then
               break
             end
           end
         else
           report_missing_coverage(dataset,sequence)
         end
       end
       if start then
         start=getnext(start)
       end
     else
       start=getnext(start)
     end
   elseif char==false then
     return head,done
   elseif sweep then
     return head,done
   else
     start=getnext(start)
   end
 end
 return head,done
end
local function t_run_multiple(start,stop,font,attr,steps,nofsteps)
 while start~=stop do
   local char=ischar(start,font)
   if char then
     local a=attr and getattr(start,0)
     if not a or (a==attr) then
       for i=1,nofsteps do
         local step=steps[i]
         local lookupcache=step.coverage
         if lookupcache then
           local lookupmatch=lookupcache[char]
           if lookupmatch then
             local s=getnext(start)
             local l=nil
             local d=0
             while s do
               if s==stop then
                 d=1
               elseif d>0 then
                 d=d+1
               end
               local lg=lookupmatch[getchar(s)]
               if lg then
                 l=lg
                 s=getnext(s)
               else
                 break
               end
             end
             if l and l.ligature then
               return true,d>1
             end
           end
         else
           report_missing_coverage(dataset,sequence)
         end
       end
     else
     end
     start=getnext(start)
   else
     break
   end
 end
end
local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
 local a=attr and getattr(sub,0)
 if not a or (a==attr) then
   for n in traverse_nodes(sub) do
     if n==last then
       break
     end
     local char=ischar(n)
     if char then
       for i=1,nofsteps do
         local step=steps[i]
         local lookupcache=step.coverage
         if lookupcache then
           local lookupmatch=lookupcache[char]
           if lookupmatch then
             local h,d,ok=handler(head,n,dataset,sequence,lookupmatch,step,rlmode,i,injection)
             if ok then
               return true
             end
           end
         else
           report_missing_coverage(dataset,sequence)
         end
       end
     end
   end
 end
end
local function txtdirstate(start,stack,top,rlparmode)
 local dir=getfield(start,"dir")
 local new=1
 if dir=="+TRT" then
   top=top+1
   stack[top]=dir
   new=-1
 elseif dir=="+TLT" then
   top=top+1
   stack[top]=dir
 elseif dir=="-TRT" or dir=="-TLT" then
   top=top-1
   if stack[top]=="+TRT" then
     new=-1
   end
 else
   new=rlparmode
 end
 if trace_directions then
   report_process("directions after txtdir %a: parmode %a, txtmode %a, level %a",dir,mref(rlparmode),mref(new),top)
 end
 return getnext(start),top,new
end
local function pardirstate(start)
 local dir=getfield(start,"dir")
 local new=0
 if dir=="TLT" then
   new=1
 elseif dir=="TRT" then
   new=-1
 end
 if trace_directions then
   report_process("directions after pardir %a: parmode %a",dir,mref(new))
 end
 return getnext(start),new,new
end
otf.helpers=otf.helpers or {}
otf.helpers.txtdirstate=txtdirstate
otf.helpers.pardirstate=pardirstate
local function featuresprocessor(head,font,attr)
 local sequences=sequencelists[font]
 if not sequencelists then
   return head,false
 end
 nesting=nesting+1
 if nesting==1 then
   currentfont=font
   tfmdata=fontdata[font]
   descriptions=tfmdata.descriptions
   characters=tfmdata.characters
   marks=tfmdata.resources.marks
   threshold,
   factor=getthreshold(font)
   checkmarks=tfmdata.properties.checkmarks
 elseif currentfont~=font then
   report_warning("nested call with a different font, level %s, quitting",nesting)
   nesting=nesting-1
   return head,false
 end
 head=tonut(head)
 if trace_steps then
   checkstep(head)
 end
 local rlmode=0
 local done=false
 local datasets=otf.dataset(tfmdata,font,attr)
 local forcedisc=alwaysdisc or not attr
 local dirstack={}
 sweephead={}
 for s=1,#datasets do
   local dataset=datasets[s]
   local attribute=dataset[2]
   local sequence=dataset[3]
   local rlparmode=0
   local topstack=0
   local success=false
   local typ=sequence.type
   local gpossing=typ=="gpos_single" or typ=="gpos_pair"
   local handler=handlers[typ]
   local steps=sequence.steps
   local nofsteps=sequence.nofsteps
   if not steps then
     local h,d,ok=handler(head,head,dataset,sequence,nil,nil,nil,0,font,attr)
     if ok then
       success=true
       if h then
         head=h
       end
     end
   elseif typ=="gsub_reversecontextchain" then
     local start=find_node_tail(head)
     while start do
       local char=ischar(start,font)
       if char then
         local a=attr and getattr(start,0)
         if not a or (a==attr) then
           for i=1,nofsteps do
             local step=steps[i]
             local lookupcache=step.coverage
             if lookupcache then
               local lookupmatch=lookupcache[char]
               if lookupmatch then
                 local ok
                 head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
                 if ok then
                   success=true
                   break
                 end
               end
             else
               report_missing_coverage(dataset,sequence)
             end
           end
           if start then
             start=getprev(start)
           end
         else
           start=getprev(start)
         end
       else
         start=getprev(start)
       end
     end
   else
     local start=head
     rlmode=0
     if nofsteps==1 then
       local step=steps[1]
       local lookupcache=step.coverage
       if not lookupcache then
         report_missing_coverage(dataset,sequence)
       else
         while start do
           local char,id=ischar(start,font)
           if char then
             local a=attr and getattr(start,0)
             if a then
               a=(a==attr) and (not attribute or getprop(start,a_state)==attribute)
             else
               a=not attribute or getprop(start,a_state)==attribute
             end
             if a then
               local lookupmatch=lookupcache[char]
               if lookupmatch then
                 local ok
                 head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1)
                 if ok then
                   success=true
                 end
               end
               if start then
                 start=getnext(start)
               end
             else
               start=getnext(start)
             end
           elseif char==false then
             start=getnext(start)
           elseif id==disc_code then
             local a=forcedisc or getsubtype(start)==discretionary_code or getattr(start,0)==attr
             if a then
               local ok
               if gpossing then
                 start,ok=kernrun(start,k_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
               elseif typ=="gsub_ligature" then
                 start,ok=testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
               else
                 start,ok=comprun(start,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
               end
               if ok then
                 success=true
               end
             else
               start=getnext(start)
             end
           elseif id==math_code then
             start=getnext(end_of_math(start))
           elseif id==dir_code then
             start,topstack,rlmode=txtdirstate(start,dirstack,topstack,rlparmode)
           elseif id==localpar_code then
             start,rlparmode,rlmode=pardirstate(start)
           else
             start=getnext(start)
           end
         end
       end
     else
       while start do
         local char,id=ischar(start,font)
         if char then
           local a=attr and getattr(start,0)
           if a then
             a=(a==attr) and (not attribute or getprop(start,a_state)==attribute)
           else
             a=not attribute or getprop(start,a_state)==attribute
           end
           if a then
             for i=1,nofsteps do
               local step=steps[i]
               local lookupcache=step.coverage
               if lookupcache then
                 local lookupmatch=lookupcache[char]
                 if lookupmatch then
                   local ok
                   head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
                   if ok then
                     success=true
                     break
                   elseif not start then
                     break
                   end
                 end
               else
                 report_missing_coverage(dataset,sequence)
               end
             end
             if start then
               start=getnext(start)
             end
           else
             start=getnext(start)
           end
         elseif char==false then
           start=getnext(start)
         elseif id==disc_code then
           local a=forcedisc or getsubtype(start)==discretionary_code or getattr(start,0)==attr
           if a then
             local ok
             if gpossing then
               start,ok=kernrun(start,k_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
             elseif typ=="gsub_ligature" then
               start,ok=testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
             else
               start,ok=comprun(start,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
             end
             if ok then
               success=true
             end
           else
             start=getnext(start)
           end
         elseif id==math_code then
           start=getnext(end_of_math(start))
         elseif id==dir_code then
           start,topstack,rlmode=txtdirstate(start,dirstack,topstack,rlparmode)
         elseif id==localpar_code then
           start,rlparmode,rlmode=pardirstate(start)
         else
           start=getnext(start)
         end
       end
     end
   end
   if success then
     done=true
   end
   if trace_steps then
     registerstep(head)
   end
 end
 nesting=nesting-1
 head=tonode(head)
 return head,done
end
local plugins={}
otf.plugins=plugins
function otf.registerplugin(name,f)
 if type(name)=="string" and type(f)=="function" then
   plugins[name]={ name,f }
 end
end
local function plugininitializer(tfmdata,value)
 if type(value)=="string" then
   tfmdata.shared.plugin=plugins[value]
 end
end
local function pluginprocessor(head,font)
 local s=fontdata[font].shared
 local p=s and s.plugin
 if p then
   if trace_plugins then
     report_process("applying plugin %a",p[1])
   end
   return p[2](head,font)
 else
   return head,false
 end
end
local function featuresinitializer(tfmdata,value)
end
registerotffeature {
 name="features",
 description="features",
 default=true,
 initializers={
   position=1,
   node=featuresinitializer,
   plug=plugininitializer,
 },
 processors={
   node=featuresprocessor,
   plug=pluginprocessor,
 }
}
otf.nodemodeinitializer=featuresinitializer
otf.featuresprocessor=featuresprocessor
otf.handlers=handlers
local setspacekerns=nodes.injections.setspacekerns if not setspacekerns then os.exit() end
if fontfeatures then
 function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)
   local features=fontfeatures[font]
   local enabled=features and features.spacekern and features.kern
   if enabled then
     setspacekerns(font,sequence)
   end
   return head,start,enabled
 end
else
 function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)
   local shared=fontdata[font].shared
   local features=shared and shared.features
   local enabled=features and features.spacekern and features.kern
   if enabled then
     setspacekerns(font,sequence)
   end
   return head,start,enabled
 end
end
local function hasspacekerns(data)
 local sequences=data.resources.sequences
 for i=1,#sequences do
   local sequence=sequences[i]
   local steps=sequence.steps
   if steps and sequence.features.kern then
     for i=1,#steps do
       local coverage=steps[i].coverage
       if not coverage then
       elseif coverage[32] then
         return true
       else
         for k,v in next,coverage do
           if v[32] then
             return true
           end
         end
       end
     end
   end
 end
 return false
end
otf.readers.registerextender {
 name="spacekerns",
 action=function(data)
   data.properties.hasspacekerns=hasspacekerns(data)
 end
}
local function spaceinitializer(tfmdata,value)
 local resources=tfmdata.resources
 local spacekerns=resources and resources.spacekerns
 local properties=tfmdata.properties
 if value and spacekerns==nil then
   if properties and properties.hasspacekerns then
     local sequences=resources.sequences
     local left={}
     local right={}
     local last=0
     local feat=nil
     for i=1,#sequences do
       local sequence=sequences[i]
       local steps=sequence.steps
       if steps then
         local kern=sequence.features.kern
         if kern then
           if feat then
             for script,languages in next,kern do
               local f=feat[script]
               if f then
                 for l in next,languages do
                   f[l]=true
                 end
               else
                 feat[script]=languages
               end
             end
           else
             feat=kern
           end
           for i=1,#steps do
             local step=steps[i]
             local coverage=step.coverage
             local rules=step.rules
             local format=step.format
             if rules then
             elseif coverage then
               local single=format==gpos_single
               local kerns=coverage[32]
               if kerns then
                 for k,v in next,kerns do
                   if type(v)~="table" then
                     right[k]=v
                   elseif single then
                     right[k]=v[3]
                   else
                     local one=v[1]
                     if one then
                       right[k]=one[3]
                     end
                   end
                 end
               end
               for k,v in next,coverage do
                 local kern=v[32]
                 if kern then
                   if type(kern)~="table" then
                     left[k]=kern
                   elseif single then
                     left[k]=v[3]
                   else
                     local one=v[1]
                     if one then
                       left[k]=one[3]
                     end
                   end
                 end
               end
             end
           end
           last=i
         end
       else
       end
     end
     left=next(left) and left or false
     right=next(right) and right or false
     if left or right then
       spacekerns={
         left=left,
         right=right,
       }
       if last>0 then
         local triggersequence={
           features={ kern=feat or { dflt={ dflt=true,} } },
           flags=noflags,
           name="trigger_space_kerns",
           order={ "kern" },
           type="trigger_space_kerns",
           left=left,
           right=right,
         }
         insert(sequences,last,triggersequence)
       end
     else
       spacekerns=false
     end
   else
     spacekerns=false
   end
   resources.spacekerns=spacekerns
 end
 return spacekerns
end
registerotffeature {
 name="spacekern",
 description="space kern injection",
 default=true,
 initializers={
   node=spaceinitializer,
 },
}
local function markinitializer(tfmdata,value)
 local properties=tfmdata.properties
 properties.checkmarks=value
end
registerotffeature {
 name="checkmarks",
 description="check mark widths",
 default=true,
 initializers={
   node=markinitializer,
 },
}

end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ots”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-osd” 10ecd4b375680b011e7c6a25e5ad74f7] ---

if not modules then modules={} end modules ['font-osd']={
 version=1.001,
 comment="companion to font-ini.mkiv",
 author="Kai Eigner, TAT Zetwerk / Hans Hagen, PRAGMA ADE",
 copyright="TAT Zetwerk / PRAGMA ADE / ConTeXt Development Team",
 license="see context related readme files"
}
local insert,imerge,copy=table.insert,table.imerge,table.copy
local next,type=next,type
local report_devanagari=logs.reporter("otf","devanagari")
fonts=fonts          or {}
fonts.analyzers=fonts.analyzers     or {}
fonts.analyzers.methods=fonts.analyzers.methods or { node={ otf={} } }
local otf=fonts.handlers.otf
local handlers=otf.handlers
local methods=fonts.analyzers.methods
local otffeatures=fonts.constructors.features.otf
local registerotffeature=otffeatures.register
local nuts=nodes.nuts
local tonode=nuts.tonode
local tonut=nuts.tonut
local getnext=nuts.getnext
local getprev=nuts.getprev
local getboth=nuts.getboth
local getid=nuts.getid
local getchar=nuts.getchar
local getfont=nuts.getfont
local getsubtype=nuts.getsubtype
local setlink=nuts.setlink
local setnext=nuts.setnext
local setprev=nuts.setprev
local setchar=nuts.setchar
local getprop=nuts.getprop
local setprop=nuts.setprop
local ischar=nuts.is_char
local insert_node_after=nuts.insert_after
local copy_node=nuts.copy
local remove_node=nuts.remove
local flush_list=nuts.flush_list
local flush_node=nuts.flush_node
local copyinjection=nodes.injections.copy
local unsetvalue=attributes.unsetvalue
local fontdata=fonts.hashes.identifiers
local a_state=attributes.private('state')
local a_syllabe=attributes.private('syllabe')
local dotted_circle=0x25CC
local states=fonts.analyzers.states
local s_rphf=states.rphf
local s_half=states.half
local s_pref=states.pref
local s_blwf=states.blwf
local s_pstf=states.pstf
local replace_all_nbsp=nil
replace_all_nbsp=function(head)
 replace_all_nbsp=typesetters and typesetters.characters and typesetters.characters.replacenbspaces or function(head)
   return head
 end
 return replace_all_nbsp(head)
end
local xprocesscharacters=nil
if context then
 xprocesscharacters=function(head,font)
   xprocesscharacters=nodes.handlers.characters
   return xprocesscharacters(head,font)
 end
else
 xprocesscharacters=function(head,font)
   xprocesscharacters=nodes.handlers.nodepass
   return xprocesscharacters(head,font)
 end
end
local function processcharacters(head,font)
 return tonut(xprocesscharacters(tonode(head)))
end
local consonant={
 [0x0915]=true,[0x0916]=true,[0x0917]=true,[0x0918]=true,
 [0x0919]=true,[0x091A]=true,[0x091B]=true,[0x091C]=true,
 [0x091D]=true,[0x091E]=true,[0x091F]=true,[0x0920]=true,
 [0x0921]=true,[0x0922]=true,[0x0923]=true,[0x0924]=true,
 [0x0925]=true,[0x0926]=true,[0x0927]=true,[0x0928]=true,
 [0x0929]=true,[0x092A]=true,[0x092B]=true,[0x092C]=true,
 [0x092D]=true,[0x092E]=true,[0x092F]=true,[0x0930]=true,
 [0x0931]=true,[0x0932]=true,[0x0933]=true,[0x0934]=true,
 [0x0935]=true,[0x0936]=true,[0x0937]=true,[0x0938]=true,
 [0x0939]=true,[0x0958]=true,[0x0959]=true,[0x095A]=true,
 [0x095B]=true,[0x095C]=true,[0x095D]=true,[0x095E]=true,
 [0x095F]=true,[0x0979]=true,[0x097A]=true,
 [0x0C95]=true,[0x0C96]=true,[0x0C97]=true,[0x0C98]=true,
 [0x0C99]=true,[0x0C9A]=true,[0x0C9B]=true,[0x0C9C]=true,
 [0x0C9D]=true,[0x0C9E]=true,[0x0C9F]=true,[0x0CA0]=true,
 [0x0CA1]=true,[0x0CA2]=true,[0x0CA3]=true,[0x0CA4]=true,
 [0x0CA5]=true,[0x0CA6]=true,[0x0CA7]=true,[0x0CA8]=true,
 [0x0CA9]=true,[0x0CAA]=true,[0x0CAB]=true,[0x0CAC]=true,
 [0x0CAD]=true,[0x0CAE]=true,[0x0CAF]=true,[0x0CB0]=true,
 [0x0CB1]=true,[0x0CB2]=true,[0x0CB3]=true,[0x0CB4]=true,
 [0x0CB5]=true,[0x0CB6]=true,[0x0CB7]=true,[0x0CB8]=true,
 [0x0CB9]=true,
 [0x0CDE]=true,
 [0x0D15]=true,[0x0D16]=true,[0x0D17]=true,[0x0D18]=true,
 [0x0D19]=true,[0x0D1A]=true,[0x0D1B]=true,[0x0D1C]=true,
 [0x0D1D]=true,[0x0D1E]=true,[0x0D1F]=true,[0x0D20]=true,
 [0x0D21]=true,[0x0D22]=true,[0x0D23]=true,[0x0D24]=true,
 [0x0D25]=true,[0x0D26]=true,[0x0D27]=true,[0x0D28]=true,
 [0x0D29]=true,[0x0D2A]=true,[0x0D2B]=true,[0x0D2C]=true,
 [0x0D2D]=true,[0x0D2E]=true,[0x0D2F]=true,[0x0D30]=true,
 [0x0D31]=true,[0x0D32]=true,[0x0D33]=true,[0x0D34]=true,
 [0x0D35]=true,[0x0D36]=true,[0x0D37]=true,[0x0D38]=true,
 [0x0D39]=true,[0x0D3A]=true,
}
local independent_vowel={
 [0x0904]=true,[0x0905]=true,[0x0906]=true,[0x0907]=true,
 [0x0908]=true,[0x0909]=true,[0x090A]=true,[0x090B]=true,
 [0x090C]=true,[0x090D]=true,[0x090E]=true,[0x090F]=true,
 [0x0910]=true,[0x0911]=true,[0x0912]=true,[0x0913]=true,
 [0x0914]=true,[0x0960]=true,[0x0961]=true,[0x0972]=true,
 [0x0973]=true,[0x0974]=true,[0x0975]=true,[0x0976]=true,
 [0x0977]=true,
 [0x0C85]=true,[0x0C86]=true,[0x0C87]=true,[0x0C88]=true,
 [0x0C89]=true,[0x0C8A]=true,[0x0C8B]=true,[0x0C8C]=true,
 [0x0C8D]=true,[0x0C8E]=true,[0x0C8F]=true,[0x0C90]=true,
 [0x0C91]=true,[0x0C92]=true,[0x0C93]=true,[0x0C94]=true,
 [0x0D05]=true,[0x0D06]=true,[0x0D07]=true,[0x0D08]=true,
 [0x0D09]=true,[0x0D0A]=true,[0x0D0B]=true,[0x0D0C]=true,
 [0x0D0E]=true,[0x0D0F]=true,[0x0D10]=true,[0x0D12]=true,
 [0x0D13]=true,[0x0D14]=true,
}
local dependent_vowel={
 [0x093A]=true,[0x093B]=true,[0x093E]=true,[0x093F]=true,
 [0x0940]=true,[0x0941]=true,[0x0942]=true,[0x0943]=true,
 [0x0944]=true,[0x0945]=true,[0x0946]=true,[0x0947]=true,
 [0x0948]=true,[0x0949]=true,[0x094A]=true,[0x094B]=true,
 [0x094C]=true,[0x094E]=true,[0x094F]=true,[0x0955]=true,
 [0x0956]=true,[0x0957]=true,[0x0962]=true,[0x0963]=true,
 [0x0CBE]=true,[0x0CBF]=true,[0x0CC0]=true,[0x0CC1]=true,
 [0x0CC2]=true,[0x0CC3]=true,[0x0CC4]=true,[0x0CC5]=true,
 [0x0CC6]=true,[0x0CC7]=true,[0x0CC8]=true,[0x0CC9]=true,
 [0x0CCA]=true,[0x0CCB]=true,[0x0CCC]=true,
 [0x0D3E]=true,[0x0D3F]=true,[0x0D40]=true,[0x0D41]=true,
 [0x0D42]=true,[0x0D43]=true,[0x0D44]=true,[0x0D46]=true,
 [0x0D47]=true,[0x0D48]=true,[0x0D4A]=true,[0x0D4B]=true,
 [0x0D4C]=true,[0x0D57]=true,
}
local vowel_modifier={
 [0x0900]=true,[0x0901]=true,[0x0902]=true,[0x0903]=true,
 [0xA8E0]=true,[0xA8E1]=true,[0xA8E2]=true,[0xA8E3]=true,
 [0xA8E4]=true,[0xA8E5]=true,[0xA8E6]=true,[0xA8E7]=true,
 [0xA8E8]=true,[0xA8E9]=true,[0xA8EA]=true,[0xA8EB]=true,
 [0xA8EC]=true,[0xA8ED]=true,[0xA8EE]=true,[0xA8EF]=true,
 [0xA8F0]=true,[0xA8F1]=true,
 [0x0D02]=true,[0x0D03]=true,
}
local stress_tone_mark={
 [0x0951]=true,[0x0952]=true,[0x0953]=true,[0x0954]=true,
 [0x0CCD]=true,
 [0x0D4D]=true,
}
local nukta={
 [0x093C]=true,
 [0x0CBC]=true,
}
local halant={
 [0x094D]=true,
 [0x0CCD]=true,
 [0x0D4D]=true,
}
local ra={
 [0x0930]=true,
 [0x0CB0]=true,
 [0x0D30]=true,
}
local c_anudatta=0x0952
local c_nbsp=0x00A0
local c_zwnj=0x200C
local c_zwj=0x200D
local zw_char={
 [0x200C]=true,
 [0x200D]=true,
}
local pre_mark={
 [0x093F]=true,[0x094E]=true,
 [0x0D46]=true,[0x0D47]=true,[0x0D48]=true,
}
local above_mark={
 [0x0900]=true,[0x0901]=true,[0x0902]=true,[0x093A]=true,
 [0x0945]=true,[0x0946]=true,[0x0947]=true,[0x0948]=true,
 [0x0951]=true,[0x0953]=true,[0x0954]=true,[0x0955]=true,
 [0xA8E0]=true,[0xA8E1]=true,[0xA8E2]=true,[0xA8E3]=true,
 [0xA8E4]=true,[0xA8E5]=true,[0xA8E6]=true,[0xA8E7]=true,
 [0xA8E8]=true,[0xA8E9]=true,[0xA8EA]=true,[0xA8EB]=true,
 [0xA8EC]=true,[0xA8ED]=true,[0xA8EE]=true,[0xA8EF]=true,
 [0xA8F0]=true,[0xA8F1]=true,
 [0x0D4E]=true,
}
local below_mark={
 [0x093C]=true,[0x0941]=true,[0x0942]=true,[0x0943]=true,
 [0x0944]=true,[0x094D]=true,[0x0952]=true,[0x0956]=true,
 [0x0957]=true,[0x0962]=true,[0x0963]=true,
}
local post_mark={
 [0x0903]=true,[0x093B]=true,[0x093E]=true,[0x0940]=true,
 [0x0949]=true,[0x094A]=true,[0x094B]=true,[0x094C]=true,
 [0x094F]=true,
}
local twopart_mark={
 [0x0D4A]={ 0x0D46,0x0D3E,},
 [0x0D4B]={ 0x0D47,0x0D3E,},
 [0x0D4C]={ 0x0D46,0x0D57,},
}
local mark_four={}
for k,v in next,pre_mark  do mark_four[k]=pre_mark  end
for k,v in next,above_mark do mark_four[k]=above_mark end
for k,v in next,below_mark do mark_four[k]=below_mark end
for k,v in next,post_mark do mark_four[k]=post_mark end
local mark_above_below_post={}
for k,v in next,above_mark do mark_above_below_post[k]=above_mark end
for k,v in next,below_mark do mark_above_below_post[k]=below_mark end
for k,v in next,post_mark do mark_above_below_post[k]=post_mark end
local reorder_class={
 [0x0930]="before postscript",
 [0x093F]="before half",
 [0x0940]="after subscript",
 [0x0941]="after subscript",
 [0x0942]="after subscript",
 [0x0943]="after subscript",
 [0x0944]="after subscript",
 [0x0945]="after subscript",
 [0x0946]="after subscript",
 [0x0947]="after subscript",
 [0x0948]="after subscript",
 [0x0949]="after subscript",
 [0x094A]="after subscript",
 [0x094B]="after subscript",
 [0x094C]="after subscript",
 [0x0962]="after subscript",
 [0x0963]="after subscript",
 [0x093E]="after subscript",
 [0x0CB0]="after postscript",
 [0x0CBF]="before subscript",
 [0x0CC6]="before subscript",
 [0x0CCC]="before subscript",
 [0x0CBE]="before subscript",
 [0x0CE2]="before subscript",
 [0x0CE3]="before subscript",
 [0x0CC1]="before subscript",
 [0x0CC2]="before subscript",
 [0x0CC3]="after subscript",
 [0x0CC4]="after subscript",
 [0x0CD5]="after subscript",
 [0x0CD6]="after subscript",
}
local dflt_true={
 dflt=true
}
local dev2_defaults={
 dev2=dflt_true,
}
local deva_defaults={
 dev2=dflt_true,
 deva=dflt_true,
}
local false_flags={ false,false,false,false }
local both_joiners_true={
 [0x200C]=true,
 [0x200D]=true,
}
local sequence_reorder_matras={
 features={ dv01=dev2_defaults },
 flags=false_flags,
 name="dv01_reorder_matras",
 order={ "dv01" },
 type="devanagari_reorder_matras",
 nofsteps=1,
 steps={
   {
     osdstep=true,
     coverage=pre_mark,
   }
 }
}
local sequence_reorder_reph={
 features={ dv02=dev2_defaults },
 flags=false_flags,
 name="dv02_reorder_reph",
 order={ "dv02" },
 type="devanagari_reorder_reph",
 nofsteps=1,
 steps={
   {
     osdstep=true,
     coverage={},
   }
 }
}
local sequence_reorder_pre_base_reordering_consonants={
 features={ dv03=dev2_defaults },
 flags=false_flags,
 name="dv03_reorder_pre_base_reordering_consonants",
 order={ "dv03" },
 type="devanagari_reorder_pre_base_reordering_consonants",
 nofsteps=1,
 steps={
   {
     osdstep=true,
     coverage={},
   }
 }
}
local sequence_remove_joiners={
 features={ dv04=deva_defaults },
 flags=false_flags,
 name="dv04_remove_joiners",
 order={ "dv04" },
 type="devanagari_remove_joiners",
 nofsteps=1,
 steps={
   { osdstep=true,
     coverage=both_joiners_true,
   },
 }
}
local basic_shaping_forms={
 nukt=true,
 akhn=true,
 rphf=true,
 pref=true,
 rkrf=true,
 blwf=true,
 half=true,
 pstf=true,
 vatu=true,
 cjct=true,
}
local valid={
 akhn=true,
 rphf=true,
 pref=true,
 half=true,
 blwf=true,
 pstf=true,
 pres=true,
 blws=true,
 psts=true,
}
local function initializedevanagi(tfmdata)
 local script,language=otf.scriptandlanguage(tfmdata,attr)
 if script=="deva" or script=="dev2" or script=="mlym" or script=="mlm2" then
   local resources=tfmdata.resources
   local devanagari=resources.devanagari
   if not devanagari then
     report_devanagari("adding devanagari features to font")
     local gsubfeatures=resources.features.gsub
     local sequences=resources.sequences
     local sharedfeatures=tfmdata.shared.features
     local lastmatch=0
     for s=1,#sequences do
       local features=sequences[s].features
       if features then
         for k,v in next,features do
           if basic_shaping_forms[k] then
             lastmatch=s
           end
         end
       end
     end
     local insertindex=lastmatch+1
     gsubfeatures["dv01"]=dev2_defaults
     gsubfeatures["dv02"]=dev2_defaults
     gsubfeatures["dv03"]=dev2_defaults
     gsubfeatures["dv04"]=deva_defaults
     local reorder_pre_base_reordering_consonants=copy(sequence_reorder_pre_base_reordering_consonants)
     local reorder_reph=copy(sequence_reorder_reph)
     local reorder_matras=copy(sequence_reorder_matras)
     local remove_joiners=copy(sequence_remove_joiners)
     insert(sequences,insertindex,reorder_pre_base_reordering_consonants)
     insert(sequences,insertindex,reorder_reph)
     insert(sequences,insertindex,reorder_matras)
     insert(sequences,insertindex,remove_joiners)
     local blwfcache={}
     local seqsubset={}
     local rephstep={
       coverage={}
     }
     local devanagari={
       reph=false,
       vattu=false,
       blwfcache=blwfcache,
       seqsubset=seqsubset,
       reorderreph=rephstep,
     }
     reorder_reph.steps={ rephstep }
     local pre_base_reordering_consonants={}
     reorder_pre_base_reordering_consonants.steps[1].coverage=pre_base_reordering_consonants
     resources.devanagari=devanagari
     for s=1,#sequences do
       local sequence=sequences[s]
       local steps=sequence.steps
       local nofsteps=sequence.nofsteps
       local features=sequence.features
       local has_rphf=features.rphf
       local has_blwf=features.blwf
       if has_rphf and has_rphf.deva then
         devanagari.reph=true
       elseif has_blwf and has_blwf.deva then
         devanagari.vattu=true
         for i=1,nofsteps do
           local step=steps[i]
           local coverage=step.coverage
           if coverage then
             for k,v in next,coverage do
               if not blwfcache[k] then
                 blwfcache[k]=v
               end
             end
           end
         end
       end
       for kind,spec in next,features do
         if spec.dev2 and valid[kind] then
           for i=1,nofsteps do
             local step=steps[i]
             local coverage=step.coverage
             if coverage then
               local reph=false
               if kind=="rphf" then
                 if true then
                   for k,v in next,ra do
                     local r=coverage[k]
                     if r then
                       local h=false
                       for k,v in next,halant do
                         local h=r[k]
                         if h then
                           reph=h.ligature or false
                           break
                         end
                       end
                       if reph then
                         break
                       end
                     end
                   end
                 else
                 end
               end
               seqsubset[#seqsubset+1]={ kind,coverage,reph }
             end
           end
         end
         if kind=="pref" then
           local steps=sequence.steps
           local nofsteps=sequence.nofsteps
           for i=1,nofsteps do
             local step=steps[i]
             local coverage=step.coverage
             if coverage then
               for k,v in next,halant do
                 local h=coverage[k]
                 if h then
                   local found=false
                   for k,v in next,h do
                     found=v and v.ligature
                     if found then
                       pre_base_reordering_consonants[k]=found
                       break
                     end
                   end
                   if found then
                     break
                   end
                 end
               end
             end
           end
         end
       end
     end
     if script=="deva" then
       sharedfeatures["dv04"]=true
     elseif script=="dev2" then
       sharedfeatures["dv01"]=true
       sharedfeatures["dv02"]=true
       sharedfeatures["dv03"]=true
       sharedfeatures["dv04"]=true
     elseif script=="mlym" then
       sharedfeatures["pstf"]=true
     elseif script=="mlm2" then
       sharedfeatures["pstf"]=true
       sharedfeatures["pref"]=true
       sharedfeatures["dv03"]=true
       gsubfeatures ["dv03"]=dev2_defaults
       insert(sequences,insertindex,sequence_reorder_pre_base_reordering_consonants)
     end
   end
 end
end
registerotffeature {
 name="devanagari",
 description="inject additional features",
 default=true,
 initializers={
   node=initializedevanagi,
 },
}
local function deva_initialize(font,attr)
 local tfmdata=fontdata[font]
 local datasets=otf.dataset(tfmdata,font,attr)
 local devanagaridata=datasets.devanagari
 if not devanagaridata then
   devanagaridata={
     reph=false,
     vattu=false,
     blwfcache={},
   }
   datasets.devanagari=devanagaridata
   local resources=tfmdata.resources
   local devanagari=resources.devanagari
   for s=1,#datasets do
     local dataset=datasets[s]
     if dataset and dataset[1] then
       local kind=dataset[4]
       if kind=="rphf" then
         devanagaridata.reph=true
       elseif kind=="blwf" then
         devanagaridata.vattu=true
         devanagaridata.blwfcache=devanagari.blwfcache
       end
     end
   end
 end
 return devanagaridata.reph,devanagaridata.vattu,devanagaridata.blwfcache
end
local function deva_reorder(head,start,stop,font,attr,nbspaces)
 local reph,vattu,blwfcache=deva_initialize(font,attr)
 local current=start
 local n=getnext(start)
 local base=nil
 local firstcons=nil
 local lastcons=nil
 local basefound=false
 if reph and ra[getchar(start)] and halant[getchar(n)] then
   if n==stop then
     return head,stop,nbspaces
   end
   if getchar(getnext(n))==c_zwj then
     current=start
   else
     current=getnext(n)
     setprop(start,a_state,s_rphf)
   end
 end
 if getchar(current)==c_nbsp then
   if current==stop then
     stop=getprev(stop)
     head=remove_node(head,current)
     flush_node(current)
     return head,stop,nbspaces
   else
     nbspaces=nbspaces+1
     base=current
     firstcons=current
     lastcons=current
     current=getnext(current)
     if current~=stop then
       if nukta[getchar(current)] then
         current=getnext(current)
       end
       if getchar(current)==c_zwj then
         if current~=stop then
           local next=getnext(current)
           if next~=stop and halant[getchar(next)] then
             current=next
             next=getnext(current)
             local tmp=next and getnext(next) or nil
             local changestop=next==stop
             local tempcurrent=copy_node(next)
                                                       copyinjection(tempcurrent,next)
             local nextcurrent=copy_node(current)
                                                       copyinjection(nextcurrent,current)
             setlink(tempcurrent,nextcurrent)
             setprop(tempcurrent,a_state,s_blwf)
             tempcurrent=processcharacters(tempcurrent,font)
             setprop(tempcurrent,a_state,unsetvalue)
             if getchar(next)==getchar(tempcurrent) then
               flush_list(tempcurrent)
               local n=copy_node(current)
                                                               copyinjection(n,current)
               setchar(current,dotted_circle)
               head=insert_node_after(head,current,n)
             else
               setchar(current,getchar(tempcurrent))
               local freenode=getnext(current)
               setlink(current,tmp)
               flush_node(freenode)
               flush_list(tempcurrent)
               if changestop then
                 stop=current
               end
             end
           end
         end
       end
     end
   end
 end
 while not basefound do
   local char=getchar(current)
   if consonant[char] then
     setprop(current,a_state,s_half)
     if not firstcons then
       firstcons=current
     end
     lastcons=current
     if not base then
       base=current
     elseif blwfcache[char] then
       setprop(current,a_state,s_blwf)
     else
       base=current
     end
   end
   basefound=current==stop
   current=getnext(current)
 end
 if base~=lastcons then
   local np=base
   local n=getnext(base)
   local ch=getchar(n)
   if nukta[ch] then
     np=n
     n=getnext(n)
     ch=getchar(n)
   end
   if halant[ch] then
     if lastcons~=stop then
       local ln=getnext(lastcons)
       if nukta[getchar(ln)] then
         lastcons=ln
       end
     end
     local nn=getnext(n)
     local ln=getnext(lastcons)
     setlink(np,nn)
     setnext(lastcons,n)
     if ln then
       setprev(ln,n)
     end
     setnext(n,ln)
     setprev(n,lastcons)
     if lastcons==stop then
       stop=n
     end
   end
 end
 n=getnext(start)
 if n~=stop and ra[getchar(start)] and halant[getchar(n)] and not zw_char[getchar(getnext(n))] then
   local matra=base
   if base~=stop then
     local next=getnext(base)
     if dependent_vowel[getchar(next)] then
       matra=next
     end
   end
   local sp=getprev(start)
   local nn=getnext(n)
   local mn=getnext(matra)
   setlink(sp,nn)
   setlink(matra,start)
   setlink(n,mn)
   if head==start then
     head=nn
   end
   start=nn
   if matra==stop then
     stop=n
   end
 end
 local current=start
 while current~=stop do
   local next=getnext(current)
   if next~=stop and halant[getchar(next)] and getchar(getnext(next))==c_zwnj then
     setprop(current,a_state,unsetvalue)
   end
   current=next
 end
 if base~=stop and getprop(base,a_state) then
   local next=getnext(base)
   if halant[getchar(next)] and not (next~=stop and getchar(getnext(next))==c_zwj) then
     setprop(base,a_state,unsetvalue)
   end
 end
 local current,allreordered,moved=start,false,{ [base]=true }
 local a,b,p,bn=base,base,base,getnext(base)
 if base~=stop and nukta[getchar(bn)] then
   a,b,p=bn,bn,bn
 end
 while not allreordered do
   local c=current
   local n=getnext(current)
   local l=nil
   if c~=stop then
     local ch=getchar(n)
     if nukta[ch] then
       c=n
       n=getnext(n)
       ch=getchar(n)
     end
     if c~=stop then
       if halant[ch] then
         c=n
         n=getnext(n)
         ch=getchar(n)
       end
       while c~=stop and dependent_vowel[ch] do
         c=n
         n=getnext(n)
         ch=getchar(n)
       end
       if c~=stop then
         if vowel_modifier[ch] then
           c=n
           n=getnext(n)
           ch=getchar(n)
         end
         if c~=stop and stress_tone_mark[ch] then
           c=n
           n=getnext(n)
         end
       end
     end
   end
   local bp=getprev(firstcons)
   local cn=getnext(current)
   local last=getnext(c)
   while cn~=last do
     if pre_mark[getchar(cn)] then
       if bp then
         setnext(bp,cn)
       end
       local prev,next=getboth(cn)
       if next then
         setprev(next,prev)
       end
       setnext(prev,next)
       if cn==stop then
         stop=prev
       end
       setprev(cn,bp)
       setlink(cn,firstcons)
       if firstcons==start then
         if head==start then
           head=cn
         end
         start=cn
       end
       break
     end
     cn=getnext(cn)
   end
   allreordered=c==stop
   current=getnext(c)
 end
 if reph or vattu then
   local current,cns=start,nil
   while current~=stop do
     local c=current
     local n=getnext(current)
     if ra[getchar(current)] and halant[getchar(n)] then
       c=n
       n=getnext(n)
       local b,bn=base,base
       while bn~=stop do
         local next=getnext(bn)
         if dependent_vowel[getchar(next)] then
           b=next
         end
         bn=next
       end
       if getprop(current,a_state)==s_rphf then
         if b~=current then
           if current==start then
             if head==start then
               head=n
             end
             start=n
           end
           if b==stop then
             stop=c
           end
           local prev=getprev(current)
           setlink(prev,n)
           local next=getnext(b)
           setlink(c,next)
           setlink(b,current)
         end
       elseif cns and getnext(cns)~=current then
         local cp=getprev(current)
         local cnsn=getnext(cns)
         setlink(cp,n)
         setlink(cns,current)
         setlink(c,cnsn)
         if c==stop then
           stop=cp
           break
         end
         current=getprev(n)
       end
     else
       local char=getchar(current)
       if consonant[char] then
         cns=current
         local next=getnext(cns)
         if halant[getchar(next)] then
           cns=next
         end
       elseif char==c_nbsp then
         nbspaces=nbspaces+1
         cns=current
         local next=getnext(cns)
         if halant[getchar(next)] then
           cns=next
         end
       end
     end
     current=getnext(current)
   end
 end
 if getchar(base)==c_nbsp then
   nbspaces=nbspaces-1
   head=remove_node(head,base)
   flush_node(base)
 end
 return head,stop,nbspaces
end
function handlers.devanagari_reorder_matras(head,start)
 local current=start
 local startfont=getfont(start)
 local startattr=getprop(start,a_syllabe)
 while current do
   local char=ischar(current,startfont)
   local next=getnext(current)
   if char and getprop(current,a_syllabe)==startattr then
     if halant[char] and not getprop(current,a_state) then
       if next then
         local char=ischar(next,startfont)
         if char and zw_char[char] and getprop(next,a_syllabe)==startattr then
           current=next
           next=getnext(current)
         end
       end
       local startnext=getnext(start)
       head=remove_node(head,start)
       setlink(start,next)
       setlink(current,start)
       start=startnext
       break
     end
   else
     break
   end
   current=next
 end
 return head,start,true
end
function handlers.devanagari_reorder_reph(head,start)
 local current=getnext(start)
 local startnext=nil
 local startprev=nil
 local startfont=getfont(start)
 local startattr=getprop(start,a_syllabe)
 while current do
   local char=ischar(current,startfont)
   if char and getprop(current,a_syllabe)==startattr then
     if halant[char] and not getprop(current,a_state) then
       local next=getnext(current)
       if next then
         local nextchar=ischar(next,startfont)
         if nextchar and zw_char[nextchar] and getprop(next,a_syllabe)==startattr then
           current=next
           next=getnext(current)
         end
       end
       startnext=getnext(start)
       head=remove_node(head,start)
       setlink(start,next)
       setlink(current,start)
       start=startnext
       startattr=getprop(start,a_syllabe)
       break
     end
     current=getnext(current)
   else
     break
   end
 end
 if not startnext then
   current=getnext(start)
   while current do
     local char=ischar(current,startfont)
     if char and getprop(current,a_syllabe)==startattr then
       if getprop(current,a_state)==s_pstf then
         startnext=getnext(start)
         head=remove_node(head,start)
         local prev=getprev(current)
         setlink(prev,start)
         setlink(start,current)
         start=startnext
         startattr=getprop(start,a_syllabe)
         break
       end
       current=getnext(current)
     else
       break
     end
   end
 end
 if not startnext then
   current=getnext(start)
   local c=nil
   while current do
     local char=ischar(current,startfont)
     if char and getprop(current,a_syllabe)==startattr then
       if not c and mark_above_below_post[char] and reorder_class[char]~="after subscript" then
         c=current
       end
       current=getnext(current)
     else
       break
     end
   end
   if c then
     startnext=getnext(start)
     head=remove_node(head,start)
     local prev=getprev(c)
     setlink(prev,start)
     setlink(start,c)
     start=startnext
     startattr=getprop(start,a_syllabe)
   end
 end
 if not startnext then
   current=start
   local next=getnext(current)
   while next do
     local nextchar=ischar(next,startfont)
     if nextchar and getprop(next,a_syllabe)==startattr then
       current=next
       next=getnext(current)
     else
       break
     end
   end
   if start~=current then
     startnext=getnext(start)
     head=remove_node(head,start)
     local next=getnext(current)
     setlink(start,next)
     setlink(current,start)
     start=startnext
   end
 end
 return head,start,true
end
function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
 local current=start
 local startnext=nil
 local startprev=nil
 local startfont=getfont(start)
 local startattr=getprop(start,a_syllabe)
 while current do
   local char=ischar(current,startfont)
   if char and getprop(current,a_syllabe)==startattr then
     local next=getnext(current)
     if halant[char] and not getprop(current,a_state) then
       if next then
         local nextchar=ischar(next,startfont)
         if nextchar and getprop(next,a_syllabe)==startattr then
           if nextchar==c_zwnj or nextchar==c_zwj then
             current=next
             next=getnext(current)
           end
         end
       end
       startnext=getnext(start)
       removenode(start,start)
       setlink(start,next)
       setlink(current,start)
       start=startnext
       break
     end
     current=next
   else
     break
   end
 end
 if not startnext then
   current=getnext(start)
   startattr=getprop(start,a_syllabe)
   while current do
     local char=ischar(current,startfont)
     if char and getprop(current,a_syllabe)==startattr then
       if not consonant[char] and getprop(current,a_state) then
         startnext=getnext(start)
         removenode(start,start)
         local prev=getprev(current)
         setlink(prev,start)
         setlink(start,current)
         start=startnext
         break
       end
       current=getnext(current)
     else
       break
     end
   end
 end
 return head,start,true
end
function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replacement)
 local stop=getnext(start)
 local font=getfont(start)
 local last=start
 while stop do
   local char=ischar(stop,font)
   if char and (char==c_zwnj or char==c_zwj) then
     last=stop
     stop=getnext(stop)
   else
     break
   end
 end
 local prev=getprev(start)
 if stop then
   setnext(last)
   setlink(prev,stop)
 elseif prev then
   setnext(prev)
 end
 if head==start then
       head=stop
 end
 flush_list(start)
 return head,stop,true
end
local function dev2_initialize(font,attr)
 local devanagari=fontdata[font].resources.devanagari
 if devanagari then
   return devanagari.seqsubset or {},devanagari.reorderreph or {}
 else
   return {},{}
 end
end
local function dev2_reorder(head,start,stop,font,attr,nbspaces)
 local seqsubset,reorderreph=dev2_initialize(font,attr)
 local reph=false
 local halfpos=nil
 local basepos=nil
 local subpos=nil
 local postpos=nil
 local locl={}
 for i=1,#seqsubset do
   local subset=seqsubset[i]
   local kind=subset[1]
   local lookupcache=subset[2]
   if kind=="rphf" then
     reph=subset[3]
     local current=start
     local last=getnext(stop)
     while current~=last do
       if current~=stop then
         local c=locl[current] or getchar(current)
         local found=lookupcache[c]
         if found then
           local next=getnext(current)
           local n=locl[next] or getchar(next)
           if found[n] then
             local afternext=next~=stop and getnext(next)
             if afternext and zw_char[getchar(afternext)] then
               current=next
               current=getnext(current)
             elseif current==start then
               setprop(current,a_state,s_rphf)
               current=next
             else
               current=next
             end
           end
         end
       end
       current=getnext(current)
     end
   elseif kind=="pref" then
     local current=start
     local last=getnext(stop)
     while current~=last do
       if current~=stop then
         local c=locl[current] or getchar(current)
         local found=lookupcache[c]
         if found then
           local next=getnext(current)
           local n=locl[next] or getchar(next)
           if found[n] then
             setprop(current,a_state,s_pref)
             setprop(next,a_state,s_pref)
             current=next
           end
         end
       end
       current=getnext(current)
     end
   elseif kind=="half" then
     local current=start
     local last=getnext(stop)
     while current~=last do
       if current~=stop then
         local c=locl[current] or getchar(current)
         local found=lookupcache[c]
         if found then
           local next=getnext(current)
           local n=locl[next] or getchar(next)
           if found[n] then
             if next~=stop and getchar(getnext(next))==c_zwnj then
               current=next
             else
               setprop(current,a_state,s_half)
               if not halfpos then
                 halfpos=current
               end
             end
             current=getnext(current)
           end
         end
       end
       current=getnext(current)
     end
   elseif kind=="blwf" then
     local current=start
     local last=getnext(stop)
     while current~=last do
       if current~=stop then
         local c=locl[current] or getchar(current)
         local found=lookupcache[c]
         if found then
           local next=getnext(current)
           local n=locl[next] or getchar(next)
           if found[n] then
             setprop(current,a_state,s_blwf)
             setprop(next,a_state,s_blwf)
             current=next
             subpos=current
           end
         end
       end
       current=getnext(current)
     end
   elseif kind=="pstf" then
     local current=start
     local last=getnext(stop)
     while current~=last do
       if current~=stop then
         local c=locl[current] or getchar(current)
         local found=lookupcache[c]
         if found then
           local next=getnext(current)
           local n=locl[next] or getchar(next)
           if found[n] then
             setprop(current,a_state,s_pstf)
             setprop(next,a_state,s_pstf)
             current=next
             postpos=current
           end
         end
       end
       current=getnext(current)
     end
   end
 end
 reorderreph.coverage={ [reph]=true }
 local current,base,firstcons=start,nil,nil
 if getprop(start,a_state)==s_rphf then
   current=getnext(getnext(start))
 end
 if current~=getnext(stop) and getchar(current)==c_nbsp then
   if current==stop then
     stop=getprev(stop)
     head=remove_node(head,current)
     flush_node(current)
     return head,stop,nbspaces
   else
     nbspaces=nbspaces+1
     base=current
     current=getnext(current)
     if current~=stop then
       local char=getchar(current)
       if nukta[char] then
         current=getnext(current)
         char=getchar(current)
       end
       if char==c_zwj then
         local next=getnext(current)
         if current~=stop and next~=stop and halant[getchar(next)] then
           current=next
           next=getnext(current)
           local tmp=getnext(next)
           local changestop=next==stop
           setnext(next,nil)
           setprop(current,a_state,s_pref)
           current=processcharacters(current,font)
           setprop(current,a_state,s_blwf)
           current=processcharacters(current,font)
           setprop(current,a_state,s_pstf)
           current=processcharacters(current,font)
           setprop(current,a_state,unsetvalue)
           if halant[getchar(current)] then
             setnext(getnext(current),tmp)
             local nc=copy_node(current)
                                                       copyinjection(nc,current)
             setchar(current,dotted_circle)
             head=insert_node_after(head,current,nc)
           else
             setnext(current,tmp)
             if changestop then
               stop=current
             end
           end
         end
       end
     end
   end
 else
   local last=getnext(stop)
   while current~=last do
     local next=getnext(current)
     if consonant[getchar(current)] then
       if not (current~=stop and next~=stop and halant[getchar(next)] and getchar(getnext(next))==c_zwj) then
         if not firstcons then
           firstcons=current
         end
         local a=getprop(current,a_state)
         if not (a==s_pref or a==s_blwf or a==s_pstf) then
           base=current
         end
       end
     end
     current=next
   end
   if not base then
     base=firstcons
   end
 end
 if not base then
   if getprop(start,a_state)==s_rphf then
     setprop(start,a_state,unsetvalue)
   end
   return head,stop,nbspaces
 else
   if getprop(base,a_state) then
     setprop(base,a_state,unsetvalue)
   end
   basepos=base
 end
 if not halfpos then
   halfpos=base
 end
 if not subpos then
   subpos=base
 end
 if not postpos then
   postpos=subpos or base
 end
 local moved={}
 local current=start
 local last=getnext(stop)
 while current~=last do
   local char,target,cn=locl[current] or getchar(current),nil,getnext(current)
   local tpm=twopart_mark[char]
   if tpm then
     local extra=copy_node(current)
     copyinjection(extra,current)
     char=tpm[1]
     setchar(current,char)
     setchar(extra,tpm[2])
     head=insert_node_after(head,current,extra)
   end
   if not moved[current] and dependent_vowel[char] then
     if pre_mark[char] then
       moved[current]=true
       local prev,next=getboth(current)
       setlink(prev,next)
       if current==stop then
         stop=getprev(current)
       end
       if halfpos==start then
         if head==start then
           head=current
         end
         start=current
       end
       local prev=getprev(halfpos)
       setlink(prev,current)
       setlink(current,halfpos)
       halfpos=current
     elseif above_mark[char] then
       target=basepos
       if subpos==basepos then
         subpos=current
       end
       if postpos==basepos then
         postpos=current
       end
       basepos=current
     elseif below_mark[char] then
       target=subpos
       if postpos==subpos then
         postpos=current
       end
       subpos=current
     elseif post_mark[char] then
       target=postpos
       postpos=current
     end
     if mark_above_below_post[char] then
       local prev=getprev(current)
       if prev~=target then
         local next=getnext(current)
         setlink(prev,next)
         if current==stop then
           stop=prev
         end
         local next=getnext(target)
         setlink(current,next)
         setlink(target,current)
       end
     end
   end
   current=cn
 end
 local current,c=start,nil
 while current~=stop do
   local char=getchar(current)
   if halant[char] or stress_tone_mark[char] then
     if not c then
       c=current
     end
   else
     c=nil
   end
   local next=getnext(current)
   if c and nukta[getchar(next)] then
     if head==c then
       head=next
     end
     if stop==next then
       stop=current
     end
     local prev=getprev(c)
     setlink(prev,next)
     local nextnext=getnext(next)
     setnext(current,nextnext)
     local nextnextnext=getnext(nextnext)
     if nextnextnext then
       setprev(nextnextnext,current)
     end
     setlink(nextnext,c)
   end
   if stop==current then break end
   current=getnext(current)
 end
 if getchar(base)==c_nbsp then
   if base==stop then
     stop=getprev(stop)
   end
   nbspaces=nbspaces-1
   head=remove_node(head,base)
   flush_node(base)
 end
 return head,stop,nbspaces
end
local separator={}
imerge(separator,consonant)
imerge(separator,independent_vowel)
imerge(separator,dependent_vowel)
imerge(separator,vowel_modifier)
imerge(separator,stress_tone_mark)
for k,v in next,nukta do separator[k]=true end
for k,v in next,halant do separator[k]=true end
local function analyze_next_chars_one(c,font,variant)
 local n=getnext(c)
 if not n then
   return c
 end
 if variant==1 then
   local v=ischar(n,font)
   if v and nukta[v] then
     n=getnext(n)
     if n then
       v=ischar(n,font)
     end
   end
   if n and v then
     local nn=getnext(n)
     if nn then
       local vv=ischar(nn,font)
       if vv then
         local nnn=getnext(nn)
         if nnn then
           local vvv=ischar(nnn,font)
           if vvv then
             if vv==c_zwj and consonant[vvv] then
               c=nnn
             elseif (vv==c_zwnj or vv==c_zwj) and halant[vvv] then
               local nnnn=getnext(nnn)
               if nnnn then
                 local vvvv=ischar(nnnn,font)
                 if vvvv and consonant[vvvv] then
                   c=nnnn
                 end
               end
             end
           end
         end
       end
     end
   end
 elseif variant==2 then
   local v=ischar(n,font)
   if v and nukta[v] then
     c=n
   end
   n=getnext(c)
   if n then
     v=ischar(n,font)
     if v then
       local nn=getnext(n)
       if nn then
         local vv=ischar(nn,font)
         if vv and zw_char[v] then
           n=nn
           v=vv
           nn=getnext(nn)
           vv=nn and ischar(nn,font)
         end
         if vv and halant[v] and consonant[vv] then
           c=nn
         end
       end
     end
   end
 end
 local n=getnext(c)
 if not n then
   return c
 end
 local v=ischar(n,font)
 if not v then
   return c
 end
 if dependent_vowel[v] then
   c=getnext(c)
   n=getnext(c)
   if not n then
     return c
   end
   v=ischar(n,font)
   if not v then
     return c
   end
 end
 if nukta[v] then
   c=getnext(c)
   n=getnext(c)
   if not n then
     return c
   end
   v=ischar(n,font)
   if not v then
     return c
   end
 end
 if halant[v] then
   c=getnext(c)
   n=getnext(c)
   if not n then
     return c
   end
   v=ischar(n,font)
   if not v then
     return c
   end
 end
 if vowel_modifier[v] then
   c=getnext(c)
   n=getnext(c)
   if not n then
     return c
   end
   v=ischar(n,font)
   if not v then
     return c
   end
 end
 if stress_tone_mark[v] then
   c=getnext(c)
   n=getnext(c)
   if not n then
     return c
   end
   v=ischar(n,font)
   if not v then
     return c
   end
 end
 if stress_tone_mark[v] then
   return n
 else
   return c
 end
end
local function analyze_next_chars_two(c,font)
 local n=getnext(c)
 if not n then
   return c
 end
 local v=ischar(n,font)
 if v and nukta[v] then
   c=n
 end
 n=c
 while true do
   local nn=getnext(n)
   if nn then
     local vv=ischar(nn,font)
     if vv then
       if halant[vv] then
         n=nn
         local nnn=getnext(nn)
         if nnn then
           local vvv=ischar(nnn,font)
           if vvv and zw_char[vvv] then
             n=nnn
           end
         end
       elseif vv==c_zwnj or vv==c_zwj then
         local nnn=getnext(nn)
         if nnn then
           local vvv=ischar(nnn,font)
           if vvv and halant[vvv] then
             n=nnn
           end
         end
       else
         break
       end
       local nn=getnext(n)
       if nn then
         local vv=ischar(nn,font)
         if vv and consonant[vv] then
           n=nn
           local nnn=getnext(nn)
           if nnn then
             local vvv=ischar(nnn,font)
             if vvv and nukta[vvv] then
               n=nnn
             end
           end
           c=n
         else
           break
         end
       else
         break
       end
     else
       break
     end
   else
     break
   end
 end
 if not c then
   return
 end
 local n=getnext(c)
 if not n then
   return c
 end
 local v=ischar(n,font)
 if not v then
   return c
 end
 if v==c_anudatta then
   c=n
   n=getnext(c)
   if not n then
     return c
   end
   v=ischar(n,font)
   if not v then
     return c
   end
 end
 if halant[v] then
   c=n
   n=getnext(c)
   if not n then
     return c
   end
   v=ischar(n,font)
   if not v then
     return c
   end
   if v==c_zwnj or v==c_zwj then
     c=n
     n=getnext(c)
     if not n then
       return c
     end
     v=ischar(n,font)
     if not v then
       return c
     end
   end
 else
   if dependent_vowel[v] then
     c=n
     n=getnext(c)
     if not n then
       return c
     end
     v=ischar(n,font)
     if not v then
       return c
     end
   end
   if nukta[v] then
     c=n
     n=getnext(c)
     if not n then
       return c
     end
     v=ischar(n,font)
     if not v then
       return c
     end
   end
   if halant[v] then
     c=n
     n=getnext(c)
     if not n then
       return c
     end
     v=ischar(n,font)
     if not v then
       return c
     end
   end
 end
 if vowel_modifier[v] then
   c=n
   n=getnext(c)
   if not n then
     return c
   end
   v=ischar(n,font)
   if not v then
     return c
   end
 end
 if stress_tone_mark[v] then
   c=n
   n=getnext(c)
   if not n then
     return c
   end
   v=ischar(n,font)
   if not v then
     return c
   end
 end
 if stress_tone_mark[v] then
   return n
 else
   return c
 end
end
local function inject_syntax_error(head,current,mark)
 local signal=copy_node(current)
       copyinjection(signal,current)
 if mark==pre_mark then
   setchar(signal,dotted_circle)
 else
   setchar(current,dotted_circle)
 end
 return insert_node_after(head,current,signal)
end
function methods.deva(head,font,attr)
 head=tonut(head)
 local current=head
 local start=true
 local done=false
 local nbspaces=0
 while current do
               local char=ischar(current,font)
   if char then
     done=true
     local syllablestart=current
     local syllableend=nil
     local c=current
     local n=getnext(c)
           local first=char
     if n and ra[first] then
       local second=ischar(n,font)
       if second and halant[second] then
         local n=getnext(n)
         if n then
           local third=ischar(n,font)
           if third then
             c=n
             first=third
           end
         end
       end
     end
     local standalone=first==c_nbsp
     if standalone then
       local prev=getprev(current)
       if prev then
         local prevchar=ischar(prev,font)
         if not prevchar then
         elseif not separator[prevchar] then
         else
           standalone=false
         end
       else
       end
     end
     if standalone then
                               local syllableend=analyze_next_chars_one(c,font,2)
                               current=getnext(syllableend)
       if syllablestart~=syllableend then
         head,current,nbspaces=deva_reorder(head,syllablestart,syllableend,font,attr,nbspaces)
         current=getnext(current)
       end
     else
       if consonant[char] then
         local prevc=true
         while prevc do
           prevc=false
           local n=getnext(current)
           if not n then
             break
           end
           local v=ischar(n,font)
           if not v then
             break
           end
           if nukta[v] then
             n=getnext(n)
             if not n then
               break
             end
             v=ischar(n,font)
             if not v then
               break
             end
           end
           if halant[v] then
             n=getnext(n)
             if not n then
               break
             end
             v=ischar(n,font)
             if not v then
               break
             end
             if v==c_zwnj or v==c_zwj then
               n=getnext(n)
               if not n then
                 break
               end
               v=ischar(n,font)
               if not v then
                 break
               end
             end
             if consonant[v] then
               prevc=true
               current=n
             end
           end
         end
         local n=getnext(current)
         if n then
           local v=ischar(n,font)
           if v and nukta[v] then
             current=n
             n=getnext(current)
           end
         end
         syllableend=current
         current=n
         if current then
           local v=ischar(current,font)
           if not v then
           elseif halant[v] then
             local n=getnext(current)
             if n then
               local v=ischar(n,font)
               if v and zw_char[v] then
                 syllableend=n
                 current=getnext(n)
               else
                 syllableend=current
                 current=n
               end
             else
               syllableend=current
               current=n
             end
           else
             if dependent_vowel[v] then
               syllableend=current
               current=getnext(current)
               v=ischar(current,font)
             end
             if v and vowel_modifier[v] then
               syllableend=current
               current=getnext(current)
               v=ischar(current,font)
             end
             if v and stress_tone_mark[v] then
               syllableend=current
               current=getnext(current)
             end
           end
         end
         if syllablestart~=syllableend then
           head,current,nbspaces=deva_reorder(head,syllablestart,syllableend,font,attr,nbspaces)
           current=getnext(current)
         end
       elseif independent_vowel[char] then
         syllableend=current
         current=getnext(current)
         if current then
           local v=ischar(current,font)
           if v then
             if vowel_modifier[v] then
               syllableend=current
               current=getnext(current)
               v=ischar(current,font)
             end
             if v and stress_tone_mark[v] then
               syllableend=current
               current=getnext(current)
             end
           end
         end
       else
         local mark=mark_four[char]
         if mark then
           head,current=inject_syntax_error(head,current,mark)
         end
         current=getnext(current)
       end
     end
   else
     current=getnext(current)
   end
   start=false
 end
 if nbspaces>0 then
   head=replace_all_nbsp(head)
 end
 head=tonode(head)
 return head,done
end
function methods.dev2(head,font,attr)
 head=tonut(head)
 local current=head
 local start=true
 local done=false
 local syllabe=0
 local nbspaces=0
 while current do
   local syllablestart=nil
   local syllableend=nil
   local char=ischar(current,font)
   if char then
     done=true
     syllablestart=current
     local c=current
     local n=getnext(current)
     if n and ra[char] then
       local nextchar=ischar(n,font)
       if nextchar and halant[nextchar] then
         local n=getnext(n)
         if n then
           local nextnextchar=ischar(n,font)
           if nextnextchar then
             c=n
                                                       char=nextnextchar
           end
         end
       end
     end
     if independent_vowel[char] then
       current=analyze_next_chars_one(c,font,1)
       syllableend=current
     else
       local standalone=char==c_nbsp
       if standalone then
         nbspaces=nbspaces+1
         local p=getprev(current)
         if not p then
         elseif ischar(p,font) then
         elseif not separator[getchar(p)] then
         else
           standalone=false
         end
       end
       if standalone then
         current=analyze_next_chars_one(c,font,2)
         syllableend=current
       elseif consonant[getchar(current)] then
         current=analyze_next_chars_two(current,font)
         syllableend=current
       end
     end
   end
   if syllableend then
     syllabe=syllabe+1
     local c=syllablestart
     local n=getnext(syllableend)
     while c~=n do
       setprop(c,a_syllabe,syllabe)
       c=getnext(c)
     end
   end
   if syllableend and syllablestart~=syllableend then
     head,current,nbspaces=dev2_reorder(head,syllablestart,syllableend,font,attr,nbspaces)
   end
   if not syllableend then
     local char=ischar(current,font)
     if char and not getprop(current,a_state) then
       local mark=mark_four[char]
       if mark then
         head,current=inject_syntax_error(head,current,mark)
       end
     end
   end
   start=false
   current=getnext(current)
 end
 if nbspaces>0 then
   head=replace_all_nbsp(head)
 end
 head=tonode(head)
 return head,done
end
methods.mlym=methods.deva
methods.mlm2=methods.dev2

end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-osd”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ocl” fbc00782e4efb24a7569f99cd1574ffb] ---

if not modules then modules={} end modules ['font-ocl']={
 version=1.001,
 comment="companion to font-otf.lua (context)",
 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
 copyright="PRAGMA ADE / ConTeXt Development Team",
 license="see context related readme files"
}
local tostring,next,format=tostring,next,string.format
local round,max=math.round,math.round
local formatters=string.formatters
local tounicode=fonts.mappings.tounicode
local otf=fonts.handlers.otf
local f_color=formatters["pdf:direct:%f %f %f rg"]
local f_gray=formatters["pdf:direct:%f g"]
local s_black="pdf:direct:0 g"
if context then
 local startactualtext=nil
 local stopactualtext=nil
 function otf.getactualtext(s)
   if not startactualtext then
     startactualtext=backends.codeinjections.startunicodetoactualtextdirect
     stopactualtext=backends.codeinjections.stopunicodetoactualtextdirect
   end
   return startactualtext(s),stopactualtext()
 end
else
 local tounicode=fonts.mappings.tounicode16
 function otf.getactualtext(s)
   return
     "/Span << /ActualText <feff"..n.."> >> BDC",
     "EMC"
 end
end
local sharedpalettes={}
if context then
 local graytorgb=attributes.colors.graytorgb
 local cmyktorgb=attributes.colors.cmyktorgb
 function otf.registerpalette(name,values)
   sharedpalettes[name]=values
   for i=1,#values do
     local v=values[i]
     local r,g,b
     local s=v.s
     if s then
       r,g,b=graytorgb(s)
     else
       local c,m,y,k=v.c,v.m,v.y,v.k
       if c or m or y or k then
         r,g,b=cmyktorgb(c or 0,m or 0,y or 0,k or 0)
       else
         r,g,b=v.r,v.g,v.b
       end
     end
     values[i]={
       max(r and round(r*255) or 0,255),
       max(g and round(g*255) or 0,255),
       max(b and round(b*255) or 0,255)
     }
   end
 end
else
 function otf.registerpalette(name,values)
   sharedpalettes[name]=values
   for i=1,#values do
     local v=values[i]
     values[i]={
       max(round((v.r or 0)*255),255),
       max(round((v.g or 0)*255),255),
       max(round((v.b or 0)*255),255)
     }
   end
 end
end
local function initializecolr(tfmdata,kind,value)
 if value then
   local palettes=tfmdata.resources.colorpalettes
   if palettes then
     local palette=sharedpalettes[value] or palettes[tonumber(value) or 1] or palettes[1] or {}
     local classes=#palette
     if classes==0 then
       return
     end
     local characters=tfmdata.characters
     local descriptions=tfmdata.descriptions
     local properties=tfmdata.properties
     local colorvalues={}
     properties.virtualized=true
     tfmdata.fonts={
       { id=0 }
     }
     for i=1,classes do
       local p=palette[i]
       local r,g,b=p[1],p[2],p[3]
       if r==g and g==b then
         colorvalues[i]={ "special",f_gray(r/255) }
       else
         colorvalues[i]={ "special",f_color(r/255,g/255,b/255) }
       end
     end
     local getactualtext=otf.getactualtext
     for unicode,character in next,characters do
       local description=descriptions[unicode]
       if description then
         local colorlist=description.colors
         if colorlist then
           local b,e=getactualtext(tounicode(characters[unicode].unicode or 0xFFFD))
           local w=character.width or 0
           local s=#colorlist
           local t={
             { "special","pdf:page:q" },
             { "special","pdf:raw:"..b }
           }
           local n=#t
           for i=1,s do
             local entry=colorlist[i]
             n=n+1 t[n]=colorvalues[entry.class] or s_black
             n=n+1 t[n]={ "char",entry.slot }
             if s>1 and i<s and w~=0 then
               n=n+1 t[n]={ "right",-w }
             end
           end
           n=n+1 t[n]={ "special","pdf:page:"..e }
           n=n+1 t[n]={ "special","pdf:raw:Q" }
           character.commands=t
         end
       end
     end
   end
 end
end
fonts.handlers.otf.features.register {
 name="colr",
 description="color glyphs",
 manipulators={
   base=initializecolr,
   node=initializecolr,
 }
}
local otfsvg=otf.svg or {}
otf.svg=otfsvg
otf.svgenabled=true
do
 local nofstreams=0
 local f_name=formatters[ [[svg-glyph-%05i]] ]
 local f_used=context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ]
 local cache={}
 function otfsvg.storepdfdata(pdf)
   nofstreams=nofstreams+1
   local o,n=epdf.openMemStream(pdf,#pdf,f_name(nofstreams))
   cache[n]=o
   return nil,f_used(n),nil
 end
 if context then
   local storepdfdata=otfsvg.storepdfdata
   local initialized=false
   function otfsvg.storepdfdata(pdf)
     if not initialized then
       if resolvers.setmemstream then
         local f_setstream=formatters[ [[resolvers.setmemstream("svg-glyph-%05i",%q,true)]] ]
         local f_getstream=formatters[ [[memstream:///svg-glyph-%05i]] ]
         local f_nilstream=formatters[ [[resolvers.resetmemstream("svg-glyph-%05i",true)]] ]
         storepdfdata=function(pdf)
           nofstreams=nofstreams+1
           return
             f_setstream(nofstreams,pdf),
             f_getstream(nofstreams),
             f_nilstream(nofstreams)
         end
         otfsvg.storepdfdata=storepdfdata
       end
       initialized=true
     end
     return storepdfdata(pdf)
   end
 end
end
do
 local report_svg=logs.reporter("fonts","svg conversion")
 local loaddata=io.loaddata
 local savedata=io.savedata
 local remove=os.remove
 if context and xml.convert then
   local xmlconvert=xml.convert
   local xmlfirst=xml.first
   function otfsvg.filterglyph(entry,index)
     local svg=xmlconvert(entry.data)
     local root=svg and xmlfirst(svg,"/svg[@id='glyph"..index.."']")
     local data=root and tostring(root)
     return data
   end
 else
   function otfsvg.filterglyph(entry,index)
     return entry.data
   end
 end
 function otfsvg.topdf(svgshapes)
   local inkscape=io.popen("inkscape --shell > temp-otf-svg-shape.log","w")
   local pdfshapes={}
   local nofshapes=#svgshapes
   local f_svgfile=formatters["temp-otf-svg-shape-%i.svg"]
   local f_pdffile=formatters["temp-otf-svg-shape-%i.pdf"]
   local f_convert=formatters["%s --export-pdf=%s\n"]
   local filterglyph=otfsvg.filterglyph
   report_svg("processing %i svg containers",nofshapes)
   statistics.starttiming()
   for i=1,nofshapes do
     local entry=svgshapes[i]
     for index=entry.first,entry.last do
       local data=filterglyph(entry,index)
       if data and data~="" then
         local svgfile=f_svgfile(index)
         local pdffile=f_pdffile(index)
         savedata(svgfile,data)
         inkscape:write(f_convert(svgfile,pdffile))
         pdfshapes[index]=true
       end
     end
   end
   inkscape:write("quit\n")
   inkscape:close()
   report_svg("processing %i pdf results",nofshapes)
   for index in next,pdfshapes do
     local svgfile=f_svgfile(index)
     local pdffile=f_pdffile(index)
     pdfshapes[index]=loaddata(pdffile)
     remove(svgfile)
     remove(pdffile)
   end
   statistics.stoptiming()
   if statistics.elapsedseconds then
     report_svg("svg conversion time %s",statistics.elapsedseconds())
   end
   return pdfshapes
 end
end
local function initializesvg(tfmdata,kind,value)
 if value and otf.svgenabled then
   local characters=tfmdata.characters
   local descriptions=tfmdata.descriptions
   local properties=tfmdata.properties
   local svg=properties.svg
   local hash=svg and svg.hash
   local timestamp=svg and svg.timestamp
   if not hash then
     return
   end
   local pdffile=containers.read(otf.pdfcache,hash)
   local pdfshapes=pdffile and pdffile.pdfshapes
   if not pdfshapes or pdffile.timestamp~=timestamp then
     local svgfile=containers.read(otf.svgcache,hash)
     local svgshapes=svgfile and svgfile.svgshapes
     pdfshapes=svgshapes and otfsvg.topdf(svgshapes) or {}
     containers.write(otf.pdfcache,hash,{
       pdfshapes=pdfshapes,
       timestamp=timestamp,
     })
   end
   if not pdfshapes or not next(pdfshapes) then
     return
   end
   properties.virtualized=true
   tfmdata.fonts={
     { id=0 }
   }
   local getactualtext=otf.getactualtext
   local storepdfdata=otfsvg.storepdfdata
   local nop={ "nop" }
   for unicode,character in next,characters do
     local index=character.index
     if index then
       local pdf=pdfshapes[index]
       if pdf then
         local setcode,name,nilcode=storepdfdata(pdf)
         if name then
           local bt,et=getactualtext(unicode)
           local wd=character.width or 0
           local ht=character.height or 0
           local dp=character.depth or 0
           character.commands={
             { "special","pdf:direct:"..bt },
             { "down",dp },
             setcode and { "lua",setcode } or nop,
             { "image",{ filename=name,width=wd,height=ht,depth=dp } },
             nilcode and { "lua",nilcode } or nop,
             { "special","pdf:direct:"..et },
           }
           character.svg=true
         end
       end
     end
   end
 end
end
fonts.handlers.otf.features.register {
 name="svg",
 description="svg glyphs",
 manipulators={
   base=initializesvg,
   node=initializesvg,
 }
}

end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ocl”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-otc” 85d63e257c748c624768aa7c8ec7f0bc] ---

if not modules then modules={} end modules ['font-otc']={
 version=1.001,
 comment="companion to font-otf.lua (context)",
 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
 copyright="PRAGMA ADE / ConTeXt Development Team",
 license="see context related readme files"
}
local format,insert,sortedkeys,tohash=string.format,table.insert,table.sortedkeys,table.tohash
local type,next=type,next
local lpegmatch=lpeg.match
local utfbyte,utflen=utf.byte,utf.len
local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end)
local report_otf=logs.reporter("fonts","otf loading")
local fonts=fonts
local otf=fonts.handlers.otf
local registerotffeature=otf.features.register
local setmetatableindex=table.setmetatableindex
local normalized={
 substitution="substitution",
 single="substitution",
 ligature="ligature",
 alternate="alternate",
 multiple="multiple",
 kern="kern",
 pair="pair",
 chainsubstitution="chainsubstitution",
 chainposition="chainposition",
}
local types={
 substitution="gsub_single",
 ligature="gsub_ligature",
 alternate="gsub_alternate",
 multiple="gsub_multiple",
 kern="gpos_pair",
 pair="gpos_pair",
 chainsubstitution="gsub_contextchain",
 chainposition="gpos_contextchain",
}
local names={
 gsub_single="gsub",
 gsub_multiple="gsub",
 gsub_alternate="gsub",
 gsub_ligature="gsub",
 gsub_context="gsub",
 gsub_contextchain="gsub",
 gsub_reversecontextchain="gsub",
 gpos_single="gpos",
 gpos_pair="gpos",
 gpos_cursive="gpos",
 gpos_mark2base="gpos",
 gpos_mark2ligature="gpos",
 gpos_mark2mark="gpos",
 gpos_context="gpos",
 gpos_contextchain="gpos",
}
setmetatableindex(types,function(t,k) t[k]=k return k end)
local everywhere={ ["*"]={ ["*"]=true } }
local noflags={ false,false,false,false }
local function getrange(sequences,category)
 local count=#sequences
 local first=nil
 local last=nil
 for i=1,count do
   local t=sequences[i].type
   if t and names[t]==category then
     if not first then
       first=i
     end
     last=i
   end
 end
 return first or 1,last or count
end
local function validspecification(specification,name)
 local dataset=specification.dataset
 if dataset then
 elseif specification[1] then
   dataset=specification
   specification={ dataset=dataset }
 else
   dataset={ { data=specification.data } }
   specification.data=nil
   specification.dataset=dataset
 end
 local first=dataset[1]
 if first then
   first=first.data
 end
 if not first then
   report_otf("invalid feature specification, no dataset")
   return
 end
 if type(name)~="string" then
   name=specification.name or first.name
 end
 if type(name)~="string" then
   report_otf("invalid feature specification, no name")
   return
 end
 local n=#dataset
 if n>0 then
   for i=1,n do
     setmetatableindex(dataset[i],specification)
   end
   return specification,name
 end
end
local function addfeature(data,feature,specifications)
 if not specifications then
   report_otf("missing specification")
   return
 end
 local descriptions=data.descriptions
 local resources=data.resources
 local features=resources.features
 local sequences=resources.sequences
 if not features or not sequences then
   report_otf("missing specification")
   return
 end
 local alreadydone=resources.alreadydone
 if not alreadydone then
   alreadydone={}
   resources.alreadydone=alreadydone
 end
 if alreadydone[specifications] then
   return
 else
   alreadydone[specifications]=true
 end
 local fontfeatures=resources.features or everywhere
 local unicodes=resources.unicodes
 local splitter=lpeg.splitter(" ",unicodes)
 local done=0
 local skip=0
 local aglunicodes=false
 local specifications=validspecification(specifications,feature)
 if not specifications then
   return
 end
 local function tounicode(code)
   if not code then
     return
   end
   if type(code)=="number" then
     return code
   end
   local u=unicodes[code]
   if u then
     return u
   end
   if utflen(code)==1 then
     u=utfbyte(code)
     if u then
       return u
     end
   end
   if not aglunicodes then
     aglunicodes=fonts.encodings.agl.unicodes
   end
   return aglunicodes[code]
 end
 local coverup=otf.coverup
 local coveractions=coverup.actions
 local stepkey=coverup.stepkey
 local register=coverup.register
 local function prepare_substitution(list,featuretype)
   local coverage={}
   local cover=coveractions[featuretype]
   for code,replacement in next,list do
     local unicode=tounicode(code)
     local description=descriptions[unicode]
     if description then
       if type(replacement)=="table" then
         replacement=replacement[1]
       end
       replacement=tounicode(replacement)
       if replacement and descriptions[replacement] then
         cover(coverage,unicode,replacement)
         done=done+1
       else
         skip=skip+1
       end
     else
       skip=skip+1
     end
   end
   return coverage
 end
 local function prepare_alternate(list,featuretype)
   local coverage={}
   local cover=coveractions[featuretype]
   for code,replacement in next,list do
     local unicode=tounicode(code)
     local description=descriptions[unicode]
     if not description then
       skip=skip+1
     elseif type(replacement)=="table" then
       local r={}
       for i=1,#replacement do
         local u=tounicode(replacement[i])
         r[i]=descriptions[u] and u or unicode
       end
       cover(coverage,unicode,r)
       done=done+1
     else
       local u=tounicode(replacement)
       if u then
         cover(coverage,unicode,{ u })
         done=done+1
       else
         skip=skip+1
       end
     end
   end
   return coverage
 end
 local function prepare_multiple(list,featuretype)
   local coverage={}
   local cover=coveractions[featuretype]
   for code,replacement in next,list do
     local unicode=tounicode(code)
     local description=descriptions[unicode]
     if not description then
       skip=skip+1
     elseif type(replacement)=="table" then
       local r,n={},0
       for i=1,#replacement do
         local u=tounicode(replacement[i])
         if descriptions[u] then
           n=n+1
           r[n]=u
         end
       end
       if n>0 then
         cover(coverage,unicode,r)
         done=done+1
       else
         skip=skip+1
       end
     else
       local u=tounicode(replacement)
       if u then
         cover(coverage,unicode,{ u })
         done=done+1
       else
         skip=skip+1
       end
     end
   end
   return coverage
 end
 local function prepare_ligature(list,featuretype)
   local coverage={}
   local cover=coveractions[featuretype]
   for code,ligature in next,list do
     local unicode=tounicode(code)
     local description=descriptions[unicode]
     if description then
       if type(ligature)=="string" then
         ligature={ lpegmatch(splitter,ligature) }
       end
       local present=true
       for i=1,#ligature do
         local l=ligature[i]
         local u=tounicode(l)
         if descriptions[u] then
           ligature[i]=u
         else
           present=false
           break
         end
       end
       if present then
         cover(coverage,unicode,ligature)
         done=done+1
       else
         skip=skip+1
       end
     else
       skip=skip+1
     end
   end
   return coverage
 end
 local function prepare_kern(list,featuretype)
   local coverage={}
   local cover=coveractions[featuretype]
   for code,replacement in next,list do
     local unicode=tounicode(code)
     local description=descriptions[unicode]
     if description and type(replacement)=="table" then
       local r={}
       for k,v in next,replacement do
         local u=tounicode(k)
         if u then
           r[u]=v
         end
       end
       if next(r) then
         cover(coverage,unicode,r)
         done=done+1
       else
         skip=skip+1
       end
     else
       skip=skip+1
     end
   end
   return coverage
 end
 local function prepare_pair(list,featuretype)
   local coverage={}
   local cover=coveractions[featuretype]
   if cover then
     for code,replacement in next,list do
       local unicode=tounicode(code)
       local description=descriptions[unicode]
       if description and type(replacement)=="table" then
         local r={}
         for k,v in next,replacement do
           local u=tounicode(k)
           if u then
             r[u]=v
           end
         end
         if next(r) then
           cover(coverage,unicode,r)
           done=done+1
         else
           skip=skip+1
         end
       else
         skip=skip+1
       end
     end
   else
     report_otf("unknown cover type %a",featuretype)
   end
   return coverage
 end
 local function prepare_chain(list,featuretype,sublookups)
   local rules=list.rules
   local coverage={}
   if rules then
     local rulehash={}
     local rulesize=0
     local sequence={}
     local nofsequences=0
     local lookuptype=types[featuretype]
     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 or false
       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
       local lookups=rule.lookups or false
       local subtype=nil
       if lookups and sublookups then
         for k,v in next,lookups do
           local lookup=sublookups[v]
           if lookup then
             lookups[k]=lookup
             if not subtype then
               subtype=lookup.type
             end
           else
           end
         end
       end
       if nofsequences>0 then
         local hashed={}
         for i=1,nofsequences do
           local t={}
           local s=sequence[i]
           for i=1,#s do
             local u=tounicode(s[i])
             if u then
               t[u]=true
             end
           end
           hashed[i]=t
         end
         sequence=hashed
         rulesize=rulesize+1
         rulehash[rulesize]={
           nofrules,
           lookuptype,
           sequence,
           start,
           stop,
           lookups,
           replacements,
           subtype,
         }
         for unic in next,sequence[start] do
           local cu=coverage[unic]
           if not cu then
             coverage[unic]=rulehash
           end
         end
       end
     end
   end
   return coverage
 end
 local dataset=specifications.dataset
 local function report(name,category,position,first,last,sequences)
   report_otf("injecting name %a of category %a at position %i in [%i,%i] of [%i,%i]",
     name,category,position,first,last,1,#sequences)
 end
 local function inject(specification,sequences,sequence,first,last,category,name)
   local position=specification.position or false
   if not position then
     position=specification.prepend
     if position==true then
       if trace_loading then
         report(name,category,first,first,last,sequences)
       end
       insert(sequences,first,sequence)
       return
     end
   end
   if not position then
     position=specification.append
     if position==true then
       if trace_loading then
         report(name,category,last+1,first,last,sequences)
       end
       insert(sequences,last+1,sequence)
       return
     end
   end
   local kind=type(position)
   if kind=="string" then
     local index=false
     for i=first,last do
       local s=sequences[i]
       local f=s.features
       if f then
         for k in next,f do
           if k==position then
             index=i
             break
           end
         end
         if index then
           break
         end
       end
     end
     if index then
       position=index
     else
       position=last+1
     end
   elseif kind=="number" then
     if position<0 then
       position=last-position+1
     end
     if position>last then
       position=last+1
     elseif position<first then
       position=first
     end
   else
     position=last+1
   end
   if trace_loading then
     report(name,category,position,first,last,sequences)
   end
   insert(sequences,position,sequence)
 end
 for s=1,#dataset do
   local specification=dataset[s]
   local valid=specification.valid
   local feature=specification.name or feature
   if not feature or feature=="" then
     report_otf("no valid name given for extra feature")
   elseif not valid or valid(data,specification,feature) then
     local initialize=specification.initialize
     if initialize then
       specification.initialize=initialize(specification,data) and initialize or nil
     end
     local askedfeatures=specification.features or everywhere
     local askedsteps=specification.steps or specification.subtables or { specification.data } or {}
     local featuretype=normalized[specification.type or "substitution"] or "substitution"
     local featureflags=specification.flags or noflags
     local featureorder=specification.order or { feature }
     local featurechain=(featuretype=="chainsubstitution" or featuretype=="chainposition") and 1 or 0
     local nofsteps=0
     local steps={}
     local sublookups=specification.lookups
     local category=nil
     if sublookups then
       local s={}
       for i=1,#sublookups do
         local specification=sublookups[i]
         local askedsteps=specification.steps or specification.subtables or { specification.data } or {}
         local featuretype=normalized[specification.type or "substitution"] or "substitution"
         local featureflags=specification.flags or noflags
         local nofsteps=0
         local steps={}
         for i=1,#askedsteps do
           local list=askedsteps[i]
           local coverage=nil
           local format=nil
           if featuretype=="substitution" then
             coverage=prepare_substitution(list,featuretype)
           elseif featuretype=="ligature" then
             coverage=prepare_ligature(list,featuretype)
           elseif featuretype=="alternate" then
             coverage=prepare_alternate(list,featuretype)
           elseif featuretype=="multiple" then
             coverage=prepare_multiple(list,featuretype)
           elseif featuretype=="kern" then
             format="kern"
             coverage=prepare_kern(list,featuretype)
           elseif featuretype=="pair" then
             format="pair"
             coverage=prepare_pair(list,featuretype)
           end
           if coverage and next(coverage) then
             nofsteps=nofsteps+1
             steps[nofsteps]=register(coverage,featuretype,format,feature,nofsteps,descriptions,resources)
           end
         end
         s[i]={
           [stepkey]=steps,
           nofsteps=nofsteps,
           type=types[featuretype],
         }
       end
       sublookups=s
     end
     for i=1,#askedsteps do
       local list=askedsteps[i]
       local coverage=nil
       local format=nil
       if featuretype=="substitution" then
         category="gsub"
         coverage=prepare_substitution(list,featuretype)
       elseif featuretype=="ligature" then
         category="gsub"
         coverage=prepare_ligature(list,featuretype)
       elseif featuretype=="alternate" then
         category="gsub"
         coverage=prepare_alternate(list,featuretype)
       elseif featuretype=="multiple" then
         category="gsub"
         coverage=prepare_multiple(list,featuretype)
       elseif featuretype=="kern" then
         category="gpos"
         format="kern"
         coverage=prepare_kern(list,featuretype)
       elseif featuretype=="pair" then
         category="gpos"
         format="pair"
         coverage=prepare_pair(list,featuretype)
       elseif featuretype=="chainsubstitution" then
         category="gsub"
         coverage=prepare_chain(list,featuretype,sublookups)
       elseif featuretype=="chainposition" then
         category="gpos"
         coverage=prepare_chain(list,featuretype,sublookups)
       else
         report_otf("not registering feature %a, unknown category",feature)
         return
       end
       if coverage and next(coverage) then
         nofsteps=nofsteps+1
         steps[nofsteps]=register(coverage,featuretype,format,feature,nofsteps,descriptions,resources)
       end
     end
     if nofsteps>0 then
       for k,v in next,askedfeatures do
         if v[1] then
           askedfeatures[k]=tohash(v)
         end
       end
       if featureflags[1] then featureflags[1]="mark" end
       if featureflags[2] then featureflags[2]="ligature" end
       if featureflags[3] then featureflags[3]="base" end
       local steptype=types[featuretype]
       local sequence={
         chain=featurechain,
         features={ [feature]=askedfeatures },
         flags=featureflags,
         name=feature,
         order=featureorder,
         [stepkey]=steps,
         nofsteps=nofsteps,
         type=steptype,
       }
       local first,last=getrange(sequences,category)
       inject(specification,sequences,sequence,first,last,category,feature)
       local features=fontfeatures[category]
       if not features then
         features={}
         fontfeatures[category]=features
       end
       local k=features[feature]
       if not k then
         k={}
         features[feature]=k
       end
       for script,languages in next,askedfeatures do
         local kk=k[script]
         if not kk then
           kk={}
           k[script]=kk
         end
         for language,value in next,languages do
           kk[language]=value
         end
       end
     end
   end
 end
 if trace_loading then
   report_otf("registering feature %a, affected glyphs %a, skipped glyphs %a",feature,done,skip)
 end
end
otf.enhancers.addfeature=addfeature
local extrafeatures={}
local knownfeatures={}
function otf.addfeature(name,specification)
 if type(name)=="table" then
   specification=name
 end
 if type(specification)~="table" then
   report_otf("invalid feature specification, no valid table")
   return
 end
 specification,name=validspecification(specification,name)
 if name and specification then
   local slot=knownfeatures[name]
   if slot then
   else
     slot=#extrafeatures+1
     knownfeatures[name]=slot
   end
   specification.name=name
   extrafeatures[slot]=specification
 end
end
local function enhance(data,filename,raw)
 for slot=1,#extrafeatures do
   local specification=extrafeatures[slot]
   addfeature(data,specification.name,specification)
 end
end
otf.enhancers.enhance=enhance
otf.enhancers.register("check extra features",enhance)
local tlig={
 [0x2013]={ 0x002D,0x002D },
 [0x2014]={ 0x002D,0x002D,0x002D },
}
local tlig_specification={
 type="ligature",
 features=everywhere,
 data=tlig,
 order={ "tlig" },
 flags=noflags,
 prepend=true,
}
otf.addfeature("tlig",tlig_specification)
registerotffeature {
 name='tlig',
 description='tex ligatures',
}
local trep={
 [0x0027]=0x2019,
}
local trep_specification={
 type="substitution",
 features=everywhere,
 data=trep,
 order={ "trep" },
 flags=noflags,
 prepend=true,
}
otf.addfeature("trep",trep_specification)
registerotffeature {
 name='trep',
 description='tex replacements',
}
local anum_arabic={
 [0x0030]=0x0660,
 [0x0031]=0x0661,
 [0x0032]=0x0662,
 [0x0033]=0x0663,
 [0x0034]=0x0664,
 [0x0035]=0x0665,
 [0x0036]=0x0666,
 [0x0037]=0x0667,
 [0x0038]=0x0668,
 [0x0039]=0x0669,
}
local anum_persian={
 [0x0030]=0x06F0,
 [0x0031]=0x06F1,
 [0x0032]=0x06F2,
 [0x0033]=0x06F3,
 [0x0034]=0x06F4,
 [0x0035]=0x06F5,
 [0x0036]=0x06F6,
 [0x0037]=0x06F7,
 [0x0038]=0x06F8,
 [0x0039]=0x06F9,
}
local function valid(data)
 local features=data.resources.features
 if features then
   for k,v in next,features do
     for k,v in next,v do
       if v.arab then
         return true
       end
     end
   end
 end
end
local anum_specification={
 {
   type="substitution",
   features={ arab={ urd=true,dflt=true } },
   order={ "anum" },
   data=anum_arabic,
   flags=noflags,
   valid=valid,
 },
 {
   type="substitution",
   features={ arab={ urd=true } },
   order={ "anum" },
   data=anum_persian,
   flags=noflags,
   valid=valid,
 },
}
otf.addfeature("anum",anum_specification)
registerotffeature {
 name='anum',
 description='arabic digits',
}

end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-otc”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-onr” 205c8bc640715aecf3538a33b842f450] ---

if not modules then modules={} end modules ['font-onr']={
 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,resolvers=fonts,logs,trackers,resolvers
local next,type,tonumber,rawget,rawset=next,type,tonumber,rawget,rawset
local match,lower,gsub,strip,find=string.match,string.lower,string.gsub,string.strip,string.find
local char,byte,sub=string.char,string.byte,string.sub
local abs=math.abs
local bxor,rshift=bit32.bxor,bit32.rshift
local P,S,R,Cmt,C,Ct,Cs,Carg,Cf,Cg=lpeg.P,lpeg.S,lpeg.R,lpeg.Cmt,lpeg.C,lpeg.Ct,lpeg.Cs,lpeg.Carg,lpeg.Cf,lpeg.Cg
local lpegmatch,patterns=lpeg.match,lpeg.patterns
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 report_afm=logs.reporter("fonts","afm loading")
local report_pfb=logs.reporter("fonts","pfb loading")
local handlers=fonts.handlers
local afm=handlers.afm or {}
handlers.afm=afm
local readers=afm.readers or {}
afm.readers=readers
afm.version=1.512
local get_indexes,get_shapes
do
 local decrypt
 do
   local r,c1,c2,n=0,0,0,0
   local function step(c)
     local cipher=byte(c)
     local plain=bxor(cipher,rshift(r,8))
     r=((cipher+r)*c1+c2)%65536
     return char(plain)
   end
   decrypt=function(binary,initial,seed)
     r,c1,c2,n=initial,52845,22719,seed
     binary=gsub(binary,".",step)
     return sub(binary,n+1)
   end
 end
 local charstrings=P("/CharStrings")
 local subroutines=P("/Subrs")
 local encoding=P("/Encoding")
 local dup=P("dup")
 local put=P("put")
 local array=P("array")
 local name=P("/")*C((R("az")+R("AZ")+R("09")+S("-_."))^1)
 local digits=R("09")^1
 local cardinal=digits/tonumber
 local spaces=P(" ")^1
 local spacing=patterns.whitespace^0
 local routines,vector,chars,n,m
 local initialize=function(str,position,size)
   n=0
   m=size
   return position+1
 end
 local setroutine=function(str,position,index,size)
   local forward=position+tonumber(size)
   local stream=sub(str,position+1,forward)
   routines[index]=decrypt(stream,4330,4)
   return forward
 end
 local setvector=function(str,position,name,size)
   local forward=position+tonumber(size)
   if n>=m then
     return #str
   elseif forward<#str then
     vector[n]=name
     n=n+1
     return forward
   else
     return #str
   end
 end
 local setshapes=function(str,position,name,size)
   local forward=position+tonumber(size)
   local stream=sub(str,position+1,forward)
   if n>m then
     return #str
   elseif forward<#str then
     vector[n]=name
     n=n+1
     chars [n]=decrypt(stream,4330,4)
     return forward
   else
     return #str
   end
 end
 local p_rd=spacing*(P("RD")+P("-|"))
 local p_np=spacing*(P("NP")+P("|"))
 local p_nd=spacing*(P("ND")+P("|"))
 local p_filterroutines=
   (1-subroutines)^0*subroutines*spaces*Cmt(cardinal,initialize)*(Cmt(cardinal*spaces*cardinal*p_rd,setroutine)*p_np+P(1))^1
 local p_filtershapes=
   (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal*p_rd,setshapes)*p_nd+P(1))^1
 local p_filternames=Ct (
   (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal,setvector)+P(1))^1
 )
 local p_filterencoding=(1-encoding)^0*encoding*spaces*digits*spaces*array*(1-dup)^0*Cf(
     Ct("")*Cg(spacing*dup*spaces*cardinal*spaces*name*spaces*put)^1
,rawset)
 local function loadpfbvector(filename,shapestoo)
   local data=io.loaddata(resolvers.findfile(filename))
   if not data then
     report_pfb("no data in %a",filename)
     return
   end
   if not (find(data,"!PS%-AdobeFont%-") or find(data,"%%!FontType1")) then
     report_pfb("no font in %a",filename)
     return
   end
   local ascii,binary=match(data,"(.*)eexec%s+......(.*)")
   if not binary then
     report_pfb("no binary data in %a",filename)
     return
   end
   binary=decrypt(binary,55665,4)
   local names={}
   local encoding=lpegmatch(p_filterencoding,ascii)
   local glyphs={}
   routines,vector,chars={},{},{}
   if shapestoo then
     lpegmatch(p_filterroutines,binary)
     lpegmatch(p_filtershapes,binary)
     local data={
       dictionaries={
         {
           charstrings=chars,
           charset=vector,
           subroutines=routines,
         }
       },
     }
     fonts.handlers.otf.readers.parsecharstrings(data,glyphs,true,true)
   else
     lpegmatch(p_filternames,binary)
   end
   names=vector
   routines,vector,chars=nil,nil,nil
   return names,encoding,glyphs
 end
 local pfb=handlers.pfb or {}
 handlers.pfb=pfb
 pfb.loadvector=loadpfbvector
 get_indexes=function(data,pfbname)
   local vector=loadpfbvector(pfbname)
   if vector then
     local characters=data.characters
     if trace_loading then
       report_afm("getting index data from %a",pfbname)
     end
     for index=1,#vector do
       local name=vector[index]
       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
 end
 get_shapes=function(pfbname)
   local vector,encoding,glyphs=loadpfbvector(pfbname,true)
   return glyphs
 end
end
local spacer=patterns.spacer
local whitespace=patterns.whitespace
local lineend=patterns.newline
local spacing=spacer^0
local number=spacing*S("+-")^-1*(R("09")+S("."))^1/tonumber
local name=spacing*C((1-whitespace)^1)
local words=spacing*((1-lineend)^1/strip)
local rest=(1-lineend)^0
local fontdata=Carg(1)
local semicolon=spacing*P(";")
local plus=spacing*P("plus")*number
local minus=spacing*P("minus")*number
local function addkernpair(data,one,two,value)
 local chr=data.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
local p_kernpair=(fontdata*P("KPX")*name*name*number)/addkernpair
local chr=false
local ind=0
local function start(data,version)
 data.metadata.afmversion=version
 ind=0
 chr={}
end
local function stop()
 ind=0
 chr=false
end
local function setindex(i)
 if i<0 then
   ind=ind+1
 else
   ind=i
 end
 chr={
   index=ind
 }
end
local function setwidth(width)
 chr.width=width
end
local function setname(data,name)
 data.characters[name]=chr
end
local function setboundingbox(boundingbox)
 chr.boundingbox=boundingbox
end
local function setligature(plus,becomes)
 local ligatures=chr.ligatures
 if ligatures then
   ligatures[plus]=becomes
 else
   chr.ligatures={ [plus]=becomes }
 end
end
local p_charmetric=((
 P("C")*number/setindex+P("WX")*number/setwidth+P("N")*fontdata*name/setname+P("B")*Ct((number)^4)/setboundingbox+P("L")*(name)^2/setligature
)*semicolon )^1
local p_charmetrics=P("StartCharMetrics")*number*(p_charmetric+(1-P("EndCharMetrics")))^0*P("EndCharMetrics")
local p_kernpairs=P("StartKernPairs")*number*(p_kernpair+(1-P("EndKernPairs" )))^0*P("EndKernPairs" )
local function set_1(data,key,a)   data.metadata[lower(key)]=a      end
local function set_2(data,key,a,b)  data.metadata[lower(key)]={ a,b }  end
local function set_3(data,key,a,b,c) data.metadata[lower(key)]={ a,b,c } end
local p_parameters=P(false)+fontdata*((P("FontName")+P("FullName")+P("FamilyName"))/lower)*words/function(data,key,value)
   data.metadata[key]=value
 end+fontdata*((P("Weight")+P("Version"))/lower)*name/function(data,key,value)
   data.metadata[key]=value
 end+fontdata*P("IsFixedPitch")*name/function(data,pitch)
   data.metadata.monospaced=toboolean(pitch,true)
 end+fontdata*P("FontBBox")*Ct(number^4)/function(data,boundingbox)
   data.metadata.boundingbox=boundingbox
end+fontdata*((P("CharWidth")+P("CapHeight")+P("XHeight")+P("Descender")+P("Ascender")+P("ItalicAngle"))/lower)*number/function(data,key,value)
   data.metadata[key]=value
 end+P("Comment")*spacing*(P(false)+(fontdata*C("DESIGNSIZE")*number*rest)/set_1
+(fontdata*C("TFM designsize")*number*rest)/set_1+(fontdata*C("DesignSize")*number*rest)/set_1+(fontdata*C("CODINGSCHEME")*words*rest)/set_1
+(fontdata*C("CHECKSUM")*number*words*rest)/set_1
+(fontdata*C("SPACE")*number*plus*minus*rest)/set_3
+(fontdata*C("QUAD")*number*rest)/set_1
+(fontdata*C("EXTRASPACE")*number*rest)/set_1
+(fontdata*C("NUM")*number*number*number*rest)/set_3
+(fontdata*C("DENOM")*number*number*rest)/set_2
+(fontdata*C("SUP")*number*number*number*rest)/set_3
+(fontdata*C("SUB")*number*number*rest)/set_2
+(fontdata*C("SUPDROP")*number*rest)/set_1
+(fontdata*C("SUBDROP")*number*rest)/set_1
+(fontdata*C("DELIM")*number*number*rest)/set_2
+(fontdata*C("AXISHEIGHT")*number*rest)/set_1
 )
local fullparser=(P("StartFontMetrics")*fontdata*name/start )*(p_charmetrics+p_kernpairs+p_parameters+(1-P("EndFontMetrics")) )^0*(P("EndFontMetrics")/stop )
local fullparser=(P("StartFontMetrics")*fontdata*name/start )*(p_charmetrics+p_kernpairs+p_parameters+(1-P("EndFontMetrics")) )^0*(P("EndFontMetrics")/stop )
local infoparser=(P("StartFontMetrics")*fontdata*name/start )*(p_parameters+(1-P("EndFontMetrics")) )^0*(P("EndFontMetrics")/stop )
local function read(filename,parser)
 local afmblob=io.loaddata(filename)
 if 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={
     },
   }
   if trace_loading then
     report_afm("parsing afm file %a",filename)
   end
   lpegmatch(parser,afmblob,1,data)
   return data
 else
   if trace_loading then
     report_afm("no valid afm file %a",filename)
   end
   return nil
 end
end
function readers.loadfont(afmname,pfbname)
 local data=read(resolvers.findfile(afmname),fullparser)
 if data then
   if not pfbname or pfbname=="" then
     pfbname=file.replacesuffix(file.nameonly(afmname),"pfb")
     pfbname=resolvers.findfile(pfbname)
   end
   if pfbname and pfbname~="" then
     data.resources.filename=resolvers.unresolve(pfbname)
     get_indexes(data,pfbname)
   elseif trace_loading then
     report_afm("no pfb file for %a",afmname)
   end
   return data
 end
end
function readers.loadshapes(filename)
 local fullname=resolvers.findfile(filename) or ""
 if fullname=="" then
   return {
     filename="not found: "..filename,
     glyphs={}
   }
 else
   return {
     filename=fullname,
     format="opentype",
     glyphs=get_shapes(fullname) or {},
     units=1000,
   }
 end
end
function readers.getinfo(filename)
 local data=read(resolvers.findfile(filename),infoparser)
 if data then
   return data.metadata
 end
end

end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-onr”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-one” 6fbf6b9e219a944cd1ad5933d77cc488] ---

if not modules then modules={} end modules ['font-one']={
 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,rawget=next,type,tonumber,rawget
local match,gmatch,lower,gsub,strip,find=string.match,string.gmatch,string.lower,string.gsub,string.strip,string.find
local char,byte,sub=string.char,string.byte,string.sub
local abs=math.abs
local bxor,rshift=bit32.bxor,bit32.rshift
local P,S,R,Cmt,C,Ct,Cs,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.Cmt,lpeg.C,lpeg.Ct,lpeg.Cs,lpeg.Carg
local lpegmatch,patterns=lpeg.match,lpeg.patterns
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 setmetatableindex=table.setmetatableindex
local derivetable=table.derive
local findbinfile=resolvers.findbinfile
local definers=fonts.definers
local readers=fonts.readers
local constructors=fonts.constructors
local afm=constructors.handlers.afm
local pfb=constructors.handlers.pfb
local otf=fonts.handlers.otf
local otfreaders=otf.readers
local otfenhancers=otf.enhancers
local afmfeatures=constructors.features.afm
local registerafmfeature=afmfeatures.register
local afmenhancers=constructors.enhancers.afm
local registerafmenhancer=afmenhancers.register
afm.version=1.512
afm.cache=containers.define("fonts","one",afm.version,true)
afm.autoprefixed=true
afm.helpdata={}
afm.syncspace=true
local overloads=fonts.mappings.overloads
local applyruntimefixes=fonts.treatments and fonts.treatments.applyfixes
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=afm.readers.loadfont(filename,pfbname)
     if data then
       afmenhancers.apply(data,filename)
       fonts.mappings.addtounicode(data,filename)
       otfreaders.pack(data)
       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
   end
   if data then
     otfreaders.unpack(data)
     otfreaders.expand(data)
     otfreaders.addunicodetable(data)
     otfenhancers.apply(data,filename,data)
     if applyruntimefixes then
       applyruntimefixes(filename,data)
     end
   end
   return data
 end
end
local uparser=fonts.mappings.makenameparser()
local function enhance_unify_names(data,filename)
 local unicodevector=fonts.encodings.agl.unicodes
 local unicodes={}
 local 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 type(code)~="number" 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.private=private
end
local everywhere={ ["*"]={ ["*"]=true } }
local noflags={ false,false,false,false }
local function enhance_normalize_features(data)
 local ligatures=setmetatableindex("table")
 local kerns=setmetatableindex("table")
 local extrakerns=setmetatableindex("table")
 for u,c in next,data.descriptions do
   local l=c.ligatures
   local k=c.kerns
   local e=c.extrakerns
   if l then
     ligatures[u]=l
     for u,v in next,l do
       l[u]={ ligature=v }
     end
     c.ligatures=nil
   end
   if k then
     kerns[u]=k
     for u,v in next,k do
       k[u]=v
     end
     c.kerns=nil
   end
   if e then
     extrakerns[u]=e
     for u,v in next,e do
       e[u]=v
     end
     c.extrakerns=nil
   end
 end
 local features={
   gpos={},
   gsub={},
 }
 local sequences={
 }
 if next(ligatures) then
   features.gsub.liga=everywhere
   data.properties.hasligatures=true
   sequences[#sequences+1]={
     features={
       liga=everywhere,
     },
     flags=noflags,
     name="s_s_0",
     nofsteps=1,
     order={ "liga" },
     type="gsub_ligature",
     steps={
       {
         coverage=ligatures,
       },
     },
   }
 end
 if next(kerns) then
   features.gpos.kern=everywhere
   data.properties.haskerns=true
   sequences[#sequences+1]={
     features={
       kern=everywhere,
     },
     flags=noflags,
     name="p_s_0",
     nofsteps=1,
     order={ "kern" },
     type="gpos_pair",
     steps={
       {
         format="kern",
         coverage=kerns,
       },
     },
   }
 end
 if next(extrakerns) then
   features.gpos.extrakerns=everywhere
   data.properties.haskerns=true
   sequences[#sequences+1]={
     features={
       extrakerns=everywhere,
     },
     flags=noflags,
     name="p_s_1",
     nofsteps=1,
     order={ "extrakerns" },
     type="gpos_pair",
     steps={
       {
         format="kern",
         coverage=extrakerns,
       },
     },
   }
 end
 data.resources.features=features
 data.resources.sequences=sequences
end
local function enhance_fix_names(data)
 for k,v in next,data.descriptions do
   local n=v.name
   local r=overloads[n]
   if r then
     local name=r.name
     if trace_indexing then
       report_afm("renaming characters %a to %a",n,name)
     end
     v.name=name
     v.unicode=r.unicode
   end
 end
end
local addthem=function(rawdata,ligatures)
 if ligatures then
   local descriptions=rawdata.descriptions
   local resources=rawdata.resources
   local unicodes=resources.unicodes
   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
local function enhance_add_ligatures(rawdata)
 addthem(rawdata,afm.helpdata.ligatures)
end
local function enhance_add_extra_kerns(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=0x0020
   local emdash=0x2014
   local spacer="space"
   local spaceunits=500
   local monospaced=metadata.monospaced
   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=0x0078
     if x then
       local x=descriptions[x]
       if x then
         parameters.x_height=x.height
       end
     end
   end
   if metadata.sup then
     local dummy={ 0,0,0 }
     parameters[ 1]=metadata.designsize    or 0
     parameters[ 2]=metadata.checksum     or 0
     parameters[ 3],
     parameters[ 4],
     parameters[ 5]=unpack(metadata.space   or dummy)
     parameters[ 6]=metadata.quad    or 0
     parameters[ 7]=metadata.extraspace or 0
     parameters[ 8],
     parameters[ 9],
     parameters[10]=unpack(metadata.num    or dummy)
     parameters[11],
     parameters[12]=unpack(metadata.denom   or dummy)
     parameters[13],
     parameters[14],
     parameters[15]=unpack(metadata.sup    or dummy)
     parameters[16],
     parameters[17]=unpack(metadata.sub    or dummy)
     parameters[18]=metadata.supdrop  or 0
     parameters[19]=metadata.subdrop  or 0
     parameters[20],
     parameters[21]=unpack(metadata.delim   or dummy)
     parameters[22]=metadata.axisheight or 0
   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 addtables(data)
 local resources=data.resources
 local lookuptags=resources.lookuptags
 local unicodes=resources.unicodes
 if not lookuptags then
   lookuptags={}
   resources.lookuptags=lookuptags
 end
 setmetatableindex(lookuptags,function(t,k)
   local v=type(k)=="number" and ("lookup "..k) or k
   t[k]=v
   return v
 end)
 if not unicodes then
   unicodes={}
   resources.unicodes=unicodes
   setmetatableindex(unicodes,function(t,k)
     setmetatableindex(unicodes,nil)
     for u,d in next,data.descriptions do
       local n=d.name
       if n then
         t[n]=u
       end
     end
     return rawget(t,k)
   end)
 end
 constructors.addcoreunicodes(unicodes)
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
       addtables(rawdata)
       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.dynamics={}
         tfmdata.changed={}
         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
registerafmfeature {
 name="mode",
 description="mode",
 initializers={
   base=otf.modeinitializer,
   node=otf.modeinitializer,
 }
}
registerafmfeature {
 name="features",
 description="features",
 default=true,
 initializers={
   node=otf.nodemodeinitializer,
   base=otf.basemodeinitializer,
 },
 processors={
   node=otf.featuresprocessor,
 }
}
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=specification.filename or ""
 local tfmdata=nil
 if fullname=="" then
   local forced=specification.forced or ""
   if forced~="" then
     tfmdata=check_afm(specification,specification.name.."."..forced)
   end
   if not tfmdata then
     local check_tfm=readers.check_tfm
     method=(check_tfm and (method or definers.method or "afm or tfm")) or "afm"
     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.forced="afm"
 local function swap(name)
   local value=specification[swap]
   if value then
     specification[swap]=gsub("%.pfb",".afm",1)
   end
 end
 swap("filename")
 swap("fullname")
 swap("forcedname")
 swap("specification")
 return readers.afm(specification,method)
end
registerafmenhancer("unify names",enhance_unify_names)
registerafmenhancer("add ligatures",enhance_add_ligatures)
registerafmenhancer("add extra kerns",enhance_add_extra_kerns)
registerafmenhancer("normalize features",enhance_normalize_features)
registerafmenhancer("check extra features",otfenhancers.enhance)
registerafmenhancer("fix names",enhance_fix_names)

end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-one”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-afk” b36a76ceb835f41f8c05b471000ddc14] ---

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 --- [luaotfload, fontloader-2017-02-11.lua scope for “font-afk”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-tfm” 3d813578dbf6c447e4b859c2bf0618f7] ---

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,type=next,type
local match,format=string.match,string.format
local concat,sortedhash=table.concat,table.sortedhash
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 setmetatableindex=table.setmetatableindex
local fonts=fonts
local handlers=fonts.handlers
local readers=fonts.readers
local constructors=fonts.constructors
local encodings=fonts.encodings
local tfm=constructors.handlers.tfm
tfm.version=1.000
tfm.maxnestingdepth=5
tfm.maxnestingsize=65536*1024
local otf=fonts.handlers.otf
local otfenhancers=otf.enhancers
local tfmfeatures=constructors.features.tfm
local registertfmfeature=tfmfeatures.register
local tfmenhancers=constructors.enhancers.tfm
local registertfmenhancer=tfmenhancers.register
constructors.resolvevirtualtoo=false
fonts.formats.tfm="type1"
fonts.formats.ofm="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 depth={}
local function read_from_tfm(specification)
 local filename=specification.filename
 local size=specification.size
 depth[filename]=(depth[filename] or 0)+1
 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 features=constructors.checkedfeatures("tfm",features)
   specification.features.normal=features
   local newtfmdata=(depth[filename]==1) and tfm.reencode(tfmdata,specification)
   if newtfmdata then
      tfmdata=newtfmdata
   end
   local resources=tfmdata.resources or {}
   local properties=tfmdata.properties or {}
   local parameters=tfmdata.parameters or {}
   local shared=tfmdata.shared   or {}
   shared.features=features
   shared.resources=resources
   properties.name=tfmdata.name
   properties.fontname=tfmdata.fontname
   properties.psname=tfmdata.psname
   properties.fullname=tfmdata.fullname
   properties.filename=specification.filename
   properties.format=fonts.formats.tfm
   tfmdata.properties=properties
   tfmdata.resources=resources
   tfmdata.parameters=parameters
   tfmdata.shared=shared
   shared.rawdata={ resources=resources }
   shared.features=features
   if newtfmdata then
     if not resources.marks then
       resources.marks={}
     end
     if not resources.sequences then
       resources.sequences={}
     end
     if not resources.features then
       resources.features={
         gsub={},
         gpos={},
       }
     end
     if not tfmdata.changed then
       tfmdata.changed={}
     end
     if not tfmdata.descriptions then
       tfmdata.descriptions=tfmdata.characters
     end
     otf.readers.addunicodetable(tfmdata)
     tfmenhancers.apply(tfmdata,filename)
     constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm)
     otf.readers.unifymissing(tfmdata)
     fonts.mappings.addtounicode(tfmdata,filename)
     tfmdata.tounicode=1
     local tounicode=fonts.mappings.tounicode
     for unicode,v in next,tfmdata.characters do
       local u=v.unicode
       if u then
         v.tounicode=tounicode(u)
       end
     end
     if tfmdata.usedbitmap then
       tfm.addtounicode(tfmdata)
     end
   end
   shared.processes=next(features) and tfm.setfeatures(tfmdata,features) or nil
   parameters.factor=1
   parameters.size=size
   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 newtfmdata then
   elseif 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
         tfmdata.type="virtual"
         local fontlist=vfdata.fonts
         local name=file.nameonly(filename)
         for i=1,#fontlist do
           local n=fontlist[i].name
           local s=fontlist[i].size
           local d=depth[filename]
           s=constructors.scaled(s,vfdata.designsize)
           if d>tfm.maxnestingdepth then
             report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth)
             fontlist[i]={ id=0 }
           elseif (d>1) and (s>tfm.maxnestingsize) then
             report_defining("virtual font %a exceeds size %s",n,s)
             fontlist[i]={ id=0 }
           else
             local t,id=fonts.constructors.readanddefine(n,s)
             fontlist[i]={ id=id }
           end
         end
       end
     end
   end
   properties.haskerns=true
   properties.hasligatures=true
   resources.unicodes={}
   resources.lookuptags={}
   depth[filename]=depth[filename]-1
   return tfmdata
 else
   depth[filename]=depth[filename]-1
 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
readers.ofm=readers.tfm
do
 local outfiles={}
 local tfmcache=table.setmetatableindex(function(t,tfmdata)
   local id=font.define(tfmdata)
   t[tfmdata]=id
   return id
 end)
 local encdone=table.setmetatableindex("table")
 function tfm.reencode(tfmdata,specification)
   local features=specification.features
   if not features then
     return
   end
   local features=features.normal
   if not features then
     return
   end
   local tfmfile=file.basename(tfmdata.name)
   local encfile=features.reencode
   local pfbfile=features.pfbfile
   local bitmap=features.bitmap
   if not encfile then
     return
   end
   local pfbfile=outfiles[tfmfile]
   if pfbfile==nil then
     if bitmap then
       pfbfile=false
     elseif type(pfbfile)~="string" then
       pfbfile=tfmfile
     end
     if type(pfbfile)=="string" then
       pfbfile=file.addsuffix(pfbfile,"pfb")
       report_tfm("using type1 shapes from %a for %a",pfbfile,tfmfile)
     else
       report_tfm("using bitmap shapes for %a",tfmfile)
       pfbfile=false
     end
     outfiles[tfmfile]=pfbfile
   end
   local encoding=false
   local vector=false
   if type(pfbfile)=="string" then
     local pfb=fonts.constructors.handlers.pfb
     if pfb and pfb.loadvector then
       local v,e=pfb.loadvector(pfbfile)
       if v then
         vector=v
       end
       if e then
         encoding=e
       end
     end
   end
   if type(encfile)=="string" and encfile~="auto" then
     encoding=fonts.encodings.load(file.addsuffix(encfile,"enc"))
     if encoding then
       encoding=encoding.vector
     end
   end
   if not encoding then
     report_tfm("bad encoding for %a, quitting",tfmfile)
     return
   end
   local unicoding=fonts.encodings.agl and fonts.encodings.agl.unicodes
   local virtualid=tfmcache[tfmdata]
   local tfmdata=table.copy(tfmdata)
   local characters={}
   local originals=tfmdata.characters
   local indices={}
   local parentfont={ "font",1 }
   local private=fonts.constructors.privateoffset
   local reported=encdone[tfmfile][encfile]
   local backmap=vector and table.swapped(vector)
   local done={}
   for index,name in sortedhash(encoding) do
     local unicode=unicoding[name]
     local original=originals[index]
     if original then
       if unicode then
         original.unicode=unicode
       else
         unicode=private
         private=private+1
         if not reported then
           report_tfm("glyph %a in font %a with encoding %a gets unicode %U",name,tfmfile,encfile,unicode)
         end
       end
       characters[unicode]=original
       indices[index]=unicode
       original.name=name
       if backmap then
         original.index=backmap[name]
       else
         original.commands={ parentfont,{ "char",index } }
         original.oindex=index
       end
       done[name]=true
     elseif not done[name] then
       report_tfm("bad index %a in font %a with name %a",index,tfmfile,name)
     end
   end
   encdone[tfmfile][encfile]=true
   for k,v in next,characters do
     local kerns=v.kerns
     if kerns then
       local t={}
       for k,v in next,kerns do
         local i=indices[k]
         if i then
           t[i]=v
         end
       end
       v.kerns=next(t) and t or nil
     end
     local ligatures=v.ligatures
     if ligatures then
       local t={}
       for k,v in next,ligatures do
         local i=indices[k]
         if i then
           t[i]=v
           v.char=indices[v.char]
         end
       end
       v.ligatures=next(t) and t or nil
     end
   end
   tfmdata.fonts={ { id=virtualid } }
   tfmdata.characters=characters
   tfmdata.fullname=tfmdata.fullname or tfmdata.name
   tfmdata.psname=file.nameonly(pfbfile or tfmdata.name)
   tfmdata.filename=pfbfile
   tfmdata.encodingbytes=2
   tfmdata.format="type1"
   tfmdata.tounicode=1
   tfmdata.embedding="subset"
   tfmdata.usedbitmap=bitmap and virtualid
   return tfmdata
 end
end
do
 local template=[[
/CIDInit /ProcSet findresource begin
 12 dict begin
 begincmap
   /CIDSystemInfo << /Registry (TeX) /Ordering (bitmap-%s) /Supplement 0 >> def
   /CMapName /TeX-bitmap-%s def
   /CMapType 2 def
   1 begincodespacerange
     <00> <FF>
   endcodespacerange
   %s beginbfchar
%s
   endbfchar
 endcmap
CMapName currentdict /CMap defineresource pop end
end
end
]]
 local flushstreamobject=lpdf and lpdf.flushstreamobject
 local setfontattributes=pdf.setfontattributes
 if not flushstreamobject then
   flushstreamobject=function(data)
     return pdf.obj {
       immediate=true,
       type="stream",
       string=data,
     }
   end
 end
 if not setfontattributes then
   setfontattributes=function(id,data)
     print(format("your luatex is too old so no tounicode bitmap font%i",id))
   end
 end
 function tfm.addtounicode(tfmdata)
   local id=tfmdata.usedbitmap
   local map={}
   local char={}
   for k,v in next,tfmdata.characters do
     local index=v.oindex
     local tounicode=v.tounicode
     if index and tounicode then
       map[index]=tounicode
     end
   end
   for k,v in sortedhash(map) do
     char[#char+1]=format("<%02X> <%s>",k,v)
   end
   char=concat(char,"\n")
   local stream=format(template,id,id,#char,char)
   local reference=flushstreamobject(stream,nil,true)
   setfontattributes(id,format("/ToUnicode %i 0 R",reference))
 end
end
do
 local everywhere={ ["*"]={ ["*"]=true } }
 local noflags={ false,false,false,false }
 local function enhance_normalize_features(data)
   local ligatures=setmetatableindex("table")
   local kerns=setmetatableindex("table")
   local characters=data.characters
   for u,c in next,characters do
     local l=c.ligatures
     local k=c.kerns
     if l then
       ligatures[u]=l
       for u,v in next,l do
         l[u]={ ligature=v.char }
       end
       c.ligatures=nil
     end
     if k then
       kerns[u]=k
       for u,v in next,k do
         k[u]=v
       end
       c.kerns=nil
     end
   end
   for u,l in next,ligatures do
     for k,v in next,l do
       local vl=v.ligature
       local dl=ligatures[vl]
       if dl then
         for kk,vv in next,dl do
           v[kk]=vv
         end
       end
     end
   end
   local features={
     gpos={},
     gsub={},
   }
   local sequences={
   }
   if next(ligatures) then
     features.gsub.liga=everywhere
     data.properties.hasligatures=true
     sequences[#sequences+1]={
       features={
         liga=everywhere,
       },
       flags=noflags,
       name="s_s_0",
       nofsteps=1,
       order={ "liga" },
       type="gsub_ligature",
       steps={
         {
           coverage=ligatures,
         },
       },
     }
   end
   if next(kerns) then
     features.gpos.kern=everywhere
     data.properties.haskerns=true
     sequences[#sequences+1]={
       features={
         kern=everywhere,
       },
       flags=noflags,
       name="p_s_0",
       nofsteps=1,
       order={ "kern" },
       type="gpos_pair",
       steps={
         {
           format="kern",
           coverage=kerns,
         },
       },
     }
   end
   data.resources.features=features
   data.resources.sequences=sequences
   data.shared.resources=data.shared.resources or resources
 end
 registertfmenhancer("normalize features",enhance_normalize_features)
 registertfmenhancer("check extra features",otfenhancers.enhance)
end
registertfmfeature {
 name="mode",
 description="mode",
 initializers={
   base=otf.modeinitializer,
   node=otf.modeinitializer,
 }
}
registertfmfeature {
 name="features",
 description="features",
 default=true,
 initializers={
   base=otf.basemodeinitializer,
   node=otf.nodemodeinitializer,
 },
 processors={
   node=otf.featuresprocessor,
 }
}

end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-tfm”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-lua” 1fbfdf7b689b2bdfd0e3bb9bf74ce136] ---

if not modules then modules={} end modules ['font-lua']={
 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 trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end)
local report_lua=logs.reporter("fonts","lua loading")
local fonts=fonts
local readers=fonts.readers
fonts.formats.lua="lua"
local function check_lua(specification,fullname)
 local fullname=resolvers.findfile(fullname) or ""
 if fullname~="" then
   local loader=loadfile(fullname)
   loader=loader and loader()
   return loader and loader(specification)
 end
end
readers.check_lua=check_lua
function readers.lua(specification)
 local original=specification.specification
 if trace_defining then
   report_lua("using lua reader for %a",original)
 end
 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_lua(specification,fullname)
end

end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-lua”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-def” 49fa2b50d8d2a1bb70b08b72f858ecd0] ---

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 lower,gsub=string.lower,string.gsub
local tostring,next=tostring,next
local lpegmatch=lpeg.match
local suffixonly,removesuffix=file.suffix,file.removesuffix
local formatters=string.formatters
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,subindex=resolve(specification.name,specification.sub,specification)
   if resolved then
     specification.resolved=resolved
     specification.sub=sub
     specification.subindex=subindex
     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,subindex=resolvespec(specification.name,specification.sub,specification)
   if resolved then
     specification.resolved=resolved
     specification.sub=sub
     specification.subindex=subindex
     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=formatters["%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 %a font with id %a, name %a, size %a, bytes %a, encoding %a, fullname %a, filename %a",
     properties.format or "unknown",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 --- [luaotfload, fontloader-2017-02-11.lua scope for “font-def”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “fonts-ext” aff3846f4c1f15de0a9f4fd7081e0c68] ---

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.features.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,
 }
}
local function ignore(tfmdata,key,value)
 if value then
   tfmdata.mathparameters=nil
 end
end
otffeatures.register {
 name="ignoremathconstants",
 description="ignore math constants table",
 initializers={
   base=ignore,
   node=ignore,
 }
}

end --- [luaotfload, fontloader-2017-02-11.lua scope for “fonts-ext”] ---


do  --- [luaotfload, fontloader-2017-02-11.lua scope for “font-gbn” 850f31ba73ff8de96371d0aed2b2b4cb] ---

if not modules then modules={} end modules ['font-gbn']={
 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 nuts=nodes.nuts
local traverse_id=nuts.traverse_id
local flush_node=nuts.flush_node
local glyph_code=nodes.nodecodes.glyph
local disc_code=nodes.nodecodes.disc
local tonode=nuts.tonode
local tonut=nuts.tonut
local getfont=nuts.getfont
local getchar=nuts.getchar
local getid=nuts.getid
local getboth=nuts.getboth
local getprev=nuts.getprev
local getnext=nuts.getnext
local getdisc=nuts.getdisc
local setchar=nuts.setchar
local setlink=nuts.setlink
local setprev=nuts.setprev
local nodetail=nuts.tail
local n_ligaturing=node.ligaturing
local n_kerning=node.kerning
local ligaturing=nuts.ligaturing
local kerning=nuts.kerning
local basemodepass=true
local function l_warning() texio.write_nl("warning: node.ligaturing called directly") l_warning=nil end
local function k_warning() texio.write_nl("warning: node.kerning called directly")  k_warning=nil end
function node.ligaturing(...)
 if basemodepass and l_warning then
   l_warning()
 end
 return n_ligaturing(...)
end
function node.kerning(...)
 if basemodepass and k_warning then
   k_warning()
 end
 return n_kerning(...)
end
function nodes.handlers.setbasemodepass(v)
 basemodepass=v
end
function nodes.handlers.nodepass(head)
 local fontdata=fonts.hashes.identifiers
 if fontdata then
   local nuthead=tonut(head)
   local usedfonts={}
   local basefonts={}
   local prevfont=nil
   local basefont=nil
   local variants=nil
   local redundant=nil
   for n in traverse_id(glyph_code,nuthead) do
     local font=getfont(n)
     if font~=prevfont then
       if basefont then
         basefont[2]=getprev(n)
       end
       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
             elseif basemodepass then
               basefont={ n,nil }
               basefonts[#basefonts+1]=basefont
             end
           end
           local resources=tfmdata.resources
           variants=resources and resources.variants
           variants=variants and next(variants) and variants or false
         end
       else
         local tfmdata=fontdata[prevfont]
         if tfmdata then
           local resources=tfmdata.resources
           variants=resources and resources.variants
           variants=variants and next(variants) and variants or false
         end
       end
     end
     if variants then
       local char=getchar(n)
       if char>=0xFE00 and (char<=0xFE0F or (char>=0xE0100 and char<=0xE01EF)) then
         local hash=variants[char]
         if hash then
           local p=getprev(n)
           if p and getid(p)==glyph_code then
             local variant=hash[getchar(p)]
             if variant then
               setchar(p,variant)
             end
           end
         end
         if not redundant then
           redundant={ n }
         else
           redundant[#redundant+1]=n
         end
       end
     end
   end
   local nofbasefonts=#basefonts
   if redundant then
     for i=1,#redundant do
       local r=redundant[i]
       local p,n=getboth(r)
       if r==nuthead then
         nuthead=n
         setprev(n)
       else
         setlink(p,n)
       end
       if nofbasefonts>0 then
         for i=1,nofbasefonts do
           local bi=basefonts[i]
           if r==bi[1] then
             bi[1]=n
           end
           if r==bi[2] then
             bi[2]=n
           end
         end
       end
       flush_node(r)
     end
   end
   for d in traverse_id(disc_code,nuthead) do
     local _,_,r=getdisc(d)
     if r then
       for n in traverse_id(glyph_code,r) do
         local font=getfont(n)
         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
                 end
               end
             end
           end
         end
       end
     end
   end
   if next(usedfonts) then
     for font,processors in next,usedfonts do
       for i=1,#processors do
         head=processors[i](head,font,0) or head
       end
     end
   end
   if basemodepass and nofbasefonts>0 then
     for i=1,nofbasefonts do
       local range=basefonts[i]
       local start=range[1]
       local stop=range[2]
       if start then
         local front=nuthead==start
         if not stop then
           stop=nodetail(start)
         end
         if stop then
           start,stop=ligaturing(start,stop)
           start,stop=kerning(start,stop)
         elseif start then
           start,stop=ligaturing(start,stop)
           start,stop=kerning(start,stop)
         end
         if front and nuthead~=start then
           head=tonode(start)
         end
       end
     end
   end
   return head,true
 else
   return head,false
 end
end
function nodes.handlers.basepass(head)
 if not basemodepass then
   head=n_ligaturing(head)
   head=n_kerning(head)
 end
 return head,true
end
local nodepass=nodes.handlers.nodepass
local basepass=nodes.handlers.basepass
local injectpass=nodes.injections.handler
local protectpass=nodes.handlers.protectglyphs
function nodes.simple_font_handler(head)
 if head then
   head=nodepass(head)
   head=injectpass(head)
   if not basemodepass then
     head=basepass(head)
   end
   protectpass(head)
   return head,true
 else
   return head,false
 end
end

end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-gbn”] ---


--- vim:ft=lua:sw=2:ts=8:et:tw=79