texlive[43153] Master/texmf-dist: lualibs (4feb17)

commits+karl at tug.org commits+karl at tug.org
Mon Feb 6 00:22:36 CET 2017


Revision: 43153
          http://tug.org/svn/texlive?view=revision&revision=43153
Author:   karl
Date:     2017-02-06 00:22:36 +0100 (Mon, 06 Feb 2017)
Log Message:
-----------
lualibs (4feb17)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/luatex/lualibs/NEWS
    trunk/Master/texmf-dist/doc/luatex/lualibs/lualibs.pdf
    trunk/Master/texmf-dist/source/luatex/lualibs/Makefile
    trunk/Master/texmf-dist/source/luatex/lualibs/lualibs.dtx
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic.lua
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-dir.lua
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended.lua
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-file.lua
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-io.lua
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-lua.lua
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-number.lua
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-string.lua
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-table.lua
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-trac-inf.lua
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-fil.lua
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-jsn.lua
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-lua.lua
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-prs.lua
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-str.lua
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-tab.lua
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs.lua

Removed Paths:
-------------
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic-merged.lua
    trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended-merged.lua

Modified: trunk/Master/texmf-dist/doc/luatex/lualibs/NEWS
===================================================================
--- trunk/Master/texmf-dist/doc/luatex/lualibs/NEWS	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/doc/luatex/lualibs/NEWS	2017-02-05 23:22:36 UTC (rev 43153)
@@ -1,4 +1,7 @@
                         History of the lualibs package
+2017/02/01 v2.5/
+    * sync with Context beta as of 2017-02-01
+
 2016/04/06 v2.4/
     * sync with Context beta as of 2016-04-06
     * basic maintenance

Modified: trunk/Master/texmf-dist/doc/luatex/lualibs/lualibs.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/source/luatex/lualibs/Makefile
===================================================================
--- trunk/Master/texmf-dist/source/luatex/lualibs/Makefile	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/source/luatex/lualibs/Makefile	2017-02-05 23:22:36 UTC (rev 43153)
@@ -125,3 +125,14 @@
 	@$(RM) -r $(DISTDIR)
 
 merge: $(MERGED)
+
+ifndef DESTDIR
+install:
+	$(error "in order to install you need to provide $$DESTDIR")
+else
+install: $(TDS_ZIP)
+	$(info installing to destination “$(DESTDIR)”)
+	install -dm755 "$(DESTDIR)"
+	unzip "$(TDS_ZIP)" -d "$(DESTDIR)"
+endif
+

Modified: trunk/Master/texmf-dist/source/luatex/lualibs/lualibs.dtx
===================================================================
--- trunk/Master/texmf-dist/source/luatex/lualibs/lualibs.dtx	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/source/luatex/lualibs/lualibs.dtx	2017-02-05 23:22:36 UTC (rev 43153)
@@ -1,6 +1,6 @@
 % \iffalse meta-comment
 %
-% Copyright (C) 2009--2016 by
+% Copyright (C) 2009--2017 by
 %
 %       PRAGMA ADE / ConTeXt Development Team
 %       The LuaLaTeX Dev Team
@@ -37,7 +37,7 @@
 \input docstrip.tex
 \Msg{************************************************************************}
 \Msg{* Installation}
-\Msg{* Package: lualibs 2016-04-06 v2.4 Lua additional functions.}
+\Msg{* Package: lualibs 2017-02-01 v2.5 Lua additional functions.}
 \Msg{************************************************************************}
 
 \keepsilent
@@ -48,7 +48,7 @@
 \preamble
 This is a generated file.
 
-Copyright (C) 2009--2016 by
+Copyright (C) 2009--2017 by
         PRAGMA ADE / ConTeXt Development Team
         The LuaLaTeX Dev Team
 
@@ -107,7 +107,7 @@
 %<*driver>
 \NeedsTeXFormat{LaTeX2e}
 \ProvidesFile{lualibs.drv}
-  [2016/04/06 v2.4 Lua Libraries.]
+  [2017/02/01 v2.5 Lua Libraries.]
 \documentclass{ltxdoc}
 \usepackage{fancyvrb,xspace}
 \usepackage[x11names]{xcolor}
@@ -208,7 +208,7 @@
 % \GetFileInfo{lualibs.drv}
 %
 % \title{The \identifier{lualibs} package}
-% \date{2016/04/06 v2.4}
+% \date{2017/02/01 v2.5}
 % \author{Élie Roux      · \email{elie.roux at telecom-bretagne.eu}\\
 %         Philipp Gesang · \email{phg at phi-gamma.net}}
 %
