From 3a75fc96a5e7607afbead86fd9a3a9a8831494aa Mon Sep 17 00:00:00 2001
From: Hans Hagen <pragma@wxs.nl>
Date: Sun, 13 Dec 2009 23:27:00 +0100
Subject: beta 2009.12.13 23:27

---
 context/data/scite/context.properties           |   2 +-
 scripts/context/lua/luatools.lua                | 164 +++++++++-----
 scripts/context/lua/mtx-context.lua             |  44 ++--
 scripts/context/lua/mtx-fonts.lua               |  20 +-
 scripts/context/lua/mtx-server-ctx-fonttest.lua | 244 ++++++++++++---------
 scripts/context/lua/mtx-server-ctx-help.lua     |  64 +++---
 scripts/context/lua/mtx-server-ctx-startup.lua  |  32 +--
 scripts/context/lua/mtx-timing.lua              |  41 ++--
 scripts/context/lua/mtx-tools.lua               |  89 +++++++-
 scripts/context/lua/mtx-update.lua              |   6 +-
 scripts/context/lua/mtx-watch.lua               | 266 ++++++++++++-----------
 scripts/context/lua/mtxrun.lua                  | 272 ++++++++++++++++++------
 scripts/context/stubs/mswin/luatools.lua        | 164 +++++++++-----
 scripts/context/stubs/mswin/mtxrun.lua          | 272 ++++++++++++++++++------
 scripts/context/stubs/unix/luatools             | 164 +++++++++-----
 scripts/context/stubs/unix/mtxrun               | 272 ++++++++++++++++++------
 tex/context/base/attr-ini.mkiv                  |   1 +
 tex/context/base/bibl-tra.mkiv                  |  28 ++-
 tex/context/base/colo-ini.mkiv                  |  19 ++
 tex/context/base/cont-new.mkiv                  |   2 +
 tex/context/base/cont-new.tex                   |   2 +-
 tex/context/base/context-base.lmx               |  67 ++++--
 tex/context/base/context.mkiv                   |   4 +-
 tex/context/base/context.tex                    |   2 +-
 tex/context/base/core-job.mkiv                  |   3 +-
 tex/context/base/data-lua.lua                   |  84 +++++++-
 tex/context/base/data-pre.lua                   |  10 +
 tex/context/base/data-res.lua                   |   9 +-
 tex/context/base/data-tmf.lua                   |   2 +-
 tex/context/base/font-syn.lua                   |  38 +++-
 tex/context/base/grph-inc.lua                   |   1 +
 tex/context/base/l-dir.lua                      |  29 +++
 tex/context/base/l-lpeg.lua                     |   2 +
 tex/context/base/l-os.lua                       | 111 +++++-----
 tex/context/base/l-string.lua                   |  14 ++
 tex/context/base/l-unicode.lua                  |  25 ++-
 tex/context/base/l-xml.lua                      |  12 +-
 tex/context/base/lpdf-ini.mkiv                  |   9 +
 tex/context/base/lxml-mis.lua                   |   2 +-
 tex/context/base/lxml-tex.lua                   |  11 +-
 tex/context/base/math-dim.lua                   |   5 +-
 tex/context/base/node-rul.mkiv                  |  13 +-
 tex/context/base/node-tra.lua                   |  11 +-
 tex/context/base/page-set.mkii                  |   7 +-
 tex/context/base/page-set.mkiv                  |   6 +-
 tex/context/base/spac-hor.mkiv                  |   2 +-
 tex/context/base/strc-pag.mkiv                  |   4 +
 tex/context/base/strc-ref.lua                   |  21 +-
 tex/context/base/strc-ref.mkiv                  |  21 +-
 tex/context/base/syst-ini.tex                   |   4 +-
 tex/context/base/trac-deb.lua                   |  53 ++---
 tex/context/base/trac-lmx.lua                   | 258 +++++++++++++---------
 tex/context/base/trac-tim.lua                   |  58 +++--
 tex/context/base/typo-spa.lua                   |   2 +-
 tex/context/base/verb-eif.mkii                  |   2 +-
 tex/context/base/verb-ini.mkii                  |  25 +--
 tex/context/base/verb-js.mkii                   |   2 +-
 tex/context/base/verb-jv.mkii                   |   2 +-
 tex/context/base/verb-pas.mkii                  |   2 +-
 tex/context/base/verb-raw.mkii                  |   6 +-
 tex/context/base/verb-sql.mkii                  |   2 +-
 tex/context/base/x-dir-05.mkii                  |  51 +++++
 tex/context/base/x-dir-05.mkiv                  |  72 +++++++
 tex/context/interface/cont-cs.xml               |   5 +
 tex/context/interface/cont-de.xml               |   5 +
 tex/context/interface/cont-en.xml               |   5 +
 tex/context/interface/cont-fr.xml               |   5 +
 tex/context/interface/cont-it.xml               |   5 +
 tex/context/interface/cont-nl.xml               |   5 +
 tex/context/interface/cont-pe.xml               |   5 +
 tex/context/interface/cont-ro.xml               |   5 +
 tex/generic/context/luatex-fonts-merged.lua     |  18 +-
 72 files changed, 2216 insertions(+), 1074 deletions(-)
 create mode 100644 tex/context/base/x-dir-05.mkii
 create mode 100644 tex/context/base/x-dir-05.mkiv

diff --git a/context/data/scite/context.properties b/context/data/scite/context.properties
index c75d1227e..13fa079c0 100644
--- a/context/data/scite/context.properties
+++ b/context/data/scite/context.properties
@@ -115,7 +115,7 @@ name.metafun.mptopdf=$(name.context.mtxrun) --script mptopdf
 # if needed one can set MTX_SERVER_ROOT to the root of the documentation
 
 if PLAT_WIN
-    name.context.wwwserver=cmd /c start /min "Context Documentation" $(name.context.mtxrun) --script server --start
+    name.context.wwwserver=cmd /c start /min "Context Documentation" $(name.context.mtxrun) --script server --auto
 
 if PLAT_GTK
     name.context.wwwserver=$(name.context.mtxrun) --script server --start > ~/context-wwwserver.log &
diff --git a/scripts/context/lua/luatools.lua b/scripts/context/lua/luatools.lua
index 6feb7a9c5..06e2a1bfc 100644
--- a/scripts/context/lua/luatools.lua
+++ b/scripts/context/lua/luatools.lua
@@ -233,6 +233,7 @@ end
 local simple_escapes = {
     ["-"] = "%-",
     ["."] = "%.",
+    ["?"] = ".",
     ["*"] = ".*",
 }
 
@@ -295,6 +296,19 @@ function string:striplong() -- strips newlines and leading spaces
     return self
 end
 
+function string:topattern(lowercase,strict)
+    if lowercase then
+        self = self:lower()
+    end
+    self = gsub(self,".",simple_escapes)
+    if self == "" then
+        self = ".*"
+    elseif strict then
+        self = "^" .. self .. "$"
+    end
+    return self
+end
+
 
 end -- of closure
 
@@ -1756,59 +1770,54 @@ os.arch = os.arch or function()
     return a
 end
 
-local platform
+-- no need for function anymore as we have more clever code and helpers now
 
-function os.currentplatform(name,default)
-    if not platform then
-        local name = os.name or os.platform or name -- os.name is built in, os.platform is mine
-        if not name then
-            platform = default or "linux"
-        elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
-            if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
-                platform = "mswin-64"
-            else
-                platform = "mswin"
-            end
+os.platform  = os.name
+os.libsuffix = 'so'
+
+local name = os.name
+
+if name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
+    if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
+        os.platform = "mswin-64"
+    else
+        os.platform = "mswin"
+    end
+    os.libsuffix = 'dll'
+else
+    local architecture = os.arch()
+    if name == "linux" then
+        if find(architecture,"x86_64") then
+            os.platform = "linux-64"
+        elseif find(architecture,"ppc") then
+            os.platform = "linux-ppc"
         else
-            local architecture = os.arch()
-            if name == "linux" then
-                if find(architecture,"x86_64") then
-                    platform = "linux-64"
-                elseif find(architecture,"ppc") then
-                    platform = "linux-ppc"
-                else
-                    platform = "linux"
-                end
-            elseif name == "macosx" then
-                local architecture = os.resultof("echo $HOSTTYPE")
-                if find(architecture,"i386") then
-                    platform = "osx-intel"
-                elseif find(architecture,"x86_64") then
-                    platform = "osx-64"
-                else
-                    platform = "osx-ppc"
-                end
-            elseif name == "sunos" then
-                if find(architecture,"sparc") then
-                    platform = "solaris-sparc"
-                else -- if architecture == 'i86pc'
-                    platform = "solaris-intel"
-                end
-            elseif name == "freebsd" then
-                if find(architecture,"amd64") then
-                    platform = "freebsd-amd64"
-                else
-                    platform = "freebsd"
-                end
-            else
-                platform = default or name
-            end
+            os.platform = "linux"
+        end
+    elseif name == "macosx" then
+        local architecture = os.resultof("echo $HOSTTYPE")
+        if find(architecture,"i386") then
+            os.platform = "osx-intel"
+        elseif find(architecture,"x86_64") then
+            os.platform = "osx-64"
+        else
+            os.platform = "osx-ppc"
         end
-        function os.currentplatform()
-            return platform
+    elseif name == "sunos" then
+        if find(architecture,"sparc") then
+            os.platform = "solaris-sparc"
+        else -- if architecture == 'i86pc'
+            os.platform = "solaris-intel"
         end
+    elseif name == "freebsd" then
+        if find(architecture,"amd64") then
+            os.platform = "freebsd-amd64"
+        else
+            os.platform = "freebsd"
+        end
+    else
+        os.platform = 'linux'
     end
-    return platform
 end
 
 -- beware, we set the randomseed
@@ -2343,6 +2352,35 @@ end
 
 dir.glob_pattern = glob_pattern
 
+local function collect_pattern(path,patt,recurse,result)
+    local ok, scanner
+    result = result or { }
+    if path == "/" then
+        ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
+    else
+        ok, scanner = xpcall(function() return walkdir(path)      end, function() end) -- kepler safe
+    end
+    if ok and type(scanner) == "function" then
+        if not find(path,"/$") then path = path .. '/' end
+        for name in scanner do
+            local full = path .. name
+            local attr = attributes(full)
+            local mode = attr.mode
+            if mode == 'file' then
+                if find(full,patt) then
+                    result[name] = attr
+                end
+            elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
+                attr.list = collect_pattern(full,patt,recurse)
+                result[name] = attr
+            end
+        end
+    end
+    return result
+end
+
+dir.collect_pattern = collect_pattern
+
 local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
 
 local pattern = Ct {
@@ -3166,9 +3204,9 @@ function aux.settings_to_hash_strict(str,existing)
     end
 end
 
-local seperator = comma * space^0
+local separator = comma * space^0
 local value     = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0)
-local pattern   = lpeg.Ct(value*(seperator*value)^0)
+local pattern   = lpeg.Ct(value*(separator*value)^0)
 
 -- "aap, {noot}, mies" : outer {} removes, leading spaces ignored
 
@@ -3187,7 +3225,7 @@ local function set(t,v)
 end
 
 local value   = lpeg.P(lpeg.Carg(1)*value) / set
-local pattern = value*(seperator*value)^0 * lpeg.Carg(1)
+local pattern = value*(separator*value)^0 * lpeg.Carg(1)
 
 function aux.add_settings_to_array(t,str)
     return pattern:match(str, nil, t)
@@ -3238,6 +3276,13 @@ function aux.settings_to_set(str,t)
     return t
 end
 
+local value     = lbrace * lpeg.C((nobrace + nested)^0) * rbrace
+local pattern   = lpeg.Ct((space + value)^0)
+
+function aux.arguments_to_table(str)
+    return pattern:match(str)
+end
+
 -- temporary here
 
 function aux.getparameters(self,class,parentclass,settings)
@@ -4068,7 +4113,7 @@ end -- of closure
 
 do -- create closure to overcome 200 locals limit
 
