From c0641b1563ce1b0219724e19c772bbc180e86c2a Mon Sep 17 00:00:00 2001
From: Khaled Hosny <khaledhosny@eglug.org>
Date: Mon, 14 Jun 2010 14:02:28 +0300
Subject: Sync with ConTeXt beta (beta 2010.06.14)

Fixes several bugs, including math bugs.
---
 luaotfload.dtx    |  26 ++--
 otfl-data-con.lua |  80 ++++++-----
 otfl-font-def.lua |  29 ++--
 otfl-font-dum.lua |  19 +++
 otfl-font-ini.lua |   5 +-
 otfl-font-ota.lua |  38 ------
 otfl-font-otd.lua |   7 +-
 otfl-font-otf.lua | 391 ++++++++++++++++++++++++++++++------------------------
 otfl-font-otn.lua | 116 ++++++++++------
 otfl-font-tfm.lua |   5 +
 otfl-luat-dum.lua |  97 +++++++++++---
 otfl-node-dum.lua | 108 ++++++++++++++-
 otfl-node-fnt.lua | 205 ----------------------------
 otfl-node-ini.lua | 244 ----------------------------------
 otfl-node-inj.lua |  92 ++++---------
 otfl-node-res.lua | 302 -----------------------------------------
 16 files changed, 608 insertions(+), 1156 deletions(-)
 delete mode 100644 otfl-node-fnt.lua
 delete mode 100644 otfl-node-ini.lua
 delete mode 100644 otfl-node-res.lua

diff --git a/luaotfload.dtx b/luaotfload.dtx
index 0918a4b..f2239b7 100644
--- a/luaotfload.dtx
+++ b/luaotfload.dtx
@@ -350,9 +350,7 @@ and the derived files
 % \begin{itemize*}
 % \item \texttt{luat-dum.lua}
 % \item \texttt{data-con.lua}
-% \item \texttt{node-ini.lua}
 % \item \texttt{node-inj.lua}
-% \item \texttt{node-fnt.lua}
 % \item \texttt{node-dum.lua}
 % \item \texttt{font-ini.lua}
 % \item \texttt{font-tfm.lua}
@@ -490,11 +488,12 @@ luaotfload.loadmodule('data-con.lua') -- maybe some day we don't need this one
 
 %    \end{macrocode}
 %
-%    This one is for node support.
+%    Node support modules.
 %
 %    \begin{macrocode}
 
-luaotfload.loadmodule('node-ini.lua')
+luaotfload.loadmodule('node-dum.lua')
+luaotfload.loadmodule('node-inj.lua')
 
 %    \end{macrocode}
 %
@@ -517,7 +516,7 @@ end
 
 %    \end{macrocode}
 %
-%    A hack to remove a warning from \texttt{node-fnt.lua} as it is \ConTeXt\
+%    A hack to remove a warning from \texttt{node-dum.lua} as it is \ConTeXt\
 %    specific.
 %
 %    \begin{macrocode}
@@ -526,21 +525,15 @@ tex.attribute[0] = 0
 
 %    \end{macrocode}
 %
-%    Some more modules. We don't load neither \texttt{font-enc.lua} nor
-%    \texttt{font-afm.lua} as it will never be used here.
+%    Font handling modules.
 %
 %    \begin{macrocode}
 
-luaotfload.loadmodule('node-res.lua')
-luaotfload.loadmodule('node-inj.lua')
-luaotfload.loadmodule('node-fnt.lua')
-luaotfload.loadmodule('node-dum.lua')
-
 luaotfload.loadmodule('font-ini.lua')
 luaotfload.loadmodule('font-tfm.lua')
 luaotfload.loadmodule('font-cid.lua')
-luaotfload.loadmodule('font-map.lua')
 luaotfload.loadmodule('font-ott.lua')
+luaotfload.loadmodule('font-map.lua')
 luaotfload.loadmodule('font-otf.lua')
 luaotfload.loadmodule('font-otd.lua')
 luaotfload.loadmodule('font-oti.lua')
@@ -551,6 +544,13 @@ luaotfload.loadmodule('font-otc.lua')
 luaotfload.loadmodule('font-def.lua')
 luaotfload.loadmodule('font-xtx.lua')
 luaotfload.loadmodule('font-dum.lua')
+
+%    \end{macrocode}
+%
+%    \textsf{luaotfload} specific modules.
+%
+%    \begin{macrocode}
+
 luaotfload.loadmodule('font-nms.lua')
 luaotfload.loadmodule('font-clr.lua')
 
diff --git a/otfl-data-con.lua b/otfl-data-con.lua
index fabe0ba..e7bb8af 100644
--- a/otfl-data-con.lua
+++ b/otfl-data-con.lua
@@ -1,5 +1,5 @@
 if not modules then modules = { } end modules ['data-con'] = {
-    version   = 1.001,
+    version   = 1.100,
     comment   = "companion to luat-lib.mkiv",
     author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
     copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -37,38 +37,48 @@ end
 
 local allocated = { }
 
--- tracing
+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
+}
 
 function containers.define(category, subcategory, version, enabled)
-    return function()
-        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 1.000,
-                    trace = false,
-                    path = caches and caches.setpath and caches.setpath(category,subcategory),
-                }
-                c[subcategory] = s
-            end
-            return s
-        else
-            return nil
+    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, -- after all, this is TeX
+                trace       = false,
+             -- writable    = caches.getwritablepath  and caches.getwritablepath (category,subcategory) or { "." },
+             -- readables   = caches.getreadablepaths and caches.getreadablepaths(category,subcategory) or { "." },
+            }
+            setmetatable(s,mt)
+            c[subcategory] = s
+        end
+        return s
     end
 end
 
 function containers.is_usable(container, name)
-    return container.enabled and caches and caches.iswritable(container.path, name)
+    return container.enabled and caches and caches.iswritable(container.writable, name)
 end
 
 function containers.is_valid(container, name)
@@ -81,18 +91,20 @@ function containers.is_valid(container, name)
 end
 
 function containers.read(container,name)
-    if container.enabled and caches and not container.storage[name] and containers.usecache then
-        container.storage[name] = caches.loaddata(container.path,name)
-        if containers.is_valid(container,name) then
+    local storage = container.storage
+    local stored = storage[name]
+    if not stored and container.enabled and caches and containers.usecache then
+        stored = caches.loaddata(container.readables,name)
+        if stored and stored.cache_version == container.version then
             report(container,"loaded",name)
         else
-            container.storage[name] = nil
+            stored = nil
         end
-    end
-    if container.storage[name] then
+        storage[name] = stored
+    elseif stored then
         report(container,"reusing",name)
     end
-    return container.storage[name]
+    return stored
 end
 
 function containers.write(container, name, data)
@@ -101,7 +113,7 @@ function containers.write(container, name, data)
         if container.enabled and caches then
             local unique, shared = data.unique, data.shared
             data.unique, data.shared = nil, nil
-            caches.savedata(container.path, name, data)
+            caches.savedata(container.writable, name, data)
             report(container,"saved",name)
             data.unique, data.shared = unique, shared
         end
diff --git a/otfl-font-def.lua b/otfl-font-def.lua
index 0add703..8e64872 100644
--- a/otfl-font-def.lua
+++ b/otfl-font-def.lua
@@ -233,18 +233,29 @@ end
 
 define.resolvers = resolvers
 
+-- todo: reporter
+
 function define.resolvers.file(specification)
-    specification.forced = file.extname(specification.name)
-    specification.name = file.removesuffix(specification.name)
+    local suffix = file.suffix(specification.name)
+    if fonts.formats[suffix] then
+        specification.forced = suffix
+        specification.name = file.removesuffix(specification.name)
+    end
 end
 
 function define.resolvers.name(specification)
     local resolve = fonts.names.resolve
     if resolve then
-        specification.resolved, specification.sub = fonts.names.resolve(specification)
-        if specification.resolved then
-            specification.forced = file.extname(specification.resolved)
-            specification.name = file.removesuffix(specification.resolved)
+        local resolved, sub = fonts.names.resolve(specification)
+        specification.resolved, specification.sub = resolved, sub
+        if resolved then
+            local suffix = file.suffix(resolved)
+            if fonts.formats[suffix] then
+                specification.forced = suffix
+                specification.name = file.removesuffix(resolved)
+            else
+                specification.name = resolved
+            end
         end
     else
         define.resolvers.file(specification)
@@ -456,7 +467,7 @@ end
 local function check_otf(forced,specification,suffix,what)
     local name = specification.name
     if forced then
-        name = file.addsuffix(name,suffix)
+        name = file.addsuffix(name,suffix,true)
     end
     local fullname, tfmtable = resolvers.findbinfile(name,suffix) or "", nil -- one shot
     if fullname == "" then
@@ -578,7 +589,7 @@ function define.read(specification,size,id) -- id can be optional, name can alre
     specification = define.resolve(specification)
     local hash = tfm.hash_instance(specification)
     if cache_them then
-        local fontdata = containers.read(fonts.cache(),hash) -- for tracing purposes
+        local fontdata = containers.read(fonts.cache,hash) -- for tracing purposes
     end
     local fontdata = define.registered(hash) -- id
     if not fontdata then
@@ -591,7 +602,7 @@ function define.read(specification,size,id) -- id can be optional, name can alre
             end
         end
         if cache_them then
-            fontdata = containers.write(fonts.cache(),hash,fontdata) -- for tracing purposes
+            fontdata = containers.write(fonts.cache,hash,fontdata) -- for tracing purposes
         end
         if fontdata then
             fontdata.hash = hash
diff --git a/otfl-font-dum.lua b/otfl-font-dum.lua
index 2de1ae1..c9ffb63 100644
--- a/otfl-font-dum.lua
+++ b/otfl-font-dum.lua
@@ -379,3 +379,22 @@ function fonts.otf.char(n)
         tex.sprint("\\char" .. n)
     end
 end