@@ -427,8 +427,8 @@
 
 lualibs.module_info = {
   name          = "lualibs",
-  version       = 2.4,
-  date          = "2016-04-06",
+  version       = 2.5,
+  date          = "2017-02-01",
   description   = "ConTeXt Lua standard libraries.",
   author        = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang",
   copyright     = "PRAGMA ADE / ConTeXt Development Team",
@@ -582,8 +582,8 @@
 
 local lualibs_basic_module = {
   name          = "lualibs-basic",
-  version       = 2.4,
-  date          = "2016-04-06",
+  version       = 2.5,
+  date          = "2017-02-01",
   description   = "ConTeXt Lua libraries -- basic collection.",
   author        = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang",
   copyright     = "PRAGMA ADE / ConTeXt Development Team",
@@ -664,8 +664,8 @@
 
 local lualibs_extended_module = {
   name          = "lualibs-extended",
-  version       = 2.4,
-  date          = "2016-04-06",
+  version       = 2.5,
+  date          = "2017-02-01",
   description   = "ConTeXt Lua libraries -- extended collection.",
   author        = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang",
   copyright     = "PRAGMA ADE / ConTeXt Development Team",

Deleted: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic-merged.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic-merged.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic-merged.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -1,5072 +0,0 @@
--- merged file : lualibs-basic-merged.lua
--- parent file : lualibs-basic.lua
--- merge date  : Wed Apr  6 23:53:30 2016
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-lua']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-_MAJORVERSION,_MINORVERSION=string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$")
-_MAJORVERSION=tonumber(_MAJORVERSION) or 5
-_MINORVERSION=tonumber(_MINORVERSION) or 1
-_LUAVERSION=_MAJORVERSION+_MINORVERSION/10
-if _LUAVERSION<5.2 and jit then
-  _MINORVERSION=2
-  _LUAVERSION=5.2
-end
-if not lpeg then
-  lpeg=require("lpeg")
-end
-if loadstring then
-  local loadnormal=load
-  function load(first,...)
-    if type(first)=="string" then
-      return loadstring(first,...)
-    else
-      return loadnormal(first,...)
-    end
-  end
-else
-  loadstring=load
-end
-if not ipairs then
-  local function iterate(a,i)
-    i=i+1
-    local v=a[i]
-    if v~=nil then
-      return i,v 
-    end
-  end
-  function ipairs(a)
-    return iterate,a,0
-  end
-end
-if not pairs then
-  function pairs(t)
-    return next,t 
-  end
-end
-if not table.unpack then
-  table.unpack=_G.unpack
-elseif not unpack then
-  _G.unpack=table.unpack
-end
-if not package.loaders then 
-  package.loaders=package.searchers
-end
-local print,select,tostring=print,select,tostring
-local inspectors={}
-function setinspector(kind,inspector) 
-  inspectors[kind]=inspector
-end
-function inspect(...) 
-  for s=1,select("#",...) do
-    local value=select(s,...)
-    if value==nil then
-      print("nil")
-    else
-      local done=false
-      local kind=type(value)
-      local inspector=inspectors[kind]
-      if inspector then
-        done=inspector(value)
-        if done then
-          break
-        end
-      end
-      for kind,inspector in next,inspectors do
-        done=inspector(value)
-        if done then
-          break
-        end
-      end
-      if not done then
-        print(tostring(value))
-      end
-    end
-  end
-end
-local dummy=function() end
-function optionalrequire(...)
-  local ok,result=xpcall(require,dummy,...)
-  if ok then
-    return result
-  end
-end
-if lua then
-  lua.mask=load([[τεχ = 1]]) and "utf" or "ascii"
-end
-local flush=io.flush
-if flush then
-  local execute=os.execute if execute then function os.execute(...) flush() return execute(...) end end
-  local exec=os.exec  if exec  then function os.exec  (...) flush() return exec  (...) end end
-  local spawn=os.spawn  if spawn  then function os.spawn (...) flush() return spawn (...) end end
-  local popen=io.popen  if popen  then function io.popen (...) flush() return popen (...) end end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-package']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local type=type
-local gsub,format,find=string.gsub,string.format,string.find
-local P,S,Cs,lpegmatch=lpeg.P,lpeg.S,lpeg.Cs,lpeg.match
-local package=package
-local searchers=package.searchers or package.loaders
-local filejoin=file and file.join    or function(path,name)  return path.."/"..name end
-local isreadable=file and file.is_readable or function(name)    local f=io.open(name) if f then f:close() return true end end
-local addsuffix=file and file.addsuffix  or function(name,suffix) return name.."."..suffix end
-local function cleanpath(path) 
-  return path
-end
-local pattern=Cs((((1-S("\\/"))^0*(S("\\/")^1/"/"))^0*(P(".")^1/"/"+P(1))^1)*-1)
-local function lualibfile(name)
-  return lpegmatch(pattern,name) or name
-end
-local offset=luarocks and 1 or 0 
-local helpers=package.helpers or {
-  cleanpath=cleanpath,
-  lualibfile=lualibfile,
-  trace=false,
-  report=function(...) print(format(...)) end,
-  builtin={
-    ["preload table"]=searchers[1+offset],
-    ["path specification"]=searchers[2+offset],
-    ["cpath specification"]=searchers[3+offset],
-    ["all in one fallback"]=searchers[4+offset],
-  },
-  methods={},
-  sequence={
-    "already loaded",
-    "preload table",
-    "qualified path",
-    "lua extra list",
-    "lib extra list",
-    "path specification",
-    "cpath specification",
-    "all in one fallback",
-    "not loaded",
-  }
-}
-package.helpers=helpers
-local methods=helpers.methods
-local builtin=helpers.builtin
-local extraluapaths={}
-local extralibpaths={}
-local luapaths=nil 
-local libpaths=nil 
-local oldluapath=nil
-local oldlibpath=nil
-local nofextralua=-1
-local nofextralib=-1
-local nofpathlua=-1
-local nofpathlib=-1
-local function listpaths(what,paths)
-  local nofpaths=#paths
-  if nofpaths>0 then
-    for i=1,nofpaths do
-      helpers.report("using %s path %i: %s",what,i,paths[i])
-    end
-  else
-    helpers.report("no %s paths defined",what)
-  end
-  return nofpaths
-end
-local function getextraluapaths()
-  if helpers.trace and #extraluapaths~=nofextralua then
-    nofextralua=listpaths("extra lua",extraluapaths)
-  end
-  return extraluapaths
-end
-local function getextralibpaths()
-  if helpers.trace and #extralibpaths~=nofextralib then
-    nofextralib=listpaths("extra lib",extralibpaths)
-  end
-  return extralibpaths
-end
-local function getluapaths()
-  local luapath=package.path or ""
-  if oldluapath~=luapath then
-    luapaths=file.splitpath(luapath,";")
-    oldluapath=luapath
-    nofpathlua=-1
-  end
-  if helpers.trace and #luapaths~=nofpathlua then
-    nofpathlua=listpaths("builtin lua",luapaths)
-  end
-  return luapaths
-end
-local function getlibpaths()
-  local libpath=package.cpath or ""
-  if oldlibpath~=libpath then
-    libpaths=file.splitpath(libpath,";")
-    oldlibpath=libpath
-    nofpathlib=-1
-  end
-  if helpers.trace and #libpaths~=nofpathlib then
-    nofpathlib=listpaths("builtin lib",libpaths)
-  end
-  return libpaths
-end
-package.luapaths=getluapaths
-package.libpaths=getlibpaths
-package.extraluapaths=getextraluapaths
-package.extralibpaths=getextralibpaths
-local hashes={
-  lua={},
-  lib={},
-}
-local function registerpath(tag,what,target,...)
-  local pathlist={... }
-  local cleanpath=helpers.cleanpath
-  local trace=helpers.trace
-  local report=helpers.report
-  local hash=hashes[what]
-  local function add(path)
-    local path=cleanpath(path)
-    if not hash[path] then
-      target[#target+1]=path
-      hash[path]=true
-      if trace then
-        report("registered %s path %s: %s",tag,#target,path)
-      end
-    else
-      if trace then
-        report("duplicate %s path: %s",tag,path)
-      end
-    end
-  end
-  for p=1,#pathlist do
-    local path=pathlist[p]
-    if type(path)=="table" then
-      for i=1,#path do
-        add(path[i])
-      end
-    else
-      add(path)
-    end
-  end
-  return paths
-end
-helpers.registerpath=registerpath
-function package.extraluapath(...)
-  registerpath("extra lua","lua",extraluapaths,...)
-end
-function package.extralibpath(...)
-  registerpath("extra lib","lib",extralibpaths,...)
-end
-local function loadedaslib(resolved,rawname) 
-  local base=gsub(rawname,"%.","_")
-  local init="luaopen_"..gsub(base,"%.","_")
-  if helpers.trace then
-    helpers.report("calling loadlib with '%s' with init '%s'",resolved,init)
-  end
-  return package.loadlib(resolved,init)
-end
-helpers.loadedaslib=loadedaslib
-local function loadedbypath(name,rawname,paths,islib,what)
-  local trace=helpers.trace
-  for p=1,#paths do
-    local path=paths[p]
-    local resolved=filejoin(path,name)
-    if trace then
-      helpers.report("%s path, identifying '%s' on '%s'",what,name,path)
-    end
-    if isreadable(resolved) then
-      if trace then
-        helpers.report("%s path, '%s' found on '%s'",what,name,resolved)
-      end
-      if islib then
-        return loadedaslib(resolved,rawname)
-      else
-        return loadfile(resolved)
-      end
-    end
-  end
-end
-helpers.loadedbypath=loadedbypath
-local function loadedbyname(name,rawname)
-  if find(name,"^/") or find(name,"^[a-zA-Z]:/") then
-    local trace=helpers.trace
-    if trace then
-      helpers.report("qualified name, identifying '%s'",what,name)
-    end
-    if isreadable(name) then
-      if trace then
-        helpers.report("qualified name, '%s' found",what,name)
-      end
-      return loadfile(name)
-    end
-  end
-end
-helpers.loadedbyname=loadedbyname
-methods["already loaded"]=function(name)
-  return package.loaded[name]
-end
-methods["preload table"]=function(name)
-  return builtin["preload table"](name)
-end
-methods["qualified path"]=function(name)
- return loadedbyname(addsuffix(lualibfile(name),"lua"),name)
-end
-methods["lua extra list"]=function(name)
-  return loadedbypath(addsuffix(lualibfile(name),"lua"),name,getextraluapaths(),false,"lua")
-end
-methods["lib extra list"]=function(name)
-  return loadedbypath(addsuffix(lualibfile(name),os.libsuffix),name,getextralibpaths(),true,"lib")
-end
-methods["path specification"]=function(name)
-  getluapaths() 
-  return builtin["path specification"](name)
-end
-methods["cpath specification"]=function(name)
-  getlibpaths() 
-  return builtin["cpath specification"](name)
-end
-methods["all in one fallback"]=function(name)
-  return builtin["all in one fallback"](name)
-end
-methods["not loaded"]=function(name)
-  if helpers.trace then
-    helpers.report("unable to locate '%s'",name or "?")
-  end
-  return nil
-end
-local level=0
-local used={}
-helpers.traceused=false
-function helpers.loaded(name)
-  local sequence=helpers.sequence
-  level=level+1
-  for i=1,#sequence do
-    local method=sequence[i]
-    if helpers.trace then
-      helpers.report("%s, level '%s', method '%s', name '%s'","locating",level,method,name)
-    end
-    local result,rest=methods[method](name)
-    if type(result)=="function" then
-      if helpers.trace then
-        helpers.report("%s, level '%s', method '%s', name '%s'","found",level,method,name)
-      end
-      if helpers.traceused then
-        used[#used+1]={ level=level,name=name }
-      end
-      level=level-1
-      return result,rest
-    end
-  end
-  level=level-1
-  return nil
-end
-function helpers.showused()
-  local n=#used
-  if n>0 then
-    helpers.report("%s libraries loaded:",n)
-    helpers.report()
-    for i=1,n do
-      local u=used[i]
-      helpers.report("%i %a",u.level,u.name)
-    end
-    helpers.report()
-   end
-end
-function helpers.unload(name)
-  if helpers.trace then
-    if package.loaded[name] then
-      helpers.report("unloading, name '%s', %s",name,"done")
-    else
-      helpers.report("unloading, name '%s', %s",name,"not loaded")
-    end
-  end
-  package.loaded[name]=nil
-end
-table.insert(searchers,1,helpers.loaded)
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-lpeg']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-lpeg=require("lpeg")
-if not lpeg.print then function lpeg.print(...) print(lpeg.pcode(...)) end end
-local type,next,tostring=type,next,tostring
-local byte,char,gmatch,format=string.byte,string.char,string.gmatch,string.format
-local floor=math.floor
-local P,R,S,V,Ct,C,Cs,Cc,Cp,Cmt=lpeg.P,lpeg.R,lpeg.S,lpeg.V,lpeg.Ct,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Cp,lpeg.Cmt
-local lpegtype,lpegmatch,lpegprint=lpeg.type,lpeg.match,lpeg.print
-if setinspector then
-  setinspector("lpeg",function(v) if lpegtype(v) then lpegprint(v) return true end end)
-end
-lpeg.patterns=lpeg.patterns or {} 
-local patterns=lpeg.patterns
-local anything=P(1)
-local endofstring=P(-1)
-local alwaysmatched=P(true)
-patterns.anything=anything
-patterns.endofstring=endofstring
-patterns.beginofstring=alwaysmatched
-patterns.alwaysmatched=alwaysmatched
-local sign=S('+-')
-local zero=P('0')
-local digit=R('09')
-local octdigit=R("07")
-local lowercase=R("az")
-local uppercase=R("AZ")
-local underscore=P("_")
-local hexdigit=digit+lowercase+uppercase
-local cr,lf,crlf=P("\r"),P("\n"),P("\r\n")
-local newline=P("\r")*(P("\n")+P(true))+P("\n") 
-local escaped=P("\\")*anything
-local squote=P("'")
-local dquote=P('"')
-local space=P(" ")
-local period=P(".")
-local comma=P(",")
-local utfbom_32_be=P('\000\000\254\255') 
-local utfbom_32_le=P('\255\254\000\000') 
-local utfbom_16_be=P('\254\255')     
-local utfbom_16_le=P('\255\254')     
-local utfbom_8=P('\239\187\191')   
-local utfbom=utfbom_32_be+utfbom_32_le+utfbom_16_be+utfbom_16_le+utfbom_8
-local utftype=utfbom_32_be*Cc("utf-32-be")+utfbom_32_le*Cc("utf-32-le")+utfbom_16_be*Cc("utf-16-be")+utfbom_16_le*Cc("utf-16-le")+utfbom_8*Cc("utf-8")+alwaysmatched*Cc("utf-8") 
-local utfstricttype=utfbom_32_be*Cc("utf-32-be")+utfbom_32_le*Cc("utf-32-le")+utfbom_16_be*Cc("utf-16-be")+utfbom_16_le*Cc("utf-16-le")+utfbom_8*Cc("utf-8")
-local utfoffset=utfbom_32_be*Cc(4)+utfbom_32_le*Cc(4)+utfbom_16_be*Cc(2)+utfbom_16_le*Cc(2)+utfbom_8*Cc(3)+Cc(0)
-local utf8next=R("\128\191")
-patterns.utfbom_32_be=utfbom_32_be
-patterns.utfbom_32_le=utfbom_32_le
-patterns.utfbom_16_be=utfbom_16_be
-patterns.utfbom_16_le=utfbom_16_le
-patterns.utfbom_8=utfbom_8
-patterns.utf_16_be_nl=P("\000\r\000\n")+P("\000\r")+P("\000\n") 
-patterns.utf_16_le_nl=P("\r\000\n\000")+P("\r\000")+P("\n\000") 
-patterns.utf_32_be_nl=P("\000\000\000\r\000\000\000\n")+P("\000\000\000\r")+P("\000\000\000\n")
-patterns.utf_32_le_nl=P("\r\000\000\000\n\000\000\000")+P("\r\000\000\000")+P("\n\000\000\000")
-patterns.utf8one=R("\000\127")
-patterns.utf8two=R("\194\223")*utf8next
-patterns.utf8three=R("\224\239")*utf8next*utf8next
-patterns.utf8four=R("\240\244")*utf8next*utf8next*utf8next
-patterns.utfbom=utfbom
-patterns.utftype=utftype
-patterns.utfstricttype=utfstricttype
-patterns.utfoffset=utfoffset
-local utf8char=patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four
-local validutf8char=utf8char^0*endofstring*Cc(true)+Cc(false)
-local utf8character=P(1)*R("\128\191")^0 
-patterns.utf8=utf8char
-patterns.utf8char=utf8char
-patterns.utf8character=utf8character 
-patterns.validutf8=validutf8char
-patterns.validutf8char=validutf8char
-local eol=S("\n\r")
-local spacer=S(" \t\f\v") 
-local whitespace=eol+spacer
-local nonspacer=1-spacer
-local nonwhitespace=1-whitespace
-patterns.eol=eol
-patterns.spacer=spacer
-patterns.whitespace=whitespace
-patterns.nonspacer=nonspacer
-patterns.nonwhitespace=nonwhitespace
-local stripper=spacer^0*C((spacer^0*nonspacer^1)^0)   
-local fullstripper=whitespace^0*C((whitespace^0*nonwhitespace^1)^0)
-local collapser=Cs(spacer^0/""*nonspacer^0*((spacer^0/" "*nonspacer^1)^0))
-local b_collapser=Cs(whitespace^0/""*(nonwhitespace^1+whitespace^1/" ")^0)
-local e_collapser=Cs((whitespace^1*P(-1)/""+nonwhitespace^1+whitespace^1/" ")^0)
-local m_collapser=Cs((nonwhitespace^1+whitespace^1/" ")^0)
-local b_stripper=Cs(spacer^0/""*(nonspacer^1+spacer^1/" ")^0)
-local e_stripper=Cs((spacer^1*P(-1)/""+nonspacer^1+spacer^1/" ")^0)
-local m_stripper=Cs((nonspacer^1+spacer^1/" ")^0)
-patterns.stripper=stripper
-patterns.fullstripper=fullstripper
-patterns.collapser=collapser
-patterns.b_collapser=b_collapser
-patterns.m_collapser=m_collapser
-patterns.e_collapser=e_collapser
-patterns.b_stripper=b_stripper
-patterns.m_stripper=m_stripper
-patterns.e_stripper=e_stripper
-patterns.lowercase=lowercase
-patterns.uppercase=uppercase
-patterns.letter=patterns.lowercase+patterns.uppercase
-patterns.space=space
-patterns.tab=P("\t")
-patterns.spaceortab=patterns.space+patterns.tab
-patterns.newline=newline
-patterns.emptyline=newline^1
-patterns.equal=P("=")
-patterns.comma=comma
-patterns.commaspacer=comma*spacer^0
-patterns.period=period
-patterns.colon=P(":")
-patterns.semicolon=P(";")
-patterns.underscore=underscore
-patterns.escaped=escaped
-patterns.squote=squote
-patterns.dquote=dquote
-patterns.nosquote=(escaped+(1-squote))^0
-patterns.nodquote=(escaped+(1-dquote))^0
-patterns.unsingle=(squote/"")*patterns.nosquote*(squote/"") 
-patterns.undouble=(dquote/"")*patterns.nodquote*(dquote/"") 
-patterns.unquoted=patterns.undouble+patterns.unsingle 
-patterns.unspacer=((patterns.spacer^1)/"")^0
-patterns.singlequoted=squote*patterns.nosquote*squote
-patterns.doublequoted=dquote*patterns.nodquote*dquote
-patterns.quoted=patterns.doublequoted+patterns.singlequoted
-patterns.digit=digit
-patterns.octdigit=octdigit
-patterns.hexdigit=hexdigit
-patterns.sign=sign
-patterns.cardinal=digit^1
-patterns.integer=sign^-1*digit^1
-patterns.unsigned=digit^0*period*digit^1
-patterns.float=sign^-1*patterns.unsigned
-patterns.cunsigned=digit^0*comma*digit^1
-patterns.cpunsigned=digit^0*(period+comma)*digit^1
-patterns.cfloat=sign^-1*patterns.cunsigned
-patterns.cpfloat=sign^-1*patterns.cpunsigned
-patterns.number=patterns.float+patterns.integer
-patterns.cnumber=patterns.cfloat+patterns.integer
-patterns.cpnumber=patterns.cpfloat+patterns.integer
-patterns.oct=zero*octdigit^1
-patterns.octal=patterns.oct
-patterns.HEX=zero*P("X")*(digit+uppercase)^1
-patterns.hex=zero*P("x")*(digit+lowercase)^1
-patterns.hexadecimal=zero*S("xX")*hexdigit^1
-patterns.hexafloat=sign^-1*zero*S("xX")*(hexdigit^0*period*hexdigit^1+hexdigit^1*period*hexdigit^0+hexdigit^1)*(S("pP")*sign^-1*hexdigit^1)^-1
-patterns.decafloat=sign^-1*(digit^0*period*digit^1+digit^1*period*digit^0+digit^1)*S("eE")*sign^-1*digit^1
-patterns.propername=(uppercase+lowercase+underscore)*(uppercase+lowercase+underscore+digit)^0*endofstring
-patterns.somecontent=(anything-newline-space)^1 
-patterns.beginline=#(1-newline)
-patterns.longtostring=Cs(whitespace^0/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(P(-1)+Cc(" ")))^0))
-local function anywhere(pattern) 
-  return P { P(pattern)+1*V(1) }
-end
-lpeg.anywhere=anywhere
-function lpeg.instringchecker(p)
-  p=anywhere(p)
-  return function(str)
-    return lpegmatch(p,str) and true or false
-  end
-end
-function lpeg.splitter(pattern,action)
-  return (((1-P(pattern))^1)/action+1)^0
-end
-function lpeg.tsplitter(pattern,action)
-  return Ct((((1-P(pattern))^1)/action+1)^0)
-end
-local splitters_s,splitters_m,splitters_t={},{},{}
-local function splitat(separator,single)
-  local splitter=(single and splitters_s[separator]) or splitters_m[separator]
-  if not splitter then
-    separator=P(separator)
-    local other=C((1-separator)^0)
-    if single then
-      local any=anything
-      splitter=other*(separator*C(any^0)+"") 
-      splitters_s[separator]=splitter
-    else
-      splitter=other*(separator*other)^0
-      splitters_m[separator]=splitter
-    end
-  end
-  return splitter
-end
-local function tsplitat(separator)
-  local splitter=splitters_t[separator]
-  if not splitter then
-    splitter=Ct(splitat(separator))
-    splitters_t[separator]=splitter
-  end
-  return splitter
-end
-lpeg.splitat=splitat
-lpeg.tsplitat=tsplitat
-function string.splitup(str,separator)
-  if not separator then
-    separator=","
-  end
-  return lpegmatch(splitters_m[separator] or splitat(separator),str)
-end
-local cache={}
-function lpeg.split(separator,str)
-  local c=cache[separator]
-  if not c then
-    c=tsplitat(separator)
-    cache[separator]=c
-  end
-  return lpegmatch(c,str)
-end
-function string.split(str,separator)
-  if separator then
-    local c=cache[separator]
-    if not c then
-      c=tsplitat(separator)
-      cache[separator]=c
-    end
-    return lpegmatch(c,str)
-  else
-    return { str }
-  end
-end
-local spacing=patterns.spacer^0*newline 
-local empty=spacing*Cc("")
-local nonempty=Cs((1-spacing)^1)*spacing^-1
-local content=(empty+nonempty)^1
-patterns.textline=content
-local linesplitter=tsplitat(newline)
-patterns.linesplitter=linesplitter
-function string.splitlines(str)
-  return lpegmatch(linesplitter,str)
-end
-local cache={}
-function lpeg.checkedsplit(separator,str)
-  local c=cache[separator]
-  if not c then
-    separator=P(separator)
-    local other=C((1-separator)^1)
-    c=Ct(separator^0*other*(separator^1*other)^0)
-    cache[separator]=c
-  end
-  return lpegmatch(c,str)
-end
-function string.checkedsplit(str,separator)
-  local c=cache[separator]
-  if not c then
-    separator=P(separator)
-    local other=C((1-separator)^1)
-    c=Ct(separator^0*other*(separator^1*other)^0)
-    cache[separator]=c
-  end
-  return lpegmatch(c,str)
-end
-local function f2(s) local c1,c2=byte(s,1,2) return  c1*64+c2-12416 end
-local function f3(s) local c1,c2,c3=byte(s,1,3) return (c1*64+c2)*64+c3-925824 end
-local function f4(s) local c1,c2,c3,c4=byte(s,1,4) return ((c1*64+c2)*64+c3)*64+c4-63447168 end
-local utf8byte=patterns.utf8one/byte+patterns.utf8two/f2+patterns.utf8three/f3+patterns.utf8four/f4
-patterns.utf8byte=utf8byte
-local cache={}
-function lpeg.stripper(str)
-  if type(str)=="string" then
-    local s=cache[str]
-    if not s then
-      s=Cs(((S(str)^1)/""+1)^0)
-      cache[str]=s
-    end
-    return s
-  else
-    return Cs(((str^1)/""+1)^0)
-  end
-end
-local cache={}
-function lpeg.keeper(str)
-  if type(str)=="string" then
-    local s=cache[str]
-    if not s then
-      s=Cs((((1-S(str))^1)/""+1)^0)
-      cache[str]=s
-    end
-    return s
-  else
-    return Cs((((1-str)^1)/""+1)^0)
-  end
-end
-function lpeg.frontstripper(str) 
-  return (P(str)+P(true))*Cs(anything^0)
-end
-function lpeg.endstripper(str) 
-  return Cs((1-P(str)*endofstring)^0)
-end
-function lpeg.replacer(one,two,makefunction,isutf) 
-  local pattern
-  local u=isutf and utf8char or 1
-  if type(one)=="table" then
-    local no=#one
-    local p=P(false)
-    if no==0 then
-      for k,v in next,one do
-        p=p+P(k)/v
-      end
-      pattern=Cs((p+u)^0)
-    elseif no==1 then
-      local o=one[1]
-      one,two=P(o[1]),o[2]
-      pattern=Cs((one/two+u)^0)
-    else
-      for i=1,no do
-        local o=one[i]
-        p=p+P(o[1])/o[2]
-      end
-      pattern=Cs((p+u)^0)
-    end
-  else
-    pattern=Cs((P(one)/(two or "")+u)^0)
-  end
-  if makefunction then
-    return function(str)
-      return lpegmatch(pattern,str)
-    end
-  else
-    return pattern
-  end
-end
-function lpeg.finder(lst,makefunction,isutf) 
-  local pattern
-  if type(lst)=="table" then
-    pattern=P(false)
-    if #lst==0 then
-      for k,v in next,lst do
-        pattern=pattern+P(k) 
-      end
-    else
-      for i=1,#lst do
-        pattern=pattern+P(lst[i])
-      end
-    end
-  else
-    pattern=P(lst)
-  end
-  if isutf then
-    pattern=((utf8char or 1)-pattern)^0*pattern
-  else
-    pattern=(1-pattern)^0*pattern
-  end
-  if makefunction then
-    return function(str)
-      return lpegmatch(pattern,str)
-    end
-  else
-    return pattern
-  end
-end
-local splitters_f,splitters_s={},{}
-function lpeg.firstofsplit(separator) 
-  local splitter=splitters_f[separator]
-  if not splitter then
-    local pattern=P(separator)
-    splitter=C((1-pattern)^0)
-    splitters_f[separator]=splitter
-  end
-  return splitter
-end
-function lpeg.secondofsplit(separator) 
-  local splitter=splitters_s[separator]
-  if not splitter then
-    local pattern=P(separator)
-    splitter=(1-pattern)^0*pattern*C(anything^0)
-    splitters_s[separator]=splitter
-  end
-  return splitter
-end
-local splitters_s,splitters_p={},{}
-function lpeg.beforesuffix(separator) 
-  local splitter=splitters_s[separator]
-  if not splitter then
-    local pattern=P(separator)
-    splitter=C((1-pattern)^0)*pattern*endofstring
-    splitters_s[separator]=splitter
-  end
-  return splitter
-end
-function lpeg.afterprefix(separator) 
-  local splitter=splitters_p[separator]
-  if not splitter then
-    local pattern=P(separator)
-    splitter=pattern*C(anything^0)
-    splitters_p[separator]=splitter
-  end
-  return splitter
-end
-function lpeg.balancer(left,right)
-  left,right=P(left),P(right)
-  return P { left*((1-left-right)+V(1))^0*right }
-end
-local nany=utf8char/""
-function lpeg.counter(pattern)
-  pattern=Cs((P(pattern)/" "+nany)^0)
-  return function(str)
-    return #lpegmatch(pattern,str)
-  end
-end
-utf=utf or (unicode and unicode.utf8) or {}
-local utfcharacters=utf and utf.characters or string.utfcharacters
-local utfgmatch=utf and utf.gmatch
-local utfchar=utf and utf.char
-lpeg.UP=lpeg.P
-if utfcharacters then
-  function lpeg.US(str)
-    local p=P(false)
-    for uc in utfcharacters(str) do
-      p=p+P(uc)
-    end
-    return p
-  end
-elseif utfgmatch then
-  function lpeg.US(str)
-    local p=P(false)
-    for uc in utfgmatch(str,".") do
-      p=p+P(uc)
-    end
-    return p
-  end
-else
-  function lpeg.US(str)
-    local p=P(false)
-    local f=function(uc)
-      p=p+P(uc)
-    end
-    lpegmatch((utf8char/f)^0,str)
-    return p
-  end
-end
-local range=utf8byte*utf8byte+Cc(false) 
-function lpeg.UR(str,more)
-  local first,last
-  if type(str)=="number" then
-    first=str
-    last=more or first
-  else
-    first,last=lpegmatch(range,str)
-    if not last then
-      return P(str)
-    end
-  end
-  if first==last then
-    return P(str)
-  elseif utfchar and (last-first<8) then 
-    local p=P(false)
-    for i=first,last do
-      p=p+P(utfchar(i))
-    end
-    return p 
-  else
-    local f=function(b)
-      return b>=first and b<=last
-    end
-    return utf8byte/f 
-  end
-end
-function lpeg.is_lpeg(p)
-  return p and lpegtype(p)=="pattern"
-end
-function lpeg.oneof(list,...) 
-  if type(list)~="table" then
-    list={ list,... }
-  end
-  local p=P(list[1])
-  for l=2,#list do
-    p=p+P(list[l])
-  end
-  return p
-end
-local sort=table.sort
-local function copyindexed(old)
-  local new={}
-  for i=1,#old do
-    new[i]=old
-  end
-  return new
-end
-local function sortedkeys(tab)
-  local keys,s={},0
-  for key,_ in next,tab do
-    s=s+1
-    keys[s]=key
-  end
-  sort(keys)
-  return keys
-end
-function lpeg.append(list,pp,delayed,checked)
-  local p=pp
-  if #list>0 then
-    local keys=copyindexed(list)
-    sort(keys)
-    for i=#keys,1,-1 do
-      local k=keys[i]
-      if p then
-        p=P(k)+p
-      else
-        p=P(k)
-      end
-    end
-  elseif delayed then 
-    local keys=sortedkeys(list)
-    if p then
-      for i=1,#keys,1 do
-        local k=keys[i]
-        local v=list[k]
-        p=P(k)/list+p
-      end
-    else
-      for i=1,#keys do
-        local k=keys[i]
-        local v=list[k]
-        if p then
-          p=P(k)+p
-        else
-          p=P(k)
-        end
-      end
-      if p then
-        p=p/list
-      end
-    end
-  elseif checked then
-    local keys=sortedkeys(list)
-    for i=1,#keys do
-      local k=keys[i]
-      local v=list[k]
-      if p then
-        if k==v then
-          p=P(k)+p
-        else
-          p=P(k)/v+p
-        end
-      else
-        if k==v then
-          p=P(k)
-        else
-          p=P(k)/v
-        end
-      end
-    end
-  else
-    local keys=sortedkeys(list)
-    for i=1,#keys do
-      local k=keys[i]
-      local v=list[k]
-      if p then
-        p=P(k)/v+p
-      else
-        p=P(k)/v
-      end
-    end
-  end
-  return p
-end
-local p_false=P(false)
-local p_true=P(true)
-local function make(t)
-  local function making(t)
-    local p=p_false
-    local keys=sortedkeys(t)
-    for i=1,#keys do
-      local k=keys[i]
-      if k~="" then
-        local v=t[k]
-        if v==true then
-          p=p+P(k)*p_true
-        elseif v==false then
-        else
-          p=p+P(k)*making(v)
-        end
-      end
-    end
-    if t[""] then
-      p=p+p_true
-    end
-    return p
-  end
-  local p=p_false
-  local keys=sortedkeys(t)
-  for i=1,#keys do
-    local k=keys[i]
-    if k~="" then
-      local v=t[k]
-      if v==true then
-        p=p+P(k)*p_true
-      elseif v==false then
-      else
-        p=p+P(k)*making(v)
-      end
-    end
-  end
-  return p
-end
-local function collapse(t,x)
-  if type(t)~="table" then
-    return t,x
-  else
-    local n=next(t)
-    if n==nil then
-      return t,x
-    elseif next(t,n)==nil then
-      local k=n
-      local v=t[k]
-      if type(v)=="table" then
-        return collapse(v,x..k)
-      else
-        return v,x..k
-      end
-    else
-      local tt={}
-      for k,v in next,t do
-        local vv,kk=collapse(v,k)
-        tt[kk]=vv
-      end
-      return tt,x
-    end
-  end
-end
-function lpeg.utfchartabletopattern(list) 
-  local tree={}
-  local n=#list
-  if n==0 then
-    for s in next,list do
-      local t=tree
-      local p,pk
-      for c in gmatch(s,".") do
-        if t==true then
-          t={ [c]=true,[""]=true }
-          p[pk]=t
-          p=t
-          t=false
-        elseif t==false then
-          t={ [c]=false }
-          p[pk]=t
-          p=t
-          t=false
-        else
-          local tc=t[c]
-          if not tc then
-            tc=false
-            t[c]=false
-          end
-          p=t
-          t=tc
-        end
-        pk=c
-      end
-      if t==false then
-        p[pk]=true
-      elseif t==true then
-      else
-        t[""]=true
-      end
-    end
-  else
-    for i=1,n do
-      local s=list[i]
-      local t=tree
-      local p,pk
-      for c in gmatch(s,".") do
-        if t==true then
-          t={ [c]=true,[""]=true }
-          p[pk]=t
-          p=t
-          t=false
-        elseif t==false then
-          t={ [c]=false }
-          p[pk]=t
-          p=t
-          t=false
-        else
-          local tc=t[c]
-          if not tc then
-            tc=false
-            t[c]=false
-          end
-          p=t
-          t=tc
-        end
-        pk=c
-      end
-      if t==false then
-        p[pk]=true
-      elseif t==true then
-      else
-        t[""]=true
-      end
-    end
-  end
-  return make(tree)
-end
-patterns.containseol=lpeg.finder(eol)
-local function nextstep(n,step,result)
-  local m=n%step   
-  local d=floor(n/step) 
-  if d>0 then
-    local v=V(tostring(step))
-    local s=result.start
-    for i=1,d do
-      if s then
-        s=v*s
-      else
-        s=v
-      end
-    end
-    result.start=s
-  end
-  if step>1 and result.start then
-    local v=V(tostring(step/2))
-    result[tostring(step)]=v*v
-  end
-  if step>0 then
-    return nextstep(m,step/2,result)
-  else
-    return result
-  end
-end
-function lpeg.times(pattern,n)
-  return P(nextstep(n,2^16,{ "start",["1"]=pattern }))
-end
-local trailingzeros=zero^0*-digit 
-local case_1=period*trailingzeros/""
-local case_2=period*(digit-trailingzeros)^1*(trailingzeros/"")
-local number=digit^1*(case_1+case_2)
-local stripper=Cs((number+1)^0)
-lpeg.patterns.stripzeros=stripper
-local byte_to_HEX={}
-local byte_to_hex={}
-local byte_to_dec={} 
-local hex_to_byte={}
-for i=0,255 do
-  local H=format("%02X",i)
-  local h=format("%02x",i)
-  local d=format("%03i",i)
-  local c=char(i)
-  byte_to_HEX[c]=H
-  byte_to_hex[c]=h
-  byte_to_dec[c]=d
-  hex_to_byte[h]=c
-  hex_to_byte[H]=c
-end
-local hextobyte=P(2)/hex_to_byte
-local bytetoHEX=P(1)/byte_to_HEX
-local bytetohex=P(1)/byte_to_hex
-local bytetodec=P(1)/byte_to_dec
-local hextobytes=Cs(hextobyte^0)
-local bytestoHEX=Cs(bytetoHEX^0)
-local bytestohex=Cs(bytetohex^0)
-local bytestodec=Cs(bytetodec^0)
-patterns.hextobyte=hextobyte
-patterns.bytetoHEX=bytetoHEX
-patterns.bytetohex=bytetohex
-patterns.bytetodec=bytetodec
-patterns.hextobytes=hextobytes
-patterns.bytestoHEX=bytestoHEX
-patterns.bytestohex=bytestohex
-patterns.bytestodec=bytestodec
-function string.toHEX(s)
-  if not s or s=="" then
-    return s
-  else
-    return lpegmatch(bytestoHEX,s)
-  end
-end
-function string.tohex(s)
-  if not s or s=="" then
-    return s
-  else
-    return lpegmatch(bytestohex,s)
-  end
-end
-function string.todec(s)
-  if not s or s=="" then
-    return s
-  else
-    return lpegmatch(bytestodec,s)
-  end
-end
-function string.tobytes(s)
-  if not s or s=="" then
-    return s
-  else
-    return lpegmatch(hextobytes,s)
-  end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-functions']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-functions=functions or {}
-function functions.dummy() end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-string']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local string=string
-local sub,gmatch,format,char,byte,rep,lower=string.sub,string.gmatch,string.format,string.char,string.byte,string.rep,string.lower
-local lpegmatch,patterns=lpeg.match,lpeg.patterns
-local P,S,C,Ct,Cc,Cs=lpeg.P,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cc,lpeg.Cs
-local unquoted=patterns.squote*C(patterns.nosquote)*patterns.squote+patterns.dquote*C(patterns.nodquote)*patterns.dquote
-function string.unquoted(str)
-  return lpegmatch(unquoted,str) or str
-end
-function string.quoted(str)
-  return format("%q",str) 
-end
-function string.count(str,pattern) 
-  local n=0
-  for _ in gmatch(str,pattern) do 
-    n=n+1
-  end
-  return n
-end
-function string.limit(str,n,sentinel) 
-  if #str>n then
-    sentinel=sentinel or "..."
-    return sub(str,1,(n-#sentinel))..sentinel
-  else
-    return str
-  end
-end
-local stripper=patterns.stripper
-local fullstripper=patterns.fullstripper
-local collapser=patterns.collapser
-local longtostring=patterns.longtostring
-function string.strip(str)
-  return lpegmatch(stripper,str) or ""
-end
-function string.fullstrip(str)
-  return lpegmatch(fullstripper,str) or ""
-end
-function string.collapsespaces(str)
-  return lpegmatch(collapser,str) or ""
-end
-function string.longtostring(str)
-  return lpegmatch(longtostring,str) or ""
-end
-local pattern=P(" ")^0*P(-1)
-function string.is_empty(str)
-  if str=="" then
-    return true
-  else
-    return lpegmatch(pattern,str) and true or false
-  end
-end
-local anything=patterns.anything
-local allescapes=Cc("%")*S(".-+%?()[]*") 
-local someescapes=Cc("%")*S(".-+%()[]")  
-local matchescapes=Cc(".")*S("*?")     
-local pattern_a=Cs ((allescapes+anything )^0 )
-local pattern_b=Cs ((someescapes+matchescapes+anything )^0 )
-local pattern_c=Cs (Cc("^")*(someescapes+matchescapes+anything )^0*Cc("$") )
-function string.escapedpattern(str,simple)
-  return lpegmatch(simple and pattern_b or pattern_a,str)
-end
-function string.topattern(str,lowercase,strict)
-  if str=="" or type(str)~="string" then
-    return ".*"
-  elseif strict then
-    str=lpegmatch(pattern_c,str)
-  else
-    str=lpegmatch(pattern_b,str)
-  end
-  if lowercase then
-    return lower(str)
-  else
-    return str
-  end
-end
-function string.valid(str,default)
-  return (type(str)=="string" and str~="" and str) or default or nil
-end
-string.itself=function(s) return s end
-local pattern_c=Ct(C(1)^0) 
-local pattern_b=Ct((C(1)/byte)^0)
-function string.totable(str,bytes)
-  return lpegmatch(bytes and pattern_b or pattern_c,str)
-end
-local replacer=lpeg.replacer("@","%%") 
-function string.tformat(fmt,...)
-  return format(lpegmatch(replacer,fmt),...)
-end
-string.quote=string.quoted
-string.unquote=string.unquoted
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-table']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local type,next,tostring,tonumber,ipairs,select=type,next,tostring,tonumber,ipairs,select
-local table,string=table,string
-local concat,sort,insert,remove=table.concat,table.sort,table.insert,table.remove
-local format,lower,dump=string.format,string.lower,string.dump
-local getmetatable,setmetatable=getmetatable,setmetatable
-local getinfo=debug.getinfo
-local lpegmatch,patterns=lpeg.match,lpeg.patterns
-local floor=math.floor
-local stripper=patterns.stripper
-function table.strip(tab)
-  local lst,l={},0
-  for i=1,#tab do
-    local s=lpegmatch(stripper,tab[i]) or ""
-    if s=="" then
-    else
-      l=l+1
-      lst[l]=s
-    end
-  end
-  return lst
-end
-function table.keys(t)
-  if t then
-    local keys,k={},0
-    for key in next,t do
-      k=k+1
-      keys[k]=key
-    end
-    return keys
-  else
-    return {}
-  end
-end
-local function compare(a,b)
-  local ta=type(a) 
-  if ta=="number" then
-    local tb=type(b) 
-    if ta==tb then
-      return a<b
-    elseif tb=="string" then
-      return tostring(a)<b
-    end
-  elseif ta=="string" then
-    local tb=type(b) 
-    if ta==tb then
-      return a<b
-    else
-      return a<tostring(b)
-    end
-  end
-  return tostring(a)<tostring(b) 
-end
-local function sortedkeys(tab)
-  if tab then
-    local srt,category,s={},0,0 
-    for key in next,tab do
-      s=s+1
-      srt[s]=key
-      if category==3 then
-      elseif category==1 then
-        if type(key)~="string" then
-          category=3
-        end
-      elseif category==2 then
-        if type(key)~="number" then
-          category=3
-        end
-      else
-        local tkey=type(key)
-        if tkey=="string" then
-          category=1
-        elseif tkey=="number" then
-          category=2
-        else
-          category=3
-        end
-      end
-    end
-    if s<2 then
-    elseif category==3 then
-      sort(srt,compare)
-    else
-      sort(srt)
-    end
-    return srt
-  else
-    return {}
-  end
-end
-local function sortedhashonly(tab)
-  if tab then
-    local srt,s={},0
-    for key in next,tab do
-      if type(key)=="string" then
-        s=s+1
-        srt[s]=key
-      end
-    end
-    if s>1 then
-      sort(srt)
-    end
-    return srt
-  else
-    return {}
-  end
-end
-local function sortedindexonly(tab)
-  if tab then
-    local srt,s={},0
-    for key in next,tab do
-      if type(key)=="number" then
-        s=s+1
-        srt[s]=key
-      end
-    end
-    if s>1 then
-      sort(srt)
-    end
-    return srt
-  else
-    return {}
-  end
-end
-local function sortedhashkeys(tab,cmp) 
-  if tab then
-    local srt,s={},0
-    for key in next,tab do
-      if key then
-        s=s+1
-        srt[s]=key
-      end
-    end
-    if s>1 then
-      sort(srt,cmp)
-    end
-    return srt
-  else
-    return {}
-  end
-end
-function table.allkeys(t)
-  local keys={}
-  for k,v in next,t do
-    for k in next,v do
-      keys[k]=true
-    end
-  end
-  return sortedkeys(keys)
-end
-table.sortedkeys=sortedkeys
-table.sortedhashonly=sortedhashonly
-table.sortedindexonly=sortedindexonly
-table.sortedhashkeys=sortedhashkeys
-local function nothing() end
-local function sortedhash(t,cmp)
-  if t then
-    local s
-    if cmp then
-      s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end)
-    else
-      s=sortedkeys(t) 
-    end
-    local m=#s
-    if m==1 then
-      return next,t
-    elseif m>0 then
-      local n=0
-      return function()
-        if n<m then
-          n=n+1
-          local k=s[n]
-          return k,t[k]
-        end
-      end
-    end
-  end
-  return nothing
-end
-table.sortedhash=sortedhash
-table.sortedpairs=sortedhash 
-function table.append(t,list)
-  local n=#t
-  for i=1,#list do
-    n=n+1
-    t[n]=list[i]
-  end
-  return t
-end
-function table.prepend(t,list)
-  local nl=#list
-  local nt=nl+#t
-  for i=#t,1,-1 do
-    t[nt]=t[i]
-    nt=nt-1
-  end
-  for i=1,#list do
-    t[i]=list[i]
-  end
-  return t
-end
-function table.merge(t,...) 
-  t=t or {}
-  for i=1,select("#",...) do
-    for k,v in next,(select(i,...)) do
-      t[k]=v
-    end
-  end
-  return t
-end
-function table.merged(...)
-  local t={}
-  for i=1,select("#",...) do
-    for k,v in next,(select(i,...)) do
-      t[k]=v
-    end
-  end
-  return t
-end
-function table.imerge(t,...)
-  local nt=#t
-  for i=1,select("#",...) do
-    local nst=select(i,...)
-    for j=1,#nst do
-      nt=nt+1
-      t[nt]=nst[j]
-    end
-  end
-  return t
-end
-function table.imerged(...)
-  local tmp,ntmp={},0
-  for i=1,select("#",...) do
-    local nst=select(i,...)
-    for j=1,#nst do
-      ntmp=ntmp+1
-      tmp[ntmp]=nst[j]
-    end
-  end
-  return tmp
-end
-local function fastcopy(old,metatabletoo) 
-  if old then
-    local new={}
-    for k,v in next,old do
-      if type(v)=="table" then
-        new[k]=fastcopy(v,metatabletoo) 
-      else
-        new[k]=v
-      end
-    end
-    if metatabletoo then
-      local mt=getmetatable(old)
-      if mt then
-        setmetatable(new,mt)
-      end
-    end
-    return new
-  else
-    return {}
-  end
-end
-local function copy(t,tables) 
-  tables=tables or {}
-  local tcopy={}
-  if not tables[t] then
-    tables[t]=tcopy
-  end
-  for i,v in next,t do 
-    if type(i)=="table" then
-      if tables[i] then
-        i=tables[i]
-      else
-        i=copy(i,tables)
-      end
-    end
-    if type(v)~="table" then
-      tcopy[i]=v
-    elseif tables[v] then
-      tcopy[i]=tables[v]
-    else
-      tcopy[i]=copy(v,tables)
-    end
-  end
-  local mt=getmetatable(t)
-  if mt then
-    setmetatable(tcopy,mt)
-  end
-  return tcopy
-end
-table.fastcopy=fastcopy
-table.copy=copy
-function table.derive(parent) 
-  local child={}
-  if parent then
-    setmetatable(child,{ __index=parent })
-  end
-  return child
-end
-function table.tohash(t,value)
-  local h={}
-  if t then
-    if value==nil then value=true end
-    for _,v in next,t do 
-      h[v]=value
-    end
-  end
-  return h
-end
-function table.fromhash(t)
-  local hsh,h={},0
-  for k,v in next,t do 
-    if v then
-      h=h+1
-      hsh[h]=k
-    end
-  end
-  return hsh
-end
-local noquotes,hexify,handle,compact,inline,functions
-local reserved=table.tohash { 
-  'and','break','do','else','elseif','end','false','for','function','if',
-  'in','local','nil','not','or','repeat','return','then','true','until','while',
-  'NaN','goto',
-}
-local function simple_table(t)
-  local nt=#t
-  if nt>0 then
-    local n=0
-    for _,v in next,t do
-      n=n+1
-    end
-    if n==nt then
-      local tt={}
-      for i=1,nt do
-        local v=t[i]
-        local tv=type(v)
-        if tv=="number" then
-          if hexify then
-            tt[i]=format("0x%X",v)
-          else
-            tt[i]=tostring(v) 
-          end
-        elseif tv=="string" then
-          tt[i]=format("%q",v)
-        elseif tv=="boolean" then
-          tt[i]=v and "true" or "false"
-        else
-          return nil
-        end
-      end
-      return tt
-    end
-  end
-  return nil
-end
-local propername=patterns.propername 
-local function dummy() end
-local function do_serialize(root,name,depth,level,indexed)
-  if level>0 then
-    depth=depth.." "
-    if indexed then
-      handle(format("%s{",depth))
-    else
-      local tn=type(name)
-      if tn=="number" then
-        if hexify then
-          handle(format("%s[0x%X]={",depth,name))
-        else
-          handle(format("%s[%s]={",depth,name))
-        end
-      elseif tn=="string" then
-        if noquotes and not reserved[name] and lpegmatch(propername,name) then
-          handle(format("%s%s={",depth,name))
-        else
-          handle(format("%s[%q]={",depth,name))
-        end
-      elseif tn=="boolean" then
-        handle(format("%s[%s]={",depth,name and "true" or "false"))
-      else
-        handle(format("%s{",depth))
-      end
-    end
-  end
-  if root and next(root)~=nil then
-    local first,last=nil,0
-    if compact then
-      last=#root
-      for k=1,last do
-        if root[k]==nil then
-          last=k-1
-          break
-        end
-      end
-      if last>0 then
-        first=1
-      end
-    end
-    local sk=sortedkeys(root)
-    for i=1,#sk do
-      local k=sk[i]
-      local v=root[k]
-      local tv=type(v)
-      local tk=type(k)
-      if compact and first and tk=="number" and k>=first and k<=last then
-        if tv=="number" then
-          if hexify then
-            handle(format("%s 0x%X,",depth,v))
-          else
-            handle(format("%s %s,",depth,v)) 
-          end
-        elseif tv=="string" then
-          handle(format("%s %q,",depth,v))
-        elseif tv=="table" then
-          if next(v)==nil then
-            handle(format("%s {},",depth))
-          elseif inline then 
-            local st=simple_table(v)
-            if st then
-              handle(format("%s { %s },",depth,concat(st,", ")))
-            else
-              do_serialize(v,k,depth,level+1,true)
-            end
-          else
-            do_serialize(v,k,depth,level+1,true)
-          end
-        elseif tv=="boolean" then
-          handle(format("%s %s,",depth,v and "true" or "false"))
-        elseif tv=="function" then
-          if functions then
-            handle(format('%s load(%q),',depth,dump(v))) 
-          else
-            handle(format('%s "function",',depth))
-          end
-        else
-          handle(format("%s %q,",depth,tostring(v)))
-        end
-      elseif k=="__p__" then 
-        if false then
-          handle(format("%s __p__=nil,",depth))
-        end
-      elseif tv=="number" then
-        if tk=="number" then
-          if hexify then
-            handle(format("%s [0x%X]=0x%X,",depth,k,v))
-          else
-            handle(format("%s [%s]=%s,",depth,k,v)) 
-          end
-        elseif tk=="boolean" then
-          if hexify then
-            handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v))
-          else
-            handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) 
-          end
-        elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
-          if hexify then
-            handle(format("%s %s=0x%X,",depth,k,v))
-          else
-            handle(format("%s %s=%s,",depth,k,v)) 
-          end
-        else
-          if hexify then
-            handle(format("%s [%q]=0x%X,",depth,k,v))
-          else
-            handle(format("%s [%q]=%s,",depth,k,v)) 
-          end
-        end
-      elseif tv=="string" then
-        if tk=="number" then
-          if hexify then
-            handle(format("%s [0x%X]=%q,",depth,k,v))
-          else
-            handle(format("%s [%s]=%q,",depth,k,v))
-          end
-        elseif tk=="boolean" then
-          handle(format("%s [%s]=%q,",depth,k and "true" or "false",v))
-        elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
-          handle(format("%s %s=%q,",depth,k,v))
-        else
-          handle(format("%s [%q]=%q,",depth,k,v))
-        end
-      elseif tv=="table" then
-        if next(v)==nil then
-          if tk=="number" then
-            if hexify then
-              handle(format("%s [0x%X]={},",depth,k))
-            else
-              handle(format("%s [%s]={},",depth,k))
-            end
-          elseif tk=="boolean" then
-            handle(format("%s [%s]={},",depth,k and "true" or "false"))
-          elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
-            handle(format("%s %s={},",depth,k))
-          else
-            handle(format("%s [%q]={},",depth,k))
-          end
-        elseif inline then
-          local st=simple_table(v)
-          if st then
-            if tk=="number" then
-              if hexify then
-                handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", ")))
-              else
-                handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))
-              end
-            elseif tk=="boolean" then
-              handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", ")))
-            elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
-              handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
-            else
-              handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
-            end
-          else
-            do_serialize(v,k,depth,level+1)
-          end
-        else
-          do_serialize(v,k,depth,level+1)
-        end
-      elseif tv=="boolean" then
-        if tk=="number" then
-          if hexify then
-            handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false"))
-          else
-            handle(format("%s [%s]=%s,",depth,k,v and "true" or "false"))
-          end
-        elseif tk=="boolean" then
-          handle(format("%s [%s]=%s,",depth,tostring(k),v and "true" or "false"))
-        elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
-          handle(format("%s %s=%s,",depth,k,v and "true" or "false"))
-        else
-          handle(format("%s [%q]=%s,",depth,k,v and "true" or "false"))
-        end
-      elseif tv=="function" then
-        if functions then
-          local f=getinfo(v).what=="C" and dump(dummy) or dump(v)
-          if tk=="number" then
-            if hexify then
-              handle(format("%s [0x%X]=load(%q),",depth,k,f))
-            else
-              handle(format("%s [%s]=load(%q),",depth,k,f))
-            end
-          elseif tk=="boolean" then
-            handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f))
-          elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
-            handle(format("%s %s=load(%q),",depth,k,f))
-          else
-            handle(format("%s [%q]=load(%q),",depth,k,f))
-          end
-        end
-      else
-        if tk=="number" then
-          if hexify then
-            handle(format("%s [0x%X]=%q,",depth,k,tostring(v)))
-          else
-            handle(format("%s [%s]=%q,",depth,k,tostring(v)))
-          end
-        elseif tk=="boolean" then
-          handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v)))
-        elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
-          handle(format("%s %s=%q,",depth,k,tostring(v)))
-        else
-          handle(format("%s [%q]=%q,",depth,k,tostring(v)))
-        end
-      end
-    end
-  end
-  if level>0 then
-    handle(format("%s},",depth))
-  end
-end
-local function serialize(_handle,root,name,specification) 
-  local tname=type(name)
-  if type(specification)=="table" then
-    noquotes=specification.noquotes
-    hexify=specification.hexify
-    handle=_handle or specification.handle or print
-    functions=specification.functions
-    compact=specification.compact
-    inline=specification.inline and compact
-    if functions==nil then
-      functions=true
-    end
-    if compact==nil then
-      compact=true
-    end
-    if inline==nil then
-      inline=compact
-    end
-  else
-    noquotes=false
-    hexify=false
-    handle=_handle or print
-    compact=true
-    inline=true
-    functions=true
-  end
-  if tname=="string" then
-    if name=="return" then
-      handle("return {")
-    else
-      handle(name.."={")
-    end
-  elseif tname=="number" then
-    if hexify then
-      handle(format("[0x%X]={",name))
-    else
-      handle("["..name.."]={")
-    end
-  elseif tname=="boolean" then
-    if name then
-      handle("return {")
-    else
-      handle("{")
-    end
-  else
-    handle("t={")
-  end
-  if root then
-    if getmetatable(root) then 
-      local dummy=root._w_h_a_t_e_v_e_r_
-      root._w_h_a_t_e_v_e_r_=nil
-    end
-    if next(root)~=nil then
-      do_serialize(root,name,"",0)
-    end
-  end
-  handle("}")
-end
-function table.serialize(root,name,specification)
-  local t,n={},0
-  local function flush(s)
-    n=n+1
-    t[n]=s
-  end
-  serialize(flush,root,name,specification)
-  return concat(t,"\n")
-end
-table.tohandle=serialize
-local maxtab=2*1024
-function table.tofile(filename,root,name,specification)
-  local f=io.open(filename,'w')
-  if f then
-    if maxtab>1 then
-      local t,n={},0
-      local function flush(s)
-        n=n+1
-        t[n]=s
-        if n>maxtab then
-          f:write(concat(t,"\n"),"\n") 
-          t,n={},0 
-        end
-      end
-      serialize(flush,root,name,specification)
-      f:write(concat(t,"\n"),"\n")
-    else
-      local function flush(s)
-        f:write(s,"\n")
-      end
-      serialize(flush,root,name,specification)
-    end
-    f:close()
-    io.flush()
-  end
-end
-local function flattened(t,f,depth) 
-  if f==nil then
-    f={}
-    depth=0xFFFF
-  elseif tonumber(f) then
-    depth=f
-    f={}
-  elseif not depth then
-    depth=0xFFFF
-  end
-  for k,v in next,t do
-    if type(k)~="number" then
-      if depth>0 and type(v)=="table" then
-        flattened(v,f,depth-1)
-      else
-        f[#f+1]=v
-      end
-    end
-  end
-  for k=1,#t do
-    local v=t[k]
-    if depth>0 and type(v)=="table" then
-      flattened(v,f,depth-1)
-    else
-      f[#f+1]=v
-    end
-  end
-  return f
-end
-table.flattened=flattened
-local function unnest(t,f) 
-  if not f then     
-    f={}      
-  end
-  for i=1,#t do
-    local v=t[i]
-    if type(v)=="table" then
-      if type(v[1])=="table" then
-        unnest(v,f)
-      else
-        f[#f+1]=v
-      end
-    else
-      f[#f+1]=v
-    end
-  end
-  return f
-end
-function table.unnest(t) 
-  return unnest(t)
-end
-local function are_equal(a,b,n,m) 
-  if a and b and #a==#b then
-    n=n or 1
-    m=m or #a
-    for i=n,m do
-      local ai,bi=a[i],b[i]
-      if ai==bi then
-      elseif type(ai)=="table" and type(bi)=="table" then
-        if not are_equal(ai,bi) then
-          return false
-        end
-      else
-        return false
-      end
-    end
-    return true
-  else
-    return false
-  end
-end
-local function identical(a,b) 
-  for ka,va in next,a do
-    local vb=b[ka]
-    if va==vb then
-    elseif type(va)=="table" and type(vb)=="table" then
-      if not identical(va,vb) then
-        return false
-      end
-    else
-      return false
-    end
-  end
-  return true
-end
-table.identical=identical
-table.are_equal=are_equal
-local function sparse(old,nest,keeptables)
-  local new={}
-  for k,v in next,old do
-    if not (v=="" or v==false) then
-      if nest and type(v)=="table" then
-        v=sparse(v,nest)
-        if keeptables or next(v)~=nil then
-          new[k]=v
-        end
-      else
-        new[k]=v
-      end
-    end
-  end
-  return new
-end
-table.sparse=sparse
-function table.compact(t)
-  return sparse(t,true,true)
-end
-function table.contains(t,v)
-  if t then
-    for i=1,#t do
-      if t[i]==v then
-        return i
-      end
-    end
-  end
-  return false
-end
-function table.count(t)
-  local n=0
-  for k,v in next,t do
-    n=n+1
-  end
-  return n
-end
-function table.swapped(t,s) 
-  local n={}
-  if s then
-    for k,v in next,s do
-      n[k]=v
-    end
-  end
-  for k,v in next,t do
-    n[v]=k
-  end
-  return n
-end
-function table.mirrored(t) 
-  local n={}
-  for k,v in next,t do
-    n[v]=k
-    n[k]=v
-  end
-  return n
-end
-function table.reversed(t)
-  if t then
-    local tt,tn={},#t
-    if tn>0 then
-      local ttn=0
-      for i=tn,1,-1 do
-        ttn=ttn+1
-        tt[ttn]=t[i]
-      end
-    end
-    return tt
-  end
-end
-function table.reverse(t)
-  if t then
-    local n=#t
-    for i=1,floor(n/2) do
-      local j=n-i+1
-      t[i],t[j]=t[j],t[i]
-    end
-    return t
-  end
-end
-function table.sequenced(t,sep,simple) 
-  if not t then
-    return ""
-  end
-  local n=#t
-  local s={}
-  if n>0 then
-    for i=1,n do
-      s[i]=tostring(t[i])
-    end
-  else
-    n=0
-    for k,v in sortedhash(t) do
-      if simple then
-        if v==true then
-          n=n+1
-          s[n]=k
-        elseif v and v~="" then
-          n=n+1
-          s[n]=k.."="..tostring(v)
-        end
-      else
-        n=n+1
-        s[n]=k.."="..tostring(v)
-      end
-    end
-  end
-  return concat(s,sep or " | ")
-end
-function table.print(t,...)
-  if type(t)~="table" then
-    print(tostring(t))
-  else
-    serialize(print,t,...)
-  end
-end
-if setinspector then
-  setinspector("table",function(v) if type(v)=="table" then serialize(print,v,"table") return true end end)
-end
-function table.sub(t,i,j)
-  return { unpack(t,i,j) }
-end
-function table.is_empty(t)
-  return not t or next(t)==nil
-end
-function table.has_one_entry(t)
-  return t and next(t,next(t))==nil
-end
-function table.loweredkeys(t) 
-  local l={}
-  for k,v in next,t do
-    l[lower(k)]=v
-  end
-  return l
-end
-function table.unique(old)
-  local hash={}
-  local new={}
-  local n=0
-  for i=1,#old do
-    local oi=old[i]
-    if not hash[oi] then
-      n=n+1
-      new[n]=oi
-      hash[oi]=true
-    end
-  end
-  return new
-end
-function table.sorted(t,...)
-  sort(t,...)
-  return t 
-end
-function table.values(t,s) 
-  if t then
-    local values,keys,v={},{},0
-    for key,value in next,t do
-      if not keys[value] then
-        v=v+1
-        values[v]=value
-        keys[k]=key
-      end
-    end
-    if s then
-      sort(values)
-    end
-    return values
-  else
-    return {}
-  end
-end
-function table.filtered(t,pattern,sort,cmp)
-  if t and type(pattern)=="string" then
-    if sort then
-      local s
-      if cmp then
-        s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end)
-      else
-        s=sortedkeys(t) 
-      end
-      local n=0
-      local m=#s
-      local function kv(s)
-        while n<m do
-          n=n+1
-          local k=s[n]
-          if find(k,pattern) then
-            return k,t[k]
-          end
-        end
-      end
-      return kv,s
-    else
-      local n=next(t)
-      local function iterator()
-        while n~=nil do
-          local k=n
-          n=next(t,k)
-          if find(k,pattern) then
-            return k,t[k]
-          end
-        end
-      end
-      return iterator,t
-    end
-  else
-    return nothing
-  end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-boolean']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local type,tonumber=type,tonumber
-boolean=boolean or {}
-local boolean=boolean
-function boolean.tonumber(b)
-  if b then return 1 else return 0 end 
-end
-function toboolean(str,tolerant) 
-  if str==nil then
-    return false
-  elseif str==false then
-    return false
-  elseif str==true then
-    return true
-  elseif str=="true" then
-    return true
-  elseif str=="false" then
-    return false
-  elseif not tolerant then
-    return false
-  elseif str==0 then
-    return false
-  elseif (tonumber(str) or 0)>0 then
-    return true
-  else
-    return str=="yes" or str=="on" or str=="t"
-  end
-end
-string.toboolean=toboolean
-function string.booleanstring(str)
-  if str=="0" then
-    return false
-  elseif str=="1" then
-    return true
-  elseif str=="" then
-    return false
-  elseif str=="false" then
-    return false
-  elseif str=="true" then
-    return true
-  elseif (tonumber(str) or 0)>0 then
-    return true
-  else
-    return str=="yes" or str=="on" or str=="t"
-  end
-end
-function string.is_boolean(str,default,strict)
-  if type(str)=="string" then
-    if str=="true" or str=="yes" or str=="on" or str=="t" or (not strict and str=="1") then
-      return true
-    elseif str=="false" or str=="no" or str=="off" or str=="f" or (not strict and str=="0") then
-      return false
-    end
-  end
-  return default
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-number']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local tostring,tonumber=tostring,tonumber
-local format,floor,match,rep=string.format,math.floor,string.match,string.rep
-local concat,insert=table.concat,table.insert
-local lpegmatch=lpeg.match
-number=number or {}
-local number=number
-if bit32 then 
-  local btest,bor=bit32.btest,bit32.bor
-  function number.bit(p)
-    return 2^(p-1) 
-  end
-  number.hasbit=btest
-  number.setbit=bor
-  function number.setbit(x,p) 
-    return btest(x,p) and x or x+p
-  end
-  function number.clearbit(x,p)
-    return btest(x,p) and x-p or x
-  end
-else
-  function number.bit(p)
-    return 2^(p-1) 
-  end
-  function number.hasbit(x,p) 
-    return x%(p+p)>=p
-  end
-  function number.setbit(x,p)
-    return (x%(p+p)>=p) and x or x+p
-  end
-  function number.clearbit(x,p)
-    return (x%(p+p)>=p) and x-p or x
-  end
-end
-if bit32 then
-  local bextract=bit32.extract
-  local t={
-    "0","0","0","0","0","0","0","0",
-    "0","0","0","0","0","0","0","0",
-    "0","0","0","0","0","0","0","0",
-    "0","0","0","0","0","0","0","0",
-  }
-  function number.tobitstring(b,m)
-    local n=32
-    for i=0,31 do
-      local v=bextract(b,i)
-      local k=32-i
-      if v==1 then
-        n=k
-        t[k]="1"
-      else
-        t[k]="0"
-      end
-    end
-    if m then
-      m=33-m*8
-      if m<1 then
-        m=1
-      end
-      return concat(t,"",m)
-    elseif n<8 then
-      return concat(t)
-    elseif n<16 then
-      return concat(t,"",9)
-    elseif n<24 then
-      return concat(t,"",17)
-    else
-      return concat(t,"",25)
-    end
-  end
-else
-  function number.tobitstring(n,m)
-    if n>0 then
-      local t={}
-      while n>0 do
-        insert(t,1,n%2>0 and 1 or 0)
-        n=floor(n/2)
-      end
-      local nn=8-#t%8
-      if nn>0 and nn<8 then
-        for i=1,nn do
-          insert(t,1,0)
-        end
-      end
-      if m then
-        m=m*8-#t
-        if m>0 then
-          insert(t,1,rep("0",m))
-        end
-      end
-      return concat(t)
-    elseif m then
-      rep("00000000",m)
-    else
-      return "00000000"
-    end
-  end
-end
-function number.valid(str,default)
-  return tonumber(str) or default or nil
-end
-function number.toevenhex(n)
-  local s=format("%X",n)
-  if #s%2==0 then
-    return s
-  else
-    return "0"..s
-  end
-end
-local one=lpeg.C(1-lpeg.S('')/tonumber)^1
-function number.toset(n)
-  return lpegmatch(one,tostring(n))
-end
-local function bits(n,i,...)
-  if n>0 then
-    local m=n%2
-    local n=floor(n/2)
-    if m>0 then
-      return bits(n,i+1,i,...)
-    else
-      return bits(n,i+1,...)
-    end
-  else
-    return...
-  end
-end
-function number.bits(n)
-  return { bits(n,1) }
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-math']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local floor,sin,cos,tan=math.floor,math.sin,math.cos,math.tan
-if not math.ceiling then
-  math.ceiling=math.ceil
-end
-if not math.round then
-  function math.round(x) return floor(x+0.5) end
-end
-if not math.div then
-  function math.div(n,m) return floor(n/m) end
-end
-if not math.mod then
-  function math.mod(n,m) return n%m end
-end
-local pipi=2*math.pi/360
-if not math.sind then
-  function math.sind(d) return sin(d*pipi) end
-  function math.cosd(d) return cos(d*pipi) end
-  function math.tand(d) return tan(d*pipi) end
-end
-if not math.odd then
-  function math.odd (n) return n%2~=0 end
-  function math.even(n) return n%2==0 end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-io']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local io=io
-local byte,find,gsub,format=string.byte,string.find,string.gsub,string.format
-local concat=table.concat
-local floor=math.floor
-local type=type
-if string.find(os.getenv("PATH"),";",1,true) then
-  io.fileseparator,io.pathseparator="\\",";"
-else
-  io.fileseparator,io.pathseparator="/",":"
-end
-local function readall(f)
-  return f:read("*all")
-end
-local function readall(f)
-  local size=f:seek("end")
-  if size==0 then
-    return ""
-  elseif size<1024*1024 then
-    f:seek("set",0)
-    return f:read('*all')
-  else
-    local done=f:seek("set",0)
-    local step
-    if size<1024*1024 then
-      step=1024*1024
-    elseif size>16*1024*1024 then
-      step=16*1024*1024
-    else
-      step=floor(size/(1024*1024))*1024*1024/8
-    end
-    local data={}
-    while true do
-      local r=f:read(step)
-      if not r then
-        return concat(data)
-      else
-        data[#data+1]=r
-      end
-    end
-  end
-end
-io.readall=readall
-function io.loaddata(filename,textmode) 
-  local f=io.open(filename,(textmode and 'r') or 'rb')
-  if f then
-    local data=readall(f)
-    f:close()
-    if #data>0 then
-      return data
-    end
-  end
-end
-function io.savedata(filename,data,joiner)
-  local f=io.open(filename,"wb")
-  if f then
-    if type(data)=="table" then
-      f:write(concat(data,joiner or ""))
-    elseif type(data)=="function" then
-      data(f)
-    else
-      f:write(data or "")
-    end
-    f:close()
-    io.flush()
-    return true
-  else
-    return false
-  end
-end
-function io.loadlines(filename,n) 
-  local f=io.open(filename,'r')
-  if not f then
-  elseif n then
-    local lines={}
-    for i=1,n do
-      local line=f:read("*lines")
-      if line then
-        lines[#lines+1]=line
-      else
-        break
-      end
-    end
-    f:close()
-    lines=concat(lines,"\n")
-    if #lines>0 then
-      return lines
-    end
-  else
-    local line=f:read("*line") or ""
-    f:close()
-    if #line>0 then
-      return line
-    end
-  end
-end
-function io.loadchunk(filename,n)
-  local f=io.open(filename,'rb')
-  if f then
-    local data=f:read(n or 1024)
-    f:close()
-    if #data>0 then
-      return data
-    end
-  end
-end
-function io.exists(filename)
-  local f=io.open(filename)
-  if f==nil then
-    return false
-  else
-    f:close()
-    return true
-  end
-end
-function io.size(filename)
-  local f=io.open(filename)
-  if f==nil then
-    return 0
-  else
-    local s=f:seek("end")
-    f:close()
-    return s
-  end
-end
-function io.noflines(f)
-  if type(f)=="string" then
-    local f=io.open(filename)
-    if f then
-      local n=f and io.noflines(f) or 0
-      f:close()
-      return n
-    else
-      return 0
-    end
-  else
-    local n=0
-    for _ in f:lines() do
-      n=n+1
-    end
-    f:seek('set',0)
-    return n
-  end
-end
-local nextchar={
-  [ 4]=function(f)
-    return f:read(1,1,1,1)
-  end,
-  [ 2]=function(f)
-    return f:read(1,1)
-  end,
-  [ 1]=function(f)
-    return f:read(1)
-  end,
-  [-2]=function(f)
-    local a,b=f:read(1,1)
-    return b,a
-  end,
-  [-4]=function(f)
-    local a,b,c,d=f:read(1,1,1,1)
-    return d,c,b,a
-  end
-}
-function io.characters(f,n)
-  if f then
-    return nextchar[n or 1],f
-  end
-end
-local nextbyte={
-  [4]=function(f)
-    local a,b,c,d=f:read(1,1,1,1)
-    if d then
-      return byte(a),byte(b),byte(c),byte(d)
-    end
-  end,
-  [3]=function(f)
-    local a,b,c=f:read(1,1,1)
-    if b then
-      return byte(a),byte(b),byte(c)
-    end
-  end,
-  [2]=function(f)
-    local a,b=f:read(1,1)
-    if b then
-      return byte(a),byte(b)
-    end
-  end,
-  [1]=function (f)
-    local a=f:read(1)
-    if a then
-      return byte(a)
-    end
-  end,
-  [-2]=function (f)
-    local a,b=f:read(1,1)
-    if b then
-      return byte(b),byte(a)
-    end
-  end,
-  [-3]=function(f)
-    local a,b,c=f:read(1,1,1)
-    if b then
-      return byte(c),byte(b),byte(a)
-    end
-  end,
-  [-4]=function(f)
-    local a,b,c,d=f:read(1,1,1,1)
-    if d then
-      return byte(d),byte(c),byte(b),byte(a)
-    end
-  end
-}
-function io.bytes(f,n)
-  if f then
-    return nextbyte[n or 1],f
-  else
-    return nil,nil
-  end
-end
-function io.ask(question,default,options)
-  while true do
-    io.write(question)
-    if options then
-      io.write(format(" [%s]",concat(options,"|")))
-    end
-    if default then
-      io.write(format(" [%s]",default))
-    end
-    io.write(format(" "))
-    io.flush()
-    local answer=io.read()
-    answer=gsub(answer,"^%s*(.*)%s*$","%1")
-    if answer=="" and default then
-      return default
-    elseif not options then
-      return answer
-    else
-      for k=1,#options do
-        if options[k]==answer then
-          return answer
-        end
-      end
-      local pattern="^"..answer
-      for k=1,#options do
-        local v=options[k]
-        if find(v,pattern) then
-          return v
-        end
-      end
-    end
-  end
-end
-local function readnumber(f,n,m)
-  if m then
-    f:seek("set",n)
-    n=m
-  end
-  if n==1 then
-    return byte(f:read(1))
-  elseif n==2 then
-    local a,b=byte(f:read(2),1,2)
-    return 256*a+b
-  elseif n==3 then
-    local a,b,c=byte(f:read(3),1,3)
-    return 256*256*a+256*b+c
-  elseif n==4 then
-    local a,b,c,d=byte(f:read(4),1,4)
-    return 256*256*256*a+256*256*b+256*c+d
-  elseif n==8 then
-    local a,b=readnumber(f,4),readnumber(f,4)
-    return 256*a+b
-  elseif n==12 then
-    local a,b,c=readnumber(f,4),readnumber(f,4),readnumber(f,4)
-    return 256*256*a+256*b+c
-  elseif n==-2 then
-    local b,a=byte(f:read(2),1,2)
-    return 256*a+b
-  elseif n==-3 then
-    local c,b,a=byte(f:read(3),1,3)
-    return 256*256*a+256*b+c
-  elseif n==-4 then
-    local d,c,b,a=byte(f:read(4),1,4)
-    return 256*256*256*a+256*256*b+256*c+d
-  elseif n==-8 then
-    local h,g,f,e,d,c,b,a=byte(f:read(8),1,8)
-    return 256*256*256*256*256*256*256*a+256*256*256*256*256*256*b+256*256*256*256*256*c+256*256*256*256*d+256*256*256*e+256*256*f+256*g+h
-  else
-    return 0
-  end
-end
-io.readnumber=readnumber
-function io.readstring(f,n,m)
-  if m then
-    f:seek("set",n)
-    n=m
-  end
-  local str=gsub(f:read(n),"\000","")
-  return str
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-os']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local os=os
-local date,time=os.date,os.time
-local find,format,gsub,upper,gmatch=string.find,string.format,string.gsub,string.upper,string.gmatch
-local concat=table.concat
-local random,ceil,randomseed=math.random,math.ceil,math.randomseed
-local rawget,rawset,type,getmetatable,setmetatable,tonumber,tostring=rawget,rawset,type,getmetatable,setmetatable,tonumber,tostring
-math.initialseed=tonumber(string.sub(string.reverse(tostring(ceil(socket and socket.gettime()*10000 or time()))),1,6))
-randomseed(math.initialseed)
-if not os.__getenv__ then
-  os.__getenv__=os.getenv
-  os.__setenv__=os.setenv
-  if os.env then
-    local osgetenv=os.getenv
-    local ossetenv=os.setenv
-    local osenv=os.env   local _=osenv.PATH 
-    function os.setenv(k,v)
-      if v==nil then
-        v=""
-      end
-      local K=upper(k)
-      osenv[K]=v
-      if type(v)=="table" then
-        v=concat(v,";") 
-      end
-      ossetenv(K,v)
-    end
-    function os.getenv(k)
-      local K=upper(k)
-      local v=osenv[K] or osenv[k] or osgetenv(K) or osgetenv(k)
-      if v=="" then
-        return nil
-      else
-        return v
-      end
-    end
-  else
-    local ossetenv=os.setenv
-    local osgetenv=os.getenv
-    local osenv={}
-    function os.setenv(k,v)
-      if v==nil then
-        v=""
-      end
-      local K=upper(k)
-      osenv[K]=v
-    end
-    function os.getenv(k)
-      local K=upper(k)
-      local v=osenv[K] or osgetenv(K) or osgetenv(k)
-      if v=="" then
-        return nil
-      else
-        return v
-      end
-    end
-    local function __index(t,k)
-      return os.getenv(k)
-    end
-    local function __newindex(t,k,v)
-      os.setenv(k,v)
-    end
-    os.env={}
-    setmetatable(os.env,{ __index=__index,__newindex=__newindex } )
-  end
-end
-local execute=os.execute
-local iopopen=io.popen
-function os.resultof(command)
-  local handle=iopopen(command,"r") 
-  if handle then
-    local result=handle:read("*all") or ""
-    handle:close()
-    return result
-  else
-    return ""
-  end
-end
-if not io.fileseparator then
-  if find(os.getenv("PATH"),";",1,true) then
-    io.fileseparator,io.pathseparator,os.type="\\",";",os.type or "mswin"
-  else
-    io.fileseparator,io.pathseparator,os.type="/",":",os.type or "unix"
-  end
-end
-os.type=os.type or (io.pathseparator==";"    and "windows") or "unix"
-os.name=os.name or (os.type=="windows" and "mswin" ) or "linux"
-if os.type=="windows" then
-  os.libsuffix,os.binsuffix,os.binsuffixes='dll','exe',{ 'exe','cmd','bat' }
-else
-  os.libsuffix,os.binsuffix,os.binsuffixes='so','',{ '' }
-end
-local launchers={
-  windows="start %s",
-  macosx="open %s",
-  unix="$BROWSER %s &> /dev/null &",
-}
-function os.launch(str)
-  execute(format(launchers[os.name] or launchers.unix,str))
-end
-if not os.times then
-  function os.times()
-    return {
-      utime=os.gettimeofday(),
-      stime=0,
-      cutime=0,
-      cstime=0,
-    }
-  end
-end
-local gettimeofday=os.gettimeofday or os.clock
-os.gettimeofday=gettimeofday
-local startuptime=gettimeofday()
-function os.runtime()
-  return gettimeofday()-startuptime
-end
-local resolvers=os.resolvers or {}
-os.resolvers=resolvers
-setmetatable(os,{ __index=function(t,k)
-  local r=resolvers[k]
-  return r and r(t,k) or nil 
-end })
-local name,platform=os.name or "linux",os.getenv("MTX_PLATFORM") or ""
-local function guess()
-  local architecture=os.resultof("uname -m") or ""
-  if architecture~="" then
-    return architecture
-  end
-  architecture=os.getenv("HOSTTYPE") or ""
-  if architecture~="" then
-    return architecture
-  end
-  return os.resultof("echo $HOSTTYPE") or ""
-end
-if platform~="" then
-  os.platform=platform
-elseif os.type=="windows" then
-  function resolvers.platform(t,k)
-    local platform,architecture="",os.getenv("PROCESSOR_ARCHITECTURE") or ""
-    if find(architecture,"AMD64",1,true) then
-      platform="win64"
-    else
-      platform="mswin"
-    end
-    os.setenv("MTX_PLATFORM",platform)
-    os.platform=platform
-    return platform
-  end
-elseif name=="linux" then
-  function resolvers.platform(t,k)
-    local platform,architecture="",os.getenv("HOSTTYPE") or os.resultof("uname -m") or ""
-    if find(architecture,"x86_64",1,true) then
-      platform="linux-64"
-    elseif find(architecture,"ppc",1,true) then
-      platform="linux-ppc"
-    else
-      platform="linux"
-    end
-    os.setenv("MTX_PLATFORM",platform)
-    os.platform=platform
-    return platform
-  end
-elseif name=="macosx" then
-  function resolvers.platform(t,k)
-    local platform,architecture="",os.resultof("echo $HOSTTYPE") or ""
-    if architecture=="" then
-      platform="osx-intel"
-    elseif find(architecture,"i386",1,true) then
-      platform="osx-intel"
-    elseif find(architecture,"x86_64",1,true) then
-      platform="osx-64"
-    else
-      platform="osx-ppc"
-    end
-    os.setenv("MTX_PLATFORM",platform)
-    os.platform=platform
-    return platform
-  end
-elseif name=="sunos" then
-  function resolvers.platform(t,k)
-    local platform,architecture="",os.resultof("uname -m") or ""
-    if find(architecture,"sparc",1,true) then
-      platform="solaris-sparc"
-    else 
-      platform="solaris-intel"
-    end
-    os.setenv("MTX_PLATFORM",platform)
-    os.platform=platform
-    return platform
-  end
-elseif name=="freebsd" then
-  function resolvers.platform(t,k)
-    local platform,architecture="",os.resultof("uname -m") or ""
-    if find(architecture,"amd64",1,true) then
-      platform="freebsd-amd64"
-    else
-      platform="freebsd"
-    end
-    os.setenv("MTX_PLATFORM",platform)
-    os.platform=platform
-    return platform
-  end
-elseif name=="kfreebsd" then
-  function resolvers.platform(t,k)
-    local platform,architecture="",os.getenv("HOSTTYPE") or os.resultof("uname -m") or ""
-    if find(architecture,"x86_64",1,true) then
-      platform="kfreebsd-amd64"
-    else
-      platform="kfreebsd-i386"
-    end
-    os.setenv("MTX_PLATFORM",platform)
-    os.platform=platform
-    return platform
-  end
-else
-  function resolvers.platform(t,k)
-    local platform="linux"
-    os.setenv("MTX_PLATFORM",platform)
-    os.platform=platform
-    return platform
-  end
-end
-os.newline=name=="windows" and "\013\010" or "\010" 
-function resolvers.bits(t,k)
-  local bits=find(os.platform,"64",1,true) and 64 or 32
-  os.bits=bits
-  return bits
-end
-local t={ 8,9,"a","b" }
-function os.uuid()
-  return format("%04x%04x-4%03x-%s%03x-%04x-%04x%04x%04x",
-    random(0xFFFF),random(0xFFFF),
-    random(0x0FFF),
-    t[ceil(random(4))] or 8,random(0x0FFF),
-    random(0xFFFF),
-    random(0xFFFF),random(0xFFFF),random(0xFFFF)
-  )
-end
-local d
-function os.timezone(delta)
-  d=d or tonumber(tonumber(date("%H")-date("!%H")))
-  if delta then
-    if d>0 then
-      return format("+%02i:00",d)
-    else
-      return format("-%02i:00",-d)
-    end
-  else
-    return 1
-  end
-end
-local timeformat=format("%%s%s",os.timezone(true))
-local dateformat="!%Y-%m-%d %H:%M:%S"
-local lasttime=nil
-local lastdate=nil
-function os.fulltime(t,default)
-  t=t and tonumber(t) or 0
-  if t>0 then
-  elseif default then
-    return default
-  else
-    t=time()
-  end
-  if t~=lasttime then
-    lasttime=t
-    lastdate=format(timeformat,date(dateformat))
-  end
-  return lastdate
-end
-local dateformat="%Y-%m-%d %H:%M:%S"
-local lasttime=nil
-local lastdate=nil
-function os.localtime(t,default)
-  t=t and tonumber(t) or 0
-  if t>0 then
-  elseif default then
-    return default
-  else
-    t=time()
-  end
-  if t~=lasttime then
-    lasttime=t
-    lastdate=date(dateformat,t)
-  end
-  return lastdate
-end
-function os.converttime(t,default)
-  local t=tonumber(t)
-  if t and t>0 then
-    return date(dateformat,t)
-  else
-    return default or "-"
-  end
-end
-local memory={}
-local function which(filename)
-  local fullname=memory[filename]
-  if fullname==nil then
-    local suffix=file.suffix(filename)
-    local suffixes=suffix=="" and os.binsuffixes or { suffix }
-    for directory in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
-      local df=file.join(directory,filename)
-      for i=1,#suffixes do
-        local dfs=file.addsuffix(df,suffixes[i])
-        if io.exists(dfs) then
-          fullname=dfs
-          break
-        end
-      end
-    end
-    if not fullname then
-      fullname=false
-    end
-    memory[filename]=fullname
-  end
-  return fullname
-end
-os.which=which
-os.where=which
-function os.today()
-  return date("!*t") 
-end
-function os.now()
-  return date("!%Y-%m-%d %H:%M:%S") 
-end
-if not os.sleep then
-  local socket=socket
-  function os.sleep(n)
-    if not socket then
-      socket=require("socket")
-    end
-    socket.sleep(n)
-  end
-end
-local function isleapyear(year)
-  return (year%400==0) or ((year%100~=0) and (year%4==0))
-end
-os.isleapyear=isleapyear
-local days={ 31,28,31,30,31,30,31,31,30,31,30,31 }
-local function nofdays(year,month)
-  if not month then
-    return isleapyear(year) and 365 or 364
-  else
-    return month==2 and isleapyear(year) and 29 or days[month]
-  end
-end
-os.nofdays=nofdays
-function os.weekday(day,month,year)
-  return date("%w",time { year=year,month=month,day=day })+1
-end
-function os.validdate(year,month,day)
-  if month<1 then
-    month=1
-  elseif month>12 then
-    month=12
-  end
-  if day<1 then
-    day=1
-  else
-    local max=nofdays(year,month)
-    if day>max then
-      day=max
-    end
-  end
-  return year,month,day
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-file']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-file=file or {}
-local file=file
-if not lfs then
-  lfs=optionalrequire("lfs")
-end
-local insert,concat=table.insert,table.concat
-local match,find,gmatch=string.match,string.find,string.gmatch
-local lpegmatch=lpeg.match
-local getcurrentdir,attributes=lfs.currentdir,lfs.attributes
-local checkedsplit=string.checkedsplit
-local P,R,S,C,Cs,Cp,Cc,Ct=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Cp,lpeg.Cc,lpeg.Ct
-local tricky=S("/\\")*P(-1)
-local attributes=lfs.attributes
-if sandbox then
-  sandbox.redefine(lfs.isfile,"lfs.isfile")
-  sandbox.redefine(lfs.isdir,"lfs.isdir")
-end
-function lfs.isdir(name)
-  if lpegmatch(tricky,name) then
-    return attributes(name,"mode")=="directory"
-  else
-    return attributes(name.."/.","mode")=="directory"
-  end
-end
-function lfs.isfile(name)
-  return attributes(name,"mode")=="file"
-end
-local colon=P(":")
-local period=P(".")
-local periods=P("..")
-local fwslash=P("/")
-local bwslash=P("\\")
-local slashes=S("\\/")
-local noperiod=1-period
-local noslashes=1-slashes
-local name=noperiod^1
-local suffix=period/""*(1-period-slashes)^1*-1
-local pattern=C((1-(slashes^1*noslashes^1*-1))^1)*P(1) 
-local function pathpart(name,default)
-  return name and lpegmatch(pattern,name) or default or ""
-end
-local pattern=(noslashes^0*slashes)^1*C(noslashes^1)*-1
-local function basename(name)
-  return name and lpegmatch(pattern,name) or name
-end
-local pattern=(noslashes^0*slashes^1)^0*Cs((1-suffix)^1)*suffix^0
-local function nameonly(name)
-  return name and lpegmatch(pattern,name) or name
-end
-local pattern=(noslashes^0*slashes)^0*(noperiod^1*period)^1*C(noperiod^1)*-1
-local function suffixonly(name)
-  return name and lpegmatch(pattern,name) or ""
-end
-local pattern=(noslashes^0*slashes)^0*noperiod^1*((period*C(noperiod^1))^1)*-1+Cc("")
-local function suffixesonly(name)
-  if name then
-    return lpegmatch(pattern,name)
-  else
-    return ""
-  end
-end
-file.pathpart=pathpart
-file.basename=basename
-file.nameonly=nameonly
-file.suffixonly=suffixonly
-file.suffix=suffixonly
-file.suffixesonly=suffixesonly
-file.suffixes=suffixesonly
-file.dirname=pathpart  
-file.extname=suffixonly
-local drive=C(R("az","AZ"))*colon
-local path=C((noslashes^0*slashes)^0)
-local suffix=period*C(P(1-period)^0*P(-1))
-local base=C((1-suffix)^0)
-local rest=C(P(1)^0)
-drive=drive+Cc("")
-path=path+Cc("")
-base=base+Cc("")
-suffix=suffix+Cc("")
-local pattern_a=drive*path*base*suffix
-local pattern_b=path*base*suffix
-local pattern_c=C(drive*path)*C(base*suffix) 
-local pattern_d=path*rest
-function file.splitname(str,splitdrive)
-  if not str then
-  elseif splitdrive then
-    return lpegmatch(pattern_a,str) 
-  else
-    return lpegmatch(pattern_b,str) 
-  end
-end
-function file.splitbase(str)
-  if str then
-    return lpegmatch(pattern_d,str) 
-  else
-    return "",str 
-  end
-end
-function file.nametotable(str,splitdrive)
-  if str then
-    local path,drive,subpath,name,base,suffix=lpegmatch(pattern_c,str)
-    if splitdrive then
-      return {
-        path=path,
-        drive=drive,
-        subpath=subpath,
-        name=name,
-        base=base,
-        suffix=suffix,
-      }
-    else
-      return {
-        path=path,
-        name=name,
-        base=base,
-        suffix=suffix,
-      }
-    end
-  end
-end
-local pattern=Cs(((period*(1-period-slashes)^1*-1)/""+1)^1)
-function file.removesuffix(name)
-  return name and lpegmatch(pattern,name)
-end
-local suffix=period/""*(1-period-slashes)^1*-1
-local pattern=Cs((noslashes^0*slashes^1)^0*((1-suffix)^1))*Cs(suffix)
-function file.addsuffix(filename,suffix,criterium)
-  if not filename or not suffix or suffix=="" then
-    return filename
-  elseif criterium==true then
-    return filename.."."..suffix
-  elseif not criterium then
-    local n,s=lpegmatch(pattern,filename)
-    if not s or s=="" then
-      return filename.."."..suffix
-    else
-      return filename
-    end
-  else
-    local n,s=lpegmatch(pattern,filename)
-    if s and s~="" then
-      local t=type(criterium)
-      if t=="table" then
-        for i=1,#criterium do
-          if s==criterium[i] then
-            return filename
-          end
-        end
-      elseif t=="string" then
-        if s==criterium then
-          return filename
-        end
-      end
-    end
-    return (n or filename).."."..suffix
-  end
-end
-local suffix=period*(1-period-slashes)^1*-1
-local pattern=Cs((1-suffix)^0)
-function file.replacesuffix(name,suffix)
-  if name and suffix and suffix~="" then
-    return lpegmatch(pattern,name).."."..suffix
-  else
-    return name
-  end
-end
-local reslasher=lpeg.replacer(P("\\"),"/")
-function file.reslash(str)
-  return str and lpegmatch(reslasher,str)
-end
-function file.is_writable(name)
-  if not name then
-  elseif lfs.isdir(name) then
-    name=name.."/m_t_x_t_e_s_t.tmp"
-    local f=io.open(name,"wb")
-    if f then
-      f:close()
-      os.remove(name)
-      return true
-    end
-  elseif lfs.isfile(name) then
-    local f=io.open(name,"ab")
-    if f then
-      f:close()
-      return true
-    end
-  else
-    local f=io.open(name,"ab")
-    if f then
-      f:close()
-      os.remove(name)
-      return true
-    end
-  end
-  return false
-end
-local readable=P("r")*Cc(true)
-function file.is_readable(name)
-  if name then
-    local a=attributes(name)
-    return a and lpegmatch(readable,a.permissions) or false
-  else
-    return false
-  end
-end
-file.isreadable=file.is_readable 
-file.iswritable=file.is_writable 
-function file.size(name)
-  if name then
-    local a=attributes(name)
-    return a and a.size or 0
-  else
-    return 0
-  end
-end
-function file.splitpath(str,separator) 
-  return str and checkedsplit(lpegmatch(reslasher,str),separator or io.pathseparator)
-end
-function file.joinpath(tab,separator) 
-  return tab and concat(tab,separator or io.pathseparator) 
-end
-local someslash=S("\\/")
-local stripper=Cs(P(fwslash)^0/""*reslasher)
-local isnetwork=someslash*someslash*(1-someslash)+(1-fwslash-colon)^1*colon
-local isroot=fwslash^1*-1
-local hasroot=fwslash^1
-local reslasher=lpeg.replacer(S("\\/"),"/")
-local deslasher=lpeg.replacer(S("\\/")^1,"/")
-function file.join(one,two,three,...)
-  if not two then
-    return one=="" and one or lpegmatch(stripper,one)
-  end
-  if one=="" then
-    return lpegmatch(stripper,three and concat({ two,three,... },"/") or two)
-  end
-  if lpegmatch(isnetwork,one) then
-    local one=lpegmatch(reslasher,one)
-    local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two)
-    if lpegmatch(hasroot,two) then
-      return one..two
-    else
-      return one.."/"..two
-    end
-  elseif lpegmatch(isroot,one) then
-    local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two)
-    if lpegmatch(hasroot,two) then
-      return two
-    else
-      return "/"..two
-    end
-  else
-    return lpegmatch(deslasher,concat({ one,two,three,... },"/"))
-  end
-end
-local drivespec=R("az","AZ")^1*colon
-local anchors=fwslash+drivespec
-local untouched=periods+(1-period)^1*P(-1)
-local mswindrive=Cs(drivespec*(bwslash/"/"+fwslash)^0)
-local mswinuncpath=(bwslash+fwslash)*(bwslash+fwslash)*Cc("//")
-local splitstarter=(mswindrive+mswinuncpath+Cc(false))*Ct(lpeg.splitat(S("/\\")^1))
-local absolute=fwslash
-function file.collapsepath(str,anchor) 
-  if not str then
-    return
-  end
-  if anchor==true and not lpegmatch(anchors,str) then
-    str=getcurrentdir().."/"..str
-  end
-  if str=="" or str=="." then
-    return "."
-  elseif lpegmatch(untouched,str) then
-    return lpegmatch(reslasher,str)
-  end
-  local starter,oldelements=lpegmatch(splitstarter,str)
-  local newelements={}
-  local i=#oldelements
-  while i>0 do
-    local element=oldelements[i]
-    if element=='.' then
-    elseif element=='..' then
-      local n=i-1
-      while n>0 do
-        local element=oldelements[n]
-        if element~='..' and element~='.' then
-          oldelements[n]='.'
-          break
-        else
-          n=n-1
-        end
-       end
-      if n<1 then
-        insert(newelements,1,'..')
-      end
-    elseif element~="" then
-      insert(newelements,1,element)
-    end
-    i=i-1
-  end
-  if #newelements==0 then
-    return starter or "."
-  elseif starter then
-    return starter..concat(newelements,'/')
-  elseif lpegmatch(absolute,str) then
-    return "/"..concat(newelements,'/')
-  else
-    newelements=concat(newelements,'/')
-    if anchor=="." and find(str,"^%./") then
-      return "./"..newelements
-    else
-      return newelements
-    end
-  end
-end
-local validchars=R("az","09","AZ","--","..")
-local pattern_a=lpeg.replacer(1-validchars)
-local pattern_a=Cs((validchars+P(1)/"-")^1)
-local whatever=P("-")^0/""
-local pattern_b=Cs(whatever*(1-whatever*-1)^1)
-function file.robustname(str,strict)
-  if str then
-    str=lpegmatch(pattern_a,str) or str
-    if strict then
-      return lpegmatch(pattern_b,str) or str 
-    else
-      return str
-    end
-  end
-end
-file.readdata=io.loaddata
-file.savedata=io.savedata
-function file.copy(oldname,newname)
-  if oldname and newname then
-    local data=io.loaddata(oldname)
-    if data and data~="" then
-      file.savedata(newname,data)
-    end
-  end
-end
-local letter=R("az","AZ")+S("_-+")
-local separator=P("://")
-local qualified=period^0*fwslash+letter*colon+letter^1*separator+letter^1*fwslash
-local rootbased=fwslash+letter*colon
-lpeg.patterns.qualified=qualified
-lpeg.patterns.rootbased=rootbased
-function file.is_qualified_path(filename)
-  return filename and lpegmatch(qualified,filename)~=nil
-end
-function file.is_rootbased_path(filename)
-  return filename and lpegmatch(rootbased,filename)~=nil
-end
-function file.strip(name,dir)
-  if name then
-    local b,a=match(name,"^(.-)"..dir.."(.*)$")
-    return a~="" and a or name
-  end
-end
-function lfs.mkdirs(path)
-  local full=""
-  for sub in gmatch(path,"(/*[^\\/]+)") do 
-    full=full..sub
-    lfs.mkdir(full)
-  end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-gzip']={
-  version=1.001,
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-if not gzip then
-  return
-end
-local suffix,suffixes=file.suffix,file.suffixes
-function gzip.load(filename)
-  local f=io.open(filename,"rb")
-  if not f then
-  elseif suffix(filename)=="gz" then
-    f:close()
-    local g=gzip.open(filename,"rb")
-    if g then
-      local str=g:read("*all")
-      g:close()
-      return str
-    end
-  else
-    local str=f:read("*all")
-    f:close()
-    return str
-  end
-end
-function gzip.save(filename,data)
-  if suffix(filename)~="gz" then
-    filename=filename..".gz"
-  end
-  local f=io.open(filename,"wb")
-  if f then
-    local s=zlib.compress(data or "",9,nil,15+16)
-    f:write(s)
-    f:close()
-    return #s
-  end
-end
-function gzip.suffix(filename)
-  local suffix,extra=suffixes(filename)
-  local gzipped=extra=="gz"
-  return suffix,gzipped
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-md5']={
-  version=1.001,
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-if not md5 then
-  md5=optionalrequire("md5")
-end
-if not md5 then
-  md5={
-    sum=function(str) print("error: md5 is not loaded (sum     ignored)") return str end,
-    sumhexa=function(str) print("error: md5 is not loaded (sumhexa ignored)") return str end,
-  }
-end
-local md5,file=md5,file
-local gsub=string.gsub
-do
-  local patterns=lpeg and lpeg.patterns
-  if patterns then
-    local bytestoHEX=patterns.bytestoHEX
-    local bytestohex=patterns.bytestohex
-    local bytestodec=patterns.bytestodec
-    local lpegmatch=lpeg.match
-    local md5sum=md5.sum
-    if not md5.HEX then function md5.HEX(str) if str then return lpegmatch(bytestoHEX,md5sum(str)) end end end
-    if not md5.hex then function md5.hex(str) if str then return lpegmatch(bytestohex,md5sum(str)) end end end
-    if not md5.dec then function md5.dec(str) if str then return lpegmatch(bytestodec,md5sum(str)) end end end
-  end
-end
-function file.needsupdating(oldname,newname,threshold) 
-  local oldtime=lfs.attributes(oldname,"modification")
-  if oldtime then
-    local newtime=lfs.attributes(newname,"modification")
-    if not newtime then
-      return true 
-    elseif newtime>=oldtime then
-      return false 
-    elseif oldtime-newtime<(threshold or 1) then
-      return false 
-    else
-      return true 
-    end
-  else
-    return false 
-  end
-end
-file.needs_updating=file.needsupdating
-function file.syncmtimes(oldname,newname)
-  local oldtime=lfs.attributes(oldname,"modification")
-  if oldtime and lfs.isfile(newname) then
-    lfs.touch(newname,oldtime,oldtime)
-  end
-end
-function file.checksum(name)
-  if md5 then
-    local data=io.loaddata(name)
-    if data then
-      return md5.HEX(data)
-    end
-  end
-  return nil
-end
-function file.loadchecksum(name)
-  if md5 then
-    local data=io.loaddata(name..".md5")
-    return data and (gsub(data,"%s",""))
-  end
-  return nil
-end
-function file.savechecksum(name,checksum)
-  if not checksum then checksum=file.checksum(name) end
-  if checksum then
-    io.savedata(name..".md5",checksum)
-    return checksum
-  end
-  return nil
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-dir']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local type,select=type,select
-local find,gmatch,match,gsub,sub=string.find,string.gmatch,string.match,string.gsub,string.sub
-local concat,insert,remove,unpack=table.concat,table.insert,table.remove,table.unpack
-local lpegmatch=lpeg.match
-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
-dir=dir or {}
-local dir=dir
-local lfs=lfs
-local attributes=lfs.attributes
-local walkdir=lfs.dir
-local isdir=lfs.isdir 
-local isfile=lfs.isfile 
-local currentdir=lfs.currentdir
-local chdir=lfs.chdir
-local mkdir=lfs.mkdir
-local onwindows=os.type=="windows" or find(os.getenv("PATH"),";",1,true)
-if onwindows then
-  local tricky=S("/\\")*P(-1)
-  isdir=function(name)
-    if lpegmatch(tricky,name) then
-      return attributes(name,"mode")=="directory"
-    else
-      return attributes(name.."/.","mode")=="directory"
-    end
-  end
-  isfile=function(name)
-    return attributes(name,"mode")=="file"
-  end
-  lfs.isdir=isdir
-  lfs.isfile=isfile
-else
-  isdir=function(name)
-    return attributes(name,"mode")=="directory"
-  end
-  isfile=function(name)
-    return attributes(name,"mode")=="file"
-  end
-  lfs.isdir=isdir
-  lfs.isfile=isfile
-end
-function dir.current()
-  return (gsub(currentdir(),"\\","/"))
-end
-local function glob_pattern_function(path,patt,recurse,action)
-  if isdir(path) then
-    local usedpath
-    if path=="/" then
-      usedpath="/."
-    elseif not find(path,"/$") then
-      usedpath=path.."/."
-      path=path.."/"
-    else
-      usedpath=path
-    end
-    local dirs
-    for name in walkdir(usedpath) do
-      if name~="." and name~=".." then
-        local full=path..name
-        local mode=attributes(full,'mode')
-        if mode=='file' then
-          if not patt or find(full,patt) then
-            action(full)
-          end
-        elseif recurse and mode=="directory" then
-          if not dirs then
-            dirs={ full }
-          else
-            dirs[#dirs+1]=full
-          end
-        end
-      end
-    end
-    if dirs then
-      for i=1,#dirs do
-        glob_pattern_function(dirs[i],patt,recurse,action)
-      end
-    end
-  end
-end
-local function glob_pattern_table(path,patt,recurse,result)
-  if not result then
-    result={}
-  end
-  if isdir(path) then
-    local usedpath
-    if path=="/" then
-      usedpath="/."
-    elseif not find(path,"/$") then
-      usedpath=path.."/."
-      path=path.."/"
-    else
-      usedpath=path
-    end
-    local dirs
-    for name in walkdir(usedpath) do
-      if name~="." and name~=".." then
-        local full=path..name
-        local mode=attributes(full,'mode')
-        if mode=='file' then
-          if not patt or find(full,patt) then
-            result[#result+1]=full
-          end
-        elseif recurse and mode=="directory" then
-          if not dirs then
-            dirs={ full }
-          else
-            dirs[#dirs+1]=full
-          end
-        end
-      end
-    end
-    if dirs then
-      for i=1,#dirs do
-        glob_pattern_table(dirs[i],patt,recurse,result)
-      end
-    end
-  end
-  return result
-end
-local function globpattern(path,patt,recurse,method)
-  local kind=type(method)
-  if patt and sub(patt,1,-3)==path then
-    patt=false
-  end
-  if kind=="function" then
-    return glob_pattern_function(path,patt,recurse,method)
-  elseif kind=="table" then
-    return glob_pattern_table(path,patt,recurse,method)
-  else
-    return glob_pattern_table(path,patt,recurse,{})
-  end
-end
-dir.globpattern=globpattern
-local function collectpattern(path,patt,recurse,result)
-  local ok,scanner
-  result=result or {}
-  if path=="/" then
-    ok,scanner,first=xpcall(function() return walkdir(path..".") end,function() end) 
-  else
-    ok,scanner,first=xpcall(function() return walkdir(path)   end,function() end) 
-  end
-  if ok and type(scanner)=="function" then
-    if not find(path,"/$") then
-      path=path..'/'
-    end
-    for name in scanner,first do
-      if name=="." then
-      elseif name==".." then
-      else
-        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" then
-          attr.list=collectpattern(full,patt,recurse)
-          result[name]=attr
-        end
-      end
-    end
-  end
-  return result
-end
-dir.collectpattern=collectpattern
-local separator,pattern
-if onwindows then 
-  local slash=S("/\\")/"/"
-  pattern={
-    [1]=(Cs(P(".")+slash^1)+Cs(R("az","AZ")*P(":")*slash^0)+Cc("./"))*V(2)*V(3),
-    [2]=Cs(((1-S("*?/\\"))^0*slash)^0),
-    [3]=Cs(P(1)^0)
-  }
-else
-  pattern={
-    [1]=(C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3),
-    [2]=C(((1-S("*?/"))^0*P("/"))^0),
-    [3]=C(P(1)^0)
-  }
-end
-local filter=Cs ((
-  P("**")/".*"+P("*")/"[^/]*"+P("?")/"[^/]"+P(".")/"%%."+P("+")/"%%+"+P("-")/"%%-"+P(1)
-)^0 )
-local function glob(str,t)
-  if type(t)=="function" then
-    if type(str)=="table" then
-      for s=1,#str do
-        glob(str[s],t)
-      end
-    elseif isfile(str) then
-      t(str)
-    else
-      local root,path,base=lpegmatch(pattern,str) 
-      if root and path and base then
-        local recurse=find(base,"**",1,true) 
-        local start=root..path
-        local result=lpegmatch(filter,start..base)
-        globpattern(start,result,recurse,t)
-      end
-    end
-  else
-    if type(str)=="table" then
-      local t=t or {}
-      for s=1,#str do
-        glob(str[s],t)
-      end
-      return t
-    elseif isfile(str) then
-      if t then
-        t[#t+1]=str
-        return t
-      else
-        return { str }
-      end
-    else
-      local root,path,base=lpegmatch(pattern,str) 
-      if root and path and base then
-        local recurse=find(base,"**",1,true) 
-        local start=root..path
-        local result=lpegmatch(filter,start..base)
-        return globpattern(start,result,recurse,t)
-      else
-        return {}
-      end
-    end
-  end
-end
-dir.glob=glob
-local function globfiles(path,recurse,func,files) 
-  if type(func)=="string" then
-    local s=func
-    func=function(name) return find(name,s) end
-  end
-  files=files or {}
-  local noffiles=#files
-  for name in walkdir(path) do
-    if find(name,"^%.") then
-    else
-      local mode=attributes(name,'mode')
-      if mode=="directory" then
-        if recurse then
-          globfiles(path.."/"..name,recurse,func,files)
-        end
-      elseif mode=="file" then
-        if not func or func(name) then
-          noffiles=noffiles+1
-          files[noffiles]=path.."/"..name
-        end
-      end
-    end
-  end
-  return files
-end
-dir.globfiles=globfiles
-function dir.ls(pattern)
-  return concat(glob(pattern),"\n")
-end
-local make_indeed=true 
-if onwindows then
-  function dir.mkdirs(...)
-    local n=select("#",...)
-    local str
-    if n==1 then
-      str=select(1,...)
-      if isdir(str) then
-        return str,true
-      end
-    else
-      str=""
-      for i=1,n do
-        local s=select(i,...)
-        if s=="" then
-        elseif str=="" then
-          str=s
-        else
-          str=str.."/"..s
-        end
-      end
-    end
-    local pth=""
-    local drive=false
-    local first,middle,last=match(str,"^(//)(//*)(.*)$")
-    if first then
-    else
-      first,last=match(str,"^(//)/*(.-)$")
-      if first then
-        middle,last=match(str,"([^/]+)/+(.-)$")
-        if middle then
-          pth="//"..middle
-        else
-          pth="//"..last
-          last=""
-        end
-      else
-        first,middle,last=match(str,"^([a-zA-Z]:)(/*)(.-)$")
-        if first then
-          pth,drive=first..middle,true
-        else
-          middle,last=match(str,"^(/*)(.-)$")
-          if not middle then
-            last=str
-          end
-        end
-      end
-    end
-    for s in gmatch(last,"[^/]+") do
-      if pth=="" then
-        pth=s
-      elseif drive then
-        pth,drive=pth..s,false
-      else
-        pth=pth.."/"..s
-      end
-      if make_indeed and not isdir(pth) then
-        mkdir(pth)
-      end
-    end
-    return pth,(isdir(pth)==true)
-  end
-else
-  function dir.mkdirs(...)
-    local n=select("#",...)
-    local str,pth
-    if n==1 then
-      str=select(1,...)
-      if isdir(str) then
-        return str,true
-      end
-    else
-      str=""
-      for i=1,n do
-        local s=select(i,...)
-        if s and s~="" then 
-          if str~="" then
-            str=str.."/"..s
-          else
-            str=s
-          end
-        end
-      end
-    end
-    str=gsub(str,"/+","/")
-    if find(str,"^/") then
-      pth="/"
-      for s in gmatch(str,"[^/]+") do
-        local first=(pth=="/")
-        if first then
-          pth=pth..s
-        else
-          pth=pth.."/"..s
-        end
-        if make_indeed and not first and not isdir(pth) then
-          mkdir(pth)
-        end
-      end
-    else
-      pth="."
-      for s in gmatch(str,"[^/]+") do
-        pth=pth.."/"..s
-        if make_indeed and not isdir(pth) then
-          mkdir(pth)
-        end
-      end
-    end
-    return pth,(isdir(pth)==true)
-  end
-end
-dir.makedirs=dir.mkdirs
-do
-  local chdir=sandbox and sandbox.original(chdir) or chdir
-  if onwindows then
-    local xcurrentdir=dir.current
-    function dir.expandname(str) 
-      local first,nothing,last=match(str,"^(//)(//*)(.*)$")
-      if first then
-        first=xcurrentdir().."/" 
-      end
-      if not first then
-        first,last=match(str,"^(//)/*(.*)$")
-      end
-      if not first then
-        first,last=match(str,"^([a-zA-Z]:)(.*)$")
-        if first and not find(last,"^/") then
-          local d=currentdir() 
-          if chdir(first) then
-            first=xcurrentdir() 
-          end
-          chdir(d)
-        end
-      end
-      if not first then
-        first,last=xcurrentdir(),str
-      end
-      last=gsub(last,"//","/")
-      last=gsub(last,"/%./","/")
-      last=gsub(last,"^/*","")
-      first=gsub(first,"/*$","")
-      if last=="" or last=="." then
-        return first
-      else
-        return first.."/"..last
-      end
-    end
-  else
-    function dir.expandname(str) 
-      if not find(str,"^/") then
-        str=currentdir().."/"..str
-      end
-      str=gsub(str,"//","/")
-      str=gsub(str,"/%./","/")
-      str=gsub(str,"(.)/%.$","%1")
-      return str
-    end
-  end
-end
-file.expandname=dir.expandname 
-local stack={}
-function dir.push(newdir)
-  insert(stack,currentdir())
-  if newdir and newdir~="" then
-    chdir(newdir)
-  end
-end
-function dir.pop()
-  local d=remove(stack)
-  if d then
-    chdir(d)
-  end
-  return d
-end
-local function found(...) 
-  for i=1,select("#",...) do
-    local path=select(i,...)
-    local kind=type(path)
-    if kind=="string" then
-      if isdir(path) then
-        return path
-      end
-    elseif kind=="table" then
-      local path=found(unpack(path))
-      if path then
-        return path
-      end
-    end
-  end
-end
-dir.found=found
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-unicode']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-utf=utf or (unicode and unicode.utf8) or {}
-utf.characters=utf.characters or string.utfcharacters
-utf.values=utf.values   or string.utfvalues
-local type=type
-local char,byte,format,sub,gmatch=string.char,string.byte,string.format,string.sub,string.gmatch
-local concat=table.concat
-local P,C,R,Cs,Ct,Cmt,Cc,Carg,Cp=lpeg.P,lpeg.C,lpeg.R,lpeg.Cs,lpeg.Ct,lpeg.Cmt,lpeg.Cc,lpeg.Carg,lpeg.Cp
-local lpegmatch=lpeg.match
-local patterns=lpeg.patterns
-local tabletopattern=lpeg.utfchartabletopattern
-local bytepairs=string.bytepairs
-local finder=lpeg.finder
-local replacer=lpeg.replacer
-local utfvalues=utf.values
-local utfgmatch=utf.gmatch 
-local p_utftype=patterns.utftype
-local p_utfstricttype=patterns.utfstricttype
-local p_utfoffset=patterns.utfoffset
-local p_utf8char=patterns.utf8character
-local p_utf8byte=patterns.utf8byte
-local p_utfbom=patterns.utfbom
-local p_newline=patterns.newline
-local p_whitespace=patterns.whitespace
-if not unicode then
-  unicode={ utf=utf } 
-end
-if not utf.char then
-  local floor,char=math.floor,string.char
-  function utf.char(n)
-    if n<0x80 then
-      return char(n)
-    elseif n<0x800 then
-      return char(
-        0xC0+floor(n/0x40),
-        0x80+(n%0x40)
-      )
-    elseif n<0x10000 then
-      return char(
-        0xE0+floor(n/0x1000),
-        0x80+(floor(n/0x40)%0x40),
-        0x80+(n%0x40)
-      )
-    elseif n<0x200000 then
-      return char(
-        0xF0+floor(n/0x40000),
-        0x80+(floor(n/0x1000)%0x40),
-        0x80+(floor(n/0x40)%0x40),
-        0x80+(n%0x40)
-      )
-    else
-      return ""
-    end
-  end
-end
-if not utf.byte then
-  local utf8byte=patterns.utf8byte
-  function utf.byte(c)
-    return lpegmatch(utf8byte,c)
-  end
-end
-local utfchar,utfbyte=utf.char,utf.byte
-function utf.filetype(data)
-  return data and lpegmatch(p_utftype,data) or "unknown"
-end
-local toentities=Cs (
-  (
-    patterns.utf8one+(
-        patterns.utf8two+patterns.utf8three+patterns.utf8four
-      )/function(s) local b=utfbyte(s) if b<127 then return s else return format("&#%X;",b) end end
-  )^0
-)
-patterns.toentities=toentities
-function utf.toentities(str)
-  return lpegmatch(toentities,str)
-end
-local one=P(1)
-local two=C(1)*C(1)
-local four=C(R(utfchar(0xD8),utfchar(0xFF)))*C(1)*C(1)*C(1)
-local pattern=P("\254\255")*Cs((
-          four/function(a,b,c,d)
-                local ab=0xFF*byte(a)+byte(b)
-                local cd=0xFF*byte(c)+byte(d)
-                return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000)
-              end+two/function(a,b)
-                return utfchar(byte(a)*256+byte(b))
-              end+one
-        )^1 )+P("\255\254")*Cs((
-          four/function(b,a,d,c)
-                local ab=0xFF*byte(a)+byte(b)
-                local cd=0xFF*byte(c)+byte(d)
-                return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000)
-              end+two/function(b,a)
-                return utfchar(byte(a)*256+byte(b))
-              end+one
-        )^1 )
-function string.toutf(s) 
-  return lpegmatch(pattern,s) or s 
-end
-local validatedutf=Cs (
-  (
-    patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four+P(1)/"�"
-  )^0
-)
-patterns.validatedutf=validatedutf
-function utf.is_valid(str)
-  return type(str)=="string" and lpegmatch(validatedutf,str) or false
-end
-if not utf.len then
-  local n,f=0,1
-  local utfcharcounter=patterns.utfbom^-1*Cmt (
-    Cc(1)*patterns.utf8one^1+Cc(2)*patterns.utf8two^1+Cc(3)*patterns.utf8three^1+Cc(4)*patterns.utf8four^1,
-    function(_,t,d) 
-      n=n+(t-f)/d
-      f=t
-      return true
-    end
-  )^0
-  function utf.len(str)
-    n,f=0,1
-    lpegmatch(utfcharcounter,str or "")
-    return n
-  end
-end
-utf.length=utf.len
-if not utf.sub then
-  local utflength=utf.length
-  local b,e,n,first,last=0,0,0,0,0
-  local function slide_zero(s,p)
-    n=n+1
-    if n>=last then
-      e=p-1
-    else
-      return p
-    end
-  end
-  local function slide_one(s,p)
-    n=n+1
-    if n==first then
-      b=p
-    end
-    if n>=last then
-      e=p-1
-    else
-      return p
-    end
-  end
-  local function slide_two(s,p)
-    n=n+1
-    if n==first then
-      b=p
-    else
-      return true
-    end
-  end
-  local pattern_zero=Cmt(p_utf8char,slide_zero)^0
-  local pattern_one=Cmt(p_utf8char,slide_one )^0
-  local pattern_two=Cmt(p_utf8char,slide_two )^0
-  local pattern_first=C(patterns.utf8character)
-  function utf.sub(str,start,stop)
-    if not start then
-      return str
-    end
-    if start==0 then
-      start=1
-    end
-    if not stop then
-      if start<0 then
-        local l=utflength(str) 
-        start=l+start
-      else
-        start=start-1
-      end
-      b,n,first=0,0,start
-      lpegmatch(pattern_two,str)
-      if n>=first then
-        return sub(str,b)
-      else
-        return ""
-      end
-    end
-    if start<0 or stop<0 then
-      local l=utf.length(str)
-      if start<0 then
-        start=l+start
-        if start<=0 then
-          start=1
-        else
-          start=start+1
-        end
-      end
-      if stop<0 then
-        stop=l+stop
-        if stop==0 then
-          stop=1
-        else
-          stop=stop+1
-        end
-      end
-    end
-    if start==1 and stop==1 then
-      return lpegmatch(pattern_first,str) or ""
-    elseif start>stop then
-      return ""
-    elseif start>1 then
-      b,e,n,first,last=0,0,0,start-1,stop
-      lpegmatch(pattern_one,str)
-      if n>=first and e==0 then
-        e=#str
-      end
-      return sub(str,b,e)
-    else
-      b,e,n,last=1,0,0,stop
-      lpegmatch(pattern_zero,str)
-      if e==0 then
-        e=#str
-      end
-      return sub(str,b,e)
-    end
-  end
-end
-function utf.remapper(mapping,option,action) 
-  local variant=type(mapping)
-  if variant=="table" then
-    action=action or mapping
-    if option=="dynamic" then
-      local pattern=false
-      table.setmetatablenewindex(mapping,function(t,k,v) rawset(t,k,v) pattern=false end)
-      return function(str)
-        if not str or str=="" then
-          return ""
-        else
-          if not pattern then
-            pattern=Cs((tabletopattern(mapping)/action+p_utf8char)^0)
-          end
-          return lpegmatch(pattern,str)
-        end
-      end
-    elseif option=="pattern" then
-      return Cs((tabletopattern(mapping)/action+p_utf8char)^0)
-    else
-      local pattern=Cs((tabletopattern(mapping)/action+p_utf8char)^0)
-      return function(str)
-        if not str or str=="" then
-          return ""
-        else
-          return lpegmatch(pattern,str)
-        end
-      end,pattern
-    end
-  elseif variant=="function" then
-    if option=="pattern" then
-      return Cs((p_utf8char/mapping+p_utf8char)^0)
-    else
-      local pattern=Cs((p_utf8char/mapping+p_utf8char)^0)
-      return function(str)
-        if not str or str=="" then
-          return ""
-        else
-          return lpegmatch(pattern,str)
-        end
-      end,pattern
-    end
-  else
-    return function(str)
-      return str or ""
-    end
-  end
-end
-function utf.replacer(t) 
-  local r=replacer(t,false,false,true)
-  return function(str)
-    return lpegmatch(r,str)
-  end
-end
-function utf.subtituter(t) 
-  local f=finder (t)
-  local r=replacer(t,false,false,true)
-  return function(str)
-    local i=lpegmatch(f,str)
-    if not i then
-      return str
-    elseif i>#str then
-      return str
-    else
-      return lpegmatch(r,str)
-    end
-  end
-end
-local utflinesplitter=p_utfbom^-1*lpeg.tsplitat(p_newline)
-local utfcharsplitter_ows=p_utfbom^-1*Ct(C(p_utf8char)^0)
-local utfcharsplitter_iws=p_utfbom^-1*Ct((p_whitespace^1+C(p_utf8char))^0)
-local utfcharsplitter_raw=Ct(C(p_utf8char)^0)
-patterns.utflinesplitter=utflinesplitter
-function utf.splitlines(str)
-  return lpegmatch(utflinesplitter,str or "")
-end
-function utf.split(str,ignorewhitespace) 
-  if ignorewhitespace then
-    return lpegmatch(utfcharsplitter_iws,str or "")
-  else
-    return lpegmatch(utfcharsplitter_ows,str or "")
-  end
-end
-function utf.totable(str) 
-  return lpegmatch(utfcharsplitter_raw,str)
-end
-function utf.magic(f) 
-  local str=f:read(4) or ""
-  local off=lpegmatch(p_utfoffset,str)
-  if off<4 then
-    f:seek('set',off)
-  end
-  return lpegmatch(p_utftype,str)
-end
-local utf16_to_utf8_be,utf16_to_utf8_le
-local utf32_to_utf8_be,utf32_to_utf8_le
-local utf_16_be_getbom=patterns.utfbom_16_be^-1
-local utf_16_le_getbom=patterns.utfbom_16_le^-1
-local utf_32_be_getbom=patterns.utfbom_32_be^-1
-local utf_32_le_getbom=patterns.utfbom_32_le^-1
-local utf_16_be_linesplitter=utf_16_be_getbom*lpeg.tsplitat(patterns.utf_16_be_nl)
-local utf_16_le_linesplitter=utf_16_le_getbom*lpeg.tsplitat(patterns.utf_16_le_nl)
-local utf_32_be_linesplitter=utf_32_be_getbom*lpeg.tsplitat(patterns.utf_32_be_nl)
-local utf_32_le_linesplitter=utf_32_le_getbom*lpeg.tsplitat(patterns.utf_32_le_nl)
-local more=0
-local p_utf16_to_utf8_be=C(1)*C(1)/function(left,right)
-  local now=256*byte(left)+byte(right)
-  if more>0 then
-    now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 
-    more=0
-    return utfchar(now)
-  elseif now>=0xD800 and now<=0xDBFF then
-    more=now
-    return "" 
-  else
-    return utfchar(now)
-  end
-end
-local p_utf16_to_utf8_le=C(1)*C(1)/function(right,left)
-  local now=256*byte(left)+byte(right)
-  if more>0 then
-    now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 
-    more=0
-    return utfchar(now)
-  elseif now>=0xD800 and now<=0xDBFF then
-    more=now
-    return "" 
-  else
-    return utfchar(now)
-  end
-end
-local p_utf32_to_utf8_be=C(1)*C(1)*C(1)*C(1)/function(a,b,c,d)
-  return utfchar(256*256*256*byte(a)+256*256*byte(b)+256*byte(c)+byte(d))
-end
-local p_utf32_to_utf8_le=C(1)*C(1)*C(1)*C(1)/function(a,b,c,d)
-  return utfchar(256*256*256*byte(d)+256*256*byte(c)+256*byte(b)+byte(a))
-end
-p_utf16_to_utf8_be=P(true)/function() more=0 end*utf_16_be_getbom*Cs(p_utf16_to_utf8_be^0)
-p_utf16_to_utf8_le=P(true)/function() more=0 end*utf_16_le_getbom*Cs(p_utf16_to_utf8_le^0)
-p_utf32_to_utf8_be=P(true)/function() more=0 end*utf_32_be_getbom*Cs(p_utf32_to_utf8_be^0)
-p_utf32_to_utf8_le=P(true)/function() more=0 end*utf_32_le_getbom*Cs(p_utf32_to_utf8_le^0)
-patterns.utf16_to_utf8_be=p_utf16_to_utf8_be
-patterns.utf16_to_utf8_le=p_utf16_to_utf8_le
-patterns.utf32_to_utf8_be=p_utf32_to_utf8_be
-patterns.utf32_to_utf8_le=p_utf32_to_utf8_le
-utf16_to_utf8_be=function(s)
-  if s and s~="" then
-    return lpegmatch(p_utf16_to_utf8_be,s)
-  else
-    return s
-  end
-end
-local utf16_to_utf8_be_t=function(t)
-  if not t then
-    return nil
-  elseif type(t)=="string" then
-    t=lpegmatch(utf_16_be_linesplitter,t)
-  end
-  for i=1,#t do
-    local s=t[i]
-    if s~="" then
-      t[i]=lpegmatch(p_utf16_to_utf8_be,s)
-    end
-  end
-  return t
-end
-utf16_to_utf8_le=function(s)
-  if s and s~="" then
-    return lpegmatch(p_utf16_to_utf8_le,s)
-  else
-    return s
-  end
-end
-local utf16_to_utf8_le_t=function(t)
-  if not t then
-    return nil
-  elseif type(t)=="string" then
-    t=lpegmatch(utf_16_le_linesplitter,t)
-  end
-  for i=1,#t do
-    local s=t[i]
-    if s~="" then
-      t[i]=lpegmatch(p_utf16_to_utf8_le,s)
-    end
-  end
-  return t
-end
-utf32_to_utf8_be=function(s)
-  if s and s~="" then
-    return lpegmatch(p_utf32_to_utf8_be,s)
-  else
-    return s
-  end
-end
-local utf32_to_utf8_be_t=function(t)
-  if not t then
-    return nil
-  elseif type(t)=="string" then
-    t=lpegmatch(utf_32_be_linesplitter,t)
-  end
-  for i=1,#t do
-    local s=t[i]
-    if s~="" then
-      t[i]=lpegmatch(p_utf32_to_utf8_be,s)
-    end
-  end
-  return t
-end
-utf32_to_utf8_le=function(s)
-  if s and s~="" then
-    return lpegmatch(p_utf32_to_utf8_le,s)
-  else
-    return s
-  end
-end
-local utf32_to_utf8_le_t=function(t)
-  if not t then
-    return nil
-  elseif type(t)=="string" then
-    t=lpegmatch(utf_32_le_linesplitter,t)
-  end
-  for i=1,#t do
-    local s=t[i]
-    if s~="" then
-      t[i]=lpegmatch(p_utf32_to_utf8_le,s)
-    end
-  end
-  return t
-end
-utf.utf16_to_utf8_le_t=utf16_to_utf8_le_t
-utf.utf16_to_utf8_be_t=utf16_to_utf8_be_t
-utf.utf32_to_utf8_le_t=utf32_to_utf8_le_t
-utf.utf32_to_utf8_be_t=utf32_to_utf8_be_t
-utf.utf16_to_utf8_le=utf16_to_utf8_le
-utf.utf16_to_utf8_be=utf16_to_utf8_be
-utf.utf32_to_utf8_le=utf32_to_utf8_le
-utf.utf32_to_utf8_be=utf32_to_utf8_be
-function utf.utf8_to_utf8_t(t)
-  return type(t)=="string" and lpegmatch(utflinesplitter,t) or t
-end
-function utf.utf16_to_utf8_t(t,endian)
-  return endian and utf16_to_utf8_be_t(t) or utf16_to_utf8_le_t(t) or t
-end
-function utf.utf32_to_utf8_t(t,endian)
-  return endian and utf32_to_utf8_be_t(t) or utf32_to_utf8_le_t(t) or t
-end
-local function little(b)
-  if b<0x10000 then
-    return char(b%256,b/256)
-  else
-    b=b-0x10000
-    local b1,b2=b/1024+0xD800,b%1024+0xDC00
-    return char(b1%256,b1/256,b2%256,b2/256)
-  end
-end
-local function big(b)
-  if b<0x10000 then
-    return char(b/256,b%256)
-  else
-    b=b-0x10000
-    local b1,b2=b/1024+0xD800,b%1024+0xDC00
-    return char(b1/256,b1%256,b2/256,b2%256)
-  end
-end
-local l_remap=Cs((p_utf8byte/little+P(1)/"")^0)
-local b_remap=Cs((p_utf8byte/big+P(1)/"")^0)
-local function utf8_to_utf16_be(str,nobom)
-  if nobom then
-    return lpegmatch(b_remap,str)
-  else
-    return char(254,255)..lpegmatch(b_remap,str)
-  end
-end
-local function utf8_to_utf16_le(str,nobom)
-  if nobom then
-    return lpegmatch(l_remap,str)
-  else
-    return char(255,254)..lpegmatch(l_remap,str)
-  end
-end
-utf.utf8_to_utf16_be=utf8_to_utf16_be
-utf.utf8_to_utf16_le=utf8_to_utf16_le
-function utf.utf8_to_utf16(str,littleendian,nobom)
-  if littleendian then
-    return utf8_to_utf16_le(str,nobom)
-  else
-    return utf8_to_utf16_be(str,nobom)
-  end
-end
-local pattern=Cs (
-  (p_utf8byte/function(unicode     ) return format("0x%04X",unicode) end)*(p_utf8byte*Carg(1)/function(unicode,separator) return format("%s0x%04X",separator,unicode) end)^0
-)
-function utf.tocodes(str,separator)
-  return lpegmatch(pattern,str,1,separator or " ")
-end
-function utf.ustring(s)
-  return format("U+%05X",type(s)=="number" and s or utfbyte(s))
-end
-function utf.xstring(s)
-  return format("0x%05X",type(s)=="number" and s or utfbyte(s))
-end
-function utf.toeight(str)
-  if not str or str=="" then
-    return nil
-  end
-  local utftype=lpegmatch(p_utfstricttype,str)
-  if utftype=="utf-8" then
-    return sub(str,4)        
-  elseif utftype=="utf-16-be" then
-    return utf16_to_utf8_be(str)  
-  elseif utftype=="utf-16-le" then
-    return utf16_to_utf8_le(str)  
-  else
-    return str
-  end
-end
-local p_nany=p_utf8char/""
-if utfgmatch then
-  function utf.count(str,what)
-    if type(what)=="string" then
-      local n=0
-      for _ in utfgmatch(str,what) do
-        n=n+1
-      end
-      return n
-    else 
-      return #lpegmatch(Cs((P(what)/" "+p_nany)^0),str)
-    end
-  end
-else
-  local cache={}
-  function utf.count(str,what)
-    if type(what)=="string" then
-      local p=cache[what]
-      if not p then
-        p=Cs((P(what)/" "+p_nany)^0)
-        cache[p]=p
-      end
-      return #lpegmatch(p,str)
-    else 
-      return #lpegmatch(Cs((P(what)/" "+p_nany)^0),str)
-    end
-  end
-end
-if not utf.characters then
-  function utf.characters(str)
-    return gmatch(str,".[\128-\191]*")
-  end
-  string.utfcharacters=utf.characters
-end
-if not utf.values then
-  local find=string.find
-  local dummy=function()
-  end
-  function utf.values(str)
-    local n=#str
-    if n==0 then
-      return dummy
-    elseif n==1 then
-      return function() return utfbyte(str) end
-    else
-      local p=1
-      return function()
-          local b,e=find(str,".[\128-\191]*",p)
-          if b then
-            p=e+1
-            return utfbyte(sub(str,b,e))
-          end
-      end
-    end
-  end
-  string.utfvalues=utf.values
-end
-function utf.chrlen(u) 
-  return
-    (u<0x80 and 1) or
-    (u<0xE0 and 2) or
-    (u<0xF0 and 3) or
-    (u<0xF8 and 4) or
-    (u<0xFC and 5) or
-    (u<0xFE and 6) or 0
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-url']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local char,format,byte=string.char,string.format,string.byte
-local concat=table.concat
-local tonumber,type=tonumber,type
-local P,C,R,S,Cs,Cc,Ct,Cf,Cg,V=lpeg.P,lpeg.C,lpeg.R,lpeg.S,lpeg.Cs,lpeg.Cc,lpeg.Ct,lpeg.Cf,lpeg.Cg,lpeg.V
-local lpegmatch,lpegpatterns,replacer=lpeg.match,lpeg.patterns,lpeg.replacer
-url=url or {}
-local url=url
-local tochar=function(s) return char(tonumber(s,16)) end
-local colon=P(":")
-local qmark=P("?")
-local hash=P("#")
-local slash=P("/")
-local percent=P("%")
-local endofstring=P(-1)
-local hexdigit=R("09","AF","af")
-local plus=P("+")
-local nothing=Cc("")
-local escapedchar=(percent*C(hexdigit*hexdigit))/tochar
-local escaped=(plus/" ")+escapedchar 
-local noslash=P("/")/""
-local schemestr=Cs((escaped+(1-colon-slash-qmark-hash))^2)
-local authoritystr=Cs((escaped+(1-   slash-qmark-hash))^0)
-local pathstr=Cs((escaped+(1-      qmark-hash))^0)
-local querystr=Cs(((1-         hash))^0)
-local fragmentstr=Cs((escaped+(1-      endofstring))^0)
-local scheme=schemestr*colon+nothing
-local authority=slash*slash*authoritystr+nothing
-local path=slash*pathstr+nothing
-local query=qmark*querystr+nothing
-local fragment=hash*fragmentstr+nothing
-local validurl=scheme*authority*path*query*fragment
-local parser=Ct(validurl)
-lpegpatterns.url=validurl
-lpegpatterns.urlsplitter=parser
-local escapes={}
-setmetatable(escapes,{ __index=function(t,k)
-  local v=format("%%%02X",byte(k))
-  t[k]=v
-  return v
-end })
-local escaper=Cs((R("09","AZ","az")^1+P(" ")/"%%20"+S("-./_")^1+P(1)/escapes)^0) 
-local unescaper=Cs((escapedchar+1)^0)
-local getcleaner=Cs((P("+++")/"%%2B"+P("+")/"%%20"+P(1))^1)
-lpegpatterns.urlunescaped=escapedchar
-lpegpatterns.urlescaper=escaper
-lpegpatterns.urlunescaper=unescaper
-lpegpatterns.urlgetcleaner=getcleaner
-function url.unescapeget(str)
-  return lpegmatch(getcleaner,str)
-end
-local function split(str)
-  return (type(str)=="string" and lpegmatch(parser,str)) or str
-end
-local isscheme=schemestr*colon*slash*slash 
-local function hasscheme(str)
-  if str then
-    local scheme=lpegmatch(isscheme,str) 
-    return scheme~="" and scheme or false
-  else
-    return false
-  end
-end
-local rootletter=R("az","AZ")+S("_-+")
-local separator=P("://")
-local qualified=P(".")^0*P("/")+rootletter*P(":")+rootletter^1*separator+rootletter^1*P("/")
-local rootbased=P("/")+rootletter*P(":")
-local barswapper=replacer("|",":")
-local backslashswapper=replacer("\\","/")
-local equal=P("=")
-local amp=P("&")
-local key=Cs(((escapedchar+1)-equal      )^0)
-local value=Cs(((escapedchar+1)-amp -endofstring)^0)
-local splitquery=Cf (Ct("")*P { "sequence",
-  sequence=V("pair")*(amp*V("pair"))^0,
-  pair=Cg(key*equal*value),
-},rawset)
-local function hashed(str) 
-  if not str or str=="" then
-    return {
-      scheme="invalid",
-      original=str,
-    }
-  end
-  local detailed=split(str)
-  local rawscheme=""
-  local rawquery=""
-  local somescheme=false
-  local somequery=false
-  if detailed then
-    rawscheme=detailed[1]
-    rawquery=detailed[4]
-    somescheme=rawscheme~=""
-    somequery=rawquery~=""
-  end
-  if not somescheme and not somequery then
-    return {
-      scheme="file",
-      authority="",
-      path=str,
-      query="",
-      fragment="",
-      original=str,
-      noscheme=true,
-      filename=str,
-    }
-  end
-  local authority=detailed[2]
-  local path=detailed[3]
-  local filename=nil
-  if authority=="" then
-    filename=path
-  elseif path=="" then
-    filename=""
-  else
-    filename=authority.."/"..path
-  end
-  return {
-    scheme=rawscheme,
-    authority=authority,
-    path=path,
-    query=lpegmatch(unescaper,rawquery),
-    queries=lpegmatch(splitquery,rawquery),
-    fragment=detailed[5],
-    original=str,
-    noscheme=false,
-    filename=filename,
-  }
-end
-url.split=split
-url.hasscheme=hasscheme
-url.hashed=hashed
-function url.addscheme(str,scheme) 
-  if hasscheme(str) then
-    return str
-  elseif not scheme then
-    return "file:///"..str
-  else
-    return scheme..":///"..str
-  end
-end
-function url.construct(hash) 
-  local fullurl,f={},0
-  local scheme,authority,path,query,fragment=hash.scheme,hash.authority,hash.path,hash.query,hash.fragment
-  if scheme and scheme~="" then
-    f=f+1;fullurl[f]=scheme.."://"
-  end
-  if authority and authority~="" then
-    f=f+1;fullurl[f]=authority
-  end
-  if path and path~="" then
-    f=f+1;fullurl[f]="/"..path
-  end
-  if query and query~="" then
-    f=f+1;fullurl[f]="?"..query
-  end
-  if fragment and fragment~="" then
-    f=f+1;fullurl[f]="#"..fragment
-  end
-  return lpegmatch(escaper,concat(fullurl))
-end
-local pattern=Cs(slash^-1/""*R("az","AZ")*((S(":|")/":")+P(":"))*slash*P(1)^0)
-function url.filename(filename)
-  local spec=hashed(filename)
-  local path=spec.path
-  return (spec.scheme=="file" and path and lpegmatch(pattern,path)) or filename
-end
-local function escapestring(str)
-  return lpegmatch(escaper,str)
-end
-url.escape=escapestring
-function url.query(str)
-  if type(str)=="string" then
-    return lpegmatch(splitquery,str) or ""
-  else
-    return str
-  end
-end
-function url.toquery(data)
-  local td=type(data)
-  if td=="string" then
-    return #str and escape(data) or nil 
-  elseif td=="table" then
-    if next(data) then
-      local t={}
-      for k,v in next,data do
-        t[#t+1]=format("%s=%s",k,escapestring(v))
-      end
-      return concat(t,"&")
-    end
-  else
-  end
-end
-local pattern=Cs(noslash^0*(1-noslash*P(-1))^0)
-function url.barepath(path)
-  if not path or path=="" then
-    return ""
-  else
-    return lpegmatch(pattern,path)
-  end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['l-set']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-set=set or {}
-local nums={}
-local tabs={}
-local concat=table.concat
-local next,type=next,type
-set.create=table.tohash
-function set.tonumber(t)
-  if next(t) then
-    local s=""
-    for k,v in next,t do
-      if v then
-        s=s.." "..k
-      end
-    end
-    local n=nums[s]
-    if not n then
-      n=#tabs+1
-      tabs[n]=t
-      nums[s]=n
-    end
-    return n
-  else
-    return 0
-  end
-end
-function set.totable(n)
-  if n==0 then
-    return {}
-  else
-    return tabs[n] or {}
-  end
-end
-function set.tolist(n)
-  if n==0 or not tabs[n] then
-    return ""
-  else
-    local t,n={},0
-    for k,v in next,tabs[n] do
-      if v then
-        n=n+1
-        t[n]=k
-      end
-    end
-    return concat(t," ")
-  end
-end
-function set.contains(n,s)
-  if type(n)=="table" then
-    return n[s]
-  elseif n==0 then
-    return false
-  else
-    local t=tabs[n]
-    return t and t[s]
-  end
-end
-
-end -- closure

Modified: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -7,7 +7,7 @@
 --  lualibs.dtx  (with options: `basic')
 --  This is a generated file.
 --  
---  Copyright (C) 2009--2016 by
+--  Copyright (C) 2009--2017 by
 --          PRAGMA ADE / ConTeXt Development Team
 --          The LuaLaTeX Dev Team
 --  
@@ -29,8 +29,8 @@
 
 local lualibs_basic_module = {
   name          = "lualibs-basic",
-  version       = 2.4,
-  date          = "2016-04-06",
+  version       = 2.5,
+  date          = "2017-02-01",
   description   = "ConTeXt Lua libraries -- basic collection.",
   author        = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang",
   copyright     = "PRAGMA ADE / ConTeXt Development Team",

Modified: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-dir.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-dir.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-dir.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -335,6 +335,36 @@
 
 dir.globfiles = globfiles
 
+local function globdirs(path,recurse,func,files) -- func == pattern or function
+    if type(func) == "string" then
+        local s = func
+        func = function(name) return find(name,s) end
+    end
+    files = files or { }
+    local noffiles = #files
+    for name in walkdir(path) do
+        if find(name,"^%.") then
+            --- skip
+        else
+            local mode = attributes(name,'mode')
+            if mode == "directory" then
+                if not func or func(name) then
+                    noffiles = noffiles + 1
+                    files[noffiles] = path .. "/" .. name
+                    if recurse then
+                        globdirs(path .. "/" .. name,recurse,func,files)
+                    end
+                end
+            end
+        end
+    end
+    return files
+end
+
+dir.globdirs = globdirs
+
+-- inspect(globdirs("e:/tmp"))
+
 -- t = dir.glob("c:/data/develop/context/sources/**/????-*.tex")
 -- t = dir.glob("c:/data/develop/tex/texmf/**/*.tex")
 -- t = dir.glob("c:/data/develop/context/texmf/**/*.tex")
@@ -557,9 +587,13 @@
 local stack = { }
 
 function dir.push(newdir)
-    insert(stack,currentdir())
+    local curdir = currentdir()
+    insert(stack,curdir)
     if newdir and newdir ~= "" then
         chdir(newdir)
+        return newdir
+    else
+        return curdir
     end
 end
 

Deleted: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended-merged.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended-merged.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended-merged.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -1,3233 +0,0 @@
--- merged file : lualibs-extended-merged.lua
--- parent file : lualibs-extended.lua
--- merge date  : Wed Apr  6 23:53:30 2016
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['util-str']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-utilities=utilities or {}
-utilities.strings=utilities.strings or {}
-local strings=utilities.strings
-local format,gsub,rep,sub=string.format,string.gsub,string.rep,string.sub
-local load,dump=load,string.dump
-local tonumber,type,tostring=tonumber,type,tostring
-local unpack,concat=table.unpack,table.concat
-local P,V,C,S,R,Ct,Cs,Cp,Carg,Cc=lpeg.P,lpeg.V,lpeg.C,lpeg.S,lpeg.R,lpeg.Ct,lpeg.Cs,lpeg.Cp,lpeg.Carg,lpeg.Cc
-local patterns,lpegmatch=lpeg.patterns,lpeg.match
-local utfchar,utfbyte=utf.char,utf.byte
-local loadstripped=nil
-if _LUAVERSION<5.2 then
-  loadstripped=function(str,shortcuts)
-    return load(str)
-  end
-else
-  loadstripped=function(str,shortcuts)
-    if shortcuts then
-      return load(dump(load(str),true),nil,nil,shortcuts)
-    else
-      return load(dump(load(str),true))
-    end
-  end
-end
-if not number then number={} end 
-local stripper=patterns.stripzeros
-local newline=patterns.newline
-local endofstring=patterns.endofstring
-local whitespace=patterns.whitespace
-local spacer=patterns.spacer
-local spaceortab=patterns.spaceortab
-local function points(n)
-  n=tonumber(n)
-  return (not n or n==0) and "0pt" or lpegmatch(stripper,format("%.5fpt",n/65536))
-end
-local function basepoints(n)
-  n=tonumber(n)
-  return (not n or n==0) and "0bp" or lpegmatch(stripper,format("%.5fbp",n*(7200/7227)/65536))
-end
-number.points=points
-number.basepoints=basepoints
-local rubish=spaceortab^0*newline
-local anyrubish=spaceortab+newline
-local anything=patterns.anything
-local stripped=(spaceortab^1/"")*newline
-local leading=rubish^0/""
-local trailing=(anyrubish^1*endofstring)/""
-local redundant=rubish^3/"\n"
-local pattern=Cs(leading*(trailing+redundant+stripped+anything)^0)
-function strings.collapsecrlf(str)
-  return lpegmatch(pattern,str)
-end
-local repeaters={} 
-function strings.newrepeater(str,offset)
-  offset=offset or 0
-  local s=repeaters[str]
-  if not s then
-    s={}
-    repeaters[str]=s
-  end
-  local t=s[offset]
-  if t then
-    return t
-  end
-  t={}
-  setmetatable(t,{ __index=function(t,k)
-    if not k then
-      return ""
-    end
-    local n=k+offset
-    local s=n>0 and rep(str,n) or ""
-    t[k]=s
-    return s
-  end })
-  s[offset]=t
-  return t
-end
-local extra,tab,start=0,0,4,0
-local nspaces=strings.newrepeater(" ")
-string.nspaces=nspaces
-local pattern=Carg(1)/function(t)
-    extra,tab,start=0,t or 7,1
-  end*Cs((
-   Cp()*patterns.tab/function(position)
-     local current=(position-start+1)+extra
-     local spaces=tab-(current-1)%tab
-     if spaces>0 then
-       extra=extra+spaces-1
-       return nspaces[spaces] 
-     else
-       return ""
-     end
-   end+newline*Cp()/function(position)
-     extra,start=0,position
-   end+patterns.anything
- )^1)
-function strings.tabtospace(str,tab)
-  return lpegmatch(pattern,str,1,tab or 7)
-end
-local space=spacer^0
-local nospace=space/""
-local endofline=nospace*newline
-local stripend=(whitespace^1*endofstring)/""
-local normalline=(nospace*((1-space*(newline+endofstring))^1)*nospace)
-local stripempty=endofline^1/""
-local normalempty=endofline^1
-local singleempty=endofline*(endofline^0/"")
-local doubleempty=endofline*endofline^-1*(endofline^0/"")
-local stripstart=stripempty^0
-local p_prune_normal=Cs (stripstart*(stripend+normalline+normalempty )^0 )
-local p_prune_collapse=Cs (stripstart*(stripend+normalline+doubleempty )^0 )
-local p_prune_noempty=Cs (stripstart*(stripend+normalline+singleempty )^0 )
-local p_retain_normal=Cs ((normalline+normalempty )^0 )
-local p_retain_collapse=Cs ((normalline+doubleempty )^0 )
-local p_retain_noempty=Cs ((normalline+singleempty )^0 )
-local striplinepatterns={
-  ["prune"]=p_prune_normal,
-  ["prune and collapse"]=p_prune_collapse,
-  ["prune and no empty"]=p_prune_noempty,
-  ["retain"]=p_retain_normal,
-  ["retain and collapse"]=p_retain_collapse,
-  ["retain and no empty"]=p_retain_noempty,
-  ["collapse"]=patterns.collapser,
-}
-setmetatable(striplinepatterns,{ __index=function(t,k) return p_prune_collapse end })
-strings.striplinepatterns=striplinepatterns
-function strings.striplines(str,how)
-  return str and lpegmatch(striplinepatterns[how],str) or str
-end
-strings.striplong=strings.striplines
-function strings.nice(str)
-  str=gsub(str,"[:%-+_]+"," ") 
-  return str
-end
-local n=0
-local sequenced=table.sequenced
-function string.autodouble(s,sep)
-  if s==nil then
-    return '""'
-  end
-  local t=type(s)
-  if t=="number" then
-    return tostring(s) 
-  end
-  if t=="table" then
-    return ('"'..sequenced(s,sep or ",")..'"')
-  end
-  return ('"'..tostring(s)..'"')
-end
-function string.autosingle(s,sep)
-  if s==nil then
-    return "''"
-  end
-  local t=type(s)
-  if t=="number" then
-    return tostring(s) 
-  end
-  if t=="table" then
-    return ("'"..sequenced(s,sep or ",").."'")
-  end
-  return ("'"..tostring(s).."'")
-end
-local tracedchars={ [0]=
-  "[null]","[soh]","[stx]","[etx]","[eot]","[enq]","[ack]","[bel]",
-  "[bs]","[ht]","[lf]","[vt]","[ff]","[cr]","[so]","[si]",
-  "[dle]","[dc1]","[dc2]","[dc3]","[dc4]","[nak]","[syn]","[etb]",
-  "[can]","[em]","[sub]","[esc]","[fs]","[gs]","[rs]","[us]",
-  "[space]",
-}
-string.tracedchars=tracedchars
-strings.tracers=tracedchars
-function string.tracedchar(b)
-  if type(b)=="number" then
-    return tracedchars[b] or (utfchar(b).." (U+"..format("%05X",b)..")")
-  else
-    local c=utfbyte(b)
-    return tracedchars[c] or (b.." (U+"..(c and format("%05X",c) or "?????")..")")
-  end
-end
-function number.signed(i)
-  if i>0 then
-    return "+",i
-  else
-    return "-",-i
-  end
-end
-local zero=P("0")^1/""
-local plus=P("+")/""
-local minus=P("-")
-local separator=S(".")
-local digit=R("09")
-local trailing=zero^1*#S("eE")
-local exponent=(S("eE")*(plus+Cs((minus*zero^0*P(-1))/"")+minus)*zero^0*(P(-1)*Cc("0")+P(1)^1))
-local pattern_a=Cs(minus^0*digit^1*(separator/""*trailing+separator*(trailing+digit)^0)*exponent)
-local pattern_b=Cs((exponent+P(1))^0)
-function number.sparseexponent(f,n)
-  if not n then
-    n=f
-    f="%e"
-  end
-  local tn=type(n)
-  if tn=="string" then 
-    local m=tonumber(n)
-    if m then
-      return lpegmatch((f=="%e" or f=="%E") and pattern_a or pattern_b,format(f,m))
-    end
-  elseif tn=="number" then
-    return lpegmatch((f=="%e" or f=="%E") and pattern_a or pattern_b,format(f,n))
-  end
-  return tostring(n)
-end
-local template=[[
-%s
-%s
-return function(%s) return %s end
-]]
-local preamble,environment="",{}
-if _LUAVERSION<5.2 then
-  preamble=[[
-local lpeg=lpeg
-local type=type
-local tostring=tostring
-local tonumber=tonumber
-local format=string.format
-local concat=table.concat
-local signed=number.signed
-local points=number.points
-local basepoints= number.basepoints
-local utfchar=utf.char
-local utfbyte=utf.byte
-local lpegmatch=lpeg.match
-local nspaces=string.nspaces
-local tracedchar=string.tracedchar
-local autosingle=string.autosingle
-local autodouble=string.autodouble
-local sequenced=table.sequenced
-local formattednumber=number.formatted
-local sparseexponent=number.sparseexponent
-    ]]
-else
-  environment={
-    global=global or _G,
-    lpeg=lpeg,
-    type=type,
-    tostring=tostring,
-    tonumber=tonumber,
-    format=string.format,
-    concat=table.concat,
-    signed=number.signed,
-    points=number.points,
-    basepoints=number.basepoints,
-    utfchar=utf.char,
-    utfbyte=utf.byte,
-    lpegmatch=lpeg.match,
-    nspaces=string.nspaces,
-    tracedchar=string.tracedchar,
-    autosingle=string.autosingle,
-    autodouble=string.autodouble,
-    sequenced=table.sequenced,
-    formattednumber=number.formatted,
-    sparseexponent=number.sparseexponent,
-  }
-end
-local arguments={ "a1" } 
-setmetatable(arguments,{ __index=function(t,k)
-    local v=t[k-1]..",a"..k
-    t[k]=v
-    return v
-  end
-})
-local prefix_any=C((S("+- .")+R("09"))^0)
-local prefix_tab=P("{")*C((1-P("}"))^0)*P("}")+C((1-R("az","AZ","09","%%"))^0)
-local format_s=function(f)
-  n=n+1
-  if f and f~="" then
-    return format("format('%%%ss',a%s)",f,n)
-  else 
-    return format("(a%s or '')",n) 
-  end
-end
-local format_S=function(f) 
-  n=n+1
-  if f and f~="" then
-    return format("format('%%%ss',tostring(a%s))",f,n)
-  else
-    return format("tostring(a%s)",n)
-  end
-end
-local format_q=function()
-  n=n+1
-  return format("(a%s and format('%%q',a%s) or '')",n,n) 
-end
-local format_Q=function() 
-  n=n+1
-  return format("format('%%q',tostring(a%s))",n)
-end
-local format_i=function(f)
-  n=n+1
-  if f and f~="" then
-    return format("format('%%%si',a%s)",f,n)
-  else
-    return format("format('%%i',a%s)",n) 
-  end
-end
-local format_d=format_i
-local format_I=function(f)
-  n=n+1
-  return format("format('%%s%%%si',signed(a%s))",f,n)
-end
-local format_f=function(f)
-  n=n+1
-  return format("format('%%%sf',a%s)",f,n)
-end
-local format_F=function(f) 
-  n=n+1
-  if not f or f=="" then
-    return format("(((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or format((a%s %% 1 == 0) and '%%i' or '%%.9f',a%s))",n,n,n,n)
-  else
-    return format("format((a%s %% 1 == 0) and '%%i' or '%%%sf',a%s)",n,f,n)
-  end
-end
-local format_g=function(f)
-  n=n+1
-  return format("format('%%%sg',a%s)",f,n)
-end
-local format_G=function(f)
-  n=n+1
-  return format("format('%%%sG',a%s)",f,n)
-end
-local format_e=function(f)
-  n=n+1
-  return format("format('%%%se',a%s)",f,n)
-end
-local format_E=function(f)
-  n=n+1
-  return format("format('%%%sE',a%s)",f,n)
-end
-local format_j=function(f)
-  n=n+1
-  return format("sparseexponent('%%%se',a%s)",f,n)
-end
-local format_J=function(f)
-  n=n+1
-  return format("sparseexponent('%%%sE',a%s)",f,n)
-end
-local format_x=function(f)
-  n=n+1
-  return format("format('%%%sx',a%s)",f,n)
-end
-local format_X=function(f)
-  n=n+1
-  return format("format('%%%sX',a%s)",f,n)
-end
-local format_o=function(f)
-  n=n+1
-  return format("format('%%%so',a%s)",f,n)
-end
-local format_c=function()
-  n=n+1
-  return format("utfchar(a%s)",n)
-end
-local format_C=function()
-  n=n+1
-  return format("tracedchar(a%s)",n)
-end
-local format_r=function(f)
-  n=n+1
-  return format("format('%%%s.0f',a%s)",f,n)
-end
-local format_h=function(f)
-  n=n+1
-  if f=="-" then
-    f=sub(f,2)
-    return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
-  else
-    return format("format('0x%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
-  end
-end
-local format_H=function(f)
-  n=n+1
-  if f=="-" then
-    f=sub(f,2)
-    return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
-  else
-    return format("format('0x%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
-  end
-end
-local format_u=function(f)
-  n=n+1
-  if f=="-" then
-    f=sub(f,2)
-    return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
-  else
-    return format("format('u+%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
-  end
-end
-local format_U=function(f)
-  n=n+1
-  if f=="-" then
-    f=sub(f,2)
-    return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
-  else
-    return format("format('U+%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
-  end
-end
-local format_p=function()
-  n=n+1
-  return format("points(a%s)",n)
-end
-local format_b=function()
-  n=n+1
-  return format("basepoints(a%s)",n)
-end
-local format_t=function(f)
-  n=n+1
-  if f and f~="" then
-    return format("concat(a%s,%q)",n,f)
-  else
-    return format("concat(a%s)",n)
-  end
-end
-local format_T=function(f)
-  n=n+1
-  if f and f~="" then
-    return format("sequenced(a%s,%q)",n,f)
-  else
-    return format("sequenced(a%s)",n)
-  end
-end
-local format_l=function()
-  n=n+1
-  return format("(a%s and 'true' or 'false')",n)
-end
-local format_L=function()
-  n=n+1
-  return format("(a%s and 'TRUE' or 'FALSE')",n)
-end
-local format_N=function() 
-  n=n+1
-  return format("tostring(tonumber(a%s) or a%s)",n,n)
-end
-local format_a=function(f)
-  n=n+1
-  if f and f~="" then
-    return format("autosingle(a%s,%q)",n,f)
-  else
-    return format("autosingle(a%s)",n)
-  end
-end
-local format_A=function(f)
-  n=n+1
-  if f and f~="" then
-    return format("autodouble(a%s,%q)",n,f)
-  else
-    return format("autodouble(a%s)",n)
-  end
-end
-local format_w=function(f) 
-  n=n+1
-  f=tonumber(f)
-  if f then 
-    return format("nspaces[%s+a%s]",f,n) 
-  else
-    return format("nspaces[a%s]",n) 
-  end
-end
-local format_W=function(f) 
-  return format("nspaces[%s]",tonumber(f) or 0)
-end
-local digit=patterns.digit
-local period=patterns.period
-local three=digit*digit*digit
-local splitter=Cs (
-  (((1-(three^1*period))^1+C(three))*(Carg(1)*three)^1+C((1-period)^1))*(P(1)/""*Carg(2))*C(2)
-)
-patterns.formattednumber=splitter
-function number.formatted(n,sep1,sep2)
-  local s=type(s)=="string" and n or format("%0.2f",n)
-  if sep1==true then
-    return lpegmatch(splitter,s,1,".",",")
-  elseif sep1=="." then
-    return lpegmatch(splitter,s,1,sep1,sep2 or ",")
-  elseif sep1=="," then
-    return lpegmatch(splitter,s,1,sep1,sep2 or ".")
-  else
-    return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".")
-  end
-end
-local format_m=function(f)
-  n=n+1
-  if not f or f=="" then
-    f=","
-  end
-  return format([[formattednumber(a%s,%q,".")]],n,f)
-end
-local format_M=function(f)
-  n=n+1
-  if not f or f=="" then
-    f="."
-  end
-  return format([[formattednumber(a%s,%q,",")]],n,f)
-end
-local format_z=function(f)
-  n=n+(tonumber(f) or 1)
-  return "''" 
-end
-local format_rest=function(s)
-  return format("%q",s) 
-end
-local format_extension=function(extensions,f,name)
-  local extension=extensions[name] or "tostring(%s)"
-  local f=tonumber(f) or 1
-  if f==0 then
-    return extension
-  elseif f==1 then
-    n=n+1
-    local a="a"..n
-    return format(extension,a,a) 
-  elseif f<0 then
-    local a="a"..(n+f+1)
-    return format(extension,a,a)
-  else
-    local t={}
-    for i=1,f do
-      n=n+1
-      t[#t+1]="a"..n
-    end
-    return format(extension,unpack(t))
-  end
-end
-local builder=Cs { "start",
-  start=(
-    (
-      P("%")/""*(
-        V("!") 
-+V("s")+V("q")+V("i")+V("d")+V("f")+V("F")+V("g")+V("G")+V("e")+V("E")+V("x")+V("X")+V("o")
-+V("c")+V("C")+V("S") 
-+V("Q") 
-+V("N")
-+V("r")+V("h")+V("H")+V("u")+V("U")+V("p")+V("b")+V("t")+V("T")+V("l")+V("L")+V("I")+V("w") 
-+V("W") 
-+V("a") 
-+V("A") 
-+V("j")+V("J") 
-+V("m")+V("M") 
-+V("z")
-      )+V("*")
-    )*(P(-1)+Carg(1))
-  )^0,
-  ["s"]=(prefix_any*P("s"))/format_s,
-  ["q"]=(prefix_any*P("q"))/format_q,
-  ["i"]=(prefix_any*P("i"))/format_i,
-  ["d"]=(prefix_any*P("d"))/format_d,
-  ["f"]=(prefix_any*P("f"))/format_f,
-  ["F"]=(prefix_any*P("F"))/format_F,
-  ["g"]=(prefix_any*P("g"))/format_g,
-  ["G"]=(prefix_any*P("G"))/format_G,
-  ["e"]=(prefix_any*P("e"))/format_e,
-  ["E"]=(prefix_any*P("E"))/format_E,
-  ["x"]=(prefix_any*P("x"))/format_x,
-  ["X"]=(prefix_any*P("X"))/format_X,
-  ["o"]=(prefix_any*P("o"))/format_o,
-  ["S"]=(prefix_any*P("S"))/format_S,
-  ["Q"]=(prefix_any*P("Q"))/format_S,
-  ["N"]=(prefix_any*P("N"))/format_N,
-  ["c"]=(prefix_any*P("c"))/format_c,
-  ["C"]=(prefix_any*P("C"))/format_C,
-  ["r"]=(prefix_any*P("r"))/format_r,
-  ["h"]=(prefix_any*P("h"))/format_h,
-  ["H"]=(prefix_any*P("H"))/format_H,
-  ["u"]=(prefix_any*P("u"))/format_u,
-  ["U"]=(prefix_any*P("U"))/format_U,
-  ["p"]=(prefix_any*P("p"))/format_p,
-  ["b"]=(prefix_any*P("b"))/format_b,
-  ["t"]=(prefix_tab*P("t"))/format_t,
-  ["T"]=(prefix_tab*P("T"))/format_T,
-  ["l"]=(prefix_any*P("l"))/format_l,
-  ["L"]=(prefix_any*P("L"))/format_L,
-  ["I"]=(prefix_any*P("I"))/format_I,
-  ["w"]=(prefix_any*P("w"))/format_w,
-  ["W"]=(prefix_any*P("W"))/format_W,
-  ["j"]=(prefix_any*P("j"))/format_j,
-  ["J"]=(prefix_any*P("J"))/format_J,
-  ["m"]=(prefix_tab*P("m"))/format_m,
-  ["M"]=(prefix_tab*P("M"))/format_M,
-  ["z"]=(prefix_any*P("z"))/format_z,
-  ["a"]=(prefix_any*P("a"))/format_a,
-  ["A"]=(prefix_any*P("A"))/format_A,
-  ["*"]=Cs(((1-P("%"))^1+P("%%")/"%%")^1)/format_rest,
-  ["?"]=Cs(((1-P("%"))^1        )^1)/format_rest,
-  ["!"]=Carg(2)*prefix_any*P("!")*C((1-P("!"))^1)*P("!")/format_extension,
-}
-local direct=Cs (
-  P("%")*(S("+- .")+R("09"))^0*S("sqidfgGeExXo")*P(-1)/[[local format = string.format return function(str) return format("%0",str) end]]
-)
-local function make(t,str)
-  local f
-  local p
-  local p=lpegmatch(direct,str)
-  if p then
-    f=loadstripped(p)()
-  else
-    n=0
-    p=lpegmatch(builder,str,1,t._connector_,t._extensions_) 
-    if n>0 then
-      p=format(template,preamble,t._preamble_,arguments[n],p)
-      f=loadstripped(p,t._environment_)() 
-    else
-      f=function() return str end
-    end
-  end
-  t[str]=f
-  return f
-end
-local function use(t,fmt,...)
-  return t[fmt](...)
-end
-strings.formatters={}
-if _LUAVERSION<5.2 then
-  function strings.formatters.new(noconcat)
-    local t={ _type_="formatter",_connector_=noconcat and "," or "..",_extensions_={},_preamble_=preamble,_environment_={} }
-    setmetatable(t,{ __index=make,__call=use })
-    return t
-  end
-else
-  function strings.formatters.new(noconcat)
-    local e={} 
-    for k,v in next,environment do
-      e[k]=v
-    end
-    local t={ _type_="formatter",_connector_=noconcat and "," or "..",_extensions_={},_preamble_="",_environment_=e }
-    setmetatable(t,{ __index=make,__call=use })
-    return t
-  end
-end
-local formatters=strings.formatters.new() 
-string.formatters=formatters 
-string.formatter=function(str,...) return formatters[str](...) end 
-local function add(t,name,template,preamble)
-  if type(t)=="table" and t._type_=="formatter" then
-    t._extensions_[name]=template or "%s"
-    if type(preamble)=="string" then
-      t._preamble_=preamble.."\n"..t._preamble_ 
-    elseif type(preamble)=="table" then
-      for k,v in next,preamble do
-        t._environment_[k]=v
-      end
-    end
-  end
-end
-strings.formatters.add=add
-patterns.xmlescape=Cs((P("<")/"<"+P(">")/">"+P("&")/"&"+P('"')/"""+P(1))^0)
-patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+P(1))^0)
-patterns.luaescape=Cs(((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0) 
-patterns.luaquoted=Cs(Cc('"')*((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0*Cc('"'))
-if _LUAVERSION<5.2 then
-  add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],"local xmlescape = lpeg.patterns.xmlescape")
-  add(formatters,"tex",[[lpegmatch(texescape,%s)]],"local texescape = lpeg.patterns.texescape")
-  add(formatters,"lua",[[lpegmatch(luaescape,%s)]],"local luaescape = lpeg.patterns.luaescape")
-else
-  add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape=lpeg.patterns.xmlescape })
-  add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=lpeg.patterns.texescape })
-  add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=lpeg.patterns.luaescape })
-end
-local dquote=patterns.dquote 
-local equote=patterns.escaped+dquote/'\\"'+1
-local space=patterns.space
-local cquote=Cc('"')
-local pattern=Cs(dquote*(equote-P(-2))^0*dquote)          
-+Cs(cquote*(equote-space)^0*space*equote^0*cquote) 
-function string.optionalquoted(str)
-  return lpegmatch(pattern,str) or str
-end
-local pattern=Cs((newline/(os.newline or "\r")+1)^0)
-function string.replacenewlines(str)
-  return lpegmatch(pattern,str)
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['util-fil']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local byte=string.byte
-local extract=bit32.extract
-utilities=utilities or {}
-local files={}
-utilities.files=files
-local zerobased={}
-function files.open(filename,zb)
-  local f=io.open(filename,"rb")
-  if f then
-    zerobased[f]=zb or false
-  end
-  return f
-end
-function files.close(f)
-  zerobased[f]=nil
-  f:close()
-end
-function files.size(f)
-  return f:seek("end")
-end
-function files.setposition(f,n)
-  if zerobased[f] then
-    f:seek("set",n)
-  else
-    f:seek("set",n-1)
-  end
-end
-function files.getposition(f)
-  if zerobased[f] then
-    return f:seek()
-  else
-    return f:seek()+1
-  end
-end
-function files.look(f,n,chars)
-  local p=f:seek()
-  local s=f:read(n)
-  f:seek("set",p)
-  if chars then
-    return s
-  else
-    return byte(s,1,#s)
-  end
-end
-function files.skip(f,n)
-  if n==1 then
-    f:read(n)
-  else
-    f:seek("set",f:seek()+n)
-  end
-end
-function files.readbyte(f)
-  return byte(f:read(1))
-end
-function files.readbytes(f,n)
-  return byte(f:read(n),1,n)
-end
-function files.readchar(f)
-  return f:read(1)
-end
-function files.readstring(f,n)
-  return f:read(n or 1)
-end
-function files.readinteger1(f) 
-  local n=byte(f:read(1))
-  if n>=0x80 then
-    return n-0xFF-1
-  else
-    return n
-  end
-end
-files.readcardinal1=files.readbyte 
-files.readcardinal=files.readcardinal1
-files.readinteger=files.readinteger1
-function files.readcardinal2(f)
-  local a,b=byte(f:read(2),1,2)
-  return 0x100*a+b
-end
-function files.readinteger2(f)
-  local a,b=byte(f:read(2),1,2)
-  local n=0x100*a+b
-  if n>=0x8000 then
-    return n-0xFFFF-1
-  else
-    return n
-  end
-end
-function files.readcardinal3(f)
-  local a,b,c=byte(f:read(3),1,3)
-  return 0x10000*a+0x100*b+c
-end
-function files.readcardinal4(f)
-  local a,b,c,d=byte(f:read(4),1,4)
-  return 0x1000000*a+0x10000*b+0x100*c+d
-end
-function files.readinteger4(f)
-  local a,b,c,d=byte(f:read(4),1,4)
-  local n=0x1000000*a+0x10000*b+0x100*c+d
-  if n>=0x8000000 then
-    return n-0xFFFFFFFF-1
-  else
-    return n
-  end
-end
-function files.readfixed4(f)
-  local a,b,c,d=byte(f:read(4),1,4)
-  local n=0x100*a+b
-  if n>=0x8000 then
-    return n-0xFFFF-1+(0x100*c+d)/0xFFFF
-  else
-    return n+(0x100*c+d)/0xFFFF
-  end
-end
-function files.read2dot14(f)
-  local a,b=byte(f:read(2),1,2)
-  local n=0x100*a+b
-  local m=extract(n,0,30)
-  if n>0x7FFF then
-    n=extract(n,30,2)
-    return m/0x4000-4
-  else
-    n=extract(n,30,2)
-    return n+m/0x4000
-  end
-end
-function files.skipshort(f,n)
-  f:read(2*(n or 1))
-end
-function files.skiplong(f,n)
-  f:read(4*(n or 1))
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['util-tab']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-utilities=utilities or {}
-utilities.tables=utilities.tables or {}
-local tables=utilities.tables
-local format,gmatch,gsub,sub=string.format,string.gmatch,string.gsub,string.sub
-local concat,insert,remove,sort=table.concat,table.insert,table.remove,table.sort
-local setmetatable,getmetatable,tonumber,tostring=setmetatable,getmetatable,tonumber,tostring
-local type,next,rawset,tonumber,tostring,load,select=type,next,rawset,tonumber,tostring,load,select
-local lpegmatch,P,Cs,Cc=lpeg.match,lpeg.P,lpeg.Cs,lpeg.Cc
-local sortedkeys,sortedpairs=table.sortedkeys,table.sortedpairs
-local formatters=string.formatters
-local utftoeight=utf.toeight
-local splitter=lpeg.tsplitat(".")
-function utilities.tables.definetable(target,nofirst,nolast) 
-  local composed,t=nil,{}
-  local snippets=lpegmatch(splitter,target)
-  for i=1,#snippets-(nolast and 1 or 0) do
-    local name=snippets[i]
-    if composed then
-      composed=composed.."."..name
-        t[#t+1]=formatters["if not %s then %s = { } end"](composed,composed)
-    else
-      composed=name
-      if not nofirst then
-        t[#t+1]=formatters["%s = %s or { }"](composed,composed)
-      end
-    end
-  end
-  if composed then
-    if nolast then
-      composed=composed.."."..snippets[#snippets]
-    end
-    return concat(t,"\n"),composed 
-  else
-    return "",target
-  end
-end
-function tables.definedtable(...)
-  local t=_G
-  for i=1,select("#",...) do
-    local li=select(i,...)
-    local tl=t[li]
-    if not tl then
-      tl={}
-      t[li]=tl
-    end
-    t=tl
-  end
-  return t
-end
-function tables.accesstable(target,root)
-  local t=root or _G
-  for name in gmatch(target,"([^%.]+)") do
-    t=t[name]
-    if not t then
-      return
-    end
-  end
-  return t
-end
-function tables.migratetable(target,v,root)
-  local t=root or _G
-  local names=lpegmatch(splitter,target)
-  for i=1,#names-1 do
-    local name=names[i]
-    t[name]=t[name] or {}
-    t=t[name]
-    if not t then
-      return
-    end
-  end
-  t[names[#names]]=v
-end
-function tables.removevalue(t,value) 
-  if value then
-    for i=1,#t do
-      if t[i]==value then
-        remove(t,i)
-      end
-    end
-  end
-end
-function tables.replacevalue(t,oldvalue,newvalue)
-  if oldvalue and newvalue then
-    for i=1,#t do
-      if t[i]==oldvalue then
-        t[i]=newvalue
-      end
-    end
-  end
-end
-function tables.insertbeforevalue(t,value,extra)
-  for i=1,#t do
-    if t[i]==extra then
-      remove(t,i)
-    end
-  end
-  for i=1,#t do
-    if t[i]==value then
-      insert(t,i,extra)
-      return
-    end
-  end
-  insert(t,1,extra)
-end
-function tables.insertaftervalue(t,value,extra)
-  for i=1,#t do
-    if t[i]==extra then
-      remove(t,i)
-    end
-  end
-  for i=1,#t do
-    if t[i]==value then
-      insert(t,i+1,extra)
-      return
-    end
-  end
-  insert(t,#t+1,extra)
-end
-local escape=Cs(Cc('"')*((P('"')/'""'+P(1))^0)*Cc('"'))
-function table.tocsv(t,specification)
-  if t and #t>0 then
-    local result={}
-    local r={}
-    specification=specification or {}
-    local fields=specification.fields
-    if type(fields)~="string" then
-      fields=sortedkeys(t[1])
-    end
-    local separator=specification.separator or ","
-    if specification.preamble==true then
-      for f=1,#fields do
-        r[f]=lpegmatch(escape,tostring(fields[f]))
-      end
-      result[1]=concat(r,separator)
-    end
-    for i=1,#t do
-      local ti=t[i]
-      for f=1,#fields do
-        local field=ti[fields[f]]
-        if type(field)=="string" then
-          r[f]=lpegmatch(escape,field)
-        else
-          r[f]=tostring(field)
-        end
-      end
-      result[#result+1]=concat(r,separator)
-    end
-    return concat(result,"\n")
-  else
-    return ""
-  end
-end
-local nspaces=utilities.strings.newrepeater(" ")
-local function toxml(t,d,result,step)
-  for k,v in sortedpairs(t) do
-    local s=nspaces[d] 
-    local tk=type(k)
-    local tv=type(v)
-    if tv=="table" then
-      if tk=="number" then
-        result[#result+1]=formatters["%s<entry n='%s'>"](s,k)
-        toxml(v,d+step,result,step)
-        result[#result+1]=formatters["%s</entry>"](s,k)
-      else
-        result[#result+1]=formatters["%s<%s>"](s,k)
-        toxml(v,d+step,result,step)
-        result[#result+1]=formatters["%s</%s>"](s,k)
-      end
-    elseif tv=="string" then
-      if tk=="number" then
-        result[#result+1]=formatters["%s<entry n='%s'>%!xml!</entry>"](s,k,v,k)
-      else
-        result[#result+1]=formatters["%s<%s>%!xml!</%s>"](s,k,v,k)
-      end
-    elseif tk=="number" then
-      result[#result+1]=formatters["%s<entry n='%s'>%S</entry>"](s,k,v,k)
-    else
-      result[#result+1]=formatters["%s<%s>%S</%s>"](s,k,v,k)
-    end
-  end
-end
-function table.toxml(t,specification)
-  specification=specification or {}
-  local name=specification.name
-  local noroot=name==false
-  local result=(specification.nobanner or noroot) and {} or { "<?xml version='1.0' standalone='yes' ?>" }
-  local indent=specification.indent or 0
-  local spaces=specification.spaces or 1
-  if noroot then
-    toxml(t,indent,result,spaces)
-  else
-    toxml({ [name or "data"]=t },indent,result,spaces)
-  end
-  return concat(result,"\n")
-end
-function tables.encapsulate(core,capsule,protect)
-  if type(capsule)~="table" then
-    protect=true
-    capsule={}
-  end
-  for key,value in next,core do
-    if capsule[key] then
-      print(formatters["\ninvalid %s %a in %a"]("inheritance",key,core))
-      os.exit()
-    else
-      capsule[key]=value
-    end
-  end
-  if protect then
-    for key,value in next,core do
-      core[key]=nil
-    end
-    setmetatable(core,{
-      __index=capsule,
-      __newindex=function(t,key,value)
-        if capsule[key] then
-          print(formatters["\ninvalid %s %a' in %a"]("overload",key,core))
-          os.exit()
-        else
-          rawset(t,key,value)
-        end
-      end
-    } )
-  end
-end
-local f_hashed_string=formatters["[%q]=%q,"]
-local f_hashed_number=formatters["[%q]=%s,"]
-local f_hashed_boolean=formatters["[%q]=%l,"]
-local f_hashed_table=formatters["[%q]="]
-local f_indexed_string=formatters["[%s]=%q,"]
-local f_indexed_number=formatters["[%s]=%s,"]
-local f_indexed_boolean=formatters["[%s]=%l,"]
-local f_indexed_table=formatters["[%s]="]
-local f_ordered_string=formatters["%q,"]
-local f_ordered_number=formatters["%s,"]
-local f_ordered_boolean=formatters["%l,"]
-function table.fastserialize(t,prefix)
-  local r={ type(prefix)=="string" and prefix or "return" }
-  local m=1
-  local function fastserialize(t,outer) 
-    local n=#t
-    m=m+1
-    r[m]="{"
-    if n>0 then
-      for i=0,n do
-        local v=t[i]
-        local tv=type(v)
-        if tv=="string" then
-          m=m+1 r[m]=f_ordered_string(v)
-        elseif tv=="number" then
-          m=m+1 r[m]=f_ordered_number(v)
-        elseif tv=="table" then
-          fastserialize(v)
-        elseif tv=="boolean" then
-          m=m+1 r[m]=f_ordered_boolean(v)
-        end
-      end
-    end
-    for k,v in next,t do
-      local tk=type(k)
-      if tk=="number" then
-        if k>n or k<0 then
-          local tv=type(v)
-          if tv=="string" then
-            m=m+1 r[m]=f_indexed_string(k,v)
-          elseif tv=="number" then
-            m=m+1 r[m]=f_indexed_number(k,v)
-          elseif tv=="table" then
-            m=m+1 r[m]=f_indexed_table(k)
-            fastserialize(v)
-          elseif tv=="boolean" then
-            m=m+1 r[m]=f_indexed_boolean(k,v)
-          end
-        end
-      else
-        local tv=type(v)
-        if tv=="string" then
-          m=m+1 r[m]=f_hashed_string(k,v)
-        elseif tv=="number" then
-          m=m+1 r[m]=f_hashed_number(k,v)
-        elseif tv=="table" then
-          m=m+1 r[m]=f_hashed_table(k)
-          fastserialize(v)
-        elseif tv=="boolean" then
-          m=m+1 r[m]=f_hashed_boolean(k,v)
-        end
-      end
-    end
-    m=m+1
-    if outer then
-      r[m]="}"
-    else
-      r[m]="},"
-    end
-    return r
-  end
-  return concat(fastserialize(t,true))
-end
-function table.deserialize(str)
-  if not str or str=="" then
-    return
-  end
-  local code=load(str)
-  if not code then
-    return
-  end
-  code=code()
-  if not code then
-    return
-  end
-  return code
-end
-function table.load(filename,loader)
-  if filename then
-    local t=(loader or io.loaddata)(filename)
-    if t and t~="" then
-      local t=utftoeight(t)
-      t=load(t)
-      if type(t)=="function" then
-        t=t()
-        if type(t)=="table" then
-          return t
-        end
-      end
-    end
-  end
-end
-function table.save(filename,t,n,...)
-  io.savedata(filename,table.serialize(t,n==nil and true or n,...)) 
-end
-local f_key_value=formatters["%s=%q"]
-local f_add_table=formatters[" {%t},\n"]
-local f_return_table=formatters["return {\n%t}"]
-local function slowdrop(t) 
-  local r={}
-  local l={}
-  for i=1,#t do
-    local ti=t[i]
-    local j=0
-    for k,v in next,ti do
-      j=j+1
-      l[j]=f_key_value(k,v)
-    end
-    r[i]=f_add_table(l)
-  end
-  return f_return_table(r)
-end
-local function fastdrop(t)
-  local r={ "return {\n" }
-  local m=1
-  for i=1,#t do
-    local ti=t[i]
-    m=m+1 r[m]=" {"
-    for k,v in next,ti do
-      m=m+1 r[m]=f_key_value(k,v)
-    end
-    m=m+1 r[m]="},\n"
-  end
-  m=m+1
-  r[m]="}"
-  return concat(r)
-end
-function table.drop(t,slow) 
-  if #t==0 then
-    return "return { }"
-  elseif slow==true then
-    return slowdrop(t) 
-  else
-    return fastdrop(t) 
-  end
-end
-function table.autokey(t,k)
-  local v={}
-  t[k]=v
-  return v
-end
-local selfmapper={ __index=function(t,k) t[k]=k return k end }
-function table.twowaymapper(t)
-  if not t then
-    t={}
-  else
-    for i=0,#t do
-      local ti=t[i]    
-      if ti then
-        local i=tostring(i)
-        t[i]=ti   
-        t[ti]=i    
-      end
-    end
-    t[""]=t[0] or ""
-  end
-  setmetatable(t,selfmapper)
-  return t
-end
-local f_start_key_idx=formatters["%w{"]
-local f_start_key_num=formatters["%w[%s]={"]
-local f_start_key_str=formatters["%w[%q]={"]
-local f_start_key_boo=formatters["%w[%l]={"]
-local f_start_key_nop=formatters["%w{"]
-local f_stop=formatters["%w},"]
-local f_key_num_value_num=formatters["%w[%s]=%s,"]
-local f_key_str_value_num=formatters["%w[%q]=%s,"]
-local f_key_boo_value_num=formatters["%w[%l]=%s,"]
-local f_key_num_value_str=formatters["%w[%s]=%q,"]
-local f_key_str_value_str=formatters["%w[%q]=%q,"]
-local f_key_boo_value_str=formatters["%w[%l]=%q,"]
-local f_key_num_value_boo=formatters["%w[%s]=%l,"]
-local f_key_str_value_boo=formatters["%w[%q]=%l,"]
-local f_key_boo_value_boo=formatters["%w[%l]=%l,"]
-local f_key_num_value_not=formatters["%w[%s]={},"]
-local f_key_str_value_not=formatters["%w[%q]={},"]
-local f_key_boo_value_not=formatters["%w[%l]={},"]
-local f_key_num_value_seq=formatters["%w[%s]={ %, t },"]
-local f_key_str_value_seq=formatters["%w[%q]={ %, t },"]
-local f_key_boo_value_seq=formatters["%w[%l]={ %, t },"]
-local f_val_num=formatters["%w%s,"]
-local f_val_str=formatters["%w%q,"]
-local f_val_boo=formatters["%w%l,"]
-local f_val_not=formatters["%w{},"]
-local f_val_seq=formatters["%w{ %, t },"]
-local f_fin_seq=formatters[" %, t }"]
-local f_table_return=formatters["return {"]
-local f_table_name=formatters["%s={"]
-local f_table_direct=formatters["{"]
-local f_table_entry=formatters["[%q]={"]
-local f_table_finish=formatters["}"]
-local spaces=utilities.strings.newrepeater(" ")
-local original_serialize=table.serialize
-local function serialize(root,name,specification)
-  if type(specification)=="table" then
-    return original_serialize(root,name,specification) 
-  end
-  local t  
-  local n=1
-  local unknown=false
-  local function simple_table(t)
-    local nt=#t
-    if nt>0 then
-      local n=0
-      for _,v in next,t do
-        n=n+1
-        if type(v)=="table" then
-          return nil
-        end
-      end
-      local haszero=t[0]
-      if n==nt then
-        local tt={}
-        for i=1,nt do
-          local v=t[i]
-          local tv=type(v)
-          if tv=="number" then
-            tt[i]=v 
-          elseif tv=="string" then
-            tt[i]=format("%q",v) 
-          elseif tv=="boolean" then
-            tt[i]=v and "true" or "false"
-          else
-            return nil
-          end
-        end
-        return tt
-      elseif haszero and (n==nt+1) then
-        local tt={}
-        for i=0,nt do
-          local v=t[i]
-          local tv=type(v)
-          if tv=="number" then
-            tt[i+1]=v 
-          elseif tv=="string" then
-            tt[i+1]=format("%q",v) 
-          elseif tv=="boolean" then
-            tt[i+1]=v and "true" or "false"
-          else
-            return nil
-          end
-        end
-        tt[1]="[0] = "..tt[1]
-        return tt
-      end
-    end
-    return nil
-  end
-  local function do_serialize(root,name,depth,level,indexed)
-    if level>0 then
-      n=n+1
-      if indexed then
-        t[n]=f_start_key_idx(depth)
-      else
-        local tn=type(name)
-        if tn=="number" then
-          t[n]=f_start_key_num(depth,name)
-        elseif tn=="string" then
-          t[n]=f_start_key_str(depth,name)
-        elseif tn=="boolean" then
-          t[n]=f_start_key_boo(depth,name)
-        else
-          t[n]=f_start_key_nop(depth)
-        end
-      end
-      depth=depth+1
-    end
-    if root and next(root)~=nil then
-      local first=nil
-      local last=0
-      last=#root
-      for k=1,last do
-        if root[k]==nil then
-          last=k-1
-          break
-        end
-      end
-      if last>0 then
-        first=1
-      end
-      local sk=sortedkeys(root) 
-      for i=1,#sk do
-        local k=sk[i]
-        local v=root[k]
-        local tv=type(v)
-        local tk=type(k)
-        if first and tk=="number" and k<=last and k>=first then
-          if tv=="number" then
-            n=n+1 t[n]=f_val_num(depth,v)
-          elseif tv=="string" then
-            n=n+1 t[n]=f_val_str(depth,v)
-          elseif tv=="table" then
-            if next(v)==nil then 
-              n=n+1 t[n]=f_val_not(depth)
-            else
-              local st=simple_table(v)
-              if st then
-                n=n+1 t[n]=f_val_seq(depth,st)
-              else
-                do_serialize(v,k,depth,level+1,true)
-              end
-            end
-          elseif tv=="boolean" then
-            n=n+1 t[n]=f_val_boo(depth,v)
-          elseif unknown then
-            n=n+1 t[n]=f_val_str(depth,tostring(v))
-          end
-        elseif tv=="number" then
-          if tk=="number" then
-            n=n+1 t[n]=f_key_num_value_num(depth,k,v)
-          elseif tk=="string" then
-            n=n+1 t[n]=f_key_str_value_num(depth,k,v)
-          elseif tk=="boolean" then
-            n=n+1 t[n]=f_key_boo_value_num(depth,k,v)
-          elseif unknown then
-            n=n+1 t[n]=f_key_str_value_num(depth,tostring(k),v)
-          end
-        elseif tv=="string" then
-          if tk=="number" then
-            n=n+1 t[n]=f_key_num_value_str(depth,k,v)
-          elseif tk=="string" then
-            n=n+1 t[n]=f_key_str_value_str(depth,k,v)
-          elseif tk=="boolean" then
-            n=n+1 t[n]=f_key_boo_value_str(depth,k,v)
-          elseif unknown then
-            n=n+1 t[n]=f_key_str_value_str(depth,tostring(k),v)
-          end
-        elseif tv=="table" then
-          if next(v)==nil then
-            if tk=="number" then
-              n=n+1 t[n]=f_key_num_value_not(depth,k)
-            elseif tk=="string" then
-              n=n+1 t[n]=f_key_str_value_not(depth,k)
-            elseif tk=="boolean" then
-              n=n+1 t[n]=f_key_boo_value_not(depth,k)
-            elseif unknown then
-              n=n+1 t[n]=f_key_str_value_not(depth,tostring(k))
-            end
-          else
-            local st=simple_table(v)
-            if not st then
-              do_serialize(v,k,depth,level+1)
-            elseif tk=="number" then
-              n=n+1 t[n]=f_key_num_value_seq(depth,k,st)
-            elseif tk=="string" then
-              n=n+1 t[n]=f_key_str_value_seq(depth,k,st)
-            elseif tk=="boolean" then
-              n=n+1 t[n]=f_key_boo_value_seq(depth,k,st)
-            elseif unknown then
-              n=n+1 t[n]=f_key_str_value_seq(depth,tostring(k),st)
-            end
-          end
-        elseif tv=="boolean" then
-          if tk=="number" then
-            n=n+1 t[n]=f_key_num_value_boo(depth,k,v)
-          elseif tk=="string" then
-            n=n+1 t[n]=f_key_str_value_boo(depth,k,v)
-          elseif tk=="boolean" then
-            n=n+1 t[n]=f_key_boo_value_boo(depth,k,v)
-          elseif unknown then
-            n=n+1 t[n]=f_key_str_value_boo(depth,tostring(k),v)
-          end
-        else
-          if tk=="number" then
-            n=n+1 t[n]=f_key_num_value_str(depth,k,tostring(v))
-          elseif tk=="string" then
-            n=n+1 t[n]=f_key_str_value_str(depth,k,tostring(v))
-          elseif tk=="boolean" then
-            n=n+1 t[n]=f_key_boo_value_str(depth,k,tostring(v))
-          elseif unknown then
-            n=n+1 t[n]=f_key_str_value_str(depth,tostring(k),tostring(v))
-          end
-        end
-      end
-    end
-    if level>0 then
-      n=n+1 t[n]=f_stop(depth-1)
-    end
-  end
-  local tname=type(name)
-  if tname=="string" then
-    if name=="return" then
-      t={ f_table_return() }
-    else
-      t={ f_table_name(name) }
-    end
-  elseif tname=="number" then
-    t={ f_table_entry(name) }
-  elseif tname=="boolean" then
-    if name then
-      t={ f_table_return() }
-    else
-      t={ f_table_direct() }
-    end
-  else
-    t={ f_table_name("t") }
-  end
-  if root then
-    if getmetatable(root) then 
-      local dummy=root._w_h_a_t_e_v_e_r_
-      root._w_h_a_t_e_v_e_r_=nil
-    end
-    if next(root)~=nil then
-      local st=simple_table(root)
-      if st then
-        return t[1]..f_fin_seq(st) 
-      else
-        do_serialize(root,name,1,0)
-      end
-    end
-  end
-  n=n+1
-  t[n]=f_table_finish()
-  return concat(t,"\n")
-end
-table.serialize=serialize
-if setinspector then
-  setinspector("table",function(v) if type(v)=="table" then print(serialize(v,"table",{})) return true end end)
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['util-sto']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local setmetatable,getmetatable,type=setmetatable,getmetatable,type
-utilities=utilities or {}
-utilities.storage=utilities.storage or {}
-local storage=utilities.storage
-function storage.mark(t)
-  if not t then
-    print("\nfatal error: storage cannot be marked\n")
-    os.exit()
-    return
-  end
-  local m=getmetatable(t)
-  if not m then
-    m={}
-    setmetatable(t,m)
-  end
-  m.__storage__=true
-  return t
-end
-function storage.allocate(t)
-  t=t or {}
-  local m=getmetatable(t)
-  if not m then
-    m={}
-    setmetatable(t,m)
-  end
-  m.__storage__=true
-  return t
-end
-function storage.marked(t)
-  local m=getmetatable(t)
-  return m and m.__storage__
-end
-function storage.checked(t)
-  if not t then
-    report("\nfatal error: storage has not been allocated\n")
-    os.exit()
-    return
-  end
-  return t
-end
-function storage.setinitializer(data,initialize)
-  local m=getmetatable(data) or {}
-  m.__index=function(data,k)
-    m.__index=nil 
-    initialize()
-    return data[k]
-  end
-  setmetatable(data,m)
-end
-local keyisvalue={ __index=function(t,k)
-  t[k]=k
-  return k
-end }
-function storage.sparse(t)
-  t=t or {}
-  setmetatable(t,keyisvalue)
-  return t
-end
-local function f_empty ()              return "" end 
-local function f_self (t,k) t[k]=k        return k end
-local function f_table (t,k) local v={} t[k]=v return v end
-local function f_number(t,k) t[k]=0        return 0 end 
-local function f_ignore()                   end 
-local f_index={
-  ["empty"]=f_empty,
-  ["self"]=f_self,
-  ["table"]=f_table,
-  ["number"]=f_number,
-}
-function table.setmetatableindex(t,f)
-  if type(t)~="table" then
-    f,t=t,{}
-  end
-  local m=getmetatable(t)
-  local i=f_index[f] or f
-  if m then
-    m.__index=i
-  else
-    setmetatable(t,{ __index=i })
-  end
-  return t
-end
-local f_index={
-  ["ignore"]=f_ignore,
-}
-function table.setmetatablenewindex(t,f)
-  if type(t)~="table" then
-    f,t=t,{}
-  end
-  local m=getmetatable(t)
-  local i=f_index[f] or f
-  if m then
-    m.__newindex=i
-  else
-    setmetatable(t,{ __newindex=i })
-  end
-  return t
-end
-function table.setmetatablecall(t,f)
-  if type(t)~="table" then
-    f,t=t,{}
-  end
-  local m=getmetatable(t)
-  if m then
-    m.__call=f
-  else
-    setmetatable(t,{ __call=f })
-  end
-  return t
-end
-function table.setmetatablekey(t,key,value)
-  local m=getmetatable(t)
-  if not m then
-    m={}
-    setmetatable(t,m)
-  end
-  m[key]=value
-  return t
-end
-function table.getmetatablekey(t,key,value)
-  local m=getmetatable(t)
-  return m and m[key]
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['util-prs']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local lpeg,table,string=lpeg,table,string
-local P,R,V,S,C,Ct,Cs,Carg,Cc,Cg,Cf,Cp=lpeg.P,lpeg.R,lpeg.V,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cs,lpeg.Carg,lpeg.Cc,lpeg.Cg,lpeg.Cf,lpeg.Cp
-local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns
-local concat,gmatch,find=table.concat,string.gmatch,string.find
-local tostring,type,next,rawset=tostring,type,next,rawset
-local mod,div=math.mod,math.div
-utilities=utilities or {}
-local parsers=utilities.parsers or {}
-utilities.parsers=parsers
-local patterns=parsers.patterns or {}
-parsers.patterns=patterns
-local setmetatableindex=table.setmetatableindex
-local sortedhash=table.sortedhash
-local sortedkeys=table.sortedkeys
-local tohash=table.tohash
-local hashes={}
-utilities.parsers.hashes=hashes
-local digit=R("09")
-local space=P(' ')
-local equal=P("=")
-local comma=P(",")
-local lbrace=P("{")
-local rbrace=P("}")
-local lparent=P("(")
-local rparent=P(")")
-local period=S(".")
-local punctuation=S(".,:;")
-local spacer=lpegpatterns.spacer
-local whitespace=lpegpatterns.whitespace
-local newline=lpegpatterns.newline
-local anything=lpegpatterns.anything
-local endofstring=lpegpatterns.endofstring
-local nobrace=1-(lbrace+rbrace )
-local noparent=1-(lparent+rparent)
-local escape,left,right=P("\\"),P('{'),P('}')
-lpegpatterns.balanced=P {
-  [1]=((escape*(left+right))+(1-(left+right))+V(2))^0,
-  [2]=left*V(1)*right
-}
-local nestedbraces=P { lbrace*(nobrace+V(1))^0*rbrace }
-local nestedparents=P { lparent*(noparent+V(1))^0*rparent }
-local spaces=space^0
-local argument=Cs((lbrace/"")*((nobrace+nestedbraces)^0)*(rbrace/""))
-local content=(1-endofstring)^0
-lpegpatterns.nestedbraces=nestedbraces 
-lpegpatterns.nestedparents=nestedparents 
-lpegpatterns.nested=nestedbraces 
-lpegpatterns.argument=argument   
-lpegpatterns.content=content    
-local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+(1-comma))^0)
-local key=C((1-equal-comma)^1)
-local pattern_a=(space+comma)^0*(key*equal*value+key*C(""))
-local pattern_c=(space+comma)^0*(key*equal*value)
-local key=C((1-space-equal-comma)^1)
-local pattern_b=spaces*comma^0*spaces*(key*((spaces*equal*spaces*value)+C("")))
-local hash={}
-local function set(key,value)
-  hash[key]=value
-end
-local pattern_a_s=(pattern_a/set)^1
-local pattern_b_s=(pattern_b/set)^1
-local pattern_c_s=(pattern_c/set)^1
-patterns.settings_to_hash_a=pattern_a_s
-patterns.settings_to_hash_b=pattern_b_s
-patterns.settings_to_hash_c=pattern_c_s
-function parsers.make_settings_to_hash_pattern(set,how)
-  if how=="strict" then
-    return (pattern_c/set)^1
-  elseif how=="tolerant" then
-    return (pattern_b/set)^1
-  else
-    return (pattern_a/set)^1
-  end
-end
-function parsers.settings_to_hash(str,existing)
-  if not str or str=="" then
-    return {}
-  elseif type(str)=="table" then
-    if existing then
-      for k,v in next,str do
-        existing[k]=v
-      end
-      return exiting
-    else
-      return str
-    end
-  else
-    hash=existing or {}
-    lpegmatch(pattern_a_s,str)
-    return hash
-  end
-end
-function parsers.settings_to_hash_tolerant(str,existing)
-  if not str or str=="" then
-    return {}
-  elseif type(str)=="table" then
-    if existing then
-      for k,v in next,str do
-        existing[k]=v
-      end
-      return exiting
-    else
-      return str
-    end
-  else
-    hash=existing or {}
-    lpegmatch(pattern_b_s,str)
-    return hash
-  end
-end
-function parsers.settings_to_hash_strict(str,existing)
-  if not str or str=="" then
-    return nil
-  elseif type(str)=="table" then
-    if existing then
-      for k,v in next,str do
-        existing[k]=v
-      end
-      return exiting
-    else
-      return str
-    end
-  elseif str and str~="" then
-    hash=existing or {}
-    lpegmatch(pattern_c_s,str)
-    return next(hash) and hash
-  end
-end
-local separator=comma*space^0
-local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+(1-comma))^0)
-local pattern=spaces*Ct(value*(separator*value)^0)
-patterns.settings_to_array=pattern
-function parsers.settings_to_array(str,strict)
-  if not str or str=="" then
-    return {}
-  elseif type(str)=="table" then
-    return str
-  elseif strict then
-    if find(str,"{",1,true) then
-      return lpegmatch(pattern,str)
-    else
-      return { str }
-    end
-  elseif find(str,",",1,true) then
-    return lpegmatch(pattern,str)
-  else
-    return { str }
-  end
-end
-local cache_a={}
-local cache_b={}
-function parsers.groupedsplitat(symbol,withaction)
-  if not symbol then
-    symbol=","
-  end
-  local pattern=(withaction and cache_b or cache_a)[symbol]
-  if not pattern then
-    local symbols=S(symbol)
-    local separator=space^0*symbols*space^0
-    local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0)
-    if withaction then
-      local withvalue=Carg(1)*value/function(f,s) return f(s) end
-      pattern=spaces*withvalue*(separator*withvalue)^0
-      cache_b[symbol]=pattern
-    else
-      pattern=spaces*Ct(value*(separator*value)^0)
-      cache_a[symbol]=pattern
-    end
-  end
-  return pattern
-end
-local pattern_a=parsers.groupedsplitat(",",false)
-local pattern_b=parsers.groupedsplitat(",",true)
-function parsers.stripped_settings_to_array(str)
-  if not str or str=="" then
-    return {}
-  else
-    return lpegmatch(pattern_a,str)
-  end
-end
-function parsers.process_stripped_settings(str,action)
-  if not str or str=="" then
-    return {}
-  else
-    return lpegmatch(pattern_b,str,1,action)
-  end
-end
-local function set(t,v)
-  t[#t+1]=v
-end
-local value=P(Carg(1)*value)/set
-local pattern=value*(separator*value)^0*Carg(1)
-function parsers.add_settings_to_array(t,str)
-  return lpegmatch(pattern,str,nil,t)
-end
-function parsers.hash_to_string(h,separator,yes,no,strict,omit)
-  if h then
-    local t,tn,s={},0,sortedkeys(h)
-    omit=omit and tohash(omit)
-    for i=1,#s do
-      local key=s[i]
-      if not omit or not omit[key] then
-        local value=h[key]
-        if type(value)=="boolean" then
-          if yes and no then
-            if value then
-              tn=tn+1
-              t[tn]=key..'='..yes
-            elseif not strict then
-              tn=tn+1
-              t[tn]=key..'='..no
-            end
-          elseif value or not strict then
-            tn=tn+1
-            t[tn]=key..'='..tostring(value)
-          end
-        else
-          tn=tn+1
-          t[tn]=key..'='..value
-        end
-      end
-    end
-    return concat(t,separator or ",")
-  else
-    return ""
-  end
-end
-function parsers.array_to_string(a,separator)
-  if a then
-    return concat(a,separator or ",")
-  else
-    return ""
-  end
-end
-local pattern=Cf(Ct("")*Cg(C((1-S(", "))^1)*S(", ")^0*Cc(true))^1,rawset)
-function utilities.parsers.settings_to_set(str)
-  return str and lpegmatch(pattern,str) or {}
-end
-hashes.settings_to_set=table.setmetatableindex(function(t,k) 
-  local v=k and lpegmatch(pattern,k) or {}
-  t[k]=v
-  return v
-end)
-getmetatable(hashes.settings_to_set).__mode="kv" 
-function parsers.simple_hash_to_string(h,separator)
-  local t,tn={},0
-  for k,v in sortedhash(h) do
-    if v then
-      tn=tn+1
-      t[tn]=k
-    end
-  end
-  return concat(t,separator or ",")
-end
-local str=Cs(lpegpatterns.unquoted)+C((1-whitespace-equal)^1)
-local setting=Cf(Carg(1)*(whitespace^0*Cg(str*whitespace^0*(equal*whitespace^0*str+Cc(""))))^1,rawset)
-local splitter=setting^1
-function utilities.parsers.options_to_hash(str,target)
-  return str and lpegmatch(splitter,str,1,target or {}) or {}
-end
-local splitter=lpeg.tsplitat(" ")
-function utilities.parsers.options_to_array(str)
-  return str and lpegmatch(splitter,str) or {}
-end
-local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C(digit^1*lparent*(noparent+nestedparents)^1*rparent)+C((nestedbraces+(1-comma))^1)
-local pattern_a=spaces*Ct(value*(separator*value)^0)
-local function repeater(n,str)
-  if not n then
-    return str
-  else
-    local s=lpegmatch(pattern_a,str)
-    if n==1 then
-      return unpack(s)
-    else
-      local t,tn={},0
-      for i=1,n do
-        for j=1,#s do
-          tn=tn+1
-          t[tn]=s[j]
-        end
-      end
-      return unpack(t)
-    end
-  end
-end
-local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+(C(digit^1)/tonumber*lparent*Cs((noparent+nestedparents)^1)*rparent)/repeater+C((nestedbraces+(1-comma))^1)
-local pattern_b=spaces*Ct(value*(separator*value)^0)
-function parsers.settings_to_array_with_repeat(str,expand) 
-  if expand then
-    return lpegmatch(pattern_b,str) or {}
-  else
-    return lpegmatch(pattern_a,str) or {}
-  end
-end
-local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace
-local pattern=Ct((space+value)^0)
-function parsers.arguments_to_table(str)
-  return lpegmatch(pattern,str)
-end
-function parsers.getparameters(self,class,parentclass,settings)
-  local sc=self[class]
-  if not sc then
-    sc={}
-    self[class]=sc
-    if parentclass then
-      local sp=self[parentclass]
-      if not sp then
-        sp={}
-        self[parentclass]=sp
-      end
-      setmetatableindex(sc,sp)
-    end
-  end
-  parsers.settings_to_hash(settings,sc)
-end
-function parsers.listitem(str)
-  return gmatch(str,"[^, ]+")
-end
-local pattern=Cs { "start",
-  start=V("one")+V("two")+V("three"),
-  rest=(Cc(",")*V("thousand"))^0*(P(".")+endofstring)*anything^0,
-  thousand=digit*digit*digit,
-  one=digit*V("rest"),
-  two=digit*digit*V("rest"),
-  three=V("thousand")*V("rest"),
-}
-lpegpatterns.splitthousands=pattern 
-function parsers.splitthousands(str)
-  return lpegmatch(pattern,str) or str
-end
-local optionalwhitespace=whitespace^0
-lpegpatterns.words=Ct((Cs((1-punctuation-whitespace)^1)+anything)^1)
-lpegpatterns.sentences=Ct((optionalwhitespace*Cs((1-period)^0*period))^1)
-lpegpatterns.paragraphs=Ct((optionalwhitespace*Cs((whitespace^1*endofstring/""+1-(spacer^0*newline*newline))^1))^1)
-local dquote=P('"')
-local equal=P('=')
-local escape=P('\\')
-local separator=S(' ,')
-local key=C((1-equal)^1)
-local value=dquote*C((1-dquote-escape*dquote)^0)*dquote
-local pattern=Cf(Ct("")*(Cg(key*equal*value)*separator^0)^1,rawset)^0*P(-1)
-function parsers.keq_to_hash(str)
-  if str and str~="" then
-    return lpegmatch(pattern,str)
-  else
-    return {}
-  end
-end
-local defaultspecification={ separator=",",quote='"' }
-function parsers.csvsplitter(specification)
-  specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification
-  local separator=specification.separator
-  local quotechar=specification.quote
-  local separator=S(separator~="" and separator or ",")
-  local whatever=C((1-separator-newline)^0)
-  if quotechar and quotechar~="" then
-    local quotedata=nil
-    for chr in gmatch(quotechar,".") do
-      local quotechar=P(chr)
-      local quoteword=quotechar*C((1-quotechar)^0)*quotechar
-      if quotedata then
-        quotedata=quotedata+quoteword
-      else
-        quotedata=quoteword
-      end
-    end
-    whatever=quotedata+whatever
-  end
-  local parser=Ct((Ct(whatever*(separator*whatever)^0)*S("\n\r")^1)^0 )
-  return function(data)
-    return lpegmatch(parser,data)
-  end
-end
-function parsers.rfc4180splitter(specification)
-  specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification
-  local separator=specification.separator 
-  local quotechar=P(specification.quote) 
-  local dquotechar=quotechar*quotechar  
-/specification.quote
-  local separator=S(separator~="" and separator or ",")
-  local escaped=quotechar*Cs((dquotechar+(1-quotechar))^0)*quotechar
-  local non_escaped=C((1-quotechar-newline-separator)^1)
-  local field=escaped+non_escaped+Cc("")
-  local record=Ct(field*(separator*field)^1)
-  local headerline=record*Cp()
-  local wholeblob=Ct((newline^(specification.strict and -1 or 1)*record)^0)
-  return function(data,getheader)
-    if getheader then
-      local header,position=lpegmatch(headerline,data)
-      local data=lpegmatch(wholeblob,data,position)
-      return data,header
-    else
-      return lpegmatch(wholeblob,data)
-    end
-  end
-end
-local function ranger(first,last,n,action)
-  if not first then
-  elseif last==true then
-    for i=first,n or first do
-      action(i)
-    end
-  elseif last then
-    for i=first,last do
-      action(i)
-    end
-  else
-    action(first)
-  end
-end
-local cardinal=lpegpatterns.cardinal/tonumber
-local spacers=lpegpatterns.spacer^0
-local endofstring=lpegpatterns.endofstring
-local stepper=spacers*(C(cardinal)*(spacers*S(":-")*spacers*(C(cardinal)+Cc(true) )+Cc(false) )*Carg(1)*Carg(2)/ranger*S(", ")^0 )^1
-local stepper=spacers*(C(cardinal)*(spacers*S(":-")*spacers*(C(cardinal)+(P("*")+endofstring)*Cc(true) )+Cc(false) )*Carg(1)*Carg(2)/ranger*S(", ")^0 )^1*endofstring 
-function parsers.stepper(str,n,action)
-  if type(n)=="function" then
-    lpegmatch(stepper,str,1,false,n or print)
-  else
-    lpegmatch(stepper,str,1,n,action or print)
-  end
-end
-local pattern_math=Cs((P("%")/"\\percent "+P("^")*Cc("{")*lpegpatterns.integer*Cc("}")+anything)^0)
-local pattern_text=Cs((P("%")/"\\percent "+(P("^")/"\\high")*Cc("{")*lpegpatterns.integer*Cc("}")+anything)^0)
-patterns.unittotex=pattern
-function parsers.unittotex(str,textmode)
-  return lpegmatch(textmode and pattern_text or pattern_math,str)
-end
-local pattern=Cs((P("^")/"<sup>"*lpegpatterns.integer*Cc("</sup>")+anything)^0)
-function parsers.unittoxml(str)
-  return lpegmatch(pattern,str)
-end
-local cache={}
-local spaces=lpegpatterns.space^0
-local dummy=function() end
-setmetatableindex(cache,function(t,k)
-  local separator=P(k)
-  local value=(1-separator)^0
-  local pattern=spaces*C(value)*separator^0*Cp()
-  t[k]=pattern
-  return pattern
-end)
-local commalistiterator=cache[","]
-function utilities.parsers.iterator(str,separator)
-  local n=#str
-  if n==0 then
-    return dummy
-  else
-    local pattern=separator and cache[separator] or commalistiterator
-    local p=1
-    return function()
-      if p<=n then
-        local s,e=lpegmatch(pattern,str,p)
-        if e then
-          p=e
-          return s
-        end
-      end
-    end
-  end
-end
-local function initialize(t,name)
-  local source=t[name]
-  if source then
-    local result={}
-    for k,v in next,t[name] do
-      result[k]=v
-    end
-    return result
-  else
-    return {}
-  end
-end
-local function fetch(t,name)
-  return t[name] or {}
-end
-local function process(result,more)
-  for k,v in next,more do
-    result[k]=v
-  end
-  return result
-end
-local name=C((1-S(", "))^1)
-local parser=(Carg(1)*name/initialize)*(S(", ")^1*(Carg(1)*name/fetch))^0
-local merge=Cf(parser,process)
-function utilities.parsers.mergehashes(hash,list)
-  return lpegmatch(merge,list,1,hash)
-end
-function utilities.parsers.runtime(time)
-  if not time then
-    time=os.runtime()
-  end
-  local days=div(time,24*60*60)
-  time=mod(time,24*60*60)
-  local hours=div(time,60*60)
-  time=mod(time,60*60)
-  local minutes=div(time,60)
-  local seconds=mod(time,60)
-  return days,hours,minutes,seconds
-end
-local spacing=whitespace^0
-local apply=P("->")
-local method=C((1-apply)^1)
-local token=lbrace*C((1-rbrace)^1)*rbrace+C(anything^1)
-local pattern=spacing*(method*spacing*apply+Carg(1))*spacing*token
-function utilities.parsers.splitmethod(str,default)
-  if str then
-    return lpegmatch(pattern,str,1,default or false)
-  else
-    return default or false,""
-  end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['util-dim']={
-  version=1.001,
-  comment="support for dimensions",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local format,match,gsub,type,setmetatable=string.format,string.match,string.gsub,type,setmetatable
-local P,S,R,Cc,C,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.Cc,lpeg.C,lpeg.match
-local allocate=utilities.storage.allocate
-local setmetatableindex=table.setmetatableindex
-local formatters=string.formatters
-local texget=tex and tex.get or function() return 65536*10*100 end
-local p_stripzeros=lpeg.patterns.stripzeros
-number=number or {}
-local number=number
-number.tonumberf=function(n) return lpegmatch(p_stripzeros,format("%.20f",n)) end
-number.tonumberg=function(n) return format("%.20g",n) end
-local dimenfactors=allocate {
-  ["pt"]=1/65536,
-  ["in"]=(100/7227)/65536,
-  ["cm"]=(254/7227)/65536,
-  ["mm"]=(2540/7227)/65536,
-  ["sp"]=1,
-  ["bp"]=(7200/7227)/65536,
-  ["pc"]=(1/12)/65536,
-  ["dd"]=(1157/1238)/65536,
-  ["cc"]=(1157/14856)/65536,
-  ["nd"]=(20320/21681)/65536,
-  ["nc"]=(5080/65043)/65536
-}
-local f_none=formatters["%s%s"]
-local f_true=formatters["%0.5F%s"]
-local function numbertodimen(n,unit,fmt) 
-  if type(n)=='string' then
-    return n
-  else
-    unit=unit or 'pt'
-    n=n*dimenfactors[unit]
-    if not fmt then
-      fmt=f_none(n,unit)
-    elseif fmt==true then
-      fmt=f_true(n,unit)
-    else
-      return formatters[fmt](n,unit)
-    end
-  end
-end
-number.maxdimen=1073741823
-number.todimen=numbertodimen
-number.dimenfactors=dimenfactors
-function number.topoints   (n,fmt) return numbertodimen(n,"pt",fmt) end
-function number.toinches   (n,fmt) return numbertodimen(n,"in",fmt) end
-function number.tocentimeters (n,fmt) return numbertodimen(n,"cm",fmt) end
-function number.tomillimeters (n,fmt) return numbertodimen(n,"mm",fmt) end
-function number.toscaledpoints(n,fmt) return numbertodimen(n,"sp",fmt) end
-function number.toscaledpoints(n)   return      n.."sp"   end
-function number.tobasepoints (n,fmt) return numbertodimen(n,"bp",fmt) end
-function number.topicas    (n,fmt) return numbertodimen(n "pc",fmt) end
-function number.todidots   (n,fmt) return numbertodimen(n,"dd",fmt) end
-function number.tociceros   (n,fmt) return numbertodimen(n,"cc",fmt) end
-function number.tonewdidots  (n,fmt) return numbertodimen(n,"nd",fmt) end
-function number.tonewciceros (n,fmt) return numbertodimen(n,"nc",fmt) end
-local amount=(S("+-")^0*R("09")^0*P(".")^0*R("09")^0)+Cc("0")
-local unit=R("az")^1+P("%")
-local dimenpair=amount/tonumber*(unit^1/dimenfactors+Cc(1)) 
-lpeg.patterns.dimenpair=dimenpair
-local splitter=amount/tonumber*C(unit^1)
-function number.splitdimen(str)
-  return lpegmatch(splitter,str)
-end
-setmetatableindex(dimenfactors,function(t,s)
-  return false
-end)
-local stringtodimen 
-local amount=S("+-")^0*R("09")^0*S(".,")^0*R("09")^0
-local unit=P("pt")+P("cm")+P("mm")+P("sp")+P("bp")+P("in")+P("pc")+P("dd")+P("cc")+P("nd")+P("nc")
-local validdimen=amount*unit
-lpeg.patterns.validdimen=validdimen
-local dimensions={}
-function dimensions.__add(a,b)
-  local ta,tb=type(a),type(b)
-  if ta=="string" then a=stringtodimen(a) elseif ta=="table" then a=a[1] end
-  if tb=="string" then b=stringtodimen(b) elseif tb=="table" then b=b[1] end
-  return setmetatable({ a+b },dimensions)
-end
-function dimensions.__sub(a,b)
-  local ta,tb=type(a),type(b)
-  if ta=="string" then a=stringtodimen(a) elseif ta=="table" then a=a[1] end
-  if tb=="string" then b=stringtodimen(b) elseif tb=="table" then b=b[1] end
-  return setmetatable({ a-b },dimensions)
-end
-function dimensions.__mul(a,b)
-  local ta,tb=type(a),type(b)
-  if ta=="string" then a=stringtodimen(a) elseif ta=="table" then a=a[1] end
-  if tb=="string" then b=stringtodimen(b) elseif tb=="table" then b=b[1] end
-  return setmetatable({ a*b },dimensions)
-end
-function dimensions.__div(a,b)
-  local ta,tb=type(a),type(b)
-  if ta=="string" then a=stringtodimen(a) elseif ta=="table" then a=a[1] end
-  if tb=="string" then b=stringtodimen(b) elseif tb=="table" then b=b[1] end
-  return setmetatable({ a/b },dimensions)
-end
-function dimensions.__unm(a)
-  local ta=type(a)
-  if ta=="string" then a=stringtodimen(a) elseif ta=="table" then a=a[1] end
-  return setmetatable({-a },dimensions)
-end
-function dimensions.__lt(a,b)
-  return a[1]<b[1]
-end
-function dimensions.__eq(a,b)
-  return a[1]==b[1]
-end
-function dimensions.__tostring(a)
-  return a[1]/65536 .."pt" 
-end
-function dimensions.__index(tab,key)
-  local d=dimenfactors[key]
-  if not d then
-    error("illegal property of dimen: "..key)
-    d=1
-  end
-  return 1/d
-end
-  dimenfactors["ex"]=4*1/65536 
-  dimenfactors["em"]=10*1/65536
-local known={} setmetatable(known,{ __mode="v" })
-function dimen(a)
-  if a then
-    local ta=type(a)
-    if ta=="string" then
-      local k=known[a]
-      if k then
-        a=k
-      else
-        local value,unit=lpegmatch(dimenpair,a)
-        if value and unit then
-          k=value/unit 
-        else
-          k=0
-        end
-        known[a]=k
-        a=k
-      end
-    elseif ta=="table" then
-      a=a[1]
-    end
-    return setmetatable({ a },dimensions)
-  else
-    return setmetatable({ 0 },dimensions)
-  end
-end
-function string.todimen(str) 
-  if type(str)=="number" then
-    return str
-  else
-    local k=known[str]
-    if not k then
-      local value,unit=lpegmatch(dimenpair,str)
-      if value and unit then
-        k=value/unit 
-      else
-        k=0
-      end
-      known[str]=k
-    end
-    return k
-  end
-end
-stringtodimen=string.todimen 
-function number.toscaled(d)
-  return format("%0.5f",d/2^16)
-end
-function number.percent(n,d) 
-  d=d or texget("hsize")
-  if type(d)=="string" then
-    d=stringtodimen(d)
-  end
-  return (n/100)*d
-end
-number["%"]=number.percent
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['util-jsn']={
-  version=1.001,
-  comment="companion to m-json.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local P,V,R,S,C,Cc,Cs,Ct,Cf,Cg=lpeg.P,lpeg.V,lpeg.R,lpeg.S,lpeg.C,lpeg.Cc,lpeg.Cs,lpeg.Ct,lpeg.Cf,lpeg.Cg
-local lpegmatch=lpeg.match
-local format=string.format
-local utfchar=utf.char
-local concat=table.concat
-local tonumber,tostring,rawset,type=tonumber,tostring,rawset,type
-local json=utilities.json or {}
-utilities.json=json
-local lbrace=P("{")
-local rbrace=P("}")
-local lparent=P("[")
-local rparent=P("]")
-local comma=P(",")
-local colon=P(":")
-local dquote=P('"')
-local whitespace=lpeg.patterns.whitespace
-local optionalws=whitespace^0
-local escapes={
-  ["b"]="\010",
-  ["f"]="\014",
-  ["n"]="\n",
-  ["r"]="\r",
-  ["t"]="\t",
-}
-local escape_un=C(P("\\u")/"0x"*S("09","AF","af"))/function(s) return utfchar(tonumber(s)) end
-local escape_bs=P([[\]])/""*(P(1)/escapes) 
-local jstring=dquote*Cs((escape_un+escape_bs+(1-dquote))^0)*dquote
-local jtrue=P("true")*Cc(true)
-local jfalse=P("false")*Cc(false)
-local jnull=P("null")*Cc(nil)
-local jnumber=(1-whitespace-rparent-rbrace-comma)^1/tonumber
-local key=jstring
-local jsonconverter={ "value",
-  object=lbrace*Cf(Ct("")*V("pair")*(comma*V("pair"))^0,rawset)*rbrace,
-  pair=Cg(optionalws*key*optionalws*colon*V("value")),
-  array=Ct(lparent*V("value")*(comma*V("value"))^0*rparent),
-  value=optionalws*(jstring+V("object")+V("array")+jtrue+jfalse+jnull+jnumber+#rparent)*optionalws,
-}
-function json.tolua(str)
-  return lpegmatch(jsonconverter,str)
-end
-local function tojson(value,t) 
-  local kind=type(value)
-  if kind=="table" then
-    local done=false
-    local size=#value
-    if size==0 then
-      for k,v in next,value do
-        if done then
-          t[#t+1]=","
-        else
-          t[#t+1]="{"
-          done=true
-        end
-        t[#t+1]=format("%q:",k)
-        tojson(v,t)
-      end
-      if done then
-        t[#t+1]="}"
-      else
-        t[#t+1]="{}"
-      end
-    elseif size==1 then
-      t[#t+1]="["
-      tojson(value[1],t)
-      t[#t+1]="]"
-    else
-      for i=1,size do
-        if done then
-          t[#t+1]=","
-        else
-          t[#t+1]="["
-          done=true
-        end
-        tojson(value[i],t)
-      end
-      t[#t+1]="]"
-    end
-  elseif kind=="string" then
-    t[#t+1]=format("%q",value)
-  elseif kind=="number" then
-    t[#t+1]=value
-  elseif kind=="boolean" then
-    t[#t+1]=tostring(value)
-  end
-  return t
-end
-function json.tostring(value)
-  local kind=type(value)
-  if kind=="table" then
-    return concat(tojson(value,{}),"")
-  elseif kind=="string" or kind=="number" then
-    return value
-  else
-    return tostring(value)
-  end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['trac-inf']={
-  version=1.001,
-  comment="companion to trac-inf.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local type,tonumber,select=type,tonumber,select
-local format,lower,find=string.format,string.lower,string.find
-local concat=table.concat
-local clock=os.gettimeofday or os.clock 
-local setmetatableindex=table.setmetatableindex
-local serialize=table.serialize
-local formatters=string.formatters
-statistics=statistics or {}
-local statistics=statistics
-statistics.enable=true
-statistics.threshold=0.01
-local statusinfo,n,registered,timers={},0,{},{}
-setmetatableindex(timers,function(t,k)
-  local v={ timing=0,loadtime=0 }
-  t[k]=v
-  return v
-end)
-local function hastiming(instance)
-  return instance and timers[instance]
-end
-local function resettiming(instance)
-  timers[instance or "notimer"]={ timing=0,loadtime=0 }
-end
-local function starttiming(instance)
-  local timer=timers[instance or "notimer"]
-  local it=timer.timing or 0
-  if it==0 then
-    timer.starttime=clock()
-    if not timer.loadtime then
-      timer.loadtime=0
-    end
-  end
-  timer.timing=it+1
-end
-local function stoptiming(instance)
-  local timer=timers[instance or "notimer"]
-  local it=timer.timing
-  if it>1 then
-    timer.timing=it-1
-  else
-    local starttime=timer.starttime
-    if starttime then
-      local stoptime=clock()
-      local loadtime=stoptime-starttime
-      timer.stoptime=stoptime
-      timer.loadtime=timer.loadtime+loadtime
-      timer.timing=0
-      return loadtime
-    end
-  end
-  return 0
-end
-local function elapsed(instance)
-  if type(instance)=="number" then
-    return instance or 0
-  else
-    local timer=timers[instance or "notimer"]
-    return timer and timer.loadtime or 0
-  end
-end
-local function elapsedtime(instance)
-  return format("%0.3f",elapsed(instance))
-end
-local function elapsedindeed(instance)
-  return elapsed(instance)>statistics.threshold
-end
-local function elapsedseconds(instance,rest) 
-  if elapsedindeed(instance) then
-    return format("%0.3f seconds %s",elapsed(instance),rest or "")
-  end
-end
-statistics.hastiming=hastiming
-statistics.resettiming=resettiming
-statistics.starttiming=starttiming
-statistics.stoptiming=stoptiming
-statistics.elapsed=elapsed
-statistics.elapsedtime=elapsedtime
-statistics.elapsedindeed=elapsedindeed
-statistics.elapsedseconds=elapsedseconds
-function statistics.register(tag,fnc)
-  if statistics.enable and type(fnc)=="function" then
-    local rt=registered[tag] or (#statusinfo+1)
-    statusinfo[rt]={ tag,fnc }
-    registered[tag]=rt
-    if #tag>n then n=#tag end
-  end
-end
-local report=logs.reporter("mkiv lua stats")
-function statistics.show()
-  if statistics.enable then
-    local register=statistics.register
-    register("used platform",function()
-      return format("%s, type: %s, binary subtree: %s",
-        os.platform or "unknown",os.type or "unknown",environment.texos or "unknown")
-    end)
-    register("luatex banner",function()
-      return lower(status.banner)
-    end)
-    register("control sequences",function()
-      return format("%s of %s + %s",status.cs_count,status.hash_size,status.hash_extra)
-    end)
-    register("callbacks",function()
-      local total,indirect=status.callbacks or 0,status.indirect_callbacks or 0
-      return format("%s direct, %s indirect, %s total",total-indirect,indirect,total)
-    end)
-    if jit then
-      local jitstatus={ jit.status() }
-      if jitstatus[1] then
-        register("luajit options",concat(jitstatus," ",2))
-      end
-    end
-    register("lua properties",function()
-      local hashchar=tonumber(status.luatex_hashchars)
-      local hashtype=status.luatex_hashtype
-      local mask=lua.mask or "ascii"
-      return format("engine: %s, used memory: %s, hash type: %s, hash chars: min(%s,40), symbol mask: %s (%s)",
-        jit and "luajit" or "lua",
-        statistics.memused(),
-        hashtype or "default",
-        hashchar and 2^hashchar or "unknown",
-        mask,
-        mask=="utf" and "τεχ" or "tex")
-    end)
-    register("runtime",statistics.runtime)
-    logs.newline() 
-    for i=1,#statusinfo do
-      local s=statusinfo[i]
-      local r=s[2]()
-      if r then
-        report("%s: %s",s[1],r)
-      end
-    end
-    statistics.enable=false
-  end
-end
-function statistics.memused() 
-  local round=math.round or math.floor
-  return format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000),round(status.luastate_bytes/1000000))
-end
-starttiming(statistics)
-function statistics.formatruntime(runtime) 
-  return format("%s seconds",runtime)  
-end
-function statistics.runtime()
-  stoptiming(statistics)
-  return statistics.formatruntime(elapsedtime(statistics))
-end
-local report=logs.reporter("system")
-function statistics.timed(action)
-  starttiming("run")
-  action()
-  stoptiming("run")
-  report("total runtime: %s seconds",elapsedtime("run"))
-end
-function statistics.tracefunction(base,tag,...)
-  for i=1,select("#",...) do
-    local name=select(i,...)
-    local stat={}
-    local func=base[name]
-    setmetatableindex(stat,function(t,k) t[k]=0 return 0 end)
-    base[name]=function(n,k,v) stat[k]=stat[k]+1 return func(n,k,v) end
-    statistics.register(formatters["%s.%s"](tag,name),function() return serialize(stat,"calls") end)
-  end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['util-lua']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  comment="the strip code is written by Peter Cawley",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local rep,sub,byte,dump,format=string.rep,string.sub,string.byte,string.dump,string.format
-local load,loadfile,type=load,loadfile,type
-utilities=utilities or {}
-utilities.lua=utilities.lua or {}
-local luautilities=utilities.lua
-local report_lua=logs.reporter("system","lua")
-local tracestripping=false
-local forcestupidcompile=true 
-luautilities.stripcode=true 
-luautilities.alwaysstripcode=false 
-luautilities.nofstrippedchunks=0
-luautilities.nofstrippedbytes=0
-local strippedchunks={} 
-luautilities.strippedchunks=strippedchunks
-luautilities.suffixes={
-  tma="tma",
-  tmc=jit and "tmb" or "tmc",
-  lua="lua",
-  luc=jit and "lub" or "luc",
-  lui="lui",
-  luv="luv",
-  luj="luj",
-  tua="tua",
-  tuc="tuc",
-}
-local function register(name)
-  if tracestripping then
-    report_lua("stripped bytecode from %a",name or "unknown")
-  end
-  strippedchunks[#strippedchunks+1]=name
-  luautilities.nofstrippedchunks=luautilities.nofstrippedchunks+1
-end
-local function stupidcompile(luafile,lucfile,strip)
-  local code=io.loaddata(luafile)
-  if code and code~="" then
-    code=load(code)
-    if code then
-      code=dump(code,strip and luautilities.stripcode or luautilities.alwaysstripcode)
-      if code and code~="" then
-        register(name)
-        io.savedata(lucfile,code)
-        return true,0
-      end
-    else
-      report_lua("fatal error %a in file %a",1,luafile)
-    end
-  else
-    report_lua("fatal error %a in file %a",2,luafile)
-  end
-  return false,0
-end
-function luautilities.loadedluacode(fullname,forcestrip,name)
-  name=name or fullname
-  local code,message
-  if environment.loadpreprocessedfile then
-    code,message=environment.loadpreprocessedfile(fullname)
-  else
-    code,message=loadfile(fullname)
-  end
-  if code then
-    code()
-  else
-    report_lua("loading of file %a failed:\n\t%s",fullname,message or "no message")
-  end
-  if forcestrip and luautilities.stripcode then
-    if type(forcestrip)=="function" then
-      forcestrip=forcestrip(fullname)
-    end
-    if forcestrip or luautilities.alwaysstripcode then
-      register(name)
-      return load(dump(code,true)),0
-    else
-      return code,0
-    end
-  elseif luautilities.alwaysstripcode then
-    register(name)
-    return load(dump(code,true)),0
-  else
-    return code,0
-  end
-end
-function luautilities.strippedloadstring(code,forcestrip,name) 
-  local code,message=load(code)
-  if not code then
-    report_lua("loading of file %a failed:\n\t%s",name,message or "no message")
-  end
-  if forcestrip and luautilities.stripcode or luautilities.alwaysstripcode then
-    register(name)
-    return load(dump(code,true)),0 
-  else
-    return code,0
-  end
-end
-function luautilities.compile(luafile,lucfile,cleanup,strip,fallback) 
-  report_lua("compiling %a into %a",luafile,lucfile)
-  os.remove(lucfile)
-  local done=stupidcompile(luafile,lucfile,strip~=false)
-  if done then
-    report_lua("dumping %a into %a stripped",luafile,lucfile)
-    if cleanup==true and lfs.isfile(lucfile) and lfs.isfile(luafile) then
-      report_lua("removing %a",luafile)
-      os.remove(luafile)
-    end
-  end
-  return done
-end
-function luautilities.loadstripped(...)
-  local l=load(...)
-  if l then
-    return load(dump(l,true))
-  end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['util-deb']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local debug=require "debug"
-local getinfo=debug.getinfo
-local type,next,tostring=type,next,tostring
-local format,find=string.format,string.find
-local is_boolean=string.is_boolean
-utilities=utilities or {}
-local debugger=utilities.debugger or {}
-utilities.debugger=debugger
-local counters={}
-local names={}
-local report=logs.reporter("debugger")
-local function hook()
-  local f=getinfo(2) 
-  if f then
-    local n="unknown"
-    if f.what=="C" then
-      n=f.name or '<anonymous>'
-      if not names[n] then
-        names[n]=format("%42s",n)
-      end
-    else
-      n=f.name or f.namewhat or f.what
-      if not n or n=="" then
-        n="?"
-      end
-      if not names[n] then
-        names[n]=format("%42s : % 5i : %s",n,f.linedefined or 0,f.short_src or "unknown source")
-      end
-    end
-    counters[n]=(counters[n] or 0)+1
-  end
-end
-function debugger.showstats(printer,threshold) 
-  printer=printer or report
-  threshold=threshold or 0
-  local total,grandtotal,functions=0,0,0
-  local dataset={}
-  for name,count in next,counters do
-    dataset[#dataset+1]={ name,count }
-  end
-  table.sort(dataset,function(a,b) return a[2]==b[2] and b[1]>a[1] or a[2]>b[2] end)
-  for i=1,#dataset do
-    local d=dataset[i]
-    local name=d[1]
-    local count=d[2]
-    if count>threshold and not find(name,"for generator") then 
-      printer(format("%8i  %s\n",count,names[name]))
-      total=total+count
-    end
-    grandtotal=grandtotal+count
-    functions=functions+1
-  end
-  printer("\n")
-  printer(format("functions  : % 10i\n",functions))
-  printer(format("total      : % 10i\n",total))
-  printer(format("grand total: % 10i\n",grandtotal))
-  printer(format("threshold  : % 10i\n",threshold))
-end
-function debugger.savestats(filename,threshold)
-  local f=io.open(filename,'w')
-  if f then
-    debugger.showstats(function(str) f:write(str) end,threshold)
-    f:close()
-  end
-end
-function debugger.enable()
-  debug.sethook(hook,"c")
-end
-function debugger.disable()
-  debug.sethook()
-end
-local function showtraceback(rep) 
-  local level=2 
-  local reporter=rep or report
-  while true do
-    local info=getinfo(level,"Sl")
-    if not info then
-      break
-    elseif info.what=="C" then
-      reporter("%2i : %s",level-1,"C function")
-    else
-      reporter("%2i : %s : %s",level-1,info.short_src,info.currentline)
-    end
-    level=level+1
-  end
-end
-debugger.showtraceback=showtraceback
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['util-tpl']={
-  version=1.001,
-  comment="companion to luat-lib.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-utilities.templates=utilities.templates or {}
-local templates=utilities.templates
-local trace_template=false trackers.register("templates.trace",function(v) trace_template=v end)
-local report_template=logs.reporter("template")
-local tostring=tostring
-local format,sub,byte=string.format,string.sub,string.byte
-local P,C,R,Cs,Cc,Carg,lpegmatch,lpegpatterns=lpeg.P,lpeg.C,lpeg.R,lpeg.Cs,lpeg.Cc,lpeg.Carg,lpeg.match,lpeg.patterns
-local replacer
-local function replacekey(k,t,how,recursive)
-  local v=t[k]
-  if not v then
-    if trace_template then
-      report_template("unknown key %a",k)
-    end
-    return ""
-  else
-    v=tostring(v)
-    if trace_template then
-      report_template("setting key %a to value %a",k,v)
-    end
-    if recursive then
-      return lpegmatch(replacer,v,1,t,how,recursive)
-    else
-      return v
-    end
-  end
-end
-local sqlescape=lpeg.replacer {
-  { "'","''"  },
-  { "\\","\\\\" },
-  { "\r\n","\\n" },
-  { "\r","\\n" },
-}
-local sqlquoted=Cs(Cc("'")*sqlescape*Cc("'"))
-lpegpatterns.sqlescape=sqlescape
-lpegpatterns.sqlquoted=sqlquoted
-local luaescape=lpegpatterns.luaescape
-local escapers={
-  lua=function(s)
-    return lpegmatch(luaescape,s)
-  end,
-  sql=function(s)
-    return lpegmatch(sqlescape,s)
-  end,
-}
-local quotedescapers={
-  lua=function(s)
-    return format("%q",s)
-  end,
-  sql=function(s)
-    return lpegmatch(sqlquoted,s)
-  end,
-}
-local luaescaper=escapers.lua
-local quotedluaescaper=quotedescapers.lua
-local function replacekeyunquoted(s,t,how,recurse) 
-  if how==false then
-    return replacekey(s,t,how,recurse)
-  else
-    local escaper=how and escapers[how] or luaescaper
-    return escaper(replacekey(s,t,how,recurse))
-  end
-end
-local function replacekeyquoted(s,t,how,recurse) 
-  if how==false then
-    return replacekey(s,t,how,recurse)
-  else
-    local escaper=how and quotedescapers[how] or quotedluaescaper
-    return escaper(replacekey(s,t,how,recurse))
-  end
-end
-local function replaceoptional(l,m,r,t,how,recurse)
-  local v=t[l]
-  return v and v~="" and lpegmatch(replacer,r,1,t,how or "lua",recurse or false) or ""
-end
-local single=P("%") 
-local double=P("%%") 
-local lquoted=P("%[") 
-local rquoted=P("]%") 
-local lquotedq=P("%(") 
-local rquotedq=P(")%") 
-local escape=double/'%%'
-local nosingle=single/''
-local nodouble=double/''
-local nolquoted=lquoted/''
-local norquoted=rquoted/''
-local nolquotedq=lquotedq/''
-local norquotedq=rquotedq/''
-local noloptional=P("%?")/''
-local noroptional=P("?%")/''
-local nomoptional=P(":")/''
-local args=Carg(1)*Carg(2)*Carg(3)
-local key=nosingle*((C((1-nosingle  )^1)*args)/replacekey    )*nosingle
-local quoted=nolquotedq*((C((1-norquotedq )^1)*args)/replacekeyquoted )*norquotedq
-local unquoted=nolquoted*((C((1-norquoted )^1)*args)/replacekeyunquoted)*norquoted
-local optional=noloptional*((C((1-nomoptional)^1)*nomoptional*C((1-noroptional)^1)*args)/replaceoptional)*noroptional
-local any=P(1)
-   replacer=Cs((unquoted+quoted+escape+optional+key+any)^0)
-local function replace(str,mapping,how,recurse)
-  if mapping and str then
-    return lpegmatch(replacer,str,1,mapping,how or "lua",recurse or false) or str
-  else
-    return str
-  end
-end
-templates.replace=replace
-function templates.replacer(str,how,recurse) 
-  return function(mapping)
-    return lpegmatch(replacer,str,1,mapping,how or "lua",recurse or false) or str
-  end
-end
-function templates.load(filename,mapping,how,recurse)
-  local data=io.loaddata(filename) or ""
-  if mapping and next(mapping) then
-    return replace(data,mapping,how,recurse)
-  else
-    return data
-  end
-end
-function templates.resolve(t,mapping,how,recurse)
-  if not mapping then
-    mapping=t
-  end
-  for k,v in next,t do
-    t[k]=replace(v,mapping,how,recurse)
-  end
-  return t
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['util-sta']={
-  version=1.001,
-  comment="companion to util-ini.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local insert,remove,fastcopy,concat=table.insert,table.remove,table.fastcopy,table.concat
-local format=string.format
-local select,tostring=select,tostring
-local trace_stacker=false trackers.register("stacker.resolve",function(v) trace_stacker=v end)
-local stacker=stacker or {}
-utilities.stacker=stacker
-local function start(s,t,first,last)
-  if s.mode=="switch" then
-    local n=tostring(t[last])
-    if trace_stacker then
-      s.report("start: %s",n)
-    end
-    return n
-  else
-    local r={}
-    for i=first,last do
-      r[#r+1]=tostring(t[i])
-    end
-    local n=concat(r," ")
-    if trace_stacker then
-      s.report("start: %s",n)
-    end
-    return n
-  end
-end
-local function stop(s,t,first,last)
-  if s.mode=="switch" then
-    local n=tostring(false)
-    if trace_stacker then
-      s.report("stop: %s",n)
-    end
-    return n
-  else
-    local r={}
-    for i=last,first,-1 do
-      r[#r+1]=tostring(false)
-    end
-    local n=concat(r," ")
-    if trace_stacker then
-      s.report("stop: %s",n)
-    end
-    return n
-  end
-end
-local function change(s,t1,first1,last1,t2,first2,last2)
-  if s.mode=="switch" then
-    local n=tostring(t2[last2])
-    if trace_stacker then
-      s.report("change: %s",n)
-    end
-    return n
-  else
-    local r={}
-    for i=last1,first1,-1 do
-      r[#r+1]=tostring(false)
-    end
-    local n=concat(r," ")
-    for i=first2,last2 do
-      r[#r+1]=tostring(t2[i])
-    end
-    if trace_stacker then
-      s.report("change: %s",n)
-    end
-    return n
-  end
-end
-function stacker.new(name)
-  local report=logs.reporter("stacker",name or nil)
-  local s
-  local stack={}
-  local list={}
-  local ids={}
-  local hash={}
-  local hashing=true
-  local function push(...)
-    for i=1,select("#",...) do
-      insert(stack,(select(i,...))) 
-    end
-    if hashing then
-      local c=concat(stack,"|")
-      local n=hash[c]
-      if not n then
-        n=#list+1
-        hash[c]=n
-        list[n]=fastcopy(stack)
-      end
-      insert(ids,n)
-      return n
-    else
-      local n=#list+1
-      list[n]=fastcopy(stack)
-      insert(ids,n)
-      return n
-    end
-  end
-  local function pop()
-    remove(stack)
-    remove(ids)
-    return ids[#ids] or s.unset or -1
-  end
-  local function clean()
-    if #stack==0 then
-      if trace_stacker then
-        s.report("%s list entries, %s stack entries",#list,#stack)
-      end
-    end
-  end
-  local tops={}
-  local top=nil
-  local switch=nil
-  local function resolve_reset(mode)
-    if #tops>0 then
-      report("resetting %s left-over states of %a",#tops,name)
-    end
-    tops={}
-    top=nil
-    switch=nil
-  end
-  local function resolve_begin(mode)
-    if mode then
-      switch=mode=="switch"
-    else
-      switch=s.mode=="switch"
-    end
-    top={ switch=switch }
-    insert(tops,top)
-  end
-  local function resolve_step(ti)
-    local result=nil
-    local noftop=#top
-    if ti>0 then
-      local current=list[ti]
-      if current then
-        local noflist=#current
-        local nofsame=0
-        if noflist>noftop then
-          for i=1,noflist do
-            if current[i]==top[i] then
-              nofsame=i
-            else
-              break
-            end
-          end
-        else
-          for i=1,noflist do
-            if current[i]==top[i] then
-              nofsame=i
-            else
-              break
-            end
-          end
-        end
-        local plus=nofsame+1
-        if plus<=noftop then
-          if plus<=noflist then
-            if switch then
-              result=s.change(s,top,plus,noftop,current,nofsame,noflist)
-            else
-              result=s.change(s,top,plus,noftop,current,plus,noflist)
-            end
-          else
-            if switch then
-              result=s.change(s,top,plus,noftop,current,nofsame,noflist)
-            else
-              result=s.stop(s,top,plus,noftop)
-            end
-          end
-        elseif plus<=noflist then
-          if switch then
-            result=s.start(s,current,nofsame,noflist)
-          else
-            result=s.start(s,current,plus,noflist)
-          end
-        end
-        top=current
-      else
-        if 1<=noftop then
-          result=s.stop(s,top,1,noftop)
-        end
-        top={}
-      end
-      return result
-    else
-      if 1<=noftop then
-        result=s.stop(s,top,1,noftop)
-      end
-      top={}
-      return result
-    end
-  end
-  local function resolve_end()
-    if #tops>0 then 
-      local result=s.stop(s,top,1,#top)
-      remove(tops)
-      top=tops[#tops]
-      switch=top and top.switch
-      return result
-    end
-  end
-  local function resolve(t)
-    resolve_begin()
-    for i=1,#t do
-      resolve_step(t[i])
-    end
-    resolve_end()
-  end
-  s={
-    name=name or "unknown",
-    unset=-1,
-    report=report,
-    start=start,
-    stop=stop,
-    change=change,
-    push=push,
-    pop=pop,
-    clean=clean,
-    resolve=resolve,
-    resolve_begin=resolve_begin,
-    resolve_step=resolve_step,
-    resolve_end=resolve_end,
-    resolve_reset=resolve_reset,
-  }
-  return s 
-end
-
-end -- closure

Modified: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -7,7 +7,7 @@
 --  lualibs.dtx  (with options: `extended')
 --  This is a generated file.
 --  
---  Copyright (C) 2009--2016 by
+--  Copyright (C) 2009--2017 by
 --          PRAGMA ADE / ConTeXt Development Team
 --          The LuaLaTeX Dev Team
 --  
@@ -30,8 +30,8 @@
 
 local lualibs_extended_module = {
   name          = "lualibs-extended",
-  version       = 2.4,
-  date          = "2016-04-06",
+  version       = 2.5,
+  date          = "2017-02-01",
   description   = "ConTeXt Lua libraries -- extended collection.",
   author        = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang",
   copyright     = "PRAGMA ADE / ConTeXt Development Team",

Modified: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-file.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-file.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-file.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -436,7 +436,7 @@
 
 function file.join(one, two, three, ...)
     if not two then
-        return one == "" and one or lpegmatch(stripper,one)
+        return one == "" and one or lpegmatch(reslasher,one)
     end
     if one == "" then
         return lpegmatch(stripper,three and concat({ two, three, ... },"/") or two)
@@ -607,14 +607,17 @@
     end
 end
 
-file.readdata = io.loaddata
-file.savedata = io.savedata
+local loaddata = io.loaddata
+local savedata = io.savedata
 
+file.readdata  = loaddata
+file.savedata  = savedata
+
 function file.copy(oldname,newname)
     if oldname and newname then
-        local data = io.loaddata(oldname)
+        local data = loaddata(oldname)
         if data and data ~= "" then
-            file.savedata(newname,data)
+            savedata(newname,data)
         end
     end
 end

Modified: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-io.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-io.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-io.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -7,6 +7,7 @@
 }
 
 local io = io
+local open, flush, write, read = io.open, io.flush, io.write, io.read
 local byte, find, gsub, format = string.byte, string.find, string.gsub, string.format
 local concat = table.concat
 local floor = math.floor
@@ -30,15 +31,13 @@
     local size = f:seek("end")
     if size == 0 then
         return ""
-    elseif size < 1024*1024 then
-        f:seek("set",0)
+    end
+    f:seek("set",0)
+    if size < 1024*1024 then
         return f:read('*all')
     else
-        local done = f:seek("set",0)
         local step
-        if size < 1024*1024 then
-            step = 1024 * 1024
-        elseif size > 16*1024*1024 then
+        if size > 16*1024*1024 then
             step = 16*1024*1024
         else
             step = floor(size/(1024*1024)) * 1024 * 1024 / 8
@@ -58,9 +57,8 @@
 io.readall = readall
 
 function io.loaddata(filename,textmode) -- return nil if empty
-    local f = io.open(filename,(textmode and 'r') or 'rb')
+    local f = open(filename,(textmode and 'r') or 'rb')
     if f then
-     -- local data = f:read('*all')
         local data = readall(f)
         f:close()
         if #data > 0 then
@@ -69,8 +67,55 @@
     end
 end
 
+function io.copydata(source,target,action)
+    local f = open(source,"rb")
+    if f then
+        local g = open(target,"wb")
+        if g then
+            local size = f:seek("end")
+            if size == 0 then
+                -- empty
+            else
+                f:seek("set",0)
+                if size < 1024*1024 then
+                    local data = f:read('*all')
+                    if action then
+                        data = action(data)
+                    end
+                    if data then
+                        g:write(data)
+                    end
+                else
+                    local step
+                    if size > 16*1024*1024 then
+                        step = 16*1024*1024
+                    else
+                        step = floor(size/(1024*1024)) * 1024 * 1024 / 8
+                    end
+                    while true do
+                        local data = f:read(step)
+                        if data then
+                            if action then
+                                data = action(data)
+                            end
+                            if data then
+                                g:write(data)
+                            end
+                        else
+                            break
+                        end
+                    end
+                end
+            end
+            g:close()
+        end
+        f:close()
+        flush()
+    end
+end
+
 function io.savedata(filename,data,joiner)
-    local f = io.open(filename,"wb")
+    local f = open(filename,"wb")
     if f then
         if type(data) == "table" then
             f:write(concat(data,joiner or ""))
@@ -80,7 +125,7 @@
             f:write(data or "")
         end
         f:close()
-        io.flush()
+        flush()
         return true
     else
         return false
@@ -90,7 +135,7 @@
 -- we can also chunk this one if needed: io.lines(filename,chunksize,"*l")
 
 function io.loadlines(filename,n) -- return nil if empty
-    local f = io.open(filename,'r')
+    local f = open(filename,'r')
     if not f then
         -- no file
     elseif n then
@@ -118,7 +163,7 @@
 end
 
 function io.loadchunk(filename,n)
-    local f = io.open(filename,'rb')
+    local f = open(filename,'rb')
     if f then
         local data = f:read(n or 1024)
         f:close()
@@ -129,7 +174,7 @@
 end
 
 function io.exists(filename)
-    local f = io.open(filename)
+    local f = open(filename)
     if f == nil then
         return false
     else
@@ -139,7 +184,7 @@
 end
 
 function io.size(filename)
-    local f = io.open(filename)
+    local f = open(filename)
     if f == nil then
         return 0
     else
@@ -149,11 +194,11 @@
     end
 end
 
-function io.noflines(f)
+local function noflines(f)
     if type(f) == "string" then
-        local f = io.open(filename)
+        local f = open(filename)
         if f then
-            local n = f and io.noflines(f) or 0
+            local n = f and noflines(f) or 0
             f:close()
             return n
         else
@@ -169,6 +214,10 @@
     end
 end
 
+io.noflines = noflines
+
+-- inlined is faster
+
 local nextchar = {
     [ 4] = function(f)
         return f:read(1,1,1,1)
@@ -250,16 +299,16 @@
 
 function io.ask(question,default,options)
     while true do
-        io.write(question)
+        write(question)
         if options then
-            io.write(format(" [%s]",concat(options,"|")))
+            write(format(" [%s]",concat(options,"|")))
         end
         if default then
-            io.write(format(" [%s]",default))
+            write(format(" [%s]",default))
         end
-        io.write(format(" "))
-        io.flush()
-        local answer = io.read()
+        write(format(" "))
+        flush()
+        local answer = read()
         answer = gsub(answer,"^%s*(.*)%s*$","%1")
         if answer == "" and default then
             return default

Modified: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-lua.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-lua.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-lua.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -198,3 +198,4 @@
     local popen   = io.popen   if popen   then function io.popen  (...) flush() return popen  (...) end end
 
 end
+

Modified: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-number.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-number.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-number.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -13,6 +13,7 @@
 local format, floor, match, rep = string.format, math.floor, string.match, string.rep
 local concat, insert = table.concat, table.insert
 local lpegmatch = lpeg.match
+local floor = math.floor
 
 number       = number or { }
 local number = number
@@ -205,3 +206,25 @@
 function number.bits(n)
     return { bits(n,1) }
 end
+
+function number.bytetodecimal(b)
+    local d = floor(b * 100 / 255 + 0.5)
+    if d > 100 then
+        return 100
+    elseif d < -100 then
+        return -100
+    else
+        return d
+    end
+end
+
+function number.decimaltobyte(d)
+    local b = floor(d * 255 / 100 + 0.5)
+    if b > 255 then
+        return 255
+    elseif b < -255 then
+        return -255
+    else
+        return b
+    end
+end

Modified: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-string.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-string.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-string.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -75,19 +75,19 @@
 local longtostring = patterns.longtostring
 
 function string.strip(str)
-    return lpegmatch(stripper,str) or ""
+    return str and lpegmatch(stripper,str) or ""
 end
 
 function string.fullstrip(str)
-    return lpegmatch(fullstripper,str) or ""
+    return str and lpegmatch(fullstripper,str) or ""
 end
 
 function string.collapsespaces(str)
-    return lpegmatch(collapser,str) or ""
+    return str and lpegmatch(collapser,str) or ""
 end
 
 function string.longtostring(str)
-    return lpegmatch(longtostring,str) or ""
+    return str and lpegmatch(longtostring,str) or ""
 end
 
 -- function string.is_empty(str)
@@ -99,7 +99,7 @@
 -- patterns.onlyspaces = pattern
 
 function string.is_empty(str)
-    if str == "" then
+    if not str or str == "" then
         return true
     else
         return lpegmatch(pattern,str) and true or false
@@ -163,7 +163,7 @@
 end
 
 function string.topattern(str,lowercase,strict)
-    if str=="" or type(str) ~= "string" then
+    if str == "" or type(str) ~= "string" then
         return ".*"
     elseif strict then
         str = lpegmatch(pattern_c,str)
@@ -177,6 +177,7 @@
     end
 end
 
+-- print(string.escapedpattern("abc*234",true))
 -- print(string.escapedpattern("12+34*.tex",false))
 -- print(string.escapedpattern("12+34*.tex",true))
 -- print(string.topattern     ("12+34*.tex",false,false))

Modified: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-table.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-table.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-table.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -478,7 +478,7 @@
     return hsh
 end
 
-local noquotes, hexify, handle, compact, inline, functions
+local noquotes, hexify, handle, compact, inline, functions, metacheck
 
 local reserved = table.tohash { -- intercept a language inconvenience: no reserved words as key
     'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if',
@@ -608,7 +608,8 @@
         if compact then
             last = #root
             for k=1,last do
-                if root[k] == nil then
+             -- if root[k] == nil then
+                if rawget(root,k) == nil then
                     last = k - 1
                     break
                 end
@@ -673,6 +674,8 @@
                     else
                         handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) -- %.99g
                     end
+                elseif tk ~= "string" then
+                    -- ignore
                 elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
                     if hexify then
                         handle(format("%s %s=0x%X,",depth,k,v))
@@ -695,6 +698,8 @@
                     end
                 elseif tk == "boolean" then
                     handle(format("%s [%s]=%q,",depth,k and "true" or "false",v))
+                elseif tk ~= "string" then
+                    -- ignore
                 elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
                     handle(format("%s %s=%q,",depth,k,v))
                 else
@@ -710,6 +715,8 @@
                         end
                     elseif tk == "boolean" then
                         handle(format("%s [%s]={},",depth,k and "true" or "false"))
+                    elseif tk ~= "string" then
+                        -- ignore
                     elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
                         handle(format("%s %s={},",depth,k))
                     else
@@ -726,6 +733,8 @@
                             end
                         elseif tk == "boolean" then
                             handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", ")))
+                        elseif tk ~= "string" then
+                            -- ignore
                         elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
                             handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
                         else
@@ -746,6 +755,8 @@
                     end
                 elseif tk == "boolean" then
                     handle(format("%s [%s]=%s,",depth,tostring(k),v and "true" or "false"))
+                elseif tk ~= "string" then
+                    -- ignore
                 elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
                     handle(format("%s %s=%s,",depth,k,v and "true" or "false"))
                 else
@@ -763,6 +774,8 @@
                         end
                     elseif tk == "boolean" then
                         handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f))
+                    elseif tk ~= "string" then
+                        -- ignore
                     elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
                         handle(format("%s %s=load(%q),",depth,k,f))
                     else
@@ -778,6 +791,8 @@
                     end
                 elseif tk == "boolean" then
                     handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v)))