-if not modules then modules = { } end modules ['luat-log'] = {
+if not modules then modules = { } end modules ['trac-log'] = {
     version   = 1.001,
     comment   = "companion to trac-log.mkiv",
     author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
@@ -4345,8 +4390,12 @@ end
 
 logs.simpleline = logs.reportline
 
-function logs.help(message,option)
+function logs.reportbanner() -- for scripts too
     logs.report(banner)
+end
+
+function logs.help(message,option)
+    logs.reportbanner()
     logs.reportline()
     logs.reportlines(message)
     local moreinfo = logs.moreinfo or ""
@@ -4509,6 +4558,11 @@ formats     ['sfd']                      = 'SFDFONTS'
 suffixes    ['sfd']                      = { 'sfd' }
 alternatives['subfont definition files'] = 'sfd'
 
+-- lib paths
+
+formats ['lib'] = 'CLUAINPUTS' -- new (needs checking)
+suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' }
+
 -- In practice we will work within one tds tree, but i want to keep
 -- the option open to build tools that look at multiple trees, which is
 -- why we keep the tree specific data in a table. We used to pass the
@@ -5728,9 +5782,9 @@ end
 function resolvers.expanded_path_list_from_var(str) -- brrr
     local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$",""))
     if tmp ~= "" then
-        return resolvers.expanded_path_list(str)
-    else
         return resolvers.expanded_path_list(tmp)
+    else
+        return resolvers.expanded_path_list(str)
     end
 end
 
diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua
index 40ab67eff..9ce164ab3 100644
--- a/scripts/context/lua/mtx-context.lua
+++ b/scripts/context/lua/mtx-context.lua
@@ -1390,27 +1390,36 @@ logs.extendbanner("ConTeXt Process Management 0.51",true)
 messages.help = [[
 --run                 process (one or more) files (default action)
 --make                create context formats
---generate            generate file database etc.
---ctx=name            use ctx file
---version             report installed context version
+
+--ctx=name            use ctx file (process management specification)
+--interface           use specified user interface (default: en)
+
+--autopdf             close pdf file in viewer and start pdf viewer afterwards
+--purge(all)          purge files either or not after a run (--pattern=...)
+
+--usemodule=list      load the given module or style, normally part o fthe distribution
+--environment=list    load the given environment file first (document styles)
+--mode=list           enable given the modes (conditional processing in styles)
+--path=list           also consult the given paths when files are looked for
+--arguments=list      set variables that can be consulted during a run (key/value pairs)
+--randomseed=number   set the randomseed
+--result=name         rename the resulting output to the given name
+--trackers=list       show/set tracker variables
+--directives=list     show/set directive variables
+
 --forcexml            force xml stub (optional flag: --mkii)
 --forcecld            force cld (context lua document) stub
---autopdf             close pdf file in viewer and start pdf viewer afterwards
---once                only one run
---purge(all)          purge files (--pattern=...)
---result=name         rename result to given name
---arrange             run extra arrange pass
---noarrange           ignore arrange commands in the file
+
+--arrange             run extra imposition pass, given that the style sets up imposition
+--noarrange           ignore imposition specifications in the style
+
+--once                only run once (no multipass data file is produced)
 --batchmode           run without stopping and don't show messages on the console
 --nonstopmode         run without stopping
---usemodule=list      load the given module (or style)
---environment=list    load the given file first
---mode=list           enable given the mode(s)
---path=list           also consult the given paths when files are looked for
+
+--generate            generate file database etc. (as luatools does)
 --paranoid            don't descend to .. and ../..
---randomseed=number   set the randomseed
---arguments=list      set variables that can be consulted during a run (key/value pairs)
---interface           use specified user interface
+--version             report installed context version
 
 --expert              expert options
 ]]
@@ -1430,11 +1439,8 @@ expert options:
 --nostats             omit runtime statistics at the end of the run
 --update              update context from website (not to be confused with contextgarden)
 --profile             profile job (use: mtxrun --script profile --analyse)
---trackers            show/set tracker variables
---directives          show/set directive variables
 --timing              generate timing and statistics overview
 --tracefiles          show some extra info when locating files (at the tex end)
---randomseed
 
 --extra=name          process extra (mtx-context-<name> in distribution)
 --extras              show extras
diff --git a/scripts/context/lua/mtx-fonts.lua b/scripts/context/lua/mtx-fonts.lua
index bc93eaaa9..03c3eb068 100644
--- a/scripts/context/lua/mtx-fonts.lua
+++ b/scripts/context/lua/mtx-fonts.lua
@@ -96,20 +96,6 @@ local function showfeatures(tag,specification)
     logs.reportline()
 end
 
-local function make_pattern(pattern) -- will become helper in string
-    pattern = pattern:lower()
-    pattern = pattern:gsub("%-","%%-")
-    pattern = pattern:gsub("%.","%%.")
-    pattern = pattern:gsub("%*",".*")
-    pattern = pattern:gsub("%?",".?")
-    if pattern == "" then
-        pattern = ".*"
-    else
---~         pattern = "^" .. pattern .. "$"
-    end
-    return pattern
-end
-
 local function reloadbase(reload)
     if reload then
         logs.simple("fontnames, reloading font database")
@@ -195,7 +181,7 @@ function scripts.fonts.list()
     if environment.argument("name") then
         if pattern then
             --~ mtxrun --script font --list --name --pattern=*somename*
-            list_matches(fonts.names.list(make_pattern(pattern),reload,all))
+            list_matches(fonts.names.list(string.topattern(pattern,true),reload,all))
         elseif filter then
             logs.report("fontnames","not supported: --list --name --filter",name)
         elseif given then
@@ -220,7 +206,7 @@ function scripts.fonts.list()
     elseif environment.argument("file") then
         if pattern then
             --~ mtxrun --script font --list --file --pattern=*somename*
-            list_specifications(fonts.names.collectfiles(make_pattern(pattern),reload,all))
+            list_specifications(fonts.names.collectfiles(string.topattern(pattern,true),reload,all))
         elseif filter then
             logs.report("fontnames","not supported: --list --spec",name)
         elseif given then
@@ -231,7 +217,7 @@ function scripts.fonts.list()
         end
     elseif pattern then
         --~ mtxrun --script font --list --pattern=*somename*
-        list_matches(fonts.names.list(make_pattern(pattern),reload,all))
+        list_matches(fonts.names.list(string.topattern(pattern,true),reload,all))
     elseif given then
         --~ mtxrun --script font --list somename
         list_matches(fonts.names.list(given,reload,all))
diff --git a/scripts/context/lua/mtx-server-ctx-fonttest.lua b/scripts/context/lua/mtx-server-ctx-fonttest.lua
index f3a5d7690..23a3b5d11 100644
--- a/scripts/context/lua/mtx-server-ctx-fonttest.lua
+++ b/scripts/context/lua/mtx-server-ctx-fonttest.lua
@@ -147,9 +147,10 @@ local cache = { }
 
 local function showfeatures(f)
     if f then
+        logs.simple("processing font '%s'",f)
         local features = cache[f]
         if features == nil then
-            features = fonts.get_features(f)
+            features = fonts.get_features(resolvers.find_file(f))
             if not features then
                 logs.simple("building cache for '%s'",f)
                 io.savedata(file.join(temppath,file.addsuffix(tempname,"tex")),format(process_templates.cache,f,f))
@@ -217,25 +218,50 @@ local function showfeatures(f)
     end
 end
 
+local template_h = [[
+<tr>
+    <th>safe name&nbsp;&nbsp;&nbsp;&nbsp;</th>
+    <th>family name&nbsp;&nbsp;&nbsp;&nbsp;</th>
+    <th>style-variant-weight-width&nbsp;&nbsp;&nbsp;&nbsp;</th>
+    <th>font name&nbsp;&nbsp;&nbsp;&nbsp;</th>
+    <th>weight&nbsp;&nbsp;&nbsp;&nbsp;</th>
+    <th>filename</th>
+</tr>]]
+
+local template_d = [[
+<tr>
+    <td><a href='mtx-server-ctx-fonttest.lua?selection=%s'>%s</a>&nbsp;&nbsp;&nbsp;&nbsp;</td>
+    <td>%s&nbsp;&nbsp;&nbsp;&nbsp;</td>
+    <td>%s-%s-%s-%s&nbsp;&nbsp;&nbsp;&nbsp;</td>
+    <td>%s&nbsp;&nbsp;&nbsp;&nbsp;</td>
+    <td>%s&nbsp;&nbsp;&nbsp;&nbsp;</td>
+    <td>%s</td>
+</tr>]]
+
 local function select_font()
-    local t = fonts.names.list(".*")
+    local t = fonts.names.list(".*",false,true)
     if t then
         local listoffonts = { }
-        local t = fonts.names.list(".*")
-        if t then
-            listoffonts[#listoffonts+1] = "<table>"
-            listoffonts[#listoffonts+1] = "<tr><th>safe name</th><th>font name</th><th>filename</th><th>sub font&nbsp;</th><th>type</th></tr>"
-            for k, id in ipairs(table.sortedkeys(t)) do
-                local ti = t[id]
-                local type, name, file, sub = ti[1], ti[2], ti[3], ti[4]
-                if type == "otf" or  type == "ttf" or  type == "ttc" then
-                    if sub then sub = "(sub)" else sub = "" end
-                    listoffonts[#listoffonts+1] = format("<tr><td><a href='mtx-server-ctx-fonttest.lua?selection=%s'>%s</a></td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>",id,id,name,file,sub,type)
-                end
+        listoffonts[#listoffonts+1] = "<table>"
+        listoffonts[#listoffonts+1] = template_h
+        for k, v in table.sortedpairs(t) do
+            local kind = v.format
+            if kind == "otf" or kind == "ttf" or kind == "ttc" then
+                local fontname = v.fontname
+                listoffonts[#listoffonts+1] = format(template_d, fontname, fontname,
+                    v.familyname or "",
+                    t.variant    or "normal",
+                    t.weight     or "normal",
+                    t.width      or "normal",
+                    t.style      or "normal",
+                    v.rawname    or fontname,
+                    v.fontweight or "",
+                    v.filename   or ""
+                )
             end
-            listoffonts[#listoffonts+1] = "</table>"
-            return concat(listoffonts,"\n")
         end
+        listoffonts[#listoffonts+1] = "</table>"
+        return concat(listoffonts,"\n")
     end
     return "<b>no fonts</b>"
 end
@@ -260,59 +286,67 @@ local result_template = [[
 
 scripts.webserver.registerpath(temppath)
 
+local function get_specification(name)
+    return fonts.names.resolvedspecification(name or "")
+end
+
 local function edit_font(currentfont,detail,tempname)
-    local fontname, fontfile, issub = fonts.names.specification(currentfont or "")
-    local htmldata = showfeatures(fontfile)
-    if htmldata then
-        local features, languages, scripts, options = { }, { }, { }, { }
-        for k,v in ipairs(table.sortedkeys(htmldata.scripts)) do
-            local s = fonts.otf.tables.scripts[v] or v
-            if detail and v == detail.script then
-                scripts[#scripts+1] = format("<input title='%s' id='s-%s' type='radio' name='script' value='%s' onclick='check_script()' checked='checked'/>&nbsp;<span id='t-s-%s'>%s</span>",s,v,v,v,v)
-            else
-                scripts[#scripts+1] = format("<input title='%s' id='s-%s' type='radio' name='script' value='%s' onclick='check_script()' />&nbsp;<span id='t-s-%s'>%s</span>",s,v,v,v,v)
+    logs.simple("entering edit mode for '%s'",currentfont)
+    local specification = get_specification(currentfont)
+    if specification then
+        local htmldata = showfeatures(specification.filename)
+        if htmldata then
+            local features, languages, scripts, options = { }, { }, { }, { }
+            for k,v in ipairs(table.sortedkeys(htmldata.scripts)) do
+                local s = fonts.otf.tables.scripts[v] or v
+                if detail and v == detail.script then
+                    scripts[#scripts+1] = format("<input title='%s' id='s-%s' type='radio' name='script' value='%s' onclick='check_script()' checked='checked'/>&nbsp;<span id='t-s-%s'>%s</span>",s,v,v,v,v)
+                else
+                    scripts[#scripts+1] = format("<input title='%s' id='s-%s' type='radio' name='script' value='%s' onclick='check_script()' />&nbsp;<span id='t-s-%s'>%s</span>",s,v,v,v,v)
+                end
             end
-        end
-        for k,v in ipairs(table.sortedkeys(htmldata.languages)) do
-            local l = fonts.otf.tables.languages[v] or v
-            if detail and v == detail.language then
-                languages[#languages+1] = format("<input title='%s' id='l-%s' type='radio' name='language' value='%s' onclick='check_language()' checked='checked'/>&nbsp;<span id='t-l-%s'>%s</span>",l,v,v,v,v)
-            else
-                languages[#languages+1] = format("<input title='%s' id='l-%s' type='radio' name='language' value='%s' onclick='check_language()' />&nbsp;<span id='t-l-%s'>%s</span>",l,v,v,v,v)
+            for k,v in ipairs(table.sortedkeys(htmldata.languages)) do
+                local l = fonts.otf.tables.languages[v] or v
+                if detail and v == detail.language then
+                    languages[#languages+1] = format("<input title='%s' id='l-%s' type='radio' name='language' value='%s' onclick='check_language()' checked='checked'/>&nbsp;<span id='t-l-%s'>%s</span>",l,v,v,v,v)
+                else
+                    languages[#languages+1] = format("<input title='%s' id='l-%s' type='radio' name='language' value='%s' onclick='check_language()' />&nbsp;<span id='t-l-%s'>%s</span>",l,v,v,v,v)
+                end
             end
-        end
-        for k,v in ipairs(table.sortedkeys(htmldata.features)) do
-            local f = fonts.otf.tables.features[v] or v
-            if detail and detail["f-"..v] then
-                features[#features+1] = format("<input title='%s' id='f-%s' type='checkbox' name='f-%s' onclick='check_feature()' checked='checked'/>&nbsp;<span id='t-f-%s'>%s</span>",f,v,v,v,v)
-            else
-                features[#features+1] = format("<input title='%s' id='f-%s' type='checkbox' name='f-%s' onclick='check_feature()' />&nbsp;<span id='t-f-%s'>%s</span>",f,v,v,v,v)
+            for k,v in ipairs(table.sortedkeys(htmldata.features)) do
+                local f = fonts.otf.tables.features[v] or v
+                if detail and detail["f-"..v] then
+                    features[#features+1] = format("<input title='%s' id='f-%s' type='checkbox' name='f-%s' onclick='check_feature()' checked='checked'/>&nbsp;<span id='t-f-%s'>%s</span>",f,v,v,v,v)
+                else
+                    features[#features+1] = format("<input title='%s' id='f-%s' type='checkbox' name='f-%s' onclick='check_feature()' />&nbsp;<span id='t-f-%s'>%s</span>",f,v,v,v,v)
+                end
             end
-        end
-        for k, v in ipairs { "trace", "basemode" } do
-            if detail and detail["o-"..v] then
-                options[#options+1] = format("<input id='o-%s' type='checkbox' name='o-%s' checked='checked'/>&nbsp;%s",v,v,v)
+            for k, v in ipairs { "trace", "basemode" } do
+                if detail and detail["o-"..v] then
+                    options[#options+1] = format("<input id='o-%s' type='checkbox' name='o-%s' checked='checked'/>&nbsp;%s",v,v,v)
+                else
+                    options[#options+1] = format("<input id='o-%s' type='checkbox' name='o-%s'/>&nbsp;%s",v,v,v)
+                end
+            end
+            local e = format(edit_template,
+                (detail and detail.sampletext) or sample_line,(detail and detail.name) or "no name",(detail and detail.title) or "",
+                concat(scripts,"  "),concat(languages,"  "),concat(features,"  "),concat(options,"  "))
+            if tempname then
+                local pdffile, texfile = file.addsuffix(tempname,"pdf"), file.addsuffix(tempname,"tex")
+                local r = format(result_template,pdffile,texfile,pdffile)
+                return e .. r, htmldata.javascript or ""
             else
-                options[#options+1] = format("<input id='o-%s' type='checkbox' name='o-%s'/>&nbsp;%s",v,v,v)
+                return e, htmldata.javascript or ""
             end
-        end
-        local e = format(edit_template,
-            (detail and detail.sampletext) or sample_line,(detail and detail.name) or "no name",(detail and detail.title) or "",
-            concat(scripts,"  "),concat(languages,"  "),concat(features,"  "),concat(options,"  "))
-        if tempname then
-            local pdffile, texfile = file.addsuffix(tempname,"pdf"), file.addsuffix(tempname,"tex")
-            local r = format(result_template,pdffile,texfile,pdffile)
-            return e .. r, htmldata.javascript or ""
         else
-            return e, htmldata.javascript or ""
+            return "error, nothing set up yet"
         end
     else
-        return "error, nothing set up yet"
+        return "error, no info about font"
     end
 end
 
 local function process_font(currentfont,detail) -- maybe just fontname
-    local fontname, fontfile, issub = fonts.names.specification(currentfont or "")
     local features = {
         "mode=node",
         format("language=%s",detail.language or "dflt"),
@@ -361,14 +395,27 @@ local function show_log(currentfont,detail)
 end
 
 local function show_font(currentfont,detail)
-    local fontname, fontfile, issub = fonts.names.specification(currentfont or "")
-    local features = fonts.get_features(fontfile)
+    local specification = get_specification(currentfont)
+    local features = fonts.get_features(specification.filename)
     local result = { }
     result[#result+1] = format("<h1>names</h1>",what)
     result[#result+1] = "<table>"
-    result[#result+1] = format("<tr><td class='tc'>fontname:</td><td>%s</td></tr>",currentfont)
-    result[#result+1] = format("<tr><td class='tc'>fullname:</td><td>%s</td></tr>",fontname)
-    result[#result+1] = format("<tr><td class='tc'>filename:</td><td>%s</td></tr>",fontfile)
+    result[#result+1] = format("<tr><td class='tc'>fontname:   </td><td>%s</td></tr>",currentfont)
+    result[#result+1] = format("<tr><td class='tc'>fullname:   </td><td>%s</td></tr>",specification.fontname   or "-")
+    result[#result+1] = format("<tr><td class='tc'>filename:   </td><td>%s</td></tr>",specification.fontfile   or "-")
+    result[#result+1] = format("<tr><td class='tc'>familyname: </td><td>%s</td></tr>",specification.familyname or "-")
+    result[#result+1] = format("<tr><td class='tc'>fontweight: </td><td>%s</td></tr>",specification.fontweight or "-")
+    result[#result+1] = format("<tr><td class='tc'>format:     </td><td>%s</td></tr>",specification.format     or "-")
+    result[#result+1] = format("<tr><td class='tc'>fullname:   </td><td>%s</td></tr>",specification.fullname   or "-")
+    result[#result+1] = format("<tr><td class='tc'>subfamily:  </td><td>%s</td></tr>",specification.subfamily  or "-")
+    result[#result+1] = format("<tr><td class='tc'>rawname:    </td><td>%s</td></tr>",specification.rawname    or "-")
+    result[#result+1] = format("<tr><td class='tc'>designsize: </td><td>%s</td></tr>",specification.designsize or "-")
+    result[#result+1] = format("<tr><td class='tc'>minimumsize:</td><td>%s</td></tr>",specification.minsize    or "-")
+    result[#result+1] = format("<tr><td class='tc'>maximumsize:</td><td>%s</td></tr>",specification.maxsize    or "-")
+    result[#result+1] = format("<tr><td class='tc'>style:      </td><td>%s</td></tr>",specification.style   ~= "" and specification.style or "normal")
+    result[#result+1] = format("<tr><td class='tc'>variant:    </td><td>%s</td></tr>",specification.variant ~= "" and specification.variant    or "normal")
+    result[#result+1] = format("<tr><td class='tc'>weight:     </td><td>%s</td></tr>",specification.weight  ~= "" and specification.weight     or "normal")
+    result[#result+1] = format("<tr><td class='tc'>width:      </td><td>%s</td></tr>",specification.width   ~= "" and specification.width      or "normal")
     result[#result+1] = "</table>"
     if features then
         for what, v in table.sortedpairs(features) do
@@ -486,10 +533,10 @@ local function deletestored(detail,currentfont,name)
 end
 
 local function save_font(currentfont,detail)
-    local fontname, fontfile, issub = fonts.names.specification(currentfont or "")
+    local specification = get_specification(currentfont)
     local name, title, script, language, features, options, text = currentfont, "", "dflt", "dflt", { }, { }, ""
     if detail then
-        local htmldata = showfeatures(fontfile)
+        local htmldata = showfeatures(specification.filename)
         script = detail.script or script
         language = detail.language or language
         text = string.strip(detail.sampletext or text)
@@ -519,7 +566,7 @@ local function load_font(currentfont)
     local result = {}
     result[#result+1] = format("<tr><th>del&nbsp;</th><th>name&nbsp;</th><th>font&nbsp;</th><th>fontname&nbsp;</th><th>script&nbsp;</th><th>language&nbsp;</th><th>features&nbsp;</th><th>title&nbsp;</th><th>sampletext&nbsp;</th></tr>")
     for k,v in table.sortedpairs(storage) do
-        local fontname, fontfile, issub = fonts.names.specification(v.font or "")
+        local fontname, fontfile = get_specification(v.font)
         result[#result+1] = format("<tr><td><a href='mtx-server-ctx-fonttest.lua?deletename=%s'>x</a>&nbsp;</td><td><a href='mtx-server-ctx-fonttest.lua?loadname=%s'>%s</a>&nbsp;</td><td>%s&nbsp;</td<td>%s&nbsp;</td><td>%s&nbsp;</td><td>%s&nbsp;</td><td>%s&nbsp;</td><td>%s&nbsp;</td><td>%s&nbsp;</td></tr>",
             k,k,k,v.font,fontname,v.script,v.language,concat(table.sortedkeys(v.features)," "),v.title or "no title",v.text or "")
     end
@@ -562,6 +609,13 @@ local status_template = [[
     <input type="hidden" name="currentfont" value="%s" />
 ]]
 
+local variables = {
+    ['color-background-one'] = lmx.get('color-background-green'),
+    ['color-background-two'] = lmx.get('color-background-blue'),
+    ['title']                = 'ConTeXt Font Tester',
+    ['formaction']           = "mtx-server-ctx-fonttest.lua",
+}
+
 function doit(configuration,filename,hashed)
 
     local start = os.clock()
@@ -589,65 +643,49 @@ function doit(configuration,filename,hashed)
         action = "extras"
     end
 
-    lmx.restore()
-
-    local fontname, fontfile, issub = fonts.names.specification(currentfont or "")
+    local fontname, fontfile = get_specification(currentfont)
 
     if fontfile then
-        lmx.variables['title-default'] = format('ConTeXt Font Tester: %s (%s)',fontname,fontfile)
+        variables.title = format('ConTeXt Font Tester: %s (%s)',fontname,fontfile)
     else
-        lmx.variables['title-default'] = 'ConTeXt Font Tester'
+        variables.title = 'ConTeXt Font Tester'
     end
 
-    lmx.variables['color-background-green']  = '#4F6F6F'
-    lmx.variables['color-background-blue']   = '#6F6F8F'
-    lmx.variables['color-background-yellow'] = '#8F8F6F'
-    lmx.variables['color-background-purple'] = '#8F6F8F'
-
-    lmx.variables['color-background-body']   = '#808080'
-    lmx.variables['color-background-main']   = '#3F3F3F'
-    lmx.variables['color-background-one']    = lmx.variables['color-background-green']
-    lmx.variables['color-background-two']    = lmx.variables['color-background-blue']
-
-    lmx.variables['title']                   = lmx.variables['title-default']
-
-    lmx.set('title',                lmx.get('title'))
-    lmx.set('color-background-one', lmx.get('color-background-green'))
-    lmx.set('color-background-two', lmx.get('color-background-blue'))
-
     -- lua table and adapt
 
-    lmx.set('formaction', "mtx-server-ctx-fonttest.lua")
-
     local menu = { }
     for k, v in ipairs { 'process', 'select', 'save', 'load', 'edit', 'reset', 'features', 'source', 'log', 'info', 'extras'} do
         menu[#menu+1] = format("<button name='action' value='%s' type='submit'>%s</button>",v,v)
     end
-    lmx.set('menu', concat(menu,"&nbsp;"))
 
-    logs.simple("action: %s",action or "no action")
+    variables.menu           = concat(menu,"&nbsp;")
+    variables.status         = format(status_template,currentfont or "")
+    variables.maintext       = ""
+    variables.javascriptdata = ""
+    variables.javascripts    = ""
+    variables.javascriptinit = ""
 
-    lmx.set("status",format(status_template,currentfont or ""))
+    logs.simple("action: %s",action or "no action")
 
     local result
 
     if action == "select" then
-        lmx.set('maintext',select_font())
+        variables.maintext = select_font()
     elseif action == "info" then
-        lmx.set('maintext',info_about())
+        variables.maintext = info_about()
     elseif action == "extras" then
-        lmx.set('maintext',do_extras())
+        variables.maintext = do_extras()
     elseif currentfont and currentfont ~= "" then
         if action == "save" then
-            lmx.set('maintext',save_font(currentfont,detail))
+            variables.maintext = save_font(currentfont,detail)
         elseif action == "load" then
-            lmx.set('maintext',load_font(currentfont,detail))
+            variables.maintext = load_font(currentfont,detail)
         elseif action == "source" then
-            lmx.set('maintext',show_source(currentfont,detail))
+            variables.maintext = show_source(currentfont,detail)
         elseif action == "log" then
-            lmx.set('maintext',show_log(currentfont,detail))
+            variables.maintext = show_log(currentfont,detail)
         elseif action == "features" then
-            lmx.set('maintext',show_font(currentfont,detail))
+            variables.maintext = show_font(currentfont,detail)
         else
             local e, s
             if action == "process" then
@@ -659,16 +697,16 @@ function doit(configuration,filename,hashed)
             else
                 e, s = process_font(currentfont,detail)
             end
-            lmx.set('maintext',e)
-            lmx.set('javascriptdata',s)
-            lmx.set('javascripts',javascripts)
-            lmx.set('javascriptinit', "check_form()")
+            variables.maintext       = e
+            variables.javascriptdata = s
+            variables.javascripts    = javascripts
+            variables.javascriptinit = "check_form()"
         end
     else
-        lmx.set('maintext',select_font())
+        variables.maintext = select_font()
     end
 
-    result = { content = lmx.convert('context-fonttest.lmx') }
+    result = { content = lmx.convert('context-fonttest.lmx',false,variables) }
 
     logs.simple("time spent on page: %0.03f seconds",os.clock()-start)
 
diff --git a/scripts/context/lua/mtx-server-ctx-help.lua b/scripts/context/lua/mtx-server-ctx-help.lua
index d77cc66e8..b6c97118b 100644
--- a/scripts/context/lua/mtx-server-ctx-help.lua
+++ b/scripts/context/lua/mtx-server-ctx-help.lua
@@ -548,25 +548,6 @@ end
 
 tex = tex or { }
 
-lmx.variables['color-background-green']      = '#4F6F6F'
-lmx.variables['color-background-blue']       = '#6F6F8F'
-lmx.variables['color-background-yellow']     = '#8F8F6F'
-lmx.variables['color-background-purple']     = '#8F6F8F'
-
-lmx.variables['color-background-body']       = '#808080'
-lmx.variables['color-background-main']       = '#3F3F3F'
-lmx.variables['color-background-main-left']  = '#3F3F3F'
-lmx.variables['color-background-main-right'] = '#5F5F5F'
-lmx.variables['color-background-one']        = lmx.variables['color-background-green']
-lmx.variables['color-background-two']        = lmx.variables['color-background-blue']
-
-lmx.variables['title-default']               = 'ConTeXt Help Information'
-lmx.variables['title']                       = lmx.variables['title-default']
-
-function lmx.loadedfile(filename)
-    return io.loaddata(resolvers.find_file(filename)) -- return resolvers.texdatablob(filename)
-end
-
 -- -- --
 
 local interfaces = {
@@ -582,6 +563,18 @@ local interfaces = {
 
 local lastinterface, lastcommand, lastsource, lastmode = "en", "", "", 1
 
+local variables = {
+    ['color-background-main-left']  = '#3F3F3F',
+    ['color-background-main-right'] = '#5F5F5F',
+    ['color-background-one']        = lmx.get('color-background-green'),
+    ['color-background-two']        = lmx.get('color-background-blue'),
+    ['title']                       = 'ConTeXt Help Information',
+}
+
+--~ function lmx.loadedfile(filename)
+--~     return io.loaddata(resolvers.find_file(filename)) -- return resolvers.texdatablob(filename)
+--~ end
+
 local function doit(configuration,filename,hashed)
 
     local formats = document.setups.formats
@@ -615,34 +608,32 @@ local function doit(configuration,filename,hashed)
         end
     end
 
-    lmx.restore()
-    lmx.set('title', 'ConTeXt Help Information')
-    lmx.set('color-background-one', lmx.get('color-background-green'))
-    lmx.set('color-background-two', lmx.get('color-background-blue'))
-
     local n = concat(refs,"<br/>")
     local i = concat(ints,"<br/><br/>")
 
     if div then
-        lmx.set('names',div:format(n))
-        lmx.set('interfaces',div:format(i))
+        variables.names      = div:format(n)
+        variables.interfaces = div:format(i)
     else
-        lmx.set('names', n)
-        lmx.set('interfaces', i)
+        variables.names      = n
+        variables.interfaces = i
     end
 
     -- first we need to add information about mkii/mkiv
 
+    variables.maintitle = "no definition"
+    variables.maintext  = ""
+    variables.extra     = ""
+
     if document.setups.showsources and lastsource and lastsource ~= "" then
         -- todo: mkii, mkiv, tex (can be different)
         local data = io.loaddata(resolvers.find_file(lastsource))
-        lmx.set('maintitle', lastsource)
-        lmx.set('maintext', formats.listing:format(data))
+        variables.maintitle = lastsource
+        variables.maintext  = formats.listing:format(data)
         lastsource = ""
     elseif lastcommand and lastcommand ~= "" then
         local data = document.setups.collect(lastcommand,lastinterface,lastmode)
         if data then
-            lmx.set('maintitle', data.sequence)
             local extra = { }
             for k, v in ipairs { "environment", "category", "source", "mode" } do
                 if data[v] and data[v] ~= "" then
@@ -650,16 +641,15 @@ local function doit(configuration,filename,hashed)
                     extra[#extra+1] = v .. ": " .. data[v]
                 end
             end
-            lmx.set('extra', concat(extra,"&nbsp;&nbsp;&nbsp;"))
-            lmx.set('maintext', formats.parameters:format(concat(data.parameters)))
+            variables.maintitle = data.sequence
+            variables.maintext  = formats.parameters:format(concat(data.parameters))
+            variables.extra     = concat(extra,"&nbsp;&nbsp;&nbsp;")
         else
-            lmx.set('maintext', "select command")
+            variables.maintext = "select command"
         end
-    else
-        lmx.set('maintext', "no definition")
     end
 
-    local content = lmx.convert('context-help.lmx')
+    local content = lmx.convert('context-help.lmx',false,variables)
 
     logs.simple("time spent on page: %0.03f seconds",os.clock()-start)
 
diff --git a/scripts/context/lua/mtx-server-ctx-startup.lua b/scripts/context/lua/mtx-server-ctx-startup.lua
index fcb757b3e..59536c36c 100644
--- a/scripts/context/lua/mtx-server-ctx-startup.lua
+++ b/scripts/context/lua/mtx-server-ctx-startup.lua
@@ -10,25 +10,6 @@ dofile(resolvers.find_file("trac-lmx.lua","tex"))
 
 function doit(configuration,filename,hashed)
 
-    lmx.restore()
-
-    lmx.variables['color-background-green']  = '#4F6F6F'
-    lmx.variables['color-background-blue']   = '#6F6F8F'
-    lmx.variables['color-background-yellow'] = '#8F8F6F'
-    lmx.variables['color-background-purple'] = '#8F6F8F'
-
-    lmx.variables['color-background-body']   = '#808080'
-    lmx.variables['color-background-main']   = '#3F3F3F'
-    lmx.variables['color-background-one']    = lmx.variables['color-background-green']
-    lmx.variables['color-background-two']    = lmx.variables['color-background-blue']
-
-    lmx.variables['title']                   = "Overview Of Goodies"
-
-    lmx.set('title',                lmx.get('title'))
-    lmx.set('color-background-one', lmx.get('color-background-green'))
-    lmx.set('color-background-two', lmx.get('color-background-blue'))
-
-
     local list = { }
     local root = file.dirname(resolvers.find_file("mtx-server.lua") or ".")
     if root == "" then root = "." end
@@ -42,11 +23,16 @@ function doit(configuration,filename,hashed)
         end
     end
 
-    lmx.set('maintext',table.concat(list,"\n"))
-
-    result = { content = lmx.convert('context-base.lmx') }
+    local variables = {
+        ['color-background-one']    = lmx.get('color-background-green'),
+        ['color-background-two']    = lmx.get('color-background-blue'),
+        ['title']                   = "Overview Of Goodies",
+        ['color-background-one']    = lmx.get('color-background-green'),
+        ['color-background-two']    = lmx.get('color-background-blue'),
+        ['maintext']                = table.concat(list,"\n"),
+    }
 
-    return result
+    return  { content = lmx.convert('context-base.lmx',false,variables) }
 
 end
 
diff --git a/scripts/context/lua/mtx-timing.lua b/scripts/context/lua/mtx-timing.lua
index 375d5d90b..a9a0c8745 100644
--- a/scripts/context/lua/mtx-timing.lua
+++ b/scripts/context/lua/mtx-timing.lua
@@ -124,50 +124,39 @@ function goodies.progress.valid_file(name)
 end
 
 function goodies.progress.make_lmx_page(name,launch,remove)
+
     local filename = name .. "-luatex-progress"
     local other    = "elapsed_time"
     local template = 'context-timing.lmx'
 
-    lmx.variables['color-background-green']  = '#4F6F6F'
-    lmx.variables['color-background-blue']   = '#6F6F8F'
-    lmx.variables['color-background-yellow'] = '#8F8F6F'
-    lmx.variables['color-background-purple'] = '#8F6F8F'
-
-    lmx.variables['color-background-body']   = '#808080'
-    lmx.variables['color-background-main']   = '#3F3F3F'
-    lmx.variables['color-background-one']    = lmx.variables['color-background-green']
-    lmx.variables['color-background-two']    = lmx.variables['color-background-blue']
-
-    lmx.variables['title-default']           = 'ConTeXt Timing Information'
-    lmx.variables['title']                   = lmx.variables['title-default']
-
-    lmx.htmfile = function(name) return name .. "-timing.xhtml" end
-    lmx.lmxfile = function(name) return resolvers.find_file(name,'tex') end
-
-    lmx.set('title', format('ConTeXt Timing Information: %s',file.basename(name)))
-    lmx.set('color-background-one', lmx.get('color-background-green'))
-    lmx.set('color-background-two', lmx.get('color-background-blue'))
-
     goodies.progress.convert(filename)
 
     local menudata, metadata = goodies.progress.make_svg(filename,other)
     local htmldata = goodies.progress.makehtml(filename,other,menudata,metadata)
 
-    lmx.set('parametersmenu', concat(htmldata.parameters, "&nbsp;&nbsp;"))
-    lmx.set('nodesmenu',      concat(htmldata.nodes,      "&nbsp;&nbsp;"))
-    lmx.set('graphics',       concat(htmldata.graphics,   "\n\n"))
+    lmx.htmfile = function(name) return name .. "-timing.xhtml" end
+    lmx.lmxfile = function(name) return resolvers.find_file(name,'tex') end
+
+    local variables = {
+        ['title-default']        = 'ConTeXt Timing Information',
+        ['title']                = format('ConTeXt Timing Information: %s',file.basename(name)),
+        ['parametersmenu']       = concat(htmldata.parameters, "&nbsp;&nbsp;"),
+        ['nodesmenu']            = concat(htmldata.nodes, "&nbsp;&nbsp;"),
+        ['graphics']             = concat(htmldata.graphics, "\n\n"),
+        ['color-background-one'] = lmx.get('color-background-green'),
+        ['color-background-two'] = lmx.get('color-background-blue'),
+    }
 
     if launch then
-        local htmfile = lmx.show(template)
+        local htmfile = lmx.show(template,variables)
         if remove then
             os.sleep(1) -- give time to launch
             os.remove(htmfile)
         end
     else
-        lmx.make(template)
+        lmx.make(template,variables)
     end
 
-    lmx.restore()
 end
 
 scripts         = scripts         or { }
diff --git a/scripts/context/lua/mtx-tools.lua b/scripts/context/lua/mtx-tools.lua
index ca2faaf29..5c90df071 100644
--- a/scripts/context/lua/mtx-tools.lua
+++ b/scripts/context/lua/mtx-tools.lua
@@ -6,9 +6,7 @@ if not modules then modules = { } end modules ['mtx-tools'] = {
     license   = "see context related readme files"
 }
 
--- data tables by Thomas A. Schmitz
-
-local find, gsub = string.find, string.gsub
+local find, format, sub, rep, gsub = string.find, string.format, string.sub, string.rep, string.gsub
 
 scripts       = scripts       or { }
 scripts.tools = scripts.tools or { }
@@ -44,14 +42,97 @@ function scripts.tools.disarmutfbomb()
     end
 end
 
-logs.extendbanner("Some File Related Goodies 1.00",true)
+function scripts.tools.dirtoxml()
+
+    local join, removesuffix, extname, date = file.join, file.removesuffix, file.extname, os.date
+
+    local xmlns      = "http://www.pragma-ade.com/rlg/xmldir.rng"
+    local timestamp  = "%Y-%m-%d %H:%M"
+
+    local pattern    = environment.argument('pattern') or ".*"
+    local url        = environment.argument('url')     or "no-url"
+    local root       = environment.argument('root')    or "."
+    local outputfile = environment.argument('output')
+
+    local recurse    = environment.argument('recurse')
+    local stripname  = environment.argument('stripname')
+    local longname   = environment.argument('longname')
+
+    local function flush(list,result,n,path)
+        n, result = n or 1, result or { }
+        local d = rep("  ",n)
+        for name, attr in table.sortedpairs(list) do
+            local mode = attr.mode
+            if mode == "file" then
+                result[#result+1] = format("%s<file name='%s'>",d,(longname and path and join(path,name)) or name)
+                result[#result+1] = format("%s  <base>%s</base>",d,removesuffix(name))
+                result[#result+1] = format("%s  <type>%s</type>",d,extname(name))
+                result[#result+1] = format("%s  <size>%s</size>",d,attr.size)
+                result[#result+1] = format("%s  <permissions>%s</permissions>",d,sub(attr.permissions,7,9))
+                result[#result+1] = format("%s  <date>%s</date>",d,date(timestamp,attr.modification))
+                result[#result+1] = format("%s</file>",d)
+            elseif mode == "directory" then
+                result[#result+1] = format("%s<directory name='%s'>",d,name)
+                flush(attr.list,result,n+1,(path and join(path,name)) or name)
+                result[#result+1] = format("%s</directory>",d)
+            end
+        end
+    end
+
+    if not pattern or pattern == ""  then
+        logs.report('provide --pattern=')
+        return
+    end
+
+    if stripname then
+        pattern = file.dirname(pattern)
+    end
+
+    local luapattern = string.topattern(pattern,true)
+
+    lfs.chdir(root)
+
+    local list = dir.collect_pattern(root,luapattern,recurse)
+
+    if list[outputfile] then
+        list[outputfile] = nil
+    end
+
+    local result = { "<?xml version='1.0'?>" }
+    result[#result+1] = format("<files url=%q root=%q pattern=%q luapattern=%q xmlns='%s' timestamp='%s'>",url,root,pattern,luapattern,xmlns,date(timestamp))
+    flush(list,result)
+    result[#result+1] = "</files>"
+
+    result = table.concat(result,"\n")
+
+    if not outputfile or outputfile == "" then
+        texio.write_nl(result)
+    else
+        io.savedata(outputfile,result)
+    end
+
+end
+
+logs.extendbanner("Some File Related Goodies 1.01",true)
 
 messages.help = [[
 --disarmutfbomb       remove utf bomb if present
+    --force             remove indeed
+
+--dirtoxml              glob directory into xml
+    --pattern           glob pattern (default: .*)
+    --url               url attribute (no processing)
+    --root              the root of the globbed path (default: .)
+    --output            output filename (console by default)
+    --recurse           recurse into subdirecories
+    --stripname         take pathpart of given pattern
+    --longname          set name attributes to full path name
 ]]
 
 if environment.argument("disarmutfbomb") then
     scripts.tools.disarmutfbomb()
+elseif environment.argument("dirtoxml") then
+    scripts.tools.dirtoxml()
 else
     logs.help(messages.help)
 end
diff --git a/scripts/context/lua/mtx-update.lua b/scripts/context/lua/mtx-update.lua
index 61d6b0d84..48df6862a 100644
--- a/scripts/context/lua/mtx-update.lua
+++ b/scripts/context/lua/mtx-update.lua
@@ -195,7 +195,7 @@ function scripts.update.synchronize()
 
     if ok or not force then
 
-        local fetched, individual, osplatform = { }, { }, os.currentplatform()
+        local fetched, individual, osplatform = { }, { }, os.platform
 
         -- takes a collection as argument and returns a list of folders
 
@@ -223,7 +223,7 @@ function scripts.update.synchronize()
             return prefix .. concat(list_of_folders, format(" %s", prefix))
         end
 
-        -- example of usage: print(list_of_folders_to_rsync_string(collection_to_list_of_folders(scripts.update.base, os.currentplatform)))
+        -- example of usage: print(list_of_folders_to_rsync_string(collection_to_list_of_folders(scripts.update.base, os.platform)))
 
         -- rename function and add some more functionality:
         --   * recursive/non-recursive (default: non-recursive)
@@ -507,7 +507,7 @@ if scripts.savestate then
         end
     end
     local valid = scripts.update.platforms
-    for r in gmatch(environment.argument("platform") or os.currentplatform(),"([^, ]+)") do
+    for r in gmatch(environment.argument("platform") or os.platform,"([^, ]+)") do
         if valid[r] then states.set("platforms." .. r, true) end
     end
 
diff --git a/scripts/context/lua/mtx-watch.lua b/scripts/context/lua/mtx-watch.lua
index 44f61ae6b..9cfe2bbfd 100644
--- a/scripts/context/lua/mtx-watch.lua
+++ b/scripts/context/lua/mtx-watch.lua
@@ -9,160 +9,168 @@ if not modules then modules = { } end modules ['mtx-watch'] = {
 scripts       = scripts       or { }
 scripts.watch = scripts.watch or { }
 
-do
-
-    function scripts.watch.save_exa_modes(joblog,ctmname)
-        local t= { }
-        if joblog then
-            t[#t+1] = "<?xml version='1.0' standalone='yes'?>\n"
-            t[#t+1] = "<exa:variables xmlns:exa='htpp://www.pragma-ade.com/schemas/exa-variables.rng'>"
-            if joblog.values then
-                for k, v in pairs(joblog.values) do
-                    t[#t+1] = string.format("\t<exa:variable label='%s'>%s</exa:variable>", k, tostring(v))
-                end
-            else
-                t[#t+1] = "<!-- no modes -->"
+function scripts.watch.save_exa_modes(joblog,ctmname)
+    local t= { }
+    if joblog then
+        t[#t+1] = "<?xml version='1.0' standalone='yes'?>\n"
+        t[#t+1] = "<exa:variables xmlns:exa='htpp://www.pragma-ade.com/schemas/exa-variables.rng'>"
+        if joblog.values then
+            for k, v in pairs(joblog.values) do
+                t[#t+1] = string.format("\t<exa:variable label='%s'>%s</exa:variable>", k, tostring(v))
             end
-            t[#t+1] = "</exa:variables>"
+        else
+            t[#t+1] = "<!-- no modes -->"
         end
-        os.remove(ctmname)
-        io.savedata(ctmname,table.concat(t,"\n"))
+        t[#t+1] = "</exa:variables>"
     end
+    os.remove(ctmname)
+    io.savedata(ctmname,table.concat(t,"\n"))
+end
 
-    function scripts.watch.watch()
-        local delay   = environment.argument("delay")   or 5
-        local logpath = environment.argument("logpath") or ""
-        local pipe    = environment.argument("pipe")    or false
-        if #environment.files > 0 then
-            for _, path in ipairs(environment.files) do
-                logs.report("watch", "watching path ".. path)
-            end
-            local function glob(files,path)
-                for name in lfs.dir(path) do
-                    if name:find("^%.") then
-                        -- skip . and ..
-                    else
-                        name = path .. "/" .. name
-                        local a = lfs.attributes(name)
-                        if not a then
-                            -- weird
-                        elseif a.mode == "directory" then
-                            if name:find("graphics$") or name:find("figures$") or name:find("resources$") then
-                                -- skip these too
-                            else
-                                glob(files,name)
-                            end
-                        elseif name:find(".%luj$") then
-                            files[name] = a.change or a.ctime or a.modification or a.mtime
-                        end
-                    end
-                end
-            end
-            local function toset(t)
-                if type(t) == "table" then
-                    return table.concat(t,",")
-                else
-                    return t
-                end
-            end
-            local function noset(t)
-                if type(t) == "table" then
-                    return t[1]
+local function toset(t)
+    if type(t) == "table" then
+        return table.concat(t,",")
+    else
+        return t
+    end
+end
+
+local function noset(t)
+    if type(t) == "table" then
+        return t[1]
+    else
+        return t
+    end
+end
+
+local lfsdir, lfsattributes = lfs.dir, lfs.attributes
+
+local function glob(files,path)
+    for name in lfsdir(path) do
+        if name:find("^%.") then
+            -- skip . and ..
+        else
+            name = path .. "/" .. name
+            local a = lfsattributes(name)
+            if not a then
+                -- weird
+            elseif a.mode == "directory" then
+                if name:find("graphics$") or name:find("figures$") or name:find("resources$") then
+                    -- skip these too
                 else
-                    return t
+                    glob(files,name)
                 end
+            elseif name:find(".%luj$") then
+                files[name] = a.change or a.ctime or a.modification or a.mtime
             end
-            local function process()
-                local done = false
-                for _, path in ipairs(environment.files) do
-                    lfs.chdir(path)
-                    local files = { }
-                    glob(files,path)
-                    table.sort(files) -- what gets sorted here
-                    for name, time in pairs(files) do
-                    --~ local ok, joblog = xpcall(function() return dofile(name) end, function() end )
-                        local ok, joblog = pcall(dofile,name)
-                        if ok and joblog then
-                            if joblog.status == "processing" then
-                                logs.report("watch",string.format("aborted job, %s added to queue",name))
-                                joblog.status = "queued"
-                                io.savedata(name, table.serialize(joblog,true))
-                            elseif joblog.status == "queued" then
-                                local command = joblog.command
-                                if command then
-                                    local replacements = {
-                                        inputpath  = toset((joblog.paths and joblog.paths.input ) or "."),
-                                        outputpath = noset((joblog.paths and joblog.paths.output) or "."),
-                                        filename   = joblog.filename or "",
-                                    }
-                                    command = command:gsub("%%(.-)%%", replacements)
-                                    if command ~= "" then
-                                        joblog.status = "processing"
-                                        joblog.runtime = os.time() -- os.clock()
-                                        io.savedata(name, table.serialize(joblog,true))
-                                        logs.report("watch",string.format("running: %s", command))
-                                        local newpath = file.dirname(name)
-                                        io.flush()
-                                        local result = ""
-                                        local ctmname = file.basename(replacements.filename)
-                                        if ctmname == "" then ctmname = name end -- use self as fallback
-                                        ctmname = file.replacesuffix(ctmname,"ctm")
-                                        if newpath ~= "" and newpath ~= "." then
-                                            local oldpath = lfs.currentdir()
-                                            lfs.chdir(newpath)
-                                            scripts.watch.save_exa_modes(joblog,ctmname)
-                                            if pipe then result = os.resultof(command) else result = os.spawn(command) end
-                                            lfs.chdir(oldpath)
-                                        else
-                                            scripts.watch.save_exa_modes(joblog,ctmname)
-                                            if pipe then result = os.resultof(command) else result = os.spawn(command) end
-                                        end
-                                        logs.report("watch",string.format("return value: %s", result))
-                                        done = true
-                                        local path, base = replacements.outputpath, file.basename(replacements.filename)
-                                        joblog.runtime = os.time() - joblog.runtime -- os.clock() - joblog.runtime
+        end
+    end
+end
+
+function scripts.watch.watch()
+    local delay   = environment.argument("delay")   or 5
+    local logpath = environment.argument("logpath") or ""
+    local pipe    = environment.argument("pipe")    or false
+    if #environment.files > 0 then
+        for _, path in ipairs(environment.files) do
+            logs.report("watch", "watching path ".. path)
+        end
+        local function process()
+            local done = false
+            for _, path in ipairs(environment.files) do
+                lfs.chdir(path)
+                local files = { }
+                glob(files,path)
+                table.sort(files) -- what gets sorted here
+                for name, time in pairs(files) do
+                --~ local ok, joblog = xpcall(function() return dofile(name) end, function() end )
+                    local ok, joblog = pcall(dofile,name)
+                    if ok and joblog then
+                        if joblog.status == "processing" then
+                            logs.report("watch",string.format("aborted job, %s added to queue",name))
+                            joblog.status = "queued"
+                            io.savedata(name, table.serialize(joblog,true))
+                        elseif joblog.status == "queued" then
+                            local command = joblog.command
+                            if command then
+                                local replacements = {
+                                    inputpath  = toset((joblog.paths and joblog.paths.input ) or "."),
+                                    outputpath = noset((joblog.paths and joblog.paths.output) or "."),
+                                    filename   = joblog.filename or "",
+                                }
+                                command = command:gsub("%%(.-)%%", replacements)
+                                if command ~= "" then
+                                    joblog.status = "processing"
+                                    joblog.runtime = os.clock()
+                                    io.savedata(name, table.serialize(joblog,true))
+                                    logs.report("watch",string.format("running: %s", command))
+                                    local newpath = file.dirname(name)
+                                    io.flush()
+                                    local result = ""
+                                    local ctmname = file.basename(replacements.filename)
+                                    if ctmname == "" then ctmname = name end -- use self as fallback
+                                    ctmname = file.replacesuffix(ctmname,"ctm")
+                                    if newpath ~= "" and newpath ~= "." then
+                                        local oldpath = lfs.currentdir()
+                                        lfs.chdir(newpath)
+                                        scripts.watch.save_exa_modes(joblog,ctmname)
+                                        if pipe then result = os.resultof(command) else result = os.spawn(command) end
+                                        lfs.chdir(oldpath)
+                                    else
+                                        scripts.watch.save_exa_modes(joblog,ctmname)
+                                        if pipe then result = os.resultof(command) else result = os.spawn(command) end
+                                    end
+                                    logs.report("watch",string.format("return value: %s", result))
+                                    done = true
+                                    local path, base = replacements.outputpath, file.basename(replacements.filename)
+                                    joblog.runtime = os.clock() - joblog.runtime
+                                    if base ~= "" then
                                         joblog.result  = file.replacesuffix(file.join(path,base),"pdf")
                                         joblog.size    = lfs.attributes(joblog.result,"size")
-                                        joblog.status  = "finished"
-                                    else
-                                        joblog.status = "invalid command"
                                     end
+                                    joblog.status  = "finished"
                                 else
-                                    joblog.status = "no command"
+                                    joblog.status = "invalid command"
                                 end
-                                -- pcall, when error sleep + again
+                            else
+                                joblog.status = "no command"
+                            end
+                            -- pcall, when error sleep + again
+                            io.savedata(name, table.serialize(joblog,true))
+                            if logpath ~= "" then
+                                local name = string.format("%s/%s%04i%09i.lua", logpath, os.time(), math.floor((os.clock()*100)%1000), math.random(99999999))
                                 io.savedata(name, table.serialize(joblog,true))
-                                if logpath ~= "" then
-                                    local name = string.format("%s/%s%04i%09i.lua", logpath, os.time(), math.floor((os.clock()*100)%1000), math.random(99999999))
-                                    io.savedata(name, table.serialize(joblog,true))
-                                    logs.report("watch", "saving joblog ".. name)
-                                end
+                                logs.report("watch", "saving joblog ".. name)
                             end
                         end
                     end
                 end
             end
-            local n, start = 0, os.clock()
-            local function wait()
-                io.flush()
-                if not done then
-                    n = n + 1
-                    if n >= 10 then
-                        logs.report("watch", string.format("run time: %i seconds, memory usage: %0.3g MB", os.clock() - start, (status.luastate_bytes/1024)/1000))
-                        n = 0
-                    end
-                    os.sleep(delay)
+        end
+        local n, start = 0, os.clock()
+        local function wait()
+            io.flush()
+            if not done then
+                n = n + 1
+                if n >= 10 then
+                    logs.report("watch", string.format("run time: %i seconds, memory usage: %0.3g MB", os.clock() - start, (status.luastate_bytes/1024)/1000))
+                    n = 0
                 end
+                os.sleep(delay)
             end
-            while true do
+        end
+        while true do
+            if false then
+                process()
+                wait()
+            else
                 pcall(process)
                 pcall(wait)
             end
-        else
-            logs.report("watch", "no paths to watch")
         end
+    else
+        logs.report("watch", "no paths to watch")
     end
-
 end
 
 function scripts.watch.collect_logs(path) -- clean 'm up too
diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua
index a1fc6eaf5..c5b0acd04 100644
--- a/scripts/context/lua/mtxrun.lua
+++ b/scripts/context/lua/mtxrun.lua
@@ -242,6 +242,7 @@ end
 local simple_escapes = {
     ["-"] = "%-",
     ["."] = "%.",
+    ["?"] = ".",
     ["*"] = ".*",
 }
 
@@ -304,6 +305,19 @@ function string:striplong() -- strips newlines and leading spaces
     return self
 end
 
+function string:topattern(lowercase,strict)
+    if lowercase then
+        self = self:lower()
+    end
+    self = gsub(self,".",simple_escapes)
+    if self == "" then
+        self = ".*"
+    elseif strict then
+        self = "^" .. self .. "$"
+    end
+    return self
+end
+
 
 end -- of closure
 
@@ -1765,59 +1779,54 @@ os.arch = os.arch or function()
     return a
 end
 
-local platform
+-- no need for function anymore as we have more clever code and helpers now
 
-function os.currentplatform(name,default)
-    if not platform then
-        local name = os.name or os.platform or name -- os.name is built in, os.platform is mine
-        if not name then
-            platform = default or "linux"
-        elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
-            if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
-                platform = "mswin-64"
-            else
-                platform = "mswin"
-            end
+os.platform  = os.name
+os.libsuffix = 'so'
+
+local name = os.name
+
+if name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
+    if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
+        os.platform = "mswin-64"
+    else
+        os.platform = "mswin"
+    end
+    os.libsuffix = 'dll'
+else
+    local architecture = os.arch()
+    if name == "linux" then
+        if find(architecture,"x86_64") then
+            os.platform = "linux-64"
+        elseif find(architecture,"ppc") then
+            os.platform = "linux-ppc"
         else
-            local architecture = os.arch()
-            if name == "linux" then
-                if find(architecture,"x86_64") then
-                    platform = "linux-64"
-                elseif find(architecture,"ppc") then
-                    platform = "linux-ppc"
-                else
-                    platform = "linux"
-                end
-            elseif name == "macosx" then
-                local architecture = os.resultof("echo $HOSTTYPE")
-                if find(architecture,"i386") then
-                    platform = "osx-intel"
-                elseif find(architecture,"x86_64") then
-                    platform = "osx-64"
-                else
-                    platform = "osx-ppc"
-                end
-            elseif name == "sunos" then
-                if find(architecture,"sparc") then
-                    platform = "solaris-sparc"
-                else -- if architecture == 'i86pc'
-                    platform = "solaris-intel"
-                end
-            elseif name == "freebsd" then
-                if find(architecture,"amd64") then
-                    platform = "freebsd-amd64"
-                else
-                    platform = "freebsd"
-                end
-            else
-                platform = default or name
-            end
+            os.platform = "linux"
+        end
+    elseif name == "macosx" then
+        local architecture = os.resultof("echo $HOSTTYPE")
+        if find(architecture,"i386") then
+            os.platform = "osx-intel"
+        elseif find(architecture,"x86_64") then
+            os.platform = "osx-64"
+        else
+            os.platform = "osx-ppc"
         end
-        function os.currentplatform()
-            return platform
+    elseif name == "sunos" then
+        if find(architecture,"sparc") then
+            os.platform = "solaris-sparc"
+        else -- if architecture == 'i86pc'
+            os.platform = "solaris-intel"
         end
+    elseif name == "freebsd" then
+        if find(architecture,"amd64") then
+            os.platform = "freebsd-amd64"
+        else
+            os.platform = "freebsd"
+        end
+    else
+        os.platform = 'linux'
     end
-    return platform
 end
 
 -- beware, we set the randomseed
@@ -2241,6 +2250,35 @@ end
 
 dir.glob_pattern = glob_pattern
 
+local function collect_pattern(path,patt,recurse,result)
+    local ok, scanner
+    result = result or { }
+    if path == "/" then
+        ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
+    else
+        ok, scanner = xpcall(function() return walkdir(path)      end, function() end) -- kepler safe
+    end
+    if ok and type(scanner) == "function" then
+        if not find(path,"/$") then path = path .. '/' end
+        for name in scanner do
+            local full = path .. name
+            local attr = attributes(full)
+            local mode = attr.mode
+            if mode == 'file' then
+                if find(full,patt) then
+                    result[name] = attr
+                end
+            elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
+                attr.list = collect_pattern(full,patt,recurse)
+                result[name] = attr
+            end
+        end
+    end
+    return result
+end
+
+dir.collect_pattern = collect_pattern
+
 local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
 
 local pattern = Ct {
@@ -7264,6 +7302,11 @@ formats     ['sfd']                      = 'SFDFONTS'
 suffixes    ['sfd']                      = { 'sfd' }
 alternatives['subfont definition files'] = 'sfd'
 
+-- lib paths
+
+formats ['lib'] = 'CLUAINPUTS' -- new (needs checking)
+suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' }
+
 -- In practice we will work within one tds tree, but i want to keep
 -- the option open to build tools that look at multiple trees, which is
 -- why we keep the tree specific data in a table. We used to pass the
@@ -8483,9 +8526,9 @@ end
 function resolvers.expanded_path_list_from_var(str) -- brrr
     local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$",""))
     if tmp ~= "" then
-        return resolvers.expanded_path_list(str)
-    else
         return resolvers.expanded_path_list(tmp)
+    else
+        return resolvers.expanded_path_list(str)
     end
 end
 
@@ -9473,6 +9516,16 @@ prefixes.full = prefixes.locate
 prefixes.file = prefixes.filename
 prefixes.path = prefixes.pathname
 
+function resolvers.allprefixes(separator)
+    local all = table.sortedkeys(prefixes)
+    if separator then
+        for i=1,#all do
+            all[i] = all[i] .. ":"
+        end
+    end
+    return all
+end
+
 local function _resolve_(method,target)
     if prefixes[method] then
         return prefixes[method](target)
@@ -10130,43 +10183,109 @@ local trace_locating = false  trackers.register("resolvers.locating", function(v
 
 local gsub = string.gsub
 
-local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' }
-local libpaths   = file.split_path(package.path)
+local  libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } -- 'luainputs'
+local clibformats = { 'lib' }
+local  libpaths   = file.split_path(package.path)
+local clibpaths   = file.split_path(package.cpath)
+
+local function thepath(...)
+    local t = { ... } t[#t+1] = "?.lua"
+    local path = file.join(unpack(t))
+    if trace_locating then
+        logs.report("fileio","! appending '%s' to 'package.path'",path)
+    end
+    return path
+end
+
+function package.append_libpath(...)
+    table.insert(libpaths,thepath(...))
+end
+
+function package.prepend_libpath(...)
+    table.insert(libpaths,1,thepath(...))
+end
+
+-- beware, we need to return a loadfile result !
 
 package.loaders[2] = function(name) -- was [#package.loaders+1]
---~ package.loaders[#package.loaders+1] = function(name) -- was
+    if trace_locating then -- mode detail
+        logs.report("fileio","! locating '%s'",name)
+    end
     for i=1,#libformats do
         local format = libformats[i]
         local resolved = resolvers.find_file(name,format) or ""
+        if trace_locating then -- mode detail
+            logs.report("fileio","! checking for '%s' using 'libformat path': '%s'",name,format)
+        end
         if resolved ~= "" then
             if trace_locating then
                 logs.report("fileio","! lib '%s' located via environment: '%s'",name,resolved)
             end
-            return function() return dofile(resolved) end
+            return loadfile(resolved)
         end
     end
-    local simple = file.removesuffix(name)
+    local simple = gsub(name,"%.lua$","")
+    local simple = gsub(simple,"%.","/")
     for i=1,#libpaths do -- package.path, might become option
-        local resolved = gsub(libpaths[i],"?",simple)
+        local libpath = libpaths[i]
+        local resolved = gsub(libpath,"?",simple)
+        if trace_locating then -- more detail
+            logs.report("fileio","! checking for '%s' on 'package.path': '%s'",simple,libpath)
+        end
         if resolvers.isreadable.file(resolved) then
             if trace_locating then
                 logs.report("fileio","! lib '%s' located via 'package.path': '%s'",name,resolved)
             end
-            return function() return dofile(resolved) end
+            return loadfile(resolved)
+        end
+    end
+    local libname = file.addsuffix(simple,os.libsuffix)
+    for i=1,#clibformats do
+        -- better have a dedicated loop
+        local format = clibformats[i]
+        local paths = resolvers.expanded_path_list_from_var(format)
+        for p=1,#paths do
+            local path = paths[p]
+            local resolved = file.join(path,libname)
+            if trace_locating then -- mode detail
+                logs.report("fileio","! checking for '%s' using 'clibformat path': '%s'",libname,path)
+            end
+            if resolvers.isreadable.file(resolved) then
+                if trace_locating then
+                    logs.report("fileio","! lib '%s' located via 'clibformat': '%s'",libname,resolved)
+                end
+                return package.loadlib(resolved,name)
+            end
+        end
+    end
+    for i=1,#clibpaths do -- package.path, might become option
+        local libpath = clibpaths[i]
+        local resolved = gsub(libpath,"?",simple)
+        if trace_locating then -- more detail
+            logs.report("fileio","! checking for '%s' on 'package.cpath': '%s'",simple,libpath)
+        end
+        if resolvers.isreadable.file(resolved) then
+            if trace_locating then
+                logs.report("fileio","! lib '%s' located via 'package.cpath': '%s'",name,resolved)
+            end
+            return package.loadlib(resolved,name)
         end
     end
     -- just in case the distribution is messed up
+    if trace_loading then -- more detail
+        logs.report("fileio","! checking for '%s' using 'luatexlibs': '%s'",name)
+    end
     local resolved = resolvers.find_file(file.basename(name),'luatexlibs') or ""
     if resolved ~= "" then
         if trace_locating then
             logs.report("fileio","! lib '%s' located by basename via environment: '%s'",name,resolved)
         end
-        return function() return dofile(resolved) end
+        return loadfile(resolved)
     end
     if trace_locating then
         logs.report("fileio",'? unable to locate lib: %s',name)
     end
-    return "unable to locate " .. name
+--  return "unable to locate " .. name
 end
 
 resolvers.loadlualib = require
@@ -10359,7 +10478,7 @@ if not modules then modules = { } end modules ['data-tmf'] = {
 function resolvers.check_environment(tree)
     logs.simpleline()
     os.setenv('TMP', os.getenv('TMP') or os.getenv('TEMP') or os.getenv('TMPDIR') or os.getenv('HOME'))
-    os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.currentplatform()))
+    os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.platform))
     os.setenv('TEXPATH', (tree or "tex"):gsub("\/+$",''))
     os.setenv('TEXMFOS', os.getenv('TEXPATH') .. "/" .. os.getenv('TEXOS'))
     logs.simpleline()
@@ -10723,10 +10842,11 @@ runners  = runners  or { } -- global
 messages = messages or { }
 
 messages.help = [[
---script              run an mtx script (--noquotes), no script gives list
---execute             run a script or program (--noquotes)
+--script              run an mtx script (lua prefered method) (--noquotes), no script gives list
+--execute             run a script or program (texmfstart method) (--noquotes)
 --resolve             resolve prefixed arguments
 --ctxlua              run internally (using preloaded libs)
+--internal            run script using built in libraries (same as --ctxlua)
 --locate              locate given filename
 
 --autotree            use texmf tree cf. env 'texmfstart_tree' or 'texmfstarttree'
@@ -10750,11 +10870,13 @@ messages.help = [[
 --edit                launch editor with found file
 --launch (--all)      launch files like manuals, assumes os support
 
---internal            run script using built in libraries (same as --ctxlua)
 --timedrun            run a script an time its run
+--autogenerate        regenerate databases if needed (handy when used to run context in an editor)
 
 --usekpse             use kpse as fallback (when no mkiv and cache installed, often slower)
 --forcekpse           force using kpse (handy when no mkiv and cache installed but less functionality)
+
+--prefixes            show supported prefixes
 ]]
 
 runners.applications = {
@@ -10800,6 +10922,13 @@ runners.launchers = {
     unix = { }
 }
 
+-- like runners.libpath("framework"): looks on script's subpath
+
+function runners.libpath(...)
+    package.prepend_libpath(file.dirname(environment.ownscript),...)
+    package.prepend_libpath(file.dirname(environment.ownname)  ,...)
+end
+
 function runners.prepare()
     local checkname = environment.argument("ifchanged")
     if checkname and checkname ~= "" then
@@ -10890,6 +11019,7 @@ function runners.execute_script(fullname,internal,nosplit)
                 end
                 if internal then
                     arg = { } for _,v in pairs(environment.arguments_after) do arg[#arg+1] = v end
+                    environment.ownscript = result
                     dofile(result)
                 else
                     local binary = runners.applications[file.extname(result)]
@@ -10993,7 +11123,7 @@ function runners.locate_file(filename)
 end
 
 function runners.locate_platform()
-    runners.report_location(os.currentplatform())
+    runners.report_location(os.platform)
 end
 
 function runners.report_location(result)
@@ -11170,6 +11300,7 @@ function runners.execute_ctx_script(filename)
             if logs.verbose then
                 logs.simple("using script: %s\n",fullname)
             end
+            environment.ownscript = fullname
             dofile(fullname)
             local savename = environment.arguments['save']
             if savename and runners.save_list and not table.is_empty(runners.save_list or { }) then
@@ -11222,6 +11353,11 @@ function runners.execute_ctx_script(filename)
     end
 end
 
+function runners.prefixes()
+    logs.reportbanner()
+    logs.reportline()
+    logs.simple(table.concat(resolvers.allprefixes(true)," "))
+end
 
 function runners.timedrun(filename) -- just for me
     if filename and filename ~= "" then
@@ -11337,7 +11473,7 @@ elseif environment.argument("selfupdate") then
 elseif environment.argument("ctxlua") or environment.argument("internal") then
     -- run a script by loading it (using libs)
     ok = runners.execute_script(filename,true)
-elseif environment.argument("script") or environment.argument("s") then
+elseif environment.argument("script") or environment.argument("s") or environment.argument("scripts") then
     -- run a script by loading it (using libs), pass args
     ok = runners.execute_ctx_script(filename)
 elseif environment.argument("execute") then
@@ -11366,6 +11502,8 @@ elseif environment.argument("locate") then
 elseif environment.argument("platform")then
     -- locate platform
     runners.locate_platform()
+elseif environment.argument("prefixes") then
+    runners.prefixes()
 elseif environment.argument("timedrun") then
     -- locate platform
     runners.timedrun(filename)
@@ -11375,9 +11513,9 @@ elseif environment.argument("help") or filename=='help' or filename == "" then
 elseif filename:find("^bin:") then
     ok = runners.execute_program(filename)
 else
-    ok = runners.execute_script(filename)
+    ok = runners.execute_ctx_script(filename)
     if not ok then
-        ok = runners.execute_ctx_script(filename)
+        ok = runners.execute_script(filename)
     end
 end
 
diff --git a/scripts/context/stubs/mswin/luatools.lua b/scripts/context/stubs/mswin/luatools.lua
index 6feb7a9c5..06e2a1bfc 100644
--- a/scripts/context/stubs/mswin/luatools.lua
+++ b/scripts/context/stubs/mswin/luatools.lua
@@ -233,6 +233,7 @@ end
 local simple_escapes = {
     ["-"] = "%-",
     ["."] = "%.",
+    ["?"] = ".",
     ["*"] = ".*",
 }
 
@@ -295,6 +296,19 @@ function string:striplong() -- strips newlines and leading spaces
     return self
 end
 
+function string:topattern(lowercase,strict)
+    if lowercase then
+        self = self:lower()
+    end
+    self = gsub(self,".",simple_escapes)
+    if self == "" then
+        self = ".*"
+    elseif strict then
+        self = "^" .. self .. "$"
+    end
+    return self
+end
+
 
 end -- of closure
 
@@ -1756,59 +1770,54 @@ os.arch = os.arch or function()
     return a
 end
 
-local platform
+-- no need for function anymore as we have more clever code and helpers now
 
-function os.currentplatform(name,default)
-    if not platform then
-        local name = os.name or os.platform or name -- os.name is built in, os.platform is mine
-        if not name then
-            platform = default or "linux"
-        elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
-            if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
-                platform = "mswin-64"
-            else
-                platform = "mswin"
-            end
+os.platform  = os.name
+os.libsuffix = 'so'
+
+local name = os.name
+
+if name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
+    if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
+        os.platform = "mswin-64"
+    else
+        os.platform = "mswin"
+    end
+    os.libsuffix = 'dll'
+else
+    local architecture = os.arch()
+    if name == "linux" then
+        if find(architecture,"x86_64") then
+            os.platform = "linux-64"
+        elseif find(architecture,"ppc") then
+            os.platform = "linux-ppc"
         else
-            local architecture = os.arch()
-            if name == "linux" then
-                if find(architecture,"x86_64") then
-                    platform = "linux-64"
-                elseif find(architecture,"ppc") then
-                    platform = "linux-ppc"
-                else
-                    platform = "linux"
-                end
-            elseif name == "macosx" then
-                local architecture = os.resultof("echo $HOSTTYPE")
-                if find(architecture,"i386") then
-                    platform = "osx-intel"
-                elseif find(architecture,"x86_64") then
-                    platform = "osx-64"
-                else
-                    platform = "osx-ppc"
-                end
-            elseif name == "sunos" then
-                if find(architecture,"sparc") then
-                    platform = "solaris-sparc"
-                else -- if architecture == 'i86pc'
-                    platform = "solaris-intel"
-                end
-            elseif name == "freebsd" then
-                if find(architecture,"amd64") then
-                    platform = "freebsd-amd64"
-                else
-                    platform = "freebsd"
-                end
-            else
-                platform = default or name
-            end
+            os.platform = "linux"
+        end
+    elseif name == "macosx" then
+        local architecture = os.resultof("echo $HOSTTYPE")
+        if find(architecture,"i386") then
+            os.platform = "osx-intel"
+        elseif find(architecture,"x86_64") then
+            os.platform = "osx-64"
+        else
+            os.platform = "osx-ppc"
         end
-        function os.currentplatform()
-            return platform
+    elseif name == "sunos" then
+        if find(architecture,"sparc") then
+            os.platform = "solaris-sparc"
+        else -- if architecture == 'i86pc'
+            os.platform = "solaris-intel"
         end
+    elseif name == "freebsd" then
+        if find(architecture,"amd64") then
+            os.platform = "freebsd-amd64"
+        else
+            os.platform = "freebsd"
+        end
+    else
+        os.platform = 'linux'
     end
-    return platform
 end
 
 -- beware, we set the randomseed
@@ -2343,6 +2352,35 @@ end
 
 dir.glob_pattern = glob_pattern
 
+local function collect_pattern(path,patt,recurse,result)
+    local ok, scanner
+    result = result or { }
+    if path == "/" then
+        ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
+    else
+        ok, scanner = xpcall(function() return walkdir(path)      end, function() end) -- kepler safe
+    end
+    if ok and type(scanner) == "function" then
+        if not find(path,"/$") then path = path .. '/' end
+        for name in scanner do
+            local full = path .. name
+            local attr = attributes(full)
+            local mode = attr.mode
+            if mode == 'file' then
+                if find(full,patt) then
+                    result[name] = attr
+                end
+            elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
+                attr.list = collect_pattern(full,patt,recurse)
+                result[name] = attr
+            end
+        end
+    end
+    return result
+end
+
+dir.collect_pattern = collect_pattern
+
 local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
 
 local pattern = Ct {
@@ -3166,9 +3204,9 @@ function aux.settings_to_hash_strict(str,existing)
     end
 end
 
-local seperator = comma * space^0
+local separator = comma * space^0
 local value     = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0)
-local pattern   = lpeg.Ct(value*(seperator*value)^0)
+local pattern   = lpeg.Ct(value*(separator*value)^0)
 
 -- "aap, {noot}, mies" : outer {} removes, leading spaces ignored
 
@@ -3187,7 +3225,7 @@ local function set(t,v)
 end
 
 local value   = lpeg.P(lpeg.Carg(1)*value) / set
-local pattern = value*(seperator*value)^0 * lpeg.Carg(1)
+local pattern = value*(separator*value)^0 * lpeg.Carg(1)
 
 function aux.add_settings_to_array(t,str)
     return pattern:match(str, nil, t)
@@ -3238,6 +3276,13 @@ function aux.settings_to_set(str,t)
     return t
 end
 
+local value     = lbrace * lpeg.C((nobrace + nested)^0) * rbrace
+local pattern   = lpeg.Ct((space + value)^0)
+
+function aux.arguments_to_table(str)
+    return pattern:match(str)
+end
+
 -- temporary here
 
 function aux.getparameters(self,class,parentclass,settings)
@@ -4068,7 +4113,7 @@ end -- of closure
 
 do -- create closure to overcome 200 locals limit
 
-if not modules then modules = { } end modules ['luat-log'] = {
+if not modules then modules = { } end modules ['trac-log'] = {
     version   = 1.001,
     comment   = "companion to trac-log.mkiv",
     author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
@@ -4345,8 +4390,12 @@ end
 
 logs.simpleline = logs.reportline
 
-function logs.help(message,option)
+function logs.reportbanner() -- for scripts too
     logs.report(banner)
+end
+
+function logs.help(message,option)
+    logs.reportbanner()
     logs.reportline()
     logs.reportlines(message)
     local moreinfo = logs.moreinfo or ""
@@ -4509,6 +4558,11 @@ formats     ['sfd']                      = 'SFDFONTS'
 suffixes    ['sfd']                      = { 'sfd' }
 alternatives['subfont definition files'] = 'sfd'
 
+-- lib paths
+
+formats ['lib'] = 'CLUAINPUTS' -- new (needs checking)
+suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' }
+
 -- In practice we will work within one tds tree, but i want to keep
 -- the option open to build tools that look at multiple trees, which is
 -- why we keep the tree specific data in a table. We used to pass the
@@ -5728,9 +5782,9 @@ end
 function resolvers.expanded_path_list_from_var(str) -- brrr
     local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$",""))
     if tmp ~= "" then
-        return resolvers.expanded_path_list(str)
-    else
         return resolvers.expanded_path_list(tmp)
+    else
+        return resolvers.expanded_path_list(str)
     end
 end
 
diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua
index a1fc6eaf5..c5b0acd04 100644
--- a/scripts/context/stubs/mswin/mtxrun.lua
+++ b/scripts/context/stubs/mswin/mtxrun.lua
@@ -242,6 +242,7 @@ end
 local simple_escapes = {
     ["-"] = "%-",
     ["."] = "%.",
+    ["?"] = ".",
     ["*"] = ".*",
 }
 
@@ -304,6 +305,19 @@ function string:striplong() -- strips newlines and leading spaces
     return self
 end
 
+function string:topattern(lowercase,strict)
+    if lowercase then
+        self = self:lower()
+    end
+    self = gsub(self,".",simple_escapes)
+    if self == "" then
+        self = ".*"
+    elseif strict then
+        self = "^" .. self .. "$"
+    end
+    return self
+end
+
 
 end -- of closure
 
@@ -1765,59 +1779,54 @@ os.arch = os.arch or function()
     return a
 end
 
-local platform
+-- no need for function anymore as we have more clever code and helpers now
 
-function os.currentplatform(name,default)
-    if not platform then
-        local name = os.name or os.platform or name -- os.name is built in, os.platform is mine
-        if not name then
-            platform = default or "linux"
-        elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
-            if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
-                platform = "mswin-64"
-            else
-                platform = "mswin"
-            end
+os.platform  = os.name
+os.libsuffix = 'so'
+
+local name = os.name
+
+if name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
+    if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
+        os.platform = "mswin-64"
+    else
+        os.platform = "mswin"
+    end
+    os.libsuffix = 'dll'
+else
+    local architecture = os.arch()
+    if name == "linux" then
+        if find(architecture,"x86_64") then
+            os.platform = "linux-64"
+        elseif find(architecture,"ppc") then
+            os.platform = "linux-ppc"
         else
-            local architecture = os.arch()
-            if name == "linux" then
-                if find(architecture,"x86_64") then
-                    platform = "linux-64"
-                elseif find(architecture,"ppc") then
-                    platform = "linux-ppc"
-                else
-                    platform = "linux"
-                end
-            elseif name == "macosx" then
-                local architecture = os.resultof("echo $HOSTTYPE")
-                if find(architecture,"i386") then
-                    platform = "osx-intel"
-                elseif find(architecture,"x86_64") then
-                    platform = "osx-64"
-                else
-                    platform = "osx-ppc"
-                end
-            elseif name == "sunos" then
-                if find(architecture,"sparc") then
-                    platform = "solaris-sparc"
-                else -- if architecture == 'i86pc'
-                    platform = "solaris-intel"
-                end
-            elseif name == "freebsd" then
-                if find(architecture,"amd64") then
-                    platform = "freebsd-amd64"
-                else
-                    platform = "freebsd"
-                end
-            else
-                platform = default or name
-            end
+            os.platform = "linux"
+        end
+    elseif name == "macosx" then
+        local architecture = os.resultof("echo $HOSTTYPE")
+        if find(architecture,"i386") then
+            os.platform = "osx-intel"
+        elseif find(architecture,"x86_64") then
+            os.platform = "osx-64"
+        else
+            os.platform = "osx-ppc"
         end
-        function os.currentplatform()
-            return platform
+    elseif name == "sunos" then
+        if find(architecture,"sparc") then
+            os.platform = "solaris-sparc"
+        else -- if architecture == 'i86pc'
+            os.platform = "solaris-intel"
         end
+    elseif name == "freebsd" then
+        if find(architecture,"amd64") then
+            os.platform = "freebsd-amd64"
+        else
+            os.platform = "freebsd"
+        end
+    else
+        os.platform = 'linux'
     end
-    return platform
 end
 
 -- beware, we set the randomseed
@@ -2241,6 +2250,35 @@ end
 
 dir.glob_pattern = glob_pattern
 
+local function collect_pattern(path,patt,recurse,result)
+    local ok, scanner
+    result = result or { }
+    if path == "/" then
+        ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
+    else
+        ok, scanner = xpcall(function() return walkdir(path)      end, function() end) -- kepler safe
+    end
+    if ok and type(scanner) == "function" then
+        if not find(path,"/$") then path = path .. '/' end
+        for name in scanner do
+            local full = path .. name
+            local attr = attributes(full)
+            local mode = attr.mode
+            if mode == 'file' then
+                if find(full,patt) then
+                    result[name] = attr
+                end
+            elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
+                attr.list = collect_pattern(full,patt,recurse)
+                result[name] = attr
+            end
+        end
+    end
+    return result
+end
+
+dir.collect_pattern = collect_pattern
+
 local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
 
 local pattern = Ct {
@@ -7264,6 +7302,11 @@ formats     ['sfd']                      = 'SFDFONTS'
 suffixes    ['sfd']                      = { 'sfd' }
 alternatives['subfont definition files'] = 'sfd'
 
+-- lib paths
+
+formats ['lib'] = 'CLUAINPUTS' -- new (needs checking)
+suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' }
+
 -- In practice we will work within one tds tree, but i want to keep
 -- the option open to build tools that look at multiple trees, which is
 -- why we keep the tree specific data in a table. We used to pass the
@@ -8483,9 +8526,9 @@ end
 function resolvers.expanded_path_list_from_var(str) -- brrr
     local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$",""))
     if tmp ~= "" then
-        return resolvers.expanded_path_list(str)
-    else
         return resolvers.expanded_path_list(tmp)
+    else
+        return resolvers.expanded_path_list(str)
     end
 end
 
@@ -9473,6 +9516,16 @@ prefixes.full = prefixes.locate
 prefixes.file = prefixes.filename
 prefixes.path = prefixes.pathname
 
+function resolvers.allprefixes(separator)
+    local all = table.sortedkeys(prefixes)
+    if separator then
+        for i=1,#all do
+            all[i] = all[i] .. ":"
+        end
+    end
+    return all
+end
+
 local function _resolve_(method,target)
     if prefixes[method] then
         return prefixes[method](target)
@@ -10130,43 +10183,109 @@ local trace_locating = false  trackers.register("resolvers.locating", function(v
 
 local gsub = string.gsub
 
-local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' }
-local libpaths   = file.split_path(package.path)
+local  libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } -- 'luainputs'
+local clibformats = { 'lib' }
+local  libpaths   = file.split_path(package.path)
+local clibpaths   = file.split_path(package.cpath)
+
+local function thepath(...)
+    local t = { ... } t[#t+1] = "?.lua"
+    local path = file.join(unpack(t))
+    if trace_locating then
+        logs.report("fileio","! appending '%s' to 'package.path'",path)
+    end
+    return path
+end
+
+function package.append_libpath(...)
+    table.insert(libpaths,thepath(...))
+end
+
+function package.prepend_libpath(...)
+    table.insert(libpaths,1,thepath(...))
+end
+
+-- beware, we need to return a loadfile result !
 
 package.loaders[2] = function(name) -- was [#package.loaders+1]
---~ package.loaders[#package.loaders+1] = function(name) -- was
+    if trace_locating then -- mode detail
+        logs.report("fileio","! locating '%s'",name)
+    end
     for i=1,#libformats do
         local format = libformats[i]
         local resolved = resolvers.find_file(name,format) or ""
+        if trace_locating then -- mode detail
+            logs.report("fileio","! checking for '%s' using 'libformat path': '%s'",name,format)
+        end
         if resolved ~= "" then
             if trace_locating then
                 logs.report("fileio","! lib '%s' located via environment: '%s'",name,resolved)
             end
-            return function() return dofile(resolved) end
+            return loadfile(resolved)
         end
     end
-    local simple = file.removesuffix(name)
+    local simple = gsub(name,"%.lua$","")
+    local simple = gsub(simple,"%.","/")
     for i=1,#libpaths do -- package.path, might become option
-        local resolved = gsub(libpaths[i],"?",simple)
+        local libpath = libpaths[i]
+        local resolved = gsub(libpath,"?",simple)
+        if trace_locating then -- more detail
+            logs.report("fileio","! checking for '%s' on 'package.path': '%s'",simple,libpath)
+        end
         if resolvers.isreadable.file(resolved) then
             if trace_locating then
                 logs.report("fileio","! lib '%s' located via 'package.path': '%s'",name,resolved)
             end
-            return function() return dofile(resolved) end
+            return loadfile(resolved)
+        end
+    end
+    local libname = file.addsuffix(simple,os.libsuffix)
+    for i=1,#clibformats do
+        -- better have a dedicated loop
+        local format = clibformats[i]
+        local paths = resolvers.expanded_path_list_from_var(format)
+        for p=1,#paths do
+            local path = paths[p]
+            local resolved = file.join(path,libname)
+            if trace_locating then -- mode detail
+                logs.report("fileio","! checking for '%s' using 'clibformat path': '%s'",libname,path)
+            end
+            if resolvers.isreadable.file(resolved) then
+                if trace_locating then
+                    logs.report("fileio","! lib '%s' located via 'clibformat': '%s'",libname,resolved)
+                end
+                return package.loadlib(resolved,name)
+            end
+        end
+    end
+    for i=1,#clibpaths do -- package.path, might become option
+        local libpath = clibpaths[i]
+        local resolved = gsub(libpath,"?",simple)
+        if trace_locating then -- more detail
+            logs.report("fileio","! checking for '%s' on 'package.cpath': '%s'",simple,libpath)
+        end
+        if resolvers.isreadable.file(resolved) then
+            if trace_locating then
+                logs.report("fileio","! lib '%s' located via 'package.cpath': '%s'",name,resolved)
+            end
+            return package.loadlib(resolved,name)
         end
     end
     -- just in case the distribution is messed up
+    if trace_loading then -- more detail
+        logs.report("fileio","! checking for '%s' using 'luatexlibs': '%s'",name)
+    end
     local resolved = resolvers.find_file(file.basename(name),'luatexlibs') or ""
     if resolved ~= "" then
         if trace_locating then
             logs.report("fileio","! lib '%s' located by basename via environment: '%s'",name,resolved)
         end
-        return function() return dofile(resolved) end
+        return loadfile(resolved)
     end
     if trace_locating then
         logs.report("fileio",'? unable to locate lib: %s',name)
     end
-    return "unable to locate " .. name
+--  return "unable to locate " .. name
 end
 
 resolvers.loadlualib = require
@@ -10359,7 +10478,7 @@ if not modules then modules = { } end modules ['data-tmf'] = {
 function resolvers.check_environment(tree)
     logs.simpleline()
     os.setenv('TMP', os.getenv('TMP') or os.getenv('TEMP') or os.getenv('TMPDIR') or os.getenv('HOME'))
-    os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.currentplatform()))
+    os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.platform))
     os.setenv('TEXPATH', (tree or "tex"):gsub("\/+$",''))
     os.setenv('TEXMFOS', os.getenv('TEXPATH') .. "/" .. os.getenv('TEXOS'))
     logs.simpleline()
@@ -10723,10 +10842,11 @@ runners  = runners  or { } -- global
 messages = messages or { }
 
 messages.help = [[
---script              run an mtx script (--noquotes), no script gives list
---execute             run a script or program (--noquotes)
+--script              run an mtx script (lua prefered method) (--noquotes), no script gives list
+--execute             run a script or program (texmfstart method) (--noquotes)
 --resolve             resolve prefixed arguments
 --ctxlua              run internally (using preloaded libs)
+--internal            run script using built in libraries (same as --ctxlua)
 --locate              locate given filename
 
 --autotree            use texmf tree cf. env 'texmfstart_tree' or 'texmfstarttree'
@@ -10750,11 +10870,13 @@ messages.help = [[
 --edit                launch editor with found file
 --launch (--all)      launch files like manuals, assumes os support
 
---internal            run script using built in libraries (same as --ctxlua)
 --timedrun            run a script an time its run
+--autogenerate        regenerate databases if needed (handy when used to run context in an editor)
 
 --usekpse             use kpse as fallback (when no mkiv and cache installed, often slower)
 --forcekpse           force using kpse (handy when no mkiv and cache installed but less functionality)
+
+--prefixes            show supported prefixes
 ]]
 
 runners.applications = {
@@ -10800,6 +10922,13 @@ runners.launchers = {
     unix = { }
 }
 
+-- like runners.libpath("framework"): looks on script's subpath
+
+function runners.libpath(...)
+    package.prepend_libpath(file.dirname(environment.ownscript),...)
+    package.prepend_libpath(file.dirname(environment.ownname)  ,...)
+end
+
 function runners.prepare()
     local checkname = environment.argument("ifchanged")
     if checkname and checkname ~= "" then
@@ -10890,6 +11019,7 @@ function runners.execute_script(fullname,internal,nosplit)
                 end
                 if internal then
                     arg = { } for _,v in pairs(environment.arguments_after) do arg[#arg+1] = v end
+                    environment.ownscript = result
                     dofile(result)
                 else
                     local binary = runners.applications[file.extname(result)]
@@ -10993,7 +11123,7 @@ function runners.locate_file(filename)
 end
 
 function runners.locate_platform()
-    runners.report_location(os.currentplatform())
+    runners.report_location(os.platform)
 end
 
 function runners.report_location(result)
@@ -11170,6 +11300,7 @@ function runners.execute_ctx_script(filename)
             if logs.verbose then
                 logs.simple("using script: %s\n",fullname)
             end
+            environment.ownscript = fullname
             dofile(fullname)
             local savename = environment.arguments['save']
             if savename and runners.save_list and not table.is_empty(runners.save_list or { }) then
@@ -11222,6 +11353,11 @@ function runners.execute_ctx_script(filename)
     end
 end
 
+function runners.prefixes()
+    logs.reportbanner()
+    logs.reportline()
+    logs.simple(table.concat(resolvers.allprefixes(true)," "))
+end
 
 function runners.timedrun(filename) -- just for me
     if filename and filename ~= "" then
@@ -11337,7 +11473,7 @@ elseif environment.argument("selfupdate") then
 elseif environment.argument("ctxlua") or environment.argument("internal") then
     -- run a script by loading it (using libs)
     ok = runners.execute_script(filename,true)
-elseif environment.argument("script") or environment.argument("s") then
+elseif environment.argument("script") or environment.argument("s") or environment.argument("scripts") then
     -- run a script by loading it (using libs), pass args
     ok = runners.execute_ctx_script(filename)
 elseif environment.argument("execute") then
@@ -11366,6 +11502,8 @@ elseif environment.argument("locate") then
 elseif environment.argument("platform")then
     -- locate platform
     runners.locate_platform()
+elseif environment.argument("prefixes") then
+    runners.prefixes()
 elseif environment.argument("timedrun") then
     -- locate platform
     runners.timedrun(filename)
@@ -11375,9 +11513,9 @@ elseif environment.argument("help") or filename=='help' or filename == "" then
 elseif filename:find("^bin:") then
     ok = runners.execute_program(filename)
 else
-    ok = runners.execute_script(filename)
+    ok = runners.execute_ctx_script(filename)
     if not ok then
-        ok = runners.execute_ctx_script(filename)
+        ok = runners.execute_script(filename)
     end
 end
 
diff --git a/scripts/context/stubs/unix/luatools b/scripts/context/stubs/unix/luatools
index 6feb7a9c5..06e2a1bfc 100755
--- a/scripts/context/stubs/unix/luatools
+++ b/scripts/context/stubs/unix/luatools
@@ -233,6 +233,7 @@ end
 local simple_escapes = {
     ["-"] = "%-",
     ["."] = "%.",
+    ["?"] = ".",
     ["*"] = ".*",
 }
 
@@ -295,6 +296,19 @@ function string:striplong() -- strips newlines and leading spaces
     return self
 end
 
+function string:topattern(lowercase,strict)
+    if lowercase then
+        self = self:lower()
+    end
+    self = gsub(self,".",simple_escapes)
+    if self == "" then
+        self = ".*"
+    elseif strict then
+        self = "^" .. self .. "$"
+    end
+    return self
+end
+
 
 end -- of closure
 
@@ -1756,59 +1770,54 @@ os.arch = os.arch or function()
     return a
 end
 
-local platform
+-- no need for function anymore as we have more clever code and helpers now
 
-function os.currentplatform(name,default)
-    if not platform then
-        local name = os.name or os.platform or name -- os.name is built in, os.platform is mine
-        if not name then
-            platform = default or "linux"
-        elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
-            if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
-                platform = "mswin-64"
-            else
-                platform = "mswin"
-            end
+os.platform  = os.name
+os.libsuffix = 'so'
+
+local name = os.name
+
+if name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
+    if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
+        os.platform = "mswin-64"
+    else
+        os.platform = "mswin"
+    end
+    os.libsuffix = 'dll'
+else
+    local architecture = os.arch()
+    if name == "linux" then
+        if find(architecture,"x86_64") then
+            os.platform = "linux-64"
+        elseif find(architecture,"ppc") then
+            os.platform = "linux-ppc"
         else
-            local architecture = os.arch()
-            if name == "linux" then
-                if find(architecture,"x86_64") then
-                    platform = "linux-64"
-                elseif find(architecture,"ppc") then
-                    platform = "linux-ppc"
-                else
-                    platform = "linux"
-                end
-            elseif name == "macosx" then
-                local architecture = os.resultof("echo $HOSTTYPE")
-                if find(architecture,"i386") then
-                    platform = "osx-intel"
-                elseif find(architecture,"x86_64") then
-                    platform = "osx-64"
-                else
-                    platform = "osx-ppc"
-                end
-            elseif name == "sunos" then
-                if find(architecture,"sparc") then
-                    platform = "solaris-sparc"
-                else -- if architecture == 'i86pc'
-                    platform = "solaris-intel"
-                end
-            elseif name == "freebsd" then
-                if find(architecture,"amd64") then
-                    platform = "freebsd-amd64"
-                else
-                    platform = "freebsd"
-                end
-            else
-                platform = default or name
-            end
+            os.platform = "linux"
+        end
+    elseif name == "macosx" then
+        local architecture = os.resultof("echo $HOSTTYPE")
+        if find(architecture,"i386") then
+            os.platform = "osx-intel"
+        elseif find(architecture,"x86_64") then
+            os.platform = "osx-64"
+        else
+            os.platform = "osx-ppc"
         end
-        function os.currentplatform()
-            return platform
+    elseif name == "sunos" then
+        if find(architecture,"sparc") then
+            os.platform = "solaris-sparc"
+        else -- if architecture == 'i86pc'
+            os.platform = "solaris-intel"
         end
+    elseif name == "freebsd" then
+        if find(architecture,"amd64") then
+            os.platform = "freebsd-amd64"
+        else
+            os.platform = "freebsd"
+        end
+    else
+        os.platform = 'linux'
     end
-    return platform
 end
 
 -- beware, we set the randomseed
@@ -2343,6 +2352,35 @@ end
 
 dir.glob_pattern = glob_pattern
 
+local function collect_pattern(path,patt,recurse,result)
+    local ok, scanner
+    result = result or { }
+    if path == "/" then
+        ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
+    else
+        ok, scanner = xpcall(function() return walkdir(path)      end, function() end) -- kepler safe
+    end
+    if ok and type(scanner) == "function" then
+        if not find(path,"/$") then path = path .. '/' end
+        for name in scanner do
+            local full = path .. name
+            local attr = attributes(full)
+            local mode = attr.mode
+            if mode == 'file' then
+                if find(full,patt) then
+                    result[name] = attr
+                end
+            elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
+                attr.list = collect_pattern(full,patt,recurse)
+                result[name] = attr
+            end
+        end
+    end
+    return result
+end
+
+dir.collect_pattern = collect_pattern
+
 local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
 
 local pattern = Ct {
@@ -3166,9 +3204,9 @@ function aux.settings_to_hash_strict(str,existing)
     end
 end
 
-local seperator = comma * space^0
+local separator = comma * space^0
 local value     = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0)
-local pattern   = lpeg.Ct(value*(seperator*value)^0)
+local pattern   = lpeg.Ct(value*(separator*value)^0)
 
 -- "aap, {noot}, mies" : outer {} removes, leading spaces ignored
 
@@ -3187,7 +3225,7 @@ local function set(t,v)
 end
 
 local value   = lpeg.P(lpeg.Carg(1)*value) / set
-local pattern = value*(seperator*value)^0 * lpeg.Carg(1)
+local pattern = value*(separator*value)^0 * lpeg.Carg(1)
 
 function aux.add_settings_to_array(t,str)
     return pattern:match(str, nil, t)
@@ -3238,6 +3276,13 @@ function aux.settings_to_set(str,t)
     return t
 end
 
+local value     = lbrace * lpeg.C((nobrace + nested)^0) * rbrace
+local pattern   = lpeg.Ct((space + value)^0)
+
+function aux.arguments_to_table(str)
+    return pattern:match(str)
+end
+
 -- temporary here
 
 function aux.getparameters(self,class,parentclass,settings)
@@ -4068,7 +4113,7 @@ end -- of closure
 
 do -- create closure to overcome 200 locals limit
 
-if not modules then modules = { } end modules ['luat-log'] = {
+if not modules then modules = { } end modules ['trac-log'] = {
     version   = 1.001,
     comment   = "companion to trac-log.mkiv",
     author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
@@ -4345,8 +4390,12 @@ end
 
 logs.simpleline = logs.reportline
 
-function logs.help(message,option)
+function logs.reportbanner() -- for scripts too
     logs.report(banner)
+end
+
+function logs.help(message,option)
+    logs.reportbanner()
     logs.reportline()
     logs.reportlines(message)
     local moreinfo = logs.moreinfo or ""
@@ -4509,6 +4558,11 @@ formats     ['sfd']                      = 'SFDFONTS'
 suffixes    ['sfd']                      = { 'sfd' }
 alternatives['subfont definition files'] = 'sfd'
 
+-- lib paths
+
+formats ['lib'] = 'CLUAINPUTS' -- new (needs checking)
+suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' }
+
 -- In practice we will work within one tds tree, but i want to keep
 -- the option open to build tools that look at multiple trees, which is
 -- why we keep the tree specific data in a table. We used to pass the
@@ -5728,9 +5782,9 @@ end
 function resolvers.expanded_path_list_from_var(str) -- brrr
     local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$",""))
     if tmp ~= "" then
-        return resolvers.expanded_path_list(str)
-    else
         return resolvers.expanded_path_list(tmp)
+    else
+        return resolvers.expanded_path_list(str)
     end
 end
 
diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun
index a1fc6eaf5..c5b0acd04 100755
--- a/scripts/context/stubs/unix/mtxrun
+++ b/scripts/context/stubs/unix/mtxrun
@@ -242,6 +242,7 @@ end
 local simple_escapes = {
     ["-"] = "%-",
     ["."] = "%.",
+    ["?"] = ".",
     ["*"] = ".*",
 }
 
@@ -304,6 +305,19 @@ function string:striplong() -- strips newlines and leading spaces
     return self
 end
 
+function string:topattern(lowercase,strict)
+    if lowercase then
+        self = self:lower()
+    end
+    self = gsub(self,".",simple_escapes)
+    if self == "" then
+        self = ".*"
+    elseif strict then
+        self = "^" .. self .. "$"
+    end
+    return self
+end
+
 
 end -- of closure
 
@@ -1765,59 +1779,54 @@ os.arch = os.arch or function()
     return a
 end
 
-local platform
+-- no need for function anymore as we have more clever code and helpers now
 
-function os.currentplatform(name,default)
-    if not platform then
-        local name = os.name or os.platform or name -- os.name is built in, os.platform is mine
-        if not name then
-            platform = default or "linux"
-        elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
-            if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
-                platform = "mswin-64"
-            else
-                platform = "mswin"
-            end
+os.platform  = os.name
+os.libsuffix = 'so'
+
+local name = os.name
+
+if name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
+    if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
+        os.platform = "mswin-64"
+    else
+        os.platform = "mswin"
+    end
+    os.libsuffix = 'dll'
+else
+    local architecture = os.arch()
+    if name == "linux" then
+        if find(architecture,"x86_64") then
+            os.platform = "linux-64"
+        elseif find(architecture,"ppc") then
+            os.platform = "linux-ppc"
         else
-            local architecture = os.arch()
-            if name == "linux" then
-                if find(architecture,"x86_64") then
-                    platform = "linux-64"
-                elseif find(architecture,"ppc") then
-                    platform = "linux-ppc"
-                else
-                    platform = "linux"
-                end
-            elseif name == "macosx" then
-                local architecture = os.resultof("echo $HOSTTYPE")
-                if find(architecture,"i386") then
-                    platform = "osx-intel"
-                elseif find(architecture,"x86_64") then
-                    platform = "osx-64"
-                else
-                    platform = "osx-ppc"
-                end
-            elseif name == "sunos" then
-                if find(architecture,"sparc") then
-                    platform = "solaris-sparc"
-                else -- if architecture == 'i86pc'
-                    platform = "solaris-intel"
-                end
-            elseif name == "freebsd" then
-                if find(architecture,"amd64") then
-                    platform = "freebsd-amd64"
-                else
-                    platform = "freebsd"
-                end
-            else
-                platform = default or name
-            end
+            os.platform = "linux"
+        end
+    elseif name == "macosx" then
+        local architecture = os.resultof("echo $HOSTTYPE")
+        if find(architecture,"i386") then
+            os.platform = "osx-intel"
+        elseif find(architecture,"x86_64") then
+            os.platform = "osx-64"
+        else
+            os.platform = "osx-ppc"
         end
-        function os.currentplatform()
-            return platform
+    elseif name == "sunos" then
+        if find(architecture,"sparc") then
+            os.platform = "solaris-sparc"
+        else -- if architecture == 'i86pc'
+            os.platform = "solaris-intel"
         end
+    elseif name == "freebsd" then
+        if find(architecture,"amd64") then
+            os.platform = "freebsd-amd64"
+        else
+            os.platform = "freebsd"
+        end
+    else
+        os.platform = 'linux'
     end
-    return platform
 end
 
 -- beware, we set the randomseed
@@ -2241,6 +2250,35 @@ end
 
 dir.glob_pattern = glob_pattern
 
+local function collect_pattern(path,patt,recurse,result)
+    local ok, scanner
+    result = result or { }
+    if path == "/" then
+        ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
+    else
+        ok, scanner = xpcall(function() return walkdir(path)      end, function() end) -- kepler safe
+    end
+    if ok and type(scanner) == "function" then
+        if not find(path,"/$") then path = path .. '/' end
+        for name in scanner do
+            local full = path .. name
+            local attr = attributes(full)
+            local mode = attr.mode
+            if mode == 'file' then
+                if find(full,patt) then
+                    result[name] = attr
+                end
+            elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
+                attr.list = collect_pattern(full,patt,recurse)
+                result[name] = attr
+            end
+        end
+    end
+    return result
+end
+
+dir.collect_pattern = collect_pattern
+
 local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
 
 local pattern = Ct {
@@ -7264,6 +7302,11 @@ formats     ['sfd']                      = 'SFDFONTS'
 suffixes    ['sfd']                      = { 'sfd' }
 alternatives['subfont definition files'] = 'sfd'
 
+-- lib paths
+
+formats ['lib'] = 'CLUAINPUTS' -- new (needs checking)
+suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' }
+
 -- In practice we will work within one tds tree, but i want to keep
 -- the option open to build tools that look at multiple trees, which is
 -- why we keep the tree specific data in a table. We used to pass the
@@ -8483,9 +8526,9 @@ end
 function resolvers.expanded_path_list_from_var(str) -- brrr
     local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$",""))
     if tmp ~= "" then
-        return resolvers.expanded_path_list(str)
-    else
         return resolvers.expanded_path_list(tmp)
+    else
+        return resolvers.expanded_path_list(str)
     end
 end
 
@@ -9473,6 +9516,16 @@ prefixes.full = prefixes.locate
 prefixes.file = prefixes.filename
 prefixes.path = prefixes.pathname
 
+function resolvers.allprefixes(separator)
+    local all = table.sortedkeys(prefixes)
+    if separator then
+        for i=1,#all do
+            all[i] = all[i] .. ":"
+        end
+    end
+    return all
+end
+
 local function _resolve_(method,target)
     if prefixes[method] then
         return prefixes[method](target)
@@ -10130,43 +10183,109 @@ local trace_locating = false  trackers.register("resolvers.locating", function(v
 
 local gsub = string.gsub
 
-local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' }
-local libpaths   = file.split_path(package.path)
+local  libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } -- 'luainputs'
+local clibformats = { 'lib' }
+local  libpaths   = file.split_path(package.path)
+local clibpaths   = file.split_path(package.cpath)
+
+local function thepath(...)
+    local t = { ... } t[#t+1] = "?.lua"
+    local path = file.join(unpack(t))
+    if trace_locating then
+        logs.report("fileio","! appending '%s' to 'package.path'",path)
+    end
+    return path
+end
+
+function package.append_libpath(...)
+    table.insert(libpaths,thepath(...))
+end
+
+function package.prepend_libpath(...)
+    table.insert(libpaths,1,thepath(...))
+end
+
+-- beware, we need to return a loadfile result !
 
 package.loaders[2] = function(name) -- was [#package.loaders+1]
---~ package.loaders[#package.loaders+1] = function(name) -- was
+    if trace_locating then -- mode detail
+        logs.report("fileio","! locating '%s'",name)
+    end
     for i=1,#libformats do
         local format = libformats[i]
         local resolved = resolvers.find_file(name,format) or ""
+        if trace_locating then -- mode detail
+            logs.report("fileio","! checking for '%s' using 'libformat path': '%s'",name,format)
+        end
         if resolved ~= "" then
             if trace_locating then
                 logs.report("fileio","! lib '%s' located via environment: '%s'",name,resolved)
             end
-            return function() return dofile(resolved) end
+            return loadfile(resolved)
         end
     end
-    local simple = file.removesuffix(name)
+    local simple = gsub(name,"%.lua$","")
+    local simple = gsub(simple,"%.","/")
     for i=1,#libpaths do -- package.path, might become option
-        local resolved = gsub(libpaths[i],"?",simple)
+        local libpath = libpaths[i]
+        local resolved = gsub(libpath,"?",simple)
+        if trace_locating then -- more detail
+            logs.report("fileio","! checking for '%s' on 'package.path': '%s'",simple,libpath)
+        end
         if resolvers.isreadable.file(resolved) then
             if trace_locating then
                 logs.report("fileio","! lib '%s' located via 'package.path': '%s'",name,resolved)
             end
-            return function() return dofile(resolved) end
+            return loadfile(resolved)
+        end
+    end
+    local libname = file.addsuffix(simple,os.libsuffix)
+    for i=1,#clibformats do
+        -- better have a dedicated loop
+        local format = clibformats[i]
+        local paths = resolvers.expanded_path_list_from_var(format)
+        for p=1,#paths do
+            local path = paths[p]
+            local resolved = file.join(path,libname)
+            if trace_locating then -- mode detail
+                logs.report("fileio","! checking for '%s' using 'clibformat path': '%s'",libname,path)
+            end
+            if resolvers.isreadable.file(resolved) then
+                if trace_locating then
+                    logs.report("fileio","! lib '%s' located via 'clibformat': '%s'",libname,resolved)
+                end
+                return package.loadlib(resolved,name)
+            end
+        end
+    end
+    for i=1,#clibpaths do -- package.path, might become option
+        local libpath = clibpaths[i]
+        local resolved = gsub(libpath,"?",simple)
+        if trace_locating then -- more detail
+            logs.report("fileio","! checking for '%s' on 'package.cpath': '%s'",simple,libpath)
+        end
+        if resolvers.isreadable.file(resolved) then
+            if trace_locating then
+                logs.report("fileio","! lib '%s' located via 'package.cpath': '%s'",name,resolved)
+            end
+            return package.loadlib(resolved,name)
         end
     end
     -- just in case the distribution is messed up
+    if trace_loading then -- more detail
+        logs.report("fileio","! checking for '%s' using 'luatexlibs': '%s'",name)
+    end
     local resolved = resolvers.find_file(file.basename(name),'luatexlibs') or ""
     if resolved ~= "" then
         if trace_locating then
             logs.report("fileio","! lib '%s' located by basename via environment: '%s'",name,resolved)
         end
-        return function() return dofile(resolved) end
+        return loadfile(resolved)
     end
     if trace_locating then
         logs.report("fileio",'? unable to locate lib: %s',name)
     end
-    return "unable to locate " .. name
+--  return "unable to locate " .. name
 end
 
 resolvers.loadlualib = require
@@ -10359,7 +10478,7 @@ if not modules then modules = { } end modules ['data-tmf'] = {
 function resolvers.check_environment(tree)
     logs.simpleline()
     os.setenv('TMP', os.getenv('TMP') or os.getenv('TEMP') or os.getenv('TMPDIR') or os.getenv('HOME'))
-    os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.currentplatform()))
+    os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.platform))
     os.setenv('TEXPATH', (tree or "tex"):gsub("\/+$",''))
     os.setenv('TEXMFOS', os.getenv('TEXPATH') .. "/" .. os.getenv('TEXOS'))
     logs.simpleline()
@@ -10723,10 +10842,11 @@ runners  = runners  or { } -- global
 messages = messages or { }
 
 messages.help = [[
---script              run an mtx script (--noquotes), no script gives list
---execute             run a script or program (--noquotes)
+--script              run an mtx script (lua prefered method) (--noquotes), no script gives list
+--execute             run a script or program (texmfstart method) (--noquotes)
 --resolve             resolve prefixed arguments
 --ctxlua              run internally (using preloaded libs)
+--internal            run script using built in libraries (same as --ctxlua)
 --locate              locate given filename
 
 --autotree            use texmf tree cf. env 'texmfstart_tree' or 'texmfstarttree'
@@ -10750,11 +10870,13 @@ messages.help = [[
 --edit                launch editor with found file
 --launch (--all)      launch files like manuals, assumes os support
 
---internal            run script using built in libraries (same as --ctxlua)
 --timedrun            run a script an time its run
+--autogenerate        regenerate databases if needed (handy when used to run context in an editor)
 
 --usekpse             use kpse as fallback (when no mkiv and cache installed, often slower)
 --forcekpse           force using kpse (handy when no mkiv and cache installed but less functionality)
+
+--prefixes            show supported prefixes
 ]]
 
 runners.applications = {
@@ -10800,6 +10922,13 @@ runners.launchers = {
     unix = { }
 }
 
+-- like runners.libpath("framework"): looks on script's subpath
+
+function runners.libpath(...)
+    package.prepend_libpath(file.dirname(environment.ownscript),...)
+    package.prepend_libpath(file.dirname(environment.ownname)  ,...)
+end
+
 function runners.prepare()
     local checkname = environment.argument("ifchanged")
     if checkname and checkname ~= "" then
@@ -10890,6 +11019,7 @@ function runners.execute_script(fullname,internal,nosplit)
                 end
                 if internal then
                     arg = { } for _,v in pairs(environment.arguments_after) do arg[#arg+1] = v end
+                    environment.ownscript = result
                     dofile(result)
                 else
                     local binary = runners.applications[file.extname(result)]
@@ -10993,7 +11123,7 @@ function runners.locate_file(filename)
 end
 
 function runners.locate_platform()
-    runners.report_location(os.currentplatform())
+    runners.report_location(os.platform)
 end
 
 function runners.report_location(result)
@@ -11170,6 +11300,7 @@ function runners.execute_ctx_script(filename)
             if logs.verbose then
                 logs.simple("using script: %s\n",fullname)
             end
+            environment.ownscript = fullname
             dofile(fullname)
             local savename = environment.arguments['save']
             if savename and runners.save_list and not table.is_empty(runners.save_list or { }) then
@@ -11222,6 +11353,11 @@ function runners.execute_ctx_script(filename)
     end
 end
 
+function runners.prefixes()
+    logs.reportbanner()
+    logs.reportline()
+    logs.simple(table.concat(resolvers.allprefixes(true)," "))
+end
 
 function runners.timedrun(filename) -- just for me
     if filename and filename ~= "" then
@@ -11337,7 +11473,7 @@ elseif environment.argument("selfupdate") then
 elseif environment.argument("ctxlua") or environment.argument("internal") then
     -- run a script by loading it (using libs)
     ok = runners.execute_script(filename,true)
-elseif environment.argument("script") or environment.argument("s") then
+elseif environment.argument("script") or environment.argument("s") or environment.argument("scripts") then
     -- run a script by loading it (using libs), pass args
     ok = runners.execute_ctx_script(filename)
 elseif environment.argument("execute") then
@@ -11366,6 +11502,8 @@ elseif environment.argument("locate") then
 elseif environment.argument("platform")then
     -- locate platform
     runners.locate_platform()
+elseif environment.argument("prefixes") then
+    runners.prefixes()
 elseif environment.argument("timedrun") then
     -- locate platform
     runners.timedrun(filename)
@@ -11375,9 +11513,9 @@ elseif environment.argument("help") or filename=='help' or filename == "" then
 elseif filename:find("^bin:") then
     ok = runners.execute_program(filename)
 else
-    ok = runners.execute_script(filename)
+    ok = runners.execute_ctx_script(filename)
     if not ok then
-        ok = runners.execute_ctx_script(filename)
+        ok = runners.execute_script(filename)
     end
 end
 
diff --git a/tex/context/base/attr-ini.mkiv b/tex/context/base/attr-ini.mkiv
index 49a109e7d..b04282fb8 100644
--- a/tex/context/base/attr-ini.mkiv
+++ b/tex/context/base/attr-ini.mkiv
@@ -50,6 +50,7 @@
 \definesystemattribute[reference]                              \chardef\referenceattribute      \dogetattributeid{reference}
 \definesystemattribute[destination]                            \chardef\destinationattribute    \dogetattributeid{destination}
 \definesystemattribute[graphicvadjust]                         \chardef\graphicvadjustattribute \dogetattributeid{graphicvadjust}
+\definesystemattribute[ruled]                                  \chardef\ruledattribute          \dogetattributeid{ruled}
 
 % \definesystemattribute[ignore]
 %
diff --git a/tex/context/base/bibl-tra.mkiv b/tex/context/base/bibl-tra.mkiv
index 9648c068a..29a687025 100644
--- a/tex/context/base/bibl-tra.mkiv
+++ b/tex/context/base/bibl-tra.mkiv
@@ -288,7 +288,8 @@
         {\showmessage\m!publications{1}{bibl-\@@pbalternative}}%
       \let\@@pbalternative\empty}%
    \getparameters[\??pb][#1]% as bibl-* can have set things back
-   \the\everysetuppublications}
+   \the\everysetuppublications
+   \ignorespaces}
 
 %D We can omit already shown references (\v!global) or use fresh
 %D lists each time (\v!local).
@@ -334,11 +335,25 @@
 \def\usepublications[#1]%
   {\processcommalist[#1]\dousepublications}
 
+% \def\dousepublications#1%
+%   {\doonlyonce{#1.\f!bibextension}
+%      {\readfile{#1.\f!bibextension}
+%         {\showmessage\m!publications{4}{#1.\f!bibextension}}
+%         {\showmessage\m!publications{2}{#1.\f!bibextension}}}}
+
 \def\dousepublications#1%
-  {\doonlyonce{#1.\f!bibextension}
-     {\readfile{#1.\f!bibextension}
-        {\showmessage\m!publications{4}{#1.\f!bibextension}}
-        {\showmessage\m!publications{2}{#1.\f!bibextension}}}}
+  {\doonlyonce{#1.\f!bibextension}{\dodousepublications{#1}}}
+
+\def\dodousepublications#1%
+  {\let\@@savedpar\par
+   \let\par\ignorespaces
+   \ifhmode\kern\zeropoint\fi
+   \readfile{#1.\f!bibextension}
+     {\showmessage\m!publications{4}{#1.\f!bibextension}}
+     {\showmessage\m!publications{2}{#1.\f!bibextension}}%
+   \ifhmode\removeunwantedspaces\fi
+   \let\par\@@savedpar}
+
 
 %D \macros{setuppublicationlist}
 %D
@@ -740,7 +755,8 @@
      \@@pbo\noexpand\or
      \@@pbu\noexpand\or
      \normalunexpanded{#2}\noexpand\fi}%
-   \endgroup}
+   \endgroup
+   \ignorespaces}
 
 \def\bibgetvark#1{\csname pbd:#1\endcsname\plusone  }
 \def\bibgetvara#1{\csname pbd:#1\endcsname\plustwo  }
diff --git a/tex/context/base/colo-ini.mkiv b/tex/context/base/colo-ini.mkiv
index cde9f5820..68636a23c 100644
--- a/tex/context/base/colo-ini.mkiv
+++ b/tex/context/base/colo-ini.mkiv
@@ -159,6 +159,25 @@
 
 \let\grey\graycolor
 
+%D Stacking:
+
+% \colormodelattribute \colorattribute \transparencyattribute
+
+\newcount\currentcolornesting
+
+\unexpanded\def\pushcolor[#1]%
+  {\global\advance\currentcolornesting\plusone
+   \expandafter\edef\csname\??cl:s:\number\currentcolornesting\endcsname
+     {\attribute\colormodelattribute  \the\colormodelattribute
+      \attribute\colorattribute       \the\colorattribute
+      \attribute\transparencyattribute\the\transparencyattribute
+      \space}% stack
+   \doactivatecolor{#1}}
+
+\unexpanded\def\popcolor
+  {\csname\??on:s:\number\currentcolornesting\endcsname
+   \global\advance\currentcolornesting\minusone}
+
 %D \macros
 %D   {startcurrentcolor,stopcurrentcolor}
 
diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv
index 93a1c17c2..fb5112020 100644
--- a/tex/context/base/cont-new.mkiv
+++ b/tex/context/base/cont-new.mkiv
@@ -29,6 +29,8 @@
 
 \unprotect
 
+\def\immediatemessage#1{\ctxlua{commands.writestatus("message","#1")}}
+
 % % % % % % needs testing but saves runtime
 
 \let\checknotes\relax % probably not needed, checking already done
diff --git a/tex/context/base/cont-new.tex b/tex/context/base/cont-new.tex
index 67d2d13ac..0ffa84f19 100644
--- a/tex/context/base/cont-new.tex
+++ b/tex/context/base/cont-new.tex
@@ -11,7 +11,7 @@
 %C therefore copyrighted by \PRAGMA. See mreadme.pdf for
 %C details.
 
-\newcontextversion{2009.12.01 17:09}
+\newcontextversion{2009.12.13 23:27}
 
 %D This file is loaded at runtime, thereby providing an
 %D excellent place for hacks, patches, extensions and new
diff --git a/tex/context/base/context-base.lmx b/tex/context/base/context-base.lmx
index 5c96b4979..e84202cb3 100644
--- a/tex/context/base/context-base.lmx
+++ b/tex/context/base/context-base.lmx
@@ -14,25 +14,62 @@
     <head>
         <title><?lua pv('title') ?></title>
         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <?lua if (v('refreshtime') and (tonumber(v('refreshtime')) or 0) > 0) and v('refreshurl') then ?>
+            <meta http-equiv='refresh' content="<?lua pv('refreshtime') ?>; <?lua pv('refreshurl') ?>"/>
+        <?lua end ?>
         <style type="text/css">
             <?lmx-include context.css ?>
         </style>
     </head>
+    <?lua if v('action') then ?>
+        <form action="<?lua pv(action) ?>" enctype="multi-part/form-data" method="post">
+    <?lua end ?>
     <body>
-        <div id="top"><div id="top-one"><div id="top-two">
-            <?lua pv('title') ?>
-        </div></div></div>
-        <div id="left"><div id="left-one"><div id="left-two">
-            <?lua pv('lefttext') ?>
-        </div></div></div>
-        <div id="right"><div id="right-safari"><div id="right-one"><div id="right-two"><div id="right-three"><div id="right-four"><div id="right-five">
-            <?lua pv('righttext') ?>
-        </div></div></div></div></div></div></div>
-        <div id="main"><div id='main-settings'>
-            <div class='title'><?lua pv('maintext') ?></div>
-        </div></div>
-        <div id="bottom"><div id="bottom-one"><div id="bottom-two">
-            <?lua pv('bottomtext') ?>
-        </div></div></div>
+        <div id="top">
+            <div id="top-one">
+                <div id="top-two">
+                    <?lua pv('title') ?>
+                </div>
+            </div>
+        </div>
+        <div id="bottom">
+            <div id="bottom-one">
+                <div id="bottom-two">
+                    <?lua pv('bottomtext') ?>
+                </div>
+            </div>
+        </div>
+        <div id="left">
+            <div id="left-one">
+                <div id="left-two">
+                    <?lua pv('lefttext') ?>
+                </div>
+            </div>
+        </div>
+        <div id="right">
+            <div id="right-safari">
+                <div id="right-one">
+                    <div id="right-two">
+                        <div id="right-three">
+                            <div id="right-four">
+                                <div id="right-five">
+                                    <?lua pv('righttext') ?>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div id="main">
+            <div id='main-settings'>
+                <div class='title'>
+                    <?lua pv('maintext') ?>
+                </div>
+            </div>
+        </div>
     </body>
+    <?lua if v('action') then ?>
+        </form>
+    <?lua end ?>
 </html>
diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv
index 347beb0b3..51f5d92d4 100644
--- a/tex/context/base/context.mkiv
+++ b/tex/context/base/context.mkiv
@@ -20,8 +20,8 @@
 
 \loadcorefile{syst-ini}
 
-\ifnum\luatexversion<43 % also change message
-    \writestatus{!!!!}{Your luatex binary is way too old, you need at least version 0.43!}
+\ifnum\luatexversion<47 % also change message
+    \writestatus{!!!!}{Your luatex binary is too old, you need at least version 0.47!}
     \expandafter\end
 \fi
 
diff --git a/tex/context/base/context.tex b/tex/context/base/context.tex
index 9c9b58f83..d6a4d6897 100644
--- a/tex/context/base/context.tex
+++ b/tex/context/base/context.tex
@@ -20,7 +20,7 @@
 %D your styles an modules.
 
 \edef\contextformat {\jobname}
-\edef\contextversion{2009.12.01 17:09}
+\edef\contextversion{2009.12.13 23:27}
 
 %D For those who want to use this:
 
diff --git a/tex/context/base/core-job.mkiv b/tex/context/base/core-job.mkiv
index 4333b3c69..71d4e4d30 100644
--- a/tex/context/base/core-job.mkiv
+++ b/tex/context/base/core-job.mkiv
@@ -124,7 +124,8 @@
 \def\stoptext
   {\global\advance\textlevel\minusone
    \ifnum\textlevel>\zerocount \else
-     \page[\v!last]\page % new, moved from everybye to here; flushes headers, colors etc etc etc
+     \flushfinallayoutpage % optional
+     \page % anyway
      \the\everystoptext
     %\the\everybye            %
     %\the\everygoodbye        % == \end (new)
diff --git a/tex/context/base/data-lua.lua b/tex/context/base/data-lua.lua
index d7f6fdcf5..3005d5176 100644
--- a/tex/context/base/data-lua.lua
+++ b/tex/context/base/data-lua.lua
@@ -14,43 +14,109 @@ local trace_locating = false  trackers.register("resolvers.locating", function(v
 
 local gsub = string.gsub
 
-local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' }
-local libpaths   = file.split_path(package.path)
+local  libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } -- 'luainputs'
+local clibformats = { 'lib' }
+local  libpaths   = file.split_path(package.path)
+local clibpaths   = file.split_path(package.cpath)
+
+local function thepath(...)
+    local t = { ... } t[#t+1] = "?.lua"
+    local path = file.join(unpack(t))
+    if trace_locating then
+        logs.report("fileio","! appending '%s' to 'package.path'",path)
+    end
+    return path
+end
+
+function package.append_libpath(...)
+    table.insert(libpaths,thepath(...))
+end
+
+function package.prepend_libpath(...)
+    table.insert(libpaths,1,thepath(...))
+end
+
+-- beware, we need to return a loadfile result !
 
 package.loaders[2] = function(name) -- was [#package.loaders+1]
---~ package.loaders[#package.loaders+1] = function(name) -- was
+    if trace_locating then -- mode detail
+        logs.report("fileio","! locating '%s'",name)
+    end
     for i=1,#libformats do
         local format = libformats[i]
         local resolved = resolvers.find_file(name,format) or ""
+        if trace_locating then -- mode detail
+            logs.report("fileio","! checking for '%s' using 'libformat path': '%s'",name,format)
+        end
         if resolved ~= "" then
             if trace_locating then
                 logs.report("fileio","! lib '%s' located via environment: '%s'",name,resolved)
             end
-            return function() return dofile(resolved) end
+            return loadfile(resolved)
         end
     end
-    local simple = file.removesuffix(name)
+    local simple = gsub(name,"%.lua$","")
+    local simple = gsub(simple,"%.","/")
     for i=1,#libpaths do -- package.path, might become option
-        local resolved = gsub(libpaths[i],"?",simple)
+        local libpath = libpaths[i]
+        local resolved = gsub(libpath,"?",simple)
+        if trace_locating then -- more detail
+            logs.report("fileio","! checking for '%s' on 'package.path': '%s'",simple,libpath)
+        end
         if resolvers.isreadable.file(resolved) then
             if trace_locating then
                 logs.report("fileio","! lib '%s' located via 'package.path': '%s'",name,resolved)
             end
-            return function() return dofile(resolved) end
+            return loadfile(resolved)
+        end
+    end
+    local libname = file.addsuffix(simple,os.libsuffix)
+    for i=1,#clibformats do
+        -- better have a dedicated loop
+        local format = clibformats[i]
+        local paths = resolvers.expanded_path_list_from_var(format)
+        for p=1,#paths do
+            local path = paths[p]
+            local resolved = file.join(path,libname)
+            if trace_locating then -- mode detail
+                logs.report("fileio","! checking for '%s' using 'clibformat path': '%s'",libname,path)
+            end
+            if resolvers.isreadable.file(resolved) then
+                if trace_locating then
+                    logs.report("fileio","! lib '%s' located via 'clibformat': '%s'",libname,resolved)
+                end
+                return package.loadlib(resolved,name)
+            end
+        end
+    end
+    for i=1,#clibpaths do -- package.path, might become option
+        local libpath = clibpaths[i]
+        local resolved = gsub(libpath,"?",simple)
+        if trace_locating then -- more detail
+            logs.report("fileio","! checking for '%s' on 'package.cpath': '%s'",simple,libpath)
+        end
+        if resolvers.isreadable.file(resolved) then
+            if trace_locating then
+                logs.report("fileio","! lib '%s' located via 'package.cpath': '%s'",name,resolved)
+            end
+            return package.loadlib(resolved,name)
         end
     end
     -- just in case the distribution is messed up
+    if trace_loading then -- more detail
+        logs.report("fileio","! checking for '%s' using 'luatexlibs': '%s'",name)
+    end
     local resolved = resolvers.find_file(file.basename(name),'luatexlibs') or ""
     if resolved ~= "" then
         if trace_locating then
             logs.report("fileio","! lib '%s' located by basename via environment: '%s'",name,resolved)
         end
-        return function() return dofile(resolved) end
+        return loadfile(resolved)
     end
     if trace_locating then
         logs.report("fileio",'? unable to locate lib: %s',name)
     end
-    return "unable to locate " .. name
+--  return "unable to locate " .. name
 end
 
 resolvers.loadlualib = require
diff --git a/tex/context/base/data-pre.lua b/tex/context/base/data-pre.lua
index 26843d21c..9936cd508 100644
--- a/tex/context/base/data-pre.lua
+++ b/tex/context/base/data-pre.lua
@@ -66,6 +66,16 @@ prefixes.full = prefixes.locate
 prefixes.file = prefixes.filename
 prefixes.path = prefixes.pathname
 
+function resolvers.allprefixes(separator)
+    local all = table.sortedkeys(prefixes)
+    if separator then
+        for i=1,#all do
+            all[i] = all[i] .. ":"
+        end
+    end
+    return all
+end
+
 local function _resolve_(method,target)
     if prefixes[method] then
         return prefixes[method](target)
diff --git a/tex/context/base/data-res.lua b/tex/context/base/data-res.lua
index 4305d0bed..d15046e80 100644
--- a/tex/context/base/data-res.lua
+++ b/tex/context/base/data-res.lua
@@ -124,6 +124,11 @@ formats     ['sfd']                      = 'SFDFONTS'
 suffixes    ['sfd']                      = { 'sfd' }
 alternatives['subfont definition files'] = 'sfd'
 
+-- lib paths
+
+formats ['lib'] = 'CLUAINPUTS' -- new (needs checking)
+suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' }
+
 -- In practice we will work within one tds tree, but i want to keep
 -- the option open to build tools that look at multiple trees, which is
 -- why we keep the tree specific data in a table. We used to pass the
@@ -1343,9 +1348,9 @@ end
 function resolvers.expanded_path_list_from_var(str) -- brrr
     local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$",""))
     if tmp ~= "" then
-        return resolvers.expanded_path_list(str)
-    else
         return resolvers.expanded_path_list(tmp)
+    else
+        return resolvers.expanded_path_list(str)
     end
 end
 
diff --git a/tex/context/base/data-tmf.lua b/tex/context/base/data-tmf.lua
index 4ba8c388d..e02f7f866 100644
--- a/tex/context/base/data-tmf.lua
+++ b/tex/context/base/data-tmf.lua
@@ -11,7 +11,7 @@ if not modules then modules = { } end modules ['data-tmf'] = {
 function resolvers.check_environment(tree)
     logs.simpleline()
     os.setenv('TMP', os.getenv('TMP') or os.getenv('TEMP') or os.getenv('TMPDIR') or os.getenv('HOME'))
-    os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.currentplatform()))
+    os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.platform))
     os.setenv('TEXPATH', (tree or "tex"):gsub("\/+$",''))
     os.setenv('TEXMFOS', os.getenv('TEXPATH') .. "/" .. os.getenv('TEXOS'))
     logs.simpleline()
diff --git a/tex/context/base/font-syn.lua b/tex/context/base/font-syn.lua
index b59f1f6e8..c331d6065 100644
--- a/tex/context/base/font-syn.lua
+++ b/tex/context/base/font-syn.lua
@@ -651,6 +651,29 @@ local function analysefiles()
     data.statistics.readfiles, data.statistics.skippedfiles = totalnofread, totalnofskipped
 end
 
+local function rejectclashes() -- just to be sure, so no explicit afm will be found then
+    local specifications, used, okay = names.data.specifications, { }, { }
+    for i=1,#specifications do
+        local s = specifications[i]
+        local f = s.fontname
+        if f then
+            local fnd, fnm = used[f], s.filename
+            if fnd then
+                logs.report("fontnames", "fontname '%s' clashes, rejecting '%s' in favor of '%s'",f,fnm,fnd)
+            else
+                used[f], okay[#okay+1] = fnm, s
+            end
+        else
+            okay[#okay+1] = s
+        end
+    end
+    local d = #specifications - #okay
+    if d > 0 then
+        logs.report("fontnames", "%s files rejected due to clashes",d)
+    end
+    names.data.specifications = okay
+end
+
 local function resetdata()
     local mappings, fallbacks = { }, { }
     for _, k in next, filters.list do
@@ -670,12 +693,12 @@ end
 function names.identify()
     resetdata()
     analysefiles()
+    rejectclashes()
     collectstatistics()
     cleanupkeywords()
     collecthashes()
     checkduplicates()
  -- sorthashes() -- will be resorted when saved
-
  --~     logs.report("fontnames", "%s files read, %s normal and %s extra entries added, %s rejected, %s valid",totalread,totalok,added,rejected,totalok+added-rejected)
 end
 
@@ -838,7 +861,7 @@ local function foundname(name,sub)
     end
 end
 
-function names.resolve(askedname,sub)
+function names.resolvedspecification(askedname,sub)
     if askedname and askedname ~= "" and names.enabled then
         askedname = cleanname(askedname)
         names.load()
@@ -846,9 +869,14 @@ function names.resolve(askedname,sub)
         if not found and is_reloaded() then
             found = foundname(askedname,sub)
         end
-        if found then
-            return found.filename, found.subfont and found.rawname
-        end
+        return found
+    end
+end
+
+function names.resolve(askedname,sub)
+    local found = names.resolvedspecification(askedname,sub)
+    if found then
+        return found.filename, found.subfont and found.rawname
     end
 end
 
diff --git a/tex/context/base/grph-inc.lua b/tex/context/base/grph-inc.lua
index ff8a78f0f..25adcead5 100644
--- a/tex/context/base/grph-inc.lua
+++ b/tex/context/base/grph-inc.lua
@@ -666,6 +666,7 @@ function figures.includers.generic(data)
     end
     if figure then
         local n = figures.boxnumber
+        -- it looks like we have a leak in attributes here .. todo
         tex.box[n] = node.hpack(img.node(figure))
      -- tex.box[n] = img.node(figure) -- img.write(figure) -- assigning img.node directly no longer valid
         tex.wd[n], tex.ht[n], tex.dp[n] = figure.width, figure.height, 0 -- new, hm, tricky, we need to do that in tex (yet)
diff --git a/tex/context/base/l-dir.lua b/tex/context/base/l-dir.lua
index db0737e5b..7ee565b30 100644
--- a/tex/context/base/l-dir.lua
+++ b/tex/context/base/l-dir.lua
@@ -41,6 +41,35 @@ end
 
 dir.glob_pattern = glob_pattern
 
+local function collect_pattern(path,patt,recurse,result)
+    local ok, scanner
+    result = result or { }
+    if path == "/" then
+        ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
+    else
+        ok, scanner = xpcall(function() return walkdir(path)      end, function() end) -- kepler safe
+    end
+    if ok and type(scanner) == "function" then
+        if not find(path,"/$") then path = path .. '/' end
+        for name in scanner do
+            local full = path .. name
+            local attr = attributes(full)
+            local mode = attr.mode
+            if mode == 'file' then
+                if find(full,patt) then
+                    result[name] = attr
+                end
+            elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
+                attr.list = collect_pattern(full,patt,recurse)
+                result[name] = attr
+            end
+        end
+    end
+    return result
+end
+
+dir.collect_pattern = collect_pattern
+
 local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
 
 local pattern = Ct {
diff --git a/tex/context/base/l-lpeg.lua b/tex/context/base/l-lpeg.lua
index afe941e9d..d1e0dfafb 100644
--- a/tex/context/base/l-lpeg.lua
+++ b/tex/context/base/l-lpeg.lua
@@ -6,6 +6,8 @@ if not modules then modules = { } end modules ['l-lpeg'] = {
     license   = "see context related readme files"
 }
 
+lpeg = require("lpeg")
+
 local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
 
 --~ l-lpeg.lua :
diff --git a/tex/context/base/l-os.lua b/tex/context/base/l-os.lua
index db8795253..dcf8d3e95 100644
--- a/tex/context/base/l-os.lua
+++ b/tex/context/base/l-os.lua
@@ -70,67 +70,74 @@ end
 --~ print(os.date("%H:%M:%S",os.gettimeofday()))
 --~ print(os.date("%H:%M:%S",os.time()))
 
-os.arch = os.arch or function()
-    local a = os.resultof("uname -m") or "linux"
+if os.arch then
+    -- okay
+elseif os.platform == "windows" then
     os.arch = function()
+        local a = os.getenv("PROCESSOR_ARCHITECTURE") or "x86"
+        os.arch = function()
+            return a
+        end
+        return a
+    end
+else
+    os.arch = function()
+        local a = os.getenv("PROCESSOR_ARCHITECTURE") or os.resultof("uname -m") or "x86"
+        os.arch = function()
+            return a
+        end
         return a
     end
-    return a
 end
 
-local platform
-
-function os.currentplatform(name,default)
-    if not platform then
-        local name = os.name or os.platform or name -- os.name is built in, os.platform is mine
-        if not name then
-            platform = default or "linux"
-        elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
-            if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
-                platform = "mswin-64"
-            else
-                platform = "mswin"
-            end
+-- no need for function anymore as we have more clever code and helpers now
+
+os.platform  = os.name
+os.libsuffix = 'so'
+
+local name = os.name
+
+if name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
+    if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
+        os.platform = "mswin-64"
+    else
+        os.platform = "mswin"
+    end
+    os.libsuffix = 'dll'
+else
+    local architecture = os.arch()
+    if name == "linux" then
+        if find(architecture,"x86_64") then
+            os.platform = "linux-64"
+        elseif find(architecture,"ppc") then
+            os.platform = "linux-ppc"
+        else
+            os.platform = "linux"
+        end
+    elseif name == "macosx" then
+        local architecture = os.resultof("echo $HOSTTYPE")
+        if find(architecture,"i386") then
+            os.platform = "osx-intel"
+        elseif find(architecture,"x86_64") then
+            os.platform = "osx-64"
         else
-            local architecture = os.arch()
-            if name == "linux" then
-                if find(architecture,"x86_64") then
-                    platform = "linux-64"
-                elseif find(architecture,"ppc") then
-                    platform = "linux-ppc"
-                else
-                    platform = "linux"
-                end
-            elseif name == "macosx" then
-                local architecture = os.resultof("echo $HOSTTYPE")
-                if find(architecture,"i386") then
-                    platform = "osx-intel"
-                elseif find(architecture,"x86_64") then
-                    platform = "osx-64"
-                else
-                    platform = "osx-ppc"
-                end
-            elseif name == "sunos" then
-                if find(architecture,"sparc") then
-                    platform = "solaris-sparc"
-                else -- if architecture == 'i86pc'
-                    platform = "solaris-intel"
-                end
-            elseif name == "freebsd" then
-                if find(architecture,"amd64") then
-                    platform = "freebsd-amd64"
-                else
-                    platform = "freebsd"
-                end
-            else
-                platform = default or name
-            end
+            os.platform = "osx-ppc"
         end
-        function os.currentplatform()
-            return platform
+    elseif name == "sunos" then
+        if find(architecture,"sparc") then
+            os.platform = "solaris-sparc"
+        else -- if architecture == 'i86pc'
+            os.platform = "solaris-intel"
         end
+    elseif name == "freebsd" then
+        if find(architecture,"amd64") then
+            os.platform = "freebsd-amd64"
+        else
+            os.platform = "freebsd"
+        end
+    else
+        os.platform = 'linux'
     end
-    return platform
 end
 
 -- beware, we set the randomseed
diff --git a/tex/context/base/l-string.lua b/tex/context/base/l-string.lua
index 0ee6d86d1..c27d7098f 100644
--- a/tex/context/base/l-string.lua
+++ b/tex/context/base/l-string.lua
@@ -194,6 +194,7 @@ end
 local simple_escapes = {
     ["-"] = "%-",
     ["."] = "%.",
+    ["?"] = ".",
     ["*"] = ".*",
 }
 
@@ -255,3 +256,16 @@ function string:striplong() -- strips newlines and leading spaces
     self = gsub(self,"[\n\r]+ *","\n")
     return self
 end
+
+function string:topattern(lowercase,strict)
+    if lowercase then
+        self = self:lower()
+    end
+    self = gsub(self,".",simple_escapes)
+    if self == "" then
+        self = ".*"
+    elseif strict then
+        self = "^" .. self .. "$"
+    end
+    return self
+end
diff --git a/tex/context/base/l-unicode.lua b/tex/context/base/l-unicode.lua
index a3b45028a..290234d56 100644
--- a/tex/context/base/l-unicode.lua
+++ b/tex/context/base/l-unicode.lua
@@ -6,13 +6,34 @@ if not modules then modules = { } end modules ['l-unicode'] = {
     license   = "see context related readme files"
 }
 
+if not unicode then
+
+    unicode = { utf8 = { } }
+
+    local floor, char = math.floor, string.char
+
+    function unicode.utf8.utfchar(n)
+        if n < 0x80 then
+            return char(n)
+        elseif n < 0x800 then
+            return char(0xC0 + floor(n/0x40))  .. char(0x80 + (n % 0x40))
+        elseif n < 0x10000 then
+            return char(0xE0 + floor(n/0x1000)) .. char(0x80 + (floor(n/0x40) % 0x40)) .. char(0x80 + (n % 0x40))
+        elseif n < 0x40000 then
+            return char(0xF0 + floor(n/0x40000)) .. char(0x80 + floor(n/0x1000)) .. char(0x80 + (floor(n/0x40) % 0x40)) .. char(0x80 + (n % 0x40))
+        else -- wrong:
+          -- return char(0xF1 + floor(n/0x1000000)) .. char(0x80 + floor(n/0x40000)) .. char(0x80 + floor(n/0x1000)) .. char(0x80 + (floor(n/0x40) % 0x40)) .. char(0x80 + (n % 0x40))
+            return "?"
+        end
+    end
+
+end
+
 utf = utf or unicode.utf8
 
 local concat, utfchar, utfgsub = table.concat, utf.char, utf.gsub
 local char, byte, find, bytepairs = string.char, string.byte, string.find, string.bytepairs
 
-unicode = unicode or { }
-
 -- 0  EF BB BF      UTF-8
 -- 1  FF FE         UTF-16-little-endian
 -- 2  FE FF         UTF-16-big-endian
diff --git a/tex/context/base/l-xml.lua b/tex/context/base/l-xml.lua
index 921a4edb1..14e97337b 100644
--- a/tex/context/base/l-xml.lua
+++ b/tex/context/base/l-xml.lua
@@ -11,13 +11,13 @@ if not modules then modules = { } end modules ['l-xml'] = {
 -- all is taken care of.
 
 if not trackers then
-    require('trac-tra.lua')
+    require('trac-tra')
 end
 
 if not xml then
-    require('lxml-tab.lua')
-    require('lxml-lpt.lua')
-    require('lxml-mis.lua')
-    require('lxml-aux.lua')
-    require('lxml-xml.lua')
+    require('lxml-tab')
+    require('lxml-lpt')
+    require('lxml-mis')
+    require('lxml-aux')
+    require('lxml-xml')
 end
diff --git a/tex/context/base/lpdf-ini.mkiv b/tex/context/base/lpdf-ini.mkiv
index cfc416216..bea9a5404 100644
--- a/tex/context/base/lpdf-ini.mkiv
+++ b/tex/context/base/lpdf-ini.mkiv
@@ -258,4 +258,13 @@
    \wd\scratchbox#1\ht\scratchbox#2\dp\scratchbox#3\box\scratchbox
    \egroup}
 
+\unexpanded\def\pdfactualtext#1#2%
+  {\pdfliteral direct{/Span <</ActualText \ctxlua{tex.write(lpdf.tosixteen("#2"))} >> BDC}%
+   #1%
+   \pdfliteral direct{EMC}}
+
+% \starttext
+%     text \pdfactualtext{Meier}{Müller} text
+% \stoptext
+
 \protect \endinput
diff --git a/tex/context/base/lxml-mis.lua b/tex/context/base/lxml-mis.lua
index 74c264d0c..864ab75a1 100644
--- a/tex/context/base/lxml-mis.lua
+++ b/tex/context/base/lxml-mis.lua
@@ -11,7 +11,7 @@ local type, next, tonumber, tostring, setmetatable, loadstring = type, next, ton
 local format, gsub = string.format, string.gsub
 
 --[[ldx--
-<p>The following helper functions best belong to the <t>lmxl-ini</t>
+<p>The following helper functions best belong to the <t>lxml-ini</t>
 module. Some are here because we need then in the <t>mk</t>
 document and other manuals, others came up when playing with
 this module. Since this module is also used in <l n='mtxrun'/> we've
diff --git a/tex/context/base/lxml-tex.lua b/tex/context/base/lxml-tex.lua
index 0305b889e..f5ff3b9c8 100644
--- a/tex/context/base/lxml-tex.lua
+++ b/tex/context/base/lxml-tex.lua
@@ -43,8 +43,6 @@ local trace_comments = false  trackers.register("lxml.comments", function(v) tra
 
 lxml              = lxml or { }
 lxml.loaded       = lxml.loaded or { }
-lxml.noffiles     = 0
-lxml.nofconverted = 0
 
 local loaded = lxml.loaded
 
@@ -325,8 +323,7 @@ xml.originalload = xml.originalload or xml.load
 local noffiles, nofconverted = 0, 0
 
 function xml.load(filename)
-    noffiles = noffiles + 1
-    nofconverted = nofconverted + 1
+    noffiles, nofconverted = noffiles + 1, nofconverted + 1
     starttiming(xml)
     local ok, data = resolvers.loadbinfile(filename)
     local xmltable = xml.convert((ok and data) or "")
@@ -357,6 +354,7 @@ function lxml.load(id,filename,compress,entities)
     if trace_loading then
         commands.writestatus("lxml","loading file '%s' as '%s'",filename,id)
     end
+    noffiles, nofconverted = noffiles + 1, nofconverted + 1
  -- local xmltable = xml.load(filename)
     local ok, data = resolvers.loadbinfile(filename)
     local xmltable = lxml.convert(id,(ok and data) or "",compress,entities)
@@ -1301,9 +1299,10 @@ statistics.register("xml load time", function()
 end)
 
 statistics.register("lxml preparation time", function()
-    if noffiles > 0 or nofconverted > 0 then
+    local calls, cached = xml.lpathcalls(), xml.lpathcached()
+    if calls > 0 or cached > 0 then
         return format("%s seconds, %s nodes, %s lpath calls, %s cached calls",
-            statistics.elapsedtime(lxml), nofindices, xml.lpathcalls(), xml.lpathcached())
+            statistics.elapsedtime(lxml), nofindices, calls, cached)
     else
         return nil
     end
diff --git a/tex/context/base/math-dim.lua b/tex/context/base/math-dim.lua
index b1e9635ae..754ca8314 100644
--- a/tex/context/base/math-dim.lua
+++ b/tex/context/base/math-dim.lua
@@ -260,9 +260,8 @@ function mathematics.dimensions(dimens)
             FractionNumeratorGapMin                     = t . fraction_num_vgap     . text_style,
             FractionNumeratorShiftUp                    = t . fraction_num_up       . text_style,
             FractionRuleThickness                       = t . fraction_rule         . text_style,
---~ not yet in my bin :
---~             FractionDelimiterSize                       = t . fraction_del_size     . text_style,
---~             FractionDelimiterDisplayStyleSize           = t . fraction_del_size     . display_style,
+            FractionDelimiterSize                       = t . fraction_del_size     . text_style,
+            FractionDelimiterDisplayStyleSize           = t . fraction_del_size     . display_style,
             LowerLimitBaselineDropMin                   = t . limit_below_bgap      . text_style,
             LowerLimitGapMin                            = t . limit_below_vgap      . text_style,
             OverbarExtraAscender                        = t . overbar_kern          . text_style,
diff --git a/tex/context/base/node-rul.mkiv b/tex/context/base/node-rul.mkiv
index ba2f0aed3..0beae198c 100644
--- a/tex/context/base/node-rul.mkiv
+++ b/tex/context/base/node-rul.mkiv
@@ -1,5 +1,5 @@
 %D \module
-%D   [       file=node-bar,
+%D   [       file=node-rul,
 %D        version=2009.11.03, % 1995.10.10,
 %D          title=\CONTEXT\ Core Macros,
 %D       subtitle=Bars,
@@ -57,8 +57,8 @@
 
 \unprotect
 
-\definesystemattribute[ruled]
-\definesystemattribute[shifted]
+%definesystemattribute[ruled]
+%definesystemattribute[shifted]
 
 \registerctxluafile{node-rul}{1.001}
 
@@ -137,15 +137,16 @@
 \unexpanded\def\stopbar
   {\endgroup}
 
-\newcount\currentbarnesting
+\newcount\currentbarnesting % todo: same as colors
 
 \unexpanded\def\pushbar[#1]%
   {\global\advance\currentbarnesting\plusone
-   \setevalue{\??on:s:\number\currentbarnesting}{\dogetattribute{ruled}}% stack
+   \expandafter\edef\csname\??on:s:\number\currentbarnesting\endcsname
+     {\attribute\ruledattribute\the\ruledattribute}% stack
    \dodoruled{#1}}
 
 \unexpanded\def\popbar
-  {\dosetattribute{ruled}{\getvalue{\??on:s:\number\currentbarnesting}}%
+  {\csname\??on:s:\number\currentbarnesting\endcsname
    \global\advance\currentbarnesting\minusone}
 
 \def\setupbars
diff --git a/tex/context/base/node-tra.lua b/tex/context/base/node-tra.lua
index f243c9cd0..f709a8a6a 100644
--- a/tex/context/base/node-tra.lua
+++ b/tex/context/base/node-tra.lua
@@ -137,11 +137,12 @@ function nodes.tracers.characters.start()
     end
     function nodes.tracers.characters.stop()
         tracers.list['characters'] = list
-        lmx.set('title', 'ConTeXt Character Processing Information')
-        lmx.set('color-background-one', lmx.get('color-background-yellow'))
-        lmx.set('color-background-two', lmx.get('color-background-purple'))
-        lmx.show('context-characters.lmx')
-        lmx.restore()
+        local variables = {
+            ['title']                = 'ConTeXt Character Processing Information',
+            ['color-background-one'] = lmx.get('color-background-yellow'),
+            ['color-background-two'] = lmx.get('color-background-purple'),
+        }
+        lmx.show('context-characters.lmx',variables)
         nodes.process_characters = npc
         tasks.restart("processors", "characters")
     end
diff --git a/tex/context/base/page-set.mkii b/tex/context/base/page-set.mkii
index 6724ca979..eb01799ae 100644
--- a/tex/context/base/page-set.mkii
+++ b/tex/context/base/page-set.mkii
@@ -2277,6 +2277,7 @@
               \v!right=>\doglobal\addtocommalist{#1}\columnrightareas]%
            \getparameters[\??mt#1#2]
              [\c!x=1,\c!y=1,\c!nx=1,\c!ny=1,\c!clipoffset=2\lineheight,
+              \c!leftoffset=\zeropoint,\c!rightoffset=\zeropoint,
               \c!offset=\v!overlay,\c!strut=\v!no,\c!frame=\v!off,
               \c!type=#2,\c!page=1,\c!state=\v!stop,#3]}}%
    \else
@@ -2427,7 +2428,8 @@
            %\c!bottomoffset=\columntextareaparameter\c!clipoffset,%
              %\c!leftoffset=\columntextareaparameter\c!clipoffset,%
                   \c!offset=\columntextareaparameter\c!clipoffset,%
-             \c!rightoffset=\zeropoint,%
+                  \c!offset=\columntextareaparameter\c!clipoffset,%
+             \c!rightoffset=\columntextareaparameter\c!rightoffset,%
                    \c!width=\!!widthb,%
                   \c!height=\!!heighta]%
           {\copy\scratchbox}%
@@ -2444,7 +2446,8 @@
            %\c!bottomoffset=\columntextareaparameter\c!clipoffset,%
             %\c!rightoffset=\columntextareaparameter\c!clipoffset,%
                   \c!offset=\columntextareaparameter\c!clipoffset,%
-              \c!leftoffset=\zeropoint,%
+                  \c!offset=\columntextareaparameter\c!clipoffset,%
+              \c!leftoffset=\columntextareaparameter\c!leftoffset,%
                    \c!width=\!!widtha,%
                   \c!height=\!!heighta,%
                  \c!hoffset=\!!widthb]%
diff --git a/tex/context/base/page-set.mkiv b/tex/context/base/page-set.mkiv
index 7e825d76d..ca256d97c 100644
--- a/tex/context/base/page-set.mkiv
+++ b/tex/context/base/page-set.mkiv
@@ -2183,6 +2183,7 @@
               \v!right=>\doglobal\addtocommalist{#1}\columnrightareas]%
            \getparameters[\??mt#1#2]
              [\c!x=1,\c!y=1,\c!nx=1,\c!ny=1,\c!clipoffset=2\lineheight,
+              \c!leftoffset=\zeropoint,\c!rightoffset=\zeropoint,
               \c!offset=\v!overlay,\c!strut=\v!no,\c!frame=\v!off,
               \c!type=#2,\c!page=1,\c!state=\v!stop,#3]}}%
    \else
@@ -2333,7 +2334,8 @@
            %\c!bottomoffset=\columntextareaparameter\c!clipoffset,%
              %\c!leftoffset=\columntextareaparameter\c!clipoffset,%
                   \c!offset=\columntextareaparameter\c!clipoffset,%
-             \c!rightoffset=\zeropoint,%
+                  \c!offset=\columntextareaparameter\c!clipoffset,%
+             \c!rightoffset=\columntextareaparameter\c!rightoffset,%
                    \c!width=\!!widthb,%
                   \c!height=\!!heighta]%
           {\copy\scratchbox}%
@@ -2350,7 +2352,7 @@
            %\c!bottomoffset=\columntextareaparameter\c!clipoffset,%
             %\c!rightoffset=\columntextareaparameter\c!clipoffset,%
                   \c!offset=\columntextareaparameter\c!clipoffset,%
-              \c!leftoffset=\zeropoint,%
+              \c!leftoffset=\columntextareaparameter\c!leftoffset,%
                    \c!width=\!!widtha,%
                   \c!height=\!!heighta,%
                  \c!hoffset=\!!widthb]%
diff --git a/tex/context/base/spac-hor.mkiv b/tex/context/base/spac-hor.mkiv
index fb3a9e794..fca5624ec 100644
--- a/tex/context/base/spac-hor.mkiv
+++ b/tex/context/base/spac-hor.mkiv
@@ -156,7 +156,7 @@
      \noindent\hskip\parindent
    \fi \fi}
 
-\def\toggleindentation
+\def\toggleindentation % does not play well with noindentation
   {\ifcase\indentingtoggle
      % nothing
    \or
diff --git a/tex/context/base/strc-pag.mkiv b/tex/context/base/strc-pag.mkiv
index b21ae8bc4..4bcee80ea 100644
--- a/tex/context/base/strc-pag.mkiv
+++ b/tex/context/base/strc-pag.mkiv
@@ -317,6 +317,9 @@
    \ifdefined \recalculatebackgrounds \recalculatebackgrounds \fi
 \to \everysetuppagenumbering
 
+\def\flushfinallayoutpage
+  {\doifsomething\@@nmpage{\doifnot\@@nmpage\v!no{\page[\@@nmpage]}}}
+
 % The numbered location handler is there because we need to be downward
 % compatible. So, in fact there can be multiple handlers active at the
 % same time, but only the current one does something.
@@ -441,6 +444,7 @@
    \c!width=, % in geval van \v!marginedge
    \c!left=,
    \c!right=,
+   \c!page=\v!last,
    \c!textseparator=\tfskip,
    \c!state=\v!start,
    \c!command=,
diff --git a/tex/context/base/strc-ref.lua b/tex/context/base/strc-ref.lua
index 42118436e..8cc63d50e 100644
--- a/tex/context/base/strc-ref.lua
+++ b/tex/context/base/strc-ref.lua
@@ -198,7 +198,7 @@ local function register_from_lists(collected,derived)
                     local t = { kind, i }
                     for s in gmatch(reference,"%s*([^,]+)") do
                         if trace_referencing then
-                            logs.report("referencing","list entry %s provides %s reference '%s' on realpage %s)",i,kind,s,realpage)
+                            logs.report("referencing","list entry %s provides %s reference '%s' on realpage %s",i,kind,s,realpage)
                         end
                         d[s] = t -- share them
                     end
@@ -860,15 +860,17 @@ function jobreferences.filter(name,...) -- number page title ...
             local filter = filters[kind] or filters.generic
             filter = filter and (filter[name] or filter.unknown or filters.generic[name] or filters.generic.unknown)
             if filter then
+                logs.report("referencing","name '%s', kind '%s', using dedicated filter",name,kind)
+--~                 print(table.serialize {...})
                 filter(data,name,...)
             elseif trace_referencing then
-                logs.report("referencing","no (generic) filter.name for '%s'",name)
+                logs.report("referencing","name '%s', kind '%s', using generic filter",name,kind)
             end
         elseif trace_referencing then
-            logs.report("referencing","no metadata.kind for '%s'",name)
+            logs.report("referencing","name '%s', unknown kind",name)
         end
     elseif trace_referencing then
-        logs.report("referencing","no current reference for '%s'",name)
+        logs.report("referencing","name '%s', no reference",name)
     end
 end
 
@@ -892,12 +894,13 @@ function filters.generic.text(data)
     end
 end
 
-function filters.generic.number(data,what,...) -- todo: spec and then no stopper
+function filters.generic.number(data,what,prefixspec) -- todo: spec and then no stopper
     if data then
         local numberdata = data.numberdata
         if numberdata then
-            helpers.prefix(data,...)
-            sections.typesetnumber(numberdata,"number",numberdata or false)
+--~ print(table.serialize(prefixspec))
+            helpers.prefix(data,prefixspec)
+            sections.typesetnumber(numberdata,"number",numberdata)
         else
             local useddata = data.useddata
             if useddata and useddsta.number then
@@ -964,11 +967,11 @@ end
 
 filters.section = { }
 
-function filters.section.number(data) -- todo: spec and then no stopper
+function filters.section.number(data,what,prefixspec)
     if data then
         local numberdata = data.numberdata
         if numberdata then
-            sections.typesetnumber(numberdata,"number",numberdata or false)
+            sections.typesetnumber(numberdata,"number",prefixspec,numberdata)
         else
             local useddata = data.useddata
             if useddata and useddata.number then
diff --git a/tex/context/base/strc-ref.mkiv b/tex/context/base/strc-ref.mkiv
index d54d75207..cbed71d68 100644
--- a/tex/context/base/strc-ref.mkiv
+++ b/tex/context/base/strc-ref.mkiv
@@ -13,14 +13,17 @@
 
 % todo: (1) configure references, (2) rendering => with presets
 %
-% \starttext
-%     \definestructureconversionset[default][Character,number,Romannumerals,Character][number]
-%     \definestructureseparatorset [default][.,.,--][.]
-%     \setupstructurehead[subsection][sectionstopper=),sectionsegments=4:4]
-
-%     \setupreferencing[sectionsegments=3:4]
-%     \section {One} \subsection[sec:test]{Two} See \in[sec:test]
-% \stoptext
+% \definestructureconversionset[default][Character,number,Romannumerals,Character][number]
+% \definestructureseparatorset [default][.,.,--][.]
+% \setupstructurehead[subsection][sectionstopper=),sectionsegments=4:4]
+% \setupreferencestructureprefix[default][prefixsegments=2:4]
+% \setupreferencestructureprefix[figure][default][prefixsegments=3:4]
+% \chapter {One}
+% \section {One}
+% \subsection[sec:test]{Two}
+% See \in[sec:test] and \in[fig:xx] and \in[fig:yy]
+% \placefigure[here][fig:xx]{}{}
+% \placefigure[here][fig:yy]{}{}
 
 \writestatus{loading}{ConTeXt Structure Macros / Cross Referencing}
 
@@ -1780,7 +1783,7 @@
 %      {\ctxlua{jobreferences.get_current_metadata("name")}}
 %      {#1}}
 % \def\currentreferencedefault
-%   {\ctxlua{jobreferences.filter("default",\referencestructureprefixspec\v!default)}}
+%   {\ctxlua{jobreferences.filter("default",\getreferencestructureprefixspec\v!default)}}
 %
 % this is shortcut for:
 
diff --git a/tex/context/base/syst-ini.tex b/tex/context/base/syst-ini.tex
index 0c3770294..51e78e67b 100644
--- a/tex/context/base/syst-ini.tex
+++ b/tex/context/base/syst-ini.tex
@@ -805,8 +805,8 @@
     \ifdefined\pdfgentounicode     \else \newcount\pdfgentounicode     \fi \pdfgentounicode\plusone
 
     \def\nopdfcompression     {\pdfobjcompresslevel\zerocount \pdfcompresslevel\zerocount}
-    \def\maximumpdfcompression{\pdfobjcompresslevel\plusone   \pdfcompresslevel\plusnine }
-    \def\normalpdfcompression {\pdfobjcompresslevel\plusone   \pdfcompresslevel\plusthree}
+    \def\maximumpdfcompression{\pdfobjcompresslevel\plusnine  \pdfcompresslevel\plusnine }
+    \def\normalpdfcompression {\pdfobjcompresslevel\plusthree \pdfcompresslevel\plusthree}
 
     \normalpdfcompression
 
diff --git a/tex/context/base/trac-deb.lua b/tex/context/base/trac-deb.lua
index 4cd324922..08252c6c9 100644
--- a/tex/context/base/trac-deb.lua
+++ b/tex/context/base/trac-deb.lua
@@ -9,19 +9,6 @@ if not modules then modules = { } end modules ['trac-deb'] = {
 if not lmx           then lmx           = { } end
 if not lmx.variables then lmx.variables = { } end
 
-lmx.variables['color-background-green']  = '#4F6F6F'
-lmx.variables['color-background-blue']   = '#6F6F8F'
-lmx.variables['color-background-yellow'] = '#8F8F6F'
-lmx.variables['color-background-purple'] = '#8F6F8F'
-
-lmx.variables['color-background-body']   = '#808080'
-lmx.variables['color-background-main']   = '#3F3F3F'
-lmx.variables['color-background-one']    = lmx.variables['color-background-green']
-lmx.variables['color-background-two']    = lmx.variables['color-background-blue']
-
-lmx.variables['title-default']           = 'ConTeXt Status Information'
-lmx.variables['title']                   = lmx.variables['title-default']
-
 lmx.htmfile = function(name) return environment.jobname .. "-status.html" end
 lmx.lmxfile = function(name) return resolvers.find_file(name,'tex') end
 
@@ -82,30 +69,30 @@ function tracers.knownlist(name)
 end
 
 function tracers.showdebuginfo()
-    lmx.set('title', 'ConTeXt Debug Information')
-    lmx.set('color-background-one', lmx.get('color-background-green'))
-    lmx.set('color-background-two', lmx.get('color-background-blue'))
-    lmx.show('context-debug.lmx')
-    lmx.restore()
+    local variables = {
+        ['title']                = 'ConTeXt Debug Information',
+        ['color-background-one'] = lmx.get('color-background-green'),
+        ['color-background-two'] = lmx.get('color-background-blue'),
+    }
+    lmx.show('context-debug.lmx',variables)
 end
 
 function tracers.showerror()
-    lmx.set('title', 'ConTeXt Error Information')
-    lmx.set('errormessage', status.lasterrorstring)
-    lmx.set('linenumber', status.linenumber)
-    lmx.set('color-background-one', lmx.get('color-background-yellow'))
-    lmx.set('color-background-two', lmx.get('color-background-purple'))
     local filename = status.filename
     local linenumber = tonumber(status.linenumber or "0")
+    local variables = {
+        ['title']                = 'ConTeXt Error Information',
+        ['errormessage']         = status.lasterrorstring,
+        ['linenumber']           = status.linenumber,
+        ['color-background-one'] = lmx.get('color-background-yellow'),
+        ['color-background-two'] = lmx.get('color-background-purple'),
+    }
     if not filename then
-        lmx.set('filename', 'unknown')
-        lmx.set('errorcontext', 'error in filename')
+        variables.filename, variables.errorcontext = 'unknown', 'error in filename'
     elseif type(filename) == "number" then
-        lmx.set('filename', "<read " .. filename .. ">")
-        lmx.set('errorcontext', 'unknown error')
+        variables.filename, variables.errorcontext = "<read " .. filename .. ">", 'unknown error'
     elseif io.exists(filename) then
         -- todo: use an input opener so that we also catch utf16 an reencoding
-        lmx.set('filename', filename)
         lines = io.lines(filename)
         if lines then
             local context = { }
@@ -124,16 +111,14 @@ function tracers.showerror()
                 end
                 n = n + 1
             end
-            lmx.set('errorcontext', table.concat(context,"\n"))
+            variables.filename, variables.errorcontext = filename, table.concat(context,"\n")
         else
-            lmx.set('errorcontext', "")
+            variables.filename, variables.errorcontext = filename, ""
         end
     else
-        lmx.set('filename', filename)
-        lmx.set('errorcontext', 'file not found')
+        variables.filename, variables.errorcontext = filename, 'file not found'
     end
-    lmx.show('context-error.lmx')
-    lmx.restore()
+    lmx.show('context-error.lmx',variables)
 end
 
 function tracers.overloaderror()
diff --git a/tex/context/base/trac-lmx.lua b/tex/context/base/trac-lmx.lua
index a39e3fe4e..a272564de 100644
--- a/tex/context/base/trac-lmx.lua
+++ b/tex/context/base/trac-lmx.lua
@@ -1,72 +1,128 @@
 if not modules then modules = { } end modules ['trac-lmx'] = {
-    version   = 1.001,
+    version   = 1.002,
     comment   = "companion to trac-lmx.mkiv",
     author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
     copyright = "PRAGMA ADE / ConTeXt Development Team",
     license   = "see context related readme files"
 }
 
-local gsub, format, concat = string.gsub, string.format, table.concat
+-- todo: use lpeg instead (although not really needed)
 
--- we can now use l-xml, and we can also use lpeg
+local gsub, format, concat, byte = string.gsub, string.format, table.concat, string.byte
 
 lmx = lmx or { }
 
-lmx.escapes = {
+local escapes = {
     ['&'] = '&amp;',
     ['<'] = '&lt;',
     ['>'] = '&gt;',
     ['"'] = '&quot;'
 }
 
--- local function p -> ends up in lmx.p, so we need to cast
-
-lmx.variables = { }
-
-lmx.variables['title-default'] = 'LMX File'
-lmx.variables['title']         = lmx.variables['title-default']
-
--- demonstrates: local, *all, gsub using tables, nil or value, loadstring
-
-function lmx.loadedfile(filename)
-    return io.loaddata(resolvers.find_file(filename))
-end
-
-lmx.converting = false
-
-local templates = { }
-
-function lmx.convert(template,result) -- todo: use lpeg instead
-    if not lmx.converting then -- else, if error then again tex error and loop
-        local data = templates[template]
-        if not data then
-            data = lmx.loadedfile(template)
-            templates[template] = data
-        end
-        local text = { }
-        function lmx.print(...)
-            text[#text+1] = concat({...})
-        end
-        function lmx.variable(str)
-            return lmx.variables[str] or ""
-        end
-        function lmx.escape(str)
-            str = tostring(str)
-            str = gsub(str,'&','&amp;')
-            str = gsub(str,'[<>"]',lmx.escapes)
-            return str
-        end
-        function lmx.type(str)
-            if str then lmx.print("<tt>" .. lmx.escape(str) .. "</tt>") end
-        end
-        function lmx.pv(str)
-            lmx.print(lmx.variable(str))
-        end
-        function lmx.tv(str)
-            lmx.type(lmx.variable(str))
-        end
+-- variables
+
+lmx.variables = { } -- global, shared
+
+local lmxvariables = lmx.variables
+
+lmxvariables['title-default']           = 'ConTeXt LMX File'
+lmxvariables['title']                   = lmx.variables['title-default']
+lmxvariables['color-background-green']  = '#4F6F6F'
+lmxvariables['color-background-blue']   = '#6F6F8F'
+lmxvariables['color-background-yellow'] = '#8F8F6F'
+lmxvariables['color-background-purple'] = '#8F6F8F'
+lmxvariables['color-background-body']   = '#808080'
+lmxvariables['color-background-main']   = '#3F3F3F'
+lmxvariables['color-background-one']    = lmxvariables['color-background-green']
+lmxvariables['color-background-two']    = lmxvariables['color-background-blue']
+
+function lmx.set(key, value)
+    lmxvariables[key] = value
+end
+
+function lmx.get(key)
+    return lmxvariables[key] or ""
+end
+
+-- helpers
+
+local variables, result = { } -- we assume no nesting
+
+local function do_print(one,two,...)
+    if two then
+        result[#result+1] = concat { one, two, ... }
+    else
+        result[#result+1] = one
+    end
+end
+
+local function do_escape(str)
+    str = tostring(str)
+    str = gsub(str,'&','&amp;')
+    str = gsub(str,'[<>"]',escapes)
+    return str
+end
+
+local function do_urlescaped(str)
+    return (gsub(str,"[^%a%d]",format("%%0x",byte("%1"))))
+end
+
+function do_type(str)
+    if str then do_print("<tt>" .. do_escape(str) .. "</tt>") end
+end
+
+local function do_variable(str)
+    return variables[str] or lmxvariables[str] -- or format("<!-- unset lmx instance variable: %s -->",str or "?")
+end
+
+function lmx.loadedfile(name)
+    name = (resolvers and resolvers.find_file and resolvers.find_file(name)) or name
+    return io.loaddata(name)
+end
+
+local function do_include(filename)
+    local stylepath = do_variable('includepath')
+    local data = lmx.loadedfile(filename)
+    if (not data or data == "") and stylepath ~= "" then
+        data = lmx.loadedfile(file.join(stylepath,filename))
+    end
+    if not data or data == "" then
+        data = format("<!-- unknown lmx include file: %s -->",filename)
+    end
+    return data
+end
+
+lmx.print     = do_print
+lmx.type      = do_type
+lmx.escape    = do_escape
+lmx.urlescape = do_escape
+lmx.variable  = do_variable
+lmx.include   = do_include
+
+function lmx.pv(str)
+    do_print(do_variable(str) or "")
+end
+
+function lmx.tv(str)
+    lmx.type(do_variable(str) or "")
+end
+
+local template = [[
+    local definitions = { }
+    local p, v, e, t, pv, tv = lmx.print, lmx.variable, lmx.escape, lmx.type, lmx.pv, lmx.tv
+    %s
+]]
+
+local cache = { }
+
+local trace = false
+
+function lmx.new(data,variables)
+    local known = cache[data]
+    if not known then
+        local definitions = { }
         data = gsub(data,"<%?lmx%-include%s+(.-)%s-%?>", function(filename)
-            return lmx.loadedfile(filename)
+            return lmx.include(filename)
         end)
         local definitions =  { }
         data = gsub(data,"<%?lmx%-define%-begin%s+(%S-)%s-%?>(.-)<%?lmx%-define%-end%s-%?>", function(tag,content)
@@ -76,33 +132,60 @@ function lmx.convert(template,result) -- todo: use lpeg instead
         data = gsub(data,"<%?lmx%-resolve%s+(%S-)%s-%?>", function(tag)
             return definitions[tag] or ""
         end)
-        data = gsub(data,"%c%s-(<%?lua .-%?>)%s-%c", function(lua)
-            return "\n" .. lua .. " "
-        end)
-        data = gsub(data .. "<?lua ?>","(.-)<%?lua%s+(.-)%?>", function(txt, lua)
-            txt = gsub(txt,"%c+", "\\n")
-            txt = gsub(txt,'"'  , '\\"')
-            txt = gsub(txt,"'"  , "\\'")
-         -- txt = gsub(txt,"([\'\"])", { ["'"] = '\\"', ['"'] = "\\'" } )
-            return "p(\"" .. txt .. "\")\n" .. lua .. "\n"
+        data = gsub(data .. "<?lua ?>","(.-)<%?lua%s+(.-)%s*%?>", function(txt,lua)
+            txt = gsub(txt,"%c+","\n")
+            return format("p(%q)%s ",txt,lua) -- nb! space
         end)
-        lmx.converting = true
-        data = "local p,v,e,t,pv,tv = lmx.print,lmx.variable,lmx.escape,lmx.type,lmx.pv,lmx.tv " .. data
-        assert(loadstring(data))()
-        lmx.converting = false
-        text = concat(text)
-        if result then
-            io.savedata(result,text)
-        else
-            return text
-        end
+        data = format(template,data)
+        known = {
+            data = trace and data,
+            variables = variables or { },
+            converter = loadstring(data),
+        }
+    elseif variables then
+        known.variables = variables
+    end
+    return known, known.variables
+end
+
+function lmx.reset(self)
+    self.variables = { }
+end
+
+function lmx.result(self)
+    if trace then
+        return self.data
+    else
+        variables, result = self.variables, { }
+        self.converter()
+        return concat(result)
+    end
+end
+
+-- file converter
+
+local loaded = { }
+
+function lmx.convert(templatefile,resultfile,variables)
+    local data = loaded[templatefile]
+    if not data then
+        data = lmx.new(lmx.loadedfile(templatefile),variables)
+        loaded[template] = data
+    elseif variables then
+        data.variables = variables
+    end
+    local result = lmx.result(data)
+    if resultfile then
+        io.savedata(resultfile,result)
+    else
+        return lmx.result(data,result)
     end
 end
 
 -- these can be overloaded; we assume that the os handles filename associations
 
-lmx.lmxfile = function(filename) return filename end
-lmx.htmfile = function(filename) return filename end
+lmx.lmxfile = function(filename) return filename end -- beware, these can be set!
+lmx.htmfile = function(filename) return filename end -- beware, these can be set!
 
 if os.platform == "windows" then
     lmx.popupfile = function(filename) os.execute("start " .. filename) end
@@ -110,44 +193,25 @@ else
     lmx.popupfile = function(filename) os.execute(filename) end
 end
 
-function lmx.make(name)
+function lmx.make(name,variables)
     local lmxfile = lmx.lmxfile(name)
     local htmfile = lmx.htmfile(name)
     if lmxfile == htmfile then
         htmfile = gsub(lmxfile, "%.%a+$", "html")
     end
-    lmx.convert(lmxfile, htmfile)
+    lmx.convert(lmxfile,htmfile,variables)
     return htmfile
 end
 
-function lmx.show(name)
-    local htmfile = lmx.make(name)
+function lmx.show(name,variables)
+    local htmfile = lmx.make(name,variables)
     lmx.popupfile(htmfile)
     return htmfile
 end
 
--- kind of private
-
-lmx.restorables = { }
-
-function lmx.set(key, value)
-    if not lmx.restorables[key] then
-        table.insert(lmx.restorables, key)
-        lmx.variables['@@' .. key] = lmx.variables[key]
-    end
-    lmx.variables[key] = value
-end
-
-function lmx.get(key)
-    return lmx.variables[key] or ""
-end
+-- test
 
-function lmx.restore()
-    for _,key in pairs(lmx.restorables) do
-        lmx.variables[key] = lmx.variables['@@' .. key]
-    end
-    lmx.restorables = { }
-end
+--~ print(lmx.result(lmx.new(io.loaddata("t:/sources/context-timing.lmx"))))
 
 -- command line
 
diff --git a/tex/context/base/trac-tim.lua b/tex/context/base/trac-tim.lua
index 82c03f4c7..a896d767f 100644
--- a/tex/context/base/trac-tim.lua
+++ b/tex/context/base/trac-tim.lua
@@ -26,7 +26,7 @@ local params = {
     "pdf_mem_ptr",
     "pdf_mem_size",
     "pdf_os_cntr",
-    "pool_ptr",
+--  "pool_ptr", -- obsolete
     "str_ptr",
 }
 
@@ -36,12 +36,8 @@ local last  = os.clock()
 local data  = { }
 
 function progress.save()
-    local f = io.open((name or progress.defaultfilename) .. ".lut","w")
-    if f then
-        f:write(table.serialize(data,true))
-        f:close()
-        data = { }
-    end
+    io.savedata((name or progress.defaultfilename) .. ".lut",table.serialize(data,true))
+    data = { }
 end
 
 function progress.store()
@@ -61,32 +57,7 @@ end
 
 local processed = { }
 
-function progress.bot(name,tag)
-    local d = progress.convert(name)
-    return d.bot[tag] or 0
-end
-function progress.top(name,tag)
-    local d = progress.convert(name)
-    return d.top[tag] or 0
-end
-function progress.pages(name,tag)
-    local d = progress.convert(name)
-    return d.pages or 0
-end
-function progress.path(name,tag)
-    local d = progress.convert(name)
-    return d.paths[tag] or "origin"
-end
-function progress.nodes(name)
-    local d = progress.convert(name)
-    return d.names or { }
-end
-function progress.parameters(name)
-    local d = progress.convert(name)
-    return params -- shared
-end
-
-function progress.convert(name)
+local function convert(name)
     name = ((name ~= "") and name) or progress.defaultfilename
     if not processed[name] then
         local names, top, bot, pages, paths, keys = { }, { }, { }, 0, { }, { }
@@ -161,3 +132,24 @@ function progress.convert(name)
     end
     return processed[name]
 end
+
+progress.convert = convert
+
+function progress.bot(name,tag)
+    return convert(name).bot[tag] or 0
+end
+function progress.top(name,tag)
+    return convert(name).top[tag] or 0
+end
+function progress.pages(name,tag)
+    return convert(name).pages or 0
+end
+function progress.path(name,tag)
+    return convert(name).paths[tag] or "origin"
+end
+function progress.nodes(name)
+    return convert(name).names or { }
+end
+function progress.parameters(name)
+    return params -- shared
+end
diff --git a/tex/context/base/typo-spa.lua b/tex/context/base/typo-spa.lua
index 56ce36a05..d9ded1cfa 100644
--- a/tex/context/base/typo-spa.lua
+++ b/tex/context/base/typo-spa.lua
@@ -56,7 +56,7 @@ function spacings.process(namespace,attribute,head)
                 local map = mapping[attr]
                 if map then
                     map = map[start.char]
-                    unset_attribute(start,attribute)
+                    unset_attribute(start,attribute) -- needed?
                     if map then
                         local left, right, alternative = map.left, map.right, map.alternative
                         local quad = fontdata[start.font].parameters.quad
diff --git a/tex/context/base/verb-eif.mkii b/tex/context/base/verb-eif.mkii
index 5904abc6e..68c84d4be 100644
--- a/tex/context/base/verb-eif.mkii
+++ b/tex/context/base/verb-eif.mkii
@@ -64,7 +64,7 @@
 
 %D We borrow most of the macros from the \PERL\ driver.
 
-\ifx\undefined\setupprettyPLtype \input verb-pl \relax \fi
+\ifdefined\setupprettyPLtype \else \loadmarkfile{verb-pl} \fi
 
 \unprotect
 
diff --git a/tex/context/base/verb-ini.mkii b/tex/context/base/verb-ini.mkii
index 4726d0eac..829e10fd8 100644
--- a/tex/context/base/verb-ini.mkii
+++ b/tex/context/base/verb-ini.mkii
@@ -1455,11 +1455,8 @@
 
 \ifCONTEXT \else
 
-  \input verb-tex
-  \input verb-mp
-  \input verb-pl
-  \input verb-jv
-  \input verb-sql
+  \input verb-tex.mkii
+  \input verb-mp.mkii
 
   \def\startTEX
     {\bgroup \everypar{}%
@@ -1471,26 +1468,8 @@
      \let\obeycharacters\setupprettyMPtype
      \processdisplayverbatim{\stopMP}}
 
-  \def\startPL
-    {\bgroup \everypar{}%
-     \let\obeycharacters\setupprettyPLtype
-     \processdisplayverbatim{\stopPL}}
-
-  \def\startJV
-    {\bgroup \everypar{}%
-     \let\obeycharacters\setupprettyJVtype
-     \processdisplayverbatim{\stopJV}}
-
-  \def\startSQL
-    {\bgroup \everypar{}%
-     \let\obeycharacters\setupprettySQLtype
-     \processdisplayverbatim{\stopSQL}}
-
   \let\stopTEX=\egroup
   \let\stopMP =\egroup
-  \let\stopPL =\egroup
-  \let\stopJV =\egroup
-  \let\stopSQL=\egroup
 
 \fi
 
diff --git a/tex/context/base/verb-js.mkii b/tex/context/base/verb-js.mkii
index 3d1b69f8b..e497e475b 100644
--- a/tex/context/base/verb-js.mkii
+++ b/tex/context/base/verb-js.mkii
@@ -32,7 +32,7 @@
 %D a slightly adapted \PERL\ visualization. First we load the
 %D \PERL\ module:
 
-\ifx\undefined\setupprettyPLtype \input verb-pl \relax \fi
+\ifdefined\setupprettyPLtype \else \loadmarkfile{verb-pl} \fi
 
 \unprotect
 
diff --git a/tex/context/base/verb-jv.mkii b/tex/context/base/verb-jv.mkii
index 197b37ee7..ee79e5c03 100644
--- a/tex/context/base/verb-jv.mkii
+++ b/tex/context/base/verb-jv.mkii
@@ -22,7 +22,7 @@
 %D driver looks much like the \JAVASCRIPT\ one, we don't
 %D comment it extensively.
 
-\ifx\undefined\setupprettyPLtype \input verb-pl \relax \fi
+\ifdefined\setupprettyPLtype \else \loadmarkfile{verb-pl} \fi
 
 \unprotect
 
diff --git a/tex/context/base/verb-pas.mkii b/tex/context/base/verb-pas.mkii
index 0c9850abf..71c0b5a12 100644
--- a/tex/context/base/verb-pas.mkii
+++ b/tex/context/base/verb-pas.mkii
@@ -36,7 +36,7 @@
 %D   [palet=,icommand=\bf,vcommand=,ccommand=\it]
 %D \stopbuffer
 
-\ifx\undefined\setupprettyPLtype \input verb-pl \relax \fi
+\ifdefined\setupprettyPLtype \else \loadmarkfile{verb-pl} \fi
 
 \unprotect
 
diff --git a/tex/context/base/verb-raw.mkii b/tex/context/base/verb-raw.mkii
index 32903db77..43a0891a0 100644
--- a/tex/context/base/verb-raw.mkii
+++ b/tex/context/base/verb-raw.mkii
@@ -1,7 +1,7 @@
-\ifx\undefined\setupprettyTEXtype \input verb-tex \relax \fi
+\ifdefined\setupprettyPLtype \else \loadmarkfile{verb-pl} \fi
 
 \gdef\setupprettyRAWtype%
   {\setupprettyTEXtype
    \def\prettyidentifier{RAW}}
-  
-\endinput 
+
+\endinput
diff --git a/tex/context/base/verb-sql.mkii b/tex/context/base/verb-sql.mkii
index a00841d73..f145607f8 100644
--- a/tex/context/base/verb-sql.mkii
+++ b/tex/context/base/verb-sql.mkii
@@ -49,7 +49,7 @@
 %D Like we did with the \JAVASCRIPT\ driver, we will borrow
 %D most of the macros from the \PERL\ driver.
 
-\ifx\undefined\setupprettyPLtype \input verb-pl \relax \fi
+\ifdefined\setupprettyPLtype \else \loadmarkfile{verb-pl} \fi
 
 \unprotect
 
diff --git a/tex/context/base/x-dir-05.mkii b/tex/context/base/x-dir-05.mkii
new file mode 100644
index 000000000..0d0edd832
--- /dev/null
+++ b/tex/context/base/x-dir-05.mkii
@@ -0,0 +1,51 @@
+%D \module
+%D   [      file=x-dir-05,
+%D        version=2003.05.10, % around that time -)
+%D          title=\CONTEXT\ Directory Handling,
+%D       subtitle=Access,
+%D         author=Hans Hagen,
+%D           date=\currentdate,
+%D      copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\setvariables
+  [filestate]
+  [name=,base=,type=,size=,permissions=,date=]
+
+\def\savefilestate
+  {\dodoubleargument\dosavefilestate}
+
+\def\dosavefilestate[#1][#2]%
+  {\startnointerference
+     \setxvariables
+       [#1]
+       [name=#2,base=,type=,size=,permissions=,date=]
+     \executesystemcommand{texmfstart xmltools.rb --dir --pattern=\getvariable{#1}{name} --output=xmldir.tmp}
+     \defineXMLprocess [files]
+     \defineXMLprocess [directory]
+     \defineXMLenvironment [file]
+       {\defineXMLsave [base]
+        \defineXMLsave [type]
+        \defineXMLsave [size]
+        \defineXMLsave [permissions]
+        \defineXMLsave [date]}
+       {\setxvariables
+          [#1]
+          [name=\XMLop{name},
+           base=\XMLflush{base},
+           type=\XMLflush{type},
+           size=\XMLflush{size},
+           permissions=\XMLflush{permissions},
+           date=\XMLflush{date}]}
+     \startXMLignore
+     \processXMLfile{xmldir.tmp}
+     \stopXMLignore
+   \stopnointerference}
+
+\def\getfilestate#1% old one
+  {\savefilestate[filestate][#1]}
+
+\endinput
diff --git a/tex/context/base/x-dir-05.mkiv b/tex/context/base/x-dir-05.mkiv
new file mode 100644
index 000000000..c29c9ea2a
--- /dev/null
+++ b/tex/context/base/x-dir-05.mkiv
@@ -0,0 +1,72 @@
+%D \module
+%D   [      file=x-dir-05,
+%D        version=2003.05.10, % around that time -)
+%D          title=\CONTEXT\ Directory Handling,
+%D       subtitle=Access,
+%D         author=Hans Hagen,
+%D           date=\currentdate,
+%D      copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\setvariables
+  [filestate]
+  [name=,
+   base=,
+   type=,
+   size=,
+   permissions=,
+   date=]
+
+% \savefilestate[zip-latest][context/latest/cont-#2.zip]%
+
+\startluacode
+    local filestates = { }
+    function commands.savefilestate(tag,name)
+        if not filestates[tag] then
+            local attr = lfs.attributes(name)
+            if attr then attr.name = name end
+            filestates[tag] = attr
+        end
+    end
+    function commands.getfilestatevariable(tag,name)
+        local fs = filestates[tag]
+        if fs then
+            local value
+            if name == "base" then
+                value = file.basename(fs.name)
+            elseif name == "type" then
+                value = file.extname(fs.name)
+            elseif name == "date" then
+                value = os.date("%Y-%m-%d %H:%M",fs.modification)
+            else
+                value = fs[name] or ""
+            end
+            tex.sprint(tex.vrbcatcodes,value)
+        end
+    end
+\stopluacode
+
+\def\getfilestatevariable#1#2%
+  {\ctxlua{commands.getfilestatevariable("#1","#2")}}
+
+\def\savefilestate
+  {\dodoubleargument\dosavefilestate}
+
+\def\dosavefilestate[#1][#2]%
+  {\ctxlua{commands.savefilestate("#1","#2")}%
+   \setxvariables
+     [#1]
+     [name={#2},
+      base=\getfilestatevariable{#1}{base},
+      type=\getfilestatevariable{#1}{type},
+      size=\getfilestatevariable{#1}{size},
+      date=\getfilestatevariable{#1}{date},
+      permissions=\getfilestatevariable{#1}{permissions}]}
+
+\def\getfilestate#1% old one
+  {\savefilestate[filestate][#1]}
+
+\endinput
diff --git a/tex/context/interface/cont-cs.xml b/tex/context/interface/cont-cs.xml
index c50d3c5d5..98e0111e0 100644
--- a/tex/context/interface/cont-cs.xml
+++ b/tex/context/interface/cont-cs.xml
@@ -4209,6 +4209,11 @@
         <cd:parameter name="prikaz">
           <cd:constant type="cd:oneargument"/>
         </cd:parameter>
+        <cd:parameter name="stranka">
+          <cd:constant type="posledni"/>
+          <cd:constant type="ano"/>
+          <cd:constant type="ne"/>
+        </cd:parameter>
       </cd:assignments>
     </cd:arguments>
   </cd:command>
diff --git a/tex/context/interface/cont-de.xml b/tex/context/interface/cont-de.xml
index 2aa738ed1..5b39c628a 100644
--- a/tex/context/interface/cont-de.xml
+++ b/tex/context/interface/cont-de.xml
@@ -4209,6 +4209,11 @@
         <cd:parameter name="befehl">
           <cd:constant type="cd:oneargument"/>
         </cd:parameter>
+        <cd:parameter name="seite">
+          <cd:constant type="letzte"/>
+          <cd:constant type="ja"/>
+          <cd:constant type="nein"/>
+        </cd:parameter>
       </cd:assignments>
     </cd:arguments>
   </cd:command>
diff --git a/tex/context/interface/cont-en.xml b/tex/context/interface/cont-en.xml
index f2cf7f7b8..cf1a59085 100644
--- a/tex/context/interface/cont-en.xml
+++ b/tex/context/interface/cont-en.xml
@@ -4209,6 +4209,11 @@
         <cd:parameter name="command">
           <cd:constant type="cd:oneargument"/>
         </cd:parameter>
+        <cd:parameter name="page">
+          <cd:constant type="last"/>
+          <cd:constant type="yes"/>
+          <cd:constant type="no"/>
+        </cd:parameter>
       </cd:assignments>
     </cd:arguments>
   </cd:command>
diff --git a/tex/context/interface/cont-fr.xml b/tex/context/interface/cont-fr.xml
index 81baacff3..be4a19280 100644
--- a/tex/context/interface/cont-fr.xml
+++ b/tex/context/interface/cont-fr.xml
@@ -4209,6 +4209,11 @@
         <cd:parameter name="commande">
           <cd:constant type="cd:oneargument"/>
         </cd:parameter>
+        <cd:parameter name="page">
+          <cd:constant type="dernier"/>
+          <cd:constant type="oui"/>
+          <cd:constant type="non"/>
+        </cd:parameter>
       </cd:assignments>
     </cd:arguments>
   </cd:command>
diff --git a/tex/context/interface/cont-it.xml b/tex/context/interface/cont-it.xml
index 058e71735..e167f22f2 100644
--- a/tex/context/interface/cont-it.xml
+++ b/tex/context/interface/cont-it.xml
@@ -4209,6 +4209,11 @@
         <cd:parameter name="comando">
           <cd:constant type="cd:oneargument"/>
         </cd:parameter>
+        <cd:parameter name="pagina">
+          <cd:constant type="ultimo"/>
+          <cd:constant type="si"/>
+          <cd:constant type="no"/>
+        </cd:parameter>
       </cd:assignments>
     </cd:arguments>
   </cd:command>
diff --git a/tex/context/interface/cont-nl.xml b/tex/context/interface/cont-nl.xml
index ebb29402f..dff677cd2 100644
--- a/tex/context/interface/cont-nl.xml
+++ b/tex/context/interface/cont-nl.xml
@@ -4209,6 +4209,11 @@
         <cd:parameter name="commando">
           <cd:constant type="cd:oneargument"/>
         </cd:parameter>
+        <cd:parameter name="pagina">
+          <cd:constant type="laatste"/>
+          <cd:constant type="ja"/>
+          <cd:constant type="nee"/>
+        </cd:parameter>
       </cd:assignments>
     </cd:arguments>
   </cd:command>
diff --git a/tex/context/interface/cont-pe.xml b/tex/context/interface/cont-pe.xml
index 5a86933a8..228cae2e8 100644
--- a/tex/context/interface/cont-pe.xml
+++ b/tex/context/interface/cont-pe.xml
@@ -4209,6 +4209,11 @@
         <cd:parameter name="فرمان">
           <cd:constant type="cd:oneargument"/>
         </cd:parameter>
+        <cd:parameter name="صفحه">
+          <cd:constant type="آخرین"/>
+          <cd:constant type="بله"/>
+          <cd:constant type="نه"/>
+        </cd:parameter>
       </cd:assignments>
     </cd:arguments>
   </cd:command>
diff --git a/tex/context/interface/cont-ro.xml b/tex/context/interface/cont-ro.xml
index 17e914725..74003dd5c 100644
--- a/tex/context/interface/cont-ro.xml
+++ b/tex/context/interface/cont-ro.xml
@@ -4209,6 +4209,11 @@
         <cd:parameter name="comanda">
           <cd:constant type="cd:oneargument"/>
         </cd:parameter>
+        <cd:parameter name="pagina">
+          <cd:constant type="ultim"/>
+          <cd:constant type="da"/>
+          <cd:constant type="nu"/>
+        </cd:parameter>
       </cd:assignments>
     </cd:arguments>
   </cd:command>
diff --git a/tex/generic/context/luatex-fonts-merged.lua b/tex/generic/context/luatex-fonts-merged.lua
index e9a57d93b..c03196d1b 100644
--- a/tex/generic/context/luatex-fonts-merged.lua
+++ b/tex/generic/context/luatex-fonts-merged.lua
@@ -1,6 +1,6 @@
 -- merged file : c:/data/develop/context/texmf/tex/generic/context/luatex-fonts-merged.lua
 -- parent file : c:/data/develop/context/texmf/tex/generic/context/luatex-fonts.lua
--- merge date  : 12/01/09 17:16:42
+-- merge date  : 12/13/09 23:30:54
 
 do -- begin closure to overcome local limits and interference
 
@@ -200,6 +200,7 @@ end
 local simple_escapes = {
     ["-"] = "%-",
     ["."] = "%.",
+    ["?"] = ".",
     ["*"] = ".*",
 }
 
@@ -262,6 +263,19 @@ function string:striplong() -- strips newlines and leading spaces
     return self
 end
 
+function string:topattern(lowercase,strict)
+    if lowercase then
+        self = self:lower()
+    end
+    self = gsub(self,".",simple_escapes)
+    if self == "" then
+        self = ".*"
+    elseif strict then
+        self = "^" .. self .. "$"
+    end
+    return self
+end
+
 end -- closure
 
 do -- begin closure to overcome local limits and interference
@@ -274,6 +288,8 @@ if not modules then modules = { } end modules ['l-lpeg'] = {
     license   = "see context related readme files"
 }
 
+lpeg = require("lpeg")
+
 local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
 
 --~ l-lpeg.lua :
-- 
cgit v1.2.3