+
+-- another one:
+
+fonts.strippables = table.tohash {
+    0x000AD, 0x017B4, 0x017B5, 0x0200B, 0x0200C, 0x0200D, 0x0200E, 0x0200F, 0x0202A, 0x0202B,
+    0x0202C, 0x0202D, 0x0202E, 0x02060, 0x02061, 0x02062, 0x02063, 0x0206A, 0x0206B, 0x0206C,
+    0x0206D, 0x0206E, 0x0206F, 0x0FEFF, 0x1D173, 0x1D174, 0x1D175, 0x1D176, 0x1D177, 0x1D178,
+    0x1D179, 0x1D17A, 0xE0001, 0xE0020, 0xE0021, 0xE0022, 0xE0023, 0xE0024, 0xE0025, 0xE0026,
+    0xE0027, 0xE0028, 0xE0029, 0xE002A, 0xE002B, 0xE002C, 0xE002D, 0xE002E, 0xE002F, 0xE0030,
+    0xE0031, 0xE0032, 0xE0033, 0xE0034, 0xE0035, 0xE0036, 0xE0037, 0xE0038, 0xE0039, 0xE003A,
+    0xE003B, 0xE003C, 0xE003D, 0xE003E, 0xE003F, 0xE0040, 0xE0041, 0xE0042, 0xE0043, 0xE0044,
+    0xE0045, 0xE0046, 0xE0047, 0xE0048, 0xE0049, 0xE004A, 0xE004B, 0xE004C, 0xE004D, 0xE004E,
+    0xE004F, 0xE0050, 0xE0051, 0xE0052, 0xE0053, 0xE0054, 0xE0055, 0xE0056, 0xE0057, 0xE0058,
+    0xE0059, 0xE005A, 0xE005B, 0xE005C, 0xE005D, 0xE005E, 0xE005F, 0xE0060, 0xE0061, 0xE0062,
+    0xE0063, 0xE0064, 0xE0065, 0xE0066, 0xE0067, 0xE0068, 0xE0069, 0xE006A, 0xE006B, 0xE006C,
+    0xE006D, 0xE006E, 0xE006F, 0xE0070, 0xE0071, 0xE0072, 0xE0073, 0xE0074, 0xE0075, 0xE0076,
+    0xE0077, 0xE0078, 0xE0079, 0xE007A, 0xE007B, 0xE007C, 0xE007D, 0xE007E, 0xE007F,
+}
+
diff --git a/otfl-font-ini.lua b/otfl-font-ini.lua
index e451497..c695ec4 100644
--- a/otfl-font-ini.lua
+++ b/otfl-font-ini.lua
@@ -13,6 +13,7 @@ if not modules then modules = { } end modules ['font-ini'] = {
 local utf = unicode.utf8
 local format, serialize = string.format, table.serialize
 local write_nl = texio.write_nl
+local lower = string.lower
 
 if not fontloader then fontloader = fontforge end
 
@@ -84,12 +85,12 @@ end
 fonts.formats = { }
 
 function fonts.fontformat(filename,default)
-    local extname = file.extname(filename)
+    local extname = lower(file.extname(filename))
     local format = fonts.formats[extname]
     if format then
         return format
     else
-        logs.report("fonts define","unable to detemine font format for '%s'",filename)
+        logs.report("fonts define","unable to determine font format for '%s'",filename)
         return default
     end
 end
diff --git a/otfl-font-ota.lua b/otfl-font-ota.lua
index 558e2fc..0b61e17 100644
--- a/otfl-font-ota.lua
+++ b/otfl-font-ota.lua
@@ -35,14 +35,8 @@ local penalty = node.id('penalty')
 local set_attribute      = node.set_attribute
 local has_attribute      = node.has_attribute
 local traverse_id        = node.traverse_id
-local delete_node        = nodes.delete
-local replace_node       = nodes.replace
-local insert_node_after  = node.insert_after
-local insert_node_before = node.insert_before
 local traverse_node_list = node.traverse
 
-local new_glue_node      = nodes.glue
-
 local fontdata = fonts.ids
 local state    = attributes.private('state')
 
@@ -56,7 +50,6 @@ local a_to_language = otf.a_to_language
 -- font related value, but then we also need dynamic features which is
 -- somewhat slower; and .. we need a chain of them
 
-
 function fonts.initializers.node.otf.analyze(tfmdata,value,attr)
     if attr and attr > 0 then
         script, language = a_to_script[attr], a_to_language[attr]
@@ -195,8 +188,6 @@ function fonts.analyzers.methods.nocolor(head,font,attr)
     return head, true
 end
 
-otf.remove_joiners = false -- true -- for idris who want it as option
-
 local function finish(first,last)
     if last then
         if first == last then
@@ -242,22 +233,10 @@ function fonts.analyzers.methods.arab(head,font,attr) -- maybe make a special ve
     local tfmdata = fontdata[font]
     local marks = tfmdata.marks
     local first, last, current, done = nil, nil, head, false
-    local joiners, nonjoiners
-    local removejoiners = tfmdata.remove_joiners -- or otf.remove_joiners
-    if removejoiners then
-        joiners, nonjoiners = { }, { }
-    end
     while current do
         if current.id == glyph and current.subtype<256 and current.font == font and not has_attribute(current,state) then
             done = true
             local char = current.char
-            if removejoiners then
-                if char == zwj then
-                    joiners[#joiners+1] = current
-                elseif char == zwnj then
-                    nonjoiners[#nonjoiners+1] = current
-                end
-            end
             if marks[char] then
                 set_attribute(current,state,5) -- mark
                 if trace_analyzing then fcs(current,"font:mark") end
@@ -303,22 +282,5 @@ function fonts.analyzers.methods.arab(head,font,attr) -- maybe make a special ve
         current = current.next
     end
     first, last = finish(first,last)
-    if removejoiners then
-        -- is never head
-        for i=1,#joiners do
-            delete_node(head,joiners[i])
-        end
-        for i=1,#nonjoiners do
-            replace_node(head,nonjoiners[i],new_glue_node(0)) -- or maybe a kern
-        end
-    end
     return head, done
 end
-
-table.insert(fonts.manipulators,"joiners")
-
-function fonts.initializers.node.otf.joiners(tfmdata,value)
-    if value == "strip" then
-        tfmdata.remove_joiners = true
-    end
-end
diff --git a/otfl-font-otd.lua b/otfl-font-otd.lua
index 41e8853..14a9727 100644
--- a/otfl-font-otd.lua
+++ b/otfl-font-otd.lua
@@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['font-otd'] = {
     license   = "see context related readme files"
 }
 
-local trace_dynamics  = false  trackers.register("otf.dynamics",     function(v) trace_dynamics     = v end)
+local trace_dynamics = false  trackers.register("otf.dynamics", function(v) trace_dynamics     = v end)
 
 fonts     = fonts     or { }
 fonts.otf = fonts.otf or { }
@@ -60,9 +60,10 @@ function otf.set_dynamics(font,dynamics,attribute)
             tfmdata.script   = script
             tfmdata.shared.features = { }
             -- end of save
-            dsla = otf.set_features(tfmdata,fonts.define.check(features,otf.features.default))
+            local set = fonts.define.check(features,otf.features.default)
+            dsla = otf.set_features(tfmdata,set)
             if trace_dynamics then
-                logs.report("otf define","setting dynamics %s: attribute %s, script %s, language %s",context_numbers[attribute],attribute,script,language)
+                logs.report("otf define","setting dynamics %s: attribute %s, script %s, language %s, set: %s",context_numbers[attribute],attribute,script,language,table.sequenced(set))
             end
             -- we need to restore some values
             tfmdata.script          = saved.script
diff --git a/otfl-font-otf.lua b/otfl-font-otf.lua
index d68137c..b113cf6 100644
--- a/otfl-font-otf.lua
+++ b/otfl-font-otf.lua
@@ -8,9 +8,11 @@ if not modules then modules = { } end modules ['font-otf'] = {
 
 local utf = unicode.utf8
 
-local concat, getn, utfbyte = table.concat, table.getn, utf.byte
+local concat, utfbyte = table.concat, utf.byte
 local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
 local type, next, tonumber, tostring = type, next, tonumber, tostring
+local abs = math.abs
+local getn = table.getn
 local lpegmatch = lpeg.match
 
 local trace_private    = false  trackers.register("otf.private",      function(v) trace_private      = v end)
@@ -80,7 +82,7 @@ otf.features.default = otf.features.default or { }
 otf.enhancers        = otf.enhancers        or { }
 otf.glists           = { "gsub", "gpos" }
 
-otf.version          = 2.650 -- beware: also sync font-mis.lua
+otf.version          = 2.653 -- beware: also sync font-mis.lua
 otf.pack             = true  -- beware: also sync font-mis.lua
 otf.syncspace        = true
 otf.notdef           = false
@@ -220,6 +222,7 @@ local enhancers = {
 
 function otf.load(filename,format,sub,featurefile)
     local name = file.basename(file.removesuffix(filename))
+    local size = lfs.attributes(filename,"size") or 0
     if featurefile then
         name = name .. "@" .. file.removesuffix(file.basename(featurefile))
     end
@@ -229,8 +232,7 @@ function otf.load(filename,format,sub,featurefile)
         hash = hash .. "-" .. sub
     end
     hash = containers.cleanname(hash)
-    local data = containers.read(otf.cache(), hash)
-    local size = lfs.attributes(filename,"size") or 0
+    local data = containers.read(otf.cache,hash)
     if not data or data.verbose ~= fonts.verbose or data.size ~= size then
         logs.report("load otf","loading: %s (hash: %s)",filename,hash)
         local ff, messages
@@ -267,9 +269,9 @@ function otf.load(filename,format,sub,featurefile)
                 data.size = size
                 data.verbose = fonts.verbose
                 logs.report("load otf","saving in cache: %s",filename)
-                data = containers.write(otf.cache(), hash, data)
+                data = containers.write(otf.cache, hash, data)
                 collectgarbage("collect")
-                data = containers.read(otf.cache(), hash) -- this frees the old table and load the sparse one
+                data = containers.read(otf.cache, hash) -- this frees the old table and load the sparse one
                 collectgarbage("collect")
             else
                 logs.report("load otf","loading failed (table conversion error)")
@@ -788,14 +790,12 @@ otf.enhancers["check math"] = function(data,filename)
                 if hv then
                     math.horiz_variants = hv.variants
                     local p = hv.parts
-                    if p then
-                        if #p>0 then
-                            for i=1,#p do
-                                local pi = p[i]
-                                pi.glyph = unicodes[pi.component] or 0
-                            end
-                            math.horiz_parts = p
+                    if p and #p > 0 then
+                        for i=1,#p do
+                            local pi = p[i]
+                            pi.glyph = unicodes[pi.component] or 0
                         end
+                        math.horiz_parts = p
                     end
                     local ic = hv.italic_correction
                     if ic and ic ~= 0 then
@@ -807,14 +807,12 @@ otf.enhancers["check math"] = function(data,filename)
                     local uc = unicodes[index]
                     math.vert_variants = vv.variants
                     local p = vv.parts
-                    if p then
-                        if #p>0 then
-                            for i=1,#p do
-                                local pi = p[i]
-                                pi.glyph = unicodes[pi.component] or 0
-                            end
-                            math.vert_parts = p
+                    if p and #p > 0 then
+                        for i=1,#p do
+                            local pi = p[i]
+                            pi.glyph = unicodes[pi.component] or 0
                         end
+                        math.vert_parts = p
                     end
                     local ic = vv.italic_correction
                     if ic and ic ~= 0 then
@@ -863,10 +861,15 @@ end
 
 -- kern: ttf has a table with kerns
 
+-- Weird, as maxfirst and maxseconds can have holes, first seems to be indexed, but
+-- seconds can start at 2 .. this need to be fixed as getn as well as # are sort of
+-- unpredictable alternatively we could force an [1] if not set (maybe I will do that
+-- anyway).
+
 --~ otf.enhancers["reorganize kerns"] = function(data,filename)
 --~     local glyphs, mapmap, unicodes = data.glyphs, data.luatex.indices, data.luatex.unicodes
 --~     local mkdone = false
---~     for index, glyph in next, data.glyphs do
+--~     for index, glyph in next, glyphs do
 --~         if glyph.kerns then
 --~             local mykerns = { }
 --~             for k,v in next, glyph.kerns do
@@ -915,6 +918,9 @@ end
 --~     end
 --~     local dgpos = data.gpos
 --~     if dgpos then
+--~         local separator = lpeg.P(" ")
+--~         local other = ((1 - separator)^0) / unicodes
+--~         local splitter = lpeg.Ct(other * (separator * other)^0)
 --~         for gp=1,#dgpos do
 --~             local gpos = dgpos[gp]
 --~             local subtables = gpos.subtables
@@ -923,56 +929,70 @@ end
 --~                     local subtable = subtables[s]
 --~                     local kernclass = subtable.kernclass -- name is inconsistent with anchor_classes
 --~                     if kernclass then -- the next one is quite slow
+--~                         local split = { } -- saves time
 --~                         for k=1,#kernclass do
 --~                             local kcl = kernclass[k]
 --~                             local firsts, seconds, offsets, lookups = kcl.firsts, kcl.seconds, kcl.offsets, kcl.lookup -- singular
 --~                             if type(lookups) ~= "table" then
 --~                                 lookups = { lookups }
 --~                             end
+--~                             local maxfirsts, maxseconds = getn(firsts), getn(seconds)
+--~                             for _, s in next, firsts do
+--~                                 split[s] = split[s] or lpegmatch(splitter,s)
+--~                             end
+--~                             for _, s in next, seconds do
+--~                                 split[s] = split[s] or lpegmatch(splitter,s)
+--~                             end
 --~                             for l=1,#lookups do
 --~                                 local lookup = lookups[l]
---~                                 -- weird, as maxfirst and maxseconds can have holes
---~                                 local maxfirsts, maxseconds = getn(firsts), getn(seconds)
---~                                 if trace_loading then
---~                                     logs.report("load otf", "adding kernclass %s with %s times %s pairs",lookup, maxfirsts, maxseconds)
---~                                 end
---~                                 for fk, fv in next, firsts do
---~                                     for first in gmatch(fv,"[^ ]+") do
---~                                         local first_unicode = unicodes[first]
---~                                         if type(first_unicode) == "number" then
---~                                             first_unicode = { first_unicode }
+--~                                 local function do_it(fk,first_unicode)
+--~                                     local glyph = glyphs[mapmap[first_unicode]]
+--~                                     if glyph then
+--~                                         local mykerns = glyph.mykerns
+--~                                         if not mykerns then
+--~                                             mykerns = { } -- unicode indexed !
+--~                                             glyph.mykerns = mykerns
 --~                                         end
---~                                         for f=1,#first_unicode do
---~                                             local glyph = glyphs[mapmap[first_unicode[f]]]
---~                                             if glyph then
---~                                                 local mykerns = glyph.mykerns
---~                                                 if not mykerns then
---~                                                     mykerns = { } -- unicode indexed !
---~                                                     glyph.mykerns = mykerns
---~                                                 end
---~                                                 local lookupkerns = mykerns[lookup]
---~                                                 if not lookupkerns then
---~                                                     lookupkerns = { }
---~                                                     mykerns[lookup] = lookupkerns
---~                                                 end
---~                                                 for sk, sv in next, seconds do
---~                                                     local offset = offsets[(fk-1) * maxseconds + sk]
---~                                                     --~ local offset = offsets[sk] -- (fk-1) * maxseconds + sk]
---~                                                     for second in gmatch(sv,"[^ ]+") do
---~                                                         local second_unicode = unicodes[second]
---~                                                         if type(second_unicode) == "number" then
+--~                                         local lookupkerns = mykerns[lookup]
+--~                                         if not lookupkerns then
+--~                                             lookupkerns = { }
+--~                                             mykerns[lookup] = lookupkerns
+--~                                         end
+--~                                         local baseoffset = (fk-1) * maxseconds
+--~                                         for sk=2,maxseconds do -- we can avoid this loop with a table
+--~                                             local sv = seconds[sk]
+--~                                             local splt = split[sv]
+--~                                             if splt then
+--~                                                 local offset = offsets[baseoffset + sk]
+--~                                                 --~ local offset = offsets[sk] -- (fk-1) * maxseconds + sk]
+--~                                                 if offset then
+--~                                                     for i=1,#splt do
+--~                                                         local second_unicode = splt[i]
+--~                                                         if tonumber(second_unicode) then
 --~                                                             lookupkerns[second_unicode] = offset
---~                                                         else
---~                                                             for s=1,#second_unicode do
---~                                                                 lookupkerns[second_unicode[s]] = offset
---~                                                             end
---~                                                         end
+--~                                                         else for s=1,#second_unicode do
+--~                                                             lookupkerns[second_unicode[s]] = offset
+--~                                                         end end
 --~                                                     end
 --~                                                 end
---~                                             elseif trace_loading then
---~                                                 logs.report("load otf", "no glyph data for U+%04X", first_unicode[f])
 --~                                             end
 --~                                         end
+--~                                     elseif trace_loading then
+--~                                         logs.report("load otf", "no glyph data for U+%04X", first_unicode)
+--~                                     end
+--~                                 end
+--~                                 for fk=1,#firsts do
+--~                                     local fv = firsts[fk]
+--~                                     local splt = split[fv]
+--~                                     if splt then
+--~                                         for i=1,#splt do
+--~                                             local first_unicode = splt[i]
+--~                                             if tonumber(first_unicode) then
+--~                                                 do_it(fk,first_unicode)
+--~                                             else for f=1,#first_unicode do
+--~                                                 do_it(fk,first_unicode[f])
+--~                                             end end
+--~                                         end
 --~                                     end
 --~                                 end
 --~                             end
@@ -989,7 +1009,27 @@ end
 otf.enhancers["reorganize kerns"] = function(data,filename)
     local glyphs, mapmap, unicodes = data.glyphs, data.luatex.indices, data.luatex.unicodes
     local mkdone = false
-    for index, glyph in next, data.glyphs do
+    local function do_it(lookup,first_unicode,kerns)
+        local glyph = glyphs[mapmap[first_unicode]]
+        if glyph then
+            local mykerns = glyph.mykerns
+            if not mykerns then
+                mykerns = { } -- unicode indexed !
+                glyph.mykerns = mykerns
+            end
+            local lookupkerns = mykerns[lookup]
+            if not lookupkerns then
+                lookupkerns = { }
+                mykerns[lookup] = lookupkerns
+            end
+            for second_unicode, kern in next, kerns do
+                lookupkerns[second_unicode] = kern
+            end
+        elseif trace_loading then
+            logs.report("load otf", "no glyph data for U+%04X", first_unicode)
+        end
+    end
+    for index, glyph in next, glyphs do
         if glyph.kerns then
             local mykerns = { }
             for k,v in next, glyph.kerns do
@@ -1049,75 +1089,53 @@ otf.enhancers["reorganize kerns"] = function(data,filename)
                     local subtable = subtables[s]
                     local kernclass = subtable.kernclass -- name is inconsistent with anchor_classes
                     if kernclass then -- the next one is quite slow
+                        local split = { } -- saves time
                         for k=1,#kernclass do
                             local kcl = kernclass[k]
                             local firsts, seconds, offsets, lookups = kcl.firsts, kcl.seconds, kcl.offsets, kcl.lookup -- singular
                             if type(lookups) ~= "table" then
                                 lookups = { lookups }
                             end
-                            local split = { }
+                            local maxfirsts, maxseconds = getn(firsts), getn(seconds)
+                            -- here we could convert split into a list of unicodes which is a bit
+                            -- faster but as this is only done when caching it does not save us much
+                            for _, s in next, firsts do
+                                split[s] = split[s] or lpegmatch(splitter,s)
+                            end
+                            for _, s in next, seconds do
+                                split[s] = split[s] or lpegmatch(splitter,s)
+                            end
                             for l=1,#lookups do
                                 local lookup = lookups[l]
-                                -- weird, as maxfirst and maxseconds can have holes, first seems to be indexed, seconds starts at 2
-                                local maxfirsts, maxseconds = getn(firsts), getn(seconds)
-                                for _, s in next, firsts do
-                                    split[s] = split[s] or lpegmatch(splitter,s)
-                                end
-                                for _, s in next, seconds do
-                                    split[s] = split[s] or lpegmatch(splitter,s)
-                                end
-                                if trace_loading then
-                                    logs.report("load otf", "adding kernclass %s with %s times %s pairs",lookup, maxfirsts, maxseconds)
-                                end
-                                local function do_it(fk,first_unicode)
-                                    local glyph = glyphs[mapmap[first_unicode]]
-                                    if glyph then
-                                        local mykerns = glyph.mykerns
-                                        if not mykerns then
-                                            mykerns = { } -- unicode indexed !
-                                            glyph.mykerns = mykerns
-                                        end
-                                        local lookupkerns = mykerns[lookup]
-                                        if not lookupkerns then
-                                            lookupkerns = { }
-                                            mykerns[lookup] = lookupkerns
-                                        end
-                                        local baseoffset = (fk-1) * maxseconds
+                                for fk=1,#firsts do
+                                    local fv = firsts[fk]
+                                    local splt = split[fv]
+                                    if splt then
+                                        local kerns, baseoffset = { }, (fk-1) * maxseconds
                                         for sk=2,maxseconds do
                                             local sv = seconds[sk]
-                                            local offset = offsets[baseoffset + sk]
-                                            --~ local offset = offsets[sk] -- (fk-1) * maxseconds + sk]
                                             local splt = split[sv]
                                             if splt then
-                                                for i=1,#splt do
-                                                    local second_unicode = splt[i]
-                                                    if tonumber(second_unicode) then
-                                                        lookupkerns[second_unicode] = offset
-                                                    else
-                                                        for s=1,#second_unicode do
-                                                            lookupkerns[second_unicode[s]] = offset
-                                                        end
+                                                local offset = offsets[baseoffset + sk]
+                                                if offset then
+                                                    for i=1,#splt do
+                                                        local second_unicode = splt[i]
+                                                        if tonumber(second_unicode) then
+                                                            kerns[second_unicode] = offset
+                                                        else for s=1,#second_unicode do
+                                                            kerns[second_unicode[s]] = offset
+                                                        end end
                                                     end
                                                 end
                                             end
                                         end
-                                    elseif trace_loading then
-                                        logs.report("load otf", "no glyph data for U+%04X", first_unicode)
-                                    end
-                                end
-                                for fk=1,#firsts do
-                                    local fv = firsts[fk]
-                                    local splt = split[fv]
-                                    if splt then
                                         for i=1,#splt do
                                             local first_unicode = splt[i]
                                             if tonumber(first_unicode) then
-                                                do_it(fk,first_unicode)
-                                            else
-                                                for f=1,#first_unicode do
-                                                    do_it(fk,first_unicode[f])
-                                                end
-                                            end
+                                                do_it(lookup,first_unicode,kerns)
+                                            else for f=1,#first_unicode do
+                                                do_it(lookup,first_unicode[f],kerns)
+                                            end end
                                         end
                                     end
                                 end
@@ -1132,6 +1150,14 @@ otf.enhancers["reorganize kerns"] = function(data,filename)
     end
 end
 
+
+
+
+
+
+
+
+
 otf.enhancers["strip not needed data"] = function(data,filename)
     local verbose = fonts.verbose
     local int_to_uni = data.luatex.unicodes
@@ -1356,10 +1382,12 @@ function otf.features.register(name,default)
     otf.features.default[name] = default
 end
 
+-- for context this will become a task handler
+
 function otf.set_features(tfmdata,features)
     local processes = { }
     if features and next(features) then
-        local lists = {
+        local lists = { -- why local
             fonts.triggers,
             fonts.processors,
             fonts.manipulators,
@@ -1396,7 +1424,7 @@ function otf.set_features(tfmdata,features)
                 end
             end
         end
-        local fm = fonts.methods[mode]
+        local fm = fonts.methods[mode] -- todo: zonder node/mode otf/...
         if fm then
             local fmotf = fm.otf
             if fmotf then
@@ -1429,7 +1457,7 @@ function otf.otf_to_tfm(specification)
     local format   = specification.format
     local features = specification.features.normal
     local cache_id = specification.hash
-    local tfmdata  = containers.read(tfm.cache(),cache_id)
+    local tfmdata  = containers.read(tfm.cache,cache_id)
 --~ print(cache_id)
     if not tfmdata then
         local otfdata = otf.load(filename,format,sub,features and features.featurefile)
@@ -1463,7 +1491,7 @@ function otf.otf_to_tfm(specification)
                 shared.processes, shared.features = otf.set_features(tfmdata,fonts.define.check(features,otf.features.default))
             end
         end
-        containers.write(tfm.cache(),cache_id,tfmdata)
+        containers.write(tfm.cache,cache_id,tfmdata)
     end
     return tfmdata
 end
@@ -1505,14 +1533,11 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th
         local unicodes = luatex.unicodes -- names to unicodes
         local indices = luatex.indices
         local characters, parameters, math_parameters, descriptions = { }, { }, { }, { }
-        local tfm = {
-            characters = characters,
-            parameters = parameters,
-            math_parameters = math_parameters,
-            descriptions = descriptions,
-            indices = indices,
-            unicodes = unicodes,
-        }
+        local designsize = metadata.designsize or metadata.design_size or 100
+        if designsize == 0 then
+            designsize = 100
+        end
+        local spaceunits = 500
         -- indices maps from unicodes to indices
         for u, i in next, indices do
             characters[u] = { } -- we need this because for instance we add protruding info and loop over characters
@@ -1531,9 +1556,8 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th
                 -- we have them shared because that packs nicer
                 -- we could prepare the variants and keep 'm in descriptions
                 if m then
-                    local variants = m.horiz_variants
+                    local variants, parts, c = m.horiz_variants, m.horiz_parts, char
                     if variants then
-                        local c = char
                         for n in gmatch(variants,"[^ ]+") do
                             local un = unicodes[n]
                             if un and u ~= un then
@@ -1541,21 +1565,26 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th
                                 c = characters[un]
                             end
                         end
-                        c.horiz_variants = m.horiz_parts
-                    else
-                        local variants = m.vert_variants
-                        if variants then
-                            local c = char
-                            for n in gmatch(variants,"[^ ]+") do
-                                local un = unicodes[n]
-                                if un and u ~= un then
-                                    c.next = un
-                                    c = characters[un]
-                                end
+                        c.horiz_variants = parts
+                    elseif parts then
+                        c.horiz_variants = parts
+                    end
+                    local variants, parts, c = m.vert_variants, m.vert_parts, char
+                    if variants then
+                        for n in gmatch(variants,"[^ ]+") do
+                            local un = unicodes[n]
+                            if un and u ~= un then
+                                c.next = un
+                                c = characters[un]
                             end
-                            c.vert_variants = m.vert_parts
-                            c.vert_italic_correction = m.vert_italic_correction
-                        end
+                        end -- c is now last in chain
+                        c.vert_variants = parts
+                    elseif parts then
+                        c.vert_variants = parts
+                    end
+                    local italic_correction = m.vert_italic_correction
+                    if italic_correction then
+                        c.vert_italic_correction = italic_correction
                     end
                     local kerns = m.kerns
                     if kerns then
@@ -1565,65 +1594,49 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th
             end
         end
         -- end math
-        local designsize = metadata.designsize or metadata.design_size or 100
-        if designsize == 0 then
-            designsize = 100
-        end
-        local spaceunits = 500
-        -- we need a runtime lookup because of running from cdrom or zip, brrr (shouldn't we use the basename then?)
-        tfm.filename           = fonts.tfm.checked_filename(luatex)
-        tfm.fontname           = metadata.fontname
-        tfm.fullname           = metadata.fullname or tfm.fontname
-        tfm.psname             = tfm.fontname or tfm.fullname
-        tfm.name               = tfm.filename or tfm.fullname or tfm.fontname
-        tfm.units              = metadata.units_per_em or 1000
-        tfm.encodingbytes      = 2
-        tfm.format             = fonts.fontformat(tfm.filename,"opentype")
-        tfm.cidinfo            = data.cidinfo
-        tfm.cidinfo.registry   = tfm.cidinfo.registry or ""
-        tfm.type               = "real"
-        tfm.direction          = 0
-        tfm.boundarychar_label = 0
-        tfm.boundarychar       = 65536
-        tfm.designsize         = (designsize/10)*65536
-        tfm.spacer             = "500 units"
-        local endash, emdash = 0x20, 0x2014 -- unicodes['space'], unicodes['emdash']
+        local endash, emdash, space = 0x20, 0x2014, "space" -- unicodes['space'], unicodes['emdash']
         if metadata.isfixedpitch then
             if descriptions[endash] then
-                spaceunits, tfm.spacer = descriptions[endash].width, "space"
+                spaceunits, spacer = descriptions[endash].width, "space"
             end
             if not spaceunits and descriptions[emdash] then
-                spaceunits, tfm.spacer = descriptions[emdash].width, "emdash"
+                spaceunits, spacer = descriptions[emdash].width, "emdash"
             end
             if not spaceunits and metadata.charwidth then
-                spaceunits, tfm.spacer = metadata.charwidth, "charwidth"
+                spaceunits, spacer = metadata.charwidth, "charwidth"
             end
         else
             if descriptions[endash] then
-                spaceunits, tfm.spacer = descriptions[endash].width, "space"
+                spaceunits, spacer = descriptions[endash].width, "space"
             end
             if not spaceunits and descriptions[emdash] then
-                spaceunits, tfm.spacer = descriptions[emdash].width/2, "emdash/2"
+                spaceunits, spacer = descriptions[emdash].width/2, "emdash/2"
             end
             if not spaceunits and metadata.charwidth then
-                spaceunits, tfm.spacer = metadata.charwidth, "charwidth"
+                spaceunits, spacer = metadata.charwidth, "charwidth"
             end
         end
         spaceunits = tonumber(spaceunits) or tfm.units/2 -- 500 -- brrr
+        -- we need a runtime lookup because of running from cdrom or zip, brrr (shouldn't we use the basename then?)
+        local filename = fonts.tfm.checked_filename(luatex)
+        local fontname = metadata.fontname
+        local fullname = metadata.fullname or fontname
+        local cidinfo  = data.cidinfo
+        local units    = metadata.units_per_em or 1000
+        --
+        cidinfo.registry = cidinfo and cidinfo.registry or "" -- weird here, fix upstream
+        --
         parameters.slant         = 0
-        parameters.space         = spaceunits              -- 3.333 (cmr10)
-        parameters.space_stretch = tfm.units/2   --  500   -- 1.666 (cmr10)
-        parameters.space_shrink  = 1*tfm.units/3 --  333   -- 1.111 (cmr10)
-        parameters.x_height      = 2*tfm.units/5 --  400
-        parameters.quad          = tfm.units     -- 1000
-        if spaceunits < 2*tfm.units/5 then
+        parameters.space         = spaceunits          -- 3.333 (cmr10)
+        parameters.space_stretch = units/2   --  500   -- 1.666 (cmr10)
+        parameters.space_shrink  = 1*units/3 --  333   -- 1.111 (cmr10)
+        parameters.x_height      = 2*units/5 --  400
+        parameters.quad          = units     -- 1000
+        if spaceunits < 2*units/5 then
             -- todo: warning
         end
         local italicangle = metadata.italicangle
-        tfm.ascender    = math.abs(metadata.ascent  or 0)
-        tfm.descender   = math.abs(metadata.descent or 0)
         if italicangle then -- maybe also in afm _
-            tfm.italicangle = italicangle
             parameters.slant = parameters.slant - math.round(math.tan(italicangle*math.pi/180))
         end
         if metadata.isfixedpitch then
@@ -1645,8 +1658,34 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th
                 end
             end
         end
-        -- [6]
-        return tfm
+        --
+        return {
+            characters         = characters,
+            parameters         = parameters,
+            math_parameters    = math_parameters,
+            descriptions       = descriptions,
+            indices            = indices,
+            unicodes           = unicodes,
+            type               = "real",
+            direction          = 0,
+            boundarychar_label = 0,
+            boundarychar       = 65536,
+            designsize         = (designsize/10)*65536,
+            spacer             = "500 units",
+            encodingbytes      = 2,
+            filename           = filename,
+            fontname           = fontname,
+            fullname           = fullname,
+            psname             = fontname or fullname,
+            name               = filename or fullname,
+            units              = units,
+            format             = fonts.fontformat(filename,"opentype"),
+            cidinfo            = cidinfo,
+            ascender           = abs(metadata.ascent  or 0),
+            descender          = abs(metadata.descent or 0),
+            spacer             = spacer,
+            italicangle        = italicangle,
+        }
     else
         return nil
     end
diff --git a/otfl-font-otn.lua b/otfl-font-otn.lua
index d4f89ad..4402dd6 100644
--- a/otfl-font-otn.lua
+++ b/otfl-font-otn.lua
@@ -1882,6 +1882,9 @@ end
 local resolved = { } -- we only resolve a font,script,language pair once
 
 -- todo: pass all these 'locals' in a table
+--
+-- dynamics will be isolated some day ... for the moment we catch attribute zero
+-- not being set
 
 function fonts.methods.node.otf.features(head,font,attr)
     if trace_steps then
@@ -1926,8 +1929,7 @@ function fonts.methods.node.otf.features(head,font,attr)
     local ra  = rl      [attr]     if ra == nil then ra  = { } rl      [attr]     = ra  end -- attr can be false
     -- sequences always > 1 so no need for optimization
     for s=1,#sequences do
-        local pardir, txtdir = 0, { }
-        local success = false
+        local pardir, txtdir, success = 0, { }, false
         local sequence = sequences[s]
         local r = ra[s] -- cache
         if r == nil then
@@ -1994,24 +1996,33 @@ function fonts.methods.node.otf.features(head,font,attr)
                 while start do
                     local id = start.id
                     if id == glyph then
-                        if start.subtype<256 and start.font == font and (not attr or has_attribute(start,0,attr)) then
---~                         if start.subtype<256 and start.font == font and has_attribute(start,0,attr) then
-                            for i=1,#subtables do
-                                local lookupname = subtables[i]
-                                local lookupcache = thecache[lookupname]
-                                if lookupcache then
-                                    local lookupmatch = lookupcache[start.char]
-                                    if lookupmatch then
-                                        start, success = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i)
-                                        if success then
-                                            break
+                        if start.subtype<256 and start.font == font then
+                            local a = has_attribute(start,0)
+                            if a then
+                                a = a == attr
+                            else
+                                a = true
+                            end
+                            if a then
+                                for i=1,#subtables do
+                                    local lookupname = subtables[i]
+                                    local lookupcache = thecache[lookupname]
+                                    if lookupcache then
+                                        local lookupmatch = lookupcache[start.char]
+                                        if lookupmatch then
+                                            start, success = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i)
+                                            if success then
+                                                break
+                                            end
                                         end
+                                    else
+                                        report_missing_cache(typ,lookupname)
                                     end
-                                else
-                                    report_missing_cache(typ,lookupname)
                                 end
+                                if start then start = start.prev end
+                            else
+                                start = start.prev
                             end
-                            if start then start = start.prev end
                         else
                             start = start.prev
                         end
@@ -2034,18 +2045,27 @@ function fonts.methods.node.otf.features(head,font,attr)
                         while start do
                             local id = start.id
                             if id == glyph then
---~                                 if start.font == font and start.subtype<256 and has_attribute(start,0,attr) and (not attribute or has_attribute(start,state,attribute)) then
-                                if start.font == font and start.subtype<256 and (not attr or has_attribute(start,0,attr)) and (not attribute or has_attribute(start,state,attribute)) then
-                                    local lookupmatch = lookupcache[start.char]
-                                    if lookupmatch then
-                                        -- sequence kan weg
-                                        local ok
-                                        start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,1)
-                                        if ok then
-                                            success = true
+                                if start.subtype<256 and start.font == font then
+                                    local a = has_attribute(start,0)
+                                    if a then
+                                        a = (a == attr) and (not attribute or has_attribute(start,state,attribute))
+                                    else
+                                        a = not attribute or has_attribute(start,state,attribute)
+                                    end
+                                    if a then
+                                        local lookupmatch = lookupcache[start.char]
+                                        if lookupmatch then
+                                            -- sequence kan weg
+                                            local ok
+                                            start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,1)
+                                            if ok then
+                                                success = true
+                                            end
                                         end
+                                        if start then start = start.next end
+                                    else
+                                        start = start.next
                                     end
-                                    if start then start = start.next end
                                 else
                                     start = start.next
                                 end
@@ -2109,27 +2129,36 @@ function fonts.methods.node.otf.features(head,font,attr)
                     while start do
                         local id = start.id
                         if id == glyph then
-                            if start.subtype<256 and start.font == font and (not attr or has_attribute(start,0,attr)) and (not attribute or has_attribute(start,state,attribute)) then
---~                             if start.subtype<256 and start.font == font and has_attribute(start,0,attr) and (not attribute or has_attribute(start,state,attribute)) then
-                                for i=1,ns do
-                                    local lookupname = subtables[i]
-                                    local lookupcache = thecache[lookupname]
-                                    if lookupcache then
-                                        local lookupmatch = lookupcache[start.char]
-                                        if lookupmatch then
-                                            -- we could move all code inline but that makes things even more unreadable
-                                            local ok
-                                            start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i)
-                                            if ok then
-                                                success = true
-                                                break
+                            if start.subtype<256 and start.font == font then
+                                local a = has_attribute(start,0)
+                                if a then
+                                    a = (a == attr) and (not attribute or has_attribute(start,state,attribute))
+                                else
+                                    a = not attribute or has_attribute(start,state,attribute)
+                                end
+                                if a then
+                                    for i=1,ns do
+                                        local lookupname = subtables[i]
+                                        local lookupcache = thecache[lookupname]
+                                        if lookupcache then
+                                            local lookupmatch = lookupcache[start.char]
+                                            if lookupmatch then
+                                                -- we could move all code inline but that makes things even more unreadable
+                                                local ok
+                                                start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i)
+                                                if ok then
+                                                    success = true
+                                                    break
+                                                end
                                             end