+                elseif tk ~= "string" then
+                    -- ignore
                 elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
                     handle(format("%s %s=%q,",depth,k,tostring(v)))
                 else
@@ -803,6 +818,7 @@
         functions = specification.functions
         compact   = specification.compact
         inline    = specification.inline and compact
+        metacheck = specification.metacheck
         if functions == nil then
             functions = true
         end
@@ -812,6 +828,9 @@
         if inline == nil then
             inline = compact
         end
+        if metacheck == nil then
+            metacheck = true
+        end
     else
         noquotes  = false
         hexify    = false
@@ -819,6 +838,7 @@
         compact   = true
         inline    = true
         functions = true
+        metacheck = true
     end
     if tname == "string" then
         if name == "return" then
@@ -843,8 +863,9 @@
     end
     if root then
         -- The dummy access will initialize a table that has a delayed initialization
-        -- using a metatable. (maybe explicitly test for metatable)
-        if getmetatable(root) then -- todo: make this an option, maybe even per subtable
+        -- using a metatable. (maybe explicitly test for metatable). This can crash on
+        -- metatables that check the index against a number.
+        if metacheck and getmetatable(root) then
             local dummy = root._w_h_a_t_e_v_e_r_
             root._w_h_a_t_e_v_e_r_ = nil
         end