+                                        else
+                                            report_missing_cache(typ,lookupname)
                                         end
-                                    else
-                                        report_missing_cache(typ,lookupname)
                                     end
+                                    if start then start = start.next end
+                                else
+                                    start = start.next
                                 end
-                                if start then start = start.next end
                             else
                                 start = start.next
                             end
@@ -2149,7 +2178,6 @@ function fonts.methods.node.otf.features(head,font,attr)
                         --         start = start.next
                         --     end
                         elseif id == whatsit then
-                            local subtype = start.subtype
                             local subtype = start.subtype
                             if subtype == 7 then
                                 local dir = start.dir
diff --git a/otfl-font-tfm.lua b/otfl-font-tfm.lua
index 31ae2ca..560ba1c 100644
--- a/otfl-font-tfm.lua
+++ b/otfl-font-tfm.lua
@@ -52,6 +52,8 @@ tfm.fontname_mode    = "fullpath"
 
 tfm.enhance = tfm.enhance or function() end
 
+fonts.formats.tfm = "type1" -- we need to have at least a value here
+
 function tfm.read_from_tfm(specification)
     local fname, tfmdata = specification.filename or "", nil
     if fname ~= "" then
@@ -391,6 +393,9 @@ t.colorscheme = tfmtable.colorscheme
             local vn = v.next
             if vn then
                 chr.next = vn
+            --~ if v.vert_variants or v.horiz_variants then
+            --~     logs.report("glyph 0x%05X has combination of next, vert_variants and horiz_variants",index)
+            --~ end
             else
                 local vv = v.vert_variants
                 if vv then
diff --git a/otfl-luat-dum.lua b/otfl-luat-dum.lua
index 3946b6f..0737762 100644
--- a/otfl-luat-dum.lua
+++ b/otfl-luat-dum.lua
@@ -1,5 +1,5 @@
 if not modules then modules = { } end modules ['luat-dum'] = {
-    version   = 1.001,
+    version   = 1.100,
     comment   = "companion to luatex-*.tex",
     author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
     copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -80,29 +80,80 @@ end
 -- usage as I don't want any dependency at all. Also, ConTeXt might have
 -- different needs and tricks added.
 
+--~ containers.usecache = true
+
 caches = { }
 
---~ containers.usecache = true
+local writable, readables = nil, { }
+
+if not caches.namespace or caches.namespace == "" or caches.namespace == "context" then
+    caches.namespace = 'generic'
+end
+
+do
+
+    local cachepaths = kpse.expand_path('$TEXMFCACHE') or ""
+
+    if cachepaths == "" then
+        cachepaths = kpse.expand_path('$VARTEXMF')
+    end
+
+    if cachepaths == "" then
+        cachepaths = "."
+    end
+
+    cachepaths = string.split(cachepaths,os.type == "windows" and ";" or ":")
 
-function caches.setpath(category,subcategory)
---  local root = kpse.var_value("TEXMFCACHE") or ""
---  if root == "" then
---      root = kpse.var_value("VARTEXMF") or ""
---  end
-    local var  = kpse.var_value("TEXMFVAR")
-    local root = var and (var .. "/luatex/generic/luaotfload/") or ""
-    if root ~= "" then
-        root = file.join(root,category)
-        lfs.mkdir(root)
-        root = file.join(root,subcategory)
-        lfs.mkdir(root)
-        return lfs.isdir(root) and root
+    for i=1,#cachepaths do
+        if file.iswritable(cachepaths[i]) then
+            writable = file.join(cachepaths[i],"luatex-cache")
+            lfs.mkdir(writable)
+            writable = file.join(writable,caches.namespace)
+            lfs.mkdir(writable)
+            break
+        end
     end
+
+    for i=1,#cachepaths do
+        if file.isreadable(cachepaths[i]) then
+            readables[#readables+1] = file.join(cachepaths[i],"luatex-cache",caches.namespace)
+        end
+    end
+
+    if not writable then
+        texio.write_nl("quiting: fix your writable cache path")
+        os.exit()
+    elseif #readables == 0 then
+        texio.write_nl("quiting: fix your readable cache path")
+        os.exit()
+    elseif #readables == 1 and readables[1] == writable then
+        texio.write(string.format("(using cache: %s)",writable))
+    else
+        texio.write(string.format("(using write cache: %s)",writable))
+        texio.write(string.format("(using read cache: %s)",table.concat(readables, " ")))
+    end
+
+end
+
+function caches.getwritablepath(category,subcategory)
+    local path = file.join(writable,category)
+    lfs.mkdir(path)
+    path = file.join(path,subcategory)
+    lfs.mkdir(path)
+    return path
+end
+
+function caches.getreadablepaths(category,subcategory)
+    local t = { }
+    for i=1,#readables do
+        t[i] = file.join(readables[i],category,subcategory)
+    end
+    return t
 end
 
 local function makefullname(path,name)
     if path and path ~= "" then
-        name = "temp-" and name -- clash prevention
+        name = "temp-" .. name -- clash prevention
         return file.addsuffix(file.join(path,name),"lua")
     end
 end
@@ -112,17 +163,21 @@ function caches.iswritable(path,name)
     return fullname and file.iswritable(fullname)
 end
 
-function caches.loaddata(path,name)
-    local fullname = makefullname(path,name)
-    if fullname then
-        local data = loadfile(fullname)
-        return data and data()
+function caches.loaddata(paths,name)
+    for i=1,#paths do
+        local fullname = makefullname(paths[i],name)
+        if fullname then
+            texio.write(string.format("(load: %s)",fullname))
+            local data = loadfile(fullname)
+            return data and data()
+        end
     end
 end
 
 function caches.savedata(path,name,data)
     local fullname = makefullname(path,name)
     if fullname then
+        texio.write(string.format("(save: %s)",fullname))
         table.tofile(fullname,data,'return',false,true,false)
     end
 end
diff --git a/otfl-node-dum.lua b/otfl-node-dum.lua
index f39a087..fbc8264 100644
--- a/otfl-node-dum.lua
+++ b/otfl-node-dum.lua
@@ -6,7 +6,19 @@ if not modules then modules = { } end modules ['node-dum'] = {
     license   = "see context related readme files"
 }
 
-nodes = nodes or { }
+nodes      = nodes      or { }
+fonts      = fonts      or { }
+attributes = attributes or { }
+
+local traverse_id = node.traverse_id
+local free_node   = node.free
+local remove_node = node.remove
+
+local glyph = node.id('glyph')
+
+-- fonts
+
+local fontdata = fonts.ids or { }
 
 function nodes.simple_font_handler(head)
 --  lang.hyphenate(head)
@@ -17,3 +29,97 @@ function nodes.simple_font_handler(head)
     head = node.kerning(head)
     return head
 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","! purposed so setting them at the TeX end might break the font handler.")
+    texio.write_nl("log","!")
+
+    tex.attribute[0] = 0 -- else no features
+
+end
+
+nodes.protect_glyphs   = node.protect_glyphs
+nodes.unprotect_glyphs = node.unprotect_glyphs
+
+function nodes.process_characters(head)
+    local usedfonts, done, prevfont = { }, false, nil
+    for n in traverse_id(glyph,head) do
+        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 -- we need to check shared, only when same features
+                    if shared then
+                        local processors = shared.processes
+                        if processors and #processors > 0 then
+                            usedfonts[font] = processors
+                            done = true
+                        end
+                    end
+                end
+            end
+        end
+    end
+    if done then
+        for font, processors in next, usedfonts do
+            for i=1,#processors do
+                local h, d = processors[i](head,font,0)
+                head, done = h or head, done or d
+            end
+        end
+    end
+    return head, true
+end
+
+-- helper
+
+function nodes.kern(k)
+    local n = new_node("kern",1)
+    n.kern = k
+    return n
+end
+
+function nodes.remove(head, current, free_too)
+   local t = current
+   head, current = remove_node(head,current)
+   if t then
+        if free_too then
+            free_node(t)
+            t = nil
+        else
+            t.next, t.prev = nil, nil
+        end
+   end
+   return head, current, t
+end
+
+function nodes.delete(head,current)
+    return nodes.remove(head,current,true)
+end
+
+nodes.before = node.insert_before
+nodes.after  = node.insert_after
+
+-- attributes
+
+attributes.unsetvalue = -0x7FFFFFFF
+
+local numbers, last = { }, 127
+
+function attributes.private(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
diff --git a/otfl-node-fnt.lua b/otfl-node-fnt.lua
deleted file mode 100644
index f2d8e1d..0000000
--- a/otfl-node-fnt.lua
+++ /dev/null
@@ -1,205 +0,0 @@
-if not modules then modules = { } end modules ['node-fnt'] = {
-    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 trace_characters = false  trackers.register("nodes.characters", function(v) trace_characters = v end)
-
-local glyph = node.id('glyph')
-
-local traverse_id   = node.traverse_id
-local has_attribute = node.has_attribute
-
-local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming
-
-fonts     = fonts      or { }
-fonts.tfm = fonts.tfm  or { }
-fonts.ids = fonts.ids  or { }
-
-local fontdata = fonts.ids
-
--- some tests with using an array of dynamics[id] and processes[id] demonstrated
--- that there was nothing to gain (unless we also optimize other parts)
---
--- maybe getting rid of the intermediate shared can save some time
-
--- potential speedup: check for subtype < 256 so that we can remove that test
--- elsewhere, danger: injected nodes will not be dealt with but that does not
--- happen often; we could consider processing sublists but that might need mor
--- checking later on; the current approach also permits variants
-
-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","! purposed so setting them at the TeX end might break the font handler.")
-    texio.write_nl("log","!")
-
-    tex.attribute[0] = 0 -- else no features
-
-end
-
-function nodes.process_characters(head)
-    -- either next or not, but definitely no already processed list
-    starttiming(nodes)
-    local usedfonts, attrfonts, done = { }, { }, false
-    local a, u, prevfont, prevattr = 0, 0, nil, 0
-    for n in traverse_id(glyph,head) do
-        local font, attr = n.font, has_attribute(n,0) -- zero attribute is reserved for fonts in context
-        if attr and attr > 0 then
-            if font ~= prevfont or attr ~= prevattr then
-                local used = attrfonts[font]
-                if not used then
-                    used = { }
-                    attrfonts[font] = used
-                end
-                if not used[attr] then
-                    -- we do some testing outside the function
-                    local tfmdata = fontdata[font]
-                    local shared = tfmdata.shared
-                    if shared then
-                        local dynamics = shared.dynamics
-                        if dynamics then
-                            local d = shared.set_dynamics(font,dynamics,attr) -- still valid?
-                            if d then
-                                used[attr] = d
-                                a = a + 1
-                            end
-                        end
-                    end
-                end
-                prevfont, prevattr = font, attr
-            end
-        elseif font ~= prevfont then
-            prevfont, prevattr = font, 0
-            local used = usedfonts[font]
-            if not used then
-                local tfmdata = fontdata[font]
-                if tfmdata then
-                    local shared = tfmdata.shared -- we need to check shared, only when same features
-                    if shared then
-                        local processors = shared.processes
-                        if processors and #processors > 0 then
-                            usedfonts[font] = processors
-                            u = u + 1
-                        end
-                    end
-                else
-                    -- probably nullfont
-                end
-            end
-        else
-            prevattr = attr
-        end
-    end
-    -- we could combine these and just make the attribute nil
-    if u == 1 then
-        local font, processors = next(usedfonts)
-        local n = #processors
-        if n > 0 then
-            local h, d = processors[1](head,font,false)
-            head, done = h or head, done or d
-            if n > 1 then
-                for i=2,n do
-                    local h, d = processors[i](head,font,false)
-                    head, done = h or head, done or d
-                end
-            end
-        end
-    elseif u > 0 then
-        for font, processors in next, usedfonts do
-            local n = #processors
-            local h, d = processors[1](head,font,false)
-            head, done = h or head, done or d
-            if n > 1 then
-                for i=2,n do
-                    local h, d = processors[i](head,font,false)
-                    head, done = h or head, done or d
-                end
-            end
-        end
-    end
-    if a == 1 then
-        local font, dynamics = next(attrfonts)
-        for attribute, processors in next, dynamics do -- attr can switch in between
-            local n = #processors
-            local h, d = processors[1](head,font,attribute)
-            head, done = h or head, done or d
-            if n > 1 then
-                for i=2,n do
-                    local h, d = processors[i](head,font,attribute)
-                    head, done = h or head, done or d
-                end
-            end
-        end
-    elseif a > 0 then
-        for font, dynamics in next, attrfonts do
-            for attribute, processors in next, dynamics do -- attr can switch in between
-                local n = #processors
-                local h, d = processors[1](head,font,attribute)
-                head, done = h or head, done or d
-                if n > 1 then
-                    for i=2,n do
-                        local h, d = processors[i](head,font,attribute)
-                        head, done = h or head, done or d
-                    end
-                end
-            end
-        end
-    end
-    stoptiming(nodes)
-    if trace_characters then
-        nodes.report(head,done)
-    end
-    return head, true
-end
-
-if node.protect_glyphs then
-
-    nodes.protect_glyphs   = node.protect_glyphs
-    nodes.unprotect_glyphs = node.unprotect_glyphs
-
-else do
-
-    -- initial value subtype     : X000 0001 =  1 = 0x01 = char
-    --
-    -- expected before linebreak : X000 0000 =  0 = 0x00 = glyph
-    --                             X000 0010 =  2 = 0x02 = ligature
-    --                             X000 0100 =  4 = 0x04 = ghost
-    --                             X000 1010 = 10 = 0x0A = leftboundary lig
-    --                             X001 0010 = 18 = 0x12 = rightboundary lig
-    --                             X001 1010 = 26 = 0x1A = both boundaries lig
-    --                             X000 1100 = 12 = 0x1C = leftghost
-    --                             X001 0100 = 20 = 0x14 = rightghost
-
-    function nodes.protect_glyphs(head)
-        local done = false
-        for g in traverse_id(glyph,head) do
-            local s = g.subtype
-            if s == 1 then
-                done, g.subtype = true, 256
-            elseif s <= 256 then
-                done, g.subtype = true, 256 + s
-            end
-        end
-        return done
-    end
-
-    function nodes.unprotect_glyphs(head)
-        local done = false
-        for g in traverse_id(glyph,head) do
-            local s = g.subtype
-            if s > 256 then
-                done, g.subtype = true, s - 256
-            end
-        end
-        return done
-    end
-
-end end
diff --git a/otfl-node-ini.lua b/otfl-node-ini.lua
deleted file mode 100644
index 36e2402..0000000
--- a/otfl-node-ini.lua
+++ /dev/null
@@ -1,244 +0,0 @@
-if not modules then modules = { } end modules ['node-ini'] = {
-    version   = 1.001,
-    comment   = "companion to node-ini.mkiv",
-    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
-    copyright = "PRAGMA ADE / ConTeXt Development Team",
-    license   = "see context related readme files"
-}
-
---[[ldx--
-<p>Most of the code that had accumulated here is now separated in
-modules.</p>
---ldx]]--
-
--- this module is being reconstructed
-
-local utf = unicode.utf8
-local next, type = next, type
-local format, concat, match, utfchar = string.format, table.concat, string.match, utf.char
-
-local chardata = characters and characters.data
-
---[[ldx--
-<p>We start with a registration system for atributes so that we can use the
-symbolic names later on.</p>
---ldx]]--
-
-attributes = attributes or { }
-
-attributes.names      = attributes.names   or { }
-attributes.numbers    = attributes.numbers or { }
-attributes.list       = attributes.list    or { }
-attributes.unsetvalue = -0x7FFFFFFF
-
-storage.register("attributes/names",   attributes.names,   "attributes.names")
-storage.register("attributes/numbers", attributes.numbers, "attributes.numbers")
-storage.register("attributes/list",    attributes.list,    "attributes.list")
-
-local names, numbers, list = attributes.names, attributes.numbers, attributes.list
-
-function attributes.define(name,number) -- at the tex end
-    if not numbers[name] then
-        numbers[name], names[number], list[number] = number, name, { }
-    end
-end
-
---[[ldx--
-<p>We can use the attributes in the range 127-255 (outside user space). These
-are only used when no attribute is set at the \TEX\ end which normally
-happens in <l n='context'/>.</p>
---ldx]]--
-
-storage.shared.attributes_last_private = storage.shared.attributes_last_private or 127
-
-function attributes.private(name) -- at the lua end (hidden from user)
-    local number = numbers[name]
-    if not number then
-        local last = storage.shared.attributes_last_private or 127
-        if last < 255 then
-            last = last + 1
-            storage.shared.attributes_last_private = last
-        end
-        number = last
-        numbers[name], names[number], list[number] = number, name, { }
-    end
-    return number
-end
-
---[[ldx--
-<p>Access to nodes is what gives <l n='luatex'/> its power. Here we
-implement a few helper functions. These functions are rather optimized.</p>
---ldx]]--
-
---[[ldx--
-<p>When manipulating node lists in <l n='context'/>, we will remove
-nodes and insert new ones. While node access was implemented, we did
-quite some experiments in order to find out if manipulating nodes
-in <l n='lua'/> was feasible from the perspective of performance.</p>
-
-<p>First of all, we noticed that the bottleneck is more with excessive
-callbacks (some gets called very often) and the conversion from and to
-<l n='tex'/>'s datastructures. However, at the <l n='lua'/> end, we
-found that inserting and deleting nodes in a table could become a
-bottleneck.</p>
-
-<p>This resulted in two special situations in passing nodes back to
-<l n='tex'/>: a table entry with value <type>false</type> is ignored,
-and when instead of a table <type>true</type> is returned, the
-original table is used.</p>
-
-<p>Insertion is handled (at least in <l n='context'/> as follows. When
-we need to insert a node at a certain position, we change the node at
-that position by a dummy node, tagged <type>inline</type> which itself
-has_attribute the original node and one or more new nodes. Before we pass
-back the list we collapse the list. Of course collapsing could be built
-into the <l n='tex'/> engine, but this is a not so natural extension.</p>
-
-<p>When we collapse (something that we only do when really needed), we
-also ignore the empty nodes. [This is obsolete!]</p>
---ldx]]--
-
-nodes = nodes or { }
-
-local hlist   = node.id('hlist')
-local vlist   = node.id('vlist')
-local glyph   = node.id('glyph')
-local glue    = node.id('glue')
-local penalty = node.id('penalty')
-local kern    = node.id('kern')
-local whatsit = node.id('whatsit')
-
-local traverse_id        = node.traverse_id
-local traverse           = node.traverse
-local free_node          = node.free
-local remove_node        = node.remove
-local insert_node_before = node.insert_before
-local insert_node_after  = node.insert_after
-
-function nodes.remove(head, current, free_too)
-   local t = current
-   head, current = remove_node(head,current)
-   if t then
-        if free_too then
-            free_node(t)
-            t = nil
-        else
-            t.next, t.prev = nil, nil
-        end
-   end
-   return head, current, t
-end
-
-function nodes.delete(head,current)
-    return nodes.remove(head,current,true)
-end
-
-nodes.before = insert_node_before
-nodes.after  = insert_node_after
-
--- we need to test this, as it might be fixed now
-
-function nodes.before(h,c,n)
-    if c then
-        if c == h then
-            n.next = h
-            n.prev = nil
-            h.prev = n
-        else
-            local cp = c.prev
-            n.next = c
-            n.prev = cp
-            if cp then
-                cp.next = n
-            end
-            c.prev = n
-            return h, n
-        end
-    end
-    return n, n
-end
-
-function nodes.after(h,c,n)
-    if c then
-        local cn = c.next
-        if cn then
-            n.next = cn
-            cn.prev = n
-        else
-            n.next = nil
-        end
-        c.next = n
-        n.prev = c
-        return h, n
-    end
-    return n, n
-end
-
--- local h, c = nodes.replace(head,current,new)
--- local c = nodes.replace(false,current,new)
--- local c = nodes.replace(current,new)
-
-function nodes.replace(head,current,new) -- no head returned if false
-    if not new then
-        head, current, new = false, head, current
-    end
-    local prev, next = current.prev, current.next
-    if next then
-        new.next, next.prev = next, new
-    end
-    if prev then
-        new.prev, prev.next = prev, new
-    end
-    if head then
-        if head == current then
-            head = new
-        end
-        free_node(current)
-        return head, new
-    else
-        free_node(current)
-        return new
-    end
-end
-
--- will move
-
-local function count(stack,flat)
-    local n = 0
-    while stack do
-        local id = stack.id
-        if not flat and id == hlist or id == vlist then
-            local list = stack.list
-            if list then
-                n = n + 1 + count(list) -- self counts too
-            else
-                n = n + 1
-            end
-        else
-            n = n + 1
-        end
-        stack  = stack.next
-    end
-    return n
-end
-
-nodes.count = count
-
--- new, will move
-
-function attributes.ofnode(n)
-    local a = n.attr
-    if a then
-        local names = attributes.names
-        a = a.next
-        while a do
-            local number, value = a.number, a.value
-            texio.write_nl(format("%s : attribute %3i, value %4i, name %s",tostring(n),number,value,names[number] or '?'))
-            a = a.next
-        end
-   end
-end
-
-local left, space = lpeg.P("<"), lpeg.P(" ")
-
-nodes.filterkey = left * (1-left)^0 * left * space^0 * lpeg.C((1-space)^0)
diff --git a/otfl-node-inj.lua b/otfl-node-inj.lua
index 9c4612a..579a266 100644
--- a/otfl-node-inj.lua
+++ b/otfl-node-inj.lua
@@ -342,39 +342,21 @@ function nodes.inject_kerns(head,where,keep)
                  -- only w can be nil, can be sped up when w == nil
                     local rl, x, w, r2l = k[1], k[2] or 0, k[4] or 0, k[6]
                     local wx = w - x
---~                     if rl < 0 then
---~                         if r2l then
---~                             if wx ~= 0 then
---~                                 insert_node_before(head,n,newkern(wx))
---~                             end
---~                             if x ~= 0 then
---~                                 insert_node_after (head,n,newkern(x))
---~                             end
---~                         else
---~                             if x ~= 0 then
---~                                 insert_node_before(head,n,newkern(x))
---~                             end
---~                             if wx ~= 0 then
---~                                 insert_node_after(head,n,newkern(wx))
---~                             end
---~                         end
---~                     else
-                        if r2l then
-                            if wx ~= 0 then
-                                insert_node_before(head,n,newkern(wx))
-                            end
-                            if x ~= 0 then
-                                insert_node_after (head,n,newkern(x))
-                            end
-                        else
-                            if x ~= 0 then
-                                insert_node_before(head,n,newkern(x))
-                            end
-                            if wx ~= 0 then
-                                insert_node_after(head,n,newkern(wx))
-                            end
+                    if r2l then
+                        if wx ~= 0 then
+                            insert_node_before(head,n,newkern(wx))
+                        end
+                        if x ~= 0 then
+                            insert_node_after (head,n,newkern(x))
+                        end
+                    else
+                        if x ~= 0 then
+                            insert_node_before(head,n,newkern(x))
+                        end
+                        if wx ~= 0 then
+                            insert_node_after(head,n,newkern(wx))
                         end
---~                     end
+                    end
                 end
             end
             if next(cx) then
@@ -413,39 +395,21 @@ function nodes.inject_kerns(head,where,keep)
                         -- copied from above
                         local r2l = kk[6]
                         local wx = w - x
---~                         if rl < 0 then
---~                             if r2l then
---~                                 if x ~= 0 then
---~                                     insert_node_before(head,n,newkern(x))
---~                                 end
---~                                 if wx ~= 0 then
---~                                     insert_node_after(head,n,newkern(wx))
---~                                 end
---~                             else
---~                                 if wx ~= 0 then
---~                                     insert_node_before(head,n,newkern(wx))
---~                                 end
---~                                 if x ~= 0 then
---~                                     insert_node_after (head,n,newkern(x))
---~                                 end
---~                             end
---~                         else
-                            if r2l then
-                                if wx ~= 0 then
-                                    insert_node_before(head,n,newkern(wx))
-                                end
-                                if x ~= 0 then
-                                    insert_node_after (head,n,newkern(x))
-                                end
-                            else
-                                if x ~= 0 then
-                                    insert_node_before(head,n,newkern(x))
-                                end
-                                if wx ~= 0 then
-                                    insert_node_after(head,n,newkern(wx))
-                                end
+                        if r2l then
+                            if wx ~= 0 then
+                                insert_node_before(head,n,newkern(wx))
+                            end
+                            if x ~= 0 then
+                                insert_node_after (head,n,newkern(x))
+                            end
+                        else
+                            if x ~= 0 then
+                                insert_node_before(head,n,newkern(x))
                             end
---~                         end
+                            if wx ~= 0 then
+                                insert_node_after(head,n,newkern(wx))
+                            end
+                        end
                     else
                         -- simple (e.g. kernclass kerns)
                         if x ~= 0 then
diff --git a/otfl-node-res.lua b/otfl-node-res.lua
deleted file mode 100644
index a8ea874..0000000
--- a/otfl-node-res.lua
+++ /dev/null
@@ -1,302 +0,0 @@
-if not modules then modules = { } end modules ['node-res'] = {
-    version   = 1.001,
-    comment   = "companion to node-ini.mkiv",
-    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
-    copyright = "PRAGMA ADE / ConTeXt Development Team",
-    license   = "see context related readme files"
-}
-
-local gmatch, format = string.gmatch, string.format
-local copy_node, free_node, free_list, new_node, node_type, node_id = node.copy, node.free, node.flush_list, node.new, node.type, node.id
-local tonumber, round = tonumber, math.round
-
-local glyph_node = node_id("glyph")
-
---[[ldx--
-<p>The next function is not that much needed but in <l n='context'/> we use
-for debugging <l n='luatex'/> node management.</p>
---ldx]]--
-
-nodes = nodes or { }
-
-nodes.whatsits = { } -- table.swapped(node.whatsits())
-
-local reserved = { }
-local whatsits = nodes.whatsits
-
-for k, v in next, node.whatsits() do
-    whatsits[k], whatsits[v] = v, k -- two way
-end
-
-local function register_node(n)
-    reserved[#reserved+1] = n
-    return n
-end
-
-nodes.register = register_node
-
-function nodes.cleanup_reserved(nofboxes) -- todo
-    nodes.tracers.steppers.reset() -- todo: make a registration subsystem
-    local nr, nl = #reserved, 0
-    for i=1,nr do
-        local ri = reserved[i]
-    --  if not (ri.id == glue_spec and not ri.is_writable) then
-            free_node(reserved[i])
-    --  end
-    end
-    if nofboxes then
-        local tb = tex.box
-        for i=0,nofboxes do
-            local l = tb[i]
-            if l then
-                free_node(tb[i])
-                nl = nl + 1
-            end
-        end
-    end
-    reserved = { }
-    return nr, nl, nofboxes -- can be nil
-end
-
-function nodes.usage()
-    local t = { }
-    for n, tag in gmatch(status.node_mem_usage,"(%d+) ([a-z_]+)") do
-        t[tag] = n
-    end
-    return t
-end
-
-local disc              = register_node(new_node("disc"))
-local kern              = register_node(new_node("kern",1))
-local penalty           = register_node(new_node("penalty"))
-local glue              = register_node(new_node("glue")) -- glue.spec = nil
-local glue_spec         = register_node(new_node("glue_spec"))
-local glyph             = register_node(new_node("glyph",0))
-local textdir           = register_node(new_node("whatsit",whatsits.dir)) -- 7 (6 is local par node)
-local rule              = register_node(new_node("rule"))
-local latelua           = register_node(new_node("whatsit",whatsits.late_lua)) -- 35
-local user_n            = register_node(new_node("whatsit",whatsits.user_defined)) user_n.type = 100 -- 44
-local user_l            = register_node(new_node("whatsit",whatsits.user_defined)) user_l.type = 110 -- 44
-local user_s            = register_node(new_node("whatsit",whatsits.user_defined)) user_s.type = 115 -- 44
-local user_t            = register_node(new_node("whatsit",whatsits.user_defined)) user_t.type = 116 -- 44
-local left_margin_kern  = register_node(new_node("margin_kern",0))
-local right_margin_kern = register_node(new_node("margin_kern",1))
-local lineskip          = register_node(new_node("glue",1))
-local baselineskip      = register_node(new_node("glue",2))
-local leftskip          = register_node(new_node("glue",8))
-local rightskip         = register_node(new_node("glue",9))
-local temp              = register_node(new_node("temp",0))
-
-function nodes.zeroglue(n)
-    local s = n.spec
-    return not writable or (
-                     s.width == 0
-         and       s.stretch == 0
-         and        s.shrink == 0
-         and s.stretch_order == 0
-         and  s.shrink_order == 0
-        )
-end
-
-function nodes.glyph(fnt,chr)
-    local n = copy_node(glyph)
-    if fnt then n.font = fnt end
-    if chr then n.char = chr end
-    return n
-end
-
-function nodes.penalty(p)
-    local n = copy_node(penalty)
-    n.penalty = p
-    return n
-end
-
-function nodes.kern(k)
-    local n = copy_node(kern)
-    n.kern = k
-    return n
-end
-
-function nodes.glue_spec(width,stretch,shrink)
-    local s = copy_node(glue_spec)
-    s.width, s.stretch, s.shrink = width, stretch, shrink
-    return s
-end
-
-local function someskip(skip,width,stretch,shrink)
-    local n = copy_node(skip)
-    if not width then
-        -- no spec
-    elseif tonumber(width) then
-        local s = copy_node(glue_spec)
-        s.width, s.stretch, s.shrink = width, stretch, shrink
-        n.spec = s
-    else
-        -- shared
-        n.spec = copy_node(width)
-    end
-    return n
-end
-
-function nodes.glue(width,stretch,shrink)
-    return someskip(glue,width,stretch,shrink)
-end
-function nodes.leftskip(width,stretch,shrink)
-    return someskip(leftskip,width,stretch,shrink)
-end
-function nodes.rightskip(width,stretch,shrink)
-    return someskip(rightskip,width,stretch,shrink)
-end
-function nodes.lineskip(width,stretch,shrink)
-    return someskip(lineskip,width,stretch,shrink)
-end
-function nodes.baselineskip(width,stretch,shrink)
-    return someskip(baselineskip,width,stretch,shrink)
-end
-
-function nodes.disc()
-    return copy_node(disc)
-end
-
-function nodes.textdir(dir)
-    local t = copy_node(textdir)
-    t.dir = dir
-    return t
-end
-
-function nodes.rule(width,height,depth,dir)
-    local n = copy_node(rule)
-    if width  then n.width  = width  end
-    if height then n.height = height end
-    if depth  then n.depth  = depth  end
-    if dir    then n.dir    = dir    end
-    return n
-end
-
-function nodes.latelua(code)
-    local n = copy_node(latelua)
-    n.data = code
-    return n
-end
-
-function nodes.leftmarginkern(glyph,width)
-    local n = copy_node(left_margin_kern)
-    if not glyph then
-        logs.fatal("nodes","invalid pointer to left margin glyph node")
-    elseif glyph.id ~= glyph_node then
-        logs.fatal("nodes","invalid node type %s for left margin glyph node",node_type(glyph))
-    else
-        n.glyph = glyph
-    end
-    if width then
-        n.width = width
-    end
-    return n
-end
-
-function nodes.rightmarginkern(glyph,width)
-    local n = copy_node(right_margin_kern)
-    if not glyph then
-        logs.fatal("nodes","invalid pointer to right margin glyph node")
-    elseif glyph.id ~= glyph_node then
-        logs.fatal("nodes","invalid node type %s for right margin glyph node",node_type(p))
-    else
-        n.glyph = glyph
-    end
-    if width then
-        n.width = width
-    end
-    return n
-end
-
-function nodes.temp()
-    return copy_node(temp)
-end
---[[
-<p>At some point we ran into a problem that the glue specification
-of the zeropoint dimension was overwritten when adapting a glue spec
-node. This is a side effect of glue specs being shared. After a
-couple of hours tracing and debugging Taco and I came to the
-conclusion that it made no sense to complicate the spec allocator
-and settled on a writable flag. This all is a side effect of the
-fact that some glues use reserved memory slots (with the zeropoint
-glue being a noticeable one). So, next we wrap this into a function
-and hide it for the user. And yes, LuaTeX now gives a warning as
-well.</p>
-]]--
-
-if tex.luatexversion > 51 then
-
-    function nodes.writable_spec(n)
-        local spec = n.spec
-        if not spec then
-            spec = copy_node(glue_spec)
-            n.spec = spec
-        elseif not spec.writable then
-            spec = copy_node(spec)
-            n.spec = spec
-        end
-        return spec
-    end
-
-else
-
-    function nodes.writable_spec(n)
-        local spec = n.spec
-        if not spec then
-            spec = copy_node(glue_spec)
-        else
-            spec = copy_node(spec)
-        end
-        n.spec = spec
-        return spec
-    end
-
-end
-
-local cache = { }
-
-function nodes.usernumber(num)
-    local n = cache[num]
-    if n then
-        return copy_node(n)
-    else
-        local n = copy_node(user_n)
-        if num then n.value = num end
-        return n
-    end
-end
-
-function nodes.userlist(list)
-    local n = copy_node(user_l)
-    if list then n.value = list end
-    return n
-end
-
-local cache = { } -- we could use the same cache
-
-function nodes.userstring(str)
-    local n = cache[str]
-    if n then
-        return copy_node(n)
-    else
-        local n = copy_node(user_s)
-        n.type = 115
-        if str then n.value = str end
-        return n
-    end
-end
-
-function nodes.usertokens(tokens)
-    local n = copy_node(user_t)
-    if tokens then n.value = tokens end
-    return n
-end
-
-statistics.register("cleaned up reserved nodes", function()
-    return format("%s nodes, %s lists of %s", nodes.cleanup_reserved(tex.count["lastallocatedbox"]))
-end) -- \topofboxstack
-
-statistics.register("node memory usage", function() -- comes after cleanup !
-    return status.node_mem_usage
-end)
-- 
cgit v1.2.3