@@ -950,6 +971,41 @@
 
 table.flattened = flattened
 
+local function collapsed(t,f,h)
+    if f == nil then
+        f = { }
+        h = { }
+    end
+    for k=1,#t do
+        local v = t[k]
+        if type(v) == "table" then
+            collapsed(v,f,h)
+        elseif not h[v] then
+            f[#f+1] = v
+            h[v] = true
+        end
+    end
+    return f
+end
+
+local function collapsedhash(t,h)
+    if h == nil then
+        h = { }
+    end
+    for k=1,#t do
+        local v = t[k]
+        if type(v) == "table" then
+            collapsedhash(v,h)
+        else
+            h[v] = true
+        end
+    end
+    return h
+end
+
+table.collapsed     = collapsed     -- 20% faster than unique(collapsed(t))
+table.collapsedhash = collapsedhash
+
 local function unnest(t,f) -- only used in mk, for old times sake
     if not f then          -- and only relevant for token lists
         f = { }            -- this one can become obsolete
@@ -1056,7 +1112,7 @@
     return n
 end
 
-function table.swapped(t,s) -- hash
+function table.swapped(t,s) -- hash, we need to make sure we don't mess up next
     local n = { }
     if s then
         for k, v in next, s do
@@ -1069,7 +1125,14 @@
     return n
 end
 
-function table.mirrored(t) -- hash
+function table.hashed(t) -- list, add hash to index (save because we are not yet mixed
+    for i=1,#t do
+        t[t[i]] = i
+    end
+    return t
+end
+
+function table.mirrored(t) -- hash, we need to make sure we don't mess up next
     local n = { }
     for k, v in next, t do
         n[v] = k
@@ -1165,7 +1228,7 @@
     return t and next(t,next(t)) == nil
 end
 
--- new
+-- new (rather basic, not indexed and nested)
 
 function table.loweredkeys(t) -- maybe utf
     local l = { }

Modified: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-trac-inf.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-trac-inf.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-trac-inf.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -14,7 +14,7 @@
 local type, tonumber, select = type, tonumber, select
 local format, lower, find = string.format, string.lower, string.find
 local concat = table.concat
-local clock = os.gettimeofday or os.clock -- should go in environment
+local clock  = os.gettimeofday or os.clock -- should go in environment
 
 local setmetatableindex = table.setmetatableindex
 local serialize         = table.serialize
@@ -61,12 +61,13 @@
         timer.timing = it - 1
     else
         local starttime = timer.starttime
-        if starttime then
-            local stoptime = clock()
-            local loadtime = stoptime - starttime
-            timer.stoptime = stoptime
-            timer.loadtime = timer.loadtime + loadtime
-            timer.timing = 0
+        if starttime and starttime > 0 then
+            local stoptime  = clock()
+            local loadtime  = stoptime - starttime
+            timer.stoptime  = stoptime
+            timer.loadtime  = timer.loadtime + loadtime
+            timer.timing    = 0
+            timer.starttime = 0
             return loadtime
         end
     end
@@ -183,6 +184,7 @@
 
 function statistics.runtime()
     stoptiming(statistics)
+ --  stoptiming(statistics) -- somehow we can start the timer twice, but where
     return statistics.formatruntime(elapsedtime(statistics))
 end
 

Modified: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-fil.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-fil.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-fil.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -6,8 +6,10 @@
     license   = "see context related readme files"
 }
 
-local byte = string.byte
-local extract = bit32.extract
+local byte    = string.byte
+local char    = string.char
+local extract = bit32 and bit32.extract
+local floor   = math.floor
 
 -- Here are a few helpers (the starting point were old ones I used for parsing
 -- flac files). In Lua 5.3 we can probably do this better. Some code will move
@@ -36,6 +38,8 @@
     return f:seek("end")
 end
 
+files.getsize = files.size
+
 function files.setposition(f,n)
     if zerobased[f] then
         f:seek("set",n)
@@ -90,7 +94,8 @@
 function files.readinteger1(f)  -- one byte
     local n = byte(f:read(1))
     if n  >= 0x80 then
-        return n - 0xFF - 1
+     -- return n - 0xFF - 1
+        return n - 0x100
     else
         return n
     end
@@ -104,58 +109,118 @@
     local a, b = byte(f:read(2),1,2)
     return 0x100 * a + b
 end
+function files.readcardinal2le(f)
+    local b, a = byte(f:read(2),1,2)
+    return 0x100 * a + b
+end
 
 function files.readinteger2(f)
     local a, b = byte(f:read(2),1,2)
     local n = 0x100 * a + b
     if n >= 0x8000 then
-        return n - 0xFFFF - 1
+     -- return n - 0xFFFF - 1
+        return n - 0x10000
     else
         return n
     end
 end
+function files.readinteger2le(f)
+    local b, a = byte(f:read(2),1,2)
+    local n = 0x100 * a + b
+    if n >= 0x8000 then
+     -- return n - 0xFFFF - 1
+        return n - 0x10000
+    else
+        return n
+    end
+end
 
 function files.readcardinal3(f)
     local a, b, c = byte(f:read(3),1,3)
     return 0x10000 * a + 0x100 * b + c
 end
+function files.readcardinal3le(f)
+    local c, b, a = byte(f:read(3),1,3)
+    return 0x10000 * a + 0x100 * b + c
+end
 
+function files.readinteger3(f)
+    local a, b, c = byte(f:read(3),1,3)
+    local n = 0x10000 * a + 0x100 * b + c
+    if n >= 0x80000 then
+     -- return n - 0xFFFFFF - 1
+        return n - 0x1000000
+    else
+        return n
+    end
+end
+function files.readinteger3le(f)
+    local c, b, a = byte(f:read(3),1,3)
+    local n = 0x10000 * a + 0x100 * b + c
+    if n >= 0x80000 then
+     -- return n - 0xFFFFFF - 1
+        return n - 0x1000000
+    else
+        return n
+    end
+end
+
 function files.readcardinal4(f)
     local a, b, c, d = byte(f:read(4),1,4)
     return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
 end
+function files.readcardinal4le(f)
+    local d, c, b, a = byte(f:read(4),1,4)
+    return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
+end
 
 function files.readinteger4(f)
     local a, b, c, d = byte(f:read(4),1,4)
     local n = 0x1000000 * a + 0x10000 * b + 0x100 * c + d
     if n >= 0x8000000 then
-        return n - 0xFFFFFFFF - 1
+     -- return n - 0xFFFFFFFF - 1
+        return n - 0x100000000
     else
         return n
     end
 end
+function files.readinteger4le(f)
+    local d, c, b, a = byte(f:read(4),1,4)
+    local n = 0x1000000 * a + 0x10000 * b + 0x100 * c + d
+    if n >= 0x8000000 then
+     -- return n - 0xFFFFFFFF - 1
+        return n - 0x100000000
+    else
+        return n
+    end
+end
 
 function files.readfixed4(f)
     local a, b, c, d = byte(f:read(4),1,4)
     local n = 0x100 * a + b
     if n >= 0x8000 then
-        return n - 0xFFFF - 1 + (0x100 * c + d)/0xFFFF
+     -- return n - 0xFFFF - 1 + (0x100 * c + d)/0xFFFF
+        return n - 0x10000    + (0x100 * c + d)/0xFFFF
     else
         return n              + (0x100 * c + d)/0xFFFF
     end
 end
 
-function files.read2dot14(f)
-    local a, b = byte(f:read(2),1,2)
-    local n = 0x100 * a + b
-    local m = extract(n,0,30)
-    if n > 0x7FFF then
-        n = extract(n,30,2)
-        return m/0x4000 - 4
-    else
-        n = extract(n,30,2)
-        return n + m/0x4000
+if extract then
+
+    function files.read2dot14(f)
+        local a, b = byte(f:read(2),1,2)
+        local n = 0x100 * a + b
+        local m = extract(n,0,30)
+        if n > 0x7FFF then
+            n = extract(n,30,2)
+            return m/0x4000 - 4
+        else
+            n = extract(n,30,2)
+            return n + m/0x4000
+        end
     end
+
 end
 
 function files.skipshort(f,n)
@@ -165,3 +230,32 @@
 function files.skiplong(f,n)
     f:read(4*(n or 1))
 end
+
+-- writers (kind of slow)
+
+function files.writecardinal2(f,n)
+    local a = char(n % 256)
+    n = floor(n/256)
+    local b = char(n % 256)
+    f:write(b,a)
+end
+
+function files.writecardinal4(f,n)
+    local a = char(n % 256)
+    n = floor(n/256)
+    local b = char(n % 256)
+    n = floor(n/256)
+    local c = char(n % 256)
+    n = floor(n/256)
+    local d = char(n % 256)
+    f:write(d,c,b,a)
+end
+
+function files.writestring(f,s)
+    f:write(char(byte(s,1,#s)))
+end
+
+function files.writebyte(f,b)
+    f:write(char(b))
+end
+

Modified: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-jsn.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-jsn.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-jsn.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -64,18 +64,19 @@
 local key        = jstring
 
 local jsonconverter = { "value",
-    object   = lbrace * Cf(Ct("") * V("pair") * (comma * V("pair"))^0,rawset) * rbrace,
-    pair     = Cg(optionalws * key * optionalws * colon * V("value")),
-    array    = Ct(lparent * V("value") * (comma * V("value"))^0 * rparent),
-    value    = optionalws * (jstring + V("object") + V("array") + jtrue + jfalse + jnull + jnumber + #rparent) * optionalws,
+    hash  = lbrace * Cf(Ct("") * (V("pair") * (comma * V("pair"))^0 + optionalws),rawset) * rbrace,
+    pair  = Cg(optionalws * key * optionalws * colon * V("value")),
+    array = Ct(lparent * (V("value") * (comma * V("value"))^0 + optionalws) * rparent),
+--  value = optionalws * (jstring + V("hash") + V("array") + jtrue + jfalse + jnull + jnumber + #rparent) * optionalws,
+    value = optionalws * (jstring + V("hash") + V("array") + jtrue + jfalse + jnull + jnumber) * optionalws,
 }
 
 -- local jsonconverter = { "value",
---     object   = lbrace * Cf(Ct("") * V("pair") * (comma * V("pair"))^0,rawset) * rbrace,
---     pair     = Cg(optionalws * V("string") * optionalws * colon * V("value")),
---     array    = Ct(lparent * V("value") * (comma * V("value"))^0 * rparent),
---     string   = jstring,
---     value    = optionalws * (V("string") + V("object") + V("array") + jtrue + jfalse + jnull + jnumber) * optionalws,
+--     hash   = lbrace * Cf(Ct("") * (V("pair") * (comma * V("pair"))^0 + optionalws),rawset) * rbrace,
+--     pair   = Cg(optionalws * V("string") * optionalws * colon * V("value")),
+--     array  = Ct(lparent * (V("value") * (comma * V("value"))^0 + optionalws) * rparent),
+--     string = jstring,
+--     value  = optionalws * (V("string") + V("hash") + V("array") + jtrue + jfalse + jnull + jnumber) * optionalws,
 -- }
 
 -- lpeg.print(jsonconverter) -- size 181
@@ -156,3 +157,5 @@
 -- inspect(tmp)
 
 -- inspect(json.tostring(true))
+
+return json

Modified: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-lua.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-lua.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-lua.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -158,3 +158,21 @@
 -- luautilities.registerdatatype(lpeg.P("!"),"lpeg")
 --
 -- print(luautilities.datatype(lpeg.P("oeps")))
+
+-- These finalizers will only be invoked when we have a proper lua_close
+-- call (which is not happening in luatex tex node yes) or finish with an
+-- os.exit(n,true).
+
+local finalizers = { }
+
+setmetatable(finalizers, {
+    __gc = function(t)
+        for i=1,#t do
+            pcall(t[i]) -- let's not crash
+        end
+    end
+} )
+
+function luautilities.registerfinalizer(f)
+    finalizers[#finalizers+1] = f
+end

Modified: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-prs.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-prs.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-prs.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -36,6 +36,8 @@
 local rbrace      = P("}")
 local lparent     = P("(")
 local rparent     = P(")")
+local lbracket    = P("[")
+local rbracket    = P("]")
 local period      = S(".")
 local punctuation = S(".,:;")
 local spacer      = lpegpatterns.spacer
@@ -44,8 +46,9 @@
 local anything    = lpegpatterns.anything
 local endofstring = lpegpatterns.endofstring
 
-local nobrace     = 1 - (lbrace  + rbrace )
-local noparent    = 1 - (lparent + rparent)
+local nobrace     = 1 - (lbrace   + rbrace )
+local noparent    = 1 - (lparent  + rparent)
+local nobracket   = 1 - (lbracket + rbracket)
 
 -- we could use a Cf Cg construct
 
@@ -56,11 +59,12 @@
     [2] = left * V(1) * right
 }
 
-local nestedbraces  = P { lbrace * (nobrace + V(1))^0 * rbrace }
-local nestedparents = P { lparent * (noparent + V(1))^0 * rparent }
-local spaces        = space^0
-local argument      = Cs((lbrace/"") * ((nobrace + nestedbraces)^0) * (rbrace/""))
-local content       = (1-endofstring)^0
+local nestedbraces   = P { lbrace   * (nobrace   + V(1))^0 * rbrace }
+local nestedparents  = P { lparent  * (noparent  + V(1))^0 * rparent }
+local nestedbrackets = P { lbracket * (nobracket + V(1))^0 * rbracket }
+local spaces         = space^0
+local argument       = Cs((lbrace/"") * ((nobrace + nestedbraces)^0) * (rbrace/""))
+local content        = (1-endofstring)^0
 
 lpegpatterns.nestedbraces  = nestedbraces  -- no capture
 lpegpatterns.nestedparents = nestedparents -- no capture
@@ -79,10 +83,6 @@
 
 -- "a=1, b=2, c=3, d={a{b,c}d}, e=12345, f=xx{a{b,c}d}xx, g={}" : outer {} removes, leading spaces ignored
 
--- todo: rewrite to fold etc
---
--- parse = lpeg.Cf(lpeg.Carg(1) * lpeg.Cg(key * equal * value) * separator^0,rawset)^0 -- lpeg.match(parse,"...",1,hash)
-
 local hash = { }
 
 local function set(key,value)
@@ -193,6 +193,33 @@
     end
 end
 
+function parsers.settings_to_numbers(str)
+    if not str or str == "" then
+        return { }
+    end
+    if type(str) == "table" then
+        -- fall through
+    elseif find(str,",",1,true) then
+        str = lpegmatch(pattern,str)
+    else
+        return { tonumber(str) }
+    end
+    for i=1,#str do
+        str[i] = tonumber(str[i])
+    end
+    return str
+end
+
+local value     = P(lbrace * C((nobrace + nestedbraces)^0) * rbrace)
+                + C((nestedbraces + nestedbrackets + nestedparents + (1-comma))^0)
+local pattern   = spaces * Ct(value*(separator*value)^0)
+
+function parsers.settings_to_array_obey_fences(str)
+    return lpegmatch(pattern,str)
+end
+
+-- inspect(parsers.settings_to_array_obey_fences("url(http://a,b.c)"))
+
 -- this one also strips end spaces before separators
 --
 -- "{123} , 456  " -> "123" "456"

Modified: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-str.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-str.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-str.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -10,7 +10,7 @@
 utilities.strings = utilities.strings or { }
 local strings     = utilities.strings
 
-local format, gsub, rep, sub = string.format, string.gsub, string.rep, string.sub
+local format, gsub, rep, sub, find = string.format, string.gsub, string.rep, string.sub, string.find
 local load, dump = load, string.dump
 local tonumber, type, tostring = tonumber, type, tostring
 local unpack, concat = table.unpack, table.concat
@@ -385,6 +385,43 @@
     end
 end
 
+-- maybe to util-num
+
+local digit  = patterns.digit
+local period = patterns.period
+local three  = digit * digit * digit
+
+local splitter = Cs (
+    (((1 - (three^1 * period))^1 + C(three)) * (Carg(1) * three)^1 + C((1-period)^1))
+  * (P(1)/"" * Carg(2)) * C(2)
+)
+
+patterns.formattednumber = splitter
+
+function number.formatted(n,sep1,sep2)
+    local s = type(s) == "string" and n or format("%0.2f",n)
+    if sep1 == true then
+        return lpegmatch(splitter,s,1,".",",")
+    elseif sep1 == "." then
+        return lpegmatch(splitter,s,1,sep1,sep2 or ",")
+    elseif sep1 == "," then
+        return lpegmatch(splitter,s,1,sep1,sep2 or ".")
+    else
+        return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".")
+    end
+end
+
+-- print(number.formatted(1))
+-- print(number.formatted(12))
+-- print(number.formatted(123))
+-- print(number.formatted(1234))
+-- print(number.formatted(12345))
+-- print(number.formatted(123456))
+-- print(number.formatted(1234567))
+-- print(number.formatted(12345678))
+-- print(number.formatted(12345678,true))
+-- print(number.formatted(1234.56,"!","?"))
+
 local zero      = P("0")^1 / ""
 local plus      = P("+")   / ""
 local minus     = P("-")
@@ -732,43 +769,6 @@
     return format("nspaces[%s]",tonumber(f) or 0)
 end
 
--- maybe to util-num
-
-local digit  = patterns.digit
-local period = patterns.period
-local three  = digit * digit * digit
-
-local splitter = Cs (
-    (((1 - (three^1 * period))^1 + C(three)) * (Carg(1) * three)^1 + C((1-period)^1))
-  * (P(1)/"" * Carg(2)) * C(2)
-)
-
-patterns.formattednumber = splitter
-
-function number.formatted(n,sep1,sep2)
-    local s = type(s) == "string" and n or format("%0.2f",n)
-    if sep1 == true then
-        return lpegmatch(splitter,s,1,".",",")
-    elseif sep1 == "." then
-        return lpegmatch(splitter,s,1,sep1,sep2 or ",")
-    elseif sep1 == "," then
-        return lpegmatch(splitter,s,1,sep1,sep2 or ".")
-    else
-        return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".")
-    end
-end
-
--- print(number.formatted(1))
--- print(number.formatted(12))
--- print(number.formatted(123))
--- print(number.formatted(1234))
--- print(number.formatted(12345))
--- print(number.formatted(123456))
--- print(number.formatted(1234567))
--- print(number.formatted(12345678))
--- print(number.formatted(12345678,true))
--- print(number.formatted(1234.56,"!","?"))
-
 local format_m = function(f)
     n = n + 1
     if not f or f == "" then
@@ -801,9 +801,16 @@
 local format_extension = function(extensions,f,name)
     local extension = extensions[name] or "tostring(%s)"
     local f = tonumber(f) or 1
+    local w = find(extension,"%.%.%.")
     if f == 0 then
+        if w then
+            extension = gsub(extension,"%.%.%.","")
+        end
         return extension
     elseif f == 1 then
+        if w then
+            extension = gsub(extension,"%.%.%.","%%s")
+        end
         n = n + 1
         local a = "a" .. n
         return format(extension,a,a) -- maybe more times?
@@ -811,10 +818,16 @@
         local a = "a" .. (n + f + 1)
         return format(extension,a,a)
     else
+        if w then
+            extension = gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s")
+        end
+        -- we could fill an array and then n = n + 1 unpack(t,n,n+f) but as we
+        -- cache we don't save much and there are hardly any extensions anyway
         local t = { }
         for i=1,f do
             n = n + 1
-            t[#t+1] = "a" .. n
+         -- t[#t+1] = "a" .. n
+            t[i] = "a" .. n
         end
         return format(extension,unpack(t))
     end
@@ -822,6 +835,10 @@
 
 -- aA b cC d eE f gG hH iI jJ lL mM N o p qQ r sS tT uU wW xX z
 
+-- extensions : %!tag!
+
+-- can be made faster but not called that often
+
 local builder = Cs { "start",
     start = (
         (
@@ -850,10 +867,10 @@
               + V("a") -- new
               + V("A") -- new
               + V("j") + V("J") -- stripped e E
-              + V("m") + V("M") -- new
+              + V("m") + V("M") -- new (formatted number)
               + V("z") -- new
               --
-           -- + V("?") -- ignores probably messed up %
+           -- + V("?") -- ignored, probably messed up %
             )
           + V("*")
         )

Modified: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-tab.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-tab.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-tab.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -12,7 +12,7 @@
 
 local format, gmatch, gsub, sub = string.format, string.gmatch, string.gsub, string.sub
 local concat, insert, remove, sort = table.concat, table.insert, table.remove, table.sort
-local setmetatable, getmetatable, tonumber, tostring = setmetatable, getmetatable, tonumber, tostring
+local setmetatable, getmetatable, tonumber, tostring, rawget = setmetatable, getmetatable, tonumber, tostring, rawget
 local type, next, rawset, tonumber, tostring, load, select = type, next, rawset, tonumber, tostring, load, select
 local lpegmatch, P, Cs, Cc = lpeg.match, lpeg.P, lpeg.Cs, lpeg.Cc
 local sortedkeys, sortedpairs = table.sortedkeys, table.sortedpairs
@@ -169,7 +169,8 @@
                     r[f] = tostring(field)
                 end
             end
-            result[#result+1] = concat(r,separator)
+         -- result[#result+1] = concat(r,separator)
+            result[i+1] = concat(r,separator)
         end
         return concat(result,"\n")
     else
@@ -485,11 +486,12 @@
 
 local selfmapper = { __index = function(t,k) t[k] = k return k end }
 
-function table.twowaymapper(t)
-    if not t then
-        t = { }
-    else
-        for i=0,#t do
+function table.twowaymapper(t)    -- takes a 0/1 .. n indexed table and returns
+    if not t then                 -- it with  string-numbers as indices + reverse
+        t = { }                   -- mapping (all strings) .. used in cvs etc but
+    else                          -- typically a helper that one forgets about
+        local zero = rawget(t,0)  -- so it might move someplace else
+        for i=zero and 0 or 1,#t do
             local ti = t[i]       -- t[1]     = "one"
             if ti then
                 local i = tostring(i)
@@ -497,7 +499,6 @@
                 t[ti]   = i       -- t["one"] = "1"
             end
         end
-        t[""] = t[0] or ""
     end
  -- setmetatableindex(t,"key")
     setmetatable(t,selfmapper)
@@ -616,7 +617,8 @@
                     return nil
                 end
             end
-            local haszero = t[0]
+         -- local haszero = t[0]
+            local haszero = rawget(t,0) -- don't trigger meta
             if n == nt then
                 local tt = { }
                 for i=1,nt do
@@ -680,7 +682,8 @@
             local last  = 0
             last = #root
             for k=1,last do
-                if root[k] == nil then
+                if rawget(root,k) == nil then
+             -- if root[k] == nil then
                     last = k - 1
                     break
                 end
@@ -810,9 +813,10 @@
 
     if root then
         -- The dummy access will initialize a table that has a delayed initialization
-        -- using a metatable. (maybe explicitly test for metatable)
+        -- using a metatable. (maybe explicitly test for metatable). This can crash on
+        -- metatables that check the index against a number.
         if getmetatable(root) then -- todo: make this an option, maybe even per subtable
-            local dummy = root._w_h_a_t_e_v_e_r_
+            local dummy = root._w_h_a_t_e_v_e_r_ -- needed
             root._w_h_a_t_e_v_e_r_ = nil
         end
         -- Let's forget about empty tables.
@@ -833,5 +837,10 @@
 table.serialize = serialize
 
 if setinspector then
-    setinspector("table",function(v) if type(v) == "table" then print(serialize(v,"table",{})) return true end end)
+    setinspector("table",function(v)
+        if type(v) == "table" then
+            print(serialize(v,"table",{ metacheck = false }))
+            return true
+        end
+    end)
 end

Modified: trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs.lua	2017-02-05 23:22:17 UTC (rev 43152)
+++ trunk/Master/texmf-dist/tex/luatex/lualibs/lualibs.lua	2017-02-05 23:22:36 UTC (rev 43153)
@@ -7,7 +7,7 @@
 --  lualibs.dtx  (with options: `lualibs')
 --  This is a generated file.
 --  
---  Copyright (C) 2009--2016 by
+--  Copyright (C) 2009--2017 by
 --          PRAGMA ADE / ConTeXt Development Team
 --          The LuaLaTeX Dev Team
 --  
@@ -25,8 +25,8 @@
 
 lualibs.module_info = {
   name          = "lualibs",
-  version       = 2.4,
-  date          = "2016-04-06",
+  version       = 2.5,
+  date          = "2017-02-01",
   description   = "ConTeXt Lua standard libraries.",
   author        = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang",
   copyright     = "PRAGMA ADE / ConTeXt Development Team",



More information about the tex-live-commits mailing list