texlive[66253] Master/bin: Add luametatex and context for Solaris and

commits+mojca at tug.org commits+mojca at tug.org
Tue Feb 28 20:06:17 CET 2023


Revision: 66253
          http://tug.org/svn/texlive?view=revision&revision=66253
Author:   mojca
Date:     2023-02-28 20:06:16 +0100 (Tue, 28 Feb 2023)
Log Message:
-----------
Add luametatex and context for Solaris and Darwin

Added Paths:
-----------
    trunk/Master/bin/i386-solaris/context
    trunk/Master/bin/i386-solaris/context.lua
    trunk/Master/bin/i386-solaris/luametatex
    trunk/Master/bin/i386-solaris/mtxrun
    trunk/Master/bin/i386-solaris/mtxrun.lua
    trunk/Master/bin/universal-darwin/context
    trunk/Master/bin/universal-darwin/context.lua
    trunk/Master/bin/universal-darwin/luametatex
    trunk/Master/bin/universal-darwin/mtxrun
    trunk/Master/bin/universal-darwin/mtxrun.lua
    trunk/Master/bin/x86_64-darwinlegacy/context
    trunk/Master/bin/x86_64-darwinlegacy/context.lua
    trunk/Master/bin/x86_64-darwinlegacy/luametatex
    trunk/Master/bin/x86_64-darwinlegacy/mtxrun
    trunk/Master/bin/x86_64-darwinlegacy/mtxrun.lua
    trunk/Master/bin/x86_64-solaris/context
    trunk/Master/bin/x86_64-solaris/context.lua
    trunk/Master/bin/x86_64-solaris/luametatex
    trunk/Master/bin/x86_64-solaris/mtxrun
    trunk/Master/bin/x86_64-solaris/mtxrun.lua

Added: trunk/Master/bin/i386-solaris/context
===================================================================
--- trunk/Master/bin/i386-solaris/context	                        (rev 0)
+++ trunk/Master/bin/i386-solaris/context	2023-02-28 19:06:16 UTC (rev 66253)
@@ -0,0 +1 @@
+link luametatex
\ No newline at end of file


Property changes on: trunk/Master/bin/i386-solaris/context
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/bin/i386-solaris/context.lua
===================================================================
--- trunk/Master/bin/i386-solaris/context.lua	                        (rev 0)
+++ trunk/Master/bin/i386-solaris/context.lua	2023-02-28 19:06:16 UTC (rev 66253)
@@ -0,0 +1,41 @@
+-- This file is a companion to "context(.exe)" and is effectively the same
+-- as:
+--
+--     mtxrun -script context ...
+--
+-- which will locate "mtx-context.lua" and load that one. The binary is a
+-- copy of "luametatex(.exe)" aka luatex 2.0 for context lmtx. In a similar
+-- fashion "mtxrun(.exe)" will load the "mtrun.lua" script.
+--
+-- The installation of context should do this on Windows:
+--
+-- luametatex.exe -> tex/texmf-win64/bin/luatex.exe
+-- luametatex.exe -> tex/texmf-win64/bin/mtxrun.exe
+-- luametatex.exe -> tex/texmf-win64/bin/context.exe
+-- mtxrun.lua     -> tex/texmf-win64/bin/mtxrun.lua
+-- context.lua    -> tex/texmf-win64/bin/context.lua
+--
+-- and this on Unix:
+--
+-- luametatex     -> tex/texmf-linux-64/bin/luatex
+-- luametatex     -> tex/texmf-linux-64/bin/mtxrun
+-- luametatex     -> tex/texmf-linux-64/bin/context
+-- mtxrun.lua     -> tex/texmf-linux-64/bin/mtxrun.lua
+-- context.lua    -> tex/texmf-linux-64/bin/context.lua
+--
+-- The static binary is smaller than 3MB so the few copies provide no real
+-- overhead.
+
+local selfpath = os.selfpath
+
+if not arg or not selfpath then
+    print("invalid stub")
+    os.exit()
+end
+
+arg[0] = "mtxrun"
+
+table.insert(arg,1,"mtx-context")
+table.insert(arg,1,"--script")
+
+dofile(selfpath .. "/" .. "mtxrun.lua")

Added: trunk/Master/bin/i386-solaris/luametatex
===================================================================
(Binary files differ)

Index: trunk/Master/bin/i386-solaris/luametatex
===================================================================
--- trunk/Master/bin/i386-solaris/luametatex	2023-02-28 16:13:59 UTC (rev 66252)
+++ trunk/Master/bin/i386-solaris/luametatex	2023-02-28 19:06:16 UTC (rev 66253)

Property changes on: trunk/Master/bin/i386-solaris/luametatex
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+application/x-executable
\ No newline at end of property
Added: trunk/Master/bin/i386-solaris/mtxrun
===================================================================
--- trunk/Master/bin/i386-solaris/mtxrun	                        (rev 0)
+++ trunk/Master/bin/i386-solaris/mtxrun	2023-02-28 19:06:16 UTC (rev 66253)
@@ -0,0 +1 @@
+link luametatex
\ No newline at end of file


Property changes on: trunk/Master/bin/i386-solaris/mtxrun
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/bin/i386-solaris/mtxrun.lua
===================================================================
--- trunk/Master/bin/i386-solaris/mtxrun.lua	                        (rev 0)
+++ trunk/Master/bin/i386-solaris/mtxrun.lua	2023-02-28 19:06:16 UTC (rev 66253)
@@ -0,0 +1,27610 @@
+#!/usr/bin/env texlua
+
+if not modules then modules = { } end modules ['mtxrun'] = {
+    version   = 1.001,
+    comment   = "runner, lua replacement for texmfstart.rb",
+    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+    copyright = "PRAGMA ADE / ConTeXt Development Team",
+    license   = "see context related readme files"
+}
+
+-- one can make a stub:
+
+-- mtxrun :
+--
+-- #!/bin/sh
+-- env LUATEXDIR=/....../texmf/scripts/context/lua luatex --luaonly mtxrun.lua "$@"
+
+-- mtxrun.cmd :
+--
+-- @luatex --luaonly %~d0%~p0mtxrun.lua %*
+
+-- filename : mtxrun.lua
+-- comment  : companion to context.tex
+-- author   : Hans Hagen, PRAGMA-ADE, Hasselt NL
+-- copyright: PRAGMA ADE / ConTeXt Development Team
+-- license  : see context related readme files
+
+-- This script is based on texmfstart.rb but does not use kpsewhich to locate files.
+-- Although kpse is a library it never came to opening up its interface to other
+-- programs (esp scripting languages) and so we do it ourselves. The lua variant
+-- evolved out of an experimental ruby one. Interesting is that using a scripting
+-- language instead of c does not have a speed penalty. Actually the lua variant is
+-- more efficient, especially when multiple calls to kpsewhich are involved. The lua
+-- library also gives way more control.
+
+-- When libraries used here are updates you can run
+--
+--   mtxrun --selfmerge
+--
+-- to update the embedded code. After that you might need to run
+--
+--   mtxrun --selfupdate
+--
+-- to copy the new script (from scripts/context/lua) to location where
+-- binaries are expected. If you want to remove the embedded code you can run
+--
+--   mtxxun --selfclean
+
+-- to be done / considered
+--
+-- support for --exec or make it default
+-- support for jar files (or maybe not, never used, too messy)
+-- support for $RUBYINPUTS cum suis (if still needed)
+-- remember for subruns: _CTX_K_V_#{original}_
+-- remember for subruns: _CTX_K_S_#{original}_
+-- remember for subruns: TEXMFSTART.#{original} [tex.rb texmfstart.rb]
+
+-- begin library merge
+
+
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-bit32"] = package.loaded["l-bit32"] or true
+
+-- original size: 3607, stripped down to: 3009
+
+if not modules then modules={} end modules ['l-bit32']={
+ version=1.001,
+ license="the same as regular Lua",
+ source="bitwise.lua, v 1.24 2014/12/26 17:20:53 roberto",
+ comment="drop-in for bit32, adapted a bit by Hans Hagen",
+}
+if bit32 then
+elseif utf8 then
+ load ([[
+local select = select -- instead of: arg = { ... }
+bit32 = {
+  bnot = function (a)
+    return ~a & 0xFFFFFFFF
+  end,
+  band = function (x, y, z, ...)
+    if not z then
+      return ((x or -1) & (y or -1)) & 0xFFFFFFFF
+    else
+      local res = x & y & z
+      for i=1,select("#",...) do
+        res = res & select(i,...)
+      end
+      return res & 0xFFFFFFFF
+    end
+  end,
+  bor = function (x, y, z, ...)
+    if not z then
+      return ((x or 0) | (y or 0)) & 0xFFFFFFFF
+    else
+      local res = x | y | z
+      for i=1,select("#",...) do
+        res = res | select(i,...)
+      end
+      return res & 0xFFFFFFFF
+    end
+  end,
+  bxor = function (x, y, z, ...)
+    if not z then
+      return ((x or 0) ~ (y or 0)) & 0xFFFFFFFF
+    else
+      local res = x ~ y ~ z
+      for i=1,select("#",...) do
+        res = res ~ select(i,...)
+      end
+      return res & 0xFFFFFFFF
+    end
+  end,
+  btest = function (x, y, z, ...)
+    if not z then
+      return (((x or -1) & (y or -1)) & 0xFFFFFFFF) ~= 0
+    else
+      local res = x & y & z
+      for i=1,select("#",...) do
+          res = res & select(i,...)
+      end
+      return (res & 0xFFFFFFFF) ~= 0
+    end
+  end,
+  lshift = function (a, b)
+    return ((a & 0xFFFFFFFF) << b) & 0xFFFFFFFF
+  end,
+  rshift = function (a, b)
+    return ((a & 0xFFFFFFFF) >> b) & 0xFFFFFFFF
+  end,
+  arshift = function (a, b)
+    a = a & 0xFFFFFFFF
+    if b <= 0 or (a & 0x80000000) == 0 then
+      return (a >> b) & 0xFFFFFFFF
+    else
+      return ((a >> b) | ~(0xFFFFFFFF >> b)) & 0xFFFFFFFF
+    end
+  end,
+  lrotate = function (a ,b)
+    b = b & 31
+    a = a & 0xFFFFFFFF
+    a = (a << b) | (a >> (32 - b))
+    return a & 0xFFFFFFFF
+  end,
+  rrotate = function (a, b)
+    b = -b & 31
+    a = a & 0xFFFFFFFF
+    a = (a << b) | (a >> (32 - b))
+    return a & 0xFFFFFFFF
+  end,
+  extract = function (a, f, w)
+    return (a >> f) & ~(-1 << (w or 1))
+  end,
+  replace = function (a, v, f, w)
+    local mask = ~(-1 << (w or 1))
+    return ((a & ~(mask << f)) | ((v & mask) << f)) & 0xFFFFFFFF
+  end,
+}
+        ]] ) ()
+elseif bit then
+ load ([[
+local band, bnot, rshift, lshift = bit.band, bit.bnot, bit.rshift, bit.lshift
+bit32 = {
+  arshift = bit.arshift,
+  band    = band,
+  bnot    = bnot,
+  bor     = bit.bor,
+  bxor    = bit.bxor,
+  btest   = function(...)
+    return band(...) ~= 0
+  end,
+  extract = function(a,f,w)
+    return band(rshift(a,f),2^(w or 1)-1)
+  end,
+  lrotate = bit.rol,
+  lshift  = lshift,
+  replace = function(a,v,f,w)
+    local mask = 2^(w or 1)-1
+    return band(a,bnot(lshift(mask,f)))+lshift(band(v,mask),f)
+  end,
+  rrotate = bit.ror,
+  rshift  = rshift,
+}
+        ]] ) ()
+else
+ xpcall(function() local _,t=require("bit32") if t then bit32=t end return end,function() end)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-lua"] = package.loaded["l-lua"] or true
+
+-- original size: 6405, stripped down to: 2865
+
+if not modules then modules={} end modules ['l-lua']={
+ version=1.001,
+ comment="companion to luat-lib.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local next,type,tonumber=next,type,tonumber
+LUAMAJORVERSION,LUAMINORVERSION=string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$")
+LUAMAJORVERSION=tonumber(LUAMAJORVERSION) or 5
+LUAMINORVERSION=tonumber(LUAMINORVERSION) or 1
+LUAVERSION=LUAMAJORVERSION+LUAMINORVERSION/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
+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
+FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load
+if not FFISUPPORTED then
+ local okay;okay,ffi=pcall(require,"ffi")
+ FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load
+end
+if not FFISUPPORTED then
+ ffi=nil
+elseif not ffi.number then
+ ffi.number=tonumber
+end
+if LUAVERSION>5.3 then
+end
+if status and os.setenv then
+ os.setenv("engine",string.lower(status.luatex_engine or "unknown"))
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-macro"] = package.loaded["l-macro"] or true
+
+-- original size: 10130, stripped down to: 5990
+
+if not modules then modules={} end modules ['l-macros']={
+ 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 S,P,R,V,C,Cs,Cc,Ct,Carg=lpeg.S,lpeg.P,lpeg.R,lpeg.V,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Ct,lpeg.Carg
+local lpegmatch=lpeg.match
+local concat=table.concat
+local format,sub,match=string.format,string.sub,string.match
+local next,load,type=next,load,type
+local newline=S("\n\r")^1
+local continue=P("\\")*newline
+local whitespace=S(" \t\n\r")
+local spaces=S(" \t")+continue
+local nametoken=R("az","AZ","__","09")
+local name=nametoken^1
+local body=((continue/""+1)-newline)^1
+local lparent=P("(")
+local rparent=P(")")
+local noparent=1-(lparent+rparent)
+local nested=P { lparent*(noparent+V(1))^0*rparent }
+local escaped=P("\\")*P(1)
+local squote=P("'")
+local dquote=P('"')
+local quoted=dquote*(escaped+(1-dquote))^0*dquote+squote*(escaped+(1-squote))^0*squote
+local arguments=lparent*Ct((Cs((nested+(quoted+1-S("),")))^1)+S(", "))^0)*rparent
+local macros=lua.macros or {}
+lua.macros=macros
+local patterns={}
+local definitions={}
+local resolve
+local subparser
+local report_lua=function(...)
+ if logs and logs.reporter then
+  report_lua=logs.reporter("system","lua")
+  report_lua(...)
+ else
+  print(format(...))
+ end
+end
+local safeguard=P("local")*whitespace^1*name*(whitespace+P("="))
+resolve=safeguard+C(C(name)*(arguments^-1))/function(raw,s,a)
+ local d=definitions[s]
+ if d then
+  if a then
+   local n=#a
+   local p=patterns[s][n]
+   if p then
+    local d=d[n]
+    for i=1,n do
+     a[i]=lpegmatch(subparser,a[i]) or a[i]
+    end
+    return lpegmatch(p,d,1,a) or d
+   else
+    return raw
+   end
+  else
+   return d[0] or raw
+  end
+ elseif a then
+  for i=1,#a do
+   a[i]=lpegmatch(subparser,a[i]) or a[i]
+  end
+  return s.."("..concat(a,",")..")"
+ else
+  return raw
+ end
+end
+subparser=Cs((resolve+P(1))^1)
+local enddefine=P("#enddefine")/""
+local beginregister=(C(name)*(arguments+Cc(false))*C((1-enddefine)^1)*enddefine)/function(k,a,v)
+ local n=0
+ if a then
+  n=#a
+  local pattern=P(false)
+  for i=1,n do
+   pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end
+  end
+  pattern=Cs((pattern+P(1))^1)
+  local p=patterns[k]
+  if not p then
+   p={ [0]=false,false,false,false,false,false,false,false,false }
+   patterns[k]=p
+  end
+  p[n]=pattern
+ end
+ local d=definitions[k]
+ if not d then
+  d={ a=a,[0]=false,false,false,false,false,false,false,false,false }
+  definitions[k]=d
+ end
+ d[n]=lpegmatch(subparser,v) or v
+ return ""
+end
+local register=(Cs(name)*(arguments+Cc(false))*spaces^0*Cs(body))/function(k,a,v)
+ local n=0
+ if a then
+  n=#a
+  local pattern=P(false)
+  for i=1,n do
+   pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end
+  end
+  pattern=Cs((pattern+P(1))^1)
+  local p=patterns[k]
+  if not p then
+   p={ [0]=false,false,false,false,false,false,false,false,false }
+   patterns[k]=p
+  end
+  p[n]=pattern
+ end
+ local d=definitions[k]
+ if not d then
+  d={ a=a,[0]=false,false,false,false,false,false,false,false,false }
+  definitions[k]=d
+ end
+ d[n]=lpegmatch(subparser,v) or v
+ return ""
+end
+local unregister=(C(name)*spaces^0*(arguments+Cc(false)))/function(k,a)
+ local n=0
+ if a then
+  n=#a
+  local p=patterns[k]
+  if p then
+   p[n]=false
+  end
+ end
+ local d=definitions[k]
+ if d then
+  d[n]=false
+ end
+ return ""
+end
+local begindefine=(P("begindefine")*spaces^0/"")*beginregister
+local define=(P("define"  )*spaces^0/"")*register
+local undefine=(P("undefine"   )*spaces^0/"")*unregister
+local parser=Cs((((P("#")/"")*(define+begindefine+undefine)*(newline^0/"") )+resolve+P(1) )^0 )
+function macros.reset()
+ definitions={}
+ patterns={}
+end
+function macros.showdefinitions()
+ for name,list in table.sortedhash(definitions) do
+  local arguments=list.a
+  if arguments then
+   arguments="("..concat(arguments,",")..")"
+  else
+   arguments=""
+  end
+  print("macro: "..name..arguments)
+  for i=0,#list do
+   local l=list[i]
+   if l then
+    print("  "..l)
+   end
+  end
+ end
+end
+function macros.resolvestring(str)
+ return lpegmatch(parser,str) or str
+end
+function macros.resolving()
+ return next(patterns)
+end
+local function reload(path,name,data)
+ local only=match(name,".-([^/]+)%.lua")
+ if only and only~="" then
+  local name=path.."/"..only
+  local f=io.open(name,"wb")
+  f:write(data)
+  f:close()
+  local f=loadfile(name)
+  os.remove(name)
+  return f
+ end
+end
+local function reload(path,name,data)
+ if path and path~="" then
+  local only=string.match(name,".-([^/]+)%.lua")
+  if only and only~="" then
+   local name=path.."/"..only.."-macro.lua"
+   local f=io.open(name,"wb")
+   if f then
+    f:write(data)
+    f:close()
+    local l=loadfile(name)
+    os.remove(name)
+    return l
+   end
+  end
+ end
+ return load(data,name)
+end
+local function loaded(name,trace,detail)
+ local f=io.open(name,"rb")
+ if not f then
+  return false,format("file '%s' not found",name)
+ end
+ local c=f:read("*a")
+ if not c then
+  return false,format("file '%s' is invalid",name)
+ end
+ f:close()
+ local n=lpegmatch(parser,c)
+ if trace then
+  if #n~=#c then
+   report_lua("macros expanded in '%s' (%i => %i bytes)",name,#c,#n)
+   if detail then
+    report_lua()
+    report_lua(n)
+    report_lua()
+   end
+  elseif detail then
+   report_lua("no macros expanded in '%s'",name)
+  end
+ end
+ return reload(lfs and lfs.currentdir(),name,n)
+end
+macros.loaded=loaded
+function required(name,trace)
+ local filename=file.addsuffix(name,"lua")
+ local fullname=resolvers and resolvers.findfile(filename) or filename
+ if not fullname or fullname=="" then
+  return false
+ end
+ local codeblob=package.loaded[fullname]
+ if codeblob then
+  return codeblob
+ end
+ local code,message=loaded(fullname,macros,trace,trace)
+ if type(code)=="function" then
+  code=code()
+ else
+  report_lua("error when loading '%s'",fullname)
+  return false,message
+ end
+ if code==nil then
+  code=false
+ end
+ package.loaded[fullname]=code
+ return code
+end
+macros.required=required
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-sandbox"] = package.loaded["l-sandbox"] or true
+
+-- original size: 9604, stripped down to: 6394
+
+if not modules then modules={} end modules ['l-sandbox']={
+ 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 global=_G
+local next=next
+local unpack=unpack or table.unpack
+local type=type
+local tprint=texio and texio.write_nl or print
+local tostring=tostring
+local format=string.format 
+local concat=table.concat
+local sort=table.sort
+local gmatch=string.gmatch
+local gsub=string.gsub
+local requiem=require
+sandbox={}
+local sandboxed=false
+local overloads={}
+local skiploads={}
+local initializers={}
+local finalizers={}
+local originals={}
+local comments={}
+local trace=false
+local logger=false
+local blocked={}
+local function report(...)
+ tprint("sandbox         ! "..format(...)) 
+end
+sandbox.report=report
+function sandbox.setreporter(r)
+ report=r
+ sandbox.report=r
+end
+function sandbox.settrace(v)
+ trace=v
+end
+function sandbox.setlogger(l)
+ logger=type(l)=="function" and l or false
+end
+local function register(func,overload,comment)
+ if type(func)=="function" then
+  if type(overload)=="string" then
+   comment=overload
+   overload=nil
+  end
+  local function f(...)
+   if sandboxed then
+    local overload=overloads[f]
+    if overload then
+     if logger then
+      local result={ overload(func,...) }
+      logger {
+       comment=comments[f] or tostring(f),
+       arguments={... },
+       result=result[1] and true or false,
+      }
+      return unpack(result)
+     else
+      return overload(func,...)
+     end
+    else
+    end
+   else
+    return func(...)
+   end
+  end
+  if comment then
+   comments[f]=comment
+   if trace then
+    report("registering function: %s",comment)
+   end
+  end
+  overloads[f]=overload or false
+  originals[f]=func
+  return f
+ end
+end
+local function redefine(func,comment)
+ if type(func)=="function" then
+  skiploads[func]=comment or comments[func] or "unknown"
+  if overloads[func]==false then
+   overloads[func]=nil 
+  end
+ end
+end
+sandbox.register=register
+sandbox.redefine=redefine
+function sandbox.original(func)
+ return originals and originals[func] or func
+end
+function sandbox.overload(func,overload,comment)
+ comment=comment or comments[func] or "?"
+ if type(func)~="function" then
+  if trace then
+   report("overloading unknown function: %s",comment)
+  end
+ elseif type(overload)~="function" then
+  if trace then
+   report("overloading function with bad overload: %s",comment)
+  end
+ elseif overloads[func]==nil then
+  if trace then
+   report("function is not registered: %s",comment)
+  end
+ elseif skiploads[func] then
+  if trace then
+   report("function is not skipped: %s",comment)
+  end
+ else
+  if trace then
+   report("overloading function: %s",comment)
+  end
+  overloads[func]=overload
+ end
+ return func
+end
+local function whatever(specification,what,target)
+ if type(specification)~="table" then
+  report("%s needs a specification",what)
+ elseif type(specification.category)~="string" or type(specification.action)~="function" then
+  report("%s needs a category and action",what)
+ elseif not sandboxed then
+  target[#target+1]=specification
+ elseif trace then
+  report("already enabled, discarding %s",what)
+ end
+end
+function sandbox.initializer(specification)
+ whatever(specification,"initializer",initializers)
+end
+function sandbox.finalizer(specification)
+ whatever(specification,"finalizer",finalizers)
+end
+function require(name)
+ local n=gsub(name,"^.*[\\/]","")
+ local n=gsub(n,"[%.].*$","")
+ local b=blocked[n]
+ if b==false then
+  return nil 
+ elseif b then
+  if trace then
+   report("using blocked: %s",n)
+  end
+  return b
+ else
+  if trace then
+   report("requiring: %s",name)
+  end
+  return requiem(name)
+ end
+end
+function blockrequire(name,lib)
+ if trace then
+  report("preventing reload of: %s",name)
+ end
+ blocked[name]=lib or _G[name] or false
+end
+function sandbox.enable()
+ if not sandboxed then
+  debug={
+   traceback=debug.traceback,
+  }
+  for i=1,#initializers do
+   initializers[i].action()
+  end
+  for i=1,#finalizers do
+   finalizers[i].action()
+  end
+  local nnot=0
+  local nyes=0
+  local cnot={}
+  local cyes={}
+  local skip={}
+  for k,v in next,overloads do
+   local c=comments[k]
+   if v then
+    if c then
+     cyes[#cyes+1]=c
+    else 
+     nyes=nyes+1
+    end
+   else
+    if c then
+     cnot[#cnot+1]=c
+    else 
+     nnot=nnot+1
+    end
+   end
+  end
+  for k,v in next,skiploads do
+   skip[#skip+1]=v
+  end
+  if #cyes>0 then
+   sort(cyes)
+   report("overloaded known: %s",concat(cyes," | "))
+  end
+  if nyes>0 then
+   report("overloaded unknown: %s",nyes)
+  end
+  if #cnot>0 then
+   sort(cnot)
+   report("not overloaded known: %s",concat(cnot," | "))
+  end
+  if nnot>0 then
+   report("not overloaded unknown: %s",nnot)
+  end
+  if #skip>0 then
+   sort(skip)
+   report("not overloaded redefined: %s",concat(skip," | "))
+  end
+  initializers=nil
+  finalizers=nil
+  originals=nil
+  sandboxed=true
+ end
+end
+blockrequire("lfs",lfs)
+blockrequire("io",io)
+blockrequire("os",os)
+blockrequire("ffi",ffi)
+local function supported(library)
+ local l=_G[library]
+ return l
+end
+loadfile=register(loadfile,"loadfile")
+if supported("lua") then
+ lua.openfile=register(lua.openfile,"lua.openfile")
+end
+if supported("io") then
+ io.open=register(io.open,"io.open")
+ io.popen=register(io.popen,"io.popen") 
+ io.lines=register(io.lines,"io.lines")
+ io.output=register(io.output,"io.output")
+ io.input=register(io.input,"io.input")
+end
+if supported("os") then
+ os.execute=register(os.execute,"os.execute")
+ os.spawn=register(os.spawn,"os.spawn")
+ os.exec=register(os.exec,"os.exec")
+ os.rename=register(os.rename,"os.rename")
+ os.remove=register(os.remove,"os.remove")
+end
+if supported("lfs") then
+ lfs.chdir=register(lfs.chdir,"lfs.chdir")
+ lfs.mkdir=register(lfs.mkdir,"lfs.mkdir")
+ lfs.rmdir=register(lfs.rmdir,"lfs.rmdir")
+ lfs.isfile=register(lfs.isfile,"lfs.isfile")
+ lfs.isdir=register(lfs.isdir,"lfs.isdir")
+ lfs.attributes=register(lfs.attributes,"lfs.attributes")
+ lfs.dir=register(lfs.dir,"lfs.dir")
+ lfs.lock_dir=register(lfs.lock_dir,"lfs.lock_dir")
+ lfs.touch=register(lfs.touch,"lfs.touch")
+ lfs.link=register(lfs.link,"lfs.link")
+ lfs.setmode=register(lfs.setmode,"lfs.setmode")
+ lfs.readlink=register(lfs.readlink,"lfs.readlink")
+ lfs.shortname=register(lfs.shortname,"lfs.shortname")
+ lfs.symlinkattributes=register(lfs.symlinkattributes,"lfs.symlinkattributes")
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-package"] = package.loaded["l-package"] or true
+
+-- original size: 12566, stripped down to: 8937
+
+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,unpack=type,unpack
+local gsub,format,find=string.gsub,string.format,string.find
+local insert,remove=table.insert,table.remove
+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={
+  "reset loaded",
+  "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 checkedfiles={}
+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
+end
+local function pushpath(tag,what,target,path)
+ local path=helpers.cleanpath(path)
+ insert(target,1,path)
+ if helpers.trace then
+  helpers.report("pushing %s path in front: %s",tag,path)
+ end
+end
+local function poppath(tag,what,target)
+ local path=remove(target,1)
+ if helpers.trace then
+  if path then
+   helpers.report("popping %s path from front: %s",tag,path)
+  else
+   helpers.report("no %s path to pop",tag)
+  end
+ end
+end
+helpers.registerpath=registerpath
+function package.extraluapath(...)
+ registerpath("extra lua","lua",extraluapaths,...)
+end
+function package.pushluapath(path)
+ pushpath("extra lua","lua",extraluapaths,path)
+end
+function package.popluapath()
+ poppath("extra lua","lua",extraluapaths)
+end
+function package.extralibpath(...)
+ registerpath("extra lib","lib",extralibpaths,...)
+end
+function package.pushlibpath(path)
+ pushpath("extra lib","lib",extralibpaths,path)
+end
+function package.poplibpath()
+ poppath("extra lib","lua",extralibpaths)
+end
+local function loadedaslib(resolved,rawname) 
+ local base=gsub(rawname,"%.","_")
+ local init="luaopen_"..gsub(base,"%.","_")
+ local data={ resolved,init,"" }
+ checkedfiles[#checkedfiles+1]=data
+ if helpers.trace then
+  helpers.report("calling loadlib with '%s' with init '%s'",resolved,init)
+ end
+ local a,b,c=package.loadlib(resolved,init)
+ if not a and type(b)=="string" then
+  data[3]=string.fullstrip(b or "unknown error")
+ end
+ return a,b,c 
+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["reset loaded"]=function(name)
+ checkedfiles={}
+ return false
+end
+methods["already loaded"]=function(name)
+ return package.loaded[name]
+end
+methods["preload table"]=function(name)
+ local f=builtin["preload table"]
+ if f then
+  return f(name)
+ end
+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)
+ local f=builtin["path specification"]
+ if f then
+  getluapaths() 
+  return f(name)
+ end
+end
+methods["cpath specification"]=function(name)
+ local f=builtin["cpath specification"]
+ if f then
+  getlibpaths() 
+  return f(name)
+ end
+end
+methods["all in one fallback"]=function(name)
+ local f=builtin["all in one fallback"]
+ if f then
+  return f(name)
+ end
+end
+methods["not loaded"]=function(name)
+ if helpers.trace then
+  helpers.report("unable to locate '%s'",name or "?")
+  for i=1,#checkedfiles do
+   helpers.report("checked file '%s', initializer '%s', message '%s'",unpack(checkedfiles[i]))
+  end
+ 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]
+  local lookup=method and methods[method]
+  if type(lookup)=="function" then
+   if helpers.trace then
+    helpers.report("%s, level '%s', method '%s', name '%s'","locating",level,method,name)
+   end
+   local result,rest=lookup(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
+ 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)
+if context then
+ package.path=""
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-lpeg"] = package.loaded["l-lpeg"] or true
+
+-- original size: 38742, stripped down to: 19489
+
+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") 
+local lpeg=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 digits=digit^1
+local octdigit=R("07")
+local octdigits=octdigit^1
+local lowercase=R("az")
+local uppercase=R("AZ")
+local underscore=P("_")
+local hexdigit=digit+lowercase+uppercase
+local hexdigits=hexdigit^1
+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 nospacer=Cs((whitespace^1/""+nonwhitespace^1)^0)
+local b_collapser=Cs(whitespace^0/""*(nonwhitespace^1+whitespace^1/" ")^0)
+local m_collapser=Cs((nonwhitespace^1+whitespace^1/" ")^0)
+local e_collapser=Cs((whitespace^1*endofstring/""+nonwhitespace^1+whitespace^1/" ")^0)
+local x_collapser=Cs((nonwhitespace^1+whitespace^1/"" )^0)
+local b_stripper=Cs(spacer^0/""*(nonspacer^1+spacer^1/" ")^0)
+local m_stripper=Cs((nonspacer^1+spacer^1/" ")^0)
+local e_stripper=Cs((spacer^1*endofstring/""+nonspacer^1+spacer^1/" ")^0)
+local x_stripper=Cs((nonspacer^1+spacer^1/"" )^0)
+patterns.stripper=stripper
+patterns.fullstripper=fullstripper
+patterns.collapser=collapser
+patterns.nospacer=nospacer
+patterns.b_collapser=b_collapser
+patterns.m_collapser=m_collapser
+patterns.e_collapser=e_collapser
+patterns.x_collapser=x_collapser
+patterns.b_stripper=b_stripper
+patterns.m_stripper=m_stripper
+patterns.e_stripper=e_stripper
+patterns.x_stripper=x_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.digits=digits
+patterns.octdigit=octdigit
+patterns.octdigits=octdigits
+patterns.hexdigit=hexdigit
+patterns.hexdigits=hexdigits
+patterns.sign=sign
+patterns.cardinal=digits
+patterns.integer=sign^-1*digits
+patterns.unsigned=digit^0*period*digits
+patterns.float=sign^-1*patterns.unsigned
+patterns.cunsigned=digit^0*comma*digits
+patterns.cpunsigned=digit^0*(period+comma)*digits
+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*octdigits 
+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")*hexdigits
+patterns.hexafloat=sign^-1*zero*S("xX")*(hexdigit^0*period*hexdigits+hexdigits*period*hexdigit^0+hexdigits)*(S("pP")*sign^-1*hexdigits)^-1
+patterns.decafloat=sign^-1*(digit^0*period*digits+digits*period*digit^0+digits)*S("eE")*sign^-1*digits
+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/""*(endofstring+Cc(" ")))^0))
+local function anywhere(pattern) 
+ return (1-P(pattern))^0*P(pattern)
+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)
+ if action then
+  return (((1-P(pattern))^1)/action+1)^0
+ else
+  return (Cs((1-P(pattern))^1)+1)^0
+ end
+end
+function lpeg.tsplitter(pattern,action)
+ if action then
+  return Ct((((1-P(pattern))^1)/action+1)^0)
+ else
+  return Ct((Cs((1-P(pattern))^1)+1)^0)
+ end
+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
+function lpeg.counter(pattern,action)
+ local n=0
+ local pattern=(P(pattern)/function() n=n+1 end+anything)^0
+ if action then
+  return function(str) n=0;lpegmatch(pattern,str);action(n) end
+ else
+  return function(str) n=0;lpegmatch(pattern,str);return n end
+ 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 lower=utf and utf.lower or string.lower
+local upper=utf and utf.upper or string.upper
+function lpeg.setutfcasers(l,u)
+ lower=l or lower
+ upper=u or upper
+end
+local function make1(t,rest)
+ 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)*make1(v,v[""])
+   end
+  end
+ end
+ if rest then
+  p=p+p_true
+ end
+ return p
+end
+local function make2(t,rest) 
+ 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(lower(k))+P(upper(k)))*p_true
+   elseif v==false then
+   else
+    p=p+(P(lower(k))+P(upper(k)))*make2(v,v[""])
+   end
+  end
+ end
+ if rest then
+  p=p+p_true
+ end
+ return p
+end
+local function utfchartabletopattern(list,insensitive) 
+ 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 (insensitive and make2 or make1)(tree)
+end
+lpeg.utfchartabletopattern=utfchartabletopattern
+function lpeg.utfreplacer(list,insensitive)
+ local pattern=Cs((utfchartabletopattern(list,insensitive)/list+utf8character)^0)
+ return function(str)
+  return lpegmatch(pattern,str) or str
+ end
+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
+do
+ local trailingzeros=zero^0*-digit 
+ local stripper=Cs((
+  digits*(
+   period*trailingzeros/""+period*(digit-trailingzeros)^1*(trailingzeros/"")
+  )+1
+ )^0)
+ lpeg.patterns.stripzeros=stripper 
+ local nonzero=digit-zero
+ local trailingzeros=zero^1*endofstring
+ local stripper=Cs((1-period)^0*(
+  period*trailingzeros/""+period*(nonzero^1+(trailingzeros/"")+zero^1)^0+endofstring
+ ))
+ lpeg.patterns.stripzero=stripper
+end
+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
+local patterns={} 
+local function containsws(what)
+ local p=patterns[what]
+ if not p then
+  local p1=P(what)*(whitespace+endofstring)*Cc(true)
+  local p2=whitespace*P(p1)
+  p=P(p1)+P(1-p2)^0*p2+Cc(false)
+  patterns[what]=p
+ end
+ return p
+end
+lpeg.containsws=containsws
+function string.containsws(str,what)
+ return lpegmatch(patterns[what] or containsws(what),str)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-function"] = package.loaded["l-function"] or true
+
+-- original size: 361, stripped down to: 317
+
+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 -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-string"] = package.loaded["l-string"] or true
+
+-- original size: 6955, stripped down to: 3504
+
+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,find=string.sub,string.gmatch,string.format,string.char,string.byte,string.rep,string.lower,string.find
+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
+ local i=1
+ local l=#pattern
+ while true do
+  i=find(str,pattern,i)
+  if i then
+   n=n+1
+   i=i+l
+  else
+   break
+  end
+ 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 nospacer=patterns.nospacer
+local longtostring=patterns.longtostring
+function string.strip(str)
+ return str and lpegmatch(stripper,str) or ""
+end
+function string.fullstrip(str)
+ return str and lpegmatch(fullstripper,str) or ""
+end
+function string.collapsespaces(str)
+ return str and lpegmatch(collapser,str) or ""
+end
+function string.nospaces(str)
+ return str and lpegmatch(nospacer,str) or ""
+end
+function string.longtostring(str)
+ return str and lpegmatch(longtostring,str) or ""
+end
+local pattern=P(" ")^0*P(-1)
+function string.is_empty(str)
+ if not str or str=="" then
+  return true
+ else
+  return lpegmatch(pattern,str) and true or false
+ end
+end
+local anything=patterns.anything
+local moreescapes=Cc("%")*S(".-+%?()[]*$^{}")
+local allescapes=Cc("%")*S(".-+%?()[]*")   
+local someescapes=Cc("%")*S(".-+%()[]")  
+local matchescapes=Cc(".")*S("*?")     
+local pattern_m=Cs ((moreescapes+anything )^0 )
+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=="all" then
+  str=lpegmatch(pattern_m,str)
+ 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
+if not string.bytetable then 
+ local limit=5000 
+ function string.bytetable(str) 
+  local n=#str
+  if n>limit then
+   local t={ byte(str,1,limit) }
+   for i=limit+1,n do
+    t[i]=byte(str,i)
+   end
+   return t
+  else
+   return { byte(str,1,n) }
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-table"] = package.loaded["l-table"] or true
+
+-- original size: 41758, stripped down to: 22643
+
+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,select,rawget=type,next,tostring,tonumber,select,rawget
+local table,string=table,string
+local concat,sort=table.concat,table.sort
+local format,lower,dump=string.format,string.lower,string.dump
+local getmetatable,setmetatable=getmetatable,setmetatable
+local lpegmatch,patterns=lpeg.match,lpeg.patterns
+local floor=math.floor
+local stripper=patterns.stripper
+function table.getn(t)
+ return t and #t 
+end
+function table.strip(tab)
+ local lst={}
+ local 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={}
+  local 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={}
+  local category=0 
+  local s=0
+  for key in next,tab do
+   s=s+1
+   srt[s]=key
+   if category~=3 then
+    local tkey=type(key)
+    if category==1 then
+     if tkey~="string" then
+      category=3
+     end
+    elseif category==2 then
+     if tkey~="number" then
+      category=3
+     end
+    else
+     if tkey=="string" then
+      category=1
+     elseif tkey=="number" then
+      category=2
+     else
+      category=3
+     end
+    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={}
+  local 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={}
+  local 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={}
+  local 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,...) 
+ if not t then
+  t={}
+ end
+ 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={}
+ local 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) 
+ if not tables then
+  tables={}
+ end
+ 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={}
+ local 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,metacheck,accurate
+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','const',
+}
+local function is_simple_table(t,hexify,accurate) 
+ 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=rawget(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
+     if hexify then
+      tt[i]=format("0x%X",v)
+     elseif accurate then
+      tt[i]=format("%q",v)
+     else
+      tt[i]=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
+  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
+     if hexify then
+      tt[i+1]=format("0x%X",v)
+     elseif accurate then
+      tt[i+1]=format("%q",v)
+     else
+      tt[i+1]=v 
+     end
+    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
+table.is_simple_table=is_simple_table
+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=nil
+  local last=0
+  if compact then
+   last=#root
+   for k=1,last do
+    if rawget(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))
+     elseif accurate then
+      handle(format("%s %q,",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=is_simple_table(v,hexify,accurate)
+      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))
+     elseif accurate then
+      handle(format("%s [%s]=%q,",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))
+     elseif accurate then
+      handle(format("%s [%s]=%q,",depth,k and "true" or "false",v))
+     else
+      handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) 
+     end
+    elseif tk~="string" then
+    elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
+     if hexify then
+      handle(format("%s %s=0x%X,",depth,k,v))
+     elseif accurate then
+      handle(format("%s %s=%q,",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))
+     elseif accurate then
+      handle(format("%s [%q]=%q,",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))
+     elseif accurate then
+      handle(format("%s [%q]=%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 tk~="string" then
+    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))
+      elseif accurate then
+       handle(format("%s [%q]={},",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 tk~="string" then
+     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=is_simple_table(v,hexify,accurate)
+     if st then
+      if tk=="number" then
+       if hexify then
+        handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", ")))
+       elseif accurate then
+        handle(format("%s [%q]={ %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 tk~="string" then
+      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"))
+     elseif accurate then
+      handle(format("%s [%q]=%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 tk~="string" then
+    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 getinfo=debug and debug.getinfo
+     if getinfo 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))
+       elseif accurate then
+        handle(format("%s [%q]=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 tk~="string" then
+      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
+    end
+   else
+    if tk=="number" then
+     if hexify then
+      handle(format("%s [0x%X]=%q,",depth,k,tostring(v)))
+     elseif accurate then
+      handle(format("%s [%q]=%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 tk~="string" then
+    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
+  accurate=specification.accurate
+  handle=_handle or specification.handle or print
+  functions=specification.functions
+  compact=specification.compact
+  inline=specification.inline and compact
+  metacheck=specification.metacheck
+  if functions==nil then
+   functions=true
+  end
+  if compact==nil then
+   compact=true
+  end
+  if inline==nil then
+   inline=compact
+  end
+  if metacheck==nil then
+   metacheck=true
+  end
+ else
+  noquotes=false
+  hexify=false
+  handle=_handle or print
+  compact=true
+  inline=true
+  functions=true
+  metacheck=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 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
+  if next(root)~=nil then
+   do_serialize(root,name,"",0)
+  end
+ end
+ handle("}")
+end
+function table.serialize(root,name,specification)
+ local t={}
+ local 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={}
+   local 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 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  
+table.collapsedhash=collapsedhash
+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==b then
+  return true
+ elseif a and b and #a==#b then
+  if not n then
+   n=1
+  end
+  if not m then
+   m=#a
+  end
+  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) 
+ if a~=b then
+  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
+ 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.hashed(t) 
+ for i=1,#t do
+  t[t[i]]=i
+ end
+ return t
+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={}
+  local 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
+  local m=n+1
+  for i=1,floor(n/2) do 
+   local j=m-i
+   t[i],t[j]=t[j],t[i]
+  end
+  return t
+ end
+end
+local function sequenced(t,sep,simple)
+ if not t then
+  return ""
+ elseif type(t)~="table" then
+  return t 
+ end
+ local n=#t
+ local s={}
+ if n>0 then
+  for i=1,n do
+   local v=t[i]
+   if type(v)=="table" then
+    s[i]="{"..sequenced(v,sep,simple).."}"
+   else
+    s[i]=tostring(t[i])
+   end
+  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
+     if type(v)=="table" then
+      s[n]=k.."={"..sequenced(v,sep,simple).."}"
+     else
+      s[n]=k.."="..tostring(v)
+     end
+    end
+   else
+    n=n+1
+    if type(v)=="table" then
+     s[n]=k.."={"..sequenced(v,sep,simple).."}"
+    else
+     s[n]=k.."="..tostring(v)
+    end
+   end
+  end
+ end
+ if sep==true then
+  return "{ "..concat(s,", ").." }"
+ else
+  return concat(s,sep or " | ")
+ end
+end
+table.sequenced=sequenced
+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={}
+  local keys={}
+  local 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
+if not table.move then
+ function table.move(a1,f,e,t,a2)
+  if a2 and a1~=a2 then
+   for i=f,e do
+    a2[t]=a1[i]
+    t=t+1
+   end
+   return a2
+  else
+   t=t+e-f
+   for i=e,f,-1 do
+    a1[t]=a1[i]
+    t=t-1
+   end
+   return a1
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-io"] = package.loaded["l-io"] or true
+
+-- original size: 11988, stripped down to: 6430
+
+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 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 type=type
+if string.find(os.getenv("PATH") or "",";",1,true) then
+ io.fileseparator,io.pathseparator="\\",";"
+else
+ io.fileseparator,io.pathseparator="/",":"
+end
+local large=0x01000000 
+local medium=0x00100000 
+local small=0x00020000
+local function readall(f)
+ local size=f:seek("end")
+ if size>0 then
+  f:seek("set",0)
+  return f:read(size)
+ else
+  return ""
+ end
+end
+io.readall=readall
+function io.loaddata(filename,textmode) 
+ local f=open(filename,(textmode and 'r') or 'rb')
+ if f then
+  local size=f:seek("end")
+  local data=nil
+  if size>0 then
+   f:seek("set",0)
+   data=f:read(size)
+  end
+  f:close()
+  return data
+ 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
+    f:seek("set",0)
+    local data=f:read(size)
+    if action then
+     data=action(data)
+    end
+    if data then
+     g:write(data)
+    end
+   end
+   g:close()
+  end
+  f:close()
+  flush()
+ end
+end
+function io.savedata(filename,data,joiner,append)
+ local f=open(filename,append and "ab" or "wb")
+ if f then
+  if append and joiner and f:seek("end")>0 then
+   f:write(joiner)
+  end
+  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()
+  flush()
+  return true
+ else
+  return false
+ end
+end
+if fio and fio.readline then
+ local readline=fio.readline
+ function io.loadlines(filename,n) 
+  local f=open(filename,'r')
+  if not f then
+  elseif n then
+   local lines={}
+   for i=1,n do
+    local line=readline(f)
+    if line then
+     lines[i]=line
+    else
+     break
+    end
+   end
+   f:close()
+   lines=concat(lines,"\n")
+   if #lines>0 then
+    return lines
+   end
+  else
+   local line=readline(f)
+   f:close()
+   if line and #line>0 then
+    return line
+   end
+  end
+ end
+else
+ function io.loadlines(filename,n) 
+  local f=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[i]=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
+end
+function io.loadchunk(filename,n)
+ local f=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=open(filename)
+ if f==nil then
+  return false
+ else
+  f:close()
+  return true
+ end
+end
+function io.size(filename)
+ local f=open(filename)
+ if f==nil then
+  return 0
+ else
+  local s=f:seek("end")
+  f:close()
+  return s
+ end
+end
+local function noflines(f)
+ if type(f)=="string" then
+  local f=open(filename)
+  if f then
+   local n=f and 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
+io.noflines=noflines
+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
+  write(question)
+  if options then
+   write(format(" [%s]",concat(options,"|")))
+  end
+  if default then
+   write(format(" [%s]",default))
+  end
+  write(format(" "))
+  flush()
+  local answer=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 0x100*a+b
+ elseif n==3 then
+  local a,b,c=byte(f:read(3),1,3)
+  return 0x10000*a+0x100*b+c
+ elseif n==4 then
+  local a,b,c,d=byte(f:read(4),1,4)
+  return 0x1000000*a+0x10000*b+0x100*c+d
+ elseif n==8 then
+  local a,b=readnumber(f,4),readnumber(f,4)
+  return 0x100*a+b
+ elseif n==12 then
+  local a,b,c=readnumber(f,4),readnumber(f,4),readnumber(f,4)
+  return 0x10000*a+0x100*b+c
+ elseif n==-2 then
+  local b,a=byte(f:read(2),1,2)
+  return 0x100*a+b
+ elseif n==-3 then
+  local c,b,a=byte(f:read(3),1,3)
+  return 0x10000*a+0x100*b+c
+ elseif n==-4 then
+  local d,c,b,a=byte(f:read(4),1,4)
+  return 0x1000000*a+0x10000*b+0x100*c+d
+ elseif n==-8 then
+  local h,g,f,e,d,c,b,a=byte(f:read(8),1,8)
+  return 0x100000000000000*a+0x1000000000000*b+0x10000000000*c+0x100000000*d+0x1000000*e+0x10000*f+0x100*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 -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-number"] = package.loaded["l-number"] or true
+
+-- original size: 4588, stripped down to: 2159
+
+if not modules then modules={} end modules ['l-number']={
+ version=1.001,
+ comment="companion to luat-lib.mkxl",
+ 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,match,rep=string.format,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
+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,w)
+  if not w then
+   w=32
+  end
+  local n=w
+  for i=0,w-1 do
+   local v=bextract(b,i)
+   local k=w-i
+   if v==1 then
+    n=k
+    t[k]="1"
+   else
+    t[k]="0"
+   end
+  end
+  if w then
+   return concat(t,"",1,w)
+  elseif m then
+   m=33-m*8
+   if m<1 then
+    m=1
+   end
+   return concat(t,"",1,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
+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
+function number.idiv(i,d)
+ return floor(i/d) 
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-set"] = package.loaded["l-set"] or true
+
+-- original size: 1923, stripped down to: 1044
+
+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 -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-os"] = package.loaded["l-os"] or true
+
+-- original size: 20585, stripped down to: 10701
+
+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,difftime=os.date,os.time,os.difftime
+local find,format,gsub,upper,gmatch=string.find,string.format,string.gsub,string.upper,string.gmatch
+local concat=table.concat
+local random,ceil,randomseed,modf=math.random,math.ceil,math.randomseed,math.modf
+local type,setmetatable,tonumber,tostring=type,setmetatable,tonumber,tostring
+do
+ local selfdir=os.selfdir
+ if selfdir=="" then
+  selfdir=nil
+ end
+ if not selfdir then
+  if arg then
+   for i=1,#arg do
+    local a=arg[i]
+    if find(a,"^%-%-[c:]*texmfbinpath=") then
+     selfdir=gsub(a,"^.-=","")
+     break
+    end
+   end
+  end
+  if not selfdir then
+   selfdir=os.selfbin or "luatex"
+   if find(selfdir,"[/\\]") then
+    selfdir=gsub(selfdir,"[/\\][^/\\]*$","")
+   elseif os.getenv then
+    local path=os.getenv("PATH")
+    local name=gsub(selfdir,"^.*[/\\][^/\\]","")
+    local patt="[^:]+"
+    if os.type=="windows" then
+     patt="[^;]+"
+     name=name..".exe"
+    end
+    local isfile
+    if lfs then
+     local attributes=lfs.attributes
+     isfile=function(name)
+      local a=attributes(name,"mode")
+      return a=="file" or a=="link" or nil
+     end
+    else
+     local open=io.open
+     isfile=function(name)
+      local f=open(name)
+      if f then
+       f:close()
+       return true
+      end
+     end
+    end
+    for p in gmatch(path,patt) do
+     if isfile(p.."/"..name) then
+      selfdir=p
+      break
+     end
+    end
+   end
+  end
+  os.selfdir=selfdir or "."
+ end
+end
+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
+if not io.fileseparator then
+ if find(os.getenv("PATH"),";",1,true) then
+  io.fileseparator,io.pathseparator,os.type="\\",";",os.type or "windows"
+ 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
+do
+ local execute=os.execute
+ local iopopen=io.popen
+ local ostype=os.type
+ local function resultof(command)
+  local handle=iopopen(command,ostype=="windows" and "rb" or "r")
+  if handle then
+   local result=handle:read("*all") or ""
+   handle:close()
+   return result
+  else
+   return ""
+  end
+ end
+ os.resultof=resultof
+ function os.pipeto(command)
+  return iopopen(command,"w") 
+ end
+ local launchers={
+  windows="start %s",
+  macosx="open %s",
+  unix="xdg-open %s &> /dev/null &",
+ }
+ function os.launch(str)
+  local command=format(launchers[os.name] or launchers.unix,str)
+  execute(command)
+ end
+end
+do
+ local gettimeofday=os.gettimeofday or os.clock
+ os.gettimeofday=gettimeofday
+ local startuptime=gettimeofday()
+ function os.runtime()
+  return gettimeofday()-startuptime
+ end
+end
+do
+ local name=os.name or "linux"
+ local platform=os.getenv("MTX_PLATFORM") or ""
+ local architecture=os.uname and os.uname().machine 
+ local bits=os.getenv("MTX_BITS") or find(platform,"64") and 64 or 32
+ if platform~="" then
+ elseif os.type=="windows" then
+  architecture=string.lower(architecture or os.getenv("PROCESSOR_ARCHITECTURE") or "")
+  if architecture=="x86_64" then
+   bits,platform=64,"win64"
+  elseif find(architecture,"amd64") then
+   bits,platform=64,"win64"
+  elseif find(architecture,"arm64") then
+   bits,platform=64,"windows-arm64"
+  elseif find(architecture,"arm32") then
+   bits,platform=32,"windows-arm32"
+  else
+   bits,platform=32,"mswin"
+  end
+ elseif name=="linux" then
+  architecture=architecture or os.getenv("HOSTTYPE") or resultof("uname -m") or ""
+  local musl=find(os.selfdir or "","linuxmusl")
+  if find(architecture,"x86_64") then
+   bits,platform=64,musl and "linuxmusl" or "linux-64"
+  elseif find(architecture,"ppc") then
+   bits,platform=32,"linux-ppc" 
+  else
+   bits,platform=32,musl and "linuxmusl" or "linux"
+  end
+ elseif name=="macosx" then
+  architecture=architecture or resultof("echo $HOSTTYPE") or ""
+  if architecture=="" then
+   bits,platform=64,"osx-intel"
+  elseif find(architecture,"i386") then
+   bits,platform=64,"osx-intel"
+  elseif find(architecture,"x86_64") then
+   bits,platform=64,"osx-64"
+  elseif find(architecture,"arm64") then
+   bits,platform=64,"osx-arm"
+  else
+   bits,platform=32,"osx-ppc"
+  end
+ elseif name=="sunos" then
+  architecture=architecture or resultof("uname -m") or ""
+  if find(architecture,"sparc") then
+   bits,platform=32,"solaris-sparc"
+  else 
+   bits,platform=32,"solaris-intel"
+  end
+ elseif name=="freebsd" then
+  architecture=architecture or os.getenv("MACHTYPE") or resultof("uname -m") or ""
+  if find(architecture,"amd64") or find(architecture,"AMD64") then
+   bits,platform=64,"freebsd-amd64"
+  else
+   bits,platform=32,"freebsd"
+  end
+ elseif name=="kfreebsd" then
+  architecture=architecture or os.getenv("HOSTTYPE") or resultof("uname -m") or ""
+  if architecture=="x86_64" then
+   bits,platform=64,"kfreebsd-amd64"
+  else
+   bits,platform=32,"kfreebsd-i386"
+  end
+ else
+  architecture=architecture or resultof("uname -m") or ""
+  if find(architecture,"aarch64") then
+   bits,platform="linux-aarch64"
+  elseif find(architecture,"armv7l") then
+   bits,platform=32,"linux-armhf"
+  elseif find(architecture,"mips64") or find(architecture,"mips64el") then
+   bits,platform=64,"linux-mipsel"
+  elseif find(architecture,"mipsel") or find(architecture,"mips") then
+   bits,platform=32,"linux-mipsel"
+  else
+   bits,platform=64,"linux-64" 
+  end
+ end
+ os.setenv("MTX_PLATFORM",platform)
+ os.setenv("MTX_BITS",bits)
+ os.platform=platform
+ os.bits=bits
+ os.newline=name=="windows" and "\013\010" or "\010" 
+end
+do
+ 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
+end
+do
+ local hour,min
+ function os.timezone(difference)
+  if not hour then
+   local current=time()
+   local utcdate=date("!*t",current)
+   local localdate=date("*t",current)
+   localdate.isdst=false
+   local timediff=difftime(time(localdate),time(utcdate))
+   hour,min=modf(timediff/3600)
+   min=min*60
+  end
+  if difference then
+   return hour,min
+  else
+   return format("%+03d:%02d",hour,min) 
+  end
+ end
+ local timeformat=format("%%s%s",os.timezone())
+ 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
+ function os.today()
+  return date("!*t")
+ end
+ function os.now()
+  return date("!%Y-%m-%d %H:%M:%S")
+ end
+end
+do
+ local cache={}
+ local function which(filename)
+  local fullname=cache[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
+   cache[filename]=fullname
+  end
+  return fullname
+ end
+ os.which=which
+ os.where=which
+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
+do
+ local function isleapyear(year)
+  return (year%4==0) and (year%100~=0 or year%400==0)
+ end
+ os.isleapyear=isleapyear
+ local days={ 31,28,31,30,31,30,31,31,30,31,30,31 }
+ local function nofdays(year,month,day)
+  if not month then
+   return isleapyear(year) and 365 or 364
+  elseif not day then
+   return month==2 and isleapyear(year) and 29 or days[month]
+  else
+   for i=1,month-1 do
+    day=day+days[i]
+   end
+   if month>2 and isleapyear(year) then
+    day=day+1
+   end
+   return day
+  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
+ function os.date(fmt,...)
+  if not fmt then
+   fmt="%Y-%m-%d %H:%M"
+  end
+  return date(fmt,...)
+ end
+end
+do
+ local osexit=os.exit
+ local exitcode=nil
+ function os.setexitcode(code)
+  exitcode=code
+ end
+ function os.exit(c)
+  if exitcode~=nil then
+   return osexit(exitcode)
+  end
+  if c~=nil then
+   return osexit(c)
+  end
+  return osexit()
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-file"] = package.loaded["l-file"] or true
+
+-- original size: 22186, stripped down to: 10313
+
+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 attributes=lfs.attributes
+function lfs.isdir(name)
+ if name then
+  return attributes(name,"mode")=="directory"
+ end
+end
+function lfs.isfile(name)
+ if name then
+  local a=attributes(name,"mode")
+  return a=="file" or a=="link" or nil
+ end
+end
+function lfs.isfound(name)
+ if name then
+  local a=attributes(name,"mode")
+  return (a=="file" or a=="link") and name or nil
+ end
+end
+function lfs.modification(name)
+ return name and attributes(name,"modification") or nil
+end
+if sandbox then
+ sandbox.redefine(lfs.isfile,"lfs.isfile")
+ sandbox.redefine(lfs.isdir,"lfs.isdir")
+ sandbox.redefine(lfs.isfound,"lfs.isfound")
+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
+if lfs.isreadablefile and lfs.iswritablefile then
+ file.is_readable=lfs.isreadablefile
+ file.is_writable=lfs.iswritablefile
+else
+ 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
+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(reslasher,one)
+ end
+ if not one or 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
+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=loaddata(oldname)
+  if data and data~="" then
+   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
+function file.withinbase(path) 
+ local l=0
+ if not find(path,"^/") then
+  path="/"..path
+ end
+ for dir in gmatch(path,"/([^/]+)") do
+  if dir==".." then
+   l=l-1
+  elseif dir~="." then
+   l=l+1
+  end
+  if l<0 then
+   return false
+  end
+ end
+ return true
+end
+local symlinkattributes=lfs.symlinkattributes
+function lfs.readlink(name)
+ return symlinkattributes(name,"target") or nil
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-gzip"] = package.loaded["l-gzip"] or true
+
+-- original size: 268, stripped down to: 216
+
+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"
+}
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-md5"] = package.loaded["l-md5"] or true
+
+-- original size: 3414, stripped down to: 2307
+
+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
+local modification,isfile,touch=lfs.modification,lfs.isfile,lfs.touch
+local loaddata,savedata=io.loaddata,io.savedata
+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
+  md5.sumhexa=md5.hex
+  md5.sumHEXA=md5.HEX
+ end
+end
+local md5HEX=md5.HEX
+function file.needsupdating(oldname,newname,threshold) 
+ local oldtime=modification(oldname)
+ if oldtime then
+  local newtime=modification(newname)
+  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=modification(oldname)
+ if oldtime and isfile(newname) then
+  touch(newname,oldtime,oldtime)
+ end
+end
+local function checksum(name)
+ if md5 then
+  local data=loaddata(name)
+  if data then
+   return md5HEX(data)
+  end
+ end
+ return nil
+end
+file.checksum=checksum
+function file.loadchecksum(name)
+ if md5 then
+  local data=loaddata(name..".md5")
+  return data and (gsub(data,"%s",""))
+ end
+ return nil
+end
+function file.savechecksum(name,checksum)
+ if not checksum then checksum=checksum(name) end
+ if checksum then
+  savedata(name..".md5",checksum)
+  return checksum
+ end
+ return nil
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-sha"] = package.loaded["l-sha"] or true
+
+-- original size: 1085, stripped down to: 969
+
+if not modules then modules={} end modules ['l-sha']={
+ 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"
+}
+if sha2 then
+ local lpegmatch=lpeg.match
+ local lpegpatterns=lpeg.patterns
+ local bytestohex=lpegpatterns.bytestohex
+ local bytestoHEX=lpegpatterns.bytestoHEX
+ local digest256=sha2.digest256
+ local digest384=sha2.digest384
+ local digest512=sha2.digest512
+ sha2.hash256=function(str) return lpegmatch(bytestohex,digest256(str)) end
+ sha2.hash384=function(str) return lpegmatch(bytestohex,digest384(str)) end
+ sha2.hash512=function(str) return lpegmatch(bytestohex,digest512(str)) end
+ sha2.HASH256=function(str) return lpegmatch(bytestoHEX,digest256(str)) end
+ sha2.HASH384=function(str) return lpegmatch(bytestoHEX,digest384(str)) end
+ sha2.HASH512=function(str) return lpegmatch(bytestoHEX,digest512(str)) end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-url"] = package.loaded["l-url"] or true
+
+-- original size: 14713, stripped down to: 6981
+
+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,next=tonumber,type,next
+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
+local sortedhash=table.sortedhash
+url=url or {}
+local url=url
+local unescapes={}
+local escapes={}
+setmetatable(unescapes,{ __index=function(t,k)
+ local v=char(tonumber(k,16))
+ t[k]=v
+ return v
+end })
+setmetatable(escapes,{ __index=function(t,k)
+ local v=format("%%%02X",byte(k))
+ t[k]=v
+ return v
+end })
+local colon=P(":")
+local qmark=P("?")
+local hash=P("#")
+local slash=P("/")
+local atsign=P("@")
+local percent=P("%")
+local endofstring=P(-1)
+local hexdigit=R("09","AF","af")
+local plus=P("+")
+local nothing=Cc("")
+local okay=R("09","AZ","az")+S("-_.,:=+*~!'()@&$")
+local escapedchar=(percent*C(hexdigit*hexdigit))/unescapes
+local unescapedchar=P(1)/escapes
+local escaped=(plus/" ")+escapedchar 
+local noslash=P("/")/""
+local plustospace=P("+")/" "
+local decoder=Cs((
+     plustospace+escapedchar+P("\r\n")/"\n"+P(1)
+    )^0 )
+local encoder=Cs((
+     R("09","AZ","az")^1+S("-./_")^1+P(" ")/"+"+P("\n")/"\r\n"+unescapedchar
+    )^0 )
+lpegpatterns.urldecoder=decoder
+lpegpatterns.urlencoder=encoder
+function url.decode  (str) return str and lpegmatch(decoder,str) or str end
+function url.encode  (str) return str and lpegmatch(encoder,str) or str end
+function url.unescape(str) return str and lpegmatch(unescaper,str) or str end
+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 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(((plustospace+escapedchar+1)-equal     )^0)
+local value=Cs(((plustospace+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 userpart=(1-atsign-colon)^1
+local serverpart=(1-colon)^1
+local splitauthority=((Cs(userpart)*colon*Cs(userpart)+Cs(userpart)*Cc(nil))*atsign+Cc(nil)*Cc(nil))*Cs(serverpart)*(colon*(serverpart/tonumber)+Cc(nil))
+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  
+ local username  
+ local password  
+ local host   
+ local port   
+ if authority~="" then
+  username,password,host,port=lpegmatch(splitauthority,authority)
+ end
+ 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,
+  host=host,
+  port=port,
+ }
+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 result,r={},0
+ local scheme=hash.scheme
+ local authority=hash.authority
+ local path=hash.path
+ local queries=hash.queries
+ local fragment=hash.fragment
+ if scheme and scheme~="" then
+  r=r+1;result[r]=lpegmatch(escaper,scheme)
+  r=r+1;result[r]="://"
+ end
+ if authority and authority~="" then
+  r=r+1;result[r]=lpegmatch(escaper,authority)
+ end
+ if path and path~="" then
+  r=r+1;result[r]="/"
+  r=r+1;result[r]=lpegmatch(escaper,path)
+ end
+ if queries then
+  local done=false
+  for k,v in sortedhash(queries) do
+   r=r+1;result[r]=done and "&" or "?"
+   r=r+1;result[r]=lpegmatch(escaper,k) 
+   r=r+1;result[r]="="
+   r=r+1;result[r]=lpegmatch(escaper,v) 
+   done=true
+  end
+ end
+ if fragment and fragment~="" then
+  r=r+1;result[r]="#"
+  r=r+1;result[r]=lpegmatch(escaper,fragment)
+ end
+ return concat(result)
+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 -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-dir"] = package.loaded["l-dir"] or true
+
+-- original size: 18217, stripped down to: 10792
+
+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
+  local nofdirs=0
+  for name,mode,size,time in walkdir(usedpath) do
+   if name~="." and name~=".." then
+    local full=path..name
+    if mode==nil then
+     mode=attributes(full,'mode')
+    end
+    if mode=='file' then
+     if not patt or find(full,patt) then
+      action(full,size,time)
+     end
+    elseif recurse and mode=="directory" then
+     if dirs then
+      nofdirs=nofdirs+1
+      dirs[nofdirs]=full
+     else
+      nofdirs=1
+      dirs={ full }
+     end
+    end
+   end
+  end
+  if dirs then
+   for i=1,nofdirs 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
+ local usedpath
+ if path=="/" then
+  usedpath="/."
+ elseif not find(path,"/$") then
+  usedpath=path.."/."
+  path=path.."/"
+ else
+  usedpath=path
+ end
+ local dirs
+ local nofdirs=0
+ local noffiles=#result
+ for name,mode in walkdir(usedpath) do
+  if name~="." and name~=".." then
+   local full=path..name
+   if mode==nil then
+    mode=attributes(full,'mode')
+   end
+   if mode=='file' then
+    if not patt or find(full,patt) then
+     noffiles=noffiles+1
+     result[noffiles]=full
+    end
+   elseif recurse and mode=="directory" then
+    if dirs then
+     nofdirs=nofdirs+1
+     dirs[nofdirs]=full
+    else
+     nofdirs=1
+     dirs={ full }
+    end
+   end
+  end
+ end
+ if dirs then
+  for i=1,nofdirs do
+   glob_pattern_table(dirs[i],patt,recurse,result)
+  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
+ local okay=isdir(path)
+ if kind=="function" then
+  return okay and glob_pattern_function(path,patt,recurse,method) or {}
+ elseif kind=="table" then
+  return okay and glob_pattern_table(path,patt,recurse,method) or method
+ else
+  return okay and glob_pattern_table(path,patt,recurse,{}) or {}
+ 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={
+  (Cs(P(".")+slash^1)+Cs(R("az","AZ")*P(":")*slash^0)+Cc("./"))*V(2)*V(3),
+  Cs(((1-S("*?/\\"))^0*slash)^0),
+  Cs(P(1)^0)
+ }
+else
+ pattern={
+  (C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3),
+  C(((1-S("*?/"))^0*P("/"))^0),
+  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,mode in walkdir(path) do
+  if find(name,"^%.") then
+  else
+   if mode==nil then
+    mode=attributes(name,'mode')
+   end
+   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
+local function globdirs(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,mode in walkdir(path) do
+  if find(name,"^%.") then
+  else
+   if mode==nil then
+    mode=attributes(name,'mode')
+   end
+   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
+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)
+ local curdir=currentdir()
+ insert(stack,curdir)
+ if newdir and newdir~="" and chdir(newdir) then
+  return newdir
+ else
+  return curdir
+ 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 -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-boolean"] = package.loaded["l-boolean"] or true
+
+-- original size: 1850, stripped down to: 1498
+
+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 -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-unicode"] = package.loaded["l-unicode"] or true
+
+-- original size: 41303, stripped down to: 17277
+
+if not modules then modules={} end modules ['l-unicode']={
+ version=1.001,
+ optimize=true,
+ 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=nil
+if not string.utfcharacters then
+ local gmatch=string.gmatch
+ function string.characters(str)
+  return gmatch(str,".[\128-\191]*")
+ end
+end
+utf.characters=string.utfcharacters
+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 p_utftype=patterns.utftype
+local p_utfstricttype=patterns.utfstricttype
+local p_utfoffset=patterns.utfoffset
+local p_utf8character=patterns.utf8character
+local p_utf8char=patterns.utf8char
+local p_utf8byte=patterns.utf8byte
+local p_utfbom=patterns.utfbom
+local p_newline=patterns.newline
+local p_whitespace=patterns.whitespace
+if not utf.char then
+ utf.char=string.utfcharacter or (utf8 and utf8.char)
+ if not utf.char then
+  local char=string.char
+  if bit32 then
+   local rshift=bit32.rshift
+   function utf.char(n)
+    if n<0x80 then
+     return char(n)
+    elseif n<0x800 then
+     return char(
+      0xC0+rshift(n,6),
+      0x80+(n%0x40)
+     )
+    elseif n<0x10000 then
+     return char(
+      0xE0+rshift(n,12),
+      0x80+(rshift(n,6)%0x40),
+      0x80+(n%0x40)
+     )
+    elseif n<0x200000 then
+     return char(
+      0xF0+rshift(n,18),
+      0x80+(rshift(n,12)%0x40),
+      0x80+(rshift(n,6)%0x40),
+      0x80+(n%0x40)
+     )
+    else
+     return ""
+    end
+   end
+  else
+   local floor=math.floor
+   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
+ end
+end
+if not utf.byte then
+ utf.byte=string.utfvalue or (utf8 and utf8.codepoint)
+ if not utf.byte then
+  function utf.byte(c)
+   return lpegmatch(p_utf8byte,c)
+  end
+ 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
+ utf.len=string.utflength or (utf8 and utf8.len)
+ 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
+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_utf8character,slide_zero)^0
+ local pattern_one=Cmt(p_utf8character,slide_one )^0
+ local pattern_two=Cmt(p_utf8character,slide_two )^0
+ local pattern_first=C(p_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_utf8character)^0)
+     end
+     return lpegmatch(pattern,str)
+    end
+   end
+  elseif option=="pattern" then
+   return Cs((tabletopattern(mapping)/action+p_utf8character)^0)
+  else
+   local pattern=Cs((tabletopattern(mapping)/action+p_utf8character)^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_utf8character/mapping+p_utf8character)^0)
+  else
+   local pattern=Cs((p_utf8character/mapping+p_utf8character)^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_utf8character)^0)
+local utfcharsplitter_iws=p_utfbom^-1*Ct((p_whitespace^1+C(p_utf8character))^0)
+local utfcharsplitter_raw=Ct(C(p_utf8character)^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
+if bit32 then
+ local rshift=bit32.rshift
+ local function little(b)
+  if b<0x10000 then
+   return char(b%256,rshift(b,8))
+  else
+   b=b-0x10000
+   local b1=rshift(b,10)+0xD800
+   local b2=b%1024+0xDC00
+   return char(b1%256,rshift(b1,8),b2%256,rshift(b2,8))
+  end
+ end
+ local function big(b)
+  if b<0x10000 then
+   return char(rshift(b,8),b%256)
+  else
+   b=b-0x10000
+   local b1=rshift(b,10)+0xD800
+   local b2=b%1024+0xDC00
+   return char(rshift(b1,8),b1%256,rshift(b2,8),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
+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
+do
+ local p_nany=p_utf8character/""
+ 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 string.utfvalues then
+ local find=string.find
+ local dummy=function()
+ end
+ function string.utfvalues(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
+end
+utf.values=string.utfvalues
+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
+if bit32 then
+ local extract=bit32.extract
+ local char=string.char
+ function utf.toutf32string(n)
+  if n<=0xFF then
+   return
+    char(n).."\000\000\000"
+  elseif n<=0xFFFF then
+   return
+    char(extract(n,0,8))..char(extract(n,8,8)).."\000\000"
+  elseif n<=0xFFFFFF then
+   return
+    char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8)).."\000"
+  else
+   return
+    char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8))..char(extract(n,24,8))
+  end
+ end
+end
+local len=utf.len
+local rep=rep
+function string.utfpadd(s,n)
+ if n and n~=0 then
+  local l=len(s)
+  if n>0 then
+   local d=n-l
+   if d>0 then
+    return rep(c or " ",d)..s
+   end
+  else
+   local d=- n-l
+   if d>0 then
+    return s..rep(c or " ",d)
+   end
+  end
+ end
+ return s
+end
+do
+ local utfcharacters=utf.characters or string.utfcharacters
+ local utfchar=utf.char    or string.utfcharacter
+ lpeg.UP=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
+ else
+  function lpeg.US(str)
+   local p=P(false)
+   local f=function(uc)
+    p=p+P(uc)
+   end
+   lpegmatch((p_utf8char/f)^0,str)
+   return p
+  end
+ end
+ local range=p_utf8byte*p_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)
+  end
+  if not utfchar then
+   utfchar=utf.char 
+  end
+  if 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 p_utf8byte/f 
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-math"] = package.loaded["l-math"] or true
+
+-- original size: 2679, stripped down to: 1909
+
+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"
+}
+if not math.ceiling then
+ math.ceiling=math.ceil
+end
+if not math.round then
+ if xmath then
+  math.round=xmath.round
+ else
+  local floor=math.floor
+  function math.round(x)
+   return x<0 and -floor(-x+0.5) or floor(x+0.5)
+  end
+ end
+end
+if not math.div then
+ local floor=math.floor
+ 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
+if not math.sind then
+ local sin,cos,tan=math.sin,math.cos,math.tan
+ local pipi=2*math.pi/360
+ 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
+if not math.cosh then
+ local exp=math.exp
+ function math.cosh(x)
+  local xx=exp(x)
+  return (xx+1/xx)/2
+ end
+ function math.sinh(x)
+  local xx=exp(x)
+  return (xx-1/xx)/2
+ end
+ function math.tanh(x)
+  local xx=exp(x)
+  return (xx-1/xx)/(xx+1/xx)
+ end
+end
+if not math.pow then
+ function math.pow(x,y)
+  return x^y
+ end
+end
+if not math.atan2 then
+ math.atan2=math.atan
+end
+if not math.ldexp then
+ function math.ldexp(x,e)
+  return x*2.0^e
+ end
+end
+if not math.log10 then
+ local log=math.log
+ function math.log10(x)
+  return log(x,10)
+ end
+end
+if not math.type then
+ function math.type()
+  return "float"
+ end
+end
+if not math.tointeger then
+ math.mininteger=-0x4FFFFFFFFFFF
+ math.maxinteger=0x4FFFFFFFFFFF
+ local floor=math.floor
+ function math.tointeger(n)
+  local f=floor(n)
+  return f==n and f or nil
+ end
+end
+if not math.ult then
+ local floor=math.floor
+ function math.ult(m,n)
+  return floor(m)<floor(n) 
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-str"] = package.loaded["util-str"] or true
+
+-- original size: 46322, stripped down to: 24128
+
+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,find,char=string.format,string.gsub,string.rep,string.sub,string.find,string.char
+local load,dump=load,string.dump
+local tonumber,type,tostring,next,setmetatable=tonumber,type,tostring,next,setmetatable
+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 tsplitat=lpeg.tsplitat
+local utfchar,utfbyte,utflen=utf.char,utf.byte,utf.len
+local 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
+if not number then number={} end 
+local stripzero=patterns.stripzero
+local stripzeros=patterns.stripzeros
+local newline=patterns.newline
+local endofstring=patterns.endofstring
+local anything=patterns.anything
+local whitespace=patterns.whitespace
+local space=patterns.space
+local spacer=patterns.spacer
+local spaceortab=patterns.spaceortab
+local digit=patterns.digit
+local sign=patterns.sign
+local period=patterns.period
+local ptf=1/65536
+local bpf=(7200/7227)/65536
+local function points(n)
+ if n==0 then
+  return "0pt"
+ end
+ n=tonumber(n)
+ if not n or n==0 then
+  return "0pt"
+ end
+ n=n*ptf
+ if n%1==0 then
+  return format("%ipt",n)
+ else
+  return lpegmatch(stripzeros,format("%.5fpt",n)) 
+ end
+end
+local function nupoints(n)
+ if n==0 then
+  return "0"
+ end
+ n=tonumber(n)
+ if not n or n==0 then
+  return "0"
+ end
+ n=n*ptf
+ if n%1==0 then
+  return format("%i",n)
+ else
+  return format("%.5f",n) 
+ end
+end
+local function basepoints(n)
+ if n==0 then
+  return "0bp"
+ end
+ n=tonumber(n)
+ if not n or n==0 then
+  return "0bp"
+ end
+ n=n*bpf
+ if n%1==0 then
+  return format("%ibp",n)
+ else
+  return lpegmatch(stripzeros,format("%.5fbp",n)) 
+ end
+end
+local function nubasepoints(n)
+ if n==0 then
+  return "0"
+ end
+ n=tonumber(n)
+ if not n or n==0 then
+  return "0"
+ end
+ n=n*bpf
+ if n%1==0 then
+  return format("%i",n)
+ else
+  return format("%.5f",n) 
+ end
+end
+number.points=points
+number.nupoints=nupoints
+number.basepoints=basepoints
+number.nubasepoints=nubasepoints
+local rubish=spaceortab^0*newline
+local anyrubish=spaceortab+newline
+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+anything
+  )^1)
+function strings.tabtospace(str,tab)
+ return lpegmatch(pattern,str,1,tab or 7)
+end
+function string.utfpadding(s,n)
+ if not n or n==0 then
+  return ""
+ end
+ local l=utflen(s)
+ if n>0 then
+  return nspaces[n-l]
+ else
+  return nspaces[-n-l]
+ end
+end
+local optionalspace=spacer^0
+local nospace=optionalspace/""
+local endofline=nospace*newline
+local stripend=(whitespace^1*endofstring)/""
+local normalline=(nospace*((1-optionalspace*(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 intospace=whitespace^1/" "
+local noleading=whitespace^1/""
+local notrailing=noleading*endofstring
+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_prune_intospace=Cs (noleading*(notrailing+intospace+1     )^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,
+ ["prune and to space"]=p_prune_intospace,
+ ["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
+function strings.collapse(str) 
+ return str and lpegmatch(p_prune_intospace,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 two=digit*digit
+local three=two*digit
+local prefix=(Carg(1)*three)^1
+local splitter=Cs (
+ (((1-(three^1*period))^1+C(three))*prefix+C((1-period)^1))*(anything/""*Carg(2))*C(2)
+)
+local splitter3=Cs (
+ three*prefix*endofstring+two*prefix*endofstring+digit*prefix*endofstring+three+two+digit
+)
+patterns.formattednumber=splitter
+function number.formatted(n,sep1,sep2)
+ if sep1==false then
+  if type(n)=="number" then
+   n=tostring(n)
+  end
+  return lpegmatch(splitter3,n,1,sep2 or ".")
+ else
+  if type(n)=="number" then
+   n=format("%0.2f",n)
+  end
+  if sep1==true then
+   return lpegmatch(splitter,n,1,".",",")
+  elseif sep1=="." then
+   return lpegmatch(splitter,n,1,sep1,sep2 or ",")
+  elseif sep1=="," then
+   return lpegmatch(splitter,n,1,sep1,sep2 or ".")
+  else
+   return lpegmatch(splitter,n,1,sep1 or ",",sep2 or ".")
+  end
+ end
+end
+local p=Cs(
+  P("-")^0*(P("0")^1/"")^0*(1-period)^0*(period*P("0")^1*endofstring/""+period^0)*P(1-P("0")^1*endofstring)^0
+ )
+function number.compactfloat(n,fmt)
+ if n==0 then
+  return "0"
+ elseif n==1 then
+  return "1"
+ end
+ n=lpegmatch(p,format(fmt or "%0.3f",n))
+ if n=="." or n=="" or n=="-" then
+  return "0"
+ end
+ return n
+end
+local zero=P("0")^1/""
+local plus=P("+")/""
+local minus=P("-")
+local separator=period
+local trailing=zero^1*#S("eE")
+local exponent=(S("eE")*(plus+Cs((minus*zero^0*endofstring)/"")+minus)*zero^0*(endofstring*Cc("0")+anything^1))
+local pattern_a=Cs(minus^0*digit^1*(separator/""*trailing+separator*(trailing+digit)^0)*exponent)
+local pattern_b=Cs((exponent+anything)^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 hf={}
+local hs={}
+setmetatable(hf,{ __index=function(t,k)
+ local v="%."..k.."f"
+ t[k]=v
+ return v
+end } )
+setmetatable(hs,{ __index=function(t,k)
+ local v="%"..k.."s"
+ t[k]=v
+ return v
+end } )
+function number.formattedfloat(n,b,a)
+ local s=format(hf[a],n)
+ local l=(b or 0)+(a or 0)+1
+ if #s<l then
+  return format(hs[l],s)
+ else
+  return s
+ end
+end
+local template=[[
+%s
+%s
+return function(%s) return %s end
+]]
+local pattern=Cs(Cc('"')*(
+ (1-S('"\\\n\r'))^1+P('"')/'\\"'+P('\\')/'\\\\'+P('\n')/'\\n'+P('\r')/'\\r'
+)^0*Cc('"'))
+patterns.escapedquotes=pattern
+function string.escapedquotes(s)
+ return lpegmatch(pattern,s)
+end
+local pattern=(1-P("\\"))^1;pattern=Cs (
+ pattern*((P("\\")/""*(digit^-3/function(s) return char(tonumber(s)) end))+pattern )^1
+)
+patterns.unescapedquotes=pattern
+function string.unescapedquotes(s)
+ return lpegmatch(pattern,s) or s
+end
+string.texnewlines=lpeg.replacer(patterns.newline,"\r",true)
+local preamble=""
+local 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,
+ nupoints=number.nupoints,
+ basepoints=number.basepoints,
+ nubasepoints=number.nubasepoints,
+ utfchar=utf.char,
+ utfbyte=utf.byte,
+ lpegmatch=lpeg.match,
+ nspaces=string.nspaces,
+ utfpadding=string.utfpadding,
+ tracedchar=string.tracedchar,
+ autosingle=string.autosingle,
+ autodouble=string.autodouble,
+ sequenced=table.sequenced,
+ formattednumber=number.formatted,
+ sparseexponent=number.sparseexponent,
+ formattedfloat=number.formattedfloat,
+ stripzero=patterns.stripzero,
+ stripzeros=patterns.stripzeros,
+ escapedquotes=string.escapedquotes,
+ FORMAT=string.f6,
+}
+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((sign+space+period+digit)^0)
+local prefix_sub=(C((sign+digit)^0)+Cc(0))*period*(C((sign+digit)^0)+Cc(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_right=function(f)
+ n=n+1
+ f=tonumber(f)
+ if not f or f==0 then
+  return format("(a%s or '')",n)
+ elseif f>0 then
+  return format("utfpadding(a%s,%i)..a%s",n,f,n)
+ else
+  return format("a%s..utfpadding(a%s,%i)",n,n,f)
+ end
+end
+local format_left=function(f)
+ n=n+1
+ f=tonumber(f)
+ if not f or f==0 then
+  return format("(a%s or '')",n)
+ end
+ if f<0 then
+  return format("utfpadding(a%s,%i)..a%s",n,-f,n)
+ else
+  return format("a%s..utfpadding(a%s,%i)",n,n,-f)
+ end
+end
+local format_q=JITSUPPORTED and function()
+ n=n+1
+ return format("(a%s ~= nil and format('%%q',tostring(a%s)) or '')",n,n)
+end or function()
+ n=n+1
+ return format("(a%s ~= nil and format('%%q',a%s) or '')",n,n)
+end
+local format_Q=function() 
+ n=n+1
+ return format("escapedquotes(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_k=function(b,a) 
+ n=n+1
+ return format("formattedfloat(a%s,%s,%s)",n,b or 0,a or 0)
+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_P=function()
+ n=n+1
+ return format("nupoints(a%s)",n)
+end
+local format_b=function()
+ n=n+1
+ return format("basepoints(a%s)",n)
+end
+local format_B=function()
+ n=n+1
+ return format("nubasepoints(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("((a%s %% 1 == 0) and format('%%i',a%s) or tostring(a%s))",n,n,n)
+end
+local format_N  if environment.FORMAT then
+ format_N=function(f)
+  n=n+1
+  if not f or f=="" then
+   return format("FORMAT(a%s,'%%.9f')",n)
+  elseif f==".6" or f=="0.6" then
+   return format("FORMAT(a%s)",n)
+  else
+   return format("FORMAT(a%s,'%%%sf')",n,f)
+  end
+ end
+else
+ format_N=function(f) 
+  n=n+1
+  if not f or f=="" then
+   f=".9"
+  end 
+  return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%%sf',a%s)))",n,n,f,n)
+ end
+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 format_m=function(f)
+ n=n+1
+ if not f or f=="" then
+  f=","
+ end
+ if f=="0" then
+  return format([[formattednumber(a%s,false)]],n)
+ else
+  return format([[formattednumber(a%s,%q,".")]],n,f)
+ end
+end
+local format_M=function(f)
+ n=n+1
+ if not f or f=="" then
+  f="."
+ end
+ if f=="0" then
+  return format([[formattednumber(a%s,false)]],n)
+ else
+  return format([[formattednumber(a%s,%q,",")]],n,f)
+ end
+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
+ 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) 
+ elseif f<0 then
+  if w then
+   extension=gsub(extension,"%.%.%.","")
+   return extension
+  else
+   local a="a"..(n+f+1)
+   return format(extension,a,a)
+  end
+ else
+  if w then
+   extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s")
+  end
+  local t={}
+  for i=1,f do
+   n=n+1
+   t[i]="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("N") 
++V("k")
++V("r")+V("h")+V("H")+V("u")+V("U")+V("p")+V("P")+V("b")+V("B")+V("t")+V("T")+V("l")+V("L")+V("I")+V("w") 
++V("W") 
++V("a") 
++V("A") 
++V("j")+V("J") 
++V("m")+V("M") 
++V("z")
++V(">") 
++V("<")
+   )+V("*")
+  )*(endofstring+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_Q,
+ ["n"]=(prefix_any*P("n"))/format_n,
+ ["N"]=(prefix_any*P("N"))/format_N,
+ ["k"]=(prefix_sub*P("k"))/format_k,
+ ["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,
+ ["P"]=(prefix_any*P("P"))/format_P,
+ ["b"]=(prefix_any*P("b"))/format_b,
+ ["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_any*P("m"))/format_m,
+ ["M"]=(prefix_any*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,
+ ["<"]=(prefix_any*P("<"))/format_left,
+ [">"]=(prefix_any*P(">"))/format_right,
+ ["*"]=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 xx=setmetatable({},{ __index=function(t,k) local v=format("%02x",k) t[k]=v return v end })
+local XX=setmetatable({},{ __index=function(t,k) local v=format("%02X",k) t[k]=v return v end })
+local preset={
+ ["%02x"]=function(n) return xx[n] end,
+ ["%02X"]=function(n) return XX[n] end,
+}
+local direct=P("%")*(sign+space+period+digit)^0*S("sqidfgGeExXo")*endofstring/[[local format = string.format return function(str) return format("%0",str) end]]
+local function make(t,str)
+ local f=preset[str]
+ if f then
+  return f
+ end
+ 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={}
+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
+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('"')/"""+anything)^0)
+patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+anything)^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('"'))
+add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape=patterns.xmlescape })
+add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=patterns.texescape })
+add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=patterns.luaescape })
+local dquote=patterns.dquote 
+local equote=patterns.escaped+dquote/'\\"'+1
+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
+function strings.newcollector()
+ local result,r={},0
+ return
+  function(fmt,str,...) 
+   r=r+1
+   result[r]=str==nil and fmt or formatters[fmt](str,...)
+  end,
+  function(connector) 
+   if result then
+    local str=concat(result,connector)
+    result,r={},0
+    return str
+   end
+  end
+end
+local f_16_16=formatters["%0.5N"]
+function number.to16dot16(n)
+ return f_16_16(n/65536.0)
+end
+if not string.explode then
+ local p_utf=patterns.utf8character
+ local p_check=C(p_utf)*(P("+")*Cc(true))^0
+ local p_split=Ct(C(p_utf)^0)
+ local p_space=Ct((C(1-P(" ")^1)+P(" ")^1)^0)
+ function string.explode(str,symbol)
+  if symbol=="" then
+   return lpegmatch(p_split,str)
+  elseif symbol then
+   local a,b=lpegmatch(p_check,symbol)
+   if b then
+    return lpegmatch(tsplitat(P(a)^1),str)
+   else
+    return lpegmatch(tsplitat(a),str)
+   end
+  else
+   return lpegmatch(p_space,str)
+  end
+ end
+end
+do
+ local p_whitespace=patterns.whitespace^1
+ local cache=setmetatable({},{ __index=function(t,k)
+  local p=tsplitat(p_whitespace*P(k)*p_whitespace)
+  local v=function(s)
+   return lpegmatch(p,s)
+  end
+  t[k]=v
+  return v
+ end })
+ function string.wordsplitter(s)
+  return cache[s]
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-tab"] = package.loaded["util-tab"] or true
+
+-- original size: 34148, stripped down to: 18419
+
+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,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
+local formatters=string.formatters
+local utftoeight=utf.toeight
+local splitter=lpeg.tsplitat(".")
+function utilities.tables.definetable(target,nofirst,nolast) 
+ local composed=nil
+ local t={}
+ 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 ","
+  local noffields=#fields
+  if specification.preamble==true then
+   for f=1,noffields 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,noffields do
+    local field=ti[fields[f]]
+    if type(field)=="string" then
+     r[f]=lpegmatch(escape,field)
+    else
+     r[f]=tostring(field)
+    end
+   end
+   result[i+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)
+ local r=#result
+ 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
+    r=r+1 result[r]=formatters["%s<entry n='%s'>"](s,k)
+    toxml(v,d+step,result,step)
+    r=r+1 result[r]=formatters["%s</entry>"](s,k)
+   else
+    r=r+1 result[r]=formatters["%s<%s>"](s,k)
+    toxml(v,d+step,result,step)
+    r=r+1 result[r]=formatters["%s</%s>"](s,k)
+   end
+  elseif tv=="string" then
+   if tk=="number" then
+    r=r+1 result[r]=formatters["%s<entry n='%s'>%!xml!</entry>"](s,k,v,k)
+   else
+    r=r+1 result[r]=formatters["%s<%s>%!xml!</%s>"](s,k,v,k)
+   end
+  elseif tk=="number" then
+   r=r+1 result[r]=formatters["%s<entry n='%s'>%S</entry>"](s,k,v,k)
+  else
+   r=r+1 result[r]=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
+if JITSUPPORTED then
+ 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
+    local v=t[0]
+    if v then
+     local tv=type(v)
+     if tv=="string" then
+      m=m+1 r[m]=f_indexed_string(0,v)
+     elseif tv=="number" then
+      m=m+1 r[m]=f_indexed_number(0,v)
+     elseif tv=="table" then
+      m=m+1 r[m]=f_indexed_table(0)
+      fastserialize(v)
+      m=m+1 r[m]=f_indexed_table(0)
+     elseif tv=="boolean" then
+      m=m+1 r[m]=f_indexed_boolean(0,v)
+     end
+    end
+    for i=1,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
+else
+ 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
+    local v=t[0]
+    if v then
+     m=m+1
+     r[m]="[0]="
+     if type(v)=="table" then
+      fastserialize(v)
+     else
+      r[m]=format("%q,",v)
+     end
+    end
+    for i=1,n do
+     local v=t[i]
+     m=m+1
+     if type(v)=="table" then
+      r[m]=format("[%i]=",i)
+      fastserialize(v)
+     else
+      r[m]=format("[%i]=%q,",i,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
+      m=m+1
+      if type(v)=="table" then
+       r[m]=format("[%i]=",k)
+       fastserialize(v)
+      else
+       r[m]=format("[%i]=%q,",k,v)
+      end
+     end
+    else
+     m=m+1
+     if type(v)=="table" then
+      r[m]=format("[%q]=",k)
+      fastserialize(v)
+     else
+      r[m]=format("[%q]=%q,",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
+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
+local selfmapper={ __index=function(t,k) t[k]=k return k end }
+function table.twowaymapper(t) 
+ if not t then     
+  t={}       
+ else        
+  local zero=rawget(t,0)  
+  for i=zero and 0 or 1,#t do
+   local ti=t[i]    
+   if ti then
+    local i=tostring(i)
+    t[i]=ti   
+    t[ti]=i    
+   end
+  end
+ end
+ setmetatable(t,selfmapper)
+ return t
+end
+local f_start_key_idx=formatters["%w{"]
+local f_start_key_num=JITSUPPORTED and formatters["%w[%s]={"] or formatters["%w[%q]={"]
+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=JITSUPPORTED and formatters["%w[%s]=%s,"] or formatters["%w[%s]=%q,"]
+local f_key_str_value_num=JITSUPPORTED and formatters["%w[%Q]=%s,"] or formatters["%w[%Q]=%q,"]
+local f_key_boo_value_num=JITSUPPORTED and formatters["%w[%l]=%s,"] or formatters["%w[%l]=%q,"]
+local f_key_num_value_str=JITSUPPORTED and formatters["%w[%s]=%Q,"] or formatters["%w[%q]=%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=JITSUPPORTED and formatters["%w[%s]=%l,"] or formatters["%w[%q]=%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=JITSUPPORTED and formatters["%w[%s]={},"] or formatters["%w[%q]={},"]
+local f_key_str_value_not=formatters["%w[%Q]={},"]
+local f_key_boo_value_not=formatters["%w[%l]={},"]
+local f_key_num_value_seq=JITSUPPORTED and formatters["%w[%s]={ %, t },"] or formatters["%w[%q]={ %, 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=JITSUPPORTED and formatters["%w%s,"] or formatters["%w%q,"]
+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 is_simple_table=table.is_simple_table
+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 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=#root
+   if last>0 then
+    for k=1,last do
+     if rawget(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 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=is_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=is_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=is_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",{ metacheck=false }))
+   return true
+  end
+ end)
+end
+local mt={
+ __newindex=function(t,k,v)
+  local n=t.last+1
+  t.last=n
+  t.list[n]=k
+  t.hash[k]=v
+ end,
+ __index=function(t,k)
+  return t.hash[k]
+ end,
+ __len=function(t)
+  return t.last
+ end,
+}
+function table.orderedhash()
+ return setmetatable({ list={},hash={},last=0 },mt)
+end
+function table.ordered(t)
+ local n=t.last
+ if n>0 then
+  local l=t.list
+  local i=1
+  local h=t.hash
+  local f=function()
+   if i<=n then
+    local k=i
+    local v=h[l[k]]
+    i=i+1
+    return k,v
+   end
+  end
+  return f,1,h[l[1]]
+ else
+  return function() end
+ end
+end
+function combine(target,source)
+ if target then
+  for k,v in next,source do
+   if type(v)=="table" then
+      target[k]=combine(target[k],source[k])
+   else
+      target[k]=v
+   end
+  end
+  return target
+ else
+  return source
+ end
+end
+table.combine=combine
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-fil"] = package.loaded["util-fil"] or true
+
+-- original size: 11474, stripped down to: 8973
+
+if not modules then modules={} end modules ['util-fil']={
+ version=1.001,
+ optimize=true,
+ 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 tonumber=tonumber
+local byte=string.byte
+local char=string.char
+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)
+ local current=f:seek()
+ local size=f:seek("end")
+ f:seek("set",current)
+ return size
+end
+files.getsize=files.size
+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.readbytetable(f,n)
+ local s=f:read(n or 1)
+ return { byte(s,1,#s) } 
+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-0x100
+ else
+  return n
+ end
+end
+files.readcardinal1=files.readbyte  
+files.readcardinal=files.readcardinal1
+files.readinteger=files.readinteger1
+files.readsignedbyte=files.readinteger1
+function files.readcardinal2(f)
+ 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)
+ if a>=0x80 then
+  return 0x100*a+b-0x10000
+ else
+  return 0x100*a+b
+ end
+end
+function files.readinteger2le(f)
+ local b,a=byte(f:read(2),1,2)
+ if a>=0x80 then
+  return 0x100*a+b-0x10000
+ else
+  return 0x100*a+b
+ 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)
+ if a>=0x80 then
+  return 0x10000*a+0x100*b+c-0x1000000
+ else
+  return 0x10000*a+0x100*b+c
+ end
+end
+function files.readinteger3le(f)
+ local c,b,a=byte(f:read(3),1,3)
+ if a>=0x80 then
+  return 0x10000*a+0x100*b+c-0x1000000
+ else
+  return 0x10000*a+0x100*b+c
+ 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)
+ if a>=0x80 then
+  return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000
+ else
+  return 0x1000000*a+0x10000*b+0x100*c+d
+ end
+end
+function files.readinteger4le(f)
+ local d,c,b,a=byte(f:read(4),1,4)
+ if a>=0x80 then
+  return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000
+ else
+  return 0x1000000*a+0x10000*b+0x100*c+d
+ end
+end
+function files.readfixed2(f)
+ local n1,n2=byte(f:read(2),1,2)
+ if n1>=0x80 then
+  n1=n1-0x100
+ end
+ return n1+n2/0xFF
+end
+function files.readfixed4(f)
+ local a,b,c,d=byte(f:read(4),1,4)
+ local n1=0x100*a+b
+ local n2=0x100*c+d
+ if n1>=0x8000 then
+  n1=n1-0x10000
+ end
+ return n1+n2/0xFFFF
+end
+if bit32 then
+ local extract=bit32.extract
+ local band=bit32.band
+ function files.read2dot14(f)
+  local a,b=byte(f:read(2),1,2)
+  if a>=0x80 then
+   local n=-(0x100*a+b)
+   return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0))
+  else
+   local n=0x100*a+b
+   return   (extract(n,14,2)+(band(n,0x3FFF)/16384.0))
+  end
+ 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
+if bit32 then
+ local rshift=bit32.rshift
+ function files.writecardinal2(f,n)
+  local a=char(n%256)
+  n=rshift(n,8)
+  local b=char(n%256)
+  f:write(b,a)
+ end
+ function files.writecardinal4(f,n)
+  local a=char(n%256)
+  n=rshift(n,8)
+  local b=char(n%256)
+  n=rshift(n,8)
+  local c=char(n%256)
+  n=rshift(n,8)
+  local d=char(n%256)
+  f:write(d,c,b,a)
+ end
+ function files.writecardinal2le(f,n)
+  local a=char(n%256)
+  n=rshift(n,8)
+  local b=char(n%256)
+  f:write(a,b)
+ end
+ function files.writecardinal4le(f,n)
+  local a=char(n%256)
+  n=rshift(n,8)
+  local b=char(n%256)
+  n=rshift(n,8)
+  local c=char(n%256)
+  n=rshift(n,8)
+  local d=char(n%256)
+  f:write(a,b,c,d)
+ end
+else
+ local floor=math.floor
+ 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.writecardinal2le(f,n)
+  local a=char(n%256)
+  n=floor(n/256)
+  local b=char(n%256)
+  f:write(a,b)
+ end
+ function files.writecardinal4le(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(a,b,c,d)
+ end
+end
+function files.writestring(f,s)
+ f:write(char(byte(s,1,#s)))
+end
+function files.writebyte(f,b)
+ f:write(char(b))
+end
+if fio and fio.readcardinal1 then
+ files.readcardinal1=fio.readcardinal1
+ files.readcardinal2=fio.readcardinal2
+ files.readcardinal3=fio.readcardinal3
+ files.readcardinal4=fio.readcardinal4
+ files.readcardinal1le=fio.readcardinal1le or files.readcardinal1le
+ files.readcardinal2le=fio.readcardinal2le or files.readcardinal2le
+ files.readcardinal3le=fio.readcardinal3le or files.readcardinal3le
+ files.readcardinal4le=fio.readcardinal4le or files.readcardinal4le
+ files.readinteger1=fio.readinteger1
+ files.readinteger2=fio.readinteger2
+ files.readinteger3=fio.readinteger3
+ files.readinteger4=fio.readinteger4
+ files.readinteger1le=fio.readinteger1le or files.readinteger1le
+ files.readinteger2le=fio.readinteger2le or files.readinteger2le
+ files.readinteger3le=fio.readinteger3le or files.readinteger3le
+ files.readinteger4le=fio.readinteger4le or files.readinteger4le
+ files.readfixed2=fio.readfixed2
+ files.readfixed4=fio.readfixed4
+ files.read2dot14=fio.read2dot14
+ files.setposition=fio.setposition
+ files.getposition=fio.getposition
+ files.readbyte=files.readcardinal1
+ files.readsignedbyte=files.readinteger1
+ files.readcardinal=files.readcardinal1
+ files.readinteger=files.readinteger1
+ local skipposition=fio.skipposition
+ files.skipposition=skipposition
+ files.readbytes=fio.readbytes
+ files.readbytetable=fio.readbytetable
+ function files.skipshort(f,n)
+  skipposition(f,2*(n or 1))
+ end
+ function files.skiplong(f,n)
+  skipposition(f,4*(n or 1))
+ end
+end
+if fio and fio.writecardinal1 then
+ files.writecardinal1=fio.writecardinal1
+ files.writecardinal2=fio.writecardinal2
+ files.writecardinal3=fio.writecardinal3
+ files.writecardinal4=fio.writecardinal4
+ files.writecardinal1le=fio.writecardinal1le
+ files.writecardinal2le=fio.writecardinal2le
+ files.writecardinal3le=fio.writecardinal3le
+ files.writecardinal4le=fio.writecardinal4le
+ files.writeinteger1=fio.writeinteger1 or fio.writecardinal1
+ files.writeinteger2=fio.writeinteger2 or fio.writecardinal2
+ files.writeinteger3=fio.writeinteger3 or fio.writecardinal3
+ files.writeinteger4=fio.writeinteger4 or fio.writecardinal4
+ files.writeinteger1le=files.writeinteger1le or fio.writecardinal1le
+ files.writeinteger2le=files.writeinteger2le or fio.writecardinal2le
+ files.writeinteger3le=files.writeinteger3le or fio.writecardinal3le
+ files.writeinteger4le=files.writeinteger4le or fio.writecardinal4le
+end
+if fio and fio.readcardinaltable then
+ files.readcardinaltable=fio.readcardinaltable
+ files.readintegertable=fio.readintegertable
+else
+ local readcardinal1=files.readcardinal1
+ local readcardinal2=files.readcardinal2
+ local readcardinal3=files.readcardinal3
+ local readcardinal4=files.readcardinal4
+ function files.readcardinaltable(f,n,b)
+  local t={}
+   if b==1 then for i=1,n do t[i]=readcardinal1(f) end
+  elseif b==2 then for i=1,n do t[i]=readcardinal2(f) end
+  elseif b==3 then for i=1,n do t[i]=readcardinal3(f) end
+  elseif b==4 then for i=1,n do t[i]=readcardinal4(f) end end
+  return t
+ end
+ local readinteger1=files.readinteger1
+ local readinteger2=files.readinteger2
+ local readinteger3=files.readinteger3
+ local readinteger4=files.readinteger4
+ function files.readintegertable(f,n,b)
+  local t={}
+   if b==1 then for i=1,n do t[i]=readinteger1(f) end
+  elseif b==2 then for i=1,n do t[i]=readinteger2(f) end
+  elseif b==3 then for i=1,n do t[i]=readinteger3(f) end
+  elseif b==4 then for i=1,n do t[i]=readinteger4(f) end end
+  return t
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-sac"] = package.loaded["util-sac"] or true
+
+-- original size: 14071, stripped down to: 10417
+
+if not modules then modules={} end modules ['util-sac']={
+ version=1.001,
+ optimize=true,
+ 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,sub=string.byte,string.sub
+local tonumber=tonumber
+utilities=utilities or {}
+local streams={}
+utilities.streams=streams
+function streams.open(filename,zerobased)
+ local f=filename and io.loaddata(filename)
+ if f then
+  return { f,1,#f,zerobased or false }
+ end
+end
+function streams.openstring(f,zerobased)
+ if f then
+  return { f,1,#f,zerobased or false }
+ end
+end
+function streams.getstring(f)
+ if f then
+  return f[1]
+ end
+end
+function streams.close()
+end
+function streams.size(f)
+ return f and f[3] or 0
+end
+streams.getsize=streams.size
+function streams.setposition(f,i)
+ if f[4] then
+  if i<=0 then
+   f[2]=1
+  else
+   f[2]=i+1
+  end
+ else
+  if i<=1 then
+   f[2]=1
+  else
+   f[2]=i
+  end
+ end
+end
+function streams.getposition(f)
+ if f[4] then
+  return f[2]-1
+ else
+  return f[2]
+ end
+end
+function streams.look(f,n,chars)
+ local b=f[2]
+ local e=b+n-1
+ if chars then
+  return sub(f[1],b,e)
+ else
+  return byte(f[1],b,e)
+ end
+end
+function streams.skip(f,n)
+ f[2]=f[2]+n
+end
+function streams.readbyte(f)
+ local i=f[2]
+ f[2]=i+1
+ return byte(f[1],i)
+end
+function streams.readbytes(f,n)
+ local i=f[2]
+ local j=i+n
+ f[2]=j
+ return byte(f[1],i,j-1)
+end
+function streams.readbytetable(f,n)
+ local i=f[2]
+ local j=i+n
+ f[2]=j
+ return { byte(f[1],i,j-1) }
+end
+function streams.skipbytes(f,n)
+ f[2]=f[2]+n
+end
+function streams.readchar(f)
+ local i=f[2]
+ f[2]=i+1
+ return sub(f[1],i,i)
+end
+function streams.readstring(f,n)
+ local i=f[2]
+ local j=i+n
+ f[2]=j
+ return sub(f[1],i,j-1)
+end
+function streams.readinteger1(f)  
+ local i=f[2]
+ f[2]=i+1
+ local n=byte(f[1],i)
+ if n>=0x80 then
+  return n-0x100
+ else
+  return n
+ end
+end
+streams.readcardinal1=streams.readbyte  
+streams.readcardinal=streams.readcardinal1
+streams.readinteger=streams.readinteger1
+function streams.readcardinal2(f)
+ local i=f[2]
+ local j=i+1
+ f[2]=j+1
+ local a,b=byte(f[1],i,j)
+ return 0x100*a+b
+end
+function streams.readcardinal2le(f)
+ local i=f[2]
+ local j=i+1
+ f[2]=j+1
+ local b,a=byte(f[1],i,j)
+ return 0x100*a+b
+end
+function streams.readinteger2(f)
+ local i=f[2]
+ local j=i+1
+ f[2]=j+1
+ local a,b=byte(f[1],i,j)
+ if a>=0x80 then
+  return 0x100*a+b-0x10000
+ else
+  return 0x100*a+b
+ end
+end
+function streams.readinteger2le(f)
+ local i=f[2]
+ local j=i+1
+ f[2]=j+1
+ local b,a=byte(f[1],i,j)
+ if a>=0x80 then
+  return 0x100*a+b-0x10000
+ else
+  return 0x100*a+b
+ end
+end
+function streams.readcardinal3(f)
+ local i=f[2]
+ local j=i+2
+ f[2]=j+1
+ local a,b,c=byte(f[1],i,j)
+ return 0x10000*a+0x100*b+c
+end
+function streams.readcardinal3le(f)
+ local i=f[2]
+ local j=i+2
+ f[2]=j+1
+ local c,b,a=byte(f[1],i,j)
+ return 0x10000*a+0x100*b+c
+end
+function streams.readinteger3(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local a,b,c=byte(f[1],i,j)
+ if a>=0x80 then
+  return 0x10000*a+0x100*b+c-0x1000000
+ else
+  return 0x10000*a+0x100*b+c
+ end
+end
+function streams.readinteger3le(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local c,b,a=byte(f[1],i,j)
+ if a>=0x80 then
+  return 0x10000*a+0x100*b+c-0x1000000
+ else
+  return 0x10000*a+0x100*b+c
+ end
+end
+function streams.readcardinal4(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local a,b,c,d=byte(f[1],i,j)
+ return 0x1000000*a+0x10000*b+0x100*c+d
+end
+function streams.readcardinal4le(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local d,c,b,a=byte(f[1],i,j)
+ return 0x1000000*a+0x10000*b+0x100*c+d
+end
+function streams.readinteger4(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local a,b,c,d=byte(f[1],i,j)
+ if a>=0x80 then
+  return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000
+ else
+  return 0x1000000*a+0x10000*b+0x100*c+d
+ end
+end
+function streams.readinteger4le(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local d,c,b,a=byte(f[1],i,j)
+ if a>=0x80 then
+  return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000
+ else
+  return 0x1000000*a+0x10000*b+0x100*c+d
+ end
+end
+function streams.readfixed2(f)
+ local i=f[2]
+ local j=i+1
+ f[2]=j+1
+ local n1,n2=byte(f[1],i,j)
+ if n1>=0x80 then
+  n1=n1-0x100
+ end
+ return n1+n2/0xFF
+end
+function streams.readfixed4(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local a,b,c,d=byte(f[1],i,j)
+ local n1=0x100*a+b
+ local n2=0x100*c+d
+ if n1>=0x8000 then
+  n1=n1-0x10000
+ end
+ return n1+n2/0xFFFF
+end
+if bit32 then
+ local extract=bit32.extract
+ local band=bit32.band
+ function streams.read2dot14(f)
+  local i=f[2]
+  local j=i+1
+  f[2]=j+1
+  local a,b=byte(f[1],i,j)
+  if a>=0x80 then
+   local n=-(0x100*a+b)
+   return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0))
+  else
+   local n=0x100*a+b
+   return   (extract(n,14,2)+(band(n,0x3FFF)/16384.0))
+  end
+ end
+end
+function streams.skipshort(f,n)
+ f[2]=f[2]+2*(n or 1)
+end
+function streams.skiplong(f,n)
+ f[2]=f[2]+4*(n or 1)
+end
+if sio and sio.readcardinal2 then
+ local readcardinal1=sio.readcardinal1
+ local readcardinal2=sio.readcardinal2
+ local readcardinal3=sio.readcardinal3
+ local readcardinal4=sio.readcardinal4
+ local readinteger1=sio.readinteger1
+ local readinteger2=sio.readinteger2
+ local readinteger3=sio.readinteger3
+ local readinteger4=sio.readinteger4
+ local readfixed2=sio.readfixed2
+ local readfixed4=sio.readfixed4
+ local read2dot14=sio.read2dot14
+ local readbytes=sio.readbytes
+ local readbytetable=sio.readbytetable
+ function streams.readcardinal1(f)
+  local i=f[2]
+  f[2]=i+1
+  return readcardinal1(f[1],i)
+ end
+ function streams.readcardinal2(f)
+  local i=f[2]
+  f[2]=i+2
+  return readcardinal2(f[1],i)
+ end
+ function streams.readcardinal3(f)
+  local i=f[2]
+  f[2]=i+3
+  return readcardinal3(f[1],i)
+ end
+ function streams.readcardinal4(f)
+  local i=f[2]
+  f[2]=i+4
+  return readcardinal4(f[1],i)
+ end
+ function streams.readinteger1(f)
+  local i=f[2]
+  f[2]=i+1
+  return readinteger1(f[1],i)
+ end
+ function streams.readinteger2(f)
+  local i=f[2]
+  f[2]=i+2
+  return readinteger2(f[1],i)
+ end
+ function streams.readinteger3(f)
+  local i=f[2]
+  f[2]=i+3
+  return readinteger3(f[1],i)
+ end
+ function streams.readinteger4(f)
+  local i=f[2]
+  f[2]=i+4
+  return readinteger4(f[1],i)
+ end
+ function streams.readfixed2(f) 
+  local i=f[2]
+  f[2]=i+2
+  return readfixed2(f[1],i)
+ end
+ function streams.readfixed4(f) 
+  local i=f[2]
+  f[2]=i+4
+  return readfixed4(f[1],i)
+ end
+ function streams.read2dot14(f)
+  local i=f[2]
+  f[2]=i+2
+  return read2dot14(f[1],i)
+ end
+ function streams.readbytes(f,n)
+  local i=f[2]
+  local s=f[3]
+  local p=i+n
+  if p>s then
+   f[2]=s+1
+  else
+   f[2]=p
+  end
+  return readbytes(f[1],i,n)
+ end
+ function streams.readbytetable(f,n)
+  local i=f[2]
+  local s=f[3]
+  local p=i+n
+  if p>s then
+   f[2]=s+1
+  else
+   f[2]=p
+  end
+  return readbytetable(f[1],i,n)
+ end
+ streams.readbyte=streams.readcardinal1
+ streams.readsignedbyte=streams.readinteger1
+ streams.readcardinal=streams.readcardinal1
+ streams.readinteger=streams.readinteger1
+end
+if sio and sio.readcardinaltable then
+ local readcardinaltable=sio.readcardinaltable
+ local readintegertable=sio.readintegertable
+ function utilities.streams.readcardinaltable(f,n,b)
+  local i=f[2]
+  local s=f[3]
+  local p=i+n*b
+  if p>s then
+   f[2]=s+1
+  else
+   f[2]=p
+  end
+  return readcardinaltable(f[1],i,n,b)
+ end
+ function utilities.streams.readintegertable(f,n,b)
+  local i=f[2]
+  local s=f[3]
+  local p=i+n*b
+  if p>s then
+   f[2]=s+1
+  else
+   f[2]=p
+  end
+  return readintegertable(f[1],i,n,b)
+ end
+else
+ local readcardinal1=streams.readcardinal1
+ local readcardinal2=streams.readcardinal2
+ local readcardinal3=streams.readcardinal3
+ local readcardinal4=streams.readcardinal4
+ function streams.readcardinaltable(f,n,b)
+  local i=f[2]
+  local s=f[3]
+  local p=i+n*b
+  if p>s then
+   f[2]=s+1
+  else
+   f[2]=p
+  end
+  local t={}
+   if b==1 then for i=1,n do t[i]=readcardinal1(f[1],i) end
+  elseif b==2 then for i=1,n do t[i]=readcardinal2(f[1],i) end
+  elseif b==3 then for i=1,n do t[i]=readcardinal3(f[1],i) end
+  elseif b==4 then for i=1,n do t[i]=readcardinal4(f[1],i) end end
+  return t
+ end
+ local readinteger1=streams.readinteger1
+ local readinteger2=streams.readinteger2
+ local readinteger3=streams.readinteger3
+ local readinteger4=streams.readinteger4
+ function streams.readintegertable(f,n,b)
+  local i=f[2]
+  local s=f[3]
+  local p=i+n*b
+  if p>s then
+   f[2]=s+1
+  else
+   f[2]=p
+  end
+  local t={}
+   if b==1 then for i=1,n do t[i]=readinteger1(f[1],i) end
+  elseif b==2 then for i=1,n do t[i]=readinteger2(f[1],i) end
+  elseif b==3 then for i=1,n do t[i]=readinteger3(f[1],i) end
+  elseif b==4 then for i=1,n do t[i]=readinteger4(f[1],i) end end
+  return t
+ end
+end
+do
+ local files=utilities.files
+ if files then
+  local openfile=files.open
+  local openstream=streams.open
+  local openstring=streams.openstring
+  local setmetatable=setmetatable
+  function io.newreader(str,method)
+   local f,m
+   if method=="string" then
+    f=openstring(str,true)
+    m=streams
+   elseif method=="stream" then
+    f=openstream(str,true)
+    m=streams
+   else
+    f=openfile(str,"rb")
+    m=files
+   end
+   if f then
+    local t={}
+    setmetatable(t,{
+     __index=function(t,k)
+      local r=m[k]
+      if k=="close" then
+       if f then
+        m.close(f)
+        f=nil
+       end
+       return function() end
+      elseif r then
+       local v=function(_,a,b) return r(f,a,b) end
+       t[k]=v
+       return v
+      else
+       print("unknown key",k)
+      end
+     end
+    } )
+    return t
+   end
+  end
+ end
+end
+if bit32 and not streams.tocardinal1 then
+ local extract=bit32.extract
+ local char=string.char
+    streams.tocardinal1=char
+ function streams.tocardinal2(n)   return char(extract(8,8),extract(0,8)) end
+ function streams.tocardinal3(n)   return char(extract(16,8),extract(8,8),extract(0,8)) end
+ function streams.tocardinal4(n)   return char(extract(24,8),extract(16,8),extract(8,8),extract(0,8)) end
+    streams.tocardinal1le=char
+ function streams.tocardinal2le(n) return char(extract(0,8),extract(8,8)) end
+ function streams.tocardinal3le(n) return char(extract(0,8),extract(8,8),extract(16,8)) end
+ function streams.tocardinal4le(n) return char(extract(0,8),extract(8,8),extract(16,8),extract(24,8)) end
+end
+if not streams.readcstring then
+ local readchar=streams.readchar
+ local concat=table.concat
+ function streams.readcstring(f)
+  local t={}
+  while true do
+   local c=readchar(f)
+   if c and c~="\0" then
+    t[#t+1]=c
+   else
+    return concat(t)
+   end
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-sto"] = package.loaded["util-sto"] or true
+
+-- original size: 6661, stripped down to: 3074
+
+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,rawset,type=setmetatable,getmetatable,rawset,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.setmetatableindices(t,f,n,c)
+ 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
+  m.__newindex=n
+  m.__call=c
+ else
+  setmetatable(t,{
+   __index=i,
+   __newindex=n,
+   __call=c,
+  })
+ 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
+function table.makeweak(t)
+ if not t then
+  t={}
+ end
+ local m=getmetatable(t)
+ if m then
+  m.__mode="v"
+ else
+  setmetatable(t,{ __mode="v" })
+ end
+ return t
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-prs"] = package.loaded["util-prs"] or true
+
+-- original size: 25542, stripped down to: 16783
+
+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 tonumber,tostring,type,next,rawset=tonumber,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={}
+parsers.hashes=hashes
+local digit=R("09")
+local space=P(' ')
+local equal=P("=")
+local colon=P(":")
+local comma=P(",")
+local lbrace=P("{")
+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
+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 nobracket=1-(lbracket+rbracket)
+local escape,left,right=P("\\"),P('{'),P('}')
+lpegpatterns.balanced=P {
+ ((escape*(left+right))+(1-(left+right))+V(2))^0,
+ left*V(1)*right
+}
+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   
+lpegpatterns.nestedparents=nestedparents  
+lpegpatterns.nestedbrackets=nestedbrackets 
+lpegpatterns.nested=nestedbraces   
+lpegpatterns.argument=argument    
+lpegpatterns.content=content  
+local value=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 pattern_d=(space+comma)^0*(key*(equal+colon)*value+key*C(""))
+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
+local pattern_d_s=(pattern_d/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
+patterns.settings_to_hash_d=pattern_d_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_colon_too(str)
+ if not str or str=="" then
+  return {}
+ elseif type(str)=="table" then
+  return str
+ else
+  hash={}
+  lpegmatch(pattern_d_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=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
+function parsers.settings_to_numbers(str)
+ if not str or str=="" then
+  return {}
+ end
+ if type(str)=="table" then
+ 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=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
+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=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={}
+  local tn=0
+  local s=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 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={}
+ local 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 parsers.options_to_hash(str,target)
+ return str and lpegmatch(splitter,str,1,target or {}) or {}
+end
+local splitter=lpeg.tsplitat(" ")
+function 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={}
+   local 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 numbers=specification.numbers
+ 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 quoteitem=(1-quotechar)^0
+   local quoteword=quotechar*(numbers and (quoteitem/tonumber) or C(quoteitem))*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 numbers=specification.numbers
+ local separator=specification.separator 
+ local quotechar=P(specification.quote)  
+ local dquotechar=quotechar*quotechar   
+/specification.quote
+ local separator=S(separator~="" and separator or ",")
+ local whatever=(dquotechar+(1-quotechar))^0
+ local escaped=quotechar*(numbers and (whatever/tonumber) or Cs(whatever))*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 morerecords=(newline^(specification.strict and -1 or 1)*record)^0
+ local headeryes=Ct(morerecords)
+ local headernop=Ct(record*morerecords)
+ return function(data,getheader)
+  if getheader then
+   local header,position=lpegmatch(headerline,data)
+   local data=lpegmatch(headeryes,data,position)
+   return data,header
+  else
+   return lpegmatch(headernop,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.hexadecimal+lpegpatterns.cardinal)/tonumber
+local spacers=lpegpatterns.spacer^0
+local endofstring=lpegpatterns.endofstring
+local stepper=spacers*(cardinal*(spacers*S(":-")*spacers*(cardinal+Cc(true) )+Cc(false) )*Carg(1)*Carg(2)/ranger*S(", ")^0 )^1
+local stepper=spacers*(cardinal*(spacers*S(":-")*spacers*(cardinal+(P("*")+endofstring)*Cc(true) )+Cc(false) )*Carg(1)*Carg(2)/ranger*S(", ")^0 )^1*endofstring 
+function parsers.stepper(str,n,action)
+ local ts=type(str)
+ if type(n)=="function" then
+  if ts=="number" then
+   n(str)
+  elseif ts=="table" then
+   for i=1,#str do
+    n(str[i])
+   end
+  else
+   lpegmatch(stepper,str,1,false,n or print)
+  end
+ elseif ts=="string" then
+  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=S(k) 
+ local value=(1-separator)^0
+ local pattern=spaces*C(value)*separator^0*Cp()
+ t[k]=pattern
+ return pattern
+end)
+local commalistiterator=cache[","]
+function 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 parsers.mergehashes(hash,list)
+ return lpegmatch(merge,list,1,hash)
+end
+function 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 parsers.splitmethod(str,default)
+ if str then
+  return lpegmatch(pattern,str,1,default or false)
+ else
+  return default or false,""
+ end
+end
+local p_year=lpegpatterns.digit^4/tonumber
+local pattern=Cf(Ct("")*(
+  (Cg(Cc("year")*p_year)*S("-/")*Cg(Cc("month")*cardinal)*S("-/")*Cg(Cc("day")*cardinal)
+  )+(Cg(Cc("day")*cardinal)*S("-/")*Cg(Cc("month")*cardinal)*S("-/")*Cg(Cc("year")*p_year)
+  )+(Cg(Cc("year")*p_year)*S("-/")*Cg(Cc("month")*cardinal)
+  )+(Cg(Cc("month")*cardinal)*S("-/")*Cg(Cc("year")*p_year)
+  )
+ )*(
+   P(" ")*Cg(Cc("hour")*cardinal)*P(":")*Cg(Cc("min")*cardinal)*(P(":")*Cg(Cc("sec")*cardinal))^-1+P(-1) )
+,rawset)
+lpegpatterns.splittime=pattern
+function parsers.totime(str)
+ return lpegmatch(pattern,str)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-fmt"] = package.loaded["util-fmt"] or true
+
+-- original size: 2541, stripped down to: 1624
+
+if not modules then modules={} end modules ['util-fmt']={
+ 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.formatters=utilities.formatters or {}
+local formatters=utilities.formatters
+local concat,format=table.concat,string.format
+local tostring,type=tostring,type
+local strip=string.strip
+local lpegmatch=lpeg.match
+local stripper=lpeg.patterns.stripzeros
+function formatters.stripzeros(str)
+ return lpegmatch(stripper,str)
+end
+function formatters.formatcolumns(result,between)
+ if result and #result>0 then
+  between=between or "   "
+  local widths,numbers={},{}
+  local first=result[1]
+  local n=#first
+  for i=1,n do
+   widths[i]=0
+  end
+  for i=1,#result do
+   local r=result[i]
+   for j=1,n do
+    local rj=r[j]
+    local tj=type(rj)
+    if tj=="number" then
+     numbers[j]=true
+     rj=tostring(rj)
+    elseif tj~="string" then
+     rj=tostring(rj)
+     r[j]=rj
+    end
+    local w=#rj
+    if w>widths[j] then
+     widths[j]=w
+    end
+   end
+  end
+  for i=1,n do
+   local w=widths[i]
+   if numbers[i] then
+    if w>80 then
+     widths[i]="%s"..between
+     else
+     widths[i]="%0"..w.."i"..between
+    end
+   else
+    if w>80 then
+     widths[i]="%s"..between
+     elseif w>0 then
+     widths[i]="%-"..w.."s"..between
+    else
+     widths[i]="%s"
+    end
+   end
+  end
+  local template=strip(concat(widths))
+  for i=1,#result do
+   local str=format(template,unpack(result[i]))
+   result[i]=strip(str)
+  end
+ end
+ return result
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-reset"] = package.loaded["util-soc-imp-reset"] or true
+
+-- original size: 374, stripped down to: 282
+
+local loaded=package.loaded
+loaded["socket"]=nil
+loaded["copas"]=nil
+loaded["ltn12"]=nil
+loaded["mbox"]=nil
+loaded["mime"]=nil
+loaded["socket.url"]=nil
+loaded["socket.headers"]=nil
+loaded["socket.tp"]=nil
+loaded["socket.http"]=nil
+loaded["socket.ftp"]=nil
+loaded["socket.smtp"]=nil
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-socket"] = package.loaded["util-soc-imp-socket"] or true
+
+-- original size: 4905, stripped down to: 3562
+
+
+local type,tostring,setmetatable=type,tostring,setmetatable
+local min=math.min
+local format=string.format
+local socket=socket or package.loaded.socket or require("socket.core")
+local connect=socket.connect
+local tcp4=socket.tcp4
+local tcp6=socket.tcp6
+local getaddrinfo=socket.dns.getaddrinfo
+local defaulthost="0.0.0.0"
+local function report(fmt,first,...)
+ if logs then
+  report=logs and logs.reporter("socket")
+  report(fmt,first,...)
+ elseif fmt then
+  fmt="socket: "..fmt
+  if first then
+   print(format(fmt,first,...))
+  else
+   print(fmt)
+  end
+ end
+end
+socket.report=report
+function socket.connect4(address,port,laddress,lport)
+ return connect(address,port,laddress,lport,"inet")
+end
+function socket.connect6(address,port,laddress,lport)
+ return connect(address,port,laddress,lport,"inet6")
+end
+function socket.bind(host,port,backlog)
+ if host=="*" or host=="" then
+  host=defaulthost
+ end
+ local addrinfo,err=getaddrinfo(host)
+ if not addrinfo then
+  return nil,err
+ end
+ for i=1,#addrinfo do
+  local alt=addrinfo[i]
+  local sock,err=(alt.family=="inet" and tcp4 or tcp6)()
+  if not sock then
+   return nil,err or "unknown error"
+  end
+  sock:setoption("reuseaddr",true)
+  local res,err=sock:bind(alt.addr,port)
+  if res then
+   res,err=sock:listen(backlog)
+   if res then
+    return sock
+   else
+    sock:close()
+   end
+  else
+   sock:close()
+  end
+ end
+ return nil,"invalid address"
+end
+socket.try=socket.newtry()
+function socket.choose(list)
+ return function(name,opt1,opt2)
+  if type(name)~="string" then
+   name,opt1,opt2="default",name,opt1
+  end
+  local f=list[name or "nil"]
+  if f then
+   return f(opt1,opt2)
+  else
+   report("error: unknown key '%s'",tostring(name))
+  end
+ end
+end
+local sourcet={}
+local sinkt={}
+socket.sourcet=sourcet
+socket.sinkt=sinkt
+socket.BLOCKSIZE=2048
+sinkt["close-when-done"]=function(sock)
+ return setmetatable (
+  {
+   getfd=function() return sock:getfd() end,
+   dirty=function() return sock:dirty() end,
+  },
+  {
+   __call=function(self,chunk,err)
+    if chunk then
+     return sock:send(chunk)
+    else
+     sock:close()
+     return 1 
+    end
+   end
+  }
+ )
+end
+sinkt["keep-open"]=function(sock)
+ return setmetatable (
+  {
+   getfd=function() return sock:getfd() end,
+   dirty=function() return sock:dirty() end,
+  },{
+   __call=function(self,chunk,err)
+    if chunk then
+     return sock:send(chunk)
+    else
+     return 1 
+    end
+   end
+  }
+ )
+end
+sinkt["default"]=sinkt["keep-open"]
+socket.sink=socket.choose(sinkt)
+sourcet["by-length"]=function(sock,length)
+ local blocksize=socket.BLOCKSIZE
+ return setmetatable (
+  {
+   getfd=function() return sock:getfd() end,
+   dirty=function() return sock:dirty() end,
+  },
+  {
+   __call=function()
+    if length<=0 then
+     return nil
+    end
+    local chunk,err=sock:receive(min(blocksize,length))
+    if err then
+     return nil,err
+    end
+    length=length-#chunk
+    return chunk
+   end
+  }
+ )
+end
+sourcet["until-closed"]=function(sock)
+ local blocksize=socket.BLOCKSIZE
+ local done=false
+ return setmetatable (
+  {
+   getfd=function() return sock:getfd() end,
+   dirty=function() return sock:dirty() end,
+  },{
+   __call=function()
+    if done then
+     return nil
+    end
+    local chunk,status,partial=sock:receive(blocksize)
+    if not status then
+     return chunk
+    elseif status=="closed" then
+     sock:close()
+     done=true
+     return partial
+    else
+     return nil,status
+    end
+   end
+  }
+ )
+end
+sourcet["default"]=sourcet["until-closed"]
+socket.source=socket.choose(sourcet)
+_G.socket=socket 
+package.loaded["socket"]=socket
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-copas"] = package.loaded["util-soc-imp-copas"] or true
+
+-- original size: 26186, stripped down to: 14893
+
+
+local socket=socket or require("socket")
+local ssl=ssl or nil 
+local WATCH_DOG_TIMEOUT=120
+local UDP_DATAGRAM_MAX=8192
+local type,next,pcall,getmetatable,tostring=type,next,pcall,getmetatable,tostring
+local min,max,random=math.min,math.max,math.random
+local find=string.find
+local insert,remove=table.insert,table.remove
+local gettime=socket.gettime
+local selectsocket=socket.select
+local createcoroutine=coroutine.create
+local resumecoroutine=coroutine.resume
+local yieldcoroutine=coroutine.yield
+local runningcoroutine=coroutine.running
+local function report(fmt,first,...)
+ if logs then
+  report=logs and logs.reporter("copas")
+  report(fmt,first,...)
+ elseif fmt then
+  fmt="copas: "..fmt
+  if first then
+   print(format(fmt,first,...))
+  else
+   print(fmt)
+  end
+ end
+end
+local copas={
+ _COPYRIGHT="Copyright (C) 2005-2016 Kepler Project",
+ _DESCRIPTION="Coroutine Oriented Portable Asynchronous Services",
+ _VERSION="Copas 2.0.1",
+ autoclose=true,
+ running=false,
+ report=report,
+ trace=false,
+}
+local function statushandler(status,...)
+ if status then
+  return...
+ end
+ local err=(...)
+ if type(err)=="table" then
+  err=err[1]
+ end
+ if copas.trace then
+  report("error: %s",tostring(err))
+ end
+ return nil,err
+end
+function socket.protect(func)
+ return function(...)
+  return statushandler(pcall(func,...))
+ end
+end
+function socket.newtry(finalizer)
+ return function (...)
+  local status=(...)
+  if not status then
+   local detail=select(2,...)
+   pcall(finalizer,detail)
+   if copas.trace then
+    report("error: %s",tostring(detail))
+   end
+   return
+  end
+  return...
+ end
+end
+local function newset()
+ local reverse={}
+ local set={}
+ local queue={}
+ setmetatable(set,{
+  __index={
+   insert=function(set,value)
+     if not reverse[value] then
+      local n=#set+1
+      set[n]=value
+      reverse[value]=n
+     end
+    end,
+   remove=function(set,value)
+     local index=reverse[value]
+     if index then
+      reverse[value]=nil
+      local n=#set
+      local top=set[n]
+      set[n]=nil
+      if top~=value then
+       reverse[top]=index
+       set[index]=top
+      end
+     end
+    end,
+   push=function (set,key,itm)
+     local entry=queue[key]
+     if entry==nil then 
+      queue[key]={ itm }
+     else
+      entry[#entry+1]=itm
+     end
+    end,
+   pop=function (set,key)
+     local top=queue[key]
+     if top~=nil then
+      local ret=remove(top,1)
+      if top[1]==nil then
+       queue[key]=nil
+      end
+      return ret
+     end
+    end
+  }
+ } )
+ return set
+end
+local _sleeping={
+ times={},
+ cos={},
+ lethargy={},
+ insert=function()
+  end,
+ remove=function()
+  end,
+ push=function(self,sleeptime,co)
+   if not co then
+    return
+   end
+   if sleeptime<0 then
+    self.lethargy[co]=true
+    return
+   else
+    sleeptime=gettime()+sleeptime
+   end
+   local t=self.times
+   local c=self.cos
+   local i=1
+   local n=#t
+   while i<=n and t[i]<=sleeptime do
+    i=i+1
+   end
+   insert(t,i,sleeptime)
+   insert(c,i,co)
+  end,
+ getnext=
+  function(self)
+   local t=self.times
+   local delay=t[1] and t[1]-gettime() or nil
+   return delay and max(delay,0) or nil
+  end,
+ pop=
+  function(self,time)
+   local t=self.times
+   local c=self.cos
+   if #t==0 or time<t[1] then
+    return
+   end
+   local co=c[1]
+   remove(t,1)
+   remove(c,1)
+   return co
+  end,
+  wakeup=function(self,co)
+    local let=self.lethargy
+    if let[co] then
+     self:push(0,co)
+     let[co]=nil
+    else
+     local c=self.cos
+     local t=self.times
+     for i=1,#c do
+      if c[i]==co then
+       remove(c,i)
+       remove(t,i)
+       self:push(0,co)
+       return
+      end
+     end
+    end
+   end
+}
+local _servers=newset() 
+local _reading=newset() 
+local _writing=newset() 
+local _reading_log={}
+local _writing_log={}
+local _is_timeout={  
+ timeout=true,
+ wantread=true,
+ wantwrite=true,
+}
+local function isTCP(socket)
+ return not find(tostring(socket),"^udp")
+end
+local function copasreceive(client,pattern,part)
+ if not pattern or pattern=="" then
+  pattern="*l"
+ end
+ local current_log=_reading_log
+ local s,err
+ repeat
+  s,err,part=client:receive(pattern,part)
+  if s or (not _is_timeout[err]) then
+   current_log[client]=nil
+   return s,err,part
+  end
+  if err=="wantwrite" then
+   current_log=_writing_log
+   current_log[client]=gettime()
+   yieldcoroutine(client,_writing)
+  else
+   current_log=_reading_log
+   current_log[client]=gettime()
+   yieldcoroutine(client,_reading)
+  end
+ until false
+end
+local function copasreceivefrom(client,size)
+ local s,err,port
+ if not size or size==0 then
+  size=UDP_DATAGRAM_MAX
+ end
+ repeat
+  s,err,port=client:receivefrom(size)
+  if s or err~="timeout" then
+   _reading_log[client]=nil
+   return s,err,port
+  end
+  _reading_log[client]=gettime()
+  yieldcoroutine(client,_reading)
+ until false
+end
+local function copasreceivepartial(client,pattern,part)
+ if not pattern or pattern=="" then
+  pattern="*l"
+ end
+ local logger=_reading_log
+ local queue=_reading
+ local s,err
+ repeat
+  s,err,part=client:receive(pattern,part)
+  if s or (type(pattern)=="number" and part~="" and part) or not _is_timeout[err] then
+    logger[client]=nil
+    return s,err,part
+  end
+  if err=="wantwrite" then
+   logger=_writing_log
+   queue=_writing
+  else
+   logger=_reading_log
+   queue=_reading
+  end
+  logger[client]=gettime()
+  yieldcoroutine(client,queue)
+ until false
+end
+local function copassend(client,data,from,to)
+ if not from then
+  from=1
+ end
+ local lastIndex=from-1
+ local logger=_writing_log
+ local queue=_writing
+ local s,err
+ repeat
+  s,err,lastIndex=client:send(data,lastIndex+1,to)
+  if random(100)>90 then
+   logger[client]=gettime()
+   yieldcoroutine(client,queue)
+  end
+  if s or not _is_timeout[err] then
+   logger[client]=nil
+   return s,err,lastIndex
+  end
+  if err=="wantread" then
+   logger=_reading_log
+   queue=_reading
+  else
+   logger=_writing_log
+   queue=_writing
+  end
+  logger[client]=gettime()
+  yieldcoroutine(client,queue)
+ until false
+end
+local function copassendto(client,data,ip,port)
+ repeat
+  local s,err=client:sendto(data,ip,port)
+  if random(100)>90 then
+   _writing_log[client]=gettime()
+   yieldcoroutine(client,_writing)
+  end
+  if s or err~="timeout" then
+   _writing_log[client]=nil
+   return s,err
+  end
+  _writing_log[client]=gettime()
+  yieldcoroutine(client,_writing)
+ until false
+end
+local function copasconnect(skt,host,port)
+ skt:settimeout(0)
+ local ret,err,tried_more_than_once
+ repeat
+  ret,err=skt:connect (host,port)
+  if ret or (err~="timeout" and err~="Operation already in progress") then
+   if not ret and err=="already connected" and tried_more_than_once then
+    ret=1
+    err=nil
+   end
+   _writing_log[skt]=nil
+   return ret,err
+  end
+  tried_more_than_once=tried_more_than_once or true
+  _writing_log[skt]=gettime()
+  yieldcoroutine(skt,_writing)
+ until false
+end
+local function copasdohandshake(skt,sslt) 
+ if not ssl then
+  ssl=require("ssl")
+ end
+ if not ssl then
+  report("error: no ssl library")
+  return
+ end
+ local nskt,err=ssl.wrap(skt,sslt)
+ if not nskt then
+  report("error: %s",tostring(err))
+  return
+ end
+ nskt:settimeout(0)
+ local queue
+ repeat
+  local success,err=nskt:dohandshake()
+  if success then
+   return nskt
+  elseif err=="wantwrite" then
+   queue=_writing
+  elseif err=="wantread" then
+   queue=_reading
+  else
+   report("error: %s",tostring(err))
+   return
+  end
+  yieldcoroutine(nskt,queue)
+ until false
+end
+local function copasflush(client)
+end
+copas.connect=copassconnect
+copas.send=copassend
+copas.sendto=copassendto
+copas.receive=copasreceive
+copas.receivefrom=copasreceivefrom
+copas.copasreceivepartial=copasreceivepartial
+copas.copasreceivePartial=copasreceivepartial
+copas.dohandshake=copasdohandshake
+copas.flush=copasflush
+local function _skt_mt_tostring(self)
+ return tostring(self.socket).." (copas wrapped)"
+end
+local _skt_mt_tcp_index={
+ send=function(self,data,from,to)
+   return copassend (self.socket,data,from,to)
+  end,
+ receive=function (self,pattern,prefix)
+   if self.timeout==0 then
+    return copasreceivePartial(self.socket,pattern,prefix)
+   else
+    return copasreceive(self.socket,pattern,prefix)
+   end
+  end,
+ flush=function (self)
+   return copasflush(self.socket)
+  end,
+ settimeout=function (self,time)
+   self.timeout=time
+   return true
+  end,
+ connect=function(self,...)
+   local res,err=copasconnect(self.socket,...)
+   if res and self.ssl_params then
+    res,err=self:dohandshake()
+   end
+   return res,err
+  end,
+ close=function(self,...)
+   return self.socket:close(...)
+  end,
+ bind=function(self,...)
+   return self.socket:bind(...)
+  end,
+ getsockname=function(self,...)
+   return self.socket:getsockname(...)
+  end,
+ getstats=function(self,...)
+   return self.socket:getstats(...)
+  end,
+ setstats=function(self,...)
+   return self.socket:setstats(...)
+  end,
+ listen=function(self,...)
+   return self.socket:listen(...)
+  end,
+ accept=function(self,...)
+   return self.socket:accept(...)
+  end,
+ setoption=function(self,...)
+   return self.socket:setoption(...)
+  end,
+ getpeername=function(self,...)
+   return self.socket:getpeername(...)
+  end,
+ shutdown=function(self,...)
+   return self.socket:shutdown(...)
+  end,
+ dohandshake=function(self,sslt)
+   self.ssl_params=sslt or self.ssl_params
+   local nskt,err=copasdohandshake(self.socket,self.ssl_params)
+   if not nskt then
+    return nskt,err
+   end
+   self.socket=nskt
+   return self
+  end,
+}
+local _skt_mt_tcp={
+ __tostring=_skt_mt_tostring,
+ __index=_skt_mt_tcp_index,
+}
+local _skt_mt_udp_index={
+ sendto=function (self,...)
+   return copassendto(self.socket,...)
+  end,
+ receive=function (self,size)
+   return copasreceive(self.socket,size or UDP_DATAGRAM_MAX)
+  end,
+ receivefrom=function (self,size)
+   return copasreceivefrom(self.socket,size or UDP_DATAGRAM_MAX)
+  end,
+ setpeername=function(self,...)
+   return self.socket:getpeername(...)
+  end,
+ setsockname=function(self,...)
+   return self.socket:setsockname(...)
+  end,
+ close=function(self,...)
+   return true
+  end
+}
+local _skt_mt_udp={
+ __tostring=_skt_mt_tostring,
+ __index=_skt_mt_udp_index,
+}
+for k,v in next,_skt_mt_tcp_index do
+ if not _skt_mt_udp_index[k] then
+  _skt_mt_udp_index[k]=v
+ end
+end
+local function wrap(skt,sslt)
+ if getmetatable(skt)==_skt_mt_tcp or getmetatable(skt)==_skt_mt_udp then
+  return skt 
+ end
+ skt:settimeout(0)
+ if isTCP(skt) then
+  return setmetatable ({ socket=skt,ssl_params=sslt },_skt_mt_tcp)
+ else
+  return setmetatable ({ socket=skt },_skt_mt_udp)
+ end
+end
+copas.wrap=wrap
+function copas.handler(handler,sslparams)
+ return function (skt,...)
+  skt=wrap(skt)
+  if sslparams then
+   skt:dohandshake(sslparams)
+  end
+  return handler(skt,...)
+ end
+end
+local _errhandlers={}
+function copas.setErrorHandler(err)
+ local co=runningcoroutine()
+ if co then
+  _errhandlers[co]=err
+ end
+end
+local function _deferror (msg,co,skt)
+ report("%s (%s) (%s)",msg,tostring(co),tostring(skt))
+end
+local function _doTick (co,skt,...)
+ if not co then
+  return
+ end
+ local ok,res,new_q=resumecoroutine(co,skt,...)
+ if ok and res and new_q then
+  new_q:insert(res)
+  new_q:push(res,co)
+ else
+  if not ok then
+   pcall(_errhandlers[co] or _deferror,res,co,skt)
+  end
+  if skt and copas.autoclose and isTCP(skt) then
+   skt:close()
+  end
+  _errhandlers[co]=nil
+ end
+end
+local function _accept(input,handler)
+ local client=input:accept()
+ if client then
+  client:settimeout(0)
+  local co=createcoroutine(handler)
+  _doTick (co,client)
+ end
+ return client
+end
+local function _tickRead(skt)
+ _doTick(_reading:pop(skt),skt)
+end
+local function _tickWrite(skt)
+ _doTick(_writing:pop(skt),skt)
+end
+local function addTCPserver(server,handler,timeout)
+ server:settimeout(timeout or 0)
+ _servers[server]=handler
+ _reading:insert(server)
+end
+local function addUDPserver(server,handler,timeout)
+ server:settimeout(timeout or 0)
+ local co=createcoroutine(handler)
+ _reading:insert(server)
+ _doTick(co,server)
+end
+function copas.addserver(server,handler,timeout)
+ if isTCP(server) then
+  addTCPserver(server,handler,timeout)
+ else
+  addUDPserver(server,handler,timeout)
+ end
+end
+function copas.removeserver(server,keep_open)
+ local s=server
+ local mt=getmetatable(server)
+ if mt==_skt_mt_tcp or mt==_skt_mt_udp then
+  s=server.socket
+ end
+ _servers[s]=nil
+ _reading:remove(s)
+ if keep_open then
+  return true
+ end
+ return server:close()
+end
+function copas.addthread(handler,...)
+ local thread=createcoroutine(function(_,...) return handler(...) end)
+ _doTick(thread,nil,...)
+ return thread
+end
+local _tasks={}
+local function addtaskRead(task)
+ task.def_tick=_tickRead
+ _tasks[task]=true
+end
+local function addtaskWrite(task)
+ task.def_tick=_tickWrite
+ _tasks[task]=true
+end
+local function tasks()
+ return next,_tasks
+end
+local _readable_t={
+ events=function(self)
+   local i=0
+   return function ()
+    i=i+1
+    return self._evs[i]
+   end
+  end,
+ tick=function(self,input)
+   local handler=_servers[input]
+   if handler then
+    input=_accept(input,handler)
+   else
+    _reading:remove(input)
+    self.def_tick(input)
+   end
+  end
+}
+addtaskRead(_readable_t)
+local _writable_t={
+ events=function(self)
+   local i=0
+   return function()
+    i=i+1
+    return self._evs[i]
+   end
+  end,
+ tick=function(self,output)
+   _writing:remove(output)
+   self.def_tick(output)
+  end
+}
+addtaskWrite(_writable_t)
+local _sleeping_t={
+ tick=function(self,time,...)
+  _doTick(_sleeping:pop(time),...)
+ end
+}
+function copas.sleep(sleeptime)
+ yieldcoroutine((sleeptime or 0),_sleeping)
+end
+function copas.wakeup(co)
+ _sleeping:wakeup(co)
+end
+local last_cleansing=0
+local function _select(timeout)
+ local now=gettime()
+ local r_evs,w_evs,err=selectsocket(_reading,_writing,timeout)
+ _readable_t._evs=r_evs
+ _writable_t._evs=w_evs
+ if (last_cleansing-now)>WATCH_DOG_TIMEOUT then
+  last_cleansing=now
+  for skt,time in next,_reading_log do
+   if not r_evs[skt] and (time-now)>WATCH_DOG_TIMEOUT then
+    local n=#r_evs+1
+    _reading_log[skt]=nil
+    r_evs[n]=skt
+    r_evs[skt]=n
+   end
+  end
+  for skt,time in next,_writing_log do
+   if not w_evs[skt] and (time-now)>WATCH_DOG_TIMEOUT then
+    local n=#w_evs+1
+    _writing_log[skt]=nil
+    w_evs[n]=skt
+    w_evs[skt]=n
+   end
+  end
+ end
+ if err=="timeout" and #r_evs+#w_evs>0 then
+  return nil
+ else
+  return err
+ end
+end
+local function copasfinished()
+ return not (next(_reading) or next(_writing) or _sleeping:getnext())
+end
+local function copasstep(timeout)
+ _sleeping_t:tick(gettime())
+ local nextwait=_sleeping:getnext()
+ if nextwait then
+  timeout=timeout and min(nextwait,timeout) or nextwait
+ elseif copasfinished() then
+  return false
+ end
+ local err=_select(timeout)
+ if err then
+  if err=="timeout" then
+   return false
+  end
+  return nil,err
+ end
+ for task in tasks() do
+  for event in task:events() do
+   task:tick(event)
+  end
+ end
+ return true
+end
+copas.finished=copasfinished
+copas.step=copasstep
+function copas.loop(timeout)
+ copas.running=true
+ while not copasfinished() do
+  copasstep(timeout)
+ end
+ copas.running=false
+end
+package.loaded["copas"]=copas
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-ltn12"] = package.loaded["util-soc-imp-ltn12"] or true
+
+-- original size: 8709, stripped down to: 5411
+
+
+local select,unpack=select,unpack
+local insert,remove=table.insert,table.remove
+local sub=string.sub
+local function report(fmt,first,...)
+ if logs then
+  report=logs and logs.reporter("ltn12")
+  report(fmt,first,...)
+ elseif fmt then
+  fmt="ltn12: "..fmt
+  if first then
+   print(format(fmt,first,...))
+  else
+   print(fmt)
+  end
+ end
+end
+local filter={}
+local source={}
+local sink={}
+local pump={}
+local ltn12={
+ _VERSION="LTN12 1.0.3",
+ BLOCKSIZE=2048,
+ filter=filter,
+ source=source,
+ sink=sink,
+ pump=pump,
+ report=report,
+}
+function filter.cycle(low,ctx,extra)
+ if low then
+  return function(chunk)
+   return (low(ctx,chunk,extra))
+  end
+ end
+end
+function filter.chain(...)
+ local arg={... }
+ local n=select('#',...)
+ local top=1
+ local index=1
+ local retry=""
+ return function(chunk)
+  retry=chunk and retry
+  while true do
+   local action=arg[index]
+   if index==top then
+    chunk=action(chunk)
+    if chunk=="" or top==n then
+     return chunk
+    elseif chunk then
+     index=index+1
+    else
+     top=top+1
+     index=top
+    end
+   else
+    chunk=action(chunk or "")
+    if chunk=="" then
+     index=index-1
+     chunk=retry
+    elseif chunk then
+     if index==n then
+      return chunk
+     else
+      index=index+1
+     end
+    else
+     report("error: filter returned inappropriate 'nil'")
+     return
+    end
+   end
+  end
+ end
+end
+local function empty()
+ return nil
+end
+function source.empty()
+ return empty
+end
+local function sourceerror(err)
+ return function()
+  return nil,err
+ end
+end
+source.error=sourceerror
+function source.file(handle,io_err)
+ if handle then
+  local blocksize=ltn12.BLOCKSIZE
+  return function()
+   local chunk=handle:read(blocksize)
+   if not chunk then
+    handle:close()
+   end
+   return chunk
+  end
+ else
+  return sourceerror(io_err or "unable to open file")
+ end
+end
+function source.simplify(src)
+ return function()
+  local chunk,err_or_new=src()
+  if err_or_new then
+   src=err_or_new
+  end
+  if chunk then
+   return chunk
+  else
+   return nil,err_or_new
+  end
+ end
+end
+function source.string(s)
+ if s then
+  local blocksize=ltn12.BLOCKSIZE
+  local i=1
+  return function()
+   local nexti=i+blocksize
+   local chunk=sub(s,i,nexti-1)
+   i=nexti
+   if chunk~="" then
+    return chunk
+   else
+    return nil
+   end
+  end
+ else return source.empty() end
+end
+function source.rewind(src)
+ local t={}
+ return function(chunk)
+  if chunk then
+   insert(t,chunk)
+  else
+   chunk=remove(t)
+   if chunk then
+    return chunk
+   else
+    return src()
+   end
+  end
+ end
+end
+function source.chain(src,f,...)
+ if... then
+  f=filter.chain(f,...)
+ end
+ local last_in=""
+ local last_out=""
+ local state="feeding"
+ local err
+ return function()
+  if not last_out then
+   report("error: source is empty")
+   return
+  end
+  while true do
+   if state=="feeding" then
+    last_in,err=src()
+    if err then
+     return nil,err
+    end
+    last_out=f(last_in)
+    if not last_out then
+     if last_in then
+      report("error: filter returned inappropriate 'nil'")
+     end
+     return nil
+    elseif last_out~="" then
+     state="eating"
+     if last_in then
+      last_in=""
+     end
+     return last_out
+    end
+   else
+    last_out=f(last_in)
+    if last_out=="" then
+     if last_in=="" then
+      state="feeding"
+     else
+      report("error: filter returned nothing")
+      return
+     end
+    elseif not last_out then
+     if last_in then
+      report("filter returned inappropriate 'nil'")
+     end
+     return nil
+    else
+     return last_out
+    end
+   end
+  end
+ end
+end
+function source.cat(...)
+ local arg={... }
+ local src=remove(arg,1)
+ return function()
+  while src do
+   local chunk,err=src()
+   if chunk then
+    return chunk
+   end
+   if err then
+    return nil,err
+   end
+   src=remove(arg,1)
+  end
+ end
+end
+function sink.table(t)
+ if not t then
+  t={}
+ end
+ local f=function(chunk,err)
+  if chunk then
+   insert(t,chunk)
+  end
+  return 1
+ end
+ return f,t
+end
+function sink.simplify(snk)
+ return function(chunk,err)
+  local ret,err_or_new=snk(chunk,err)
+  if not ret then
+   return nil,err_or_new
+  end
+  if err_or_new then
+   snk=err_or_new
+  end
+  return 1
+ end
+end
+local function null()
+ return 1
+end
+function sink.null()
+ return null
+end
+local function sinkerror(err)
+ return function()
+  return nil,err
+ end
+end
+sink.error=sinkerror
+function sink.file(handle,io_err)
+ if handle then
+  return function(chunk,err)
+   if not chunk then
+    handle:close()
+    return 1
+   else
+    return handle:write(chunk)
+   end
+  end
+ else
+  return sinkerror(io_err or "unable to open file")
+ end
+end
+function sink.chain(f,snk,...)
+ if... then
+  local args={ f,snk,... }
+  snk=remove(args,#args)
+  f=filter.chain(unpack(args))
+ end
+ return function(chunk,err)
+  if chunk~="" then
+   local filtered=f(chunk)
+   local done=chunk and ""
+   while true do
+    local ret,snkerr=snk(filtered,err)
+    if not ret then
+     return nil,snkerr
+    end
+    if filtered==done then
+     return 1
+    end
+    filtered=f(done)
+   end
+  else
+   return 1
+  end
+ end
+end
+function pump.step(src,snk)
+ local chunk,src_err=src()
+ local ret,snk_err=snk(chunk,src_err)
+ if chunk and ret then
+  return 1
+ else
+  return nil,src_err or snk_err
+ end
+end
+function pump.all(src,snk,step)
+ if not step then
+  step=pump.step
+ end
+ while true do
+  local ret,err=step(src,snk)
+  if not ret then
+   if err then
+    return nil,err
+   else
+    return 1
+   end
+  end
+ end
+end
+package.loaded["ltn12"]=ltn12
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-mime"] = package.loaded["util-soc-imp-mime"] or true
+
+-- original size: 2373, stripped down to: 1931
+
+
+local type,tostring=type,tostring
+local mime=mime  or package.loaded.mime  or require("mime.core")
+local ltn12=ltn12 or package.loaded.ltn12 or require("ltn12")
+local filtercycle=ltn12.filter.cycle
+local function report(fmt,first,...)
+ if logs then
+  report=logs and logs.reporter("mime")
+  report(fmt,first,...)
+ elseif fmt then
+  fmt="mime: "..fmt
+  if first then
+   print(format(fmt,first,...))
+  else
+   print(fmt)
+  end
+ end
+end
+mime.report=report
+local encodet={}
+local decodet={}
+local wrapt={}
+mime.encodet=encodet
+mime.decodet=decodet
+mime.wrapt=wrapt
+local mime_b64=mime.b64
+local mime_qp=mime.qp
+local mime_unb64=mime.unb64
+local mime_unqp=mime.unqp
+local mime_wrp=mime.wrp
+local mime_qpwrp=mime.qpwrp
+local mime_eol=mime_eol
+local mime_dot=mime_dot
+encodet['base64']=function()
+ return filtercycle(mime_b64,"")
+end
+encodet['quoted-printable']=function(mode)
+ return filtercycle(mime_qp,"",mode=="binary" and "=0D=0A" or "\r\n")
+end
+decodet['base64']=function()
+ return filtercycle(mime_unb64,"")
+end
+decodet['quoted-printable']=function()
+ return filtercycle(mime_unqp,"")
+end
+local wraptext=function(length)
+ if not length then
+  length=76
+ end
+ return filtercycle(mime_wrp,length,length)
+end
+local wrapquoted=function()
+ return filtercycle(mime_qpwrp,76,76)
+end
+wrapt['text']=wraptext
+wrapt['base64']=wraptext
+wrapt['default']=wraptext
+wrapt['quoted-printable']=wrapquoted
+function mime.normalize(marker)
+ return filtercycle(mime_eol,0,marker)
+end
+function mime.stuff()
+ return filtercycle(mime_dot,2)
+end
+local function choose(list)
+ return function(name,opt1,opt2)
+  if type(name)~="string" then
+   name,opt1,opt2="default",name,opt1
+  end
+  local filter=list[name or "nil"]
+  if filter then
+   return filter(opt1,opt2)
+  else
+   report("error: unknown key '%s'",tostring(name))
+  end
+ end
+end
+mime.encode=choose(encodet)
+mime.decode=choose(decodet)
+mime.wrap=choose(wrapt)
+package.loaded["mime"]=mime
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-url"] = package.loaded["util-soc-imp-url"] or true
+
+-- original size: 6863, stripped down to: 5269
+
+
+local tonumber,tostring,type=tonumber,tostring,type
+local gsub,sub,match,find,format,byte,char=string.gsub,string.sub,string.match,string.find,string.format,string.byte,string.char
+local insert=table.insert
+local socket=socket or require("socket")
+local url={
+ _VERSION="URL 1.0.3",
+}
+socket.url=url
+function url.escape(s)
+ return (gsub(s,"([^A-Za-z0-9_])",function(c)
+  return format("%%%02x",byte(c))
+ end))
+end
+local function make_set(t) 
+ local s={}
+ for i=1,#t do
+  s[t[i]]=true
+ end
+ return s
+end
+local segment_set=make_set {
+ "-","_",".","!","~","*","'","(",
+ ")",":","@","&","=","+","$",",",
+}
+local function protect_segment(s)
+ return gsub(s,"([^A-Za-z0-9_])",function(c)
+  if segment_set[c] then
+   return c
+  else
+   return format("%%%02X",byte(c))
+  end
+ end)
+end
+function url.unescape(s)
+ return (gsub(s,"%%(%x%x)",function(hex)
+  return char(tonumber(hex,16))
+ end))
+end
+local function absolute_path(base_path,relative_path)
+ if find(relative_path,"^/") then
+  return relative_path
+ end
+ local path=gsub(base_path,"[^/]*$","")
+ path=path..relative_path
+ path=gsub(path,"([^/]*%./)",function (s)
+  if s~="./" then
+   return s
+  else
+   return ""
+  end
+ end)
+ path=gsub(path,"/%.$","/")
+ local reduced
+ while reduced~=path do
+  reduced=path
+  path=gsub(reduced,"([^/]*/%.%./)",function (s)
+   if s~="../../" then
+    return ""
+   else
+    return s
+   end
+  end)
+ end
+ path=gsub(reduced,"([^/]*/%.%.)$",function (s)
+  if s~="../.." then
+   return ""
+  else
+   return s
+  end
+ end)
+ return path
+end
+function url.parse(url,default)
+ local parsed={}
+ for k,v in next,default or parsed do
+  parsed[k]=v
+ end
+ if not url or url=="" then
+  return nil,"invalid url"
+ end
+ url=gsub(url,"#(.*)$",function(f)
+  parsed.fragment=f
+  return ""
+ end)
+ url=gsub(url,"^([%w][%w%+%-%.]*)%:",function(s)
+  parsed.scheme=s
+  return ""
+ end)
+ url=gsub(url,"^//([^/]*)",function(n)
+  parsed.authority=n
+  return ""
+ end)
+ url=gsub(url,"%?(.*)",function(q)
+  parsed.query=q
+  return ""
+ end)
+ url=gsub(url,"%;(.*)",function(p)
+  parsed.params=p
+  return ""
+ end)
+ if url~="" then
+  parsed.path=url
+ end
+ local authority=parsed.authority
+ if not authority then
+  return parsed
+ end
+ authority=gsub(authority,"^([^@]*)@",function(u)
+  parsed.userinfo=u
+  return ""
+ end)
+ authority=gsub(authority,":([^:%]]*)$",function(p)
+  parsed.port=p
+  return ""
+ end)
+ if authority~="" then
+  parsed.host=match(authority,"^%[(.+)%]$") or authority
+ end
+ local userinfo=parsed.userinfo
+ if not userinfo then
+  return parsed
+ end
+ userinfo=gsub(userinfo,":([^:]*)$",function(p)
+  parsed.password=p
+  return ""
+ end)
+ parsed.user=userinfo
+ return parsed
+end
+function url.build(parsed)
+ local url=parsed.path or ""
+ if parsed.params then
+  url=url..";"..parsed.params
+ end
+ if parsed.query then
+  url=url.."?"..parsed.query
+ end
+ local authority=parsed.authority
+ if parsed.host then
+  authority=parsed.host
+  if find(authority,":") then 
+   authority="["..authority.."]"
+  end
+  if parsed.port then
+   authority=authority..":"..tostring(parsed.port)
+  end
+  local userinfo=parsed.userinfo
+  if parsed.user then
+   userinfo=parsed.user
+   if parsed.password then
+    userinfo=userinfo..":"..parsed.password
+   end
+  end
+  if userinfo then authority=userinfo.."@"..authority end
+ end
+ if authority then
+  url="//"..authority..url
+ end
+ if parsed.scheme then
+  url=parsed.scheme..":"..url
+ end
+ if parsed.fragment then
+  url=url.."#"..parsed.fragment
+ end
+ return url
+end
+function url.absolute(base_url,relative_url)
+ local base_parsed
+ if type(base_url)=="table" then
+  base_parsed=base_url
+  base_url=url.build(base_parsed)
+ else
+  base_parsed=url.parse(base_url)
+ end
+ local relative_parsed=url.parse(relative_url)
+ if not base_parsed then
+  return relative_url
+ elseif not relative_parsed then
+  return base_url
+ elseif relative_parsed.scheme then
+  return relative_url
+ else
+  relative_parsed.scheme=base_parsed.scheme
+  if not relative_parsed.authority then
+   relative_parsed.authority=base_parsed.authority
+   if not relative_parsed.path then
+    relative_parsed.path=base_parsed.path
+    if not relative_parsed.params then
+     relative_parsed.params=base_parsed.params
+     if not relative_parsed.query then
+      relative_parsed.query=base_parsed.query
+     end
+    end
+   else
+    relative_parsed.path=absolute_path(base_parsed.path or "",relative_parsed.path)
+   end
+  end
+  return url.build(relative_parsed)
+ end
+end
+function url.parse_path(path)
+ local parsed={}
+ path=path or ""
+ gsub(path,"([^/]+)",function (s)
+  insert(parsed,s)
+ end)
+ for i=1,#parsed do
+  parsed[i]=url.unescape(parsed[i])
+ end
+ if sub(path,1,1)=="/" then
+  parsed.is_absolute=1
+ end
+ if sub(path,-1,-1)=="/" then
+  parsed.is_directory=1
+ end
+ return parsed
+end
+function url.build_path(parsed,unsafe)
+ local path=""
+ local n=#parsed
+ if unsafe then
+  for i=1,n-1 do
+   path=path..parsed[i].."/"
+  end
+  if n>0 then
+   path=path..parsed[n]
+   if parsed.is_directory then
+    path=path.."/"
+   end
+  end
+ else
+  for i=1,n-1 do
+   path=path..protect_segment(parsed[i]).."/"
+  end
+  if n>0 then
+   path=path..protect_segment(parsed[n])
+   if parsed.is_directory then
+    path=path.."/"
+   end
+  end
+ end
+ if parsed.is_absolute then
+  path="/"..path
+ end
+ return path
+end
+package.loaded["socket.url"]=url
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-headers"] = package.loaded["util-soc-imp-headers"] or true
+
+-- original size: 5721, stripped down to: 3754
+
+
+local next=next
+local lower=string.lower
+local concat=table.concat
+local socket=socket or require("socket")
+local headers={}
+socket.headers=headers
+local canonic={
+ ["accept"]="Accept",
+ ["accept-charset"]="Accept-Charset",
+ ["accept-encoding"]="Accept-Encoding",
+ ["accept-language"]="Accept-Language",
+ ["accept-ranges"]="Accept-Ranges",
+ ["action"]="Action",
+ ["alternate-recipient"]="Alternate-Recipient",
+ ["age"]="Age",
+ ["allow"]="Allow",
+ ["arrival-date"]="Arrival-Date",
+ ["authorization"]="Authorization",
+ ["bcc"]="Bcc",
+ ["cache-control"]="Cache-Control",
+ ["cc"]="Cc",
+ ["comments"]="Comments",
+ ["connection"]="Connection",
+ ["content-description"]="Content-Description",
+ ["content-disposition"]="Content-Disposition",
+ ["content-encoding"]="Content-Encoding",
+ ["content-id"]="Content-ID",
+ ["content-language"]="Content-Language",
+ ["content-length"]="Content-Length",
+ ["content-location"]="Content-Location",
+ ["content-md5"]="Content-MD5",
+ ["content-range"]="Content-Range",
+ ["content-transfer-encoding"]="Content-Transfer-Encoding",
+ ["content-type"]="Content-Type",
+ ["cookie"]="Cookie",
+ ["date"]="Date",
+ ["diagnostic-code"]="Diagnostic-Code",
+ ["dsn-gateway"]="DSN-Gateway",
+ ["etag"]="ETag",
+ ["expect"]="Expect",
+ ["expires"]="Expires",
+ ["final-log-id"]="Final-Log-ID",
+ ["final-recipient"]="Final-Recipient",
+ ["from"]="From",
+ ["host"]="Host",
+ ["if-match"]="If-Match",
+ ["if-modified-since"]="If-Modified-Since",
+ ["if-none-match"]="If-None-Match",
+ ["if-range"]="If-Range",
+ ["if-unmodified-since"]="If-Unmodified-Since",
+ ["in-reply-to"]="In-Reply-To",
+ ["keywords"]="Keywords",
+ ["last-attempt-date"]="Last-Attempt-Date",
+ ["last-modified"]="Last-Modified",
+ ["location"]="Location",
+ ["max-forwards"]="Max-Forwards",
+ ["message-id"]="Message-ID",
+ ["mime-version"]="MIME-Version",
+ ["original-envelope-id"]="Original-Envelope-ID",
+ ["original-recipient"]="Original-Recipient",
+ ["pragma"]="Pragma",
+ ["proxy-authenticate"]="Proxy-Authenticate",
+ ["proxy-authorization"]="Proxy-Authorization",
+ ["range"]="Range",
+ ["received"]="Received",
+ ["received-from-mta"]="Received-From-MTA",
+ ["references"]="References",
+ ["referer"]="Referer",
+ ["remote-mta"]="Remote-MTA",
+ ["reply-to"]="Reply-To",
+ ["reporting-mta"]="Reporting-MTA",
+ ["resent-bcc"]="Resent-Bcc",
+ ["resent-cc"]="Resent-Cc",
+ ["resent-date"]="Resent-Date",
+ ["resent-from"]="Resent-From",
+ ["resent-message-id"]="Resent-Message-ID",
+ ["resent-reply-to"]="Resent-Reply-To",
+ ["resent-sender"]="Resent-Sender",
+ ["resent-to"]="Resent-To",
+ ["retry-after"]="Retry-After",
+ ["return-path"]="Return-Path",
+ ["sender"]="Sender",
+ ["server"]="Server",
+ ["smtp-remote-recipient"]="SMTP-Remote-Recipient",
+ ["status"]="Status",
+ ["subject"]="Subject",
+ ["te"]="TE",
+ ["to"]="To",
+ ["trailer"]="Trailer",
+ ["transfer-encoding"]="Transfer-Encoding",
+ ["upgrade"]="Upgrade",
+ ["user-agent"]="User-Agent",
+ ["vary"]="Vary",
+ ["via"]="Via",
+ ["warning"]="Warning",
+ ["will-retry-until"]="Will-Retry-Until",
+ ["www-authenticate"]="WWW-Authenticate",
+ ["x-mailer"]="X-Mailer",
+}
+headers.canonic=setmetatable(canonic,{
+ __index=function(t,k)
+  socket.report("invalid header: %s",k)
+  t[k]=k
+  return k
+ end
+})
+function headers.normalize(headers)
+ if not headers then
+  return {}
+ end
+ local normalized={}
+ for k,v in next,headers do
+  normalized[#normalized+1]=canonic[k]..": "..v
+ end
+ normalized[#normalized+1]=""
+ normalized[#normalized+1]=""
+ return concat(normalized,"\r\n")
+end
+function headers.lower(lowered,headers)
+ if not lowered then
+  return {}
+ end
+ if not headers then
+  lowered,headers={},lowered
+ end
+ for k,v in next,headers do
+  lowered[lower(k)]=v
+ end
+ return lowered
+end
+socket.headers=headers
+package.loaded["socket.headers"]=headers
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-tp"] = package.loaded["util-soc-imp-tp"] or true
+
+-- original size: 3116, stripped down to: 2533
+
+
+local setmetatable,next,type,tonumber=setmetatable,next,type,tonumber
+local find,upper=string.find,string.upper
+local socket=socket or require("socket")
+local ltn12=ltn12  or require("ltn12")
+local skipsocket=socket.skip
+local sinksocket=socket.sink
+local tcpsocket=socket.tcp
+local ltn12pump=ltn12.pump
+local pumpall=ltn12pump.all
+local pumpstep=ltn12pump.step
+local tp={
+ TIMEOUT=60,
+}
+socket.tp=tp
+local function get_reply(c)
+ local line,err=c:receive()
+ local reply=line
+ if err then return
+  nil,err
+ end
+ local code,sep=skipsocket(2,find(line,"^(%d%d%d)(.?)"))
+ if not code then
+  return nil,"invalid server reply"
+ end
+ if sep=="-" then
+  local current
+  repeat
+   line,err=c:receive()
+   if err then
+    return nil,err
+   end
+   current,sep=skipsocket(2,find(line,"^(%d%d%d)(.?)"))
+   reply=reply.."\n"..line
+  until code==current and sep==" "
+ end
+ return code,reply
+end
+local methods={}
+local mt={ __index=methods }
+function methods.getpeername(self)
+ return self.c:getpeername()
+end
+function methods.getsockname(self)
+ return self.c:getpeername()
+end
+function methods.check(self,ok)
+ local code,reply=get_reply(self.c)
+ if not code then
+  return nil,reply
+ end
+ local c=tonumber(code)
+ local t=type(ok)
+ if t=="function" then
+  return ok(c,reply)
+ elseif t=="table" then
+  for i=1,#ok do
+   if find(code,ok[i]) then
+    return c,reply
+   end
+  end
+  return nil,reply
+ elseif find(code,ok) then
+  return c,reply
+ else
+  return nil,reply
+ end
+end
+function methods.command(self,cmd,arg)
+ cmd=upper(cmd)
+ if arg then
+  cmd=cmd.." "..arg.."\r\n"
+ else
+  cmd=cmd.."\r\n"
+ end
+ return self.c:send(cmd)
+end
+function methods.sink(self,snk,pat)
+ local chunk,err=self.c:receive(pat)
+ return snk(chunk,err)
+end
+function methods.send(self,data)
+ return self.c:send(data)
+end
+function methods.receive(self,pat)
+ return self.c:receive(pat)
+end
+function methods.getfd(self)
+ return self.c:getfd()
+end
+function methods.dirty(self)
+ return self.c:dirty()
+end
+function methods.getcontrol(self)
+ return self.c
+end
+function methods.source(self,source,step)
+ local sink=sinksocket("keep-open",self.c)
+ local ret,err=pumpall(source,sink,step or pumpstep)
+ return ret,err
+end
+function methods.close(self)
+ self.c:close()
+ return 1
+end
+function tp.connect(host,port,timeout,create)
+ local c,e=(create or tcpsocket)()
+ if not c then
+  return nil,e
+ end
+ c:settimeout(timeout or tp.TIMEOUT)
+ local r,e=c:connect(host,port)
+ if not r then
+  c:close()
+  return nil,e
+ end
+ return setmetatable({ c=c },mt)
+end
+package.loaded["socket.tp"]=tp
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-http"] = package.loaded["util-soc-imp-http"] or true
+
+-- original size: 12624, stripped down to: 9598
+
+
+local tostring,tonumber,setmetatable,next,type=tostring,tonumber,setmetatable,next,type
+local find,lower,format,gsub,match=string.find,string.lower,string.format,string.gsub,string.match
+local concat=table.concat
+local socket=socket   or require("socket")
+local url=socket.url  or require("socket.url")
+local ltn12=ltn12    or require("ltn12")
+local mime=mime     or require("mime")
+local headers=socket.headers or require("socket.headers")
+local normalizeheaders=headers.normalize
+local parseurl=url.parse
+local buildurl=url.build
+local absoluteurl=url.absolute
+local unescapeurl=url.unescape
+local skipsocket=socket.skip
+local sinksocket=socket.sink
+local sourcesocket=socket.source
+local trysocket=socket.try
+local tcpsocket=socket.tcp
+local newtrysocket=socket.newtry
+local protectsocket=socket.protect
+local emptysource=ltn12.source.empty
+local stringsource=ltn12.source.string
+local rewindsource=ltn12.source.rewind
+local pumpstep=ltn12.pump.step
+local pumpall=ltn12.pump.all
+local sinknull=ltn12.sink.null
+local sinktable=ltn12.sink.table
+local lowerheaders=headers.lower
+local mimeb64=mime.b64
+local http={
+ TIMEOUT=60,
+ USERAGENT=socket._VERSION,
+}
+socket.http=http
+local PORT=80
+local SCHEMES={
+ http=true,
+}
+local function receiveheaders(sock,headers)
+ if not headers then
+  headers={}
+ end
+ local line,err=sock:receive("*l") 
+ if err then
+  return nil,err
+ end
+ while line~="" do
+  local name,value=skipsocket(2,find(line,"^(.-):%s*(.*)"))
+  if not (name and value) then
+   return nil,"malformed reponse headers"
+  end
+  name=lower(name)
+  line,err=sock:receive("*l")
+  if err then
+   return nil,err
+  end
+  while find(line,"^%s") do
+   value=value..line
+   line=sock:receive("*l")
+   if err then
+    return nil,err
+   end
+  end
+  local found=headers[name]
+  if found then
+   value=found..", "..value
+  end
+  headers[name]=value
+ end
+ return headers
+end
+socket.sourcet["http-chunked"]=function(sock,headers)
+ return setmetatable (
+  {
+   getfd=function() return sock:getfd() end,
+   dirty=function() return sock:dirty() end,
+  },{
+   __call=function()
+    local line,err=sock:receive("*l")
+    if err then
+     return nil,err
+    end
+    local size=tonumber(gsub(line,";.*",""),16)
+    if not size then
+     return nil,"invalid chunk size"
+    end
+    if size>0 then
+     local chunk,err,part=sock:receive(size)
+     if chunk then
+      sock:receive("*a")
+     end
+     return chunk,err
+    else
+     headers,err=receiveheaders(sock,headers)
+     if not headers then
+      return nil,err
+     end
+    end
+   end
+  }
+ )
+end
+socket.sinkt["http-chunked"]=function(sock)
+ return setmetatable(
+  {
+   getfd=function() return sock:getfd() end,
+   dirty=function() return sock:dirty() end,
+  },
+  {
+   __call=function(self,chunk,err)
+    if not chunk then
+     chunk=""
+    end
+    return sock:send(format("%X\r\n%s\r\n",#chunk,chunk))
+   end
+ })
+end
+local methods={}
+local mt={ __index=methods }
+local function openhttp(host,port,create)
+ local c=trysocket((create or tcpsocket)())
+ local h=setmetatable({ c=c },mt)
+ local try=newtrysocket(function() h:close() end)
+ h.try=try
+ try(c:settimeout(http.TIMEOUT))
+ try(c:connect(host,port or PORT))
+ return h
+end
+http.open=openhttp
+function methods.sendrequestline(self,method,uri)
+ local requestline=format("%s %s HTTP/1.1\r\n",method or "GET",uri)
+ return self.try(self.c:send(requestline))
+end
+function methods.sendheaders(self,headers)
+ self.try(self.c:send(normalizeheaders(headers)))
+ return 1
+end
+function methods.sendbody(self,headers,source,step)
+ if not source then
+  source=emptysource()
+ end
+ if not step then
+  step=pumpstep
+ end
+ local mode="http-chunked"
+ if headers["content-length"] then
+  mode="keep-open"
+ end
+ return self.try(pumpall(source,sinksocket(mode,self.c),step))
+end
+function methods.receivestatusline(self)
+ local try=self.try
+ local status=try(self.c:receive(5))
+ if status~="HTTP/" then
+  return nil,status 
+ end
+ status=try(self.c:receive("*l",status))
+ local code=skipsocket(2,find(status,"HTTP/%d*%.%d* (%d%d%d)"))
+ return try(tonumber(code),status)
+end
+function methods.receiveheaders(self)
+ return self.try(receiveheaders(self.c))
+end
+function methods.receivebody(self,headers,sink,step)
+ if not sink then
+  sink=sinknull()
+ end
+ if not step then
+  step=pumpstep
+ end
+ local length=tonumber(headers["content-length"])
+ local encoding=headers["transfer-encoding"] 
+ local mode="default" 
+ if encoding and encoding~="identity" then
+  mode="http-chunked"
+ elseif length then
+  mode="by-length"
+ end
+ return self.try(pumpall(sourcesocket(mode,self.c,length),sink,step))
+end
+function methods.receive09body(self,status,sink,step)
+ local source=rewindsource(sourcesocket("until-closed",self.c))
+ source(status)
+ return self.try(pumpall(source,sink,step))
+end
+function methods.close(self)
+ return self.c:close()
+end
+local function adjusturi(request)
+ if not request.proxy and not http.PROXY then
+  request={
+     path=trysocket(request.path,"invalid path 'nil'"),
+     params=request.params,
+     query=request.query,
+     fragment=request.fragment,
+  }
+ end
+ return buildurl(request)
+end
+local function adjustheaders(request)
+ local headers={
+  ["user-agent"]=http.USERAGENT,
+  ["host"]=gsub(request.authority,"^.-@",""),
+  ["connection"]="close, TE",
+  ["te"]="trailers"
+ }
+ local username=request.user
+ local password=request.password
+ if username and password then
+  headers["authorization"]="Basic "..(mimeb64(username..":"..unescapeurl(password)))
+ end
+ local proxy=request.proxy or http.PROXY
+ if proxy then
+  proxy=parseurl(proxy)
+  local username=proxy.user
+  local password=proxy.password
+  if username and password then
+   headers["proxy-authorization"]="Basic "..(mimeb64(username..":"..password))
+  end
+ end
+ local requestheaders=request.headers
+ if requestheaders then
+  headers=lowerheaders(headers,requestheaders)
+ end
+ return headers
+end
+local default={
+ host="",
+ port=PORT,
+ path="/",
+ scheme="http"
+}
+local function adjustrequest(originalrequest)
+ local url=originalrequest.url
+ local request=url and parseurl(url,default) or {}
+ for k,v in next,originalrequest do
+  request[k]=v
+ end
+ local host=request.host
+ local port=request.port
+ local uri=request.uri
+ if not host or host=="" then
+  trysocket(nil,"invalid host '"..tostring(host).."'")
+ end
+ if port=="" then
+  request.port=PORT
+ end
+ if not uri or uri=="" then
+  request.uri=adjusturi(request)
+ end
+ request.headers=adjustheaders(request)
+ local proxy=request.proxy or http.PROXY
+ if proxy then
+  proxy=parseurl(proxy)
+  request.host=proxy.host
+  request.port=proxy.port or 3128
+ end
+ return request
+end
+local maxredericts=4
+local validredirects={ [301]=true,[302]=true,[303]=true,[307]=true }
+local validmethods={ [false]=true,GET=true,HEAD=true }
+local function shouldredirect(request,code,headers)
+ local location=headers.location
+ if not location then
+  return false
+ end
+ location=gsub(location,"%s","")
+ if location=="" then
+  return false
+ end
+ local scheme=match(location,"^([%w][%w%+%-%.]*)%:")
+ if scheme and not SCHEMES[scheme] then
+  return false
+ end
+ local method=request.method
+ local redirect=request.redirect
+ local redirects=request.nredirects or 0
+ return redirect and validredirects[code] and validmethods[method] and redirects<=maxredericts
+end
+local function shouldreceivebody(request,code)
+ if request.method=="HEAD" then
+  return nil
+ end
+ if code==204 or code==304 then
+  return nil
+ end
+ if code>=100 and code<200 then
+  return nil
+ end
+ return 1
+end
+local tredirect,trequest,srequest
+tredirect=function(request,location)
+ local result,code,headers,status=trequest {
+  url=absoluteurl(request.url,location),
+  source=request.source,
+  sink=request.sink,
+  headers=request.headers,
+  proxy=request.proxy,
+  nredirects=(request.nredirects or 0)+1,
+  create=request.create,
+ }
+ if not headers then
+  headers={}
+ end
+ if not headers.location then
+  headers.location=location
+ end
+ return result,code,headers,status
+end
+trequest=function(originalrequest)
+ local request=adjustrequest(originalrequest)
+ local connection=openhttp(request.host,request.port,request.create)
+ local headers=request.headers
+ connection:sendrequestline(request.method,request.uri)
+ connection:sendheaders(headers)
+ if request.source then
+  connection:sendbody(headers,request.source,request.step)
+ end
+ local code,status=connection:receivestatusline()
+ if not code then
+  connection:receive09body(status,request.sink,request.step)
+  return 1,200
+ end
+ while code==100 do
+  headers=connection:receiveheaders()
+  code,status=connection:receivestatusline()
+ end
+ headers=connection:receiveheaders()
+ if shouldredirect(request,code,headers) and not request.source then
+  connection:close()
+  return tredirect(originalrequest,headers.location)
+ end
+ if shouldreceivebody(request,code) then
+  connection:receivebody(headers,request.sink,request.step)
+ end
+ connection:close()
+ return 1,code,headers,status
+end
+local function genericform(url,body)
+ local buffer={}
+ local request={
+  url=url,
+  sink=sinktable(buffer),
+  target=buffer,
+ }
+ if body then
+  request.source=stringsource(body)
+  request.method="POST"
+  request.headers={
+   ["content-length"]=#body,
+   ["content-type"]="application/x-www-form-urlencoded"
+  }
+ end
+ return request
+end
+http.genericform=genericform
+srequest=function(url,body)
+ local request=genericform(url,body)
+ local _,code,headers,status=trequest(request)
+ return concat(request.target),code,headers,status
+end
+http.request=protectsocket(function(request,body)
+ if type(request)=="string" then
+  return srequest(request,body)
+ else
+  return trequest(request)
+ end
+end)
+package.loaded["socket.http"]=http
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-ftp"] = package.loaded["util-soc-imp-ftp"] or true
+
+-- original size: 10357, stripped down to: 8548
+
+
+local setmetatable,type,next=setmetatable,type,next
+local find,format,gsub,match=string.find,string.format,string.gsub,string.match
+local concat=table.concat
+local mod=math.mod
+local socket=socket  or require("socket")
+local url=socket.url or require("socket.url")
+local tp=socket.tp  or require("socket.tp")
+local ltn12=ltn12   or require("ltn12")
+local tcpsocket=socket.tcp
+local trysocket=socket.try
+local skipsocket=socket.skip
+local sinksocket=socket.sink
+local selectsocket=socket.select
+local bindsocket=socket.bind
+local newtrysocket=socket.newtry
+local sourcesocket=socket.source
+local protectsocket=socket.protect
+local parseurl=url.parse
+local unescapeurl=url.unescape
+local pumpall=ltn12.pump.all
+local pumpstep=ltn12.pump.step
+local sourcestring=ltn12.source.string
+local sinktable=ltn12.sink.table
+local ftp={
+ TIMEOUT=60,
+ USER="ftp",
+ PASSWORD="anonymous at anonymous.org",
+}
+socket.ftp=ftp
+local PORT=21
+local methods={}
+local mt={ __index=methods }
+function ftp.open(server,port,create)
+ local tp=trysocket(tp.connect(server,port or PORT,ftp.TIMEOUT,create))
+ local f=setmetatable({ tp=tp },metat)
+ f.try=newtrysocket(function() f:close() end)
+ return f
+end
+function methods.portconnect(self)
+ local try=self.try
+ local server=self.server
+ try(server:settimeout(ftp.TIMEOUT))
+ self.data=try(server:accept())
+ try(self.data:settimeout(ftp.TIMEOUT))
+end
+function methods.pasvconnect(self)
+ local try=self.try
+ self.data=try(tcpsocket())
+ self(self.data:settimeout(ftp.TIMEOUT))
+ self(self.data:connect(self.pasvt.address,self.pasvt.port))
+end
+function methods.login(self,user,password)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("user",user or ftp.USER))
+ local code,reply=try(tp:check{"2..",331})
+ if code==331 then
+  try(tp:command("pass",password or ftp.PASSWORD))
+  try(tp:check("2.."))
+ end
+ return 1
+end
+function methods.pasv(self)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("pasv"))
+ local code,reply=try(self.tp:check("2.."))
+ local pattern="(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)"
+ local a,b,c,d,p1,p2=skipsocket(2,find(reply,pattern))
+ try(a and b and c and d and p1 and p2,reply)
+ local address=format("%d.%d.%d.%d",a,b,c,d)
+ local port=p1*256+p2
+ local server=self.server
+ self.pasvt={
+  address=address,
+  port=port,
+ }
+ if server then
+  server:close()
+  self.server=nil
+ end
+ return address,port
+end
+function methods.epsv(self)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("epsv"))
+ local code,reply=try(tp:check("229"))
+ local pattern="%((.)(.-)%1(.-)%1(.-)%1%)"
+ local d,prt,address,port=match(reply,pattern)
+ try(port,"invalid epsv response")
+ local address=tp:getpeername()
+ local server=self.server
+ self.pasvt={
+  address=address,
+  port=port,
+ }
+ if self.server then
+  server:close()
+  self.server=nil
+ end
+ return address,port
+end
+function methods.port(self,address,port)
+ local try=self.try
+ local tp=self.tp
+ self.pasvt=nil
+ if not address then
+  address,port=try(tp:getsockname())
+  self.server=try(bindsocket(address,0))
+  address,port=try(self.server:getsockname())
+  try(self.server:settimeout(ftp.TIMEOUT))
+ end
+ local pl=mod(port,256)
+ local ph=(port-pl)/256
+ local arg=gsub(format("%s,%d,%d",address,ph,pl),"%.",",")
+ try(tp:command("port",arg))
+ try(tp:check("2.."))
+ return 1
+end
+function methods.eprt(self,family,address,port)
+ local try=self.try
+ local tp=self.tp
+ self.pasvt=nil
+ if not address then
+  address,port=try(tp:getsockname())
+  self.server=try(bindsocket(address,0))
+  address,port=try(self.server:getsockname())
+  try(self.server:settimeout(ftp.TIMEOUT))
+ end
+ local arg=format("|%s|%s|%d|",family,address,port)
+ try(tp:command("eprt",arg))
+ try(tp:check("2.."))
+ return 1
+end
+function methods.send(self,sendt)
+ local try=self.try
+ local tp=self.tp
+ try(self.pasvt or self.server,"need port or pasv first")
+ if self.pasvt then
+  self:pasvconnect()
+ end
+ local argument=sendt.argument or unescapeurl(gsub(sendt.path or "","^[/\\]",""))
+ if argument=="" then
+  argument=nil
+ end
+ local command=sendt.command or "stor"
+ try(tp:command(command,argument))
+ local code,reply=try(tp:check{"2..","1.."})
+ if not self.pasvt then
+  self:portconnect()
+ end
+ local step=sendt.step or pumpstep
+ local readt={ tp }
+ local checkstep=function(src,snk)
+  local readyt=selectsocket(readt,nil,0)
+  if readyt[tp] then
+   code=try(tp:check("2.."))
+  end
+  return step(src,snk)
+ end
+ local sink=sinksocket("close-when-done",self.data)
+ try(pumpall(sendt.source,sink,checkstep))
+ if find(code,"1..") then
+  try(tp:check("2.."))
+ end
+ self.data:close()
+ local sent=skipsocket(1,self.data:getstats())
+ self.data=nil
+ return sent
+end
+function methods.receive(self,recvt)
+ local try=self.try
+ local tp=self.tp
+ try(self.pasvt or self.server,"need port or pasv first")
+ if self.pasvt then self:pasvconnect() end
+ local argument=recvt.argument or unescapeurl(gsub(recvt.path or "","^[/\\]",""))
+ if argument=="" then
+  argument=nil
+ end
+ local command=recvt.command or "retr"
+ try(tp:command(command,argument))
+ local code,reply=try(tp:check{"1..","2.."})
+ if code>=200 and code<=299 then
+  recvt.sink(reply)
+  return 1
+ end
+ if not self.pasvt then
+  self:portconnect()
+ end
+ local source=sourcesocket("until-closed",self.data)
+ local step=recvt.step or pumpstep
+ try(pumpall(source,recvt.sink,step))
+ if find(code,"1..") then
+  try(tp:check("2.."))
+ end
+ self.data:close()
+ self.data=nil
+ return 1
+end
+function methods.cwd(self,dir)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("cwd",dir))
+ try(tp:check(250))
+ return 1
+end
+function methods.type(self,typ)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("type",typ))
+ try(tp:check(200))
+ return 1
+end
+function methods.greet(self)
+ local try=self.try
+ local tp=self.tp
+ local code=try(tp:check{"1..","2.."})
+ if find(code,"1..") then
+  try(tp:check("2.."))
+ end
+ return 1
+end
+function methods.quit(self)
+ local try=self.try
+ try(self.tp:command("quit"))
+ try(self.tp:check("2.."))
+ return 1
+end
+function methods.close(self)
+ local data=self.data
+ if data then
+  data:close()
+ end
+ local server=self.server
+ if server then
+  server:close()
+ end
+ local tp=self.tp
+ if tp then
+  tp:close()
+ end
+end
+local function override(t)
+ if t.url then
+  local u=parseurl(t.url)
+  for k,v in next,t do
+   u[k]=v
+  end
+  return u
+ else
+  return t
+ end
+end
+local function tput(putt)
+ putt=override(putt)
+ local host=putt.host
+ trysocket(host,"missing hostname")
+ local f=ftp.open(host,putt.port,putt.create)
+ f:greet()
+ f:login(putt.user,putt.password)
+ local typ=putt.type
+ if typ then
+  f:type(typ)
+ end
+ f:epsv()
+ local sent=f:send(putt)
+ f:quit()
+ f:close()
+ return sent
+end
+local default={
+ path="/",
+ scheme="ftp",
+}
+local function genericform(u)
+ local t=trysocket(parseurl(u,default))
+ trysocket(t.scheme=="ftp","wrong scheme '"..t.scheme.."'")
+ trysocket(t.host,"missing hostname")
+ local pat="^type=(.)$"
+ if t.params then
+  local typ=skipsocket(2,find(t.params,pat))
+  t.type=typ
+  trysocket(typ=="a" or typ=="i","invalid type '"..typ.."'")
+ end
+ return t
+end
+ftp.genericform=genericform
+local function sput(u,body)
+ local putt=genericform(u)
+ putt.source=sourcestring(body)
+ return tput(putt)
+end
+ftp.put=protectsocket(function(putt,body)
+ if type(putt)=="string" then
+  return sput(putt,body)
+ else
+  return tput(putt)
+ end
+end)
+local function tget(gett)
+ gett=override(gett)
+ local host=gett.host
+ trysocket(host,"missing hostname")
+ local f=ftp.open(host,gett.port,gett.create)
+ f:greet()
+ f:login(gett.user,gett.password)
+ if gett.type then
+  f:type(gett.type)
+ end
+ f:epsv()
+ f:receive(gett)
+ f:quit()
+ return f:close()
+end
+local function sget(u)
+ local gett=genericform(u)
+ local t={}
+ gett.sink=sinktable(t)
+ tget(gett)
+ return concat(t)
+end
+ftp.command=protectsocket(function(cmdt)
+ cmdt=override(cmdt)
+ local command=cmdt.command
+ local argument=cmdt.argument
+ local check=cmdt.check
+ local host=cmdt.host
+ trysocket(host,"missing hostname")
+ trysocket(command,"missing command")
+ local f=ftp.open(host,cmdt.port,cmdt.create)
+ local try=f.try
+ local tp=f.tp
+ f:greet()
+ f:login(cmdt.user,cmdt.password)
+ if type(command)=="table" then
+  local argument=argument or {}
+  for i=1,#command do
+   local cmd=command[i]
+   try(tp:command(cmd,argument[i]))
+   if check and check[i] then
+    try(tp:check(check[i]))
+   end
+  end
+ else
+  try(tp:command(command,argument))
+  if check then
+   try(tp:check(check))
+  end
+ end
+ f:quit()
+ return f:close()
+end)
+ftp.get=protectsocket(function(gett)
+ if type(gett)=="string" then
+  return sget(gett)
+ else
+  return tget(gett)
+ end
+end)
+package.loaded["socket.ftp"]=ftp
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-smtp"] = package.loaded["util-soc-imp-smtp"] or true
+
+-- original size: 7018, stripped down to: 5883
+
+
+local type,setmetatable,next=type,setmetatable,next
+local find,lower,format=string.find,string.lower,string.format
+local osdate,osgetenv=os.date,os.getenv
+local random=math.random
+local socket=socket   or require("socket")
+local headers=socket.headers or require("socket.headers")
+local ltn12=ltn12    or require("ltn12")
+local tp=socket.tp   or require("socket.tp")
+local mime=mime     or require("mime")
+local mimeb64=mime.b64
+local mimestuff=mime.stuff
+local skipsocket=socket.skip
+local trysocket=socket.try
+local newtrysocket=socket.newtry
+local protectsocket=socket.protect
+local normalizeheaders=headers.normalize
+local lowerheaders=headers.lower
+local createcoroutine=coroutine.create
+local resumecoroutine=coroutine.resume
+local yieldcoroutine=coroutine.resume
+local smtp={
+ TIMEOUT=60,
+ SERVER="localhost",
+ PORT=25,
+ DOMAIN=osgetenv("SERVER_NAME") or "localhost",
+ ZONE="-0000",
+}
+socket.smtp=smtp
+local methods={}
+local mt={ __index=methods }
+function methods.greet(self,domain)
+ local try=self.try
+ local tp=self.tp
+ try(tp:check("2.."))
+ try(tp:command("EHLO",domain or _M.DOMAIN))
+ return skipsocket(1,try(tp:check("2..")))
+end
+function methods.mail(self,from)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("MAIL","FROM:"..from))
+ return try(tp:check("2.."))
+end
+function methods.rcpt(self,to)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("RCPT","TO:"..to))
+ return try(tp:check("2.."))
+end
+function methods.data(self,src,step)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("DATA"))
+ try(tp:check("3.."))
+ try(tp:source(src,step))
+ try(tp:send("\r\n.\r\n"))
+ return try(tp:check("2.."))
+end
+function methods.quit(self)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("QUIT"))
+ return try(tp:check("2.."))
+end
+function methods.close(self)
+ return self.tp:close()
+end
+function methods.login(self,user,password)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("AUTH","LOGIN"))
+ try(tp:check("3.."))
+ try(tp:send(mimeb64(user).."\r\n"))
+ try(tp:check("3.."))
+ try(tp:send(mimeb64(password).."\r\n"))
+ return try(tp:check("2.."))
+end
+function methods.plain(self,user,password)
+ local try=self.try
+ local tp=self.tp
+ local auth="PLAIN "..mimeb64("\0"..user.."\0"..password)
+ try(tp:command("AUTH",auth))
+ return try(tp:check("2.."))
+end
+function methods.auth(self,user,password,ext)
+ if not user or not password then
+  return 1
+ end
+ local try=self.try
+ if find(ext,"AUTH[^\n]+LOGIN") then
+  return self:login(user,password)
+ elseif find(ext,"AUTH[^\n]+PLAIN") then
+  return self:plain(user,password)
+ else
+  try(nil,"authentication not supported")
+ end
+end
+function methods.send(self,mail)
+ self:mail(mail.from)
+ local receipt=mail.rcpt
+ if type(receipt)=="table" then
+  for i=1,#receipt do
+   self:rcpt(receipt[i])
+  end
+ elseif receipt then
+  self:rcpt(receipt)
+ end
+ self:data(ltn12.source.chain(mail.source,mimestuff()),mail.step)
+end
+local function opensmtp(self,server,port,create)
+ if not server or server=="" then
+  server=smtp.SERVER
+ end
+ if not port or port=="" then
+  port=smtp.PORT
+ end
+ local s={
+  tp=trysocket(tp.connect(server,port,smtp.TIMEOUT,create)),
+  try=newtrysocket(function()
+   s:close()
+  end),
+ }
+ setmetatable(s,mt)
+ return s
+end
+smtp.open=opensmtp
+local nofboundaries=0
+local function newboundary()
+ nofboundaries=nofboundaries+1
+ return format('%s%05d==%05u',osdate('%d%m%Y%H%M%S'),random(0,99999),nofboundaries)
+end
+local send_message
+local function send_headers(headers)
+ yieldcoroutine(normalizeheaders(headers))
+end
+local function send_multipart(message)
+ local boundary=newboundary()
+ local headers=lowerheaders(message.headers)
+ local body=message.body
+ local preamble=body.preamble
+ local epilogue=body.epilogue
+ local content=headers['content-type'] or 'multipart/mixed'
+ headers['content-type']=content..'; boundary="'..boundary..'"'
+ send_headers(headers)
+ if preamble then
+  yieldcoroutine(preamble)
+  yieldcoroutine("\r\n")
+ end
+ for i=1,#body do
+  yieldcoroutine("\r\n--"..boundary.."\r\n")
+  send_message(body[i])
+ end
+ yieldcoroutine("\r\n--"..boundary.."--\r\n\r\n")
+ if epilogue then
+  yieldcoroutine(epilogue)
+  yieldcoroutine("\r\n")
+ end
+end
+local default_content_type='text/plain; charset="UTF-8"'
+local function send_source(message)
+ local headers=lowerheaders(message.headers)
+ if not headers['content-type'] then
+  headers['content-type']=default_content_type
+ end
+ send_headers(headers)
+ local getchunk=message.body
+ while true do
+  local chunk,err=getchunk()
+  if err then
+   yieldcoroutine(nil,err)
+  elseif chunk then
+   yieldcoroutine(chunk)
+  else
+   break
+  end
+ end
+end
+local function send_string(message)
+ local headers=lowerheaders(message.headers)
+ if not headers['content-type'] then
+  headers['content-type']=default_content_type
+ end
+ send_headers(headers)
+ yieldcoroutine(message.body)
+end
+function send_message(message)
+ local body=message.body
+ if type(body)=="table" then
+  send_multipart(message)
+ elseif type(body)=="function" then
+  send_source(message)
+ else
+  send_string(message)
+ end
+end
+local function adjust_headers(message)
+ local headers=lowerheaders(message.headers)
+ if not headers["date"] then
+  headers["date"]=osdate("!%a, %d %b %Y %H:%M:%S ")..(message.zone or smtp.ZONE)
+ end
+ if not headers["x-mailer"] then
+  headers["x-mailer"]=socket._VERSION
+ end
+ headers["mime-version"]="1.0"
+ return headers
+end
+function smtp.message(message)
+ message.headers=adjust_headers(message)
+ local action=createcoroutine(function()
+  send_message(message)
+ end)
+ return function()
+  local ret,a,b=resumecoroutine(action)
+  if ret then
+   return a,b
+  else
+   return nil,a
+  end
+ end
+end
+smtp.send=protectsocket(function(mail)
+ local snd=opensmtp(smtp,mail.server,mail.port,mail.create)
+ local ext=snd:greet(mail.domain)
+ snd:auth(mail.user,mail.password,ext)
+ snd:send(mail)
+ snd:quit()
+ return snd:close()
+end)
+package.loaded["socket.smtp"]=smtp
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["trac-set"] = package.loaded["trac-set"] or true
+
+-- original size: 14568, stripped down to: 9644
+
+if not modules then modules={} end modules ['trac-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"
+}
+local type,next,tostring,tonumber=type,next,tostring,tonumber
+local print=print
+local concat,sortedhash=table.concat,table.sortedhash
+local formatters,find,lower,gsub,topattern=string.formatters,string.find,string.lower,string.gsub,string.topattern
+local is_boolean=string.is_boolean
+local settings_to_hash=utilities.parsers.settings_to_hash
+local allocate=utilities.storage.allocate
+utilities=utilities or {}
+local utilities=utilities
+local setters=utilities.setters or {}
+utilities.setters=setters
+local data={}
+local trace_initialize=false 
+local frozen=true  
+local function initialize_setter(filename,name,values) 
+ local setter=data[name]
+ if setter then
+  local data=setter.data
+  if data then
+   for key,newvalue in sortedhash(values) do
+    local newvalue=is_boolean(newvalue,newvalue,true) 
+    local functions=data[key]
+    if functions then
+     local oldvalue=functions.value
+     if functions.frozen then
+      if trace_initialize then
+       setter.report("%s: %a is %s to %a",filename,key,"frozen",oldvalue)
+      end
+     elseif #functions>0 and not oldvalue then
+      if trace_initialize then
+       setter.report("%s: %a is %s to %a",filename,key,"set",newvalue)
+      end
+      for i=1,#functions do
+       functions[i](newvalue)
+      end
+      functions.value=newvalue
+      functions.frozen=functions.frozen or frozen
+     else
+      if trace_initialize then
+       setter.report("%s: %a is %s as %a",filename,key,"kept",oldvalue)
+      end
+     end
+    else
+     functions={ default=newvalue,frozen=frozen }
+     data[key]=functions
+     if trace_initialize then
+      setter.report("%s: %a is %s to %a",filename,key,"defaulted",newvalue)
+     end
+    end
+   end
+   return true
+  end
+ end
+end
+local function set(t,what,newvalue)
+ local data=t.data 
+ if data and not data.frozen then
+  local done=t.done
+  if type(what)=="string" then
+   what=settings_to_hash(what) 
+  end
+  if type(what)~="table" then
+   return
+  end
+  if not done then 
+   done={}
+   t.done=done
+  end
+  for w,value in sortedhash(what) do
+   if value=="" then
+    value=newvalue
+   elseif not value then
+    value=false 
+   else
+    value=is_boolean(value,value,true) 
+   end
+   w=topattern(w,true,true)
+   for name,functions in sortedhash(data) do
+    if done[name] then
+    elseif find(name,w) then
+     done[name]=true
+     for i=1,#functions do
+      functions[i](value)
+     end
+     functions.value=value
+    end
+   end
+  end
+ end
+end
+local function reset(t)
+ local data=t.data
+ if data and not data.frozen then
+  for name,functions in sortedthash(data) do
+   for i=1,#functions do
+    functions[i](false)
+   end
+   functions.value=false
+  end
+ end
+end
+local function enable(t,what)
+ set(t,what,true)
+end
+local function disable(t,what)
+ local data=t.data
+ if not what or what=="" then
+  t.done={}
+  reset(t)
+ else
+  set(t,what,false)
+ end
+end
+local function register_setter(t,what,...)
+ local data=t.data
+ what=lower(what)
+ local functions=data[what]
+ if not functions then
+  functions={}
+  data[what]=functions
+  if trace_initialize then
+   t.report("defining %a",what)
+  end
+ end
+ local default=functions.default 
+ for i=1,select("#",...) do
+  local fnc=select(i,...)
+  local typ=type(fnc)
+  if typ=="string" then
+   if trace_initialize then
+    t.report("coupling %a to %a",what,fnc)
+   end
+   local s=fnc 
+   fnc=function(value) set(t,s,value) end
+  elseif typ=="table" then
+   functions.values=fnc
+   fnc=nil
+  elseif typ~="function" then
+   fnc=nil
+  end
+  if fnc then
+   functions[#functions+1]=fnc
+   local value=functions.value or default
+   if value~=nil then
+    fnc(value)
+    functions.value=value
+   end
+  end
+ end
+ return false 
+end
+local function enable_setter(t,what)
+ local e=t.enable
+ t.enable,t.done=enable,{}
+ set(t,what,true)
+ enable(t,what)
+ t.enable,t.done=e,{}
+end
+local function disable_setter(t,what)
+ local e=t.disable
+ t.disable,t.done=disable,{}
+ disable(t,what)
+ t.disable,t.done=e,{}
+end
+local function reset_setter(t)
+ t.done={}
+ reset(t)
+end
+local function list_setter(t) 
+ local list=table.sortedkeys(t.data)
+ local user,system={},{}
+ for l=1,#list do
+  local what=list[l]
+  if find(what,"^%*") then
+   system[#system+1]=what
+  else
+   user[#user+1]=what
+  end
+ end
+ return user,system
+end
+local function show_setter(t,pattern)
+ local list=list_setter(t)
+ t.report()
+ for k=1,#list do
+  local name=list[k]
+  if not pattern or find(name,pattern) then
+   local functions=t.data[name]
+   if functions then
+    local value=functions.value
+    local default=functions.default
+    local values=functions.values
+    local modules=#functions
+    if default==nil then
+     default="unset"
+    elseif type(default)=="table" then
+     default=concat(default,"|")
+    else
+     default=tostring(default)
+    end
+    if value==nil then
+     value="unset"
+    elseif type(value)=="table" then
+     value=concat(value,"|")
+    else
+     value=tostring(value)
+    end
+    t.report(name)
+    t.report("    modules : %i",modules)
+    t.report("    default : %s",default)
+    t.report("    value   : %s",value)
+   if values then
+    local v={} for i=1,#values do v[i]=tostring(values[i]) end
+    t.report("    values  : % t",v)
+   end
+    t.report()
+   end
+  end
+ end
+end
+function setters.report(setter,fmt,...)
+ if fmt then
+  print(formatters["%-15s : %s"](setter.name,formatters[fmt](...)))
+ else
+  print("")
+ end
+end
+local function setter_default(setter,name)
+ local d=setter.data[name]
+ return d and d.default
+end
+local function setter_value(setter,name)
+ local d=setter.data[name]
+ return d and (d.value or d.default)
+end
+local function setter_values(setter,name)
+ local d=setter.data[name]
+ return d and d.values
+end
+local function new_setter(name) 
+ local setter 
+ setter={
+  data=allocate(),
+  name=name,
+  report=function(...)   setters.report (setter,...) end,
+  enable=function(...)   enable_setter  (setter,...) end,
+  disable=function(...)   disable_setter (setter,...) end,
+  reset=function(...)   reset_setter   (setter,...) end,
+  register=function(...)   register_setter(setter,...) end,
+  list=function(...)  return list_setter (setter,...) end,
+  show=function(...)   show_setter (setter,...) end,
+  default=function(...)  return setter_default (setter,...) end,
+  value=function(...)  return setter_value   (setter,...) end,
+  values=function(...)  return setter_values  (setter,...) end,
+ }
+ data[name]=setter
+ return setter
+end
+setters.enable=enable_setter
+setters.disable=disable_setter
+setters.register=register_setter
+setters.list=list_setter
+setters.show=show_setter
+setters.reset=reset_setter
+setters.new=new_setter
+setters.initialize=initialize_setter
+trackers=new_setter("trackers")
+directives=new_setter("directives")
+experiments=new_setter("experiments")
+local t_enable,t_disable=trackers   .enable,trackers   .disable
+local d_enable,d_disable=directives .enable,directives .disable
+local e_enable,e_disable=experiments.enable,experiments.disable
+local trace_directives=false local trace_directives=false  trackers.register("system.directives",function(v) trace_directives=v end)
+local trace_experiments=false local trace_experiments=false  trackers.register("system.experiments",function(v) trace_experiments=v end)
+function directives.enable(...)
+ if trace_directives then
+  directives.report("enabling: % t",{...})
+ end
+ d_enable(...)
+end
+function directives.disable(...)
+ if trace_directives then
+  directives.report("disabling: % t",{...})
+ end
+ d_disable(...)
+end
+function experiments.enable(...)
+ if trace_experiments then
+  experiments.report("enabling: % t",{...})
+ end
+ e_enable(...)
+end
+function experiments.disable(...)
+ if trace_experiments then
+  experiments.report("disabling: % t",{...})
+ end
+ e_disable(...)
+end
+directives.register("system.nostatistics",function(v)
+ if statistics then
+  statistics.enable=not v
+ else
+ end
+end)
+directives.register("system.nolibraries",function(v)
+ if libraries then
+  libraries=nil 
+ else
+ end
+end)
+if environment then
+ local engineflags=environment.engineflags
+ if engineflags then
+  local list=engineflags["c:trackers"] or engineflags["trackers"]
+  if type(list)=="string" then
+   initialize_setter("commandline flags","trackers",settings_to_hash(list))
+  end
+  local list=engineflags["c:directives"] or engineflags["directives"]
+  if type(list)=="string" then
+   initialize_setter("commandline flags","directives",settings_to_hash(list))
+  end
+ end
+end
+if texconfig then
+ local function set(k,v)
+  local v=tonumber(v)
+  if v then
+   texconfig[k]=v
+  end
+ end
+ directives.register("luatex.expanddepth",function(v) set("expand_depth",v)   end)
+ directives.register("luatex.hashextra",function(v) set("hash_extra",v)  end)
+ directives.register("luatex.nestsize",function(v) set("nest_size",v)   end)
+ directives.register("luatex.maxinopen",function(v) set("max_in_open",v) end)
+ directives.register("luatex.maxprintline",function(v) set("max_print_line",v) end)
+ directives.register("luatex.maxstrings",function(v) set("max_strings",v) end)
+ directives.register("luatex.paramsize",function(v) set("param_size",v)  end)
+ directives.register("luatex.savesize",function(v) set("save_size",v)   end)
+ directives.register("luatex.stacksize",function(v) set("stack_size",v)  end)
+end
+local data=table.setmetatableindex("table")
+updaters={
+ register=function(what,f)
+  local d=data[what]
+  d[#d+1]=f
+ end,
+ apply=function(what,...)
+  local d=data[what]
+  for i=1,#d do
+   d[i](...)
+  end
+ end,
+}
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["trac-log"] = package.loaded["trac-log"] or true
+
+-- original size: 16017, stripped down to: 11045
+
+if not modules then modules={} end modules ['trac-log']={
+ version=1.001,
+ comment="companion to trac-log.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local next,type,select,print=next,type,select,print
+local format,gmatch,find=string.format,string.gmatch,string.find
+local concat,insert,remove=table.concat,table.insert,table.remove
+local topattern=string.topattern
+local utfchar=utf.char
+local datetime=os.date
+local openfile=io.open
+local write_nl=print
+local write=io.write
+local setmetatableindex=table.setmetatableindex
+local formatters=string.formatters
+local settings_to_hash=utilities.parsers.settings_to_hash
+local sortedkeys=table.sortedkeys
+local variant="default"
+logs=logs or {}
+local logs=logs
+local moreinfo=[[
+More information about ConTeXt and the tools that come with it can be found at:
+]].."\n"..[[
+maillist : ntg-context at ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
+webpage  : http://www.pragma-ade.nl / http://tex.aanhet.net
+wiki     : http://contextgarden.net
+]]
+formatters.add (
+ formatters,"unichr",
+ [["U+" .. format("%%05X",%s) .. " (" .. utfchar(%s) .. ")"]]
+)
+formatters.add (
+ formatters,"chruni",
+ [[utfchar(%s) .. " (U+" .. format("%%05X",%s) .. ")"]]
+)
+local function ignore() end
+setmetatableindex(logs,function(t,k) t[k]=ignore;return ignore end)
+local report,subreport,status,settarget,setformats,settranslations
+local direct,subdirect,writer,pushtarget,poptarget,setlogfile,settimedlog,setprocessor,setformatters,newline
+local function ansisupported(specification)
+ if specification~="ansi" and specification~="ansilog" then
+  return false
+ elseif os and os.enableansi then
+  return os.enableansi()
+ else
+  return false
+ end
+end
+do
+ local report_yes,subreport_yes,status_yes
+ local report_nop,subreport_nop,status_nop
+ local variants={
+  default={
+   formats={
+    report_yes=formatters["%-15s | %s"],
+    report_nop=formatters["%-15s |"],
+    subreport_yes=formatters["%-15s | %s | %s"],
+    subreport_nop=formatters["%-15s | %s |"],
+    status_yes=formatters["%-15s : %s\n"],
+    status_nop=formatters["%-15s :\n"],
+   },
+  },
+  ansi={
+   formats={
+    report_yes=formatters["%-15s | %s"],
+    report_nop=formatters["%-15s |"],
+    subreport_yes=formatters["%-15s | %s | %s"],
+    subreport_nop=formatters["%-15s | %s |"],
+    status_yes=formatters["%-15s : %s\n"],
+    status_nop=formatters["%-15s :\n"],
+   },
+  },
+ }
+ logs.flush=ignore
+ writer=function(s)
+  write_nl(s)
+ end
+ newline=function()
+  write_nl("\n")
+ end
+ report=function(a,b,c,...)
+  if c then
+   write_nl(report_yes(a,formatters[b](c,...)))
+  elseif b then
+   write_nl(report_yes(a,b))
+  elseif a then
+   write_nl(report_nop(a))
+  else
+   write_nl("")
+  end
+ end
+ subreport=function(a,sub,b,c,...)
+  if c then
+   write_nl(subreport_yes(a,sub,formatters[b](c,...)))
+  elseif b then
+   write_nl(subreport_yes(a,sub,b))
+  elseif a then
+   write_nl(subreport_nop(a,sub))
+  else
+   write_nl("")
+  end
+ end
+ status=function(a,b,c,...) 
+  if c then
+   write_nl(status_yes(a,formatters[b](c,...)))
+  elseif b then
+   write_nl(status_yes(a,b)) 
+  elseif a then
+   write_nl(status_nop(a))
+  else
+   write_nl("\n")
+  end
+ end
+ direct=ignore
+ subdirect=ignore
+ settarget=ignore
+ pushtarget=ignore
+ poptarget=ignore
+ setformats=ignore
+ settranslations=ignore
+ setprocessor=function(f)
+  local writeline=write_nl
+  write_nl=function(s)
+   writeline(f(s))
+  end
+ end
+ setformatters=function(specification)
+  local f=nil
+  local d=variants.default
+  if specification then
+   if type(specification)=="table" then
+    f=specification.formats or specification
+   else
+    if not ansisupported(specification) then
+     specification="default"
+    end
+    local v=variants[specification]
+    if v then
+     f=v.formats
+    end
+   end
+  end
+  if f then
+   d=d.formats
+  else
+   f=d.formats
+   d=f
+  end
+  setmetatableindex(f,d)
+  report_yes=f.report_yes
+  report_nop=f.report_nop
+  subreport_yes=f.subreport_yes
+  subreport_nop=f.subreport_nop
+  status_yes=f.status_yes
+  status_nop=f.status_nop
+ end
+ setformatters(variant)
+ setlogfile=function(name,keepopen)
+  if name and name~="" then
+   local localtime=os.localtime
+   local writeline=write_nl
+   if keepopen then
+    local f=io.open(name,"ab")
+    write_nl=function(s)
+     writeline(s)
+     f:write(localtime()," | ",s,"\n")
+    end
+   else
+    write_nl=function(s)
+     writeline(s)
+     local f=io.open(name,"ab")
+     f:write(localtime()," | ",s,"\n")
+     f:close()
+    end
+   end
+  end
+  setlogfile=ignore
+ end
+ settimedlog=function()
+  local localtime=os.localtime
+  local writeline=write_nl
+  write_nl=function(s)
+   writeline(localtime().." | "..s)
+  end
+  settimedlog=ignore
+ end
+end
+logs.report=report
+logs.subreport=subreport
+logs.status=status
+logs.settarget=settarget
+logs.pushtarget=pushtarget
+logs.poptarget=poptarget
+logs.setformats=setformats
+logs.settranslations=settranslations
+logs.setlogfile=setlogfile
+logs.settimedlog=settimedlog
+logs.setprocessor=setprocessor
+logs.setformatters=setformatters
+logs.direct=direct
+logs.subdirect=subdirect
+logs.writer=writer
+logs.newline=newline
+local data={}
+local states=nil
+local force=false
+function logs.reporter(category,subcategory)
+ local logger=data[category]
+ if not logger then
+  local state=states==true
+  if not state and type(states)=="table" then
+   for c,_ in next,states do
+    if find(category,c) then
+     state=true
+     break
+    end
+   end
+  end
+  logger={
+   reporters={},
+   state=state,
+  }
+  data[category]=logger
+ end
+ local reporter=logger.reporters[subcategory or "default"]
+ if not reporter then
+  if subcategory then
+   reporter=function(...)
+    if force or not logger.state then
+     subreport(category,subcategory,...)
+    end
+   end
+   logger.reporters[subcategory]=reporter
+  else
+   local tag=category
+   reporter=function(...)
+    if force or not logger.state then
+     report(category,...)
+    end
+   end
+   logger.reporters.default=reporter
+  end
+ end
+ return reporter
+end
+logs.new=logs.reporter
+local ctxreport=logs.writer
+function logs.setmessenger(m)
+ ctxreport=m
+end
+function logs.messenger(category,subcategory)
+ if subcategory then
+  return function(...)
+   ctxreport(subdirect(category,subcategory,...))
+  end
+ else
+  return function(...)
+   ctxreport(direct(category,...))
+  end
+ end
+end
+local function setblocked(category,value) 
+ if category==true or category=="all" then
+  category,value="*",true
+ elseif category==false then
+  category,value="*",false
+ elseif value==nil then
+  value=true
+ end
+ if category=="*" then
+  states=value
+  for k,v in next,data do
+   v.state=value
+  end
+ else
+  alllocked=false
+  states=settings_to_hash(category,type(states)=="table" and states or nil)
+  for c in next,states do
+   local v=data[c]
+   if v then
+    v.state=value
+   else
+    c=topattern(c,true,true)
+    for k,v in next,data do
+     if find(k,c) then
+      v.state=value
+     end
+    end
+   end
+  end
+ end
+end
+function logs.disable(category,value)
+ setblocked(category,value==nil and true or value)
+end
+function logs.enable(category)
+ setblocked(category,false)
+end
+function logs.categories()
+ return sortedkeys(data)
+end
+function logs.show()
+ local n,c,s,max=0,0,0,0
+ for category,v in table.sortedpairs(data) do
+  n=n+1
+  local state=v.state
+  local reporters=v.reporters
+  local nc=#category
+  if nc>c then
+   c=nc
+  end
+  for subcategory,_ in next,reporters do
+   local ns=#subcategory
+   if ns>c then
+    s=ns
+   end
+   local m=nc+ns
+   if m>max then
+    max=m
+   end
+  end
+  local subcategories=concat(sortedkeys(reporters),", ")
+  if state==true then
+   state="disabled"
+  elseif state==false then
+   state="enabled"
+  else
+   state="unknown"
+  end
+  report("logging","category %a, subcategories %a, state %a",category,subcategories,state)
+ end
+ report("logging","categories: %s, max category: %s, max subcategory: %s, max combined: %s",n,c,s,max)
+end
+local delayed_reporters={}
+setmetatableindex(delayed_reporters,function(t,k)
+ local v=logs.reporter(k.name)
+ t[k]=v
+ return v
+end)
+function utilities.setters.report(setter,...)
+ delayed_reporters[setter](...)
+end
+directives.register("logs.blocked",function(v)
+ setblocked(v,true)
+end)
+directives.register("logs.target",function(v)
+ settarget(v)
+end)
+local nesting=0
+local verbose=false
+local hasscheme=url.hasscheme
+local simple=logs.reporter("comment")
+logs.simple=simple
+logs.simpleline=simple
+logs.setprogram=ignore 
+logs.extendbanner=ignore 
+logs.reportlines=ignore 
+logs.reportbanner=ignore 
+logs.reportline=ignore 
+logs.simplelines=ignore 
+logs.help=ignore
+local Carg,C,lpegmatch=lpeg.Carg,lpeg.C,lpeg.match
+local p_newline=lpeg.patterns.newline
+local linewise=(
+ Carg(1)*C((1-p_newline)^1)/function(t,s) t.report(s) end+Carg(1)*p_newline^2/function(t)   t.report()  end+p_newline
+)^1
+local function reportlines(t,str)
+ if str then
+  lpegmatch(linewise,str,1,t)
+ end
+end
+local function reportbanner(t)
+ local banner=t.banner
+ if banner then
+  t.report(banner)
+  t.report()
+ end
+end
+local function reportversion(t)
+ local banner=t.banner
+ if banner then
+  t.report(banner)
+ end
+end
+local function reporthelp(t,...)
+ local helpinfo=t.helpinfo
+ if type(helpinfo)=="string" then
+  reportlines(t,helpinfo)
+ elseif type(helpinfo)=="table" then
+  for i=1,select("#",...) do
+   reportlines(t,t.helpinfo[select(i,...)])
+   if i<n then
+    t.report()
+   end
+  end
+ end
+end
+local function reportinfo(t)
+ t.report()
+ reportlines(t,t.moreinfo)
+end
+local function reportexport(t,method)
+ report(t.helpinfo)
+end
+local reporters={
+ lines=reportlines,
+ banner=reportbanner,
+ version=reportversion,
+ help=reporthelp,
+ info=reportinfo,
+ export=reportexport,
+}
+local exporters={
+}
+logs.reporters=reporters
+logs.exporters=exporters
+function logs.application(t)
+ local arguments=environment and environment.arguments
+ if arguments then
+  local ansi=arguments.ansi or arguments.ansilog
+  if ansi then
+   logs.setformatters(arguments.ansi and "ansi" or "ansilog")
+  end
+ end
+ t.name=t.name   or "unknown"
+ t.banner=t.banner
+ t.moreinfo=moreinfo
+ t.report=logs.reporter(t.name)
+ t.help=function(...)
+  reporters.banner(t)
+  reporters.help(t,...)
+  reporters.info(t)
+ end
+ t.export=function(...)
+  reporters.export(t,...)
+ end
+ t.identify=function()
+  reporters.banner(t)
+ end
+ t.version=function()
+  reporters.version(t)
+ end
+ return t
+end
+local f_syslog=formatters["%s %s => %s => %s => %s\r"]
+function logs.system(whereto,process,jobname,category,fmt,arg,...)
+ local message=f_syslog(datetime("%d/%m/%y %H:%m:%S"),process,jobname,category,arg==nil and fmt or format(fmt,arg,...))
+ for i=1,10 do
+  local f=openfile(whereto,"a") 
+  if f then
+   f:write(message)
+   f:close()
+   break
+  else
+   sleep(0.1)
+  end
+ end
+end
+local report_system=logs.reporter("system","logs")
+if utilities then
+ utilities.report=report_system
+end
+if package.helpers.report then
+ package.helpers.report=logs.reporter("package loader") 
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["trac-inf"] = package.loaded["trac-inf"] or true
+
+-- original size: 9740, stripped down to: 7296
+
+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,offset=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,offset=0 }
+end
+local ticks=clock
+local seconds=function(n) return n or 0 end
+if os.type~="windows" then
+elseif lua.getpreciseticks then
+ ticks=lua.getpreciseticks
+ seconds=lua.getpreciseseconds
+elseif FFISUPPORTED then
+ local okay,kernel=pcall(ffi.load,"kernel32")
+ if kernel then
+  local tonumber=ffi.number or tonumber
+  ffi.cdef[[
+            int QueryPerformanceFrequency(int64_t *lpFrequency);
+            int QueryPerformanceCounter(int64_t *lpPerformanceCount);
+        ]]
+  local target=ffi.new("__int64[1]")
+  ticks=function()
+   if kernel.QueryPerformanceCounter(target)==1 then
+    return tonumber(target[0])
+   else
+    return 0
+   end
+  end
+  local target=ffi.new("__int64[1]")
+  seconds=function(ticks)
+   if kernel.QueryPerformanceFrequency(target)==1 then
+    return ticks/tonumber(target[0])
+   else
+    return 0
+   end
+  end
+ end
+else
+end
+local function starttiming(instance,reset)
+ local timer=timers[instance or "notimer"]
+ local it=timer.timing
+ if reset then
+  it=0
+  timer.loadtime=0
+ end
+ if it==0 then
+  timer.starttime=ticks()
+  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 and starttime>0 then
+   local stoptime=ticks()
+   local loadtime=stoptime-starttime
+   timer.stoptime=stoptime
+   timer.loadtime=timer.loadtime+loadtime
+   timer.timing=0
+   timer.starttime=0
+  end
+ end
+end
+local function benchmarktimer(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 and starttime>0 then
+   timer.offset=ticks()-starttime
+  else
+   timer.offset=0
+  end
+ end
+end
+local function elapsed(instance)
+ if type(instance)=="number" then
+  return instance
+ else
+  local timer=timers[instance or "notimer"]
+  return timer and seconds(timer.loadtime-2*(timer.offset or 0)) or 0
+ end
+end
+local function currenttime(instance)
+ if type(instance)=="number" then
+  return instance
+ else
+  local timer=timers[instance or "notimer"]
+  local it=timer.timing
+  if it>1 then
+  else
+   local starttime=timer.starttime
+   if starttime and starttime>0 then
+    return seconds(timer.loadtime+ticks()-starttime-2*(timer.offset or 0))
+   end
+  end
+  return 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.currenttime=currenttime
+statistics.elapsed=elapsed
+statistics.elapsedtime=elapsedtime
+statistics.elapsedindeed=elapsedindeed
+statistics.elapsedseconds=elapsedseconds
+statistics.benchmarktimer=benchmarktimer
+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("used engine",function()
+   return format("%s version: %s, functionality level: %s, banner: %s",
+    LUATEXENGINE,LUATEXVERSION,LUATEXFUNCTIONALITY,lower(status.banner))
+  end)
+  register("used hash slots",function()
+   return format("%s of %s + %s",status.cs_count,status.hash_size,status.hash_extra)
+  end)
+  register("callbacks",statistics.callbacks)
+  if JITSUPPORTED then
+   local jitstatus=jit.status
+   if jitstatus then
+    local jitstatus={ jitstatus() }
+    if jitstatus[1] then
+     register("luajit options",concat(jitstatus," ",2))
+    end
+   end
+  end
+  register("lua properties",function()
+   local hash=2^status.luatex_hashchars
+   local mask=load([[τεχ = 1]]) and "utf" or "ascii"
+   return format("engine: %s %s, used memory: %s, hash chars: min(%i,40), symbol mask: %s (%s)",
+    jit and "luajit" or "lua",LUAVERSION,statistics.memused(),hash,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, max: %s MB",
+  round(collectgarbage("count")/1000),
+  round(status.luastate_bytes/1000000),
+  status.luastate_bytes_max and round(status.luastate_bytes_max/1000000) or "unknown"
+ )
+end
+starttiming(statistics)
+function statistics.formatruntime(runtime) 
+ return format("%s seconds",runtime)   
+end
+function statistics.runtime()
+ stoptiming(statistics)
+ local runtime=lua.getruntime and lua.getruntime() or elapsedtime(statistics)
+ return statistics.formatruntime(runtime)
+end
+local report=logs.reporter("system")
+function statistics.timed(action,all)
+ starttiming("run")
+ action()
+ stoptiming("run")
+ local runtime=tonumber(elapsedtime("run"))
+ if all then
+  local alltime=tonumber(lua.getruntime and lua.getruntime() or elapsedtime(statistics))
+  if alltime and alltime>0 then
+   report("total runtime: %0.3f seconds of %0.3f seconds",runtime,alltime)
+   return
+  end
+ end
+ report("total runtime: %0.3f seconds",runtime)
+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
+function status.getreadstate()
+ return {
+  filename=status.filename   or "?",
+  linenumber=status.linenumber or 0,
+  iocode=status.inputid or 0,
+ }
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["trac-pro"] = package.loaded["trac-pro"] or true
+
+-- original size: 5841, stripped down to: 3352
+
+if not modules then modules={} end modules ['trac-pro']={
+ 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 getmetatable,setmetatable,rawset,type,next=getmetatable,setmetatable,rawset,type,next
+local trace_namespaces=false  trackers.register("system.namespaces",function(v) trace_namespaces=v end)
+local report_system=logs.reporter("system","protection")
+namespaces=namespaces or {}
+local namespaces=namespaces
+local registered={}
+local function report_index(k,name)
+ if trace_namespaces then
+  report_system("reference to %a in protected namespace %a: %s",k,name)
+  debugger.showtraceback(report_system)
+ else
+  report_system("reference to %a in protected namespace %a",k,name)
+ end
+end
+local function report_newindex(k,name)
+ if trace_namespaces then
+  report_system("assignment to %a in protected namespace %a: %s",k,name)
+  debugger.showtraceback(report_system)
+ else
+  report_system("assignment to %a in protected namespace %a",k,name)
+ end
+end
+local function register(name)
+ local data=name=="global" and _G or _G[name]
+ if not data then
+  return 
+ end
+ registered[name]=data
+ local m=getmetatable(data)
+ if not m then
+  m={}
+  setmetatable(data,m)
+ end
+ local index,newindex={},{}
+ m.__saved__index=m.__index
+ m.__no__index=function(t,k)
+  if not index[k] then
+   index[k]=true
+   report_index(k,name)
+  end
+  return nil
+ end
+ m.__saved__newindex=m.__newindex
+ m.__no__newindex=function(t,k,v)
+  if not newindex[k] then
+   newindex[k]=true
+   report_newindex(k,name)
+  end
+  rawset(t,k,v)
+ end
+ m.__protection__depth=0
+end
+local function private(name) 
+ local data=registered[name]
+ if not data then
+  data=_G[name]
+  if not data then
+   data={}
+   _G[name]=data
+  end
+  register(name)
+ end
+ return data
+end
+local function protect(name)
+ local data=registered[name]
+ if not data then
+  return
+ end
+ local m=getmetatable(data)
+ local pd=m.__protection__depth
+ if pd>0 then
+  m.__protection__depth=pd+1
+ else
+  m.__save_d_index,m.__saved__newindex=m.__index,m.__newindex
+  m.__index,m.__newindex=m.__no__index,m.__no__newindex
+  m.__protection__depth=1
+ end
+end
+local function unprotect(name)
+ local data=registered[name]
+ if not data then
+  return
+ end
+ local m=getmetatable(data)
+ local pd=m.__protection__depth
+ if pd>1 then
+  m.__protection__depth=pd-1
+ else
+  m.__index,m.__newindex=m.__saved__index,m.__saved__newindex
+  m.__protection__depth=0
+ end
+end
+local function protectall()
+ for name,_ in next,registered do
+  if name~="global" then
+   protect(name)
+  end
+ end
+end
+local function unprotectall()
+ for name,_ in next,registered do
+  if name~="global" then
+   unprotect(name)
+  end
+ end
+end
+namespaces.register=register  
+namespaces.private=private   
+namespaces.protect=protect
+namespaces.unprotect=unprotect
+namespaces.protectall=protectall
+namespaces.unprotectall=unprotectall
+namespaces.private("namespaces") registered={} register("global") 
+directives.register("system.protect",function(v)
+ if v then
+  protectall()
+ else
+  unprotectall()
+ end
+end)
+directives.register("system.checkglobals",function(v)
+ if v then
+  report_system("enabling global namespace guard")
+  protect("global")
+ else
+  report_system("disabling global namespace guard")
+  unprotect("global")
+ end
+end)
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-lua"] = package.loaded["util-lua"] or true
+
+-- original size: 7149, stripped down to: 4997
+
+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,collectgarbage=load,loadfile,type,collectgarbage
+utilities=utilities or {}
+utilities.lua=utilities.lua or {}
+local luautilities=utilities.lua
+local report_lua=logs.reporter("system","lua")
+local report_mem=logs.reporter("system","lua memory")
+local tracestripping=false
+local tracememory=false
+luautilities.stripcode=true  
+luautilities.alwaysstripcode=false 
+luautilities.nofstrippedchunks=0
+luautilities.nofstrippedbytes=0
+local strippedchunks={} 
+luautilities.strippedchunks=strippedchunks
+if not LUATEXENGINE then
+ LUATEXENGINE=status.luatex_engine and string.lower(status.luatex_engine)
+ JITSUPPORTED=LUATEXENGINE=="luajittex" or jit
+ CONTEXTLMTXMODE=CONTEXTLMTXMODE or (LUATEXENGINE=="luametatex" and 1) or 0
+end
+luautilities.suffixes={
+ tma="tma",
+ tmc=(CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 and "tmd") or (jit and "tmb") or "tmc",
+ lua="lua",
+ luc=(CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 and "lud") or (jit and "lub") or "luc",
+ lui="lui",
+ luv="luv",
+ luj="luj",
+ tua="tua",
+ tuc=(CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 and "tud") or (jit and "tub") or "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,macros)
+ name=name or fullname
+ if macros then
+  macros=lua.macros
+ end
+ local code,message
+ if macros then
+  code,message=macros.loaded(fullname,true,false)
+ 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")
+  code,message=loadfile(fullname)
+ 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,name,forcestrip) 
+ 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.loadstring(code,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
+ return code,0
+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
+local finalizers={}
+setmetatable(finalizers,{
+ __gc=function(t)
+  for i=1,#t do
+   pcall(t[i]) 
+  end
+ end
+} )
+function luautilities.registerfinalizer(f)
+ finalizers[#finalizers+1]=f
+end
+function luautilities.checkmemory(previous,threshold,trace) 
+ local current=collectgarbage("count")
+ if previous then
+  local checked=(threshold or 64)*1024
+  local delta=current-previous
+  if current-previous>checked then
+   collectgarbage("collect")
+   local afterwards=collectgarbage("count")
+   if trace or tracememory then
+    report_mem("previous %r MB, current %r MB, delta %r MB, threshold %r MB, afterwards %r MB",
+     previous/1024,current/1024,delta/1024,threshold,afterwards)
+   end
+   return afterwards
+  elseif trace or tracememory then
+   report_mem("previous %r MB, current %r MB, delta %r MB, threshold %r MB",
+    previous/1024,current/1024,delta/1024,threshold)
+  end
+ end
+ return current
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-deb"] = package.loaded["util-deb"] or true
+
+-- original size: 10593, stripped down to: 7102
+
+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 type,next,tostring,tonumber=type,next,tostring,tonumber
+local format,find,sub,gsub=string.format,string.find,string.sub,string.gsub
+local insert,remove,sort=table.insert,table.remove,table.sort
+local setmetatableindex=table.setmetatableindex
+utilities=utilities or {}
+local debugger=utilities.debugger or {}
+utilities.debugger=debugger
+local report=logs.reporter("debugger")
+local ticks=os.gettimeofday or os.clock
+local seconds=function(n) return n or 0 end
+local overhead=0
+local dummycalls=10*1000
+local nesting=0
+local names={}
+local initialize=false
+if lua.getpreciseticks then
+ initialize=function()
+  ticks=lua.getpreciseticks
+  seconds=lua.getpreciseseconds
+  initialize=false
+ end
+elseif not (FFISUPPORTED and ffi) then
+elseif os.type=="windows" then
+ initialize=function()
+  local kernel=ffilib("kernel32","system") 
+  if kernel then
+   local tonumber=ffi.number or tonumber
+   ffi.cdef[[
+                int QueryPerformanceFrequency(int64_t *lpFrequency);
+                int QueryPerformanceCounter(int64_t *lpPerformanceCount);
+            ]]
+   local target=ffi.new("__int64[1]")
+   ticks=function()
+    if kernel.QueryPerformanceCounter(target)==1 then
+     return tonumber(target[0])
+    else
+     return 0
+    end
+   end
+   local target=ffi.new("__int64[1]")
+   seconds=function(ticks)
+    if kernel.QueryPerformanceFrequency(target)==1 then
+     return ticks/tonumber(target[0])
+    else
+     return 0
+    end
+   end
+  end
+  initialize=false
+ end
+elseif os.type=="unix" then
+ initialize=function()
+  local C=ffi.C
+  local tonumber=ffi.number or tonumber
+  ffi.cdef [[
+            /* what a mess */
+            typedef int clk_id_t;
+            typedef enum { CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID } clk_id;
+            typedef struct timespec { long sec; long nsec; } ctx_timespec;
+            int clock_gettime(clk_id_t timerid, struct timespec *t);
+        ]]
+  local target=ffi.new("ctx_timespec[?]",1)
+  local clock=C.CLOCK_PROCESS_CPUTIME_ID
+  ticks=function ()
+   C.clock_gettime(clock,target)
+   return tonumber(target[0].sec*1000000000+target[0].nsec)
+  end
+  seconds=function(ticks)
+   return ticks/1000000000
+  end
+  initialize=false
+ end
+end
+setmetatableindex(names,function(t,name)
+ local v=setmetatableindex(function(t,source)
+  local v=setmetatableindex(function(t,line)
+   local v={ total=0,count=0,nesting=0 }
+   t[line]=v
+   return v
+  end)
+  t[source]=v
+  return v
+ end)
+ t[name]=v
+ return v
+end)
+local getinfo=nil
+local sethook=nil
+local function hook(where)
+ local f=getinfo(2,"nSl")
+ if f then
+  local source=f.short_src
+  if not source then
+   return
+  end
+  local line=f.linedefined or 0
+  local name=f.name
+  if not name then
+   local what=f.what
+   if what=="C" then
+    name="<anonymous>"
+   else
+    name=f.namewhat or what or "<unknown>"
+   end
+  end
+  local data=names[name][source][line]
+  if where=="call" then
+   local nesting=data.nesting
+   if nesting==0 then
+    data.count=data.count+1
+    insert(data,ticks())
+    data.nesting=1
+   else
+    data.nesting=nesting+1
+   end
+  elseif where=="return" then
+   local nesting=data.nesting
+   if nesting==1 then
+    local t=remove(data)
+    if t then
+     data.total=data.total+ticks()-t
+    end
+    data.nesting=0
+   else
+    data.nesting=nesting-1
+   end
+  end
+ end
+end
+function debugger.showstats(printer,threshold)
+ local printer=printer or report
+ local calls=0
+ local functions=0
+ local dataset={}
+ local length=0
+ local realtime=0
+ local totaltime=0
+ local threshold=threshold or 0
+ for name,sources in next,names do
+  for source,lines in next,sources do
+   for line,data in next,lines do
+    local count=data.count
+    if count>threshold then
+     if #name>length then
+      length=#name
+     end
+     local total=data.total
+     local real=total
+     if real>0 then
+      real=total-(count*overhead/dummycalls)
+      if real<0 then
+       real=0
+      end
+      realtime=realtime+real
+     end
+     totaltime=totaltime+total
+     if line<0 then
+      line=0
+     end
+     dataset[#dataset+1]={ real,total,count,name,source,line }
+    end
+   end
+  end
+ end
+ sort(dataset,function(a,b)
+  if a[1]==b[1] then
+   if a[2]==b[2] then
+    if a[3]==b[3] then
+     if a[4]==b[4] then
+      if a[5]==b[5] then
+       return a[6]<b[6]
+      else
+       return a[5]<b[5]
+      end
+     else
+      return a[4]<b[4]
+     end
+    else
+     return b[3]<a[3]
+    end
+   else
+    return b[2]<a[2]
+   end
+  else
+   return b[1]<a[1]
+  end
+ end)
+ if length>50 then
+  length=50
+ end
+ local fmt=string.formatters["%4.9k s  %3.3k %%  %4.9k s  %3.3k %%  %8i #  %-"..length.."s  %4i  %s"]
+ for i=1,#dataset do
+  local data=dataset[i]
+  local real=data[1]
+  local total=data[2]
+  local count=data[3]
+  local name=data[4]
+  local source=data[5]
+  local line=data[6]
+  calls=calls+count
+  functions=functions+1
+  name=gsub(name,"%s+"," ")
+  if #name>length then
+   name=sub(name,1,length)
+  end
+  printer(fmt(seconds(total),100*total/totaltime,seconds(real),100*real/realtime,count,name,line,source))
+ end
+ printer("")
+ printer(format("functions : %i",functions))
+ printer(format("calls     : %i",calls))
+ printer(format("overhead  : %f",seconds(overhead/1000)))
+end
+local function getdebug()
+ if sethook and getinfo then
+  return
+ end
+ if not debug then
+  local okay
+  okay,debug=pcall(require,"debug")
+ end
+ if type(debug)~="table" then
+  return
+ end
+ getinfo=debug.getinfo
+ sethook=debug.sethook
+ if type(getinfo)~="function" then
+  getinfo=nil
+ end
+ if type(sethook)~="function" then
+  sethook=nil
+ end
+end
+function debugger.savestats(filename,threshold)
+ local f=io.open(filename,'w')
+ if f then
+  debugger.showstats(function(str) f:write(str,"\n") end,threshold)
+  f:close()
+ end
+end
+function debugger.enable()
+ getdebug()
+ if sethook and getinfo and nesting==0 then
+  running=true
+  if initialize then
+   initialize()
+  end
+  sethook(hook,"cr")
+  local function dummy() end
+  local t=ticks()
+  for i=1,dummycalls do
+   dummy()
+  end
+  overhead=ticks()-t
+ end
+ if nesting>0 then
+  nesting=nesting+1
+ end
+end
+function debugger.disable()
+ if nesting>0 then
+  nesting=nesting-1
+ end
+ if sethook and getinfo and nesting==0 then
+  sethook()
+ end
+end
+local function showtraceback(rep) 
+ getdebug()
+ if getinfo then
+  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
+end
+debugger.showtraceback=showtraceback
+if luac then
+ local show,dump=luac.print,string.dump
+ function luac.inspect(v)
+  if type(v)=="function" then
+   local ok,str=xpcall(dump,function() end,v)
+   if ok then
+    v=str
+   end
+  end
+  if type(v)=="string" then
+   show(v,true)
+  else
+   print(v)
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-tpl"] = package.loaded["util-tpl"] or true
+
+-- original size: 7722, stripped down to: 4212
+
+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,next=tostring,next
+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 formatters=string.formatters
+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 function replaceformatted(l,m,r,t,how,recurse)
+ local v=t[r]
+ return v and formatters[l](v)
+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 nolformatted=P(":")/"%%"
+local norformatted=P(":")/""
+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 formatted=nosingle*((Cs(nolformatted*(1-norformatted )^1)*norformatted*C((1-nosingle)^1)*args)/replaceformatted)*nosingle
+local any=P(1)
+   replacer=Cs((unquoted+quoted+formatted+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 -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-sbx"] = package.loaded["util-sbx"] or true
+
+-- original size: 21145, stripped down to: 13271
+
+if not modules then modules={} end modules ['util-sbx']={
+ 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"
+}
+if not sandbox then require("l-sandbox") end 
+local next,type=next,type
+local replace=utilities.templates.replace
+local collapsepath=file.collapsepath
+local expandname=dir.expandname
+local sortedhash=table.sortedhash
+local lpegmatch=lpeg.match
+local platform=os.type
+local P,S,C=lpeg.P,lpeg.S,lpeg.C
+local gsub=string.gsub
+local lower=string.lower
+local find=string.find
+local concat=string.concat
+local unquoted=string.unquoted
+local optionalquoted=string.optionalquoted
+local basename=file.basename
+local nameonly=file.nameonly
+local sandbox=sandbox
+local validroots={}
+local validrunners={}
+local validbinaries=true 
+local validlibraries=true 
+local validators={}
+local finalized=nil
+local trace=false
+local p_validroot=nil
+local p_split=lpeg.firstofsplit(" ")
+local report=logs.reporter("sandbox")
+trackers.register("sandbox",function(v) trace=v end) 
+sandbox.setreporter(report)
+sandbox.finalizer {
+ category="files",
+ action=function()
+  finalized=true
+ end
+}
+local function registerroot(root,what) 
+ if finalized then
+  report("roots are already finalized")
+ else
+  if type(root)=="table" then
+   root,what=root[1],root[2]
+  end
+  if type(root)=="string" and root~="" then
+   root=collapsepath(expandname(root))
+   if what=="r" or what=="ro" or what=="readable" then
+    what="read"
+   elseif what=="w" or what=="wo" or what=="writable" then
+    what="write"
+   end
+   validroots[root]=what=="write" or false
+  end
+ end
+end
+sandbox.finalizer {
+ category="files",
+ action=function() 
+  if p_validroot then
+   report("roots are already initialized")
+  else
+   sandbox.registerroot(".","write")
+   for name in sortedhash(validroots) do
+    if p_validroot then
+     p_validroot=P(name)+p_validroot
+    else
+     p_validroot=P(name)
+    end
+   end
+   p_validroot=p_validroot/validroots
+  end
+ end
+}
+local function registerbinary(name)
+ if finalized then
+  report("binaries are already finalized")
+ elseif type(name)=="string" and name~="" then
+  if not validbinaries then
+   return
+  end
+  if validbinaries==true then
+   validbinaries={ [name]=true }
+  else
+   validbinaries[name]=true
+  end
+ elseif name==true then
+  validbinaries={}
+ end
+end
+local function registerlibrary(name)
+ if finalized then
+  report("libraries are already finalized")
+ elseif type(name)=="string" and name~="" then
+  if not validlibraries then
+   return
+  end
+  if validlibraries==true then
+   validlibraries={ [nameonly(name)]=true }
+  else
+   validlibraries[nameonly(name)]=true
+  end
+ elseif name==true then
+  validlibraries={}
+ end
+end
+local p_write=S("wa")    p_write=(1-p_write)^0*p_write
+local p_path=S("\\/~$%:")  p_path=(1-p_path )^0*p_path  
+local function normalized(name) 
+ if platform=="windows" then
+  name=gsub(name,"/","\\")
+ end
+ return name
+end
+function sandbox.possiblepath(name)
+ return lpegmatch(p_path,name) and true or false
+end
+local filenamelogger=false
+function sandbox.setfilenamelogger(l)
+ filenamelogger=type(l)=="function" and l or false
+end
+local function validfilename(name,what)
+ if p_validroot and type(name)=="string" and lpegmatch(p_path,name) then
+  local asked=collapsepath(expandname(name))
+  local okay=lpegmatch(p_validroot,asked)
+  if okay==true then
+   if filenamelogger then
+    filenamelogger(name,"w",asked,true)
+   end
+   return name
+  elseif okay==false then
+   if not what then
+    if filenamelogger then
+     filenamelogger(name,"r",asked,true)
+    end
+    return name
+   elseif lpegmatch(p_write,what) then
+    if filenamelogger then
+     filenamelogger(name,"w",asked,false)
+    end
+    return 
+   else
+    if filenamelogger then
+     filenamelogger(name,"r",asked,true)
+    end
+    return name
+   end
+  elseif filenamelogger then
+   filenamelogger(name,"*",name,false)
+  end
+ else
+  return name
+ end
+end
+local function readable(name,finalized)
+ return validfilename(name,"r")
+end
+local function normalizedreadable(name,finalized)
+ local valid=validfilename(name,"r")
+ if valid then
+  return normalized(valid)
+ end
+end
+local function writeable(name,finalized)
+ return validfilename(name,"w")
+end
+local function normalizedwriteable(name,finalized)
+ local valid=validfilename(name,"w")
+ if valid then
+  return normalized(valid)
+ end
+end
+validators.readable=readable
+validators.writeable=normalizedwriteable
+validators.normalizedreadable=normalizedreadable
+validators.normalizedwriteable=writeable
+validators.filename=readable
+table.setmetatableindex(validators,function(t,k)
+ if k then
+  t[k]=readable
+ end
+ return readable
+end)
+function validators.string(s,finalized)
+ if finalized and suspicious(s) then
+  return ""
+ else
+  return s
+ end
+end
+function validators.cache(s)
+ if finalized then
+  return basename(s)
+ else
+  return s
+ end
+end
+function validators.url(s)
+ if finalized and find("^file:") then
+  return ""
+ else
+  return s
+ end
+end
+local function filehandlerone(action,one,...)
+ local checkedone=validfilename(one)
+ if checkedone then
+  return action(one,...)
+ else
+ end
+end
+local function filehandlertwo(action,one,two,...)
+ local checkedone=validfilename(one)
+ if checkedone then
+  local checkedtwo=validfilename(two)
+  if checkedtwo then
+   return action(one,two,...)
+  else
+  end
+ else
+ end
+end
+local function iohandler(action,one,...)
+ if type(one)=="string" then
+  local checkedone=validfilename(one)
+  if checkedone then
+   return action(one,...)
+  end
+ elseif one then
+  return action(one,...)
+ else
+  return action()
+ end
+end
+local osexecute=sandbox.original(os.execute)
+local iopopen=sandbox.original(io.popen)
+local reported={}
+local function validcommand(name,program,template,checkers,defaults,variables,reporter,strict)
+ if validbinaries~=false and (validbinaries==true or validbinaries[program]) then
+  local binpath=nil
+  if variables then
+   for variable,value in next,variables do
+    local chktype=checkers[variable]
+    if chktype=="verbose" then
+    else
+     local checker=validators[chktype]
+     if checker and type(value)=="string" then
+      value=checker(unquoted(value),strict)
+      if value then
+       variables[variable]=optionalquoted(value)
+      else
+       report("variable %a with value %a fails the check",variable,value)
+       return
+      end
+     else
+      report("variable %a has no checker",variable)
+      return
+     end
+    end
+   end
+   for variable,default in next,defaults do
+    local value=variables[variable]
+    if not value or value=="" then
+     local chktype=checkers[variable]
+     if chktype=="verbose" then
+     elseif type(default)=="string" then
+      local checker=validators[chktype]
+      if checker then
+       default=checker(unquoted(default),strict)
+       if default then
+        variables[variable]=optionalquoted(default)
+       else
+        report("variable %a with default %a fails the check",variable,default)
+        return
+       end
+      end
+     end
+    end
+   end
+   binpath=variables.binarypath
+  end
+  if type(binpath)=="string" and binpath~="" then
+   program=binpath.."/"..program
+  end
+  local command=program.." "..replace(template,variables)
+  if reporter then
+   reporter("executing runner %a: %s",name,command)
+  elseif trace then
+   report("executing runner %a: %s",name,command)
+  end
+  return command
+ elseif not reported[name] then
+  report("executing program %a of runner %a is not permitted",program,name)
+  reported[name]=true
+ end
+end
+local runners={
+ resultof=function(...)
+  local command=validcommand(...)
+  if command then
+   if trace then
+    report("resultof: %s",command)
+   end
+   local handle=iopopen(command,"r") 
+   if handle then
+    local result=handle:read("*all") or ""
+    handle:close()
+    return result
+   end
+  end
+ end,
+ execute=function(...)
+  local command=validcommand(...)
+  if command then
+   if trace then
+    report("execute: %s",command)
+   end
+   local okay=osexecute(command)
+   return okay
+  end
+ end,
+ pipeto=function(...)
+  local command=validcommand(...)
+  if command then
+   if trace then
+    report("pipeto: %s",command)
+   end
+   return iopopen(command,"w") 
+  end
+ end,
+}
+function sandbox.registerrunner(specification)
+ if type(specification)=="string" then
+  local wrapped=validrunners[specification]
+  inspect(table.sortedkeys(validrunners))
+  if wrapped then
+   return wrapped
+  else
+   report("unknown predefined runner %a",specification)
+   return
+  end
+ end
+ if type(specification)~="table" then
+  report("specification should be a table (or string)")
+  return
+ end
+ local name=specification.name
+ if type(name)~="string" then
+  report("invalid name, string expected",name)
+  return
+ end
+ if validrunners[name] then
+  report("invalid name, runner %a already defined",name)
+  return
+ end
+ local program=specification.program
+ if type(program)=="string" then
+ elseif type(program)=="table" then
+  program=program[platform] or program.default or program.unix
+ end
+ if type(program)~="string" or program=="" then
+  report("invalid runner %a specified for platform %a",name,platform)
+  return
+ end
+ local template=specification.template
+ if not template then
+  report("missing template for runner %a",name)
+  return
+ end
+ local method=specification.method   or "execute"
+ local checkers=specification.checkers or {}
+ local defaults=specification.defaults or {}
+ local runner=runners[method]
+ if runner then
+  local finalized=finalized 
+  local wrapped=function(variables)
+   return runner(name,program,template,checkers,defaults,variables,specification.reporter,finalized)
+  end
+  validrunners[name]=wrapped
+  return wrapped
+ else
+  validrunners[name]=nil
+  report("invalid method for runner %a",name)
+ end
+end
+function sandbox.getrunner(name)
+ return name and validrunners[name]
+end
+local function suspicious(str)
+ return (find(str,"[/\\]") or find(command,"..",1,true)) and true or false
+end
+local function binaryrunner(action,command,...)
+ if validbinaries==false then
+  report("no binaries permitted, ignoring command: %s",command)
+  return
+ end
+ if type(command)~="string" then
+  report("command should be a string")
+  return
+ end
+ local program=lpegmatch(p_split,command)
+ if not program or program=="" then
+  report("unable to filter binary from command: %s",command)
+  return
+ end
+ if validbinaries==true then
+ elseif not validbinaries[program] then
+  report("binary not permitted, ignoring command: %s",command)
+  return
+ elseif suspicious(command) then
+  report("/ \\ or .. found, ignoring command (use sandbox.registerrunner): %s",command)
+  return
+ end
+ return action(command,...)
+end
+local function dummyrunner(action,command,...)
+ if type(command)=="table" then
+  command=concat(command," ",command[0] and 0 or 1)
+ end
+ report("ignoring command: %s",command)
+end
+sandbox.filehandlerone=filehandlerone
+sandbox.filehandlertwo=filehandlertwo
+sandbox.iohandler=iohandler
+function sandbox.disablerunners()
+ validbinaries=false
+end
+function sandbox.disablelibraries()
+ validlibraries=false
+end
+if FFISUPPORTED and ffi then
+ function sandbox.disablelibraries()
+  validlibraries=false
+  for k,v in next,ffi do
+   if k~="gc" then
+    ffi[k]=nil
+   end
+  end
+ end
+ local fiiload=ffi.load
+ if fiiload then
+  local reported={}
+  function ffi.load(name,...)
+   if validlibraries==false then
+   elseif validlibraries==true then
+    return fiiload(name,...)
+   elseif validlibraries[nameonly(name)] then
+    return fiiload(name,...)
+   else
+   end
+   if not reported[name] then
+    report("using library %a is not permitted",name)
+    reported[name]=true
+   end
+   return nil
+  end
+ end
+end
+local overload=sandbox.overload
+local register=sandbox.register
+ overload(loadfile,filehandlerone,"loadfile") 
+if io then
+ overload(io.open,filehandlerone,"io.open")
+ overload(io.popen,binaryrunner,"io.popen")
+ overload(io.input,iohandler,"io.input")
+ overload(io.output,iohandler,"io.output")
+ overload(io.lines,filehandlerone,"io.lines")
+end
+if os then
+ overload(os.execute,binaryrunner,"os.execute")
+ overload(os.spawn,dummyrunner,"os.spawn") 
+ overload(os.exec,dummyrunner,"os.exec")  
+ overload(os.resultof,binaryrunner,"os.resultof")
+ overload(os.pipeto,binaryrunner,"os.pipeto")
+ overload(os.rename,filehandlertwo,"os.rename")
+ overload(os.remove,filehandlerone,"os.remove")
+end
+if lfs then
+ overload(lfs.chdir,filehandlerone,"lfs.chdir")
+ overload(lfs.mkdir,filehandlerone,"lfs.mkdir")
+ overload(lfs.rmdir,filehandlerone,"lfs.rmdir")
+ overload(lfs.isfile,filehandlerone,"lfs.isfile")
+ overload(lfs.isdir,filehandlerone,"lfs.isdir")
+ overload(lfs.attributes,filehandlerone,"lfs.attributes")
+ overload(lfs.dir,filehandlerone,"lfs.dir")
+ overload(lfs.lock_dir,filehandlerone,"lfs.lock_dir")
+ overload(lfs.touch,filehandlerone,"lfs.touch")
+ overload(lfs.link,filehandlertwo,"lfs.link")
+ overload(lfs.setmode,filehandlerone,"lfs.setmode")
+ overload(lfs.readlink,filehandlerone,"lfs.readlink")
+ overload(lfs.shortname,filehandlerone,"lfs.shortname")
+ overload(lfs.symlinkattributes,filehandlerone,"lfs.symlinkattributes")
+end
+if zip then
+ zip.open=register(zip.open,filehandlerone,"zip.open")
+end
+sandbox.registerroot=registerroot
+sandbox.registerbinary=registerbinary
+sandbox.registerlibrary=registerlibrary
+sandbox.validfilename=validfilename
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-mrg"] = package.loaded["util-mrg"] or true
+
+-- original size: 7819, stripped down to: 5881
+
+if not modules then modules={} end modules ['util-mrg']={
+ 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 gsub,format=string.gsub,string.format
+local concat=table.concat
+local type,next=type,next
+local P,R,S,V,Ct,C,Cs,Cc,Cp,Cmt,Cb,Cg=lpeg.P,lpeg.R,lpeg.S,lpeg.V,lpeg.Ct,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Cp,lpeg.Cmt,lpeg.Cb,lpeg.Cg
+local lpegmatch,patterns=lpeg.match,lpeg.patterns
+utilities=utilities or {}
+local merger=utilities.merger or {}
+utilities.merger=merger
+merger.strip_comment=true
+local report=logs.reporter("system","merge")
+utilities.report=report
+local m_begin_merge="begin library merge"
+local m_end_merge="end library merge"
+local m_begin_closure="do -- create closure to overcome 200 locals limit"
+local m_end_closure="end -- of closure"
+local m_pattern="%c+".."%-%-%s+"..m_begin_merge.."%c+(.-)%c+".."%-%-%s+"..m_end_merge.."%c+"
+local m_format="\n\n-- "..m_begin_merge.."\n%s\n".."-- "..m_end_merge.."\n\n"
+local m_faked="-- ".."created merged file".."\n\n".."-- "..m_begin_merge.."\n\n".."-- "..m_end_merge.."\n\n"
+local m_report=[[
+-- used libraries    : %s
+-- skipped libraries : %s
+-- original bytes    : %s
+-- stripped bytes    : %s
+]]
+local m_preloaded=[[package.loaded[%q] = package.loaded[%q] or true]]
+local function self_fake()
+ return m_faked
+end
+local function self_nothing()
+ return ""
+end
+local function self_load(name)
+ local data=io.loaddata(name) or ""
+ if data=="" then
+  report("unknown file %a",name)
+ else
+  report("inserting file %a",name)
+ end
+ return data or ""
+end
+local space=patterns.space
+local eol=patterns.newline
+local equals=P("=")^0
+local open=P("[")*Cg(equals,"init")*P("[")*P("\n")^-1
+local close=P("]")*C(equals)*P("]")
+local closeeq=Cmt(close*Cb("init"),function(s,i,a,b) return a==b end)
+local longstring=open*(1-closeeq)^0*close
+local quoted=patterns.quoted
+local digit=patterns.digit
+local emptyline=space^0*eol
+local operator1=P("<=")+P(">=")+P("~=")+P("..")+S("/^<>=*+%%")
+local operator2=S("*+/")
+local operator3=S("-")
+local operator4=P("..")
+local separator=S(",;")
+local ignore=(P("]")*space^1*P("=")*space^1*P("]"))/"]=["+(P("=")*space^1*P("{"))/"={"+(P("(")*space^1)/"("+(P("{")*(space+eol)^1*P("}"))/"{}"
+local strings=quoted 
+local longcmt=(emptyline^0*P("--")*longstring*emptyline^0)/""
+local longstr=longstring
+local comment=emptyline^0*P("--")*P("-")^0*(1-eol)^0*emptyline^1/"\n"
+local optionalspaces=space^0/""
+local mandatespaces=space^1/""
+local optionalspacing=(eol+space)^0/""
+local mandatespacing=(eol+space)^1/""
+local pack=digit*space^1*operator4*optionalspacing+optionalspacing*operator1*optionalspacing+optionalspacing*operator2*optionalspaces+mandatespacing*operator3*mandatespaces+optionalspaces*separator*optionalspaces
+local lines=emptyline^2/"\n"
+local spaces=(space*space)/" "
+local spaces=(space*space*space*space)/" "
+local compact=Cs ((
+ ignore+strings+longcmt+longstr+comment+pack+lines+spaces+1
+)^1 )
+local strip=Cs((emptyline^2/"\n"+1)^0)
+local stripreturn=Cs((1-P("return")*space^1*P(1-space-eol)^1*(space+eol)^0*P(-1))^1)
+function merger.compact(data)
+ return lpegmatch(strip,lpegmatch(compact,data))
+end
+local function self_compact(data)
+ local delta=0
+ if merger.strip_comment then
+  local before=#data
+  data=lpegmatch(compact,data)
+  data=lpegmatch(strip,data)
+  local after=#data
+  delta=before-after
+  report("original size %s, compacted to %s, stripped %s",before,after,delta)
+  data=format("-- original size: %s, stripped down to: %s\n\n%s",before,after,data)
+ end
+ return lpegmatch(stripreturn,data) or data,delta
+end
+local function self_save(name,data)
+ if data~="" then
+  io.savedata(name,data)
+  report("saving %s with size %s",name,#data)
+ end
+end
+local function self_swap(data,code)
+ return data~="" and (gsub(data,m_pattern,function() return format(m_format,code) end,1)) or ""
+end
+local function self_libs(libs,list)
+ local result,f,frozen,foundpath={},nil,false,nil
+ result[#result+1]="\n"
+ if type(libs)=='string' then libs={ libs } end
+ if type(list)=='string' then list={ list } end
+ for i=1,#libs do
+  local lib=libs[i]
+  for j=1,#list do
+   local pth=gsub(list[j],"\\","/") 
+   report("checking library path %a",pth)
+   local name=pth.."/"..lib
+   if lfs.isfile(name) then
+    foundpath=pth
+   end
+  end
+  if foundpath then break end
+ end
+ if foundpath then
+  report("using library path %a",foundpath)
+  local right,wrong,original,stripped={},{},0,0
+  for i=1,#libs do
+   local lib=libs[i]
+   local fullname=foundpath.."/"..lib
+   if lfs.isfile(fullname) then
+    report("using library %a",fullname)
+    local preloaded=file.nameonly(lib)
+    local data=io.loaddata(fullname,true)
+    original=original+#data
+    local data,delta=self_compact(data)
+    right[#right+1]=lib
+    result[#result+1]=m_begin_closure
+    result[#result+1]=format(m_preloaded,preloaded,preloaded)
+    result[#result+1]=data
+    result[#result+1]=m_end_closure
+    stripped=stripped+delta
+   else
+    report("skipping library %a",fullname)
+    wrong[#wrong+1]=lib
+   end
+  end
+  right=#right>0 and concat(right," ") or "-"
+  wrong=#wrong>0 and concat(wrong," ") or "-"
+  report("used libraries: %a",right)
+  report("skipped libraries: %a",wrong)
+  report("original bytes: %a",original)
+  report("stripped bytes: %a",stripped)
+  result[#result+1]=format(m_report,right,wrong,original,stripped)
+ else
+  report("no valid library path found")
+ end
+ return concat(result,"\n\n")
+end
+function merger.selfcreate(libs,list,target)
+ if target then
+  self_save(target,self_swap(self_fake(),self_libs(libs,list)))
+ end
+end
+function merger.selfmerge(name,libs,list,target)
+ self_save(target or name,self_swap(self_load(name),self_libs(libs,list)))
+end
+function merger.selfclean(name)
+ self_save(name,self_swap(self_load(name),self_nothing()))
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-env"] = package.loaded["util-env"] or true
+
+-- original size: 9738, stripped down to: 5531
+
+if not modules then modules={} end modules ['util-env']={
+ 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 allocate,mark=utilities.storage.allocate,utilities.storage.mark
+local format,sub,match,gsub,find=string.format,string.sub,string.match,string.gsub,string.find
+local unquoted,quoted,optionalquoted=string.unquoted,string.quoted,string.optionalquoted
+local concat,insert,remove=table.concat,table.insert,table.remove
+environment=environment or {}
+local environment=environment
+local setlocale=os.setlocale
+setlocale(nil,nil)
+local report=logs.reporter("system")
+function os.setlocale(a,b)
+ if a or b then
+  if report then
+   report()
+   report("You're messing with os.locale in a supposedly locale neutral enviroment. From")
+   report("now on are on your own and without support. Crashes or unexpected side effects")
+   report("can happen but don't bother the luatex and context developer team with it.")
+   report()
+   report=nil
+  end
+  setlocale(a,b)
+ end
+end
+local validengines=allocate {
+ ["luatex"]=true,
+ ["luajittex"]=true,
+}
+local basicengines=allocate {
+ ["luatex"]="luatex",
+ ["texlua"]="luatex",
+ ["texluac"]="luatex",
+ ["luajittex"]="luajittex",
+ ["texluajit"]="luajittex",
+}
+local luaengines=allocate {
+ ["lua"]=true,
+ ["luajit"]=true,
+}
+environment.validengines=validengines
+environment.basicengines=basicengines
+if not arg then
+ environment.used_as_library=true
+elseif luaengines[file.removesuffix(arg[-1])] then
+elseif validengines[file.removesuffix(arg[0])] then
+ if arg[1]=="--luaonly" then
+  arg[-1]=arg[0]
+  arg[ 0]=arg[2]
+  for k=3,#arg do
+   arg[k-2]=arg[k]
+  end
+  remove(arg) 
+  remove(arg) 
+ else
+ end
+ local originalzero=file.basename(arg[0])
+ local specialmapping={ luatools=="base" }
+ if originalzero~="mtxrun" and originalzero~="mtxrun.lua" then
+    arg[0]=specialmapping[originalzero] or originalzero
+    insert(arg,0,"--script")
+    insert(arg,0,"mtxrun")
+ end
+end
+environment.arguments=allocate()
+environment.files=allocate()
+environment.sortedflags=nil
+function environment.initializearguments(arg)
+ local arguments={}
+ local files={}
+ environment.arguments=arguments
+ environment.files=files
+ environment.sortedflags=nil
+ for index=1,#arg do
+  local argument=arg[index]
+  if index>0 then
+   local flag,value=match(argument,"^%-+(.-)=(.-)$")
+   if flag then
+    flag=gsub(flag,"^c:","")
+    arguments[flag]=unquoted(value or "")
+   else
+    flag=match(argument,"^%-+(.+)")
+    if flag then
+     flag=gsub(flag,"^c:","")
+     arguments[flag]=true
+    else
+     files[#files+1]=argument
+    end
+   end
+  end
+ end
+ if not environment.ownname then
+  if os.selfpath and os.selfname then
+   environment.ownname=file.addsuffix(file.join(os.selfpath,os.selfname),"lua")
+  end
+ end
+ environment.ownname=file.reslash(environment.ownname or arg[0] or 'unknown.lua')
+end
+function environment.setargument(name,value)
+ environment.arguments[name]=value
+end
+function environment.getargument(name,partial)
+ local arguments,sortedflags=environment.arguments,environment.sortedflags
+ if arguments[name] then
+  return arguments[name]
+ elseif partial then
+  if not sortedflags then
+   sortedflags=allocate(table.sortedkeys(arguments))
+   for k=1,#sortedflags do
+    sortedflags[k]="^"..sortedflags[k]
+   end
+   environment.sortedflags=sortedflags
+  end
+  for k=1,#sortedflags do
+   local v=sortedflags[k]
+   if find(name,v) then
+    return arguments[sub(v,2,#v)]
+   end
+  end
+ end
+ return nil
+end
+environment.argument=environment.getargument
+function environment.splitarguments(separator) 
+ local done,before,after=false,{},{}
+ local originalarguments=environment.originalarguments
+ for k=1,#originalarguments do
+  local v=originalarguments[k]
+  if not done and v==separator then
+   done=true
+  elseif done then
+   after[#after+1]=v
+  else
+   before[#before+1]=v
+  end
+ end
+ return before,after
+end
+function environment.reconstructcommandline(arg,noquote)
+ local resolveprefix=resolvers.resolve 
+ arg=arg or environment.originalarguments
+ if noquote and #arg==1 then
+  return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1])
+ elseif #arg>0 then
+  local result={}
+  for i=1,#arg do
+   result[i]=optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix)
+  end
+  return concat(result," ")
+ else
+  return ""
+ end
+end
+function environment.relativepath(path,root)
+ if not path then
+  path=""
+ end
+ if not file.is_rootbased_path(path) then
+  if not root then
+   root=file.pathpart(environment.ownscript or environment.ownname or ".")
+  end
+  if root=="" then
+   root="."
+  end
+  path=root.."/"..path
+ end
+ return file.collapsepath(path,true)
+end
+if arg then
+ local newarg,instring={},false
+ for index=1,#arg do
+  local argument=arg[index]
+  if find(argument,"^\"") then
+   if find(argument,"\"$") then
+    newarg[#newarg+1]=gsub(argument,"^\"(.-)\"$","%1")
+    instring=false
+   else
+    newarg[#newarg+1]=gsub(argument,"^\"","")
+    instring=true
+   end
+  elseif find(argument,"\"$") then
+   if instring then
+    newarg[#newarg]=newarg[#newarg].." "..gsub(argument,"\"$","")
+    instring=false
+   else
+    newarg[#newarg+1]=argument
+   end
+  elseif instring then
+   newarg[#newarg]=newarg[#newarg].." "..argument
+  else
+   newarg[#newarg+1]=argument
+  end
+ end
+ for i=1,-5,-1 do
+  newarg[i]=arg[i]
+ end
+ environment.initializearguments(newarg)
+ environment.originalarguments=mark(newarg)
+ environment.rawarguments=mark(arg)
+ arg={} 
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["luat-env"] = package.loaded["luat-env"] or true
+
+-- original size: 6267, stripped down to: 4115
+
+ if not modules then modules={} end modules ['luat-env']={
+ 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 rawset,loadfile=rawset,loadfile
+local gsub=string.gsub
+local trace_locating=false  trackers.register("resolvers.locating",function(v) trace_locating=v end)
+local report_lua=logs.reporter("resolvers","lua")
+local luautilities=utilities.lua
+local luasuffixes=luautilities.suffixes
+local texgettoks=tex and tex.gettoks
+environment=environment or {}
+local environment=environment
+local mt={
+ __index=function(_,k)
+  if k=="version" then
+   local version=texgettoks and texgettoks("contextversiontoks")
+   if version and version~="" then
+    rawset(environment,"version",version)
+    return version
+   else
+    return "unknown"
+   end
+  elseif k=="jobname" or k=="formatname" then
+   local name=tex and tex[k]
+   if name or name=="" then
+    rawset(environment,k,name)
+    return name
+   else
+    return "unknown"
+   end
+  elseif k=="outputfilename" then
+   local name=environment.jobname
+   rawset(environment,k,name)
+   return name
+  end
+ end
+}
+setmetatable(environment,mt)
+function environment.texfile(filename)
+ return resolvers.findfile(filename,'tex')
+end
+function environment.luafile(filename) 
+ if CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 and file.suffix(filename)=="lua" then
+  local resolved=resolvers.findfile(file.replacesuffix(filename,"lmt")) or ""
+  if resolved~="" then
+   return resolved
+  end
+ end
+ local resolved=resolvers.findfile(filename,'tex') or ""
+ if resolved~="" then
+  return resolved
+ end
+ resolved=resolvers.findfile(filename,'texmfscripts') or ""
+ if resolved~="" then
+  return resolved
+ end
+ return resolvers.findfile(filename,'luatexlibs') or ""
+end
+local stripindeed=false  directives.register("system.compile.strip",function(v) stripindeed=v end)
+local function strippable(filename)
+ if stripindeed then
+  local modu=modules[file.nameonly(filename)]
+  return modu and modu.dataonly
+ else
+  return false
+ end
+end
+function environment.luafilechunk(filename,silent,macros) 
+ filename=file.replacesuffix(filename,"lua")
+ local fullname=environment.luafile(filename)
+ if fullname and fullname~="" then
+  local data=luautilities.loadedluacode(fullname,strippable,filename,macros)
+  if not silent then
+   report_lua("loading file %a %s",fullname,not data and "failed" or "succeeded")
+  end
+  return data
+ else
+  if not silent then
+   report_lua("unknown file %a",filename)
+  end
+  return nil
+ end
+end
+function environment.loadluafile(filename,version)
+ local lucname,luaname,chunk
+ local basename=file.removesuffix(filename)
+ if basename==filename then
+  luaname=file.addsuffix(basename,luasuffixes.lua)
+  lucname=file.addsuffix(basename,luasuffixes.luc)
+ else
+  luaname=filename 
+  lucname=nil
+ end
+ local fullname=(lucname and environment.luafile(lucname)) or ""
+ if fullname~="" then
+  if trace_locating then
+   report_lua("loading %a",fullname)
+  end
+  chunk=loadfile(fullname) 
+ end
+ if chunk then
+  chunk()
+  if version then
+   local v=version 
+   if modules and modules[filename] then
+    v=modules[filename].version 
+   elseif versions and versions[filename] then
+    v=versions[filename]  
+   end
+   if v==version then
+    return true
+   else
+    if trace_locating then
+     report_lua("version mismatch for %a, lua version %a, luc version %a",filename,v,version)
+    end
+    environment.loadluafile(filename)
+   end
+  else
+   return true
+  end
+ end
+ fullname=(luaname and environment.luafile(luaname)) or ""
+ if fullname~="" then
+  if trace_locating then
+   report_lua("loading %a",fullname)
+  end
+  chunk=loadfile(fullname) 
+  if not chunk then
+   if trace_locating then
+    report_lua("unknown file %a",filename)
+   end
+  else
+   chunk()
+   return true
+  end
+ end
+ return false
+end
+environment.filenames=setmetatable({},{
+ __index=function(t,k)
+  local v=environment.files[k]
+  if v then
+   return (gsub(v,"%.+$",""))
+  end
+ end,
+ __newindex=function(t,k)
+ end,
+ __len=function(t)
+  return #environment.files
+ end,
+} )
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-zip"] = package.loaded["util-zip"] or true
+
+-- original size: 23730, stripped down to: 14293
+
+if not modules then modules={} end modules ['util-zip']={
+ version=1.001,
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local type,tostring,tonumber=type,tostring,tonumber
+local sort,concat=table.sort,table.concat
+local find,format,sub,gsub=string.find,string.format,string.sub,string.gsub
+local osdate,ostime,osclock=os.date,os.time,os.clock
+local ioopen=io.open
+local loaddata,savedata=io.loaddata,io.savedata
+local filejoin,isdir,dirname,mkdirs=file.join,lfs.isdir,file.dirname,dir.mkdirs
+local suffix,suffixes=file.suffix,file.suffixes
+local openfile=io.open
+gzip=gzip or {} 
+if not zlib then
+ zlib=xzip 
+elseif not xzip then
+ xzip=zlib
+end
+local files=utilities.files
+local openfile=files.open
+local closefile=files.close
+local readstring=files.readstring
+local readcardinal2=files.readcardinal2le
+local readcardinal4=files.readcardinal4le
+local setposition=files.setposition
+local getposition=files.getposition
+local band=bit32.band
+local rshift=bit32.rshift
+local lshift=bit32.lshift
+local zlibdecompress=zlib.decompress
+local zlibdecompresssize=zlib.decompresssize
+local zlibchecksum=zlib.crc32
+if not CONTEXTLMTXMODE or CONTEXTLMTXMODE==0 then
+ local cs=zlibchecksum
+ zlibchecksum=function(str,n) return cs(n or 0,str) end
+end
+local decompress=function(source)   return zlibdecompress (source,-15)   end 
+local decompresssize=function(source,targetsize) return zlibdecompresssize(source,targetsize,-15) end 
+local calculatecrc=function(buffer,initial) return zlibchecksum   (initial or 0,buffer)   end
+local zipfiles={}
+utilities.zipfiles=zipfiles
+local openzipfile,closezipfile,unzipfile,foundzipfile,getziphash,getziplist  do
+ function openzipfile(name)
+  return {
+   name=name,
+   handle=openfile(name,0),
+  }
+ end
+ local function collect(z)
+  if not z.list then
+   local list={}
+   local hash={}
+   local position=0
+   local index=0
+   local handle=z.handle
+   while true do
+    setposition(handle,position)
+    local signature=readstring(handle,4)
+    if signature=="PK\3\4" then
+     local version=readcardinal2(handle)
+     local flag=readcardinal2(handle)
+     local method=readcardinal2(handle)
+     local filetime=readcardinal2(handle)
+     local filedate=readcardinal2(handle)
+     local crc32=readcardinal4(handle)
+     local compressed=readcardinal4(handle)
+     local uncompressed=readcardinal4(handle)
+     local namelength=readcardinal2(handle)
+     local extralength=readcardinal2(handle)
+     local filename=readstring(handle,namelength)
+     local descriptor=band(flag,8)~=0
+     local encrypted=band(flag,1)~=0
+     local acceptable=method==0 or method==8
+     local skipped=0
+     local size=0
+     if encrypted then
+      size=readcardinal2(handle)
+      skipbytes(size)
+      skipped=skipped+size+2
+      skipbytes(8)
+      skipped=skipped+8
+      size=readcardinal2(handle)
+      skipbytes(size)
+      skipped=skipped+size+2
+      size=readcardinal4(handle)
+      skipbytes(size)
+      skipped=skipped+size+4
+      size=readcardinal2(handle)
+      skipbytes(size)
+      skipped=skipped+size+2
+     end
+     position=position+30+namelength+extralength+skipped
+     if descriptor then
+      setposition(handle,position+compressed)
+      crc32=readcardinal4(handle)
+      compressed=readcardinal4(handle)
+      uncompressed=readcardinal4(handle)
+     end
+     if acceptable then
+      index=index+1
+      local data={
+       filename=filename,
+       index=index,
+       position=position,
+       method=method,
+       compressed=compressed,
+       uncompressed=uncompressed,
+       crc32=crc32,
+       encrypted=encrypted,
+      }
+      hash[filename]=data
+      list[index]=data
+     else
+     end
+     position=position+compressed
+    else
+     break
+    end
+    z.list=list
+    z.hash=hash
+   end
+  end
+ end
+ function getziplist(z)
+  local list=z.list
+  if not list then
+   collect(z)
+  end
+  return z.list
+ end
+ function getziphash(z)
+  local hash=z.hash
+  if not hash then
+   collect(z)
+  end
+  return z.hash
+ end
+ function foundzipfile(z,name)
+  return getziphash(z)[name]
+ end
+ function closezipfile(z)
+  local f=z.handle
+  if f then
+   closefile(f)
+   z.handle=nil
+  end
+ end
+ function unzipfile(z,filename,check)
+  local hash=z.hash
+  if not hash then
+   hash=zipfiles.hash(z)
+  end
+  local data=hash[filename] 
+  if not data then
+  end
+  if data then
+   local handle=z.handle
+   local position=data.position
+   local compressed=data.compressed
+   if compressed>0 then
+    setposition(handle,position)
+    local result=readstring(handle,compressed)
+    if data.method==8 then
+     if decompresssize then
+      result=decompresssize(result,data.uncompressed)
+     else
+      result=decompress(result)
+     end
+    end
+    if check and data.crc32~=calculatecrc(result) then
+     print("checksum mismatch")
+     return ""
+    end
+    return result
+   else
+    return ""
+   end
+  end
+ end
+ zipfiles.open=openzipfile
+ zipfiles.close=closezipfile
+ zipfiles.unzip=unzipfile
+ zipfiles.hash=getziphash
+ zipfiles.list=getziplist
+ zipfiles.found=foundzipfile
+end
+if xzip then 
+ local writecardinal1=files.writebyte
+ local writecardinal2=files.writecardinal2le
+ local writecardinal4=files.writecardinal4le
+ local logwriter=logs.writer
+ local globpattern=dir.globpattern
+ local compress=xzip.compress
+ local checksum=xzip.crc32
+ local function fromdostime(dostime,dosdate)
+  return ostime {
+   year=rshift(dosdate,9)+1980,
+   month=band(rshift(dosdate,5),0x0F),
+   day=band((dosdate   ),0x1F),
+   hour=band(rshift(dostime,11)    ),
+   min=band(rshift(dostime,5),0x3F),
+   sec=band((dostime   ),0x1F),
+  }
+ end
+ local function todostime(time)
+  local t=osdate("*t",time)
+  return
+   lshift(t.year-1980,9)+lshift(t.month,5)+t.day,
+   lshift(t.hour,11)+lshift(t.min,5)+rshift(t.sec,1)
+ end
+ local function openzip(filename,level,comment,verbose)
+  local f=ioopen(filename,"wb")
+  if f then
+   return {
+    filename=filename,
+    handle=f,
+    list={},
+    level=tonumber(level) or 3,
+    comment=tostring(comment),
+    verbose=verbose,
+    uncompressed=0,
+    compressed=0,
+   }
+  end
+ end
+ local function writezip(z,name,data,level,time)
+  local f=z.handle
+  local list=z.list
+  local level=tonumber(level) or z.level or 3
+  local method=8
+  local zipped=compress(data,level)
+  local checksum=checksum(data)
+  local verbose=z.verbose
+  if not zipped then
+   method=0
+   zipped=data
+  end
+  local start=f:seek()
+  local compressed=#zipped
+  local uncompressed=#data
+  z.compressed=z.compressed+compressed
+  z.uncompressed=z.uncompressed+uncompressed
+  if verbose then
+   local pct=100*compressed/uncompressed
+   if pct>=100 then
+    logwriter(format("%10i        %s",uncompressed,name))
+   else
+    logwriter(format("%10i  %02.1f  %s",uncompressed,pct,name))
+   end
+  end
+  f:write("\x50\x4b\x03\x04")
+  writecardinal2(f,0)   
+  writecardinal2(f,0)   
+  writecardinal2(f,method)    
+  writecardinal2(f,0)   
+  writecardinal2(f,0)   
+  writecardinal4(f,checksum)  
+  writecardinal4(f,compressed)   
+  writecardinal4(f,uncompressed) 
+  writecardinal2(f,#name)  
+  writecardinal2(f,0)
+  f:write(name)      
+  f:write(zipped)
+  list[#list+1]={ #zipped,#data,name,checksum,start,time or 0 }
+ end
+ local function closezip(z)
+  local f=z.handle
+  local list=z.list
+  local comment=z.comment
+  local verbose=z.verbose
+  local count=#list
+  local start=f:seek()
+  for i=1,count do
+   local l=list[i]
+   local compressed=l[1]
+   local uncompressed=l[2]
+   local name=l[3]
+   local checksum=l[4]
+   local start=l[5]
+   local time=l[6]
+   local date,time=todostime(time)
+   f:write('\x50\x4b\x01\x02')
+   writecardinal2(f,0)   
+   writecardinal2(f,0)   
+   writecardinal2(f,0)   
+   writecardinal2(f,8)   
+   writecardinal2(f,time)   
+   writecardinal2(f,date)   
+   writecardinal4(f,checksum)  
+   writecardinal4(f,compressed)   
+   writecardinal4(f,uncompressed) 
+   writecardinal2(f,#name)  
+   writecardinal2(f,0)   
+   writecardinal2(f,0)   
+   writecardinal2(f,0)   
+   writecardinal2(f,0)   
+   writecardinal4(f,0)   
+   writecardinal4(f,start)  
+   f:write(name)      
+  end
+  local stop=f:seek()
+  local size=stop-start
+  f:write('\x50\x4b\x05\x06')
+  writecardinal2(f,0)   
+  writecardinal2(f,0)   
+  writecardinal2(f,count)  
+  writecardinal2(f,count)  
+  writecardinal4(f,size)   
+  writecardinal4(f,start)  
+  if type(comment)=="string" and comment~="" then
+   writecardinal2(f,#comment) 
+   f:write(comment)     
+  else
+   writecardinal2(f,0)
+  end
+  if verbose then
+   local compressed=z.compressed
+   local uncompressed=z.uncompressed
+   local filename=z.filename
+   local pct=100*compressed/uncompressed
+   logwriter("")
+   if pct>=100 then
+    logwriter(format("%10i        %s",uncompressed,filename))
+   else
+    logwriter(format("%10i  %02.1f  %s",uncompressed,pct,filename))
+   end
+  end
+  f:close()
+ end
+ local function zipdir(zipname,path,level,verbose)
+  if type(zipname)=="table" then
+   verbose=zipname.verbose
+   level=zipname.level
+   path=zipname.path
+   zipname=zipname.zipname
+  end
+  if not zipname or zipname=="" then
+   return
+  end
+  if not path or path=="" then
+   path="."
+  end
+  if not isdir(path) then
+   return
+  end
+  path=gsub(path,"\\+","/")
+  path=gsub(path,"/+","/")
+  local list={}
+  local count=0
+  globpattern(path,"",true,function(name,size,time)
+   count=count+1
+   list[count]={ name,time }
+  end)
+  sort(list,function(a,b)
+   return a[1]<b[1]
+  end)
+  local zipf=openzip(zipname,level,comment,verbose)
+  if zipf then
+   local p=#path+2
+   for i=1,count do
+    local li=list[i]
+    local name=li[1]
+    local time=li[2]
+    local data=loaddata(name)
+    local name=sub(name,p,#name)
+    writezip(zipf,name,data,level,time,verbose)
+   end
+   closezip(zipf)
+  end
+ end
+ local function unzipdir(zipname,path,verbose)
+  if type(zipname)=="table" then
+   verbose=zipname.verbose
+   path=zipname.path
+   zipname=zipname.zipname
+  end
+  if not zipname or zipname=="" then
+   return
+  end
+  if not path or path=="" then
+   path="."
+  end
+  local z=openzipfile(zipname)
+  if z then
+   local list=getziplist(z)
+   if list then
+    local total=0
+    local count=#list
+    local step=number.idiv(count,10)
+    local done=0
+    local steps=verbose=="steps"
+    local time=steps and osclock()
+    for i=1,count do
+     local l=list[i]
+     local n=l.filename
+     local d=unzipfile(z,n) 
+     if d then
+      local p=filejoin(path,n)
+      if mkdirs(dirname(p)) then
+       if steps then
+        total=total+#d
+        done=done+1
+        if done>=step then
+         done=0
+         logwriter(format("%4i files of %4i done, %10i bytes, %0.3f seconds",i,count,total,osclock()-time))
+        end
+       elseif verbose then
+        logwriter(n)
+       end
+       savedata(p,d)
+      end
+     else
+      logwriter(format("problem with file %s",n))
+     end
+    end
+    if steps then
+     logwriter(format("%4i files of %4i done, %10i bytes, %0.3f seconds",count,count,total,osclock()-time))
+    end
+    closezipfile(z)
+    return true
+   else
+    closezipfile(z)
+   end
+  end
+ end
+ zipfiles.zipdir=zipdir
+ zipfiles.unzipdir=unzipdir
+end
+local pattern="^\x1F\x8B\x08"
+local gziplevel=3
+function gzip.suffix(filename)
+ local suffix,extra=suffixes(filename)
+ local gzipped=extra=="gz"
+ return suffix,gzipped
+end
+function gzip.compressed(s)
+ return s and find(s,pattern)
+end
+local getdecompressed
+local putcompressed
+if gzip.compress then
+ local gzipwindow=15+16 
+ local compress=zlib.compress
+ local decompress=zlib.decompress
+ getdecompressed=function(str)
+  return decompress(str,gzipwindow) 
+ end
+ putcompressed=function(str,level)
+  return compress(str,level or gziplevel,nil,gzipwindow)
+ end
+else
+ local gzipwindow=-15 
+ local identifier="\x1F\x8B"
+ local compress=zlib.compress
+ local decompress=zlib.decompress
+ local zlibchecksum=zlib.crc32
+ if not CONTEXTLMTXMODE or CONTEXTLMTXMODE==0 then
+  local cs=zlibchecksum
+  zlibchecksum=function(str,n) return cs(n or 0,str) end
+ end
+ local streams=utilities.streams
+ local openstream=streams.openstring
+ local closestream=streams.close
+ local getposition=streams.getposition
+ local readbyte=streams.readbyte
+ local readcardinal4=streams.readcardinal4le
+ local readcardinal2=streams.readcardinal2le
+ local readstring=streams.readstring
+ local readcstring=streams.readcstring
+ local skipbytes=streams.skip
+ local tocardinal1=streams.tocardinal1
+ local tocardinal4=streams.tocardinal4le
+ getdecompressed=function(str)
+  local s=openstream(str)
+  local identifier=readstring(s,2)
+  local method=readbyte(s,1)
+  local flags=readbyte(s,1)
+  local timestamp=readcardinal4(s)
+  local compression=readbyte(s,1)
+  local operating=readbyte(s,1)
+  local isjusttext=band(flags,0x01)~=0 and true    or false
+  local extrasize=band(flags,0x04)~=0 and readcardinal2(s) or 0
+  local filename=band(flags,0x08)~=0 and readcstring(s)   or ""
+  local comment=band(flags,0x10)~=0 and readcstring(s)   or ""
+  local checksum=band(flags,0x02)~=0 and readcardinal2(s) or 0
+  local compressed=readstring(s,#str)
+  local data=decompress(compressed,gzipwindow) 
+  return data
+ end
+ putcompressed=function(str,level,originalname)
+  return concat {
+   identifier,
+   tocardinal1(0x08),
+   tocardinal1(0x08),
+   tocardinal4(os.time()),
+   tocardinal1(0x02),
+   tocardinal1(0xFF),
+   (originalname or "unknownname").."\0",
+   compress(str,level,nil,gzipwindow),
+   tocardinal4(zlibchecksum(str)),
+   tocardinal4(#str),
+  }
+ end
+end
+function gzip.load(filename)
+ local f=openfile(filename,"rb")
+ if not f then
+ else
+  local data=f:read("*all")
+  f:close()
+  if data and data~="" then
+   if suffix(filename)=="gz" then
+    data=getdecompressed(data)
+   end
+   return data
+  end
+ end
+end
+function gzip.save(filename,data,level,originalname)
+ if suffix(filename)~="gz" then
+  filename=filename..".gz"
+ end
+ local f=openfile(filename,"wb")
+ if f then
+  data=putcompressed(data or "",level or gziplevel,originalname)
+  f:write(data)
+  f:close()
+  return #data
+ end
+end
+function gzip.compress(s,level)
+ if s and not find(s,pattern) then
+  if not level then
+   level=gziplevel
+  elseif level<=0 then
+   return s
+  elseif level>9 then
+   level=9
+  end
+  return putcompressed(s,level or gziplevel) or s
+ end
+end
+function gzip.decompress(s)
+ if s and find(s,pattern) then
+  return getdecompressed(s)
+ else
+  return s
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["lxml-tab"] = package.loaded["lxml-tab"] or true
+
+-- original size: 62810, stripped down to: 36225
+
+if not modules then modules={} end modules ['lxml-tab']={
+ version=1.001,
+ comment="this module is the basis for the lxml-* ones",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local trace_entities=false  trackers.register("xml.entities",function(v) trace_entities=v end)
+local report_xml=logs and logs.reporter("xml","core") or function(...) print(string.format(...)) end
+if lpeg.setmaxstack then lpeg.setmaxstack(1000) end 
+xml=xml or {}
+local xml=xml
+local concat,remove,insert=table.concat,table.remove,table.insert
+local type,next,setmetatable,getmetatable,tonumber,rawset,select=type,next,setmetatable,getmetatable,tonumber,rawset,select
+local lower,find,match,gsub=string.lower,string.find,string.match,string.gsub
+local sort=table.sort
+local utfchar=utf.char
+local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns
+local P,S,R,C,V,C,Cs=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.V,lpeg.C,lpeg.Cs
+local formatters=string.formatters
+do 
+xml.xmlns=xml.xmlns or {}
+local check=P(false)
+local parse=check
+function xml.registerns(namespace,pattern) 
+ check=check+C(P(lower(pattern)))/namespace
+ parse=P { P(check)+1*V(1) }
+end
+function xml.checkns(namespace,url)
+ local ns=lpegmatch(parse,lower(url))
+ if ns and namespace~=ns then
+  xml.xmlns[namespace]=ns
+ end
+end
+function xml.resolvens(url)
+  return lpegmatch(parse,lower(url)) or ""
+end
+end
+local nsremap,resolvens=xml.xmlns,xml.resolvens
+local stack,level,top,at,xmlnms,errorstr
+local entities,parameters
+local strip,utfize,resolve,cleanup,resolve_predefined,unify_predefined
+local dcache,hcache,acache
+local mt,dt,nt
+local currentfilename,currentline,linenumbers
+local grammar_parsed_text_one
+local grammar_parsed_text_two
+local grammar_unparsed_text
+local handle_hex_entity
+local handle_dec_entity
+local handle_any_entity_dtd
+local handle_any_entity_text
+local function preparexmlstate(settings)
+ if settings then
+  linenumbers=settings.linenumbers
+  stack={}
+  level=0
+  top={}
+  at={}
+  mt={}
+  dt={}
+  nt=0   
+  xmlns={}
+  errorstr=nil
+  strip=settings.strip_cm_and_dt
+  utfize=settings.utfize_entities
+  resolve=settings.resolve_entities   
+  resolve_predefined=settings.resolve_predefined_entities 
+  unify_predefined=settings.unify_predefined_entities   
+  cleanup=settings.text_cleanup
+  entities=settings.entities or {}
+  currentfilename=settings.currentresource
+  currentline=1
+  parameters={}
+  reported_at_errors={}
+  dcache={}
+  hcache={}
+  acache={}
+  if utfize==nil then
+   settings.utfize_entities=true
+   utfize=true
+  end
+  if resolve_predefined==nil then
+   settings.resolve_predefined_entities=true
+   resolve_predefined=true
+  end
+ else
+  linenumbers=false
+  stack=nil
+  level=nil
+  top=nil
+  at=nil
+  mt=nil
+  dt=nil
+  nt=nil
+  xmlns=nil
+  errorstr=nil
+  strip=nil
+  utfize=nil
+  resolve=nil
+  resolve_predefined=nil
+  unify_predefined=nil
+  cleanup=nil
+  entities=nil
+  parameters=nil
+  reported_at_errors=nil
+  dcache=nil
+  hcache=nil
+  acache=nil
+  currentfilename=nil
+  currentline=1
+ end
+end
+local function initialize_mt(root)
+ mt={ __index=root } 
+end
+function xml.setproperty(root,k,v)
+ getmetatable(root).__index[k]=v
+end
+function xml.checkerror(top,toclose)
+ return "" 
+end
+local checkns=xml.checkns
+local function add_attribute(namespace,tag,value)
+ if cleanup and value~="" then
+  value=cleanup(value) 
+ end
+ if tag=="xmlns" then
+  xmlns[#xmlns+1]=resolvens(value)
+  at[tag]=value
+ elseif namespace=="" then
+  at[tag]=value
+ elseif namespace=="xmlns" then
+  checkns(tag,value)
+  at["xmlns:"..tag]=value
+ else
+  at[namespace..":"..tag]=value
+ end
+end
+local function add_empty(spacing,namespace,tag)
+ if spacing~="" then
+  nt=nt+1
+  dt[nt]=spacing
+ end
+ local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace
+ top=stack[level]
+ dt=top.dt
+ nt=#dt+1
+ local t=linenumbers and {
+  ns=namespace or "",
+  rn=resolved,
+  tg=tag,
+  at=at,
+  dt={},
+  ni=nt,
+  cf=currentfilename,
+  cl=currentline,
+  __p__=top,
+ } or {
+  ns=namespace or "",
+  rn=resolved,
+  tg=tag,
+  at=at,
+  dt={},
+  ni=nt,
+  __p__=top,
+ }
+ dt[nt]=t
+ setmetatable(t,mt)
+ if at.xmlns then
+  remove(xmlns)
+ end
+ at={}
+end
+local function add_begin(spacing,namespace,tag)
+ if spacing~="" then
+  nt=nt+1
+  dt[nt]=spacing
+ end
+ local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace
+ dt={}
+ top=linenumbers and {
+  ns=namespace or "",
+  rn=resolved,
+  tg=tag,
+  at=at,
+  dt=dt,
+  ni=nil,
+  cf=currentfilename,
+  cl=currentline,
+  __p__=stack[level],
+ } or {
+  ns=namespace or "",
+  rn=resolved,
+  tg=tag,
+  at=at,
+  dt=dt,
+  ni=nil,
+  __p__=stack[level],
+ }
+ setmetatable(top,mt)
+ nt=0
+ level=level+1
+ stack[level]=top
+ at={}
+end
+local function add_end(spacing,namespace,tag)
+ if spacing~="" then
+  nt=nt+1
+  dt[nt]=spacing
+ end
+ local toclose=stack[level]
+ level=level-1
+ top=stack[level]
+ if level<1 then
+  errorstr=formatters["unable to close %s %s"](tag,xml.checkerror(top,toclose) or "")
+  report_xml(errorstr)
+ elseif toclose.tg~=tag then 
+  errorstr=formatters["unable to close %s with %s %s"](toclose.tg,tag,xml.checkerror(top,toclose) or "")
+  report_xml(errorstr)
+ end
+ dt=top.dt
+ nt=#dt+1
+ dt[nt]=toclose
+ toclose.ni=nt 
+ if toclose.at.xmlns then
+  remove(xmlns)
+ end
+end
+local function add_text(text)
+ if text=="" then
+  return
+ elseif cleanup then
+  if nt>0 then
+   local s=dt[nt]
+   if type(s)=="string" then
+    dt[nt]=s..cleanup(text)
+   else
+    nt=nt+1
+    dt[nt]=cleanup(text)
+   end
+  else
+   nt=1
+   dt[1]=cleanup(text)
+  end
+ else
+  if nt>0 then
+   local s=dt[nt]
+   if type(s)=="string" then
+    dt[nt]=s..text
+   else
+    nt=nt+1
+    dt[nt]=text
+   end
+  else
+   nt=1
+   dt[1]=text
+  end
+ end
+end
+local function add_special(what,spacing,text)
+ if spacing~="" then
+  nt=nt+1
+  dt[nt]=spacing
+ end
+ if strip and (what=="@cm@" or what=="@dt@") then
+ else
+  nt=nt+1
+  dt[nt]=linenumbers and {
+   special=true,
+   ns="",
+   tg=what,
+   ni=nil,
+   dt={ text },
+   cf=currentfilename,
+   cl=currentline,
+  } or {
+   special=true,
+   ns="",
+   tg=what,
+   ni=nil,
+   dt={ text },
+  }
+ end
+end
+local function set_message(txt)
+ errorstr="garbage at the end of the file: "..gsub(txt,"([ \n\r\t]*)","")
+end
+local function attribute_value_error(str)
+ if not reported_at_errors[str] then
+  report_xml("invalid attribute value %a",str)
+  reported_at_errors[str]=true
+  at._error_=str
+ end
+ return str
+end
+local function attribute_specification_error(str)
+ if not reported_at_errors[str] then
+  report_xml("invalid attribute specification %a",str)
+  reported_at_errors[str]=true
+  at._error_=str
+ end
+ return str
+end
+do
+ local badentity="&" 
+ xml.placeholders={
+  unknown_dec_entity=function(str) return str=="" and badentity or formatters["&%s;"](str) end,
+  unknown_hex_entity=function(str) return formatters["&#x%s;"](str) end,
+  unknown_any_entity=function(str) return formatters["&#x%s;"](str) end,
+ }
+ local function fromhex(s)
+  local n=tonumber(s,16)
+  if n then
+   return utfchar(n)
+  else
+   return formatters["h:%s"](s),true
+  end
+ end
+ local function fromdec(s)
+  local n=tonumber(s)
+  if n then
+   return utfchar(n)
+  else
+   return formatters["d:%s"](s),true
+  end
+ end
+ local p_rest=(1-P(";"))^0
+ local p_many=P(1)^0
+ local parsedentity=P("&#")*(P("x")*(p_rest/fromhex)+(p_rest/fromdec))*P(";")*P(-1)+P ("#")*(P("x")*(p_many/fromhex)+(p_many/fromdec))
+ xml.parsedentitylpeg=parsedentity
+ local predefined_unified={
+  [38]="&",
+  [42]=""",
+  [47]="'",
+  [74]="<",
+  [76]=">",
+ }
+ local predefined_simplified={
+  [38]="&",amp="&",
+  [42]='"',quot='"',
+  [47]="'",apos="'",
+  [74]="<",lt="<",
+  [76]=">",gt=">",
+ }
+ local nofprivates=0xF0000 
+ local privates_u={ 
+  [ [[&]] ]="&",
+  [ [["]] ]=""",
+  [ [[']] ]="'",
+  [ [[<]] ]="<",
+  [ [[>]] ]=">",
+ }
+ local privates_p={ 
+ }
+ local privates_s={ 
+  [ [["]] ]="&U+22;",
+  [ [[#]] ]="&U+23;",
+  [ [[$]] ]="&U+24;",
+  [ [[%]] ]="&U+25;",
+  [ [[&]] ]="&U+26;",
+  [ [[']] ]="&U+27;",
+  [ [[<]] ]="&U+3C;",
+  [ [[>]] ]="&U+3E;",
+  [ [[\]] ]="&U+5C;",
+  [ [[{]] ]="&U+7B;",
+  [ [[|]] ]="&U+7C;",
+  [ [[}]] ]="&U+7D;",
+  [ [[~]] ]="&U+7E;",
+ }
+ local privates_x={ 
+  [ [["]] ]="&U+22;",
+  [ [[#]] ]="&U+23;",
+  [ [[$]] ]="&U+24;",
+  [ [[%]] ]="&U+25;",
+  [ [[']] ]="&U+27;",
+  [ [[\]] ]="&U+5C;",
+  [ [[{]] ]="&U+7B;",
+  [ [[|]] ]="&U+7C;",
+  [ [[}]] ]="&U+7D;",
+  [ [[~]] ]="&U+7E;",
+ }
+ local privates_n={ 
+ }
+ local escaped=utf.remapper(privates_u,"dynamic")
+ local unprivatized=utf.remapper(privates_p,"dynamic")
+ local unspecialized=utf.remapper(privates_s,"dynamic")
+ local despecialized=utf.remapper(privates_x,"dynamic")
+ xml.unprivatized=unprivatized
+ xml.unspecialized=unspecialized
+ xml.despecialized=despecialized
+ xml.escaped=escaped
+ local function unescaped(s)
+  local p=privates_n[s]
+  if not p then
+   nofprivates=nofprivates+1
+   p=utfchar(nofprivates)
+   privates_n[s]=p
+   s="&"..s..";" 
+   privates_u[p]=s
+   privates_p[p]=s
+   privates_s[p]=s
+  end
+  return p
+ end
+ xml.privatetoken=unescaped
+ xml.privatecodes=privates_n
+ xml.specialcodes=privates_s
+ function xml.addspecialcode(key,value)
+  privates_s[key]=value or "&"..s..";"
+ end
+ handle_hex_entity=function(str)
+  local h=hcache[str]
+  if not h then
+   local n=tonumber(str,16)
+   h=unify_predefined and predefined_unified[n]
+   if h then
+    if trace_entities then
+     report_xml("utfize, converting hex entity &#x%s; into %a",str,h)
+    end
+   elseif utfize then
+    h=(n and utfchar(n)) or xml.unknown_hex_entity(str) or ""
+    if not n then
+     report_xml("utfize, ignoring hex entity &#x%s;",str)
+    elseif trace_entities then
+     report_xml("utfize, converting hex entity &#x%s; into %a",str,h)
+    end
+   else
+    if trace_entities then
+     report_xml("found entity &#x%s;",str)
+    end
+    h="&#x"..str..";"
+   end
+   hcache[str]=h
+  end
+  return h
+ end
+ handle_dec_entity=function(str)
+  local d=dcache[str]
+  if not d then
+   local n=tonumber(str)
+   d=unify_predefined and predefined_unified[n]
+   if d then
+    if trace_entities then
+     report_xml("utfize, converting dec entity &#%s; into %a",str,d)
+    end
+   elseif utfize then
+    d=(n and utfchar(n)) or placeholders.unknown_dec_entity(str) or ""
+    if not n then
+     report_xml("utfize, ignoring dec entity &#%s;",str)
+    elseif trace_entities then
+     report_xml("utfize, converting dec entity &#%s; into %a",str,d)
+    end
+   else
+    if trace_entities then
+     report_xml("found entity &#%s;",str)
+    end
+    d="&#"..str..";"
+   end
+   dcache[str]=d
+  end
+  return d
+ end
+ handle_any_entity_dtd=function(str)
+  if resolve then
+   local a=resolve_predefined and predefined_simplified[str] 
+   if a then
+    if trace_entities then
+     report_xml("resolving entity &%s; to predefined %a",str,a)
+    end
+   else
+    if type(resolve)=="function" then
+     a=resolve(str,entities) or entities[str]
+    else
+     a=entities[str]
+    end
+    if a then
+     if type(a)=="function" then
+      if trace_entities then
+       report_xml("expanding entity &%s; to function call",str)
+      end
+      a=a(str) or ""
+     end
+     a=lpegmatch(parsedentity,a) or a 
+     if trace_entities then
+      report_xml("resolving entity &%s; to internal %a",str,a)
+     end
+    else
+     local unknown_any_entity=placeholders.unknown_any_entity
+     if unknown_any_entity then
+      a=unknown_any_entity(str) or ""
+     end
+     if a then
+      if trace_entities then
+       report_xml("resolving entity &%s; to external %s",str,a)
+      end
+     else
+      if trace_entities then
+       report_xml("keeping entity &%s;",str)
+      end
+      if str=="" then
+       a=badentity
+      else
+       a="&"..str..";"
+      end
+     end
+    end
+   end
+   return a
+  else
+   local a=acache[str]
+   if not a then
+    a=resolve_predefined and predefined_simplified[str]
+    if a then
+     acache[str]=a
+     if trace_entities then
+      report_xml("entity &%s; becomes %a",str,a)
+     end
+    elseif str=="" then
+     if trace_entities then
+      report_xml("invalid entity &%s;",str)
+     end
+     a=badentity
+     acache[str]=a
+    else
+     if trace_entities then
+      report_xml("entity &%s; is made private",str)
+     end
+     a=unescaped(str)
+     acache[str]=a
+    end
+   end
+   return a
+  end
+ end
+ handle_any_entity_text=function(str)
+  if resolve then
+   local a=resolve_predefined and predefined_simplified[str]
+   if a then
+    if trace_entities then
+     report_xml("resolving entity &%s; to predefined %a",str,a)
+    end
+   else
+    if type(resolve)=="function" then
+     a=resolve(str,entities) or entities[str]
+    else
+     a=entities[str]
+    end
+    if a then
+     if type(a)=="function" then
+      if trace_entities then
+       report_xml("expanding entity &%s; to function call",str)
+      end
+      a=a(str) or ""
+     end
+     a=lpegmatch(grammar_parsed_text_two,a) or a
+     if type(a)=="number" then
+      return ""
+     else
+      a=lpegmatch(parsedentity,a) or a 
+      if trace_entities then
+       report_xml("resolving entity &%s; to internal %a",str,a)
+      end
+     end
+     if trace_entities then
+      report_xml("resolving entity &%s; to internal %a",str,a)
+     end
+    else
+     local unknown_any_entity=placeholders.unknown_any_entity
+     if unknown_any_entity then
+      a=unknown_any_entity(str) or ""
+     end
+     if a then
+      if trace_entities then
+       report_xml("resolving entity &%s; to external %s",str,a)
+      end
+     else
+      if trace_entities then
+       report_xml("keeping entity &%s;",str)
+      end
+      if str=="" then
+       a=badentity
+      else
+       a="&"..str..";"
+      end
+     end
+    end
+   end
+   return a
+  else
+   local a=acache[str]
+   if not a then
+    a=resolve_predefined and predefined_simplified[str]
+    if a then
+     acache[str]=a
+     if trace_entities then
+      report_xml("entity &%s; becomes %a",str,a)
+     end
+    elseif str=="" then
+     if trace_entities then
+      report_xml("invalid entity &%s;",str)
+     end
+     a=badentity
+     acache[str]=a
+    else
+     if trace_entities then
+      report_xml("entity &%s; is made private",str)
+     end
+     a=unescaped(str)
+     acache[str]=a
+    end
+   end
+   return a
+  end
+ end
+ local p_rest=(1-P(";"))^1
+ local spec={
+  [0x23]="\\Ux{23}",
+  [0x24]="\\Ux{24}",
+  [0x25]="\\Ux{25}",
+  [0x5C]="\\Ux{5C}",
+  [0x7B]="\\Ux{7B}",
+  [0x7C]="\\Ux{7C}",
+  [0x7D]="\\Ux{7D}",
+  [0x7E]="\\Ux{7E}",
+ }
+ local hash=table.setmetatableindex(spec,function(t,k)
+  local v=utfchar(k)
+  t[k]=v
+  return v
+ end)
+ local function fromuni(s)
+  local n=tonumber(s,16)
+  if n then
+   return hash[n]
+  else
+   return formatters["u:%s"](s),true
+  end
+ end
+ local function fromhex(s)
+  local n=tonumber(s,16)
+  if n then
+   return hash[n]
+  else
+   return formatters["h:%s"](s),true
+  end
+ end
+ local function fromdec(s)
+  local n=tonumber(s)
+  if n then
+   return hash[n]
+  else
+   return formatters["d:%s"](s),true
+  end
+ end
+ local reparsedentity=P("U+")*(p_rest/fromuni)+P("#")*(
+   P("x")*(p_rest/fromhex)+p_rest/fromdec
+  )
+ local hash=table.setmetatableindex(function(t,k)
+  local v=utfchar(k)
+  t[k]=v
+  return v
+ end)
+ local function fromuni(s)
+  local n=tonumber(s,16)
+  if n then
+   return hash[n]
+  else
+   return formatters["u:%s"](s),true
+  end
+ end
+ local function fromhex(s)
+  local n=tonumber(s,16)
+  if n then
+   return hash[n]
+  else
+   return formatters["h:%s"](s),true
+  end
+ end
+ local function fromdec(s)
+  local n=tonumber(s)
+  if n then
+   return hash[n]
+  else
+   return formatters["d:%s"](s),true
+  end
+ end
+ local unescapedentity=P("U+")*(p_rest/fromuni)+P("#")*(
+   P("x")*(p_rest/fromhex)+p_rest/fromdec
+  )
+ xml.reparsedentitylpeg=reparsedentity   
+ xml.unescapedentitylpeg=unescapedentity  
+end
+local escaped=xml.escaped
+local unescaped=xml.unescaped
+local placeholders=xml.placeholders
+local function handle_end_entity(str)
+ report_xml("error in entity, %a found without ending %a",str,";")
+ return str
+end
+local function handle_crap_error(chr)
+ report_xml("error in parsing, unexpected %a found ",chr)
+ add_text(chr)
+ return chr
+end
+local function handlenewline()
+ currentline=currentline+1
+end
+local spacetab=S(' \t')
+local space=S(' \r\n\t')
+local newline=lpegpatterns.newline/handlenewline
+local anything=P(1)
+local open=P('<')
+local close=P('>')
+local squote=S("'")
+local dquote=S('"')
+local equal=P('=')
+local slash=P('/')
+local colon=P(':')
+local semicolon=P(';')
+local ampersand=P('&')
+local valid_0=R("\128\255") 
+local valid_1=R('az','AZ')+S('_')+valid_0
+local valid_2=valid_1+R('09')+S('-.')
+local valid=valid_1*valid_2^0
+local name_yes=C(valid^1)*colon*C(valid^1)
+local name_nop=C(P(true))*C(valid^1)
+local name=name_yes+name_nop
+local utfbom=lpegpatterns.utfbom 
+local spacing=C(space^0)
+local space_nl=spacetab+newline
+local spacing_nl=Cs((space_nl)^0)
+local anything_nl=newline+P(1)
+local function weirdentity(k,v)
+ if trace_entities then
+  report_xml("registering %s entity %a as %a","weird",k,v)
+ end
+ parameters[k]=v
+end
+local function normalentity(k,v)
+ if trace_entities then
+  report_xml("registering %s entity %a as %a","normal",k,v)
+ end
+ entities[k]=v
+end
+local function systementity(k,v,n)
+ if trace_entities then
+  report_xml("registering %s entity %a as %a","system",k,v)
+ end
+ entities[k]=v
+end
+local function publicentity(k,v,n)
+ if trace_entities then
+  report_xml("registering %s entity %a as %a","public",k,v)
+ end
+ entities[k]=v
+end
+local function entityfile(pattern,k,v,n)
+ if n then
+  local okay,data
+  local loadbinfile=resolvers and resolvers.loadbinfile
+  if loadbinfile then
+   okay,data=loadbinfile(n)
+  else
+   data=io.loaddata(n)
+   okay=data and data~=""
+  end
+  if okay then
+   if trace_entities then
+    report_xml("loading public entities %a as %a from %a",k,v,n)
+   end
+   lpegmatch(pattern,data)
+   return
+  end
+ end
+ report_xml("ignoring public entities %a as %a from %a",k,v,n)
+end
+local function install(spacenewline,spacing,anything)
+ local anyentitycontent=(1-open-semicolon-space-close-ampersand)^0
+ local hexentitycontent=R("AF","af","09")^1
+ local decentitycontent=R("09")^1
+ local parsedentity=P("#")/""*(
+         P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity)
+        )+(anyentitycontent/handle_any_entity_dtd) 
+ local parsedentity_text=P("#")/""*(
+         P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity)
+        )+(anyentitycontent/handle_any_entity_text) 
+ local entity=(ampersand/"")*parsedentity*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity)
+ local entity_text=(ampersand/"")*parsedentity_text*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity)
+ local text_unparsed=Cs((anything-open)^1)
+ local text_parsed=(Cs((anything-open-ampersand)^1)/add_text+Cs(entity_text)/add_text)^1
+ local somespace=(spacenewline)^1
+ local optionalspace=(spacenewline)^0
+ local value=(squote*Cs((entity+(anything-squote))^0)*squote)+(dquote*Cs((entity+(anything-dquote))^0)*dquote) 
+ local endofattributes=slash*close+close 
+ local whatever=space*name*optionalspace*equal
+ local wrongvalue=Cs(P(entity+(1-space-endofattributes))^1)/attribute_value_error
+ local attributevalue=value+wrongvalue
+ local attribute=(somespace*name*optionalspace*equal*optionalspace*attributevalue)/add_attribute
+ local attributes=(attribute+somespace^-1*(((anything-endofattributes)^1)/attribute_specification_error))^0
+ local parsedtext=text_parsed   
+ local unparsedtext=text_unparsed/add_text
+ local balanced=P { "["*((anything-S"[]")+V(1))^0*"]" }
+ local emptyelement=(spacing*open*name*attributes*optionalspace*slash*close)/add_empty
+ local beginelement=(spacing*open*name*attributes*optionalspace*close)/add_begin
+ local endelement=(spacing*open*slash*name*optionalspace*close)/add_end
+ local begincomment=open*P("!--")
+ local endcomment=P("--")*close
+ local begininstruction=open*P("?")
+ local endinstruction=P("?")*close
+ local begincdata=open*P("![CDATA[")
+ local endcdata=P("]]")*close
+ local someinstruction=C((anything-endinstruction)^0)
+ local somecomment=C((anything-endcomment )^0)
+ local somecdata=C((anything-endcdata   )^0)
+ local begindoctype=open*P("!DOCTYPE")
+ local enddoctype=close
+ local beginset=P("[")
+ local endset=P("]")
+ local wrdtypename=C((anything-somespace-P(";"))^1)
+ local doctypename=C((anything-somespace-close)^0)
+ local elementdoctype=optionalspace*P("<!ELEMENT")*(anything-close)^0*close
+ local basiccomment=begincomment*((anything-endcomment)^0)*endcomment
+ local weirdentitytype=P("%")*(somespace*doctypename*somespace*value)/weirdentity
+ local normalentitytype=(doctypename*somespace*value)/normalentity
+ local publicentitytype=(doctypename*somespace*P("PUBLIC")*somespace*value)/publicentity
+ local systementitytype=(doctypename*somespace*P("SYSTEM")*somespace*value*somespace*P("NDATA")*somespace*doctypename)/systementity
+ local entitydoctype=optionalspace*P("<!ENTITY")*somespace*(systementitytype+publicentitytype+normalentitytype+weirdentitytype)*optionalspace*close
+ local publicentityfile=(doctypename*somespace*P("PUBLIC")*somespace*value*(somespace*value)^0)/function(...)
+  entityfile(entitydoctype,...)
+ end
+ local function weirdresolve(s)
+  lpegmatch(entitydoctype,parameters[s])
+ end
+ local function normalresolve(s)
+  lpegmatch(entitydoctype,entities[s])
+ end
+ local entityresolve=P("%")*(wrdtypename/weirdresolve )*P(";")+P("&")*(wrdtypename/normalresolve)*P(";")
+ entitydoctype=entitydoctype+entityresolve
+ local doctypeset=beginset*optionalspace*P(elementdoctype+entitydoctype+entityresolve+basiccomment+space)^0*optionalspace*endset
+ local definitiondoctype=doctypename*somespace*doctypeset
+ local publicdoctype=doctypename*somespace*P("PUBLIC")*somespace*value*somespace*value*somespace*doctypeset
+ local systemdoctype=doctypename*somespace*P("SYSTEM")*somespace*value*somespace*doctypeset
+ local simpledoctype=(anything-close)^1 
+ local somedoctype=C((somespace*(publicentityfile+publicdoctype+systemdoctype+definitiondoctype+simpledoctype)*optionalspace)^0)
+ local instruction=(spacing*begininstruction*someinstruction*endinstruction)/function(...) add_special("@pi@",...) end
+ local comment=(spacing*begincomment*somecomment*endcomment )/function(...) add_special("@cm@",...) end
+ local cdata=(spacing*begincdata*somecdata*endcdata   )/function(...) add_special("@cd@",...) end
+ local doctype=(spacing*begindoctype*somedoctype*enddoctype )/function(...) add_special("@dt@",...) end
+ local crap_parsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata-ampersand
+ local crap_unparsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata
+ local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error
+ local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error
+ local unparsedcrap=Cs((crap_unparsed     )^1)/handle_crap_error
+ local trailer=space^0*(text_unparsed/set_message)^0
+ local grammar_parsed_text_one=P { "preamble",
+  preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0,
+ }
+ local grammar_parsed_text_two=P { "followup",
+  followup=V("parent")*trailer,
+  parent=beginelement*V("children")^0*endelement,
+  children=parsedtext+V("parent")+emptyelement+comment+cdata+instruction+parsedcrap,
+ }
+ local grammar_unparsed_text=P { "preamble",
+  preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0*V("parent")*trailer,
+  parent=beginelement*V("children")^0*endelement,
+  children=unparsedtext+V("parent")+emptyelement+comment+cdata+instruction+unparsedcrap,
+ }
+ return grammar_parsed_text_one,grammar_parsed_text_two,grammar_unparsed_text
+end
+local
+ grammar_parsed_text_one_nop,
+ grammar_parsed_text_two_nop,
+ grammar_unparsed_text_nop=install(space,spacing,anything)
+local
+ grammar_parsed_text_one_yes,
+ grammar_parsed_text_two_yes,
+ grammar_unparsed_text_yes=install(space_nl,spacing_nl,anything_nl)
+local function _xmlconvert_(data,settings,detail)
+ settings=settings or {} 
+ preparexmlstate(settings)
+ if settings.linenumbers then
+  grammar_parsed_text_one=grammar_parsed_text_one_yes
+  grammar_parsed_text_two=grammar_parsed_text_two_yes
+  grammar_unparsed_text=grammar_unparsed_text_yes
+ else
+  grammar_parsed_text_one=grammar_parsed_text_one_nop
+  grammar_parsed_text_two=grammar_parsed_text_two_nop
+  grammar_unparsed_text=grammar_unparsed_text_nop
+ end
+ local preprocessor=settings.preprocessor
+ if data and data~="" and type(preprocessor)=="function" then
+  data=preprocessor(data,settings) or data 
+ end
+ if settings.parent_root then
+  mt=getmetatable(settings.parent_root)
+ else
+  initialize_mt(top)
+ end
+ level=level+1
+ stack[level]=top
+ top.dt={}
+ dt=top.dt
+ nt=0
+ if not data or data=="" then
+  errorstr="empty xml file"
+ elseif data==true then
+  errorstr=detail or "problematic xml file"
+ elseif utfize or resolve then
+  local m=lpegmatch(grammar_parsed_text_one,data)
+  if m then
+   m=lpegmatch(grammar_parsed_text_two,data,m)
+  end
+  if m then
+  else
+   errorstr="invalid xml file - parsed text"
+  end
+ elseif type(data)=="string" then
+  if lpegmatch(grammar_unparsed_text,data) then
+   errorstr=""
+  else
+   errorstr="invalid xml file - unparsed text"
+  end
+ else
+  errorstr="invalid xml file - no text at all"
+ end
+ local result
+ if errorstr and errorstr~="" then
+  result={ dt={ { ns="",tg="error",dt={ errorstr },at={},er=true } } }
+  setmetatable(result,mt)
+  setmetatable(result.dt[1],mt)
+  setmetatable(stack,mt)
+  local errorhandler=settings.error_handler
+  if errorhandler==false then
+  else
+   errorhandler=errorhandler or xml.errorhandler
+   if errorhandler then
+    local currentresource=settings.currentresource
+    if currentresource and currentresource~="" then
+     xml.errorhandler(formatters["load error in [%s]: %s"](currentresource,errorstr),currentresource)
+    else
+     xml.errorhandler(formatters["load error: %s"](errorstr))
+    end
+   end
+  end
+ else
+  result=stack[1]
+ end
+ if not settings.no_root then
+  result={ special=true,ns="",tg='@rt@',dt=result.dt,at={},entities=entities,settings=settings }
+  setmetatable(result,mt)
+  local rdt=result.dt
+  for k=1,#rdt do
+   local v=rdt[k]
+   if type(v)=="table" and not v.special then 
+    result.ri=k 
+    v.__p__=result  
+    break
+   end
+  end
+ end
+ if errorstr and errorstr~="" then
+  result.error=true
+ else
+  errorstr=nil
+ end
+ result.statistics={
+  errormessage=errorstr,
+  entities={
+   decimals=dcache,
+   hexadecimals=hcache,
+   names=acache,
+   intermediates=parameters,
+  }
+ }
+ preparexmlstate() 
+ return result
+end
+local function xmlconvert(data,settings)
+ local ok,result=pcall(function() return _xmlconvert_(data,settings) end)
+ if ok then
+  return result
+ elseif type(result)=="string" then
+  return _xmlconvert_(true,settings,result)
+ else
+  return _xmlconvert_(true,settings)
+ end
+end
+xml.convert=xmlconvert
+function xml.inheritedconvert(data,xmldata,cleanup) 
+ local settings=xmldata.settings
+ if settings then
+  settings.parent_root=xmldata 
+ end
+ local xc=xmlconvert(data,settings) 
+ if cleanup then
+  local x=xc.dt
+  if x then
+   x=x[1]
+   if x and x.tg=="@pi@" then
+    local dt=x.dt
+    local pi=dt and dt[1]
+    if type(pi)=="string" and find(pi,"^xml") then
+     remove(dt,1)
+    end
+   end
+  end
+ end
+ return xc
+end
+function xml.is_valid(root)
+ return root and root.dt and root.dt[1] and type(root.dt[1])=="table" and not root.dt[1].er
+end
+function xml.package(tag,attributes,data)
+ local ns,tg=match(tag,"^(.-):?([^:]+)$")
+ local t={ ns=ns,tg=tg,dt=data or "",at=attributes or {} }
+ setmetatable(t,mt)
+ return t
+end
+function xml.is_valid(root)
+ return root and not root.error
+end
+xml.errorhandler=report_xml
+function xml.load(filename,settings)
+ local data=""
+ if type(filename)=="string" then
+  local f=io.open(filename,'r') 
+  if f then
+   data=f:read("*all") 
+   f:close()
+  end
+ elseif filename then 
+  data=filename:read("*all") 
+ end
+ if settings then
+  settings.currentresource=filename
+  local result=xmlconvert(data,settings)
+  settings.currentresource=nil
+  return result
+ else
+  return xmlconvert(data,{ currentresource=filename })
+ end
+end
+local no_root={ no_root=true }
+function xml.toxml(data)
+ if type(data)=="string" then
+  local root={ xmlconvert(data,no_root) }
+  return (#root>1 and root) or root[1]
+ else
+  return data
+ end
+end
+local function copy(old,p)
+ if old then
+  local new={}
+  for k,v in next,old do
+   local t=type(v)=="table"
+   if k=="at" then
+    local t={}
+    for k,v in next,v do
+     t[k]=v
+    end
+    new[k]=t
+   elseif k=="dt" then
+    v.__p__=nil
+    local t={}
+    for i=1,#v do
+     local vi=v[i]
+     if type(vi)=="table" then
+      t[i]=copy(vi,new)
+     else
+      t[i]=vi
+     end
+    end
+    new[k]=t
+    t.__p__=p
+   else
+    new[k]=v 
+   end
+  end
+  local mt=getmetatable(old)
+  if mt then
+   setmetatable(new,mt)
+  end
+  return new
+ else
+  return {}
+ end
+end
+xml.copy=copy
+function xml.checkbom(root) 
+ if root.ri then
+  local dt=root.dt
+  for k=1,#dt do
+   local v=dt[k]
+   if type(v)=="table" and v.special and v.tg=="@pi@" and find(v.dt[1],"xml.*version=") then
+    return
+   end
+  end
+  insert(dt,1,{ special=true,ns="",tg="@pi@",dt={ "xml version='1.0' standalone='yes'" } } )
+  insert(dt,2,"\n" )
+ end
+end
+local f_attribute=formatters['%s=%q']
+local function verbose_element(e,handlers,escape) 
+ local handle=handlers.handle
+ local serialize=handlers.serialize
+ local ens,etg,eat,edt,ern=e.ns,e.tg,e.at,e.dt,e.rn
+ local ats=eat and next(eat) and {}
+ if ats then
+  local n=0
+  for k in next,eat do
+   n=n+1
+   ats[n]=k
+  end
+  if n==1 then
+   local k=ats[1]
+   ats=f_attribute(k,escaped(eat[k]))
+  else
+   sort(ats)
+   for i=1,n do
+    local k=ats[i]
+    ats[i]=f_attribute(k,escaped(eat[k]))
+   end
+   ats=concat(ats," ")
+  end
+ end
+ if ern and trace_entities and ern~=ens then
+  ens=ern
+ end
+ local n=edt and #edt
+ if ens~="" then
+  if n and n>0 then
+   if ats then
+    handle("<",ens,":",etg," ",ats,">")
+   else
+    handle("<",ens,":",etg,">")
+   end
+   for i=1,n do
+    local e=edt[i]
+    if type(e)=="string" then
+     handle(escaped(e))
+    else
+     serialize(e,handlers)
+    end
+   end
+   handle("</",ens,":",etg,">")
+  else
+   if ats then
+    handle("<",ens,":",etg," ",ats,"/>")
+   else
+    handle("<",ens,":",etg,"/>")
+   end
+  end
+ else
+  if n and n>0 then
+   if ats then
+    handle("<",etg," ",ats,">")
+   else
+    handle("<",etg,">")
+   end
+   for i=1,n do
+    local e=edt[i]
+    if type(e)=="string" then
+     handle(escaped(e)) 
+    else
+     serialize(e,handlers)
+    end
+   end
+   handle("</",etg,">")
+  else
+   if ats then
+    handle("<",etg," ",ats,"/>")
+   else
+    handle("<",etg,"/>")
+   end
+  end
+ end
+end
+local function verbose_pi(e,handlers)
+ handlers.handle("<?",e.dt[1],"?>")
+end
+local function verbose_comment(e,handlers)
+ handlers.handle("<!--",e.dt[1],"-->")
+end
+local function verbose_cdata(e,handlers)
+ handlers.handle("<![CDATA[",e.dt[1],"]]>")
+end
+local function verbose_doctype(e,handlers)
+ handlers.handle("<!DOCTYPE",e.dt[1],">") 
+end
+local function verbose_root(e,handlers)
+ handlers.serialize(e.dt,handlers)
+end
+local function verbose_text(e,handlers)
+ handlers.handle(escaped(e))
+end
+local function verbose_document(e,handlers)
+ local serialize=handlers.serialize
+ local functions=handlers.functions
+ for i=1,#e do
+  local ei=e[i]
+  if type(ei)=="string" then
+   functions["@tx@"](ei,handlers)
+  else
+   serialize(ei,handlers)
+  end
+ end
+end
+local function serialize(e,handlers,...)
+ if e then
+  local initialize=handlers.initialize
+  local finalize=handlers.finalize
+  local functions=handlers.functions
+  if initialize then
+   local state=initialize(...)
+   if not state==true then
+    return state
+   end
+  end
+  local etg=e.tg
+  if etg then
+   (functions[etg] or functions["@el@"])(e,handlers)
+  else
+   functions["@dc@"](e,handlers) 
+  end
+  if finalize then
+   return finalize()
+  end
+ end
+end
+local function xserialize(e,handlers)
+ if e then
+  local functions=handlers.functions
+  local etg=e.tg
+  if etg then
+   (functions[etg] or functions["@el@"])(e,handlers)
+  else
+   functions["@dc@"](e,handlers)
+  end
+ end
+end
+local handlers={}
+local function newhandlers(settings)
+ local t=table.copy(handlers[settings and settings.parent or "verbose"] or {}) 
+ if settings then
+  for k,v in next,settings do
+   if type(v)=="table" then
+    local tk=t[k] if not tk then tk={} t[k]=tk end
+    for kk,vv in next,v do
+     tk[kk]=vv
+    end
+   else
+    t[k]=v
+   end
+  end
+  if settings.name then
+   handlers[settings.name]=t
+  end
+ end
+ utilities.storage.mark(t)
+ return t
+end
+local nofunction=function() end
+function xml.sethandlersfunction(handler,name,fnc)
+ handler.functions[name]=fnc or nofunction
+end
+function xml.gethandlersfunction(handler,name)
+ return handler.functions[name]
+end
+function xml.gethandlers(name)
+ return handlers[name]
+end
+newhandlers {
+ name="verbose",
+ initialize=false,
+ finalize=false,
+ serialize=xserialize,
+ handle=print,
+ functions={
+  ["@dc@"]=verbose_document,
+  ["@dt@"]=verbose_doctype,
+  ["@rt@"]=verbose_root,
+  ["@el@"]=verbose_element,
+  ["@pi@"]=verbose_pi,
+  ["@cm@"]=verbose_comment,
+  ["@cd@"]=verbose_cdata,
+  ["@tx@"]=verbose_text,
+ }
+}
+local result
+local xmlfilehandler=newhandlers {
+ name="file",
+ initialize=function(name)
+  result=io.open(name,"wb")
+  return result
+ end,
+ finalize=function()
+  result:close()
+  return true
+ end,
+ handle=function(...)
+  result:write(...)
+ end,
+}
+function xml.save(root,name)
+ serialize(root,xmlfilehandler,name)
+end
+local result,r,threshold={},0,512
+local xmlstringhandler=newhandlers {
+ name="string",
+ initialize=function()
+  r=0
+  return result
+ end,
+ finalize=function()
+  local done=concat(result,"",1,r)
+  r=0
+  if r>threshold then
+   result={}
+  end
+  return done
+ end,
+ handle=function(...)
+  for i=1,select("#",...) do
+   r=r+1
+   result[r]=select(i,...)
+  end
+ end,
+}
+local function xmltostring(root) 
+ if not root then
+  return ""
+ elseif type(root)=="string" then
+  return root
+ else 
+  return serialize(root,xmlstringhandler) or ""
+ end
+end
+local function __tostring(root) 
+ return (root and xmltostring(root)) or ""
+end
+initialize_mt=function(root) 
+ mt={ __tostring=__tostring,__index=root }
+end
+xml.defaulthandlers=handlers
+xml.newhandlers=newhandlers
+xml.serialize=serialize
+xml.tostring=xmltostring
+local function xmlstring(e,handle)
+ if not handle or (e.special and e.tg~="@rt@") then
+ elseif e.tg then
+  local edt=e.dt
+  if edt then
+   for i=1,#edt do
+    xmlstring(edt[i],handle)
+   end
+  end
+ else
+  handle(e)
+ end
+end
+xml.string=xmlstring
+function xml.settings(e)
+ while e do
+  local s=e.settings
+  if s then
+   return s
+  else
+   e=e.__p__
+  end
+ end
+ return nil
+end
+function xml.root(e)
+ local r=e
+ while e do
+  e=e.__p__
+  if e then
+   r=e
+  end
+ end
+ return r
+end
+function xml.parent(root)
+ return root.__p__
+end
+function xml.body(root)
+ return root.ri and root.dt[root.ri] or root 
+end
+function xml.name(root)
+ if not root then
+  return ""
+ end
+ local ns=root.ns
+ local tg=root.tg
+ if ns=="" then
+  return tg
+ else
+  return ns..":"..tg
+ end
+end
+function xml.erase(dt,k)
+ if dt then
+  if k then
+   dt[k]=""
+  else for k=1,#dt do
+   dt[1]={ "" }
+  end end
+ end
+end
+function xml.assign(dt,k,root)
+ if dt and k then
+  dt[k]=type(root)=="table" and xml.body(root) or root
+  return dt[k]
+ else
+  return xml.body(root)
+ end
+end
+function xml.tocdata(e,wrapper) 
+ local whatever=type(e)=="table" and xmltostring(e.dt) or e or ""
+ if wrapper then
+  whatever=formatters["<%s>%s</%s>"](wrapper,whatever,wrapper)
+ end
+ local t={ special=true,ns="",tg="@cd@",at={},rn="",dt={ whatever },__p__=e }
+ setmetatable(t,getmetatable(e))
+ e.dt={ t }
+end
+function xml.makestandalone(root)
+ if root.ri then
+  local dt=root.dt
+  for k=1,#dt do
+   local v=dt[k]
+   if type(v)=="table" and v.special and v.tg=="@pi@" then
+    local txt=v.dt[1]
+    if find(txt,"xml.*version=") then
+     v.dt[1]=txt.." standalone='yes'"
+     break
+    end
+   end
+  end
+ end
+ return root
+end
+function xml.kind(e)
+ local dt=e and e.dt
+ if dt then
+  local n=#dt
+  if n==1 then
+   local d=dt[1]
+   if d.special then
+    local tg=d.tg
+    if tg=="@cd@" then
+     return "cdata"
+    elseif tg=="@cm@" then
+     return "comment"
+    elseif tg=="@pi@" then
+     return "instruction"
+    elseif tg=="@dt@" then
+     return "declaration"
+    end
+   elseif type(d)=="string" then
+    return "text"
+   end
+   return "element"
+  elseif n>0 then
+   return "mixed"
+  end
+ end
+ return "empty"
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["lxml-lpt"] = package.loaded["lxml-lpt"] or true
+
+-- original size: 54733, stripped down to: 31258
+
+if not modules then modules={} end modules ['lxml-lpt']={
+ version=1.001,
+ comment="this module is the basis for the lxml-* ones",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local concat,remove,insert=table.concat,table.remove,table.insert
+local type,next,tonumber,tostring,setmetatable,load,select=type,next,tonumber,tostring,setmetatable,load,select
+local format,upper,lower,gmatch,gsub,find,rep=string.format,string.upper,string.lower,string.gmatch,string.gsub,string.find,string.rep
+local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns
+local setmetatableindex=table.setmetatableindex
+local formatters=string.formatters
+local trace_lpath=false
+local trace_lparse=false
+local trace_lprofile=false
+local report_lpath=logs.reporter("xml","lpath")
+if trackers then
+ trackers.register("xml.path",function(v)
+  trace_lpath=v
+ end)
+ trackers.register("xml.parse",function(v)
+  trace_lparse=v
+ end)
+ trackers.register("xml.profile",function(v)
+  trace_lpath=v
+  trace_lparse=v
+  trace_lprofile=v
+ end)
+end
+local xml=xml
+local lpathcalls=0  function xml.lpathcalls () return lpathcalls  end
+local lpathcached=0  function xml.lpathcached() return lpathcached end
+xml.functions=xml.functions or {} 
+local functions=xml.functions
+xml.expressions=xml.expressions or {} 
+local expressions=xml.expressions
+xml.finalizers=xml.finalizers or {} 
+local finalizers=xml.finalizers
+xml.specialhandler=xml.specialhandler or {}
+local specialhandler=xml.specialhandler
+lpegpatterns.xml=lpegpatterns.xml or {}
+local xmlpatterns=lpegpatterns.xml
+finalizers.xml=finalizers.xml or {}
+finalizers.tex=finalizers.tex or {}
+local function fallback (t,name)
+ local fn=finalizers[name]
+ if fn then
+  t[name]=fn
+ else
+  report_lpath("unknown sub finalizer %a",name)
+  fn=function() end
+ end
+ return fn
+end
+setmetatableindex(finalizers.xml,fallback)
+setmetatableindex(finalizers.tex,fallback)
+xml.defaultprotocol="xml"
+local apply_axis={}
+apply_axis['root']=function(list)
+ local collected={}
+ for l=1,#list do
+  local ll=list[l]
+  local rt=ll
+  while ll do
+   ll=ll.__p__
+   if ll then
+    rt=ll
+   end
+  end
+  collected[l]=rt
+ end
+ return collected
+end
+apply_axis['self']=function(list)
+ return list
+end
+apply_axis['child']=function(list)
+ local collected={}
+ local c=0
+ for l=1,#list do
+  local ll=list[l]
+  local dt=ll.dt
+  if dt then 
+   local n=#dt
+   if n==0 then
+    ll.en=0
+   elseif n==1 then
+    local dk=dt[1]
+    if dk.tg then
+     c=c+1
+     collected[c]=dk
+     dk.ni=1 
+     dk.ei=1
+     ll.en=1
+    end
+   else
+    local en=0
+    for k=1,#dt do
+     local dk=dt[k]
+     if dk.tg then
+      c=c+1
+      en=en+1
+      collected[c]=dk
+      dk.ni=k 
+      dk.ei=en
+     end
+    end
+    ll.en=en
+   end
+  end
+ end
+ return collected
+end
+local function collect(list,collected,c)
+ local dt=list.dt
+ if dt then
+  local n=#dt
+  if n==0 then
+   list.en=0
+  elseif n==1 then
+   local dk=dt[1]
+   if dk.tg then
+    c=c+1
+    collected[c]=dk
+    dk.ni=1 
+    dk.ei=1
+    c=collect(dk,collected,c)
+    list.en=1
+   else
+    list.en=0
+   end
+  else
+   local en=0
+   for k=1,n do
+    local dk=dt[k]
+    if dk.tg then
+     c=c+1
+     en=en+1
+     collected[c]=dk
+     dk.ni=k 
+     dk.ei=en
+     c=collect(dk,collected,c)
+    end
+   end
+   list.en=en
+  end
+ end
+ return c
+end
+apply_axis['descendant']=function(list)
+ local collected={}
+ local c=0
+ for l=1,#list do
+  c=collect(list[l],collected,c)
+ end
+ return collected
+end
+local function collect(list,collected,c)
+ local dt=list.dt
+ if dt then
+  local n=#dt
+  if n==0 then
+   list.en=0
+  elseif n==1 then
+   local dk=dt[1]
+   if dk.tg then
+    c=c+1
+    collected[c]=dk
+    dk.ni=1 
+    dk.ei=1
+    c=collect(dk,collected,c)
+    list.en=1
+   end
+  else
+   local en=0
+   for k=1,#dt do
+    local dk=dt[k]
+    if dk.tg then
+     c=c+1
+     en=en+1
+     collected[c]=dk
+     dk.ni=k 
+     dk.ei=en
+     c=collect(dk,collected,c)
+    end
+   end
+   list.en=en
+  end
+ end
+ return c
+end
+apply_axis['descendant-or-self']=function(list)
+ local collected={}
+ local c=0
+ for l=1,#list do
+  local ll=list[l]
+  if ll.special~=true then 
+   c=c+1
+   collected[c]=ll
+  end
+  c=collect(ll,collected,c)
+ end
+ return collected
+end
+apply_axis['ancestor']=function(list)
+ local collected={}
+ local c=0
+ for l=1,#list do
+  local ll=list[l]
+  while ll do
+   ll=ll.__p__
+   if ll then
+    c=c+1
+    collected[c]=ll
+   end
+  end
+ end
+ return collected
+end
+apply_axis['ancestor-or-self']=function(list)
+ local collected={}
+ local c=0
+ for l=1,#list do
+  local ll=list[l]
+  c=c+1
+  collected[c]=ll
+  while ll do
+   ll=ll.__p__
+   if ll then
+    c=c+1
+    collected[c]=ll
+   end
+  end
+ end
+ return collected
+end
+apply_axis['parent']=function(list)
+ local collected={}
+ local c=0
+ for l=1,#list do
+  local pl=list[l].__p__
+  if pl then
+   c=c+1
+   collected[c]=pl
+  end
+ end
+ return collected
+end
+apply_axis['attribute']=function(list)
+ return {}
+end
+apply_axis['namespace']=function(list)
+ return {}
+end
+apply_axis['following']=function(list)
+ return {}
+end
+apply_axis['preceding']=function(list)
+ return {}
+end
+apply_axis['following-sibling']=function(list)
+ local collected={}
+ local c=0
+ for l=1,#list do
+  local ll=list[l]
+  local p=ll.__p__
+  local d=p.dt
+  for i=ll.ni+1,#d do
+   local di=d[i]
+   if type(di)=="table" then
+    c=c+1
+    collected[c]=di
+   end
+  end
+ end
+ return collected
+end
+apply_axis['preceding-sibling']=function(list)
+ local collected={}
+ local c=0
+ for l=1,#list do
+  local ll=list[l]
+  local p=ll.__p__
+  local d=p.dt
+  for i=1,ll.ni-1 do
+   local di=d[i]
+   if type(di)=="table" then
+    c=c+1
+    collected[c]=di
+   end
+  end
+ end
+ return collected
+end
+apply_axis['reverse-sibling']=function(list) 
+ local collected={}
+ local c=0
+ for l=1,#list do
+  local ll=list[l]
+  local p=ll.__p__
+  local d=p.dt
+  for i=ll.ni-1,1,-1 do
+   local di=d[i]
+   if type(di)=="table" then
+    c=c+1
+    collected[c]=di
+   end
+  end
+ end
+ return collected
+end
+apply_axis['auto-descendant-or-self']=apply_axis['descendant-or-self']
+apply_axis['auto-descendant']=apply_axis['descendant']
+apply_axis['auto-child']=apply_axis['child']
+apply_axis['auto-self']=apply_axis['self']
+apply_axis['initial-child']=apply_axis['child']
+local function apply_nodes(list,directive,nodes)
+ local maxn=#nodes
+ if maxn==3 then 
+  local nns=nodes[2]
+  local ntg=nodes[3]
+  if not nns and not ntg then 
+   if directive then
+    return list
+   else
+    return {}
+   end
+  else
+   local collected={}
+   local c=0
+   local m=0
+   local p=nil
+   if not nns then 
+    for l=1,#list do
+     local ll=list[l]
+     local ltg=ll.tg
+     if ltg then
+      if directive then
+       if ntg==ltg then
+        local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end
+        c=c+1
+        collected[c]=ll
+        ll.mi=m
+       end
+      elseif ntg~=ltg then
+       local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end
+       c=c+1
+       collected[c]=ll
+       ll.mi=m
+      end
+     end
+    end
+   elseif not ntg then 
+    for l=1,#list do
+     local ll=list[l]
+     local lns=ll.rn or ll.ns
+     if lns then
+      if directive then
+       if lns==nns then
+        local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end
+        c=c+1
+        collected[c]=ll
+        ll.mi=m
+       end
+      elseif lns~=nns then
+       local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end
+       c=c+1
+       collected[c]=ll
+       ll.mi=m
+      end
+     end
+    end
+   else 
+    for l=1,#list do
+     local ll=list[l]
+     local ltg=ll.tg
+     if ltg then
+      local lns=ll.rn or ll.ns
+      local ok=ltg==ntg and lns==nns
+      if directive then
+       if ok then
+        local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end
+        c=c+1
+        collected[c]=ll
+        ll.mi=m
+       end
+      elseif not ok then
+       local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end
+       c=c+1
+       collected[c]=ll
+       ll.mi=m
+      end
+     end
+    end
+   end
+   return collected
+  end
+ else
+  local collected={}
+  local c=0
+  local m=0
+  local p=nil
+  for l=1,#list do
+   local ll=list[l]
+   local ltg=ll.tg
+   if ltg then
+    local lns=ll.rn or ll.ns
+    local ok=false
+    for n=1,maxn,3 do
+     local nns=nodes[n+1]
+     local ntg=nodes[n+2]
+     ok=(not ntg or ltg==ntg) and (not nns or lns==nns)
+     if ok then
+      break
+     end
+    end
+    if directive then
+     if ok then
+      local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end
+      c=c+1
+      collected[c]=ll
+      ll.mi=m
+     end
+    elseif not ok then
+     local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end
+     c=c+1
+     collected[c]=ll
+     ll.mi=m
+    end
+   end
+  end
+  return collected
+ end
+end
+local quit_expression=false
+local function apply_expression(list,expression,order)
+ local collected={}
+ local c=0
+ quit_expression=false
+ for l=1,#list do
+  local ll=list[l]
+  if expression(list,ll,l,order) then 
+   c=c+1
+   collected[c]=ll
+  end
+  if quit_expression then
+   break
+  end
+ end
+ return collected
+end
+local function apply_selector(list,specification)
+ if xml.applyselector then
+  apply_selector=xml.applyselector
+  return apply_selector(list,specification)
+ else
+  return list
+ end
+end
+local P,V,C,Cs,Cc,Ct,R,S,Cg,Cb=lpeg.P,lpeg.V,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Ct,lpeg.R,lpeg.S,lpeg.Cg,lpeg.Cb
+local spaces=S(" \n\r\t\f")^0
+local lp_space=S(" \n\r\t\f")
+local lp_any=P(1)
+local lp_noequal=P("!=")/"~="+P("<=")+P(">=")+P("==")
+local lp_doequal=P("=")/"=="
+local lp_or=P("|")/" or "
+local lp_and=P("&")/" and "
+local builtin={
+ text="(ll.dt[1] or '')",
+ content="ll.dt",
+ name="((ll.ns~='' and ll.ns..':'..ll.tg) or ll.tg)",
+ tag="ll.tg",
+ position="l",
+ firstindex="1",
+ firstelement="1",
+ first="1",
+ lastindex="(#ll.__p__.dt or 1)",
+ lastelement="(ll.__p__.en or 1)",
+ last="#list",
+ list="list",
+ self="ll",
+ rootposition="order",
+ order="order",
+ element="(ll.ei or 1)",
+ index="(ll.ni or 1)",
+ match="(ll.mi or 1)",
+ namespace="ll.ns",
+ ns="ll.ns",
+}
+local lp_builtin=lpeg.utfchartabletopattern(builtin)/builtin*((spaces*P("(")*spaces*P(")"))/"")
+local lp_attribute=(P("@")+P("attribute::"))/""*Cc("(ll.at and ll.at['")*((R("az","AZ")+S("-_:"))^1)*Cc("'])")
+local lp_fastpos_p=P("+")^0*R("09")^1*P(-1)/"l==%0"
+local lp_fastpos_n=P("-")*R("09")^1*P(-1)/"(%0<0 and (#list+%0+1==l))" 
+local lp_fastpos=lp_fastpos_n+lp_fastpos_p
+local lp_reserved=C("and")+C("or")+C("not")+C("div")+C("mod")+C("true")+C("false")
+local lp_lua_function=Cs((R("az","AZ","__")^1*(P(".")*R("az","AZ","__")^1)^1)*("("))/"%0"
+local lp_function=C(R("az","AZ","__")^1)*P("(")/function(t) 
+ if expressions[t] then
+  return "expr."..t.."("
+ else
+  return "expr.error("
+ end
+end
+local lparent=P("(")
+local rparent=P(")")
+local noparent=1-(lparent+rparent)
+local nested=P{lparent*(noparent+V(1))^0*rparent}
+local value=P(lparent*C((noparent+nested)^0)*rparent) 
+local lp_child=Cc("expr.child(ll,'")*R("az","AZ")*R("az","AZ","--","__")^0*Cc("')")
+local lp_number=S("+-")*R("09")^1
+local lp_string=Cc("'")*R("az","AZ","--","__")^1*Cc("'")
+local lp_content=(P("'")*(1-P("'"))^0*P("'")+P('"')*(1-P('"'))^0*P('"'))
+local cleaner
+local lp_special=(C(P("name")+P("text")+P("tag")+P("count")+P("child")))*value/function(t,s)
+ if expressions[t] then
+  s=s and s~="" and lpegmatch(cleaner,s)
+  if s and s~="" then
+   return "expr."..t.."(ll,"..s..")"
+  else
+   return "expr."..t.."(ll)"
+  end
+ else
+  return "expr.error("..t..")"
+ end
+end
+local content=lp_builtin+lp_attribute+lp_special+lp_noequal+lp_doequal+lp_or+lp_and+lp_reserved+lp_lua_function+lp_function+lp_content+
+ lp_child+lp_any
+local converter=Cs (
+ lp_fastpos+(P { lparent*(V(1))^0*rparent+content } )^0
+)
+cleaner=Cs ((
+ lp_reserved+lp_number+lp_string+1 )^1 )
+local template_e=[[
+    local expr = xml.expressions
+    return function(list,ll,l,order)
+        return %s
+    end
+]]
+local template_f_y=[[
+    local finalizer = xml.finalizers['%s']['%s']
+    return function(collection)
+        return finalizer(collection,%s)
+    end
+]]
+local template_f_n=[[
+    return xml.finalizers['%s']['%s']
+]]
+local register_last_match={ kind="axis",axis="last-match"     } 
+local register_self={ kind="axis",axis="self"     } 
+local register_parent={ kind="axis",axis="parent"      } 
+local register_descendant={ kind="axis",axis="descendant"     } 
+local register_child={ kind="axis",axis="child"       } 
+local register_descendant_or_self={ kind="axis",axis="descendant-or-self"   } 
+local register_root={ kind="axis",axis="root"     } 
+local register_ancestor={ kind="axis",axis="ancestor"    } 
+local register_ancestor_or_self={ kind="axis",axis="ancestor-or-self"  } 
+local register_attribute={ kind="axis",axis="attribute"      } 
+local register_namespace={ kind="axis",axis="namespace"      } 
+local register_following={ kind="axis",axis="following"      } 
+local register_following_sibling={ kind="axis",axis="following-sibling"    } 
+local register_preceding={ kind="axis",axis="preceding"      } 
+local register_preceding_sibling={ kind="axis",axis="preceding-sibling"    } 
+local register_reverse_sibling={ kind="axis",axis="reverse-sibling"   } 
+local register_auto_descendant_or_self={ kind="axis",axis="auto-descendant-or-self" } 
+local register_auto_descendant={ kind="axis",axis="auto-descendant"   } 
+local register_auto_self={ kind="axis",axis="auto-self"      } 
+local register_auto_child={ kind="axis",axis="auto-child"     } 
+local register_initial_child={ kind="axis",axis="initial-child"     } 
+local register_all_nodes={ kind="nodes",nodetest=true,nodes={ true,false,false } }
+local skip={}
+local function errorrunner_e(str,cnv)
+ if not skip[str] then
+  report_lpath("error in expression: %s => %s",str,cnv)
+  skip[str]=cnv or str
+ end
+ return false
+end
+local function errorrunner_f(str,arg)
+ report_lpath("error in finalizer: %s(%s)",str,arg or "")
+ return false
+end
+local function register_nodes(nodetest,nodes)
+ return { kind="nodes",nodetest=nodetest,nodes=nodes }
+end
+local function register_selector(specification)
+ return { kind="selector",specification=specification }
+end
+local function register_expression(expression)
+ local converted=lpegmatch(converter,expression)
+ local wrapped=format(template_e,converted)
+ local runner=load(wrapped)
+ runner=(runner and runner()) or function() errorrunner_e(expression,converted) end
+ return { kind="expression",expression=expression,converted=converted,evaluator=runner }
+end
+local function register_finalizer(protocol,name,arguments)
+ local runner
+ if arguments and arguments~="" then
+  runner=load(format(template_f_y,protocol or xml.defaultprotocol,name,arguments))
+ else
+  runner=load(format(template_f_n,protocol or xml.defaultprotocol,name))
+ end
+ runner=(runner and runner()) or function() errorrunner_f(name,arguments) end
+ return { kind="finalizer",name=name,arguments=arguments,finalizer=runner }
+end
+local expression=P { "ex",
+ ex="["*C((V("sq")+V("dq")+(1-S("[]"))+V("ex"))^0)*"]",
+ sq="'"*(1-S("'"))^0*"'",
+ dq='"'*(1-S('"'))^0*'"',
+}
+local arguments=P { "ar",
+ ar="("*Cs((V("sq")+V("dq")+V("nq")+P(1-P(")")))^0)*")",
+ nq=((1-S("),'\""))^1)/function(s) return format("%q",s) end,
+ sq=P("'")*(1-P("'"))^0*P("'"),
+ dq=P('"')*(1-P('"'))^0*P('"'),
+}
+local function register_error(str)
+ return { kind="error",error=format("unparsed: %s",str) }
+end
+local special_1=P("*")*Cc(register_auto_descendant)*Cc(register_all_nodes) 
+local special_2=P("/")*Cc(register_auto_self)
+local special_3=P("")*Cc(register_auto_self)
+local no_nextcolon=P(-1)+#(1-P(":")) 
+local no_nextlparent=P(-1)+#(1-P("(")) 
+local pathparser=Ct { "patterns",
+ patterns=spaces*V("protocol")*spaces*(
+         (V("special")*spaces*P(-1)               )+(V("initial")*spaces*V("step")*spaces*(P("/")*spaces*V("step")*spaces)^0 )
+         ),
+ protocol=Cg(V("letters"),"protocol")*P("://")+Cg(Cc(nil),"protocol"),
+ step=((V("shortcuts")+V("selector")+P("/")+V("axis"))*spaces*V("nodes")^0+V("error"))*spaces*V("expressions")^0*spaces*V("finalizer")^0,
+ axis=V("last_match")+V("descendant")+V("child")+V("parent")+V("self")+V("root")+V("ancestor")+V("descendant_or_self")+V("following_sibling")+V("following")+V("reverse_sibling")+V("preceding_sibling")+V("preceding")+V("ancestor_or_self")+#(1-P(-1))*Cc(register_auto_child),
+ special=special_1+special_2+special_3,
+ initial=(P("/")*spaces*Cc(register_initial_child))^-1,
+ error=(P(1)^1)/register_error,
+ shortcuts_a=V("s_descendant_or_self")+V("s_descendant")+V("s_child")+V("s_parent")+V("s_self")+V("s_root")+V("s_ancestor")+V("s_lastmatch"),
+ shortcuts=V("shortcuts_a")*(spaces*"/"*spaces*V("shortcuts_a"))^0,
+ s_descendant_or_self=(P("***/")+P("/"))*Cc(register_descendant_or_self),
+ s_descendant=P("**")*Cc(register_descendant),
+ s_child=P("*")*no_nextcolon*Cc(register_child),
+ s_parent=P("..")*Cc(register_parent),
+ s_self=P("." )*Cc(register_self),
+ s_root=P("^^")*Cc(register_root),
+ s_ancestor=P("^")*Cc(register_ancestor),
+ s_lastmatch=P("=")*Cc(register_last_match),
+ descendant=P("descendant::")*Cc(register_descendant),
+ child=P("child::")*Cc(register_child),
+ parent=P("parent::")*Cc(register_parent),
+ self=P("self::")*Cc(register_self),
+ root=P('root::')*Cc(register_root),
+ ancestor=P('ancestor::')*Cc(register_ancestor),
+ descendant_or_self=P('descendant-or-self::')*Cc(register_descendant_or_self),
+ ancestor_or_self=P('ancestor-or-self::')*Cc(register_ancestor_or_self),
+ following=P('following::')*Cc(register_following),
+ following_sibling=P('following-sibling::')*Cc(register_following_sibling),
+ preceding=P('preceding::')*Cc(register_preceding),
+ preceding_sibling=P('preceding-sibling::')*Cc(register_preceding_sibling),
+ reverse_sibling=P('reverse-sibling::')*Cc(register_reverse_sibling),
+ last_match=P('last-match::')*Cc(register_last_match),
+ selector=P("{")*C((1-P("}"))^1)*P("}")/register_selector,
+ nodes=(V("nodefunction")*spaces*P("(")*V("nodeset")*P(")")+V("nodetest")*V("nodeset"))/register_nodes,
+ expressions=expression/register_expression,
+ letters=R("az")^1,
+ name=(1-S("/[]()|:*!"))^1,
+ negate=P("!")*Cc(false),
+ nodefunction=V("negate")+P("not")*Cc(false)+Cc(true),
+ nodetest=V("negate")+Cc(true),
+ nodename=(V("negate")+Cc(true))*spaces*((V("wildnodename")*P(":")*V("wildnodename"))+(Cc(false)*V("wildnodename"))),
+ wildnodename=(C(V("name"))+P("*")*Cc(false))*no_nextlparent,
+ nodeset=spaces*Ct(V("nodename")*(spaces*P("|")*spaces*V("nodename"))^0)*spaces,
+ finalizer=(Cb("protocol")*P("/")^-1*C(V("name"))*arguments*P(-1))/register_finalizer,
+}
+xmlpatterns.pathparser=pathparser
+local cache={}
+local function nodesettostring(set,nodetest)
+ local t={}
+ for i=1,#set,3 do
+  local directive,ns,tg=set[i],set[i+1],set[i+2]
+  if not ns or ns=="" then ns="*" end
+  if not tg or tg=="" then tg="*" end
+  tg=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg)
+  t[#t+1]=(directive and tg) or format("not(%s)",tg)
+ end
+ if nodetest==false then
+  return format("not(%s)",concat(t,"|"))
+ else
+  return concat(t,"|")
+ end
+end
+local function tagstostring(list)
+ if #list==0 then
+  return "no elements"
+ else
+  local t={}
+  for i=1,#list do
+   local li=list[i]
+   local ns=li.ns
+   local tg=li.tg
+   if not ns or ns=="" then ns="*" end
+   if not tg or tg=="" then tg="*" end
+   t[i]=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg)
+  end
+  return concat(t," ")
+ end
+end
+xml.nodesettostring=nodesettostring
+local lpath 
+local function lshow(parsed)
+ if type(parsed)=="string" then
+  parsed=lpath(parsed)
+ end
+ report_lpath("%s://%s => %s",parsed.protocol or xml.defaultprotocol,parsed.pattern,
+  table.serialize(parsed,false))
+end
+xml.lshow=lshow
+local function add_comment(p,str)
+ local pc=p.comment
+ if not pc then
+  p.comment={ str }
+ else
+  pc[#pc+1]=str
+ end
+end
+lpath=function (pattern) 
+ lpathcalls=lpathcalls+1
+ if type(pattern)=="table" then
+  return pattern
+ else
+  local parsed=cache[pattern]
+  if parsed then
+   lpathcached=lpathcached+1
+  else
+   parsed=lpegmatch(pathparser,pattern)
+   if parsed then
+    parsed.pattern=pattern
+    local np=#parsed
+    if np==0 then
+     parsed={ pattern=pattern,register_self,state="parsing error" }
+     report_lpath("parsing error in pattern: %s",pattern)
+     lshow(parsed)
+    else
+     local pi=parsed[1]
+     if pi.axis=="auto-child" then
+      if false then
+       add_comment(parsed,"auto-child replaced by auto-descendant-or-self")
+       parsed[1]=register_auto_descendant_or_self
+      else
+       add_comment(parsed,"auto-child replaced by auto-descendant")
+       parsed[1]=register_auto_descendant
+      end
+     elseif pi.axis=="initial-child" and np>1 and parsed[2].axis then
+      add_comment(parsed,"initial-child removed") 
+      remove(parsed,1)
+     end
+     local np=#parsed 
+     if np>1 then
+      local pnp=parsed[np]
+      if pnp.kind=="nodes" and pnp.nodetest==true then
+       local nodes=pnp.nodes
+       if nodes[1]==true and nodes[2]==false and nodes[3]==false then
+        add_comment(parsed,"redundant final wildcard filter removed")
+        remove(parsed,np)
+       end
+      end
+     end
+    end
+   else
+    parsed={ pattern=pattern }
+   end
+   cache[pattern]=parsed
+   if trace_lparse and not trace_lprofile then
+    lshow(parsed)
+   end
+  end
+  return parsed
+ end
+end
+xml.lpath=lpath
+do
+ local profiled={}
+ xml.profiled=profiled
+ local lastmatch=nil  
+ local keepmatch=nil  
+ if directives then
+  directives.register("xml.path.keeplastmatch",function(v)
+   keepmatch=v
+   lastmatch=nil
+  end)
+ end
+ apply_axis["last-match"]=function()
+  return lastmatch or {}
+ end
+ local function profiled_apply(list,parsed,nofparsed,order)
+  local p=profiled[parsed.pattern]
+  if p then
+   p.tested=p.tested+1
+  else
+   p={ tested=1,matched=0,finalized=0 }
+   profiled[parsed.pattern]=p
+  end
+  local collected=list
+  for i=1,nofparsed do
+   local pi=parsed[i]
+   local kind=pi.kind
+   if kind=="axis" then
+    collected=apply_axis[pi.axis](collected)
+   elseif kind=="nodes" then
+    collected=apply_nodes(collected,pi.nodetest,pi.nodes)
+   elseif kind=="expression" then
+    collected=apply_expression(collected,pi.evaluator,order)
+   elseif kind=="selector" then
+    collected=apply_selector(collected,pi.specification)
+   elseif kind=="finalizer" then
+    collected=pi.finalizer(collected) 
+    p.matched=p.matched+1
+    p.finalized=p.finalized+1
+    return collected
+   end
+   if not collected or #collected==0 then
+    local pn=i<nofparsed and parsed[nofparsed]
+    if pn and pn.kind=="finalizer" then
+     collected=pn.finalizer(collected) 
+     p.finalized=p.finalized+1
+     return collected
+    end
+    return nil
+   end
+  end
+  if collected then
+   p.matched=p.matched+1
+  end
+  return collected
+ end
+ local function traced_apply(list,parsed,nofparsed,order)
+  if trace_lparse then
+   lshow(parsed)
+  end
+  report_lpath("collecting: %s",parsed.pattern)
+  report_lpath("root tags : %s",tagstostring(list))
+  report_lpath("order     : %s",order or "unset")
+  local collected=list
+  for i=1,nofparsed do
+   local pi=parsed[i]
+   local kind=pi.kind
+   if kind=="axis" then
+    collected=apply_axis[pi.axis](collected)
+    report_lpath("% 10i : ax : %s",(collected and #collected) or 0,pi.axis)
+   elseif kind=="nodes" then
+    collected=apply_nodes(collected,pi.nodetest,pi.nodes)
+    report_lpath("% 10i : ns : %s",(collected and #collected) or 0,nodesettostring(pi.nodes,pi.nodetest))
+   elseif kind=="expression" then
+    collected=apply_expression(collected,pi.evaluator,order)
+    report_lpath("% 10i : ex : %s -> %s",(collected and #collected) or 0,pi.expression,pi.converted)
+   elseif kind=="selector" then
+    collected=apply_selector(collected,pi.specification)
+    report_lpath("% 10i : se : %s ",(collected and #collected) or 0,pi.specification)
+   elseif kind=="finalizer" then
+    collected=pi.finalizer(collected)
+    report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pi.name,pi.arguments or "")
+    return collected
+   end
+   if not collected or #collected==0 then
+    local pn=i<nofparsed and parsed[nofparsed]
+    if pn and pn.kind=="finalizer" then
+     collected=pn.finalizer(collected)
+     report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pn.name,pn.arguments or "")
+     return collected
+    end
+    return nil
+   end
+  end
+  return collected
+ end
+ local function normal_apply(list,parsed,nofparsed,order)
+  local collected=list
+  for i=1,nofparsed do
+   local pi=parsed[i]
+   local kind=pi.kind
+   if kind=="axis" then
+    local axis=pi.axis
+    if axis~="self" then
+     collected=apply_axis[axis](collected)
+    end
+   elseif kind=="nodes" then
+    collected=apply_nodes(collected,pi.nodetest,pi.nodes)
+   elseif kind=="expression" then
+    collected=apply_expression(collected,pi.evaluator,order)
+   elseif kind=="selector" then
+    collected=apply_selector(collected,pi.specification)
+   elseif kind=="finalizer" then
+    return pi.finalizer(collected)
+   end
+   if not collected or #collected==0 then
+    local pf=i<nofparsed and parsed[nofparsed].finalizer
+    if pf then
+     return pf(collected) 
+    end
+    return nil
+   end
+  end
+  return collected
+ end
+ local apply=normal_apply
+ if trackers then
+  trackers.register("xml.path,xml.parse,xml.profile",function()
+   if trace_lprofile then
+    apply=profiled_apply
+   elseif trace_lpath then
+    apply=traced_apply
+   else
+    apply=normal_apply
+   end
+  end)
+ end
+ function xml.applylpath(list,pattern)
+  if not list then
+   lastmatch=nil
+   return
+  end
+  local parsed=cache[pattern]
+  if parsed then
+   lpathcalls=lpathcalls+1
+   lpathcached=lpathcached+1
+  elseif type(pattern)=="table" then
+   lpathcalls=lpathcalls+1
+   parsed=pattern
+  else
+   parsed=lpath(pattern) or pattern
+  end
+  if not parsed then
+   lastmatch=nil
+   return
+  end
+  local nofparsed=#parsed
+  if nofparsed==0 then
+   lastmatch=nil
+   return 
+  end
+  local collected=apply({ list },parsed,nofparsed,list.mi)
+  lastmatch=keepmatch and collected or nil
+  return collected
+ end
+ function xml.lastmatch()
+  return lastmatch
+ end
+ local stack={}
+ function xml.pushmatch()
+  insert(stack,lastmatch)
+ end
+ function xml.popmatch()
+  lastmatch=remove(stack)
+ end
+end
+local applylpath=xml.applylpath
+function xml.filter(root,pattern) 
+ return applylpath(root,pattern)
+end
+expressions.child=function(e,pattern)
+ return applylpath(e,pattern) 
+end
+expressions.count=function(e,pattern) 
+ local collected=applylpath(e,pattern) 
+ return pattern and (collected and #collected) or 0
+end
+expressions.attribute=function(e,name,value)
+ if type(e)=="table" and name then
+  local a=e.at
+  if a then
+   local v=a[name]
+   if value then
+    return v==value
+   else
+    return v
+   end
+  end
+ end
+ return nil
+end
+expressions.oneof=function(s,...)
+ for i=1,select("#",...) do
+  if s==select(i,...) then
+   return true
+  end
+ end
+ return false
+end
+expressions.error=function(str)
+ xml.errorhandler(format("unknown function in lpath expression: %s",tostring(str or "?")))
+ return false
+end
+expressions.undefined=function(s)
+ return s==nil
+end
+expressions.quit=function(s)
+ if s or s==nil then
+  quit_expression=true
+ end
+ return true
+end
+expressions.print=function(...)
+ print(...)
+ return true
+end
+expressions.find=find
+expressions.upper=upper
+expressions.lower=lower
+expressions.number=tonumber
+expressions.boolean=toboolean
+function expressions.contains(str,pattern)
+ local t=type(str)
+ if t=="string" then
+  if find(str,pattern) then
+   return true
+  end
+ elseif t=="table" then
+  for i=1,#str do
+   local d=str[i]
+   if type(d)=="string" and find(d,pattern) then
+    return true
+   end
+  end
+ end
+ return false
+end
+function expressions.idstring(str)
+ return type(str)=="string" and gsub(str,"^#","") or ""
+end
+local function traverse(root,pattern,handle)
+ local collected=applylpath(root,pattern)
+ if collected then
+  for c=1,#collected do
+   local e=collected[c]
+   local r=e.__p__
+   handle(r,r.dt,e.ni)
+  end
+ end
+end
+local function selection(root,pattern,handle)
+ local collected=applylpath(root,pattern)
+ if collected then
+  if handle then
+   for c=1,#collected do
+    handle(collected[c])
+   end
+  else
+   return collected
+  end
+ end
+end
+xml.traverse=traverse     
+xml.selection=selection
+local function dofunction(collected,fnc,...)
+ if collected then
+  local f=functions[fnc]
+  if f then
+   for c=1,#collected do
+    f(collected[c],...)
+   end
+  else
+   report_lpath("unknown function %a",fnc)
+  end
+ end
+end
+finalizers.xml["function"]=dofunction
+finalizers.tex["function"]=dofunction
+expressions.text=function(e,n)
+ local rdt=e.__p__.dt
+ return rdt and rdt[n] or ""
+end
+expressions.name=function(e,n) 
+ local found=false
+ n=tonumber(n) or 0
+ if n==0 then
+  found=type(e)=="table" and e
+ elseif n<0 then
+  local d=e.__p__.dt
+  local k=e.ni
+  for i=k-1,1,-1 do
+   local di=d[i]
+   if type(di)=="table" then
+    if n==-1 then
+     found=di
+     break
+    else
+     n=n+1
+    end
+   end
+  end
+ else
+  local d=e.__p__.dt
+  local k=e.ni
+  for i=k+1,#d,1 do
+   local di=d[i]
+   if type(di)=="table" then
+    if n==1 then
+     found=di
+     break
+    else
+     n=n-1
+    end
+   end
+  end
+ end
+ if found then
+  local ns=found.rn or found.ns or ""
+  local tg=found.tg
+  if ns~="" then
+   return ns..":"..tg
+  else
+   return tg
+  end
+ else
+  return ""
+ end
+end
+expressions.tag=function(e,n) 
+ if not e then
+  return ""
+ else
+  local found=false
+  n=tonumber(n) or 0
+  if n==0 then
+   found=(type(e)=="table") and e 
+  elseif n<0 then
+   local d=e.__p__.dt
+   local k=e.ni
+   for i=k-1,1,-1 do
+    local di=d[i]
+    if type(di)=="table" then
+     if n==-1 then
+      found=di
+      break
+     else
+      n=n+1
+     end
+    end
+   end
+  else
+   local d=e.__p__.dt
+   local k=e.ni
+   for i=k+1,#d,1 do
+    local di=d[i]
+    if type(di)=="table" then
+     if n==1 then
+      found=di
+      break
+     else
+      n=n-1
+     end
+    end
+   end
+  end
+  return (found and found.tg) or ""
+ end
+end
+local dummy=function() end
+function xml.elements(root,pattern,reverse) 
+ local collected=applylpath(root,pattern)
+ if not collected then
+  return dummy
+ end
+ local n=#collected
+ if n==0 then
+  return dummy
+ end
+ if reverse then
+  local c=n+1
+  return function()
+   if c>1 then
+    c=c-1
+    local e=collected[c]
+    local r=e.__p__
+    return r,r.dt,e.ni
+   end
+  end
+ else
+  local c=0
+  return function()
+   if c<n then
+    c=c+1
+    local e=collected[c]
+    local r=e.__p__
+    return r,r.dt,e.ni
+   end
+  end
+ end
+end
+function xml.collected(root,pattern,reverse) 
+ local collected=applylpath(root,pattern)
+ if not collected then
+  return dummy
+ end
+ local n=#collected
+ if n==0 then
+  return dummy
+ end
+ if reverse then
+  local c=n+1
+  return function()
+   if c>1 then
+    c=c-1
+    return collected[c]
+   end
+  end
+ else
+  local c=0
+  return function()
+   if c<n then
+    c=c+1
+    return collected[c]
+   end
+  end
+ end
+end
+function xml.inspect(collection,pattern)
+ pattern=pattern or "."
+ for e in xml.collected(collection,pattern or ".") do
+  report_lpath("pattern: %s\n\n%s\n",pattern,xml.tostring(e))
+ end
+end
+local function split(e) 
+ local dt=e.dt
+ if dt then
+  for i=1,#dt do
+   local dti=dt[i]
+   if type(dti)=="string" then
+    dti=gsub(dti,"^[\n\r]*(.-)[\n\r]*","%1")
+    dti=gsub(dti,"[\n\r]+","\n\n")
+    dt[i]=dti
+   else
+    split(dti)
+   end
+  end
+ end
+ return e
+end
+function xml.finalizers.paragraphs(c)
+ for i=1,#c do
+  split(c[i])
+ end
+ return c
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["lxml-mis"] = package.loaded["lxml-mis"] or true
+
+-- original size: 3574, stripped down to: 1808
+
+if not modules then modules={} end modules ['lxml-mis']={
+ version=1.001,
+ comment="this module is the basis for the lxml-* ones",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local xml,lpeg,string=xml,lpeg,string
+local type=type
+local concat=table.concat
+local format,gsub,match=string.format,string.gsub,string.match
+local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns
+local P,S,R,C,V,Cc,Cs=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.V,lpeg.Cc,lpeg.Cs
+lpegpatterns.xml=lpegpatterns.xml or {}
+local xmlpatterns=lpegpatterns.xml
+local function xmlgsub(t,old,new) 
+ local dt=t.dt
+ if dt then
+  for k=1,#dt do
+   local v=dt[k]
+   if type(v)=="string" then
+    dt[k]=gsub(v,old,new)
+   else
+    xmlgsub(v,old,new)
+   end
+  end
+ end
+end
+function xml.stripleadingspaces(dk,d,k) 
+ if d and k then
+  local dkm=d[k-1]
+  if dkm and type(dkm)=="string" then
+   local s=match(dkm,"\n(%s+)")
+   xmlgsub(dk,"\n"..rep(" ",#s),"\n")
+  end
+ end
+end
+local normal=(1-S("<&>"))^0
+local special=P("<")/"<"+P(">")/">"+P("&")/"&"
+local escaped=Cs(normal*(special*normal)^0)
+local normal=(1-S"&")^0
+local special=P("<")/"<"+P(">")/">"+P("&")/"&"
+local unescaped=Cs(normal*(special*normal)^0)
+local cleansed=Cs(((P("<")*(1-P(">"))^0*P(">"))/""+1)^0)
+xmlpatterns.escaped=escaped
+xmlpatterns.unescaped=unescaped
+xmlpatterns.cleansed=cleansed
+function xml.escaped  (str) return lpegmatch(escaped,str)   end
+function xml.unescaped(str) return lpegmatch(unescaped,str) end
+function xml.cleansed (str) return lpegmatch(cleansed,str)  end
+function xml.fillin(root,pattern,str,check)
+ local e=xml.first(root,pattern)
+ if e then
+  local n=#e.dt
+  if not check or n==0 or (n==1 and e.dt[1]=="") then
+   e.dt={ str }
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["lxml-aux"] = package.loaded["lxml-aux"] or true
+
+-- original size: 34661, stripped down to: 21511
+
+if not modules then modules={} end modules ['lxml-aux']={
+ version=1.001,
+ comment="this module is the basis for the lxml-* ones",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local trace_manipulations=false  trackers.register("lxml.manipulations",function(v) trace_manipulations=v end)
+local trace_inclusions=false  trackers.register("lxml.inclusions",function(v) trace_inclusions=v end)
+local report_xml=logs.reporter("xml")
+local xml=xml
+local xmlcopy,xmlname=xml.copy,xml.name
+local xmlinheritedconvert=xml.inheritedconvert
+local xmlapplylpath=xml.applylpath
+local type,next,setmetatable,getmetatable=type,next,setmetatable,getmetatable
+local insert,remove,fastcopy,concat=table.insert,table.remove,table.fastcopy,table.concat
+local gmatch,gsub,format,find,strip,match=string.gmatch,string.gsub,string.format,string.find,string.strip,string.match
+local utfbyte=utf.byte
+local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns
+local striplinepatterns=utilities.strings.striplinepatterns
+local function report(what,pattern,c,e)
+ report_xml("%s element %a, root %a, position %a, index %a, pattern %a",what,xmlname(e),xmlname(e.__p__),c,e.ni,pattern)
+end
+local function withelements(e,handle,depth)
+ if e and handle then
+  local edt=e.dt
+  if edt then
+   depth=depth or 0
+   for i=1,#edt do
+    local e=edt[i]
+    if type(e)=="table" then
+     handle(e,depth)
+     withelements(e,handle,depth+1)
+    end
+   end
+  end
+ end
+end
+xml.withelements=withelements
+function xml.withelement(e,n,handle) 
+ if e and n~=0 and handle then
+  local edt=e.dt
+  if edt then
+   if n>0 then
+    for i=1,#edt do
+     local ei=edt[i]
+     if type(ei)=="table" then
+      if n==1 then
+       handle(ei)
+       return
+      else
+       n=n-1
+      end
+     end
+    end
+   elseif n<0 then
+    for i=#edt,1,-1 do
+     local ei=edt[i]
+     if type(ei)=="table" then
+      if n==-1 then
+       handle(ei)
+       return
+      else
+       n=n+1
+      end
+     end
+    end
+   end
+  end
+ end
+end
+function xml.each(root,pattern,handle,reverse)
+ local collected=xmlapplylpath(root,pattern)
+ if collected then
+  if handle then
+   if reverse then
+    for c=#collected,1,-1 do
+     handle(collected[c])
+    end
+   else
+    for c=1,#collected do
+     handle(collected[c])
+    end
+   end
+  end
+  return collected
+ end
+end
+function xml.processattributes(root,pattern,handle)
+ local collected=xmlapplylpath(root,pattern)
+ if collected and handle then
+  for c=1,#collected do
+   handle(collected[c].at)
+  end
+ end
+ return collected
+end
+function xml.collect(root,pattern)
+ return xmlapplylpath(root,pattern)
+end
+function xml.collecttexts(root,pattern,flatten) 
+ local collected=xmlapplylpath(root,pattern)
+ if collected and flatten then
+  local xmltostring=xml.tostring
+  for c=1,#collected do
+   collected[c]=xmltostring(collected[c].dt)
+  end
+ end
+ return collected or {}
+end
+function xml.collect_tags(root,pattern,nonamespace)
+ local collected=xmlapplylpath(root,pattern)
+ if collected then
+  local t={}
+  local n=0
+  for c=1,#collected do
+   local e=collected[c]
+   local ns=e.ns
+   local tg=e.tg
+   n=n+1
+   if nonamespace then
+    t[n]=tg
+   elseif ns=="" then
+    t[n]=tg
+   else
+    t[n]=ns..":"..tg
+   end
+  end
+  return t
+ end
+end
+local no_root={ no_root=true }
+local function redo_ni(d)
+ for k=1,#d do
+  local dk=d[k]
+  if type(dk)=="table" then
+   dk.ni=k
+  end
+ end
+end
+xml.reindex=redo_ni
+local function xmltoelement(whatever,root)
+ if not whatever then
+  return nil
+ end
+ local element
+ if type(whatever)=="string" then
+  element=xmlinheritedconvert(whatever,root,true) 
+ else
+  element=whatever 
+ end
+ if element.error then
+  return whatever 
+ end
+ if element then
+ end
+ return element
+end
+xml.toelement=xmltoelement
+local function copiedelement(element,newparent)
+ if type(element)~="string" then
+  element=xmlcopy(element).dt
+  if newparent and type(element)=="table" then
+   for i=1,#element do
+    local e=element[i]
+    if type(e)=="table" then
+     e.__p__=newparent
+    end
+   end
+  end
+ end
+ return element
+end
+function xml.delete(root,pattern)
+ if not pattern or pattern=="" then
+  local p=root.__p__
+  if p then
+   if trace_manipulations then
+    report('deleting',"--",c,root)
+   end
+   local d=p.dt
+   remove(d,root.ni)
+   redo_ni(d) 
+  end
+ else
+  local collected=xmlapplylpath(root,pattern)
+  if collected then
+   for c=1,#collected do
+    local e=collected[c]
+    local p=e.__p__
+    if p then
+     if trace_manipulations then
+      report('deleting',pattern,c,e)
+     end
+     local d=p.dt
+     local ni=e.ni
+     if ni<=#d then
+      if false then
+       p.dt[ni]=""
+      else
+       remove(d,ni)
+       redo_ni(d) 
+      end
+     else
+     end
+    end
+   end
+  end
+ end
+end
+function xml.wipe(root,pattern) 
+ local collected=xmlapplylpath(root,pattern)
+ if collected then
+  for c=1,#collected do
+   local e=collected[c]
+   local p=e.__p__
+   if p then
+    local d=p.dt
+    local ni=e.ni
+    if ni<=#d then
+     local dt=e.dt
+     if #dt==1 then
+      local d1=dt[1]
+      if type(d1)=="string" and match(d1,"^%s*$") then
+       if trace_manipulations then
+        report('wiping',pattern,c,e)
+       end
+       remove(d,ni)
+       redo_ni(d) 
+      end
+     end
+    end
+   end
+  end
+ end
+end
+function xml.replace(root,pattern,whatever)
+ local element=root and xmltoelement(whatever,root)
+ local collected=element and xmlapplylpath(root,pattern)
+ if collected then
+  for c=1,#collected do
+   local e=collected[c]
+   local p=e.__p__
+   if p then
+    if trace_manipulations then
+     report('replacing',pattern,c,e)
+    end
+    local d=p.dt
+    local n=e.ni
+    local t=copiedelement(element,p)
+    if type(t)=="table" then
+     d[n]=t[1]
+     for i=2,#t do
+      n=n+1
+      insert(d,n,t[i])
+     end
+    else
+     d[n]=t
+    end
+    redo_ni(d) 
+   end
+  end
+ end
+end
+function xml.expand(root,pattern,whatever)
+ local collected=root and xmlapplylpath(root,pattern)
+ if collected then
+  for c=1,#collected do
+   local e=collected[c]
+   local p=e.__p__
+   if p then
+    if trace_manipulations then
+     report('expanding',pattern,c,e)
+    end
+    local d=p.dt
+    local n=e.ni
+    local t=whatever(e,p)
+    if t then
+     if type(t)=="table" then
+      t=xmlcopy(t)
+      d[n]=t[1]
+      for i=2,#t do
+       n=n+1
+       insert(d,n,t[i])
+      end
+     else
+      d[n]=t
+     end
+     redo_ni(d) 
+    end
+   end
+  end
+ end
+end
+local function wrap(e,wrapper)
+ local t={
+  rn=e.rn,
+  tg=e.tg,
+  ns=e.ns,
+  at=e.at,
+  dt=e.dt,
+  __p__=e,
+ }
+ setmetatable(t,getmetatable(e))
+ e.rn=wrapper.rn or e.rn or ""
+ e.tg=wrapper.tg or e.tg or ""
+ e.ns=wrapper.ns or e.ns or ""
+ e.at=fastcopy(wrapper.at)
+ e.dt={ t }
+end
+function xml.wrap(root,pattern,whatever)
+ if whatever then
+  local wrapper=xmltoelement(whatever,root)
+  local collected=xmlapplylpath(root,pattern)
+  if collected then
+   for c=1,#collected do
+    local e=collected[c]
+    if trace_manipulations then
+     report('wrapping',pattern,c,e)
+    end
+    wrap(e,wrapper)
+   end
+  end
+ else
+  wrap(root,xmltoelement(pattern))
+ end
+end
+local function inject_element(root,pattern,whatever,prepend)
+ local element=root and xmltoelement(whatever,root)
+ local collected=element and xmlapplylpath(root,pattern)
+ local function inject_e(e)
+  local r=e.__p__
+  local d=r.dt
+  local k=e.ni
+  local rri=r.ri
+  local edt=(rri and d[rri].dt) or (d and d[k] and d[k].dt)
+  if edt then
+   local be,af
+   local cp=copiedelement(element,e)
+   if prepend then
+    be,af=cp,edt
+   else
+    be,af=edt,cp
+   end
+   local bn=#be
+   for i=1,#af do
+    bn=bn+1
+    be[bn]=af[i]
+   end
+   if rri then
+    r.dt[rri].dt=be
+   else
+    d[k].dt=be
+   end
+   redo_ni(d)
+  end
+ end
+ if not collected then
+ elseif collected.tg then
+  inject_e(collected)
+ else
+  for c=1,#collected do
+   inject_e(collected[c])
+  end
+ end
+end
+local function insert_element(root,pattern,whatever,before) 
+ local element=root and xmltoelement(whatever,root)
+ local collected=element and xmlapplylpath(root,pattern)
+ local function insert_e(e)
+  local r=e.__p__
+  local d=r.dt
+  local k=e.ni
+  if not before then
+   k=k+1
+  end
+  insert(d,k,copiedelement(element,r))
+  redo_ni(d)
+ end
+ if not collected then
+ elseif collected.tg then
+  insert_e(collected)
+ else
+  for c=1,#collected do
+   insert_e(collected[c])
+  end
+ end
+end
+xml.insert_element=insert_element
+xml.insertafter=insert_element
+xml.insertbefore=function(r,p,e) insert_element(r,p,e,true) end
+xml.injectafter=inject_element
+xml.injectbefore=function(r,p,e) inject_element(r,p,e,true) end
+local function include(xmldata,pattern,attribute,recursive,loaddata,level)
+ pattern=pattern or 'include'
+ loaddata=loaddata or io.loaddata
+ local collected=xmlapplylpath(xmldata,pattern)
+ if collected then
+  if not level then
+   level=1
+  end
+  for c=1,#collected do
+   local ek=collected[c]
+   local name=nil
+   local ekdt=ek.dt
+   if ekdt then
+    local ekat=ek.at
+    local ekrt=ek.__p__
+    if ekrt then
+     local epdt=ekrt.dt
+     if not attribute or attribute=="" then
+      name=(type(ekdt)=="table" and ekdt[1]) or ekdt 
+     end
+     if not name then
+      for a in gmatch(attribute or "href","([^|]+)") do
+       name=ekat[a]
+       if name then
+        break
+       end
+      end
+     end
+     local data=nil
+     if name and name~="" then
+      local d,n=loaddata(name)
+      data=d or ""
+      name=n or name
+      if trace_inclusions then
+       report_xml("including %s bytes from %a at level %s by pattern %a and attribute %a (%srecursing)",#data,name,level,pattern,attribute or "",recursive and "" or "not ")
+      end
+     end
+     if not data or data=="" then
+      epdt[ek.ni]="" 
+     elseif ekat["parse"]=="text" then
+      epdt[ek.ni]=xml.escaped(data) 
+     else
+      local settings=xmldata.settings
+      local savedresource=settings.currentresource
+      settings.currentresource=name
+      local xi=xmlinheritedconvert(data,xmldata,true)
+      if not xi then
+       epdt[ek.ni]="" 
+      else
+       if recursive then
+        include(xi,pattern,attribute,recursive,loaddata,level+1)
+       end
+       local child=xml.body(xi) 
+       child.__p__=ekrt
+       child.__f__=name 
+       child.cf=name
+       epdt[ek.ni]=child
+       local settings=xmldata.settings
+       local inclusions=settings and settings.inclusions
+       if inclusions then
+        inclusions[#inclusions+1]=name
+       elseif settings then
+        settings.inclusions={ name }
+       else
+        settings={ inclusions={ name } }
+        xmldata.settings=settings
+       end
+       if child.er then
+        local badinclusions=settings.badinclusions
+        if badinclusions then
+         badinclusions[#badinclusions+1]=name
+        else
+         settings.badinclusions={ name }
+        end
+       end
+      end
+settings.currentresource=savedresource
+     end
+    end
+   end
+  end
+ end
+end
+xml.include=include
+function xml.inclusion(e,default)
+ while e do
+  local f=e.__f__
+  if f then
+   return f
+  else
+   e=e.__p__
+  end
+ end
+ return default
+end
+local function getinclusions(key,e,sorted)
+ while e do
+  local settings=e.settings
+  if settings then
+   local inclusions=settings[key]
+   if inclusions then
+    inclusions=table.unique(inclusions) 
+    if sorted then
+     table.sort(inclusions) 
+    end
+    return inclusions 
+   else
+    e=e.__p__
+   end
+  else
+   e=e.__p__
+  end
+ end
+end
+function xml.inclusions(e,sorted)
+ return getinclusions("inclusions",e,sorted)
+end
+function xml.badinclusions(e,sorted)
+ return getinclusions("badinclusions",e,sorted)
+end
+local b_collapser=lpegpatterns.b_collapser
+local m_collapser=lpegpatterns.m_collapser
+local e_collapser=lpegpatterns.e_collapser
+local x_collapser=lpegpatterns.x_collapser
+local b_stripper=lpegpatterns.b_stripper
+local m_stripper=lpegpatterns.m_stripper
+local e_stripper=lpegpatterns.e_stripper
+local x_stripper=lpegpatterns.x_stripper
+local function stripelement(e,nolines,anywhere,everything)
+ local edt=e.dt
+ if edt then
+  local n=#edt
+  if n==0 then
+   return e 
+  elseif everything then
+   local t={}
+   local m=0
+   for i=1,n do
+    local str=edt[i]
+    if type(str)~="string" then
+     m=m+1
+     t[m]=str
+    elseif str~="" then
+     str=lpegmatch(x_collapser,str)
+     if str~="" then
+      m=m+1
+      t[m]=str
+     end
+    end
+   end
+   e.dt=t
+  elseif anywhere then
+   local t={}
+   local m=0
+   for i=1,n do
+    local str=edt[i]
+    if type(str)~="string" then
+     m=m+1
+     t[m]=str
+    elseif str~="" then
+     if nolines then
+      str=lpegmatch((i==1 and b_collapser) or (i==m and e_collapser) or m_collapser,str)
+     else
+      str=lpegmatch((i==1 and b_stripper) or (i==m and e_stripper) or m_stripper,str)
+     end
+     if str~="" then
+      m=m+1
+      t[m]=str
+     end
+    end
+   end
+   e.dt=t
+  else
+   local str=edt[1]
+   if type(str)=="string" then
+    if str~="" then
+     str=lpegmatch(nolines and b_collapser or b_stripper,str)
+    end
+    if str=="" then
+     remove(edt,1)
+     n=n-1
+    else
+     edt[1]=str
+    end
+   end
+   if n>0 then
+    str=edt[n]
+    if type(str)=="string" then
+     if str=="" then
+      remove(edt)
+     else
+      str=lpegmatch(nolines and e_collapser or e_stripper,str)
+      if str=="" then
+       remove(edt)
+      else
+       edt[n]=str
+      end
+     end
+    end
+   end
+  end
+ end
+ return e 
+end
+xml.stripelement=stripelement
+function xml.strip(root,pattern,nolines,anywhere,everything) 
+ local collected=xmlapplylpath(root,pattern) 
+ if collected then
+  for i=1,#collected do
+   stripelement(collected[i],nolines,anywhere,everything)
+  end
+ end
+end
+local function compactelement(e)
+ local edt=e.dt
+ if edt then
+  for e=1,#edt do
+   local str=edt[e]
+   if type(str)=="string" and not find(str,"%S") then
+    edt[e]=""
+   end
+  end
+ end
+ return e 
+end
+xml.compactelement=compactelement
+local function renamespace(root,oldspace,newspace) 
+ local ndt=#root.dt
+ for i=1,ndt or 0 do
+  local e=root[i]
+  if type(e)=="table" then
+   if e.ns==oldspace then
+    e.ns=newspace
+    if e.rn then
+     e.rn=newspace
+    end
+   end
+   local edt=e.dt
+   if edt then
+    renamespace(edt,oldspace,newspace)
+   end
+  end
+ end
+end
+xml.renamespace=renamespace
+function xml.remaptag(root,pattern,newtg)
+ local collected=xmlapplylpath(root,pattern)
+ if collected then
+  for c=1,#collected do
+   collected[c].tg=newtg
+  end
+ end
+end
+function xml.remapnamespace(root,pattern,newns)
+ local collected=xmlapplylpath(root,pattern)
+ if collected then
+  for c=1,#collected do
+   collected[c].ns=newns
+  end
+ end
+end
+function xml.checknamespace(root,pattern,newns)
+ local collected=xmlapplylpath(root,pattern)
+ if collected then
+  for c=1,#collected do
+   local e=collected[c]
+   if (not e.rn or e.rn=="") and e.ns=="" then
+    e.rn=newns
+   end
+  end
+ end
+end
+function xml.remapname(root,pattern,newtg,newns,newrn)
+ local collected=xmlapplylpath(root,pattern)
+ if collected then
+  for c=1,#collected do
+   local e=collected[c]
+   e.tg,e.ns,e.rn=newtg,newns,newrn
+  end
+ end
+end
+function xml.cdatatotext(e)
+ local dt=e.dt
+ if #dt==1 then
+  local first=dt[1]
+  if first.tg=="@cd@" then
+   e.dt=first.dt
+  end
+ else
+ end
+end
+function xml.texttocdata(e) 
+ local dt=e.dt
+ local s=xml.tostring(dt) 
+ e.tg="@cd@"
+ e.special=true
+ e.ns=""
+ e.rn=""
+ e.dt={ s }
+ e.at=nil
+end
+function xml.elementtocdata(e) 
+ local dt=e.dt
+ local s=xml.tostring(e) 
+ e.tg="@cd@"
+ e.special=true
+ e.ns=""
+ e.rn=""
+ e.dt={ s }
+ e.at=nil
+end
+xml.builtinentities=table.tohash { "amp","quot","apos","lt","gt" } 
+local entities=characters and characters.entities or nil
+local builtinentities=xml.builtinentities
+function xml.addentitiesdoctype(root,option) 
+ if not entities then
+  require("char-ent")
+  entities=characters.entities
+ end
+ if entities and root and root.tg=="@rt@" and root.statistics then
+  local list={}
+  local hexify=option=="hexadecimal"
+  for k,v in table.sortedhash(root.statistics.entities.names) do
+   if not builtinentities[k] then
+    local e=entities[k]
+    if not e then
+     e=format("[%s]",k)
+    elseif hexify then
+     e=format("&#%05X;",utfbyte(k))
+    end
+    list[#list+1]=format("  <!ENTITY %s %q >",k,e)
+   end
+  end
+  local dt=root.dt
+  local n=dt[1].tg=="@pi@" and 2 or 1
+  if #list>0 then
+   insert(dt,n,{ "\n" })
+   insert(dt,n,{
+      tg="@dt@",
+      dt={ format("Something [\n%s\n] ",concat(list)) },
+      ns="",
+      special=true,
+   })
+   insert(dt,n,{ "\n\n" })
+  else
+  end
+ end
+end
+xml.all=xml.each
+xml.insert=xml.insertafter
+xml.inject=xml.injectafter
+xml.after=xml.insertafter
+xml.before=xml.insertbefore
+xml.process=xml.each
+xml.obsolete=xml.obsolete or {}
+local obsolete=xml.obsolete
+xml.strip_whitespace=xml.strip     obsolete.strip_whitespace=xml.strip
+xml.collect_elements=xml.collect      obsolete.collect_elements=xml.collect
+xml.delete_element=xml.delete    obsolete.delete_element=xml.delete
+xml.replace_element=xml.replace      obsolete.replace_element=xml.replace
+xml.each_element=xml.each      obsolete.each_element=xml.each
+xml.process_elements=xml.process      obsolete.process_elements=xml.process
+xml.insert_element_after=xml.insertafter     obsolete.insert_element_after=xml.insertafter
+xml.insert_element_before=xml.insertbefore    obsolete.insert_element_before=xml.insertbefore
+xml.inject_element_after=xml.injectafter     obsolete.inject_element_after=xml.injectafter
+xml.inject_element_before=xml.injectbefore    obsolete.inject_element_before=xml.injectbefore
+xml.process_attributes=xml.processattributes  obsolete.process_attributes=xml.processattributes
+xml.collect_texts=xml.collecttexts    obsolete.collect_texts=xml.collecttexts
+xml.inject_element=xml.inject    obsolete.inject_element=xml.inject
+xml.remap_tag=xml.remaptag     obsolete.remap_tag=xml.remaptag
+xml.remap_name=xml.remapname    obsolete.remap_name=xml.remapname
+xml.remap_namespace=xml.remapnamespace  obsolete.remap_namespace=xml.remapnamespace
+function xml.cdata(e)
+ if e then
+  local dt=e.dt
+  if dt and #dt==1 then
+   local first=dt[1]
+   return first.tg=="@cd@" and first.dt[1] or ""
+  end
+ end
+ return ""
+end
+function xml.finalizers.xml.cdata(collected)
+ if collected then
+  local e=collected[1]
+  if e then
+   local dt=e.dt
+   if dt and #dt==1 then
+    local first=dt[1]
+    return first.tg=="@cd@" and first.dt[1] or ""
+   end
+  end
+ end
+ return ""
+end
+function xml.insertcomment(e,str,n)
+ insert(e.dt,n or 1,{
+  tg="@cm@",
+  ns="",
+  special=true,
+  at={},
+  dt={ str },
+ })
+end
+function xml.insertcdata(e,str,n)
+ insert(e.dt,n or 1,{
+  tg="@cd@",
+  ns="",
+  special=true,
+  at={},
+  dt={ str },
+ })
+end
+function xml.setcomment(e,str,n)
+ e.dt={ {
+  tg="@cm@",
+  ns="",
+  special=true,
+  at={},
+  dt={ str },
+ } }
+end
+function xml.setcdata(e,str)
+ e.dt={ {
+  tg="@cd@",
+  ns="",
+  special=true,
+  at={},
+  dt={ str },
+ } }
+end
+function xml.separate(x,pattern)
+ local collected=xmlapplylpath(x,pattern)
+ if collected then
+  for c=1,#collected do
+   local e=collected[c]
+   local d=e.dt
+   if d==x then
+    report_xml("warning: xml.separate changes root")
+    x=d
+   end
+   local t={ "\n" }
+   local n=1
+   local i=1
+   local nd=#d
+   while i<=nd do
+    while i<=nd do
+     local di=d[i]
+     if type(di)=="string" then
+      if di=="\n" or find(di,"^%s+$") then 
+       i=i+1
+      else
+       d[i]=strip(di)
+       break
+      end
+     else
+      break
+     end
+    end
+    if i>nd then
+     break
+    end
+    t[n+1]="\n"
+    t[n+2]=d[i]
+    t[n+3]="\n"
+    n=n+3
+    i=i+1
+   end
+   t[n+1]="\n"
+   setmetatable(t,getmetatable(d))
+   e.dt=t
+  end
+ end
+ return x
+end
+local helpers=xml.helpers or {}
+xml.helpers=helpers
+local function normal(e,action)
+ local edt=e.dt
+ if edt then
+  for i=1,#edt do
+   local str=edt[i]
+   if type(str)=="string" and str~="" then
+    edt[i]=action(str)
+   end
+  end
+ end
+end
+local function recurse(e,action)
+ local edt=e.dt
+ if edt then
+  for i=1,#edt do
+   local str=edt[i]
+   if type(str)~="string" then
+    recurse(str,action) 
+   elseif str~="" then
+    edt[i]=action(str)
+   end
+  end
+ end
+end
+function helpers.recursetext(collected,action,recursive)
+ if recursive then
+  for i=1,#collected do
+   recurse(collected[i],action)
+  end
+ else
+  for i=1,#collected do
+     normal(collected[i],action)
+  end
+ end
+end
+local specials={
+ ["@rt@"]="root",
+ ["@pi@"]="instruction",
+ ["@cm@"]="comment",
+ ["@dt@"]="declaration",
+ ["@cd@"]="cdata",
+}
+local function convert(x,strip,flat)
+ local ns=x.ns
+ local tg=x.tg
+ local at=x.at
+ local dt=x.dt
+ local node=flat and {
+  [0]=(not x.special and (ns~="" and ns..":"..tg or tg)) or nil,
+ } or {
+  _namespace=ns~="" and ns or nil,
+  _tag=not x.special and tg or nil,
+  _type=specials[tg] or "_element",
+ }
+ if at then
+  for k,v in next,at do
+   node[k]=v
+  end
+ end
+ local n=0
+ for i=1,#dt do
+  local di=dt[i]
+  if type(di)=="table" then
+   if flat and di.special then
+   else
+    di=convert(di,strip,flat)
+    if di then
+     n=n+1
+     node[n]=di
+    end
+   end
+  elseif strip then
+   di=lpegmatch(strip,di)
+   if di~="" then
+    n=n+1
+    node[n]=di
+   end
+  else
+   n=n+1
+   node[n]=di
+  end
+ end
+ if next(node) then
+  return node
+ end
+end
+function xml.totable(x,strip,flat)
+ if type(x)=="table" then
+  if strip then
+   strip=striplinepatterns[strip]
+  end
+  return convert(x,strip,flat)
+ end
+end
+function xml.rename(e,namespace,name,attributes)
+ if type(e)~="table" or not e.tg then
+  return
+ end
+ if type(name)=="table" then
+  attributes=name
+  name=namespace
+  namespace=""
+ elseif type(name)~="string" then
+  attributes={}
+  name=namespace
+  namespace=""
+ end
+ if type(attributes)~="table" then
+  attributes={}
+ end
+ e.ns=namespace
+ e.rn=namespace
+ e.tg=name
+ e.at=attributes
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["lxml-xml"] = package.loaded["lxml-xml"] or true
+
+-- original size: 11096, stripped down to: 7702
+
+if not modules then modules={} end modules ['lxml-xml']={
+ version=1.001,
+ comment="this module is the basis for the lxml-* ones",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local tonumber,next=tonumber,next
+local concat=table.concat
+local find,lower,upper=string.find,string.lower,string.upper
+local xml=xml
+local finalizers=xml.finalizers.xml
+local xmlfilter=xml.filter 
+local xmltostring=xml.tostring
+local xmlserialize=xml.serialize
+local xmlcollected=xml.collected
+local xmlnewhandlers=xml.newhandlers
+local reparsedentity=xml.reparsedentitylpeg   
+local unescapedentity=xml.unescapedentitylpeg
+local parsedentity=reparsedentity
+local function first(collected) 
+ return collected and collected[1]
+end
+local function last(collected)
+ return collected and collected[#collected]
+end
+local function all(collected)
+ return collected
+end
+local reverse=table.reversed
+local function attribute(collected,name)
+ if collected and #collected>0 then
+  local at=collected[1].at
+  return at and at[name]
+ end
+end
+local function att(id,name)
+ local at=id.at
+ return at and at[name]
+end
+local function count(collected)
+ return collected and #collected or 0
+end
+local function position(collected,n)
+ if not collected then
+  return 0
+ end
+ local nc=#collected
+ if nc==0 then
+  return 0
+ end
+ n=tonumber(n) or 0
+ if n<0 then
+  return collected[nc+n+1]
+ elseif n>0 then
+  return collected[n]
+ else
+  return collected[1].mi or 0
+ end
+end
+local function match(collected)
+ return collected and #collected>0 and collected[1].mi or 0 
+end
+local function index(collected)
+ return collected and #collected>0 and collected[1].ni or 0 
+end
+local function attributes(collected,arguments)
+ if collected and #collected>0 then
+  local at=collected[1].at
+  if arguments then
+   return at[arguments]
+  elseif next(at) then
+   return at 
+  end
+ end
+end
+local function chainattribute(collected,arguments) 
+ if collected and #collected>0 then
+  local e=collected[1]
+  while e do
+   local at=e.at
+   if at then
+    local a=at[arguments]
+    if a then
+     return a
+    end
+   else
+    break 
+   end
+   e=e.__p__
+  end
+ end
+ return ""
+end
+local function raw(collected) 
+ if collected and #collected>0 then
+  local e=collected[1] or collected
+  return e and xmltostring(e) or "" 
+ else
+  return ""
+ end
+end
+local xmltexthandler=xmlnewhandlers {
+ name="string",
+ initialize=function()
+  result={}
+  return result
+ end,
+ finalize=function()
+  return concat(result)
+ end,
+ handle=function(...)
+  result[#result+1]=concat {... }
+ end,
+ escape=false,
+}
+local function xmltotext(root)
+ local dt=root.dt
+ if not dt then
+  return ""
+ end
+ local nt=#dt 
+ if nt==0 then
+  return ""
+ elseif nt==1 and type(dt[1])=="string" then
+  return dt[1] 
+ else
+  return xmlserialize(root,xmltexthandler) or ""
+ end
+end
+function xml.serializetotext(root)
+ return root and xmlserialize(root,xmltexthandler) or ""
+end
+local function text(collected) 
+ if collected then 
+  local e=collected[1] or collected 
+  return e and xmltotext(e) or ""
+ else
+  return ""
+ end
+end
+local function texts(collected)
+ if not collected then
+  return {} 
+ end
+ local nc=#collected
+ if nc==0 then
+  return {} 
+ end
+ local t,n={},0
+ for c=1,nc do
+  local e=collected[c]
+  if e and e.dt then
+   n=n+1
+   t[n]=e.dt
+  end
+ end
+ return t
+end
+local function tag(collected,n)
+ if not collected then
+  return
+ end
+ local nc=#collected
+ if nc==0 then
+  return
+ end
+ local c
+ if n==0 or not n then
+  c=collected[1]
+ elseif n>1 then
+  c=collected[n]
+ else
+  c=collected[nc-n+1]
+ end
+ return c and c.tg
+end
+local function name(collected,n)
+ if not collected then
+  return
+ end
+ local nc=#collected
+ if nc==0 then
+  return
+ end
+ local c
+ if n==0 or not n then
+  c=collected[1]
+ elseif n>1 then
+  c=collected[n]
+ else
+  c=collected[nc-n+1]
+ end
+ if not c then
+ elseif c.ns=="" then
+  return c.tg
+ else
+  return c.ns..":"..c.tg
+ end
+end
+local function tags(collected,nonamespace)
+ if not collected then
+  return
+ end
+ local nc=#collected
+ if nc==0 then
+  return
+ end
+ local t,n={},0
+ for c=1,nc do
+  local e=collected[c]
+  local ns,tg=e.ns,e.tg
+  n=n+1
+  if nonamespace or ns=="" then
+   t[n]=tg
+  else
+   t[n]=ns..":"..tg
+  end
+ end
+ return t
+end
+local function empty(collected,spacesonly)
+ if not collected then
+  return true
+ end
+ local nc=#collected
+ if nc==0 then
+  return true
+ end
+ for c=1,nc do
+  local e=collected[c]
+  if e then
+   local edt=e.dt
+   if edt then
+    local n=#edt
+    if n==1 then
+     local edk=edt[1]
+     local typ=type(edk)
+     if typ=="table" then
+      return false
+     elseif edk~="" then
+      return false
+     elseif spacesonly and not find(edk,"%S") then
+      return false
+     end
+    elseif n>1 then
+     return false
+    end
+   end
+  end
+ end
+ return true
+end
+finalizers.first=first
+finalizers.last=last
+finalizers.all=all
+finalizers.reverse=reverse
+finalizers.elements=all
+finalizers.default=all
+finalizers.attribute=attribute
+finalizers.att=att
+finalizers.count=count
+finalizers.position=position
+finalizers.match=match
+finalizers.index=index
+finalizers.attributes=attributes
+finalizers.chainattribute=chainattribute
+finalizers.text=text
+finalizers.texts=texts
+finalizers.tag=tag
+finalizers.name=name
+finalizers.tags=tags
+finalizers.empty=empty
+function xml.first(id,pattern)
+ return first(xmlfilter(id,pattern))
+end
+function xml.last(id,pattern)
+ return last(xmlfilter(id,pattern))
+end
+function xml.count(id,pattern)
+ return count(xmlfilter(id,pattern))
+end
+function xml.attribute(id,pattern,a,default)
+ return attribute(xmlfilter(id,pattern),a,default)
+end
+function xml.raw(id,pattern)
+ if pattern then
+  return raw(xmlfilter(id,pattern))
+ else
+  return raw(id)
+ end
+end
+function xml.text(id,pattern) 
+ if pattern then
+  local collected=xmlfilter(id,pattern)
+  return collected and #collected>0 and xmltotext(collected[1]) or ""
+ elseif id then
+  return xmltotext(id) or ""
+ else
+  return ""
+ end
+end
+function xml.pure(id,pattern)
+ if pattern then
+  local collected=xmlfilter(id,pattern)
+  if collected and #collected>0 then
+   parsedentity=unescapedentity
+   local s=collected and #collected>0 and xmltotext(collected[1]) or ""
+   parsedentity=reparsedentity
+   return s
+  else
+   return ""
+  end
+ else
+  parsedentity=unescapedentity
+  local s=xmltotext(id) or ""
+  parsedentity=reparsedentity
+  return s
+ end
+end
+xml.content=text
+function xml.position(id,pattern,n) 
+ return position(xmlfilter(id,pattern),n)
+end
+function xml.match(id,pattern) 
+ return match(xmlfilter(id,pattern))
+end
+function xml.empty(id,pattern,spacesonly)
+ return empty(xmlfilter(id,pattern),spacesonly)
+end
+xml.all=xml.filter
+xml.index=xml.position
+xml.found=xml.filter
+local function totable(x)
+ local t={}
+ for e in xmlcollected(x[1] or x,"/*") do
+  t[e.tg]=xmltostring(e.dt) or ""
+ end
+ return next(t) and t or nil
+end
+xml.table=totable
+finalizers.table=totable
+local function textonly(e,t)
+ if e then
+  local edt=e.dt
+  if edt then
+   for i=1,#edt do
+    local e=edt[i]
+    if type(e)=="table" then
+     textonly(e,t)
+    else
+     t[#t+1]=e
+    end
+   end
+  end
+ end
+ return t
+end
+function xml.textonly(e) 
+ return concat(textonly(e,{}))
+end
+function finalizers.lowerall(collected)
+ for c=1,#collected do
+  local e=collected[c]
+  if not e.special then
+   e.tg=lower(e.tg)
+   local eat=e.at
+   if eat then
+    local t={}
+    for k,v in next,eat do
+     t[lower(k)]=v
+    end
+    e.at=t
+   end
+  end
+ end
+end
+function finalizers.upperall(collected)
+ for c=1,#collected do
+  local e=collected[c]
+  if not e.special then
+   e.tg=upper(e.tg)
+   local eat=e.at
+   if eat then
+    local t={}
+    for k,v in next,eat do
+     t[upper(k)]=v
+    end
+    e.at=t
+   end
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["trac-xml"] = package.loaded["trac-xml"] or true
+
+-- original size: 6407, stripped down to: 4640
+
+if not modules then modules={} end modules ['trac-xml']={
+ version=1.001,
+ comment="companion to trac-log.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local formatters=string.formatters
+local reporters=logs.reporters
+local xmlserialize=xml.serialize
+local xmlcollected=xml.collected
+local xmltext=xml.text
+local xmlfirst=xml.first
+local function showhelp(specification,...)
+ local root=xml.convert(specification.helpinfo or "")
+ if not root then
+  return
+ end
+ local xs=xml.gethandlers("string")
+ xml.sethandlersfunction(xs,"short",function(e,handler) xmlserialize(e.dt,handler) end)
+ xml.sethandlersfunction(xs,"ref",function(e,handler) handler.handle("--"..e.at.name) end)
+ local wantedcategories=select("#",...)==0 and true or table.tohash {... }
+ local nofcategories=xml.count(root,"/application/flags/category")
+ local report=specification.report
+ for category in xmlcollected(root,"/application/flags/category") do
+  local categoryname=category.at.name or ""
+  if wantedcategories==true or wantedcategories[categoryname] then
+   if nofcategories>1 then
+    report("%s options:",categoryname)
+    report()
+   end
+   for subcategory in xmlcollected(category,"/subcategory") do
+    for flag in xmlcollected(subcategory,"/flag") do
+     local name=flag.at.name
+     local value=flag.at.value
+     local short=xmltext(xmlfirst(flag,"/short"))
+     if value then
+      report("--%-20s %s",formatters["%s=%s"](name,value),short)
+     else
+      report("--%-20s %s",name,short)
+     end
+    end
+    report()
+   end
+  end
+ end
+ for category in xmlcollected(root,"/application/examples/category") do
+  local title=xmltext(xmlfirst(category,"/title"))
+  if title and title~="" then
+   report()
+   report(title)
+   report()
+  end
+  for subcategory in xmlcollected(category,"/subcategory") do
+   for example in xmlcollected(subcategory,"/example") do
+    local command=xmltext(xmlfirst(example,"/command"))
+    local comment=xmltext(xmlfirst(example,"/comment"))
+    report(command)
+   end
+   report()
+  end
+ end
+ for comment in xmlcollected(root,"/application/comments/comment") do
+  local comment=xmltext(comment)
+  report()
+  report(comment)
+  report()
+ end
+end
+local reporthelp=reporters.help
+local exporthelp=reporters.export
+local function xmlfound(t)
+ local helpinfo=t.helpinfo
+ if type(helpinfo)=="table" then
+  return false
+ end
+ if type(helpinfo)~="string" then
+  helpinfo="Warning: no helpinfo found."
+  t.helpinfo=helpinfo
+  return false
+ end
+ if string.find(helpinfo,".xml$") then
+  local ownscript=environment.ownscript
+  local helpdata=false
+  if ownscript then
+   local helpfile=file.join(file.pathpart(ownscript),helpinfo)
+   helpdata=io.loaddata(helpfile)
+   if helpdata=="" then
+    helpdata=false
+   end
+  end
+  if not helpdata then
+   local helpfile=resolvers.findfile(helpinfo,"tex")
+   helpdata=helpfile and io.loaddata(helpfile)
+  end
+  if helpdata and helpdata~="" then
+   helpinfo=helpdata
+  else
+   helpinfo=formatters["Warning: help file %a is not found."](helpinfo)
+  end
+ end
+ t.helpinfo=helpinfo
+ return string.find(t.helpinfo,"^<%?xml") and true or false
+end
+function reporters.help(t,...)
+ if xmlfound(t) then
+  showhelp(t,...)
+ else
+  reporthelp(t,...)
+ end
+end
+function reporters.export(t,methods,filename)
+ if not xmlfound(t) then
+  return exporthelp(t)
+ end
+ if not methods or methods=="" then
+  methods=environment.arguments["exporthelp"]
+ end
+ if not filename or filename=="" then
+  filename=environment.files[1]
+ end
+ dofile(resolvers.findfile("trac-exp.lua","tex"))
+ local exporters=logs.exporters
+ if not exporters or not methods then
+  return exporthelp(t)
+ end
+ if methods=="all" then
+  methods=table.keys(exporters)
+ elseif type(methods)=="string" then
+  methods=utilities.parsers.settings_to_array(methods)
+ else
+  return exporthelp(t)
+ end
+ if type(filename)~="string" or filename=="" then
+  filename=false
+ elseif file.pathpart(filename)=="" then
+  t.report("export file %a will not be saved on the current path (safeguard)",filename)
+  return
+ end
+ for i=1,#methods do
+  local method=methods[i]
+  local exporter=exporters[method]
+  if exporter then
+   local result=exporter(t,method)
+   if result and result~="" then
+    if filename then
+     local fullname=file.replacesuffix(filename,method)
+     t.report("saving export in %a",fullname)
+     dir.mkdirs(file.pathpart(fullname))
+     io.savedata(fullname,result)
+    else
+     reporters.lines(t,result)
+    end
+   else
+    t.report("no output from exporter %a",method)
+   end
+  else
+   t.report("unknown exporter %a",method)
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-ini"] = package.loaded["data-ini"] or true
+
+-- original size: 10947, stripped down to: 7176
+
+if not modules then modules={} end modules ['data-ini']={
+ 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 next,type,getmetatable,rawset=next,type,getmetatable,rawset
+local gsub,find,gmatch,char=string.gsub,string.find,string.gmatch,string.char
+local filedirname,filebasename,filejoin=file.dirname,file.basename,file.join
+local ostype,osname,osuname,ossetenv,osgetenv=os.type,os.name,os.uname,os.setenv,os.getenv
+local sortedpairs=table.sortedpairs
+local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match
+local trace_locating=false  trackers.register("resolvers.locating",function(v) trace_locating=v end)
+local trace_expansions=false  trackers.register("resolvers.expansions",function(v) trace_expansions=v end)
+local report_initialization=logs.reporter("resolvers","initialization")
+resolvers=resolvers or {}
+local resolvers=resolvers
+texconfig.kpse_init=false
+texconfig.shell_escape='t'
+if not (environment and environment.default_texmfcnf) and kpse and kpse.default_texmfcnf then
+ local default_texmfcnf=kpse.default_texmfcnf()
+ default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOLOC","selfautoloc:")
+ default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTODIR","selfautodir:")
+ default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOPARENT","selfautoparent:")
+ default_texmfcnf=gsub(default_texmfcnf,"$HOME","home:")
+ environment.default_texmfcnf=default_texmfcnf
+end
+kpse={ original=kpse }
+setmetatable(kpse,{
+ __index=function(kp,name)
+  report_initialization("fatal error: kpse library is accessed (key: %s)",name)
+  os.exit()
+ end
+} )
+do
+ local osfontdir=osgetenv("OSFONTDIR")
+ if osfontdir and osfontdir~="" then
+ elseif osname=="windows" then
+  ossetenv("OSFONTDIR","c:/windows/fonts//")
+ elseif osname=="macosx" then
+  ossetenv("OSFONTDIR","$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//")
+ end
+end
+if not environment.homedir then
+ local oldhome=osgetenv('HOME')
+ local homedir=osgetenv(ostype=="windows" and 'USERPROFILE' or 'HOME') or ''
+ if not homedir or homedir=="" then
+  homedir=char(127) 
+ end
+ homedir=file.collapsepath(homedir)
+ ossetenv("HOME",homedir) 
+ ossetenv("USERPROFILE",homedir) 
+ environment.oldhome=oldhome
+ environment.homedir=homedir
+end
+do
+ local args=environment.originalarguments or arg 
+ if not environment.ownmain then
+  environment.ownmain=status and string.match(string.lower(status.banner),"this is ([%a]+)") or "luatex"
+ end
+ local ownbin=environment.ownbin  or args[-2] or arg[-2] or args[-1] or arg[-1] or arg[0] or "luatex"
+ local ownpath=environment.ownpath or os.selfdir
+ ownbin=file.collapsepath(ownbin)
+ ownpath=file.collapsepath(ownpath)
+ if not ownpath or ownpath=="" or ownpath=="unset" then
+  ownpath=args[-1] or arg[-1]
+  ownpath=ownpath and filedirname(gsub(ownpath,"\\","/"))
+  if not ownpath or ownpath=="" then
+   ownpath=args[-0] or arg[-0]
+   ownpath=ownpath and filedirname(gsub(ownpath,"\\","/"))
+  end
+  local binary=ownbin
+  if not ownpath or ownpath=="" then
+   ownpath=ownpath and filedirname(binary)
+  end
+  if not ownpath or ownpath=="" then
+   if os.binsuffix~="" then
+    binary=file.replacesuffix(binary,os.binsuffix)
+   end
+   local path=osgetenv("PATH")
+   if path then
+    for p in gmatch(path,"[^"..io.pathseparator.."]+") do
+     local b=filejoin(p,binary)
+     if lfs.isfile(b) then
+      local olddir=lfs.currentdir()
+      if lfs.chdir(p) then
+       local pp=lfs.currentdir()
+       if trace_locating and p~=pp then
+        report_initialization("following symlink %a to %a",p,pp)
+       end
+       ownpath=pp
+       lfs.chdir(olddir)
+      else
+       if trace_locating then
+        report_initialization("unable to check path %a",p)
+       end
+       ownpath=p
+      end
+      break
+     end
+    end
+   end
+  end
+  if not ownpath or ownpath=="" then
+   ownpath="."
+   report_initialization("forcing fallback to ownpath %a",ownpath)
+  elseif trace_locating then
+   report_initialization("using ownpath %a",ownpath)
+  end
+ end
+ environment.ownbin=ownbin
+ environment.ownpath=ownpath
+end
+resolvers.ownpath=environment.ownpath
+function resolvers.getownpath()
+ return environment.ownpath
+end
+do
+ local ownpath=environment.ownpath or dir.current()
+ if ownpath then
+  ossetenv('SELFAUTOLOC',file.collapsepath(ownpath))
+  ossetenv('SELFAUTODIR',file.collapsepath(ownpath.."/.."))
+  ossetenv('SELFAUTOPARENT',file.collapsepath(ownpath.."/../.."))
+ else
+  report_initialization("error: unable to locate ownpath")
+  os.exit()
+ end
+end
+local texos=environment.texos   or osgetenv("TEXOS")
+local texmfos=environment.texmfos or osgetenv('SELFAUTODIR')
+if not texos or texos=="" then
+ texos=file.basename(texmfos)
+end
+ossetenv('TEXMFOS',texmfos)   
+ossetenv('TEXOS',texos)  
+ossetenv('SELFAUTOSYSTEM',os.platform)  
+environment.texos=texos
+environment.texmfos=texmfos
+local texroot=environment.texroot or osgetenv("TEXROOT")
+if not texroot or texroot=="" then
+ texroot=osgetenv('SELFAUTOPARENT')
+ ossetenv('TEXROOT',texroot)
+end
+environment.texroot=file.collapsepath(texroot)
+local prefixes=utilities.storage.allocate()
+resolvers.prefixes=prefixes
+local resolved={}
+local abstract={}
+local dynamic={}
+function resolvers.resetresolve(str)
+ resolved,abstract={},{}
+end
+function resolvers.allprefixes(separator)
+ local all=table.sortedkeys(prefixes)
+ if separator then
+  for i=1,#all do
+   all[i]=all[i]..":"
+  end
+ end
+ return all
+end
+local function _resolve_(method,target)
+ local action=prefixes[method]
+ if action then
+  return action(target)
+ else
+  return method..":"..target
+ end
+end
+function resolvers.unresolve(str)
+ return abstract[str] or str
+end
+function resolvers.setdynamic(str)
+ dynamic[str]=true
+end
+local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0)
+local prefix=C(R("az")^2)*P(":")
+local target=C((1-S(" \"\';,"))^1)
+local notarget=(#S(";,")+P(-1))*Cc("")
+local p_resolve=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0)
+local p_simple=prefix*P(-1)
+local function resolve(str) 
+ if type(str)=="table" then
+  local res={}
+  for i=1,#str do
+   res[i]=resolve(str[i])
+  end
+  return res
+ end
+ local res=resolved[str]
+ if res then
+  return res
+ end
+ local simple=lpegmatch(p_simple,str)
+ local action=prefixes[simple]
+ if action then
+  local res=action(res)
+  if not dynamic[simple] then
+   resolved[simple]=res
+   abstract[res]=simple
+  end
+  return res
+ end
+ res=lpegmatch(p_resolve,str)
+ resolved[str]=res
+ abstract[res]=str
+ return res
+end
+resolvers.resolve=resolve
+if type(osuname)=="function" then
+ for k,v in next,osuname() do
+  if not prefixes[k] then
+   prefixes[k]=function() return v end
+  end
+ end
+end
+if ostype=="unix" then
+ local pattern
+ local function makepattern(t,k,v)
+  if t then
+   rawset(t,k,v)
+  end
+  local colon=P(":")
+  for k,v in sortedpairs(prefixes) do
+   if p then
+    p=P(k)+p
+   else
+    p=P(k)
+   end
+  end
+  pattern=Cs((p*colon+colon/";"+P(1))^0)
+ end
+ makepattern()
+ table.setmetatablenewindex(prefixes,makepattern)
+ function resolvers.repath(str)
+  return lpegmatch(pattern,str)
+ end
+else 
+ function resolvers.repath(str)
+  return str
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-exp"] = package.loaded["data-exp"] or true
+
+-- original size: 18179, stripped down to: 10432
+
+if not modules then modules={} end modules ['data-exp']={
+ 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 format,find,gmatch,lower,char,sub=string.format,string.find,string.gmatch,string.lower,string.char,string.sub
+local concat,sort=table.concat,table.sort
+local sortedkeys=table.sortedkeys
+local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns
+local Ct,Cs,Cc,Carg,P,C,S=lpeg.Ct,lpeg.Cs,lpeg.Cc,lpeg.Carg,lpeg.P,lpeg.C,lpeg.S
+local type,next=type,next
+local isdir=lfs.isdir
+local collapsepath,joinpath,basename=file.collapsepath,file.join,file.basename
+local trace_locating=false  trackers.register("resolvers.locating",function(v) trace_locating=v end)
+local trace_expansions=false  trackers.register("resolvers.expansions",function(v) trace_expansions=v end)
+local trace_globbing=true   trackers.register("resolvers.globbing",function(v) trace_globbing=v end)
+local report_expansions=logs.reporter("resolvers","expansions")
+local report_globbing=logs.reporter("resolvers","globbing")
+local resolvers=resolvers
+local resolveprefix=resolvers.resolve
+local function f_both(a,b)
+ local t,n={},0
+ for sb in gmatch(b,"[^,]+") do     
+  for sa in gmatch(a,"[^,]+") do    
+   n=n+1;t[n]=sa..sb
+  end
+ end
+ return concat(t,",")
+end
+local comma=P(",")
+local nocomma=(1-comma)^1
+local docomma=comma^1/","
+local before=Cs((nocomma*Carg(1)+docomma)^0)
+local after=Cs((Carg(1)*nocomma+docomma)^0)
+local both=Cs(((C(nocomma)*Carg(1))/function(a,b) return lpegmatch(before,b,1,a) end+docomma)^0)
+local function f_first (a,b) return lpegmatch(after,b,1,a) end
+local function f_second(a,b) return lpegmatch(before,a,1,b) end
+local function f_both  (a,b) return lpegmatch(both,b,1,a) end
+local left=P("{")
+local right=P("}")
+local var=P((1-S("{}" ))^0)
+local set=P((1-S("{},"))^0)
+local other=P(1)
+local l_first=Cs((Cc("{")*(C(set)*left*C(var)*right/f_first)*Cc("}")+other )^0 )
+local l_second=Cs((Cc("{")*(left*C(var)*right*C(set)/f_second)*Cc("}")+other )^0 )
+local l_both=Cs((Cc("{")*(left*C(var)*right*left*C(var)*right/f_both)*Cc("}")+other )^0 )
+local l_rest=Cs((left*var*(left/"")*var*(right/"")*var*right+other )^0 )
+local stripper_1=lpeg.stripper ("{}@")
+local replacer_1=lpeg.replacer { { ",}",",@}" },{ "{,","{@," },}
+local function splitpathexpr(str,newlist,validate) 
+ if trace_expansions then
+  report_expansions("expanding variable %a",str)
+ end
+ local t,ok,done=newlist or {},false,false
+ local n=#t
+ str=lpegmatch(replacer_1,str)
+ repeat
+  local old=str
+  repeat
+   local old=str
+   str=lpegmatch(l_first,str)
+  until old==str
+  repeat
+   local old=str
+   str=lpegmatch(l_second,str)
+  until old==str
+  repeat
+   local old=str
+   str=lpegmatch(l_both,str)
+  until old==str
+  repeat
+   local old=str
+   str=lpegmatch(l_rest,str)
+  until old==str
+ until old==str 
+ str=lpegmatch(stripper_1,str)
+ if validate then
+  for s in gmatch(str,"[^,]+") do
+   s=validate(s)
+   if s then
+    n=n+1
+    t[n]=s
+   end
+  end
+ else
+  for s in gmatch(str,"[^,]+") do
+   n=n+1
+   t[n]=s
+  end
+ end
+ if trace_expansions then
+  for k=1,#t do
+   report_expansions("% 4i: %s",k,t[k])
+  end
+ end
+ return t
+end
+local function validate(s)
+ s=collapsepath(s) 
+ return s~="" and not find(s,"^!*unset/*$") and s
+end
+resolvers.validatedpath=validate 
+function resolvers.expandedpathfromlist(pathlist)
+ local newlist={}
+ for k=1,#pathlist do
+  splitpathexpr(pathlist[k],newlist,validate)
+ end
+ return newlist
+end
+local usedhomedir=nil
+local donegation=(P("!")/""  )^0
+local doslashes=(P("\\")/"/"+1)^0
+local function expandedhome()
+ if not usedhomedir then
+  usedhomedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "")
+  if usedhomedir=="~" or usedhomedir=="" or not isdir(usedhomedir) then
+   if trace_expansions then
+    report_expansions("no home dir set, ignoring dependent path using current path")
+   end
+   usedhomedir="."
+  end
+ end
+ return usedhomedir
+end
+local dohome=((P("~")+P("$HOME")+P("%HOME%"))/expandedhome)^0
+local cleanup=Cs(donegation*dohome*doslashes)
+resolvers.cleanpath=function(str)
+ return str and lpegmatch(cleanup,str) or ""
+end
+local expandhome=P("~")/"$HOME"
+local dodouble=P('"')/""*(expandhome+(1-P('"')))^0*P('"')/""
+local dosingle=P("'")/""*(expandhome+(1-P("'")))^0*P("'")/""
+local dostring=(expandhome+1     )^0
+local stripper=Cs(
+ lpegpatterns.unspacer*(dosingle+dodouble+dostring)*lpegpatterns.unspacer
+)
+function resolvers.checkedvariable(str) 
+ return type(str)=="string" and lpegmatch(stripper,str) or str
+end
+local cache={}
+local splitter=lpeg.tsplitat(";") 
+local backslashswapper=lpeg.replacer("\\","/")
+local function splitconfigurationpath(str) 
+ if str then
+  local found=cache[str]
+  if not found then
+   if str=="" then
+    found={}
+   else
+    local split=lpegmatch(splitter,lpegmatch(backslashswapper,str)) 
+    found={}
+    local noffound=0
+    for i=1,#split do
+     local s=split[i]
+     if not find(s,"^{*unset}*") then
+      noffound=noffound+1
+      found[noffound]=s
+     end
+    end
+    if trace_expansions then
+     report_expansions("splitting path specification %a",str)
+     for k=1,noffound do
+      report_expansions("% 4i: %s",k,found[k])
+     end
+    end
+    cache[str]=found
+   end
+  end
+  return found
+ end
+end
+resolvers.splitconfigurationpath=splitconfigurationpath
+function resolvers.splitpath(str)
+ if type(str)=='table' then
+  return str
+ else
+  return splitconfigurationpath(str)
+ end
+end
+function resolvers.joinpath(str)
+ if type(str)=='table' then
+  return joinpath(str)
+ else
+  return str
+ end
+end
+local attributes,directory=lfs.attributes,lfs.dir
+local weird=P(".")^1+lpeg.anywhere(S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
+local lessweird=P(".")^1+lpeg.anywhere(S("~`#$%^&*:;\"\'||<>,?\n\r\t"))
+local timer={}
+local scanned={}
+local nofscans=0
+local scancache={}
+local fullcache={}
+local nofsharedscans=0
+local addcasecraptoo=true
+local function scan(files,remap,spec,path,n,m,r,onlyone,tolerant)
+ local full=path=="" and spec or (spec..path..'/')
+ local dirlist={}
+ local nofdirs=0
+ local pattern=tolerant and lessweird or weird
+ local filelist={}
+ local noffiles=0
+ for name,mode in directory(full) do
+  if not lpegmatch(pattern,name) then
+   if not mode then
+    mode=attributes(full..name,"mode")
+   end
+   if mode=="file" then
+    n=n+1
+    noffiles=noffiles+1
+    filelist[noffiles]=name
+   elseif mode=="directory" then
+    m=m+1
+    nofdirs=nofdirs+1
+    if path~="" then
+     dirlist[nofdirs]=path.."/"..name
+    else
+     dirlist[nofdirs]=name
+    end
+   end
+  end
+ end
+ if noffiles>0 then
+  sort(filelist)
+  for i=1,noffiles do
+   local name=filelist[i]
+   local lower=lower(name)
+   local paths=files[lower]
+   if paths then
+    if onlyone then
+    else
+     if name~=lower then
+      local rl=remap[lower]
+      if not rl then
+       remap[lower]=name
+       r=r+1
+      elseif trace_globbing and rl~=name then
+       report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl)
+      end
+      if addcasecraptoo then
+       local paths=files[name]
+       if not paths then
+        files[name]=path
+       elseif type(paths)=="string" then
+        files[name]={ paths,path }
+       else
+        paths[#paths+1]=path
+       end
+      end
+     end
+     if type(paths)=="string" then
+      files[lower]={ paths,path }
+     else
+      paths[#paths+1]=path
+     end
+    end
+   else 
+    files[lower]=path
+    if name~=lower then
+     local rl=remap[lower]
+     if not rl then
+      remap[lower]=name
+      r=r+1
+     elseif trace_globbing and rl~=name then
+      report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl)
+     end
+    end
+   end
+  end
+ end
+ if nofdirs>0 then
+  sort(dirlist)
+  for i=1,nofdirs do
+   files,remap,n,m,r=scan(files,remap,spec,dirlist[i],n,m,r,onlyonce,tolerant)
+  end
+ end
+ scancache[sub(full,1,-2)]=files
+ return files,remap,n,m,r
+end
+local function scanfiles(path,branch,usecache,onlyonce,tolerant)
+ local realpath=resolveprefix(path)
+ if usecache then
+  local content=fullcache[realpath]
+  if content then
+   if trace_locating then
+    report_expansions("using cached scan of path %a, branch %a",path,branch or path)
+   end
+   nofsharedscans=nofsharedscans+1
+   return content
+  end
+ end
+ statistics.starttiming(timer)
+ if trace_locating then
+  report_expansions("scanning path %a, branch %a",path,branch or path)
+ end
+ local content
+ if isdir(realpath) then
+  local files,remap,n,m,r=scan({},{},realpath..'/',"",0,0,0,onlyonce,tolerant)
+  content={
+   metadata={
+    path=path,
+    files=n,
+    directories=m,
+    remappings=r,
+   },
+   files=files,
+   remap=remap,
+  }
+  if trace_locating then
+   report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r)
+  end
+ else
+  content={
+   metadata={
+    path=path,
+    files=0,
+    directories=0,
+    remappings=0,
+   },
+   files={},
+   remap={},
+  }
+  if trace_locating then
+   report_expansions("invalid path %a",realpath)
+  end
+ end
+ if usecache then
+  scanned[#scanned+1]=realpath
+  fullcache[realpath]=content
+ end
+ nofscans=nofscans+1
+ statistics.stoptiming(timer)
+ return content
+end
+resolvers.scanfiles=scanfiles
+function resolvers.simplescanfiles(path,branch,usecache)
+ return scanfiles(path,branch,usecache,true,true) 
+end
+function resolvers.scandata()
+ table.sort(scanned)
+ return {
+  n=nofscans,
+  shared=nofsharedscans,
+  time=statistics.elapsedtime(timer),
+  paths=scanned,
+ }
+end
+function resolvers.get_from_content(content,path,name) 
+ if not content then
+  return
+ end
+ local files=content.files
+ if not files then
+  return
+ end
+ local remap=content.remap
+ if not remap then
+  return
+ end
+ if name then
+  local used=lower(name)
+  return path,remap[used] or used
+ else
+  local name=path
+  local used=lower(name)
+  local path=files[used]
+  if path then
+   return path,remap[used] or used
+  end
+ end
+end
+local nothing=function() end
+function resolvers.filtered_from_content(content,pattern)
+ if content and type(pattern)=="string" then
+  local pattern=lower(pattern)
+  local files=content.files 
+  local remap=content.remap
+  if files and remap then
+   local f=sortedkeys(files)
+   local n=#f
+   local i=0
+   local function iterator()
+    while i<n do
+     i=i+1
+     local k=f[i]
+     if find(k,pattern) then
+      return files[k],remap and remap[k] or k
+     end
+    end
+   end
+   return iterator
+  end
+ end
+ return nothing
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-env"] = package.loaded["data-env"] or true
+
+-- original size: 9501, stripped down to: 6413
+
+if not modules then modules={} end modules ['data-env']={
+ 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 lower,gsub=string.lower,string.gsub
+local next,rawget=next,rawget
+local resolvers=resolvers
+local allocate=utilities.storage.allocate
+local setmetatableindex=table.setmetatableindex
+local suffixonly=file.suffixonly
+local formats=allocate()
+local suffixes=allocate()
+local dangerous=allocate()
+local suffixmap=allocate()
+local usertypes=allocate()
+resolvers.formats=formats
+resolvers.suffixes=suffixes
+resolvers.dangerous=dangerous
+resolvers.suffixmap=suffixmap
+resolvers.usertypes=usertypes
+local luasuffixes=utilities.lua.suffixes
+local relations=allocate { 
+ core={
+  ofm={ 
+   names={ "ofm","omega font metric","omega font metrics" },
+   variable='OFMFONTS',
+   suffixes={ 'ofm','tfm' },
+  },
+  ovf={ 
+   names={ "ovf","omega virtual font","omega virtual fonts" },
+   variable='OVFFONTS',
+   suffixes={ 'ovf','vf' },
+  },
+  tfm={
+   names={ "tfm","tex font metric","tex font metrics" },
+   variable='TFMFONTS',
+   suffixes={ 'tfm' },
+  },
+  vf={
+   names={ "vf","virtual font","virtual fonts" },
+   variable='VFFONTS',
+   suffixes={ 'vf' },
+  },
+  otf={
+   names={ "otf","opentype","opentype font","opentype fonts"},
+   variable='OPENTYPEFONTS',
+   suffixes={ 'otf' },
+  },
+  ttf={
+   names={ "ttf","truetype","truetype font","truetype fonts","truetype collection","truetype collections","truetype dictionary","truetype dictionaries" },
+   variable='TTFONTS',
+   suffixes={ 'ttf','ttc','dfont' },
+  },
+  afm={
+   names={ "afm","adobe font metric","adobe font metrics" },
+   variable="AFMFONTS",
+   suffixes={ "afm" },
+  },
+  pfb={
+   names={ "pfb","type1","type 1","type1 font","type 1 font","type1 fonts","type 1 fonts" },
+   variable='T1FONTS',
+   suffixes={ 'pfb','pfa' },
+  },
+  fea={
+   names={ "fea","font feature","font features","font feature file","font feature files" },
+   variable='FONTFEATURES',
+   suffixes={ 'fea' },
+  },
+  cid={
+   names={ "cid","cid map","cid maps","cid file","cid files" },
+   variable='FONTCIDMAPS',
+   suffixes={ 'cid','cidmap' },
+  },
+  fmt={
+   names={ "fmt","format","tex format" },
+   variable='TEXFORMATS',
+   suffixes={ 'fmt' },
+  },
+  mem={ 
+   names={ 'mem',"metapost format" },
+   variable='MPMEMS',
+   suffixes={ 'mem' },
+  },
+  mp={
+   names={ "mp" },
+   variable='MPINPUTS',
+   suffixes=CONTEXTLMTXMODE>0
+    and { 'mpxl','mpvi','mpiv','mpii','mp' }
+    or  {   'mpvi','mpiv','mpii','mp' },
+   usertype=true,
+  },
+  tex={
+   names={ "tex" },
+   variable='TEXINPUTS',
+   suffixes={ "tex","mkiv","mkvi","mkxl","mklx","mkii","cld","lfg","xml" },
+   usertype=true,
+  },
+  icc={
+   names={ "icc","icc profile","icc profiles" },
+   variable='ICCPROFILES',
+   suffixes={ 'icc' },
+  },
+  texmfscripts={
+   names={ "texmfscript","texmfscripts","script","scripts" },
+   variable='TEXMFSCRIPTS',
+   suffixes={ 'lua','rb','pl','py' },
+  },
+  lua={
+   names={ "lua" },
+   variable='LUAINPUTS',
+   suffixes={ luasuffixes.lua,luasuffixes.luc,luasuffixes.tma,luasuffixes.tmc },
+   usertype=true,
+  },
+  lib={
+   names={ "lib" },
+   variable='CLUAINPUTS',
+   suffixes=os.libsuffix and { os.libsuffix } or { 'dll','so' },
+  },
+  bib={
+   names={ 'bib' },
+   variable='BIBINPUTS',
+   suffixes={ 'bib' },
+   usertype=true,
+  },
+  bst={
+   names={ 'bst' },
+   variable='BSTINPUTS',
+   suffixes={ 'bst' },
+   usertype=true,
+  },
+  fontconfig={
+   names={ 'fontconfig','fontconfig file','fontconfig files' },
+   variable='FONTCONFIG_PATH',
+  },
+  pk={
+   names={ "pk" },
+   variable='PKFONTS',
+   suffixes={ 'pk' },
+  },
+ },
+ obsolete={
+  enc={
+   names={ "enc","enc files","enc file","encoding files","encoding file" },
+   variable='ENCFONTS',
+   suffixes={ 'enc' },
+  },
+  map={
+   names={ "map","map files","map file" },
+   variable='TEXFONTMAPS',
+   suffixes={ 'map' },
+  },
+  lig={
+   names={ "lig files","lig file","ligature file","ligature files" },
+   variable='LIGFONTS',
+   suffixes={ 'lig' },
+  },
+  opl={
+   names={ "opl" },
+   variable='OPLFONTS',
+   suffixes={ 'opl' },
+  },
+  ovp={
+   names={ "ovp" },
+   variable='OVPFONTS',
+   suffixes={ 'ovp' },
+  },
+ },
+ kpse={ 
+  base={
+   names={ 'base',"metafont format" },
+   variable='MFBASES',
+   suffixes={ 'base','bas' },
+  },
+  cmap={
+   names={ 'cmap','cmap files','cmap file' },
+   variable='CMAPFONTS',
+   suffixes={ 'cmap' },
+  },
+  cnf={
+   names={ 'cnf' },
+   suffixes={ 'cnf' },
+  },
+  web={
+   names={ 'web' },
+   suffixes={ 'web','ch' }
+  },
+  cweb={
+   names={ 'cweb' },
+   suffixes={ 'w','web','ch' },
+  },
+  gf={
+   names={ 'gf' },
+   suffixes={ '<resolution>gf' },
+  },
+  mf={
+   names={ 'mf' },
+   variable='MFINPUTS',
+   suffixes={ 'mf' },
+  },
+  mft={
+   names={ 'mft' },
+   suffixes={ 'mft' },
+  },
+  pk={
+   names={ 'pk' },
+   suffixes={ '<resolution>pk' },
+  },
+ },
+}
+resolvers.relations=relations
+function resolvers.updaterelations()
+ for category,categories in next,relations do
+  for name,relation in next,categories do
+   local rn=relation.names
+   local rv=relation.variable
+   if rn and rv then
+    local rs=relation.suffixes
+    local ru=relation.usertype
+    for i=1,#rn do
+     local rni=lower(gsub(rn[i]," ",""))
+     formats[rni]=rv
+     if rs then
+      suffixes[rni]=rs
+      for i=1,#rs do
+       local rsi=rs[i]
+       suffixmap[rsi]=rni
+      end
+     end
+    end
+    if ru then
+     usertypes[name]=true
+    end
+   end
+  end
+ end
+end
+resolvers.updaterelations() 
+local function simplified(t,k)
+ return k and rawget(t,lower(gsub(k," ",""))) or nil
+end
+setmetatableindex(formats,simplified)
+setmetatableindex(suffixes,simplified)
+setmetatableindex(suffixmap,simplified)
+function resolvers.suffixofformat(str)
+ local s=suffixes[str]
+ return s and s[1] or ""
+end
+function resolvers.suffixofformat(str)
+ return suffixes[str] or {}
+end
+for name,format in next,formats do
+ dangerous[name]=true 
+end
+dangerous.tex=nil
+function resolvers.formatofvariable(str)
+ return formats[str] or ''
+end
+function resolvers.formatofsuffix(str) 
+ return suffixmap[suffixonly(str)] or 'tex' 
+end
+function resolvers.variableofformat(str)
+ return formats[str] or ''
+end
+function resolvers.variableofformatorsuffix(str)
+ local v=formats[str]
+ if v then
+  return v
+ end
+ v=suffixmap[suffixonly(str)]
+ if v then
+  return formats[v]
+ end
+ return ''
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-tmp"] = package.loaded["data-tmp"] or true
+
+-- original size: 16456, stripped down to: 11636
+
+if not modules then modules={} end modules ['data-tmp']={
+ version=1.100,
+ comment="companion to luat-lib.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local next,type=next,type
+local pcall,loadfile,collectgarbage=pcall,loadfile,collectgarbage
+local format,lower,gsub=string.format,string.lower,string.gsub
+local concat,serialize,fastserialize,serializetofile=table.concat,table.serialize,table.fastserialize,table.tofile
+local mkdirs,expanddirname,isdir,isfile=dir.mkdirs,dir.expandname,lfs.isdir,lfs.isfile
+local is_writable,is_readable=file.is_writable,file.is_readable
+local collapsepath,joinfile,addsuffix,dirname=file.collapsepath,file.join,file.addsuffix,file.dirname
+local savedata=file.savedata
+local formatters=string.formatters
+local osexit,osdate,osuuid=os.exit,os.date,os.uuid
+local removefile=os.remove
+local md5hex=md5.hex
+local trace_locating=false  trackers.register("resolvers.locating",function(v) trace_locating=v end)
+local trace_cache=false  trackers.register("resolvers.cache",function(v) trace_cache=v end)
+local report_caches=logs.reporter("resolvers","caches")
+local report_resolvers=logs.reporter("resolvers","caching")
+local resolvers=resolvers
+local cleanpath=resolvers.cleanpath
+local resolvepath=resolvers.resolve
+local luautilities=utilities.lua
+do
+ local directive_cleanup=false  directives.register("system.compile.cleanup",function(v) directive_cleanup=v end)
+ local directive_strip=false  directives.register("system.compile.strip",function(v) directive_strip=v end)
+ local compilelua=luautilities.compile
+ function luautilities.compile(luafile,lucfile,cleanup,strip)
+  if cleanup==nil then cleanup=directive_cleanup end
+  if strip==nil then strip=directive_strip   end
+  return compilelua(luafile,lucfile,cleanup,strip)
+ end
+end
+caches=caches or {}
+local caches=caches
+local writable=nil
+local readables={}
+local usedreadables={}
+local compilelua=luautilities.compile
+local luasuffixes=luautilities.suffixes
+caches.base=caches.base or (LUATEXENGINE and LUATEXENGINE.."-cache") or "luatex-cache"  
+caches.more=caches.more or "context"    
+caches.defaults={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" }
+local direct_cache=false 
+local fast_cache=false
+local cache_tree=false
+directives.register("system.caches.direct",function(v) direct_cache=true end)
+directives.register("system.caches.fast",function(v) fast_cache=true end)
+local function configfiles()
+ return concat(resolvers.configurationfiles(),";")
+end
+local function hashed(tree)
+ tree=gsub(tree,"[\\/]+$","")
+ tree=lower(tree)
+ local hash=md5hex(tree)
+ if trace_cache or trace_locating then
+  report_caches("hashing tree %a, hash %a",tree,hash)
+ end
+ return hash
+end
+local function treehash()
+ local tree=configfiles()
+ if not tree or tree=="" then
+  return false
+ else
+  return hashed(tree)
+ end
+end
+caches.hashed=hashed
+caches.treehash=treehash
+caches.configfiles=configfiles
+local function identify()
+ local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") 
+ if texmfcaches then
+  for k=1,#texmfcaches do
+   local cachepath=texmfcaches[k]
+   if cachepath~="" then
+    cachepath=resolvepath(cachepath)
+    cachepath=cleanpath(cachepath)
+    cachepath=collapsepath(cachepath)
+    local valid=isdir(cachepath)
+    if valid then
+     if is_readable(cachepath) then
+      readables[#readables+1]=cachepath
+      if not writable and is_writable(cachepath) then
+       writable=cachepath
+      end
+     end
+    elseif not writable then
+     local cacheparent=dirname(cachepath)
+     if is_writable(cacheparent) then 
+      mkdirs(cachepath)
+      if isdir(cachepath) and is_writable(cachepath) then
+       report_caches("path %a created",cachepath)
+       writable=cachepath
+       readables[#readables+1]=cachepath
+      end
+     end
+    end
+   end
+  end
+ end
+ local texmfcaches=caches.defaults
+ if texmfcaches then
+  for k=1,#texmfcaches do
+   local cachepath=texmfcaches[k]
+   cachepath=resolvers.expansion(cachepath) 
+   if cachepath~="" then
+    cachepath=resolvepath(cachepath)
+    cachepath=cleanpath(cachepath)
+    local valid=isdir(cachepath)
+    if valid and is_readable(cachepath) then
+     if not writable and is_writable(cachepath) then
+      readables[#readables+1]=cachepath
+      writable=cachepath
+      break
+     end
+    end
+   end
+  end
+ end
+ if not writable then
+  report_caches("fatal error: there is no valid writable cache path defined")
+  osexit()
+ elseif #readables==0 then
+  report_caches("fatal error: there is no valid readable cache path defined")
+  osexit()
+ end
+ writable=expanddirname(cleanpath(writable))
+ local base=caches.base
+ local more=caches.more
+ local tree=cache_tree or treehash() 
+ if tree then
+  cache_tree=tree
+  writable=mkdirs(writable,base,more,tree)
+  for i=1,#readables do
+   readables[i]=joinfile(readables[i],base,more,tree)
+  end
+ else
+  writable=mkdirs(writable,base,more)
+  for i=1,#readables do
+   readables[i]=joinfile(readables[i],base,more)
+  end
+ end
+ if trace_cache then
+  for i=1,#readables do
+   report_caches("using readable path %a (order %s)",readables[i],i)
+  end
+  report_caches("using writable path %a",writable)
+ end
+ identify=function()
+  return writable,readables
+ end
+ return writable,readables
+end
+function caches.usedpaths(separator)
+ local writable,readables=identify()
+ if #readables>1 then
+  local result={}
+  local done={}
+  for i=1,#readables do
+   local readable=readables[i]
+   if readable==writable then
+    done[readable]=true
+    result[#result+1]=formatters["readable+writable: %a"](readable)
+   elseif usedreadables[i] then
+    done[readable]=true
+    result[#result+1]=formatters["readable: %a"](readable)
+   end
+  end
+  if not done[writable] then
+   result[#result+1]=formatters["writable: %a"](writable)
+  end
+  return concat(result,separator or " | ")
+ else
+  return writable or "?"
+ end
+end
+local r_cache={}
+local w_cache={}
+local function getreadablepaths(...)
+ local tags={... }
+ local hash=concat(tags,"/")
+ local done=r_cache[hash]
+ if not done then
+  local writable,readables=identify() 
+  if #tags>0 then
+   done={}
+   for i=1,#readables do
+    done[i]=joinfile(readables[i],...)
+   end
+  else
+   done=readables
+  end
+  r_cache[hash]=done
+ end
+ return done
+end
+local function getwritablepath(...)
+ local tags={... }
+ local hash=concat(tags,"/")
+ local done=w_cache[hash]
+ if not done then
+  local writable,readables=identify() 
+  if #tags>0 then
+   done=mkdirs(writable,...)
+  else
+   done=writable
+  end
+  w_cache[hash]=done
+ end
+ return done
+end
+local function setfirstwritablefile(filename,...)
+ local wr=getwritablepath(...)
+ local fullname=joinfile(wr,filename)
+ return fullname,wr
+end
+local function setluanames(path,name)
+ return
+  format("%s/%s.%s",path,name,luasuffixes.tma),
+  format("%s/%s.%s",path,name,luasuffixes.tmc)
+end
+local function getfirstreadablefile(filename,...)
+ local fullname,path=setfirstwritablefile(filename,...)
+ if is_readable(fullname) then
+  return fullname,path 
+ end
+ local rd=getreadablepaths(...)
+ for i=1,#rd do
+  local path=rd[i]
+  local fullname=joinfile(path,filename)
+  if is_readable(fullname) then
+   usedreadables[i]=true
+   return fullname,path 
+  end
+ end
+ return fullname,path 
+end
+caches.getreadablepaths=getreadablepaths
+caches.getwritablepath=getwritablepath
+caches.setfirstwritablefile=setfirstwritablefile
+caches.getfirstreadablefile=getfirstreadablefile
+caches.setluanames=setluanames
+local checkmemory=utilities and utilities.lua and utilities.lua.checkmemory
+local threshold=100 
+function caches.loaddata(readables,name,writable)
+ local used=checkmemory and checkmemory()
+ if type(readables)=="string" then
+  readables={ readables }
+ end
+ for i=1,#readables do
+  local path=readables[i]
+  local loader=false
+  local state=false
+  local tmaname,tmcname=setluanames(path,name)
+  if isfile(tmcname) then
+   state,loader=pcall(loadfile,tmcname)
+  end
+  if not loader and isfile(tmaname) then
+   local tmacrap,tmcname=setluanames(writable,name)
+   if isfile(tmcname) then
+    state,loader=pcall(loadfile,tmcname)
+   end
+   compilelua(tmaname,tmcname)
+   if isfile(tmcname) then
+    state,loader=pcall(loadfile,tmcname)
+   end
+   if not loader then
+    state,loader=pcall(loadfile,tmaname)
+   end
+  end
+  if loader then
+   loader=loader()
+   if checkmemory then
+    checkmemory(used,threshold)
+   else 
+    collectgarbage("step") 
+   end
+   return loader
+  end
+ end
+ return false
+end
+function caches.is_writable(filepath,filename)
+ local tmaname,tmcname=setluanames(filepath,filename)
+ return is_writable(tmaname)
+end
+local saveoptions={ compact=true,accurate=not JITSUPPORTED }
+function caches.savedata(filepath,filename,data,fast)
+ local tmaname,tmcname=setluanames(filepath,filename)
+ data.cache_uuid=osuuid()
+ if fast or fast_cache then
+  savedata(tmaname,fastserialize(data,true))
+ elseif direct_cache then
+  savedata(tmaname,serialize(data,true,saveoptions))
+ else
+  serializetofile(tmaname,data,true,saveoptions)
+ end
+ compilelua(tmaname,tmcname)
+end
+local content_state={}
+function caches.contentstate()
+ return content_state or {}
+end
+function caches.loadcontent(cachename,dataname,filename)
+ if not filename then
+  local name=hashed(cachename)
+  local full,path=getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees")
+  filename=joinfile(path,name)
+ end
+ local state,blob=pcall(loadfile,addsuffix(filename,luasuffixes.luc))
+ if not blob then
+  state,blob=pcall(loadfile,addsuffix(filename,luasuffixes.lua))
+ end
+ if blob then
+  local data=blob()
+  if data and data.content then
+   if data.type==dataname then
+    if data.version==resolvers.cacheversion then
+     content_state[#content_state+1]=data.uuid
+     if trace_locating then
+      report_resolvers("loading %a for %a from %a",dataname,cachename,filename)
+     end
+     return data.content
+    else
+     report_resolvers("skipping %a for %a from %a (version mismatch)",dataname,cachename,filename)
+    end
+   else
+    report_resolvers("skipping %a for %a from %a (datatype mismatch)",dataname,cachename,filename)
+   end
+  elseif trace_locating then
+   report_resolvers("skipping %a for %a from %a (no content)",dataname,cachename,filename)
+  end
+ elseif trace_locating then
+  report_resolvers("skipping %a for %a from %a (invalid file)",dataname,cachename,filename)
+ end
+end
+function caches.collapsecontent(content)
+ for k,v in next,content do
+  if type(v)=="table" and #v==1 then
+   content[k]=v[1]
+  end
+ end
+end
+function caches.savecontent(cachename,dataname,content,filename)
+ if not filename then
+  local name=hashed(cachename)
+  local full,path=setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees")
+  filename=joinfile(path,name) 
+ end
+ local luaname=addsuffix(filename,luasuffixes.lua)
+ local lucname=addsuffix(filename,luasuffixes.luc)
+ if trace_locating then
+  report_resolvers("preparing %a for %a",dataname,cachename)
+ end
+ local data={
+  type=dataname,
+  root=cachename,
+  version=resolvers.cacheversion,
+  date=osdate("%Y-%m-%d"),
+  time=osdate("%H:%M:%S"),
+  content=content,
+  uuid=osuuid(),
+ }
+ local ok=savedata(luaname,serialize(data,true))
+ if ok then
+  if trace_locating then
+   report_resolvers("category %a, cachename %a saved in %a",dataname,cachename,luaname)
+  end
+  if compilelua(luaname,lucname) then
+   if trace_locating then
+    report_resolvers("%a compiled to %a",dataname,lucname)
+   end
+   return true
+  else
+   if trace_locating then
+    report_resolvers("compiling failed for %a, deleting file %a",dataname,lucname)
+   end
+   removefile(lucname)
+  end
+ elseif trace_locating then
+  report_resolvers("unable to save %a in %a (access error)",dataname,luaname)
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-met"] = package.loaded["data-met"] or true
+
+-- original size: 5518, stripped down to: 3854
+
+if not modules then modules={} end modules ['data-met']={
+ version=1.100,
+ comment="companion to luat-lib.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local type=type
+local find=string.find
+local addurlscheme,urlhashed=url.addscheme,url.hashed
+local collapsepath,joinfile=file.collapsepath,file.join
+local report_methods=logs.reporter("resolvers","methods")
+local trace_locating=false
+local trace_methods=false
+trackers.register("resolvers.locating",function(v) trace_methods=v end)
+trackers.register("resolvers.methods",function(v) trace_methods=v end)
+local allocate=utilities.storage.allocate
+local resolvers=resolvers
+local registered={}
+local function splitmethod(filename) 
+ if not filename then
+  return {
+   scheme="unknown",
+   original=filename,
+  }
+ end
+ if type(filename)=="table" then
+  return filename 
+ end
+ filename=collapsepath(filename,".") 
+ if not find(filename,"://",1,true) then
+  return {
+   scheme="file",
+   path=filename,
+   original=filename,
+   filename=filename,
+  }
+ end
+ local specification=urlhashed(filename)
+ if not specification.scheme or specification.scheme=="" then
+  return {
+   scheme="file",
+   path=filename,
+   original=filename,
+   filename=filename,
+  }
+ else
+  return specification
+ end
+end
+resolvers.splitmethod=splitmethod
+local function methodhandler(what,first,...) 
+ local method=registered[what]
+ if method then
+  local how=method.how
+  local namespace=method.namespace
+  if how=="uri" or how=="url" then
+   local specification=splitmethod(first)
+   local scheme=specification.scheme
+   local resolver=namespace and namespace[scheme]
+   if resolver then
+    if trace_methods then
+     report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,scheme,first)
+    end
+    return resolver(specification,...)
+   else
+    resolver=namespace.default or namespace.file
+    if resolver then
+     if trace_methods then
+      report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"default",first)
+     end
+     return resolver(specification,...)
+    elseif trace_methods then
+     report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"unset")
+    end
+   end
+  elseif how=="tag" then
+   local resolver=namespace and namespace[first]
+   if resolver then
+    if trace_methods then
+     report_methods("resolving, method %a, how %a, tag %a",what,how,first)
+    end
+    return resolver(...)
+   else
+    resolver=namespace.default or namespace.file
+    if resolver then
+     if trace_methods then
+      report_methods("resolving, method %a, how %a, tag %a",what,how,"default")
+     end
+     return resolver(...)
+    elseif trace_methods then
+     report_methods("resolving, method %a, how %a, tag %a",what,how,"unset")
+    end
+   end
+  end
+ else
+  report_methods("resolving, invalid method %a")
+ end
+end
+resolvers.methodhandler=methodhandler
+function resolvers.registermethod(name,namespace,how)
+ registered[name]={
+  how=how or "tag",
+  namespace=namespace
+ }
+ namespace["byscheme"]=function(scheme,filename,...)
+  if scheme=="file" then
+   return methodhandler(name,filename,...)
+  else
+   return methodhandler(name,addurlscheme(filename,scheme),...)
+  end
+ end
+end
+local concatinators=allocate { notfound=joinfile  }  
+local locators=allocate { notfound=function() end  }  
+local hashers=allocate { notfound=function() end  }  
+local generators=allocate { notfound=function() end  }  
+resolvers.concatinators=concatinators
+resolvers.locators=locators
+resolvers.hashers=hashers
+resolvers.generators=generators
+local registermethod=resolvers.registermethod
+registermethod("concatinators",concatinators,"tag")
+registermethod("locators",locators,"uri")
+registermethod("hashers",hashers,"uri")
+registermethod("generators",generators,"uri")
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-res"] = package.loaded["data-res"] or true
+
+-- original size: 69576, stripped down to: 44470
+
+if not modules then modules={} end modules ['data-res']={
+ 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 gsub,find,lower,upper,match,gmatch=string.gsub,string.find,string.lower,string.upper,string.match,string.gmatch
+local concat,insert,remove=table.concat,table.insert,table.remove
+local next,type,rawget,loadfile=next,type,rawget,loadfile
+local mergedtable=table.merged
+local os=os
+local P,S,R,C,Cc,Cs,Ct,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cc,lpeg.Cs,lpeg.Ct,lpeg.Carg
+local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns
+local formatters=string.formatters
+local filedirname=file.dirname
+local filebasename=file.basename
+local suffixonly=file.suffixonly
+local addsuffix=file.addsuffix
+local removesuffix=file.removesuffix
+local filejoin=file.join
+local collapsepath=file.collapsepath
+local joinpath=file.joinpath
+local is_qualified_path=file.is_qualified_path
+local allocate=utilities.storage.allocate
+local settings_to_array=utilities.parsers.settings_to_array
+local urlhasscheme=url.hasscheme
+local getcurrentdir=lfs.currentdir
+local isfile=lfs.isfile
+local isdir=lfs.isdir
+local setmetatableindex=table.setmetatableindex
+local luasuffixes=utilities.lua.suffixes
+local trace_locating=false  trackers  .register("resolvers.locating",function(v) trace_locating=v end)
+local trace_details=false  trackers  .register("resolvers.details",function(v) trace_details=v end)
+local trace_expansions=false  trackers  .register("resolvers.expansions",function(v) trace_expansions=v end)
+local trace_paths=false  trackers  .register("resolvers.paths",function(v) trace_paths=v end)
+local resolve_otherwise=true   directives.register("resolvers.otherwise",function(v) resolve_otherwise=v end)
+local report_resolving=logs.reporter("resolvers","resolving")
+local resolvers=resolvers
+local expandedpathfromlist=resolvers.expandedpathfromlist
+local checkedvariable=resolvers.checkedvariable
+local splitconfigurationpath=resolvers.splitconfigurationpath
+local methodhandler=resolvers.methodhandler
+local filtered=resolvers.filtered_from_content
+local lookup=resolvers.get_from_content
+local cleanpath=resolvers.cleanpath
+local resolveprefix=resolvers.resolve
+local initializesetter=utilities.setters.initialize
+local ostype,osname,osenv,ossetenv,osgetenv=os.type,os.name,os.env,os.setenv,os.getenv
+resolvers.cacheversion="1.100"
+resolvers.configbanner=""
+resolvers.homedir=environment.homedir
+resolvers.luacnfname="texmfcnf.lua"
+resolvers.luacnffallback="contextcnf.lua"
+resolvers.luacnfstate="unknown"
+local criticalvars={
+ "SELFAUTOLOC",
+ "SELFAUTODIR",
+ "SELFAUTOPARENT",
+ "TEXMFCNF",
+ "TEXMF",
+ "TEXOS",
+}
+if environment.default_texmfcnf then
+ resolvers.luacnfspec="home:texmf/web2c;"..environment.default_texmfcnf 
+else
+ resolvers.luacnfspec=concat ({
+  "home:texmf/web2c",
+  "selfautoparent:/texmf-local/web2c",
+  "selfautoparent:/texmf-context/web2c",
+  "selfautoparent:/texmf-dist/web2c",
+  "selfautoparent:/texmf/web2c",
+ },";")
+end
+local unset_variable="unset"
+local formats=resolvers.formats
+local suffixes=resolvers.suffixes
+local usertypes=resolvers.usertypes
+local dangerous=resolvers.dangerous
+local suffixmap=resolvers.suffixmap
+resolvers.defaultsuffixes={ "tex" } 
+local instance=nil
+local variable
+local expansion
+local setenv
+local getenv
+local formatofsuffix=resolvers.formatofsuffix
+local splitpath=resolvers.splitpath
+local splitmethod=resolvers.splitmethod
+setenv=function(key,value,raw)
+ if instance then
+  instance.environment[key]=value
+  ossetenv(key,raw and value or resolveprefix(value))
+ end
+end
+getenv=function(key)
+ local value=rawget(instance.environment,key)
+ if value and value~="" then
+  return value
+ else
+  local e=osgetenv(key)
+  return e~=nil and e~="" and checkedvariable(e) or ""
+ end
+end
+resolvers.getenv=getenv
+resolvers.setenv=setenv
+local dollarstripper=lpeg.stripper("$")
+local inhibitstripper=P("!")^0*Cs(P(1)^0)
+local expandedvariable,resolvedvariable  do
+ local function resolveinstancevariable(k)
+  return instance.expansions[k]
+ end
+ local p_variable=P("$")/""
+ local p_key=C(R("az","AZ","09","__","--")^1)
+ local p_whatever=P(";")*((1-S("!{}/\\"))^1*P(";")/"")+P(";")*(P(";")/"")+P(1)
+ local variableexpander=Cs((p_variable*(p_key/resolveinstancevariable)+p_whatever)^1 )
+ local p_cleaner=P("\\")/"/"+P(";")*S("!{}/\\")^0*P(";")^1/";"
+ local variablecleaner=Cs((p_cleaner+P(1))^0)
+ local p_variable=R("az","AZ","09","__","--")^1/resolveinstancevariable
+ local p_variable=(P("$")/"")*(p_variable+(P("{")/"")*p_variable*(P("}")/""))
+ local variableresolver=Cs((p_variable+P(1))^0)
+ expandedvariable=function(var)
+  return lpegmatch(variableexpander,var) or var
+ end
+ function resolvers.reset()
+  if trace_locating then
+   report_resolving("creating instance")
+  end
+  local environment={}
+  local variables={}
+  local expansions={}
+  local order={}
+  instance={
+   environment=environment,
+   variables=variables,
+   expansions=expansions,
+   order=order,
+   files={},
+   setups={},
+   found={},
+   foundintrees={},
+   hashes={},
+   hashed={},
+   pathlists=false,
+   specification={},
+   lists={},
+   data={},
+   fakepaths={},
+   remember=true,
+   diskcache=true,
+   renewcache=false,
+   renewtree=false,
+   loaderror=false,
+   savelists=true,
+   pattern=nil,
+   force_suffixes=true,
+   pathstack={},
+  }
+  setmetatableindex(variables,function(t,k)
+   local v
+   for i=1,#order do
+    v=order[i][k]
+    if v~=nil then
+     t[k]=v
+     return v
+    end
+   end
+   if v==nil then
+    v=""
+   end
+   t[k]=v
+   return v
+  end)
+  local repath=resolvers.repath
+  setmetatableindex(environment,function(t,k)
+   local v=osgetenv(k)
+   if v==nil then
+    v=variables[k]
+   end
+   if v~=nil then
+    v=checkedvariable(v) or ""
+   end
+   v=repath(v) 
+   t[k]=v
+   return v
+  end)
+  setmetatableindex(expansions,function(t,k)
+   local v=environment[k]
+   if type(v)=="string" then
+    v=lpegmatch(variableresolver,v)
+    v=lpegmatch(variablecleaner,v)
+   end
+   t[k]=v
+   return v
+  end)
+ end
+end
+function resolvers.initialized()
+ return instance~=nil
+end
+local function reset_hashes()
+ instance.lists={}
+ instance.pathlists=false
+ instance.found={}
+end
+local function reset_caches()
+ instance.lists={}
+ instance.pathlists=false
+end
+local makepathexpression  do
+ local slash=P("/")
+ local pathexpressionpattern=Cs (
+  Cc("^")*(
+   Cc("%")*S(".-")+slash^2*P(-1)/"/.*"
++slash^2/"/"+(1-slash)*P(-1)*Cc("/")+P(1)
+  )^1*Cc("$") 
+ )
+ local cache={}
+ makepathexpression=function(str)
+  if str=="." then
+   return "^%./$"
+  else
+   local c=cache[str]
+   if not c then
+    c=lpegmatch(pathexpressionpattern,str)
+    cache[str]=c
+   end
+   return c
+  end
+ end
+end
+local function reportcriticalvariables(cnfspec)
+ if trace_locating then
+  for i=1,#criticalvars do
+   local k=criticalvars[i]
+   local v=getenv(k) or "unknown" 
+   report_resolving("variable %a set to %a",k,v)
+  end
+  report_resolving()
+  if cnfspec then
+   report_resolving("using configuration specification %a",type(cnfspec)=="table" and concat(cnfspec,",") or cnfspec)
+  end
+  report_resolving()
+ end
+ reportcriticalvariables=function() end
+end
+local function identify_configuration_files()
+ local specification=instance.specification
+ if #specification==0 then
+  local cnfspec=getenv("TEXMFCNF")
+  if cnfspec=="" then
+   cnfspec=resolvers.luacnfspec
+   resolvers.luacnfstate="default"
+  else
+   resolvers.luacnfstate="environment"
+  end
+  reportcriticalvariables(cnfspec)
+  local cnfpaths=expandedpathfromlist(splitpath(cnfspec))
+  local function locatecnf(luacnfname,kind)
+   for i=1,#cnfpaths do
+    local filepath=cnfpaths[i]
+    local filename=collapsepath(filejoin(filepath,luacnfname))
+    local realname=resolveprefix(filename)
+    if trace_locating then
+     local fullpath=gsub(resolveprefix(collapsepath(filepath)),"//","/")
+     local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true)
+     report_resolving("looking for %s %a on %s path %a from specification %a",
+      kind,luacnfname,weirdpath and "weird" or "given",fullpath,filepath)
+    end
+    if isfile(realname) then
+     specification[#specification+1]=filename 
+     if trace_locating then
+      report_resolving("found %s configuration file %a",kind,realname)
+     end
+    end
+   end
+  end
+  locatecnf(resolvers.luacnfname,"regular")
+  if #specification==0 then
+   locatecnf(resolvers.luacnffallback,"fallback")
+  end
+  if trace_locating then
+   report_resolving()
+  end
+ elseif trace_locating then
+  report_resolving("configuration files already identified")
+ end
+end
+local function load_configuration_files()
+ local specification=instance.specification
+ local setups=instance.setups
+ local order=instance.order
+ if #specification>0 then
+  local luacnfname=resolvers.luacnfname
+  for i=1,#specification do
+   local filename=specification[i]
+   local pathname=filedirname(filename)
+   local filename=filejoin(pathname,luacnfname)
+   local realname=resolveprefix(filename) 
+   local blob=loadfile(realname)
+   if blob then
+    local data=blob()
+    local parent=data and data.parent
+    if parent then
+     local filename=filejoin(pathname,parent)
+     local realname=resolveprefix(filename) 
+     local blob=loadfile(realname)
+     if blob then
+      local parentdata=blob()
+      if parentdata then
+       report_resolving("loading configuration file %a",filename)
+       data=mergedtable(parentdata,data)
+      end
+     end
+    end
+    data=data and data.content
+    if data then
+     if trace_locating then
+      report_resolving("loading configuration file %a",filename)
+      report_resolving()
+     end
+     local variables=data.variables or {}
+     local warning=false
+     for k,v in next,data do
+      local variant=type(v)
+      if variant=="table" then
+       initializesetter(filename,k,v)
+      elseif variables[k]==nil then
+       if trace_locating and not warning then
+        report_resolving("variables like %a in configuration file %a should move to the 'variables' subtable",
+         k,resolveprefix(filename))
+        warning=true
+       end
+       variables[k]=v
+      end
+     end
+     setups[pathname]=variables
+     if resolvers.luacnfstate=="default" then
+      local cnfspec=variables["TEXMFCNF"]
+      if cnfspec then
+       if trace_locating then
+        report_resolving("reloading configuration due to TEXMF redefinition")
+       end
+       setenv("TEXMFCNF",cnfspec)
+       instance.specification={}
+       identify_configuration_files()
+       load_configuration_files()
+       resolvers.luacnfstate="configuration"
+       break
+      end
+     end
+    else
+     if trace_locating then
+      report_resolving("skipping configuration file %a (no content)",filename)
+     end
+     setups[pathname]={}
+     instance.loaderror=true
+    end
+   elseif trace_locating then
+    report_resolving("skipping configuration file %a (no valid format)",filename)
+   end
+   order[#order+1]=setups[pathname]
+   if instance.loaderror then
+    break
+   end
+  end
+ elseif trace_locating then
+  report_resolving("warning: no lua configuration files found")
+ end
+end
+local expandedpathlist
+local unexpandedpathlist
+function resolvers.configurationfiles()
+ return instance.specification or {}
+end
+local function load_file_databases()
+ instance.loaderror=false
+ instance.files={}
+ if not instance.renewcache then
+  local hashes=instance.hashes
+  for k=1,#hashes do
+   local hash=hashes[k]
+   resolvers.hashers.byscheme(hash.type,hash.name)
+   if instance.loaderror then break end
+  end
+ end
+end
+local function locate_file_databases()
+ local texmfpaths=expandedpathlist("TEXMF")
+ if #texmfpaths>0 then
+  for i=1,#texmfpaths do
+   local path=collapsepath(texmfpaths[i])
+   path=gsub(path,"/+$","") 
+   local stripped=lpegmatch(inhibitstripper,path) 
+   if stripped~="" then
+    local runtime=stripped==path
+    path=cleanpath(path)
+    local spec=splitmethod(stripped)
+    if runtime and (spec.noscheme or spec.scheme=="file") then
+     stripped="tree:///"..stripped
+    elseif spec.scheme=="cache" or spec.scheme=="file" then
+     stripped=spec.path
+    end
+    if trace_locating then
+     if runtime then
+      report_resolving("locating list of %a (runtime) (%s)",path,stripped)
+     else
+      report_resolving("locating list of %a (cached)",path)
+     end
+    end
+    methodhandler('locators',stripped)
+   end
+  end
+  if trace_locating then
+   report_resolving()
+  end
+ elseif trace_locating then
+  report_resolving("no texmf paths are defined (using TEXMF)")
+ end
+end
+local function generate_file_databases()
+ local hashes=instance.hashes
+ for k=1,#hashes do
+  local hash=hashes[k]
+  methodhandler('generators',hash.name)
+ end
+ if trace_locating then
+  report_resolving()
+ end
+end
+local function save_file_databases() 
+ local hashes=instance.hashes
+ local files=instance.files
+ for i=1,#hashes do
+  local hash=hashes[i]
+  local cachename=hash.name
+  if hash.cache then
+   local content=files[cachename]
+   caches.collapsecontent(content)
+   if trace_locating then
+    report_resolving("saving tree %a",cachename)
+   end
+   caches.savecontent(cachename,"files",content)
+  elseif trace_locating then
+   report_resolving("not saving runtime tree %a",cachename)
+  end
+ end
+end
+function resolvers.renew(hashname)
+ local files=instance.files
+ if hashname and hashname~="" then
+  local expanded=expansion(hashname) or ""
+  if expanded~="" then
+   if trace_locating then
+    report_resolving("identifying tree %a from %a",expanded,hashname)
+   end
+   hashname=expanded
+  else
+   if trace_locating then
+    report_resolving("identifying tree %a",hashname)
+   end
+  end
+  local realpath=resolveprefix(hashname)
+  if isdir(realpath) then
+   if trace_locating then
+    report_resolving("using path %a",realpath)
+   end
+   methodhandler('generators',hashname)
+   local content=files[hashname]
+   caches.collapsecontent(content)
+   if trace_locating then
+    report_resolving("saving tree %a",hashname)
+   end
+   caches.savecontent(hashname,"files",content)
+  else
+   report_resolving("invalid path %a",realpath)
+  end
+ end
+end
+local function load_databases()
+ locate_file_databases()
+ if instance.diskcache and not instance.renewcache then
+  load_file_databases()
+  if instance.loaderror then
+   generate_file_databases()
+   save_file_databases()
+  end
+ else
+  generate_file_databases()
+  if instance.renewcache then
+   save_file_databases()
+  end
+ end
+end
+function resolvers.appendhash(type,name,cache)
+ local hashed=instance.hashed
+ local hashes=instance.hashes
+ if hashed[name] then
+ else
+  if trace_locating then
+   report_resolving("hash %a appended",name)
+  end
+  insert(hashes,{ type=type,name=name,cache=cache } )
+  hashed[name]=cache
+ end
+end
+function resolvers.prependhash(type,name,cache)
+ local hashed=instance.hashed
+ local hashes=instance.hashes
+ if hashed[name] then
+ else
+  if trace_locating then
+   report_resolving("hash %a prepended",name)
+  end
+  insert(hashes,1,{ type=type,name=name,cache=cache } )
+  hashed[name]=cache
+ end
+end
+function resolvers.extendtexmfvariable(specification) 
+ local environment=instance.environment
+ local variables=instance.variables
+ local texmftrees=splitpath(getenv("TEXMF")) 
+ insert(texmftrees,1,specification)
+ texmftrees=concat(texmftrees,",") 
+ if environment["TEXMF"] then
+  environment["TEXMF"]=texmftrees
+ elseif variables["TEXMF"] then
+  variables["TEXMF"]=texmftrees
+ else
+ end
+ reset_hashes()
+end
+function resolvers.splitexpansions()
+ local expansions=instance.expansions
+ for k,v in next,expansions do
+  local t,tn,h,p={},0,{},splitconfigurationpath(v)
+  for kk=1,#p do
+   local vv=p[kk]
+   if vv~="" and not h[vv] then
+    tn=tn+1
+    t[tn]=vv
+    h[vv]=true
+   end
+  end
+  if tn>1 then
+   expansions[k]=t
+  else
+   expansions[k]=t[1]
+  end
+ end
+end
+function resolvers.datastate()
+ return caches.contentstate()
+end
+variable=function(name)
+ local variables=instance.variables
+ local name=name and lpegmatch(dollarstripper,name)
+ local result=name and variables[name]
+ return result~=nil and result or ""
+end
+expansion=function(name)
+ local expansions=instance.expansions
+ local name=name and lpegmatch(dollarstripper,name)
+ local result=name and expansions[name]
+ return result~=nil and result or ""
+end
+resolvers.variable=variable
+resolvers.expansion=expansion
+unexpandedpathlist=function(str)
+ local pth=variable(str)
+ local lst=splitpath(pth)
+ return expandedpathfromlist(lst)
+end
+function resolvers.unexpandedpath(str)
+ return joinpath(unexpandedpathlist(str))
+end
+function resolvers.pushpath(name)
+ local pathstack=instance.pathstack
+ local lastpath=pathstack[#pathstack]
+ local pluspath=filedirname(name)
+ if lastpath then
+  lastpath=collapsepath(filejoin(lastpath,pluspath))
+ else
+  lastpath=collapsepath(pluspath)
+ end
+ insert(pathstack,lastpath)
+ if trace_paths then
+  report_resolving("pushing path %a",lastpath)
+ end
+end
+function resolvers.poppath()
+ local pathstack=instance.pathstack
+ if trace_paths and #pathstack>0 then
+  report_resolving("popping path %a",pathstack[#pathstack])
+ end
+ remove(pathstack)
+end
+function resolvers.stackpath()
+ local pathstack=instance.pathstack
+ local currentpath=pathstack[#pathstack]
+ return currentpath~="" and currentpath or nil
+end
+local done={}
+function resolvers.resetextrapaths()
+ local extra_paths=instance.extra_paths
+ if not extra_paths then
+  done={}
+  instance.extra_paths={}
+ elseif #ep>0 then
+  done={}
+  reset_caches()
+ end
+end
+function resolvers.getextrapaths()
+ return instance.extra_paths or {}
+end
+function resolvers.registerextrapath(paths,subpaths)
+ if not subpaths or subpaths=="" then
+  if not paths or path=="" then
+   return 
+  elseif done[paths] then
+   return 
+  end
+ end
+ local paths=settings_to_array(paths)
+ local subpaths=settings_to_array(subpaths)
+ local extra_paths=instance.extra_paths or {}
+ local oldn=#extra_paths
+ local newn=oldn
+ local nofpaths=#paths
+ local nofsubpaths=#subpaths
+ if nofpaths>0 then
+  if nofsubpaths>0 then
+   for i=1,nofpaths do
+    local p=paths[i]
+    for j=1,nofsubpaths do
+     local s=subpaths[j]
+     local ps=p.."/"..s
+     if not done[ps] then
+      newn=newn+1
+      extra_paths[newn]=cleanpath(ps)
+      done[ps]=true
+     end
+    end
+   end
+  else
+   for i=1,nofpaths do
+    local p=paths[i]
+    if not done[p] then
+     newn=newn+1
+     extra_paths[newn]=cleanpath(p)
+     done[p]=true
+    end
+   end
+  end
+ elseif nofsubpaths>0 then
+  for i=1,oldn do
+   for j=1,nofsubpaths do
+    local s=subpaths[j]
+    local ps=extra_paths[i].."/"..s
+    if not done[ps] then
+     newn=newn+1
+     extra_paths[newn]=cleanpath(ps)
+     done[ps]=true
+    end
+   end
+  end
+ end
+ if newn>0 then
+  instance.extra_paths=extra_paths 
+ end
+ if newn~=oldn then
+  reset_caches()
+ end
+end
+function resolvers.pushextrapath(path)
+ local paths=settings_to_array(path)
+ local extra_stack=instance.extra_stack
+ if extra_stack then
+  insert(extra_stack,1,paths)
+ else
+  instance.extra_stack={ paths }
+ end
+ reset_caches()
+end
+function resolvers.popextrapath()
+ local extra_stack=instance.extra_stack
+ if extra_stack then
+  reset_caches()
+  return remove(extra_stack,1)
+ end
+end
+local function made_list(instance,list,extra_too)
+ local done={}
+ local new={}
+ local newn=0
+ local function add(p)
+  for k=1,#p do
+   local v=p[k]
+   if not done[v] then
+    done[v]=true
+    newn=newn+1
+    new[newn]=v
+   end
+  end
+ end
+ for k=1,#list do
+  local v=list[k]
+  if done[v] then
+  elseif find(v,"^[%.%/]$") then
+   done[v]=true
+   newn=newn+1
+   new[newn]=v
+  else
+   break
+  end
+ end
+ if extra_too then
+  local extra_stack=instance.extra_stack
+  local extra_paths=instance.extra_paths
+  if extra_stack and #extra_stack>0 then
+   for k=1,#extra_stack do
+    add(extra_stack[k])
+   end
+  end
+  if extra_paths and #extra_paths>0 then
+   add(extra_paths)
+  end
+ end
+ add(list)
+ return new
+end
+expandedpathlist=function(str,extra_too)
+ if not str then
+  return {}
+ elseif instance.savelists then 
+  str=lpegmatch(dollarstripper,str)
+  local lists=instance.lists
+  local lst=lists[str]
+  if not lst then
+   local l=made_list(instance,splitpath(expansion(str)),extra_too)
+   lst=expandedpathfromlist(l)
+   lists[str]=lst
+  end
+  return lst
+ else
+  local lst=splitpath(expansion(str))
+  return made_list(instance,expandedpathfromlist(lst),extra_too)
+ end
+end
+resolvers.expandedpathlist=expandedpathlist
+resolvers.unexpandedpathlist=unexpandedpathlist
+function resolvers.cleanpathlist(str)
+ local t=expandedpathlist(str)
+ if t then
+  for i=1,#t do
+   t[i]=collapsepath(cleanpath(t[i]))
+  end
+ end
+ return t
+end
+function resolvers.expandpath(str)
+ return joinpath(expandedpathlist(str))
+end
+local function expandedpathlistfromvariable(str) 
+ str=lpegmatch(dollarstripper,str)
+ local tmp=resolvers.variableofformatorsuffix(str)
+ return expandedpathlist(tmp~="" and tmp or str)
+end
+function resolvers.expandpathfromvariable(str)
+ return joinpath(expandedpathlistfromvariable(str))
+end
+resolvers.expandedpathlistfromvariable=expandedpathlistfromvariable
+function resolvers.cleanedpathlist(v) 
+ local t=expandedpathlist(v)
+ for i=1,#t do
+  t[i]=resolveprefix(cleanpath(t[i]))
+ end
+ return t
+end
+function resolvers.expandbraces(str) 
+ local pth=expandedpathfromlist(splitpath(str))
+ return joinpath(pth)
+end
+function resolvers.registerfilehash(name,content,someerror)
+ local files=instance.files
+ if content then
+  files[name]=content
+ else
+  files[name]={}
+  if somerror==true then 
+   instance.loaderror=someerror
+  end
+ end
+end
+function resolvers.getfilehashes()
+ return instance and instance.files or {}
+end
+function resolvers.gethashes()
+ return instance and instance.hashes or {}
+end
+function resolvers.renewcache()
+ if instance then
+  instance.renewcache=true
+ end
+end
+local function isreadable(name)
+ local readable=isfile(name) 
+ if trace_details then
+  if readable then
+   report_resolving("file %a is readable",name)
+  else
+   report_resolving("file %a is not readable",name)
+  end
+ end
+ return readable
+end
+local function collect_files(names) 
+ local filelist={}   
+ local noffiles=0
+ local function check(hash,root,pathname,path,basename,name)
+  if not pathname or find(path,pathname) then
+   local variant=hash.type
+   local search=filejoin(root,path,name) 
+   local result=methodhandler('concatinators',variant,root,path,name)
+   if trace_details then
+    report_resolving("match: variant %a, search %a, result %a",variant,search,result)
+   end
+   noffiles=noffiles+1
+   filelist[noffiles]={ variant,search,result }
+  end
+ end
+ for k=1,#names do
+  local filename=names[k]
+  if trace_details then
+   report_resolving("checking name %a",filename)
+  end
+  local basename=filebasename(filename)
+  local pathname=filedirname(filename)
+  if pathname=="" or find(pathname,"^%.") then
+   pathname=false
+  else
+   pathname=gsub(pathname,"%*",".*")
+   pathname="/"..pathname.."$"
+  end
+  local hashes=instance.hashes
+  local files=instance.files
+  for h=1,#hashes do
+   local hash=hashes[h]
+   local hashname=hash.name
+   local content=hashname and files[hashname]
+   if content then
+    if trace_details then
+     report_resolving("deep checking %a, base %a, pattern %a",hashname,basename,pathname)
+    end
+    local path,name=lookup(content,basename)
+    if path then
+     local metadata=content.metadata
+     local realroot=metadata and metadata.path or hashname
+     if type(path)=="string" then
+      check(hash,realroot,pathname,path,basename,name)
+     else
+      for i=1,#path do
+       check(hash,realroot,pathname,path[i],basename,name)
+      end
+     end
+    end
+   elseif trace_locating then
+    report_resolving("no match in %a (%s)",hashname,basename)
+   end
+  end
+ end
+ return noffiles>0 and filelist or nil
+end
+local fit={}
+function resolvers.registerintrees(filename,format,filetype,usedmethod,foundname)
+ local foundintrees=instance.foundintrees
+ if usedmethod=="direct" and filename==foundname and fit[foundname] then
+ else
+  local collapsed=collapsepath(foundname,true)
+  local t={
+   filename=filename,
+   format=format~="" and format   or nil,
+   filetype=filetype~="" and filetype or nil,
+   usedmethod=usedmethod,
+   foundname=foundname,
+   fullname=collapsed,
+  }
+  fit[foundname]=t
+  foundintrees[#foundintrees+1]=t
+ end
+end
+function resolvers.foundintrees()
+ return instance.foundintrees or {}
+end
+function resolvers.foundintree(fullname)
+ local f=fit[fullname]
+ return f and f.usedmethod=="database"
+end
+local function can_be_dir(name) 
+ local fakepaths=instance.fakepaths
+ if not fakepaths[name] then
+  if isdir(name) then
+   fakepaths[name]=1 
+  else
+   fakepaths[name]=2 
+  end
+ end
+ return fakepaths[name]==1
+end
+local preparetreepattern=Cs((P(".")/"%%."+P("-")/"%%-"+P(1))^0*Cc("$"))
+local collect_instance_files
+local function find_analyze(filename,askedformat,allresults)
+ local filetype=''
+ local filesuffix=suffixonly(filename)
+ local wantedfiles={}
+ wantedfiles[#wantedfiles+1]=filename
+ if askedformat=="" then
+  if filesuffix=="" or not suffixmap[filesuffix] then
+   local defaultsuffixes=resolvers.defaultsuffixes
+   for i=1,#defaultsuffixes do
+    local forcedname=filename..'.'..defaultsuffixes[i]
+    wantedfiles[#wantedfiles+1]=forcedname
+    filetype=formatofsuffix(forcedname)
+    if trace_locating then
+     report_resolving("forcing filetype %a",filetype)
+    end
+   end
+  else
+   filetype=formatofsuffix(filename)
+   if trace_locating then
+    report_resolving("using suffix based filetype %a",filetype)
+   end
+  end
+ else
+  if filesuffix=="" or not suffixmap[filesuffix] then
+   local format_suffixes=suffixes[askedformat]
+   if format_suffixes then
+    for i=1,#format_suffixes do
+     wantedfiles[#wantedfiles+1]=filename.."."..format_suffixes[i]
+    end
+   end
+  end
+  filetype=askedformat
+  if trace_locating then
+   report_resolving("using given filetype %a",filetype)
+  end
+ end
+ return filetype,wantedfiles
+end
+local function find_direct(filename,allresults)
+ if not dangerous[askedformat] and isreadable(filename) then
+  if trace_details then
+   report_resolving("file %a found directly",filename)
+  end
+  return "direct",{ filename }
+ end
+end
+local function find_wildcard(filename,allresults)
+ if find(filename,'*',1,true) then
+  if trace_locating then
+   report_resolving("checking wildcard %a",filename)
+  end
+  local result=resolvers.findwildcardfiles(filename)
+  if result then
+   return "wildcard",result
+  end
+ end
+end
+local function find_qualified(filename,allresults,askedformat,alsostripped) 
+ if not is_qualified_path(filename) then
+  return
+ end
+ if trace_locating then
+  report_resolving("checking qualified name %a",filename)
+ end
+ if isreadable(filename) then
+  if trace_details then
+   report_resolving("qualified file %a found",filename)
+  end
+  return "qualified",{ filename }
+ end
+ if trace_details then
+  report_resolving("locating qualified file %a",filename)
+ end
+ local forcedname,suffix="",suffixonly(filename)
+ if suffix=="" then 
+  local format_suffixes=askedformat=="" and resolvers.defaultsuffixes or suffixes[askedformat]
+  if format_suffixes then
+   for i=1,#format_suffixes do
+    local suffix=format_suffixes[i]
+    forcedname=filename.."."..suffix
+    if isreadable(forcedname) then
+     if trace_locating then
+      report_resolving("no suffix, forcing format filetype %a",suffix)
+     end
+     return "qualified",{ forcedname }
+    end
+   end
+  end
+ end
+ if alsostripped and suffix and suffix~="" then
+  local basename=filebasename(filename)
+  local pattern=lpegmatch(preparetreepattern,filename)
+  local savedformat=askedformat
+  local format=savedformat or ""
+  if format=="" then
+   askedformat=formatofsuffix(suffix)
+  end
+  if not format then
+   askedformat="othertextfiles" 
+  end
+  if basename~=filename then
+   local resolved=collect_instance_files(basename,askedformat,allresults)
+   if #resolved==0 then
+    local lowered=lower(basename)
+    if filename~=lowered then
+     resolved=collect_instance_files(lowered,askedformat,allresults)
+    end
+   end
+   resolvers.format=savedformat
+   if #resolved>0 then
+    local result={}
+    for r=1,#resolved do
+     local rr=resolved[r]
+     if find(rr,pattern) then
+      result[#result+1]=rr
+     end
+    end
+    if #result>0 then
+     return "qualified",result
+    end
+   end
+  end
+ end
+end
+local function check_subpath(fname)
+ if isreadable(fname) then
+  if trace_details then
+   report_resolving("found %a by deep scanning",fname)
+  end
+  return fname
+ end
+end
+local function makepathlist(list,filetype)
+ local typespec=resolvers.variableofformat(filetype)
+ local pathlist=expandedpathlist(typespec,filetype and usertypes[filetype]) 
+ local entry={}
+ if pathlist and #pathlist>0 then
+  for k=1,#pathlist do
+   local path=pathlist[k]
+   local prescanned=find(path,'^!!')
+   local resursive=find(path,'//$')
+   local pathname=lpegmatch(inhibitstripper,path)
+   local expression=makepathexpression(pathname)
+   local barename=gsub(pathname,"/+$","")
+   barename=resolveprefix(barename)
+   local scheme=urlhasscheme(barename)
+   local schemename=gsub(barename,"%.%*$",'')
+   entry[k]={
+    path=path,
+    pathname=pathname,
+    prescanned=prescanned,
+    recursive=recursive,
+    expression=expression,
+    barename=barename,
+    scheme=scheme,
+    schemename=schemename,
+   }
+  end
+  entry.typespec=typespec
+  list[filetype]=entry
+ else
+  list[filetype]=false
+ end
+ return entry
+end
+local function find_intree(filename,filetype,wantedfiles,allresults)
+ local pathlists=instance.pathlists
+ if not pathlists then
+  pathlists=setmetatableindex({},makepathlist)
+  instance.pathlists=pathlists
+ end
+ local pathlist=pathlists[filetype]
+ if pathlist then
+  local method="intree"
+  local filelist=collect_files(wantedfiles) 
+  local dirlist={}
+  local result={}
+  if filelist then
+   for i=1,#filelist do
+    dirlist[i]=filedirname(filelist[i][3]).."/" 
+   end
+  end
+  if trace_details then
+   report_resolving("checking filename %a in tree",filename)
+  end
+  for k=1,#pathlist do
+   local entry=pathlist[k]
+   local path=entry.path
+   local pathname=entry.pathname
+   local done=false
+   if filelist then
+    local expression=entry.expression
+    if trace_details then
+     report_resolving("using pattern %a for path %a",expression,pathname)
+    end
+    for k=1,#filelist do
+     local fl=filelist[k]
+     local f=fl[2]
+     local d=dirlist[k]
+     if find(d,expression) or find(resolveprefix(d),expression) then
+      result[#result+1]=resolveprefix(fl[3]) 
+      done=true
+      if allresults then
+       if trace_details then
+        report_resolving("match to %a in hash for file %a and path %a, continue scanning",expression,f,d)
+       end
+      else
+       if trace_details then
+        report_resolving("match to %a in hash for file %a and path %a, quit scanning",expression,f,d)
+       end
+       break
+      end
+     elseif trace_details then
+      report_resolving("no match to %a in hash for file %a and path %a",expression,f,d)
+     end
+    end
+   end
+   if done then
+    method="database"
+   else
+    method="filesystem" 
+    local scheme=entry.scheme
+    if not scheme or scheme=="file" then
+     local pname=entry.schemename
+     if not find(pname,"*",1,true) then
+      if can_be_dir(pname) then
+       if not done and not entry.prescanned then
+        if trace_details then
+         report_resolving("quick root scan for %a",pname)
+        end
+        for k=1,#wantedfiles do
+         local w=wantedfiles[k]
+         local fname=check_subpath(filejoin(pname,w))
+         if fname then
+          result[#result+1]=fname
+          done=true
+          if not allresults then
+           break
+          end
+         end
+        end
+        if not done and entry.recursive then
+         if trace_details then
+          report_resolving("scanning filesystem for %a",pname)
+         end
+         local files=resolvers.simplescanfiles(pname,false,true)
+         for k=1,#wantedfiles do
+          local w=wantedfiles[k]
+          local subpath=files[w]
+          if not subpath or subpath=="" then
+          elseif type(subpath)=="string" then
+           local fname=check_subpath(filejoin(pname,subpath,w))
+           if fname then
+            result[#result+1]=fname
+            done=true
+            if not allresults then
+             break
+            end
+           end
+          else
+           for i=1,#subpath do
+            local sp=subpath[i]
+            if sp=="" then
+            else
+             local fname=check_subpath(filejoin(pname,sp,w))
+             if fname then
+              result[#result+1]=fname
+              done=true
+              if not allresults then
+               break
+              end
+             end
+            end
+           end
+           if done and not allresults then
+            break
+           end
+          end
+         end
+        end
+       end
+      end
+     else
+     end
+    else
+     for k=1,#wantedfiles do
+      local pname=entry.barename
+      local fname=methodhandler('finders',pname.."/"..wantedfiles[k])
+      if fname then
+       result[#result+1]=fname
+       done=true
+       if not allresults then
+        break
+       end
+      end
+     end
+    end
+   end
+   if done and not allresults then
+    break
+   end
+  end
+  if #result>0 then
+   return method,result
+  end
+ end
+end
+local function find_onpath(filename,filetype,wantedfiles,allresults)
+ if trace_details then
+  report_resolving("checking filename %a, filetype %a, wanted files %a",filename,filetype,concat(wantedfiles," | "))
+ end
+ local result={}
+ for k=1,#wantedfiles do
+  local fname=wantedfiles[k]
+  if fname and isreadable(fname) then
+   filename=fname
+   result[#result+1]=filejoin('.',fname)
+   if not allresults then
+    break
+   end
+  end
+ end
+ if #result>0 then
+  return "onpath",result
+ end
+end
+local function find_otherwise(filename,filetype,wantedfiles,allresults) 
+ local filelist=collect_files(wantedfiles)
+ local fl=filelist and filelist[1]
+ if fl then
+  return "otherwise",{ resolveprefix(fl[3]) } 
+ end
+end
+collect_instance_files=function(filename,askedformat,allresults) 
+ if not filename or filename=="" then
+  return {}
+ end
+ askedformat=askedformat or ""
+ filename=collapsepath(filename,".")
+ filename=gsub(filename,"^%./",getcurrentdir().."/") 
+ if allresults then
+  local filetype,wantedfiles=find_analyze(filename,askedformat)
+  local results={
+   { find_direct   (filename,true) },
+   { find_wildcard (filename,true) },
+   { find_qualified(filename,true,askedformat) },
+   { find_intree   (filename,filetype,wantedfiles,true) },
+   { find_onpath   (filename,filetype,wantedfiles,true) },
+   { find_otherwise(filename,filetype,wantedfiles,true) },
+  }
+  local result={}
+  local status={}
+  local done={}
+  for k,r in next,results do
+   local method,list=r[1],r[2]
+   if method and list then
+    for i=1,#list do
+     local c=collapsepath(list[i])
+     if not done[c] then
+      result[#result+1]=c
+      done[c]=true
+     end
+     status[#status+1]=formatters["%-10s: %s"](method,c)
+    end
+   end
+  end
+  if trace_details then
+   report_resolving("lookup status: %s",table.serialize(status,filename))
+  end
+  return result,status
+ else
+  local method,result,stamp,filetype,wantedfiles
+  if instance.remember then
+   if askedformat=="" then
+    stamp=formatters["%s::%s"](suffixonly(filename),filename)
+   else
+    stamp=formatters["%s::%s"](askedformat,filename)
+   end
+   result=stamp and instance.found[stamp]
+   if result then
+    if trace_locating then
+     report_resolving("remembered file %a",filename)
+    end
+    return result
+   end
+  end
+  method,result=find_direct(filename)
+  if not result then
+   method,result=find_wildcard(filename)
+   if not result then
+    method,result=find_qualified(filename,false,askedformat)
+    if not result then
+     filetype,wantedfiles=find_analyze(filename,askedformat)
+     method,result=find_intree(filename,filetype,wantedfiles)
+     if not result then
+      method,result=find_onpath(filename,filetype,wantedfiles)
+      if resolve_otherwise and not result then
+       method,result=find_otherwise(filename,filetype,wantedfiles)
+      end
+     end
+    end
+   end
+  end
+  if result and #result>0 then
+   local foundname=collapsepath(result[1])
+   resolvers.registerintrees(filename,askedformat,filetype,method,foundname)
+   result={ foundname }
+  else
+   result={} 
+  end
+  if stamp then
+   if trace_locating then
+    report_resolving("remembering file %a using hash %a",filename,stamp)
+   end
+   instance.found[stamp]=result
+  end
+  return result
+ end
+end
+local function findfiles(filename,filetype,allresults)
+ if not filename or filename=="" then
+  return {}
+ end
+ if allresults==nil then
+  allresults=true
+ end
+ local result,status=collect_instance_files(filename,filetype or "",allresults)
+ if not result or #result==0 then
+  local lowered=lower(filename)
+  if filename~=lowered then
+   result,status=collect_instance_files(lowered,filetype or "",allresults)
+  end
+ end
+ return result or {},status
+end
+local function findfile(filename,filetype)
+ if not filename or filename=="" then
+  return ""
+ else
+  return findfiles(filename,filetype,false)[1] or ""
+ end
+end
+resolvers.findfiles=findfiles
+resolvers.findfile=findfile
+resolvers.find_file=findfile  
+resolvers.find_files=findfiles 
+function resolvers.findpath(filename,filetype)
+ return filedirname(findfiles(filename,filetype,false)[1] or "")
+end
+local function findgivenfiles(filename,allresults)
+ local hashes=instance.hashes
+ local files=instance.files
+ local base=filebasename(filename)
+ local result={}
+ local function okay(hash,path,name)
+  local found=methodhandler('concatinators',hash.type,hash.name,path,name)
+  if found and found~="" then
+   result[#result+1]=resolveprefix(found)
+   return not allresults
+  end
+ end
+ for k=1,#hashes do
+  local hash=hashes[k]
+  local content=files[hash.name]
+  if content then
+   local path,name=lookup(content,base)
+   if not path then
+   elseif type(path)=="string" then
+    if okay(hash,path,name) then
+     return result
+    end
+   else
+    for i=1,#path do
+     if okay(hash,path[i],name) then
+      return result
+     end
+    end
+   end
+  end
+ end
+ return result
+end
+function resolvers.findgivenfiles(filename)
+ return findgivenfiles(filename,true)
+end
+function resolvers.findgivenfile(filename)
+ return findgivenfiles(filename,false)[1] or ""
+end
+local makewildcard=Cs(
+ (P("^")^0*P("/")*P(-1)+P(-1))/".*"+(P("^")^0*P("/")/"")^0*(P("*")/".*"+P("-")/"%%-"+P(".")/"%%."+P("?")/"."+P("\\")/"/"+P(1))^0
+)
+function resolvers.wildcardpattern(pattern)
+ return lpegmatch(makewildcard,pattern) or pattern
+end
+local function findwildcardfiles(filename,allresults,result)
+ local files=instance.files
+ local hashes=instance.hashes
+ local result=result or {}
+ local base=filebasename(filename)
+ local dirn=filedirname(filename)
+ local path=lower(lpegmatch(makewildcard,dirn) or dirn)
+ local name=lower(lpegmatch(makewildcard,base) or base)
+ if find(name,"*",1,true) then
+  local function okay(found,path,base,hashname,hashtype)
+   if find(found,path) then
+    local full=methodhandler('concatinators',hashtype,hashname,found,base)
+    if full and full~="" then
+     result[#result+1]=resolveprefix(full)
+     return not allresults
+    end
+   end
+  end
+  for k=1,#hashes do
+   local hash=hashes[k]
+   local hashname=hash.name
+   local hashtype=hash.type
+   if hashname and hashtype then
+    for found,base in filtered(files[hashname],name) do
+     if type(found)=='string' then
+      if okay(found,path,base,hashname,hashtype) then
+       break
+      end
+     else
+      for i=1,#found do
+       if okay(found[i],path,base,hashname,hashtype) then
+        break
+       end
+      end
+     end
+    end
+   end
+  end
+ else
+  local function okayokay(found,path,base,hashname,hashtype)
+   if find(found,path) then
+    local full=methodhandler('concatinators',hashtype,hashname,found,base)
+    if full and full~="" then
+     result[#result+1]=resolveprefix(full)
+     return not allresults
+    end
+   end
+  end
+  for k=1,#hashes do
+   local hash=hashes[k]
+   local hashname=hash.name
+   local hashtype=hash.type
+   if hashname and hashtype then
+    local found,base=lookup(content,base)
+    if not found then
+    elseif type(found)=='string' then
+     if okay(found,path,base,hashname,hashtype) then
+      break
+     end
+    else
+     for i=1,#found do
+      if okay(found[i],path,base,hashname,hashtype) then
+       break
+      end
+     end
+    end
+   end
+  end
+ end
+ return result
+end
+function resolvers.findwildcardfiles(filename,result)
+ return findwildcardfiles(filename,true,result)
+end
+function resolvers.findwildcardfile(filename)
+ return findwildcardfiles(filename,false)[1] or ""
+end
+do
+ local starttiming=statistics.starttiming
+ local stoptiming=statistics.stoptiming
+ local elapsedtime=statistics.elapsedtime
+ function resolvers.starttiming()
+  starttiming(instance)
+ end
+ function resolvers.stoptiming()
+  stoptiming(instance)
+ end
+ function resolvers.loadtime()
+  return elapsedtime(instance)
+ end
+end
+function resolvers.automount()
+end
+function resolvers.load(option)
+ resolvers.starttiming()
+ identify_configuration_files()
+ load_configuration_files()
+ if option~="nofiles" then
+  load_databases()
+  resolvers.automount()
+ end
+ resolvers.stoptiming()
+ local files=instance.files
+ return files and next(files) and true
+end
+local function report(str)
+ if trace_locating then
+  report_resolving(str) 
+ else
+  print(str)
+ end
+end
+function resolvers.dowithfilesandreport(command,files,...) 
+ if files and #files>0 then
+  if trace_locating then
+   report('') 
+  end
+  if type(files)=="string" then
+   files={ files }
+  end
+  for f=1,#files do
+   local file=files[f]
+   local result=command(file,...)
+   if type(result)=='string' then
+    report(result)
+   else
+    for i=1,#result do
+     report(result[i]) 
+    end
+   end
+  end
+ end
+end
+function resolvers.showpath(str)  
+ return joinpath(expandedpathlist(resolvers.formatofvariable(str)))
+end
+function resolvers.registerfile(files,name,path)
+ if files[name] then
+  if type(files[name])=='string' then
+   files[name]={ files[name],path }
+  else
+   files[name]=path
+  end
+ else
+  files[name]=path
+ end
+end
+function resolvers.dowithpath(name,func)
+ local pathlist=expandedpathlist(name)
+ for i=1,#pathlist do
+  func("^"..cleanpath(pathlist[i]))
+ end
+end
+function resolvers.dowithvariable(name,func)
+ func(expandedvariable(name))
+end
+function resolvers.locateformat(name)
+ local engine=environment.ownmain or "luatex"
+ local barename=removesuffix(file.basename(name))
+ local fullname=addsuffix(barename,"fmt")
+ local fmtname=caches.getfirstreadablefile(fullname,"formats",engine) or ""
+ if fmtname=="" then
+  fmtname=findfile(fullname)
+  fmtname=cleanpath(fmtname)
+ end
+ if fmtname~="" then
+  local barename=removesuffix(fmtname)
+  local luaname=addsuffix(barename,luasuffixes.lua)
+  local lucname=addsuffix(barename,luasuffixes.luc)
+  local luiname=addsuffix(barename,luasuffixes.lui)
+  if isfile(luiname) then
+   return fmtname,luiname
+  elseif isfile(lucname) then
+   return fmtname,lucname
+  elseif isfile(luaname) then
+   return fmtname,luaname
+  end
+ end
+ return nil,nil
+end
+function resolvers.booleanvariable(str,default)
+ local b=expansion(str)
+ if b=="" then
+  return default
+ else
+  b=toboolean(b)
+  return (b==nil and default) or b
+ end
+end
+function resolvers.dowithfilesintree(pattern,handle,before,after) 
+ local hashes=instance.hashes
+ local files=instance.files
+ for i=1,#hashes do
+  local hash=hashes[i]
+  local blobtype=hash.type
+  local blobpath=hash.name
+  if blobtype and blobpath then
+   local total=0
+   local checked=0
+   local done=0
+   if before then
+    before(blobtype,blobpath,pattern)
+   end
+   for path,name in filtered(files[blobpath],pattern) do
+    if type(path)=="string" then
+     checked=checked+1
+     if handle(blobtype,blobpath,path,name) then
+      done=done+1
+     end
+    else
+     checked=checked+#path
+     for i=1,#path do
+      if handle(blobtype,blobpath,path[i],name) then
+       done=done+1
+      end
+     end
+    end
+   end
+   if after then
+    after(blobtype,blobpath,pattern,checked,done)
+   end
+  end
+ end
+end
+function resolvers.knownvariables(pattern)
+ if instance then
+  local environment=instance.environment
+  local variables=instance.variables
+  local expansions=instance.expansions
+  local order=instance.order
+  local pattern=upper(pattern or "")
+  local result={}
+  for i=1,#order do
+   for key in next,order[i] do
+    if result[key]==nil and key~="" and (pattern=="" or find(upper(key),pattern)) then
+     result[key]={
+      environment=rawget(environment,key),
+      variable=key,
+      expansion=expansions[key],
+      resolved=resolveprefix(expansions[key]),
+     }
+    end
+   end
+  end
+  return result
+ else
+  return {}
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-pre"] = package.loaded["data-pre"] or true
+
+-- original size: 5872, stripped down to: 3691
+
+if not modules then modules={} end modules ['data-pre']={
+ 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 ipairs=ipairs
+local insert,remove=table.insert,table.remove
+local resolvers=resolvers
+local prefixes=resolvers.prefixes
+local cleanpath=resolvers.cleanpath
+local findgivenfile=resolvers.findgivenfile
+local expansion=resolvers.expansion
+local getenv=resolvers.getenv 
+local basename=file.basename
+local dirname=file.dirname
+local joinpath=file.join
+local isfile=lfs.isfile
+local isdir=lfs.isdir
+prefixes.environment=function(str)
+ return cleanpath(expansion(str))
+end
+local function relative(str,n)
+ if not isfile(str) then
+  local pstr="./"..str
+  if isfile(pstr) then
+   str=pstr
+  else
+   local p="../"
+   for i=1,n or 2 do
+    local pstr=p..str
+    if isfile(pstr) then
+     str=pstr
+     break
+    else
+     p=p.."../"
+    end
+   end
+  end
+ end
+ return cleanpath(str)
+end
+local function locate(str)
+ local fullname=findgivenfile(str) or ""
+ return cleanpath(fullname~="" and fullname or str)
+end
+prefixes.relative=relative
+prefixes.locate=locate
+prefixes.auto=function(str)
+ local fullname=relative(str)
+ if not isfile(fullname) then
+  fullname=locate(str)
+ end
+ return fullname
+end
+prefixes.filename=function(str)
+ local fullname=findgivenfile(str) or ""
+ return cleanpath(basename((fullname~="" and fullname) or str)) 
+end
+prefixes.pathname=function(str)
+ local fullname=findgivenfile(str) or ""
+ return cleanpath(dirname((fullname~="" and fullname) or str))
+end
+prefixes.selfautoloc=function(str)
+ local pth=getenv('SELFAUTOLOC')
+ return cleanpath(str and joinpath(pth,str) or pth)
+end
+prefixes.selfautoparent=function(str)
+ local pth=getenv('SELFAUTOPARENT')
+ return cleanpath(str and joinpath(pth,str) or pth)
+end
+prefixes.selfautodir=function(str)
+ local pth=getenv('SELFAUTODIR')
+ return cleanpath(str and joinpath(pth,str) or pth)
+end
+prefixes.home=function(str)
+ local pth=getenv('HOME')
+ return cleanpath(str and joinpath(pth,str) or pth)
+end
+do
+ local tmppth
+ prefixes.temp=function(str)
+  if not tmppth then
+   for _,s in ipairs { "TMP","TEMP","TMPDIR","TEMPDIR" } do
+    tmppth=getenv(s)
+    if tmppth~="" and isdir(tmppth) then
+     break
+    end
+   end
+   if not tmppth or tmppth=="" then
+    tmppth="."
+   end
+  end
+  return cleanpath(str and joinpath(tmppth,str) or tmppth)
+ end
+ prefixes.texruns=function(str)
+  local pth=getenv('TEXRUNS')
+  if pth=="" then
+   pth=tmppth
+  end
+  return cleanpath(str and joinpath(pth,str) or pth)
+ end
+end
+prefixes.env=prefixes.environment
+prefixes.rel=prefixes.relative
+prefixes.loc=prefixes.locate
+prefixes.kpse=prefixes.locate
+prefixes.full=prefixes.locate
+prefixes.file=prefixes.filename
+prefixes.path=prefixes.pathname
+local inputstack={}
+local stackpath=resolvers.stackpath
+local function toppath()
+ if not inputstack then      
+  return "."
+ end
+ local pathname=dirname(inputstack[#inputstack] or "")
+ if pathname=="" then
+  return "."
+ else
+  return pathname
+ end
+end
+local function jobpath()
+ local path=stackpath()
+ if not path or path=="" then
+  return "."
+ else
+  return path
+ end
+end
+local function pushinputname(name)
+ insert(inputstack,name)
+end
+local function popinputname(name)
+ return remove(inputstack)
+end
+resolvers.toppath=toppath
+resolvers.jobpath=jobpath
+resolvers.pushinputname=pushinputname
+resolvers.popinputname=popinputname
+prefixes.toppath=function(str) return cleanpath(joinpath(toppath(),str)) end 
+prefixes.jobpath=function(str) return cleanpath(joinpath(jobpath(),str)) end 
+resolvers.setdynamic("toppath")
+resolvers.setdynamic("jobpath")
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-inp"] = package.loaded["data-inp"] or true
+
+-- original size: 1050, stripped down to: 946
+
+if not modules then modules={} end modules ['data-inp']={
+ 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 allocate=utilities.storage.allocate
+local resolvers=resolvers
+local methodhandler=resolvers.methodhandler
+local registermethod=resolvers.registermethod
+local finders=allocate { helpers={},notfound=function() end }
+local openers=allocate { helpers={},notfound=function() end }
+local loaders=allocate { helpers={},notfound=function() return false,nil,0 end }
+local tracers=allocate { helpers={},notfound=function() end }
+registermethod("finders",finders,"uri")
+registermethod("openers",openers,"uri")
+registermethod("loaders",loaders,"uri")
+registermethod("tracers",tracers,"uri")
+resolvers.finders=finders
+resolvers.openers=openers
+resolvers.loaders=loaders
+resolvers.tracers=tracers
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-out"] = package.loaded["data-out"] or true
+
+-- original size: 682, stripped down to: 579
+
+if not modules then modules={} end modules ['data-out']={
+ 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 allocate=utilities.storage.allocate
+local resolvers=resolvers
+local registermethod=resolvers.registermethod
+local savers=allocate { helpers={} }
+resolvers.savers=savers
+local cleaners=allocate { helpers={} }
+resolvers.cleaners=cleaners
+registermethod("savers",savers,"uri")
+registermethod("cleaners",cleaners,"uri")
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-fil"] = package.loaded["data-fil"] or true
+
+-- original size: 4365, stripped down to: 3452
+
+if not modules then modules={} end modules ['data-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 ioopen=io.open
+local isdir=lfs.isdir
+local trace_locating=false  trackers.register("resolvers.locating",function(v) trace_locating=v end)
+local report_files=logs.reporter("resolvers","files")
+local resolvers=resolvers
+local resolveprefix=resolvers.resolve
+local findfile=resolvers.findfile
+local scanfiles=resolvers.scanfiles
+local registerfilehash=resolvers.registerfilehash
+local appendhash=resolvers.appendhash
+local loadcachecontent=caches.loadcontent
+function resolvers.locators.file(specification)
+ local filename=specification.filename
+ local realname=resolveprefix(filename) 
+ if realname and realname~='' and isdir(realname) then
+  if trace_locating then
+   report_files("file locator %a found as %a",filename,realname)
+  end
+  appendhash('file',filename,true) 
+ elseif trace_locating then
+  report_files("file locator %a not found",filename)
+ end
+end
+function resolvers.hashers.file(specification)
+ local pathname=specification.filename
+ local content=loadcachecontent(pathname,'files')
+ registerfilehash(pathname,content,content==nil)
+end
+function resolvers.generators.file(specification)
+ local pathname=specification.filename
+ local content=scanfiles(pathname,false,true) 
+ registerfilehash(pathname,content,true)
+end
+resolvers.concatinators.file=file.join
+local finders=resolvers.finders
+local notfound=finders.notfound
+function finders.file(specification,filetype)
+ local filename=specification.filename
+ local foundname=findfile(filename,filetype)
+ if foundname and foundname~="" then
+  if trace_locating then
+   report_files("file finder: %a found",filename)
+  end
+  return foundname
+ else
+  if trace_locating then
+   report_files("file finder: %a not found",filename)
+  end
+  return notfound()
+ end
+end
+local openers=resolvers.openers
+local notfound=openers.notfound
+local overloaded=false
+local function textopener(tag,filename,f)
+ return {
+  reader=function() return f:read () end,
+  close=function() return f:close() end,
+ }
+end
+function openers.helpers.textopener(...)
+ return textopener(...)
+end
+function openers.helpers.settextopener(opener)
+ if overloaded then
+  report_files("file opener: %s overloaded","already")
+ else
+  if trace_locating then
+   report_files("file opener: %s overloaded","once")
+  end
+  overloaded=true
+  textopener=opener
+ end
+end
+function openers.file(specification,filetype)
+ local filename=specification.filename
+ if filename and filename~="" then
+  local f=ioopen(filename,"r")
+  if f then
+   if trace_locating then
+    report_files("file opener: %a opened",filename)
+   end
+   return textopener("file",filename,f)
+  end
+ end
+ if trace_locating then
+  report_files("file opener: %a not found",filename)
+ end
+ return notfound()
+end
+local loaders=resolvers.loaders
+local notfound=loaders.notfound
+function loaders.file(specification,filetype)
+ local filename=specification.filename
+ if filename and filename~="" then
+  local f=ioopen(filename,"rb")
+  if f then
+   if trace_locating then
+    report_files("file loader: %a loaded",filename)
+   end
+   local s=f:read("*a")
+   f:close()
+   if s then
+    return true,s,#s
+   end
+  end
+ end
+ if trace_locating then
+  report_files("file loader: %a not found",filename)
+ end
+ return notfound()
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-con"] = package.loaded["data-con"] or true
+
+-- original size: 5487, stripped down to: 3757
+
+if not modules then modules={} end modules ['data-con']={
+ version=1.100,
+ comment="companion to luat-lib.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local setmetatable=setmetatable
+local format,lower,gsub=string.format,string.lower,string.gsub
+local trace_cache=false  trackers.register("resolvers.cache",function(v) trace_cache=v end)
+local trace_containers=false  trackers.register("resolvers.containers",function(v) trace_containers=v end)
+local trace_storage=false  trackers.register("resolvers.storage",function(v) trace_storage=v end)
+containers=containers or {}
+local containers=containers
+containers.usecache=true
+local getwritablepath=caches.getwritablepath
+local getreadablepaths=caches.getreadablepaths
+local cacheiswritable=caches.is_writable
+local loaddatafromcache=caches.loaddata
+local savedataincache=caches.savedata
+local report_containers=logs.reporter("resolvers","containers")
+local allocated={}
+local mt={
+ __index=function(t,k)
+  if k=="writable" then
+   local writable=getwritablepath(t.category,t.subcategory) or { "." }
+   t.writable=writable
+   return writable
+  elseif k=="readables" then
+   local readables=getreadablepaths(t.category,t.subcategory) or { "." }
+   t.readables=readables
+   return readables
+  end
+ end,
+ __storage__=true
+}
+function containers.define(category,subcategory,version,enabled,reload)
+ if category and subcategory then
+  local c=allocated[category]
+  if not c then
+   c={}
+   allocated[category]=c
+  end
+  local s=c[subcategory]
+  if not s then
+   s={
+    category=category,
+    subcategory=subcategory,
+    storage={},
+    enabled=enabled,
+    reload=reload,
+    version=version or math.pi,
+    trace=false,
+   }
+   setmetatable(s,mt)
+   c[subcategory]=s
+  end
+  return s
+ end
+end
+function containers.is_usable(container,name)
+ return container.enabled and caches and cacheiswritable(container.writable,name)
+end
+function containers.is_valid(container,name)
+ if name and name~="" then
+  local storage=container.storage[name]
+  return storage and storage.cache_version==container.version
+ else
+  return false
+ end
+end
+function containers.read(container,name)
+ local storage=container.storage
+ local reload=container.reload
+ local stored=not reload and storage[name]
+ if not stored and container.enabled and caches and containers.usecache then
+  stored=loaddatafromcache(container.readables,name,container.writable)
+  if stored and stored.cache_version==container.version then
+   if trace_cache or trace_containers then
+    report_containers("action %a, category %a, name %a","load",container.subcategory,name)
+   end
+  else
+   stored=nil
+  end
+  storage[name]=stored
+ elseif stored then
+  if trace_cache or trace_containers then
+   report_containers("action %a, category %a, name %a","reuse",container.subcategory,name)
+  end
+ end
+ return stored
+end
+function containers.write(container,name,data,fast)
+ if data then
+  data.cache_version=container.version
+  if container.enabled and caches then
+   local unique=data.unique
+   local shared=data.shared
+   data.unique=nil
+   data.shared=nil
+   savedataincache(container.writable,name,data,fast)
+   if trace_cache or trace_containers then
+    report_containers("action %a, category %a, name %a","save",container.subcategory,name)
+   end
+   data.unique=unique
+   data.shared=shared
+  end
+  if trace_cache or trace_containers then
+   report_containers("action %a, category %a, name %a","store",container.subcategory,name)
+  end
+  container.storage[name]=data
+ end
+ return data
+end
+function containers.content(container,name)
+ return container.storage[name]
+end
+function containers.cleanname(name)
+ return (gsub(lower(name),"[^%w\128-\255]+","-")) 
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-use"] = package.loaded["data-use"] or true
+
+-- original size: 5806, stripped down to: 2925
+
+if not modules then modules={} end modules ['data-use']={
+ 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 format=string.format
+local trace_locating=false  trackers.register("resolvers.locating",function(v) trace_locating=v end)
+local report_mounts=logs.reporter("resolvers","mounts")
+local resolvers=resolvers
+local findfile=resolvers.findfile
+statistics.register("used config file",function() return caches.configfiles() end)
+statistics.register("used cache path",function() return caches.usedpaths() end)
+function statistics.savefmtstatus(texname,formatbanner,sourcefile,banner) 
+ local enginebanner=status.banner
+ if formatbanner and enginebanner and sourcefile then
+  local luvname=file.replacesuffix(texname,"luv") 
+  local luvdata={
+   enginebanner=enginebanner,
+   formatbanner=formatbanner,
+   sourcehash=md5.hex(io.loaddata(findfile(sourcefile)) or "unknown"),
+   sourcefile=sourcefile,
+   luaversion=LUAVERSION,
+   formatid=LUATEXFORMATID,
+   functionality=LUATEXFUNCTIONALITY,
+  }
+  io.savedata(luvname,table.serialize(luvdata,true))
+  lua.registerinitexfinalizer(function()
+   if jit then
+    logs.report("format banner","%s  lua: %s jit",banner,LUAVERSION)
+   else
+    logs.report("format banner","%s  lua: %s",banner,LUAVERSION)
+   end
+   logs.newline()
+  end,"show banner")
+ end
+end
+function statistics.checkfmtstatus(texname)
+ local enginebanner=status.banner
+ if enginebanner and texname then
+  local luvname=file.replacesuffix(texname,"luv") 
+  if lfs.isfile(luvname) then
+   local luv=dofile(luvname)
+   if luv and luv.sourcefile then
+    local sourcehash=md5.hex(io.loaddata(findfile(luv.sourcefile)) or "unknown")
+    local luvbanner=luv.enginebanner or "?"
+    if luvbanner~=enginebanner then
+     return format("engine mismatch (luv: %s <> bin: %s)",luvbanner,enginebanner)
+    end
+    local luvhash=luv.sourcehash or "?"
+    if luvhash~=sourcehash then
+     return format("source mismatch (luv: %s <> bin: %s)",luvhash,sourcehash)
+    end
+    local luvluaversion=luv.luaversion or 0
+    local engluaversion=LUAVERSION or 0
+    if luvluaversion~=engluaversion then
+     return format("lua mismatch (luv: %s <> bin: %s)",luvluaversion,engluaversion)
+    end
+    local luvfunctionality=luv.functionality or 0
+    local engfunctionality=status.development_id or 0
+    if luvfunctionality~=engfunctionality then
+     return format("functionality mismatch (luv: %s <> bin: %s)",luvfunctionality,engfunctionality)
+    end
+    local luvformatid=luv.formatid or 0
+    local engformatid=status.format_id or 0
+    if luvformatid~=engformatid then
+     return format("formatid mismatch (luv: %s <> bin: %s)",luvformatid,engformatid)
+    end
+   else
+    return "invalid status file"
+   end
+  else
+   return "missing status file"
+  end
+ end
+ return true
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-zip"] = package.loaded["data-zip"] or true
+
+-- original size: 10805, stripped down to: 7951
+
+if not modules then modules={} end modules ['data-zip']={
+ 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 format,find,match=string.format,string.find,string.match
+local trace_locating=false  trackers.register("resolvers.locating",function(v) trace_locating=v end)
+local report_zip=logs.reporter("resolvers","zip")
+local resolvers=resolvers
+local findfile=resolvers.findfile
+local registerfile=resolvers.registerfile
+local splitmethod=resolvers.splitmethod
+local prependhash=resolvers.prependhash
+local starttiming=resolvers.starttiming
+local extendtexmf=resolvers.extendtexmfvariable
+local stoptiming=resolvers.stoptiming
+local urlquery=url.query
+zip=zip or {}
+local zip=zip
+local archives=zip.archives or {}
+zip.archives=archives
+local registeredfiles=zip.registeredfiles or {}
+zip.registeredfiles=registeredfiles
+local zipfiles=utilities.zipfiles
+local openzip,closezip,validfile,wholefile,filehandle,traversezip
+if zipfiles then
+ local ipairs=ipairs
+ openzip=zipfiles.open
+ closezip=zipfiles.close
+ validfile=zipfiles.found
+ wholefile=zipfiles.unzip
+ local listzip=zipfiles.list
+ traversezip=function(zfile)
+  return ipairs(listzip(zfile))
+ end
+ local streams=utilities.streams
+ local openstream=streams.open
+ local readstring=streams.readstring
+ local streamsize=streams.size
+ local metatable={ 
+  close=streams.close,
+  read=function(stream,n)
+   readstring(stream,n=="*a" and streamsize(stream) or n) 
+  end
+ }
+ filehandle=function(zfile,queryname)
+  local data=wholefile(zfile,queryname)
+  if data then
+   local stream=openstream(data)
+   if stream then
+    return setmetatableindex(stream,metatable)
+   end
+  end
+ end
+else
+ openzip=zip.open
+ closezip=zip.close
+ validfile=function(zfile,queryname)
+  local dfile=zfile:open(queryname)
+  if dfile then
+   dfile:close()
+   return true
+  end
+  return false
+ end
+ traversezip=function(zfile)
+  return z:files()
+ end
+ wholefile=function(zfile,queryname)
+  local dfile=zfile:open(queryname)
+  if dfile then
+   local s=dfile:read("*all")
+   dfile:close()
+   return s
+  end
+ end
+ filehandle=function(zfile,queryname)
+  local dfile=zfile:open(queryname)
+  if dfile then
+   return dfile
+  end
+ end
+end
+local function validzip(str) 
+ if not find(str,"^zip://") then
+  return "zip:///"..str
+ else
+  return str
+ end
+end
+local function openarchive(name)
+ if not name or name=="" then
+  return nil
+ else
+  local arch=archives[name]
+  if not arch then
+     local full=findfile(name) or ""
+     arch=full~="" and openzip(full) or false
+     archives[name]=arch
+  end
+    return arch
+ end
+end
+local function closearchive(name)
+ if not name or (name=="" and archives[name]) then
+  closezip(archives[name])
+  archives[name]=nil
+ end
+end
+zip.openarchive=openarchive
+zip.closearchive=closearchive
+function resolvers.locators.zip(specification)
+ local archive=specification.filename
+ local zipfile=archive and archive~="" and openarchive(archive) 
+ if trace_locating then
+  if zipfile then
+   report_zip("locator: archive %a found",archive)
+  else
+   report_zip("locator: archive %a not found",archive)
+  end
+ end
+end
+function resolvers.concatinators.zip(zipfile,path,name) 
+ if not path or path=="" then
+  return format('%s?name=%s',zipfile,name)
+ else
+  return format('%s?name=%s/%s',zipfile,path,name)
+ end
+end
+local finders=resolvers.finders
+local notfound=finders.notfound
+function finders.zip(specification)
+ local original=specification.original
+ local archive=specification.filename
+ if archive then
+  local query=urlquery(specification.query)
+  local queryname=query.name
+  if queryname then
+   local zfile=openarchive(archive)
+   if zfile then
+    if trace_locating then
+     report_zip("finder: archive %a found",archive)
+    end
+    if validfile(zfile,queryname) then
+     if trace_locating then
+      report_zip("finder: file %a found",queryname)
+     end
+     return specification.original
+    elseif trace_locating then
+     report_zip("finder: file %a not found",queryname)
+    end
+   elseif trace_locating then
+    report_zip("finder: unknown archive %a",archive)
+   end
+  end
+ end
+ if trace_locating then
+  report_zip("finder: %a not found",original)
+ end
+ return notfound()
+end
+local openers=resolvers.openers
+local notfound=openers.notfound
+local textopener=openers.helpers.textopener
+function openers.zip(specification)
+ local original=specification.original
+ local archive=specification.filename
+ if archive then
+  local query=urlquery(specification.query)
+  local queryname=query.name
+  if queryname then
+   local zfile=openarchive(archive)
+   if zfile then
+    if trace_locating then
+     report_zip("opener; archive %a opened",archive)
+    end
+    local handle=filehandle(zfile,queryname)
+    if handle then
+     if trace_locating then
+      report_zip("opener: file %a found",queryname)
+     end
+     return textopener('zip',original,handle)
+    elseif trace_locating then
+     report_zip("opener: file %a not found",queryname)
+    end
+   elseif trace_locating then
+    report_zip("opener: unknown archive %a",archive)
+   end
+  end
+ end
+ if trace_locating then
+  report_zip("opener: %a not found",original)
+ end
+ return notfound()
+end
+local loaders=resolvers.loaders
+local notfound=loaders.notfound
+function loaders.zip(specification)
+ local original=specification.original
+ local archive=specification.filename
+ if archive then
+  local query=urlquery(specification.query)
+  local queryname=query.name
+  if queryname then
+   local zfile=openarchive(archive)
+   if zfile then
+    if trace_locating then
+     report_zip("loader: archive %a opened",archive)
+    end
+    local data=wholefile(zfile,queryname)
+    if data then
+     if trace_locating then
+      report_zip("loader; file %a loaded",original)
+     end
+     return true,data,#data
+    elseif trace_locating then
+     report_zip("loader: file %a not found",queryname)
+    end
+   elseif trace_locating then
+    report_zip("loader; unknown archive %a",archive)
+   end
+  end
+ end
+ if trace_locating then
+  report_zip("loader: %a not found",original)
+ end
+ return notfound()
+end
+local function registerzipfile(z,tree)
+ local names={}
+ local files={} 
+ local remap={} 
+ local n=0
+ local filter=tree=="" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree)
+ if trace_locating then
+  report_zip("registering: using filter %a",filter)
+ end
+ starttiming()
+ for i in traversezip(z) do
+  local filename=i.filename
+  local path,name=match(filename,filter)
+  if not path then
+   n=n+1
+   registerfile(names,filename,"")
+   local usedname=lower(filename)
+   files[usedname]=""
+   if usedname~=filename then
+    remap[usedname]=filename
+   end
+  elseif name and name~="" then
+   n=n+1
+   register(names,name,path)
+   local usedname=lower(name)
+   files[usedname]=path
+   if usedname~=name then
+    remap[usedname]=name
+   end
+  else
+  end
+ end
+ stoptiming()
+ report_zip("registering: %s files registered",n)
+ return {
+  files=files,
+  remap=remap,
+ }
+end
+local function usezipfile(archive)
+ local specification=splitmethod(archive) 
+ local archive=specification.filename
+ if archive and not registeredfiles[archive] then
+  local z=openarchive(archive)
+  if z then
+   local tree=urlquery(specification.query).tree or ""
+   if trace_locating then
+    report_zip("registering: archive %a",archive)
+   end
+   prependhash('zip',archive)
+   extendtexmf(archive) 
+   registeredfiles[archive]=z
+   registerfilehash(archive,registerzipfile(z,tree))
+  elseif trace_locating then
+   report_zip("registering: unknown archive %a",archive)
+  end
+ elseif trace_locating then
+  report_zip("registering: archive %a not found",archive)
+ end
+end
+resolvers.usezipfile=usezipfile
+resolvers.registerzipfile=registerzipfile
+function resolvers.hashers.zip(specification)
+ local archive=specification.filename
+ if trace_locating then
+  report_zip("loading file %a",archive)
+ end
+ usezipfile(specification.original)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-tre"] = package.loaded["data-tre"] or true
+
+-- original size: 10802, stripped down to: 6619
+
+if not modules then modules={} end modules ['data-tre']={
+ 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 find,gsub,lower=string.find,string.gsub,string.lower
+local basename,dirname,joinname=file.basename,file.dirname,file.join
+local globdir,isdir,isfile=dir.glob,lfs.isdir,lfs.isfile
+local P,lpegmatch=lpeg.P,lpeg.match
+local trace_locating=false  trackers.register("resolvers.locating",function(v) trace_locating=v end)
+local report_trees=logs.reporter("resolvers","trees")
+local resolvers=resolvers
+local finders=resolvers.finders
+local openers=resolvers.openers
+local loaders=resolvers.loaders
+local locators=resolvers.locators
+local hashers=resolvers.hashers
+local generators=resolvers.generators
+do
+ local collectors={}
+ local found={}
+ local notfound=finders.notfound
+ function finders.tree(specification) 
+  local spec=specification.filename
+  local okay=found[spec]
+  if okay==nil then
+   if spec~="" then
+    local path=dirname(spec)
+    local name=basename(spec)
+    if path=="" then
+     path="."
+    end
+    local names=collectors[path]
+    if not names then
+     local pattern=find(path,"/%*+$") and path or (path.."/*")
+     names=globdir(pattern)
+     collectors[path]=names
+    end
+    local pattern="/"..gsub(name,"([%.%-%+])","%%%1").."$"
+    for i=1,#names do
+     local fullname=names[i]
+     if find(fullname,pattern) then
+      found[spec]=fullname
+      return fullname
+     end
+    end
+    local pattern=lower(pattern)
+    for i=1,#names do
+     local fullname=lower(names[i])
+     if find(fullname,pattern) then
+      if isfile(fullname) then
+       found[spec]=fullname
+       return fullname
+      else
+       break
+      end
+     end
+    end
+   end
+   okay=notfound() 
+   found[spec]=okay
+  end
+  return okay
+ end
+end
+do
+ local resolveprefix=resolvers.resolve
+ local appendhash=resolvers.appendhash
+ local function dolocate(specification)
+  local name=specification.filename
+  local realname=resolveprefix(name) 
+  if realname and realname~='' and isdir(realname) then
+   if trace_locating then
+    report_trees("locator %a found",realname)
+   end
+   appendhash('tree',name,false) 
+  elseif trace_locating then
+   report_trees("locator %a not found",name)
+  end
+ end
+ locators.tree=dolocate
+ locators.dirlist=dolocate
+ locators.dirfile=dolocate
+end
+do
+ local filegenerator=generators.file
+ generators.dirlist=filegenerator
+ generators.dirfile=filegenerator
+end
+do
+ local filegenerator=generators.file
+ local methodhandler=resolvers.methodhandler
+ local function dohash(specification)
+  local name=specification.filename
+  if trace_locating then
+   report_trees("analyzing %a",name)
+  end
+  methodhandler("hashers",name)
+  filegenerator(specification)
+ end
+ hashers.tree=dohash
+ hashers.dirlist=dohash
+ hashers.dirfile=dohash
+end
+local resolve  do
+ local collectors={}
+ local splitter=lpeg.splitat("/**/")
+ local stripper=lpeg.replacer { [P("/")*P("*")^1*P(-1)]="" }
+ local loadcontent=caches.loadcontent
+ local savecontent=caches.savecontent
+ local notfound=finders.notfound
+ local scanfiles=resolvers.scanfiles
+ local lookup=resolvers.get_from_content
+ table.setmetatableindex(collectors,function(t,k)
+  local rootname=lpegmatch(stripper,k)
+  local dataname=joinname(rootname,"dirlist")
+  local content=loadcontent(dataname,"files",dataname)
+  if not content then
+   content=scanfiles(rootname,nil,nil,false,true) 
+   savecontent(dataname,"files",content,dataname)
+  end
+  t[k]=content
+  return content
+ end)
+ local function checked(root,p,n)
+  if p then
+   if type(p)=="table" then
+    for i=1,#p do
+     local fullname=joinname(root,p[i],n)
+     if isfile(fullname) then 
+      return fullname
+     end
+    end
+   else
+    local fullname=joinname(root,p,n)
+    if isfile(fullname) then 
+     return fullname
+    end
+   end
+  end
+  return notfound()
+ end
+ resolve=function(specification) 
+  local filename=specification.filename
+  if filename~="" then
+   local root,rest=lpegmatch(splitter,filename)
+   if root and rest then
+    local path,name=dirname(rest),basename(rest)
+    if name~=rest then
+     local content=collectors[root]
+     local p,n=lookup(content,name)
+     if not p then
+      return notfound()
+     end
+     local pattern=".*/"..path.."$"
+     local istable=type(p)=="table"
+     if istable then
+      for i=1,#p do
+       local pi=p[i]
+       if pi==path or find(pi,pattern) then
+        local fullname=joinname(root,pi,n)
+        if isfile(fullname) then 
+         return fullname
+        end
+       end
+      end
+     elseif p==path or find(p,pattern) then
+      local fullname=joinname(root,p,n)
+      if isfile(fullname) then 
+       return fullname
+      end
+     end
+     local queries=specification.queries
+     if queries and queries.option=="fileonly" then
+      return checked(root,p,n)
+     else
+      return notfound()
+     end
+    end
+   end
+   local path=dirname(filename)
+   local name=basename(filename)
+   local root=lpegmatch(stripper,path)
+   local content=collectors[path]
+   local p,n=lookup(content,name)
+   if p then
+    return checked(root,p,n)
+   end
+  end
+  return notfound()
+ end
+ finders.dirlist=resolve
+ function finders.dirfile(specification)
+  local queries=specification.queries
+  if queries then
+   queries.option="fileonly"
+  else
+   specification.queries={ option="fileonly" }
+  end
+  return resolve(specification)
+ end
+end
+do
+ local fileopener=openers.file
+ local fileloader=loaders.file
+ openers.dirlist=fileopener
+ loaders.dirlist=fileloader
+ openers.dirfile=fileopener
+ loaders.dirfile=fileloader
+end
+do
+ local hashfile="dirhash.lua"
+ local kind="HASH256"
+ local version=1.0
+ local loadtable=table.load
+ local savetable=table.save
+ local loaddata=io.loaddata
+ function resolvers.dirstatus(patterns)
+  local t=type(patterns)
+  if t=="string" then
+   patterns={ patterns }
+  elseif t~="table" then
+   return false
+  end
+  local status=loadtable(hashfile)
+  if not status or status.version~=version or status.kind~=kind then
+   status={
+    version=1.0,
+    kind=kind,
+    hashes={},
+   }
+  end
+  local hashes=status.hashes
+  local changed={}
+  local action=sha2[kind]
+  local update={}
+  for i=1,#patterns do
+   local pattern=patterns[i]
+   local files=globdir(pattern)
+   for i=1,#files do
+    local name=files[i]
+    local hash=action(loaddata(name))
+    if hashes[name]~=hash then
+     changed[#changed+1]=name
+    end
+    update[name]=hash
+   end
+  end
+  status.hashes=update
+  savetable(hashfile,status)
+  return #changed>0 and changed or false
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-sch"] = package.loaded["data-sch"] or true
+
+-- original size: 6945, stripped down to: 5408
+
+if not modules then modules={} end modules ['data-sch']={
+ 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 load,tonumber=load,tonumber
+local gsub,format=string.gsub,string.format
+local sortedhash,concat=table.sortedhash,table.concat
+local finders,openers,loaders=resolvers.finders,resolvers.openers,resolvers.loaders
+local addsuffix,suffix,splitbase=file.addsuffix,file.suffix,file.splitbase
+local md5hex=md5.hex
+local trace_schemes=false  trackers.register("resolvers.schemes",function(v) trace_schemes=v end)
+local report_schemes=logs.reporter("resolvers","schemes")
+local http=require("socket.http")
+local ltn12=require("ltn12")
+if mbox then mbox=nil end 
+local resolvers=resolvers
+local schemes=resolvers.schemes or {}
+resolvers.schemes=schemes
+local cleaners={}
+schemes.cleaners=cleaners
+local threshold=24*60*60
+directives.register("schemes.threshold",function(v) threshold=tonumber(v) or threshold end)
+function cleaners.none(specification)
+ return specification.original
+end
+function cleaners.strip(specification) 
+ local path,name=splitbase(specification.original)
+ if path=="" then
+  return (gsub(name,"[^%a%d%.]+","-"))
+ else
+  return (gsub((gsub(path,"%.","-").."-"..name),"[^%a%d%.]+","-"))
+ end
+end
+function cleaners.md5(specification)
+ return addsuffix(md5hex(specification.original),suffix(specification.path))
+end
+local cleaner=cleaners.strip
+directives.register("schemes.cleanmethod",function(v) cleaner=cleaners[v] or cleaners.strip end)
+function resolvers.schemes.cleanname(specification)
+ local hash=cleaner(specification)
+ if trace_schemes then
+  report_schemes("hashing %a to %a",specification.original,hash)
+ end
+ return hash
+end
+local cached={}
+local loaded={}
+local reused={}
+local thresholds={}
+local handlers={}
+local runner=sandbox.registerrunner {
+ name="curl resolver",
+ method="execute",
+ program="curl",
+ template='--silent --insecure --create-dirs --output "%cachename%" "%original%"',
+ checkers={
+  cachename="cache",
+  original="url",
+ }
+}
+local function fetch(specification)
+ local original=specification.original
+ local scheme=specification.scheme
+ local cleanname=schemes.cleanname(specification)
+ local cachename=caches.setfirstwritablefile(cleanname,"schemes")
+ if not cached[original] then
+  statistics.starttiming(schemes)
+  if not io.exists(cachename) or (os.difftime(os.time(),lfs.attributes(cachename).modification)>(thresholds[protocol] or threshold)) then
+   cached[original]=cachename
+   local handler=handlers[scheme]
+   if handler then
+    if trace_schemes then
+     report_schemes("fetching %a, protocol %a, method %a",original,scheme,"built-in")
+    end
+    logs.flush()
+    handler(specification,cachename)
+   else
+    if trace_schemes then
+     report_schemes("fetching %a, protocol %a, method %a",original,scheme,"curl")
+    end
+    logs.flush()
+    runner {
+     original=original,
+     cachename=cachename,
+    }
+   end
+  end
+  if io.exists(cachename) then
+   cached[original]=cachename
+   if trace_schemes then
+    report_schemes("using cached %a, protocol %a, cachename %a",original,scheme,cachename)
+   end
+  else
+   cached[original]=""
+   if trace_schemes then
+    report_schemes("using missing %a, protocol %a",original,scheme)
+   end
+  end
+  loaded[scheme]=loaded[scheme]+1
+  statistics.stoptiming(schemes)
+ else
+  if trace_schemes then
+   report_schemes("reusing %a, protocol %a",original,scheme)
+  end
+  reused[scheme]=reused[scheme]+1
+ end
+ return cached[original]
+end
+local function finder(specification,filetype)
+ return resolvers.methodhandler("finders",fetch(specification),filetype)
+end
+local opener=openers.file
+local loader=loaders.file
+local function install(scheme,handler,newthreshold)
+ handlers  [scheme]=handler
+ loaded [scheme]=0
+ reused [scheme]=0
+ finders   [scheme]=finder
+ openers   [scheme]=opener
+ loaders   [scheme]=loader
+ thresholds[scheme]=newthreshold or threshold
+end
+schemes.install=install
+local function http_handler(specification,cachename)
+ local tempname=cachename..".tmp"
+ local handle=io.open(tempname,"wb")
+ local status,message=http.request {
+  url=specification.original,
+  sink=ltn12.sink.file(handle)
+ }
+ if not status then
+  os.remove(tempname)
+ else
+  os.remove(cachename)
+  os.rename(tempname,cachename)
+ end
+ return cachename
+end
+install('http',http_handler)
+install('https') 
+install('ftp')
+statistics.register("scheme handling time",function()
+ local l,r,nl,nr={},{},0,0
+ for k,v in sortedhash(loaded) do
+  if v>0 then
+   nl=nl+1
+   l[nl]=k..":"..v
+  end
+ end
+ for k,v in sortedhash(reused) do
+  if v>0 then
+   nr=nr+1
+   r[nr]=k..":"..v
+  end
+ end
+ local n=nl+nr
+ if n>0 then
+  if nl==0 then l={ "none" } end
+  if nr==0 then r={ "none" } end
+  return format("%s seconds, %s processed, threshold %s seconds, loaded: %s, reused: %s",
+   statistics.elapsedtime(schemes),n,threshold,concat(l," "),concat(l," "))
+ else
+  return nil
+ end
+end)
+local httprequest=http.request
+local toquery=url.toquery
+local function fetchstring(url,data)
+ local q=data and toquery(data)
+ if q then
+  url=url.."?"..q
+ end
+ local reply=httprequest(url)
+ return reply 
+end
+schemes.fetchstring=fetchstring
+function schemes.fetchtable(url,data)
+ local reply=fetchstring(url,data)
+ if reply then
+  local s=load("return "..reply)
+  if s then
+   return s()
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-lua"] = package.loaded["data-lua"] or true
+
+-- original size: 4227, stripped down to: 3049
+
+if not modules then modules={} end modules ['data-lua']={
+ version=1.001,
+ comment="companion to luat-lib.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local package,lpeg=package,lpeg
+local loadfile=loadfile
+local addsuffix=file.addsuffix
+local P,S,Cs,lpegmatch=lpeg.P,lpeg.S,lpeg.Cs,lpeg.match
+local luasuffixes={ 'tex','lua' }
+local libsuffixes={ 'lib' }
+local luaformats={ 'TEXINPUTS','LUAINPUTS' }
+local libformats={ 'CLUAINPUTS' }
+local helpers=package.helpers or {}
+local methods=helpers.methods or {}
+local resolvers=resolvers
+local resolveprefix=resolvers.resolve
+local expandedpaths=resolvers.expandedpathlistfromvariable
+local findfile=resolvers.findfile
+helpers.report=logs.reporter("resolvers","libraries")
+trackers.register("resolvers.libraries",function(v) helpers.trace=v end)
+trackers.register("resolvers.locating",function(v) helpers.trace=v end)
+helpers.sequence={
+ "already loaded",
+ "preload table",
+ "lua variable format",
+ "lib variable format",
+ "lua extra list",
+ "lib extra list",
+ "path specification",
+ "cpath specification",
+ "all in one fallback",
+ "not loaded",
+}
+local pattern=Cs(P("!")^0/""*(P("/")*P(-1)/"/"+P("/")^1/"/"+1)^0)
+function helpers.cleanpath(path) 
+ return resolveprefix(lpegmatch(pattern,path))
+end
+local loadedaslib=helpers.loadedaslib
+local registerpath=helpers.registerpath
+local lualibfile=helpers.lualibfile
+local luaformatpaths
+local libformatpaths
+local function getluaformatpaths()
+ if not luaformatpaths then
+  luaformatpaths={}
+  for i=1,#luaformats do
+   registerpath("lua format","lua",luaformatpaths,expandedpaths(luaformats[i]))
+  end
+ end
+ return luaformatpaths
+end
+local function getlibformatpaths()
+ if not libformatpaths then
+  libformatpaths={}
+  for i=1,#libformats do
+   registerpath("lib format","lib",libformatpaths,expandedpaths(libformats[i]))
+  end
+ end
+ return libformatpaths
+end
+local function loadedbyformat(name,rawname,suffixes,islib,what)
+ local trace=helpers.trace
+ local report=helpers.report
+ for i=1,#suffixes do 
+  local format=suffixes[i]
+  local resolved=findfile(name,format) or ""
+  if trace then
+   report("%s format, identifying %a using format %a",what,name,format)
+  end
+  if resolved~="" then
+   if trace then
+    report("%s format, %a found on %a",what,name,resolved)
+   end
+   if islib then
+    return loadedaslib(resolved,rawname)
+   else
+    return loadfile(resolved)
+   end
+  end
+ end
+end
+helpers.loadedbyformat=loadedbyformat
+methods["lua variable format"]=function(name)
+ if helpers.trace then
+  helpers.report("%s format, checking %s paths","lua",#getluaformatpaths()) 
+ end
+ return loadedbyformat(addsuffix(lualibfile(name),"lua"),name,luasuffixes,false,"lua")
+end
+methods["lib variable format"]=function(name)
+ if helpers.trace then
+  helpers.report("%s format, checking %s paths","lib",#getlibformatpaths()) 
+ end
+ return loadedbyformat(addsuffix(lualibfile(name),os.libsuffix),name,libsuffixes,true,"lib")
+end
+resolvers.loadlualib=require 
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-aux"] = package.loaded["data-aux"] or true
+
+-- original size: 2610, stripped down to: 2019
+
+if not modules then modules={} end modules ['data-aux']={
+ 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 find=string.find
+local type,next=type,next
+local addsuffix,removesuffix=file.addsuffix,file.removesuffix
+local loaddata,savedata=io.loaddata,io.savedata
+local trace_locating=false  trackers.register("resolvers.locating",function(v) trace_locating=v end)
+local resolvers=resolvers
+local cleanpath=resolvers.cleanpath
+local findfiles=resolvers.findfiles
+local report_scripts=logs.reporter("resolvers","scripts")
+function resolvers.updatescript(oldname,newname)
+ local scriptpath="context/lua"
+ local oldscript=cleanpath(oldname)
+ local newname=addsuffix(newname,"lua")
+ local newscripts=findfiles(newname) or {}
+ if trace_locating then
+  report_scripts("to be replaced old script %a",oldscript)
+ end
+ if #newscripts==0 then
+  if trace_locating then
+   report_scripts("unable to locate new script")
+  end
+ else
+  for i=1,#newscripts do
+   local newscript=cleanpath(newscripts[i])
+   if trace_locating then
+    report_scripts("checking new script %a",newscript)
+   end
+   if oldscript==newscript then
+    if trace_locating then
+     report_scripts("old and new script are the same")
+    end
+   elseif not find(newscript,scriptpath,1,true) then
+    if trace_locating then
+     report_scripts("new script should come from %a",scriptpath)
+    end
+   elseif not (find(oldscript,removesuffix(newname).."$") or find(oldscript,newname.."$")) then
+    if trace_locating then
+     report_scripts("invalid new script name")
+    end
+   else
+    local newdata=loaddata(newscript)
+    if newdata then
+     if trace_locating then
+      report_scripts("old script content replaced by new content: %s",oldscript)
+     end
+     savedata(oldscript,newdata)
+     break
+    elseif trace_locating then
+     report_scripts("unable to load new script")
+    end
+   end
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-tmf"] = package.loaded["data-tmf"] or true
+
+-- original size: 2601, stripped down to: 1549
+
+if not modules then modules={} end modules ['data-tmf']={
+ 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 resolvers=resolvers
+local report_tds=logs.reporter("resolvers","tds")
+function resolvers.load_tree(tree,resolve)
+ if type(tree)=="string" and tree~="" then
+  local getenv,setenv=resolvers.getenv,resolvers.setenv
+  local texos="texmf-"..os.platform
+  local oldroot=environment.texroot
+  local newroot=file.collapsepath(tree)
+  local newtree=file.join(newroot,texos)
+  local newpath=file.join(newtree,"bin")
+  if not lfs.isdir(newtree) then
+   report_tds("no %a under tree %a",texos,tree)
+   os.exit()
+  end
+  if not lfs.isdir(newpath) then
+   report_tds("no '%s/bin' under tree %a",texos,tree)
+   os.exit()
+  end
+  local texmfos=newtree
+  environment.texroot=newroot
+  environment.texos=texos
+  environment.texmfos=texmfos
+  if resolve then
+   resolvers.luacnfspec=resolvers.resolve(resolvers.luacnfspec)
+  end
+  setenv('SELFAUTOPARENT',newroot)
+  setenv('SELFAUTODIR',newtree)
+  setenv('SELFAUTOLOC',newpath)
+  setenv('TEXROOT',newroot)
+  setenv('TEXOS',texos)
+  setenv('TEXMFOS',texmfos)
+  setenv('TEXMFCNF',resolvers.luacnfspec,true) 
+  setenv('PATH',newpath..io.pathseparator..getenv('PATH'))
+  report_tds("changing from root %a to %a",oldroot,newroot)
+  report_tds("prepending %a to PATH",newpath)
+  report_tds("setting TEXMFCNF to %a",resolvers.luacnfspec)
+  report_tds()
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-lst"] = package.loaded["data-lst"] or true
+
+-- original size: 2038, stripped down to: 1696
+
+if not modules then modules={} end modules ['data-lst']={
+ 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 sortedhash=table.sortedhash
+local isdir=lfs.isdir
+local resolvers=resolvers
+local listers=resolvers.listers or {}
+resolvers.listers=listers
+local resolveprefix=resolvers.resolve
+local configurationfiles=resolvers.configurationfiles
+local expandedpathfromlist=resolvers.expandedpathfromlist
+local splitpath=resolvers.splitpath
+local knownvariables=resolvers.knownvariables
+local report_lists=logs.reporter("resolvers","lists")
+local report_resolved=logs.reporter("system","resolved")
+local function tabstr(str)
+ if not str then
+  return "unset"
+ elseif type(str)=='table' then
+  return concat(str," | ")
+ else
+  return str
+ end
+end
+function listers.variables(pattern)
+ local result=resolvers.knownvariables(pattern)
+ for key,value in sortedhash(result) do
+  report_lists(key)
+  report_lists("  env: %s",tabstr(value.environment))
+  report_lists("  var: %s",tabstr(value.variable))
+  report_lists("  exp: %s",tabstr(value.expansion))
+  report_lists("  res: %s",tabstr(value.resolved))
+ end
+end
+function listers.configurations()
+ local configurations=configurationfiles()
+ for i=1,#configurations do
+  report_resolved("file : %s",resolveprefix(configurations[i]))
+ end
+ report_resolved("")
+ local list=expandedpathfromlist(splitpath(resolvers.luacnfspec))
+ for i=1,#list do
+  local li=resolveprefix(list[i])
+  if isdir(li) then
+   report_resolved("path - %s",li)
+  else
+   report_resolved("path + %s",li)
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["libs-ini"] = package.loaded["libs-ini"] or true
+
+-- original size: 6524, stripped down to: 4064
+
+if not modules then modules={} end modules ['libs-ini']={
+ 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,unpack=type,unpack
+local find=string.find
+local nameonly=file.nameonly
+local joinfile=file.join
+local addsuffix=file.addsuffix
+local qualifiedpath=file.is_qualified_path
+local isfile=lfs.isfile
+local findfile=resolvers.findfile
+local expandpaths=resolvers.expandedpathlistfromvariable
+local report=logs.reporter("resolvers","libraries")
+local trace=false
+local silent=false
+trackers.register("resolvers.lib",function(v) trace=v end)
+trackers.register("resolvers.lib.silent",function(v) silent=v end)
+local function findlib(required) 
+ local suffix=os.libsuffix or "so"
+ if not qualifiedpath(required) then
+  local list=directives.value("system.librarynames" )
+  local only=nameonly(required)
+  if type(list)=="table" then
+   list=list[only]
+   if type(list)~="table" then
+    list={ only }
+   end
+  else
+   list={ only }
+  end
+  if trace then
+   report("using lookup list for library %a: % | t",only,list)
+  end
+  for i=1,#list do
+   local name=list[i]
+   local found=findfile(name,"lib")
+   if not found or found=="" then
+    found=findfile(addsuffix(name,suffix),"lib")
+   end
+   if found and found~="" then
+    if trace then
+     report("library %a resolved via %a path to %a",name,"tds lib",found)
+    end
+    return found
+   end
+  end
+  if expandpaths then
+   local list=expandpaths("PATH")
+   local base=addsuffix(only,suffix)
+   for i=1,#list do
+    local full=joinfile(list[i],base)
+    local found=isfile(full) and full
+    if found and found~="" then
+     if trace then
+      report("library %a resolved via %a path to %a",full,"system",found)
+     end
+     return found
+    end
+   end
+  end
+ elseif isfile(addsuffix(required,suffix)) then
+  if trace then
+   report("library with qualified name %a %sfound",required,"")
+  end
+  return required
+ else
+  if trace then
+   report("library with qualified name %a %sfound",required,"not ")
+  end
+ end
+ return false
+end
+local foundlibraries=table.setmetatableindex(function(t,k)
+ local v=findlib(k)
+ t[k]=v
+ return v
+end)
+function resolvers.findlib(required)
+ return foundlibraries[required]
+end
+local libraries={}
+resolvers.libraries=libraries
+local report=logs.reporter("optional")
+if optional then optional.loaded={} end
+function libraries.validoptional(name)
+ local thelib=optional and optional[name]
+ if not thelib then
+ elseif thelib.initialize then
+  return thelib
+ else
+  report("invalid optional library %a",libname)
+ end
+end
+function libraries.optionalloaded(name,libnames)
+ local thelib=optional and optional[name]
+ if not thelib then
+  report("no optional %a library found",name)
+ else
+  local thelib_initialize=thelib.initialize
+  if not thelib_initialize then
+   report("invalid optional library %a",name)
+  else
+   if type(libnames)=="string" then
+    libnames={ libnames }
+   end
+   if type(libnames)=="table" then
+    for i=1,#libnames do
+     local libname=libnames[i]
+     local filename=foundlibraries[libname]
+     if filename and filename~="" then
+      libnames[i]=filename
+     else
+      report("unable to locate library %a",libname)
+      return
+     end
+    end
+    local initialized=thelib_initialize(unpack(libnames))
+    if not initialized then
+     report("unable to initialize library '% + t'",libnames)
+    elseif not silent then
+     report("using library '% + t'",libnames)
+    end
+    return initialized
+   end
+  end
+ end
+end
+if FFISUPPORTED and ffi and ffi.load then
+ local ffiload=ffi.load
+ function ffi.load(name)
+  local full=name and foundlibraries[name]
+  if full then
+   return ffiload(full)
+  else
+   return ffiload(name)
+  end
+ end
+end
+local dofile=dofile
+local savedrequire=require
+function require(name,version)
+ if find(name,"%.lua$") or find(name,"%.lmt$") then
+  local m=dofile(findfile(name))
+  if m then
+   package.loaded[name]=m
+   return m
+  end
+ else
+  return savedrequire(name)
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["luat-sta"] = package.loaded["luat-sta"] or true
+
+-- original size: 5703, stripped down to: 2321
+
+if not modules then modules={} end modules ['luat-sta']={
+ version=1.001,
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local gmatch,match=string.gmatch,string.match
+local type=type
+states=states or {}
+local states=states
+states.data=states.data or {}
+local data=states.data
+states.hash=states.hash or {}
+local hash=states.hash
+states.tag=states.tag   or ""
+states.filename=states.filename or ""
+function states.save(filename,tag)
+ tag=tag or states.tag
+ filename=file.addsuffix(filename or states.filename,'lus')
+ io.savedata(filename,
+  "-- generator : luat-sta.lua\n".."-- state tag : "..tag.."\n\n"..table.serialize(data[tag or states.tag] or {},true)
+ )
+end
+function states.load(filename,tag)
+ states.filename=filename
+ states.tag=tag or "whatever"
+ states.filename=file.addsuffix(states.filename,'lus')
+ data[states.tag],hash[states.tag]=(io.exists(filename) and dofile(filename)) or {},{}
+end
+local function set_by_tag(tag,key,value,default,persistent)
+ local d,h=data[tag],hash[tag]
+ if d then
+  if type(d)=="table" then
+   local dkey,hkey=key,key
+   local pre,post=match(key,"(.+)%.([^%.]+)$")
+   if pre and post then
+    for k in gmatch(pre,"[^%.]+") do
+     local dk=d[k]
+     if not dk then
+      dk={}
+      d[k]=dk
+     elseif type(dk)=="string" then
+      break
+     end
+     d=dk
+    end
+    dkey,hkey=post,key
+   end
+   if value==nil then
+    value=default
+   elseif value==false then
+   elseif persistent then
+    value=value or d[dkey] or default
+   else
+    value=value or default
+   end
+   d[dkey],h[hkey]=value,value
+  elseif type(d)=="string" then
+   data[tag],hash[tag]=value,value
+  end
+ end
+end
+local function get_by_tag(tag,key,default)
+ local h=hash[tag]
+ if h and h[key] then
+  return h[key]
+ else
+  local d=data[tag]
+  if d then
+   for k in gmatch(key,"[^%.]+") do
+    local dk=d[k]
+    if dk~=nil then
+     d=dk
+    else
+     return default
+    end
+   end
+   if d==false then
+    return false
+   else
+    return d or default
+   end
+  end
+ end
+end
+states.set_by_tag=set_by_tag
+states.get_by_tag=get_by_tag
+function states.set(key,value,default,persistent)
+ set_by_tag(states.tag,key,value,default,persistent)
+end
+function states.get(key,default)
+ return get_by_tag(states.tag,key,default)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["luat-fmt"] = package.loaded["luat-fmt"] or true
+
+-- original size: 11691, stripped down to: 8350
+
+if not modules then modules={} end modules ['luat-fmt']={
+ version=1.001,
+ comment="companion to mtxrun",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local format=string.format
+local concat=table.concat
+local quoted=string.quoted
+local luasuffixes=utilities.lua.suffixes
+local report_format=logs.reporter("resolvers","formats")
+local function primaryflags(arguments)
+ local flags={}
+ if arguments.silent then
+  flags[#flags+1]="--interaction=batchmode"
+ end
+ return concat(flags," ")
+end
+local function secondaryflags(arguments)
+ local trackers=arguments.trackers
+ local directives=arguments.directives
+ local flags={}
+ if trackers and trackers~="" then
+  flags[#flags+1]="--c:trackers="..quoted(trackers)
+ end
+ if directives and directives~="" then
+  flags[#flags+1]="--c:directives="..quoted(directives)
+ end
+ if arguments.silent then
+  flags[#flags+1]="--c:silent"
+ end
+ if arguments.errors then
+  flags[#flags+1]="--c:errors"
+ end
+ if arguments.ansi then
+  flags[#flags+1]="--c:ansi"
+ end
+ if arguments.ansilog then
+  flags[#flags+1]="--c:ansilog"
+ end
+ if arguments.strip then
+  flags[#flags+1]="--c:strip"
+ end
+ if arguments.lmtx then
+  flags[#flags+1]="--c:lmtx"
+ end
+ return concat(flags," ")
+end
+local template=[[--ini %primaryflags% --lua=%luafile% %texfile% %secondaryflags% %redirect%]]
+local checkers={
+ primaryflags="verbose",
+ secondaryflags="verbose",
+ luafile="readable",
+ texfile="readable",
+ redirect="string",
+ binarypath="string",
+}
+local runners={
+ luametatex=sandbox.registerrunner {
+  name="make luametatex format",
+  program="luametatex",
+  template=template,
+  checkers=checkers,
+  reporter=report_format,
+ },
+ luatex=sandbox.registerrunner {
+  name="make luatex format",
+  program="luatex",
+  template=template,
+  checkers=checkers,
+  reporter=report_format,
+ },
+ luajittex=sandbox.registerrunner {
+  name="make luajittex format",
+  program="luajittex",
+  template=template,
+  checkers=checkers,
+  reporter=report_format,
+ },
+}
+local stubfiles={
+ luametatex="luat-cod.lmt",
+ luatex="luat-cod.lua",
+ luajittex="luat-cod.lua",
+}
+local suffixes={
+ luametatex="mkxl",
+ luatex="mkiv",
+ luajittex="mkiv",
+}
+local function validbinarypath()
+ if not environment.arguments.nobinarypath then
+  local path=environment.ownpath or file.dirname(environment.ownname)
+  if path and path~="" then
+   path=dir.expandname(path)
+   if path~="" and lfs.isdir(path) then
+    return path
+   end
+  end
+ end
+end
+local function fatalerror(startupdir,...)
+ report_format(...)
+ lfs.chdir(startupdir)
+end
+function environment.make_format(formatname)
+ local arguments=environment.arguments
+ local engine=environment.ownmain or "luatex"
+ local silent=arguments.silent
+ local errors=arguments.errors
+ local runner=runners[engine]
+ local startupdir=dir.current()
+ if not runner then
+  return fatalerror(startupdir,"the format %a cannot be generated, no runner available for engine %a",name,engine)
+ end
+ local luasourcename=stubfiles[engine]
+ if not luasourcename then
+  return fatalerror(startupdir,"no lua stub file specified for %a",engine)
+ end
+ local texsourcename=file.addsuffix(formatname,suffixes[engine])
+ local fulltexsourcename=resolvers.findfile(texsourcename,"tex") or ""
+ if fulltexsourcename=="" then
+  return fatalerror(startupdir,"no tex source file with name %a (mkiv or tex)",formatname)
+ end
+ local fulltexsourcename=dir.expandname(fulltexsourcename)
+ local texsourcepath=file.dirname(fulltexsourcename)
+ if lfs.isfile(fulltexsourcename) then
+  report_format("using tex source file %a",fulltexsourcename)
+ else
+  return fatalerror(startupdir,"no accessible tex source file with name %a",fulltexsourcename)
+ end
+ local fullluasourcename=dir.expandname(file.join(texsourcepath,luasourcename) or "")
+ if lfs.isfile(fullluasourcename) then
+  report_format("using lua stub file %a",fullluasourcename)
+ else
+  return fatalerror(startupdir,"no accessible lua stub file with name %a",fulltexsourcename)
+ end
+ local validformatpath=caches.getwritablepath("formats",engine) or ""
+ if validformatpath=="" then
+  return fatalerror(startupdir,"invalid format path, insufficient write access")
+ end
+ local binarypath=validbinarypath()
+ report_format("changing to format path %a",validformatpath)
+ if not lfs.chdir(validformatpath) then
+  return fatalerror(startupdir,"unable to change to format path %a",validformatpath)
+ end
+ local primaryflags=primaryflags(arguments)
+ local secondaryflags=secondaryflags(arguments)
+ local specification={
+  binarypath=binarypath,
+  primaryflags=primaryflags,
+  secondaryflags=secondaryflags,
+  luafile=quoted(fullluasourcename),
+  texfile=quoted(fulltexsourcename),
+ }
+ if silent then
+  specification.redirect="> temp.log"
+ end
+ statistics.starttiming("format")
+ local result=runner(specification)
+ statistics.stoptiming("format")
+ if silent then
+  os.remove("temp.log")
+ end
+ report_format()
+  if binarypath and binarypath~="" then
+ report_format("binary path      : %s",binarypath or "?")
+  end
+ report_format("format path      : %s",validformatpath)
+ report_format("luatex engine    : %s",engine)
+ report_format("lua startup file : %s",fullluasourcename)
+  if primaryflags~="" then
+ report_format("primary flags    : %s",primaryflags)
+  end
+  if secondaryflags~="" then
+ report_format("secondary flags  : %s",secondaryflags)
+  end
+ report_format("context file     : %s",fulltexsourcename)
+ report_format("run time         : %.3f seconds",statistics.elapsed("format"))
+ report_format("return value     : %s",result==0 and "okay" or "error")
+ report_format()
+ lfs.chdir(startupdir)
+end
+local template=[[%primaryflags% --fmt=%fmtfile% --lua=%luafile% %texfile% %secondaryflags%]]
+local checkers={
+ primaryflags="verbose",
+ secondaryflags="verbose",
+ fmtfile="readable",
+ luafile="readable",
+ texfile="readable",
+}
+local runners={
+ luatex=sandbox.registerrunner {
+  name="run luatex format",
+  program="luatex",
+  template=template,
+  checkers=checkers,
+  reporter=report_format,
+ },
+ luametatex=sandbox.registerrunner {
+  name="run luametatex format",
+  program="luametatex",
+  template=template,
+  checkers=checkers,
+  reporter=report_format,
+ },
+ luajittex=sandbox.registerrunner {
+  name="run luajittex format",
+  program="luajittex",
+  template=template,
+  checkers=checkers,
+  reporter=report_format,
+ },
+}
+function environment.run_format(formatname,scriptname,filename,primaryflags,secondaryflags,verbose)
+ local engine=environment.ownmain or "luatex"
+ if not formatname or formatname=="" then
+  report_format("missing format name")
+  return
+ end
+ if not scriptname or scriptname=="" then
+  report_format("missing script name")
+  return
+ end
+ if not lfs.isfile(formatname) or not lfs.isfile(scriptname) then
+  formatname,scriptname=resolvers.locateformat(formatname)
+ end
+ if not formatname or formatname=="" then
+  report_format("invalid format name")
+  return
+ end
+ if not scriptname or scriptname=="" then
+  report_format("invalid script name")
+  return
+ end
+ local runner=runners[engine]
+ if not runner then
+  report_format("format %a cannot be run, no runner available for engine %a",file.nameonly(name),engine)
+  return
+ end
+ if not filename then
+  filename ""
+ end
+ local binarypath=validbinarypath()
+ local specification={
+  binarypath=binarypath,
+  primaryflags=primaryflags or "",
+  secondaryflags=secondaryflags or "",
+  fmtfile=quoted(formatname),
+  luafile=quoted(scriptname),
+  texfile=filename~="" and quoted(filename) or "",
+ }
+ statistics.starttiming("make format")
+ local result=runner(specification)
+ statistics.stoptiming("make format")
+ if verbose then
+  report_format()
+   if binarypath and binarypath~="" then
+  report_format("binary path      : %s",binarypath)
+   end
+  report_format("luatex engine    : %s",engine)
+  report_format("lua startup file : %s",scriptname)
+  report_format("tex format file  : %s",formatname)
+   if filename~="" then
+  report_format("tex input file   : %s",filename)
+   end
+   if primaryflags~="" then
+  report_format("primary flags    : %s",primaryflags)
+   end
+   if secondaryflags~="" then
+  report_format("secondary flags  : %s",secondaryflags)
+   end
+  report_format("run time         : %0.3f seconds",statistics.elapsed("make format"))
+  report_format("return value     : %s",result==0 and "okay" or "error")
+  report_format()
+ end
+ return result
+end
+
+
+end -- of closure
+
+-- used libraries    : l-bit32.lua l-lua.lua l-macro.lua l-sandbox.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-sha.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-fil.lua util-sac.lua util-sto.lua util-prs.lua util-fmt.lua util-soc-imp-reset.lua util-soc-imp-socket.lua util-soc-imp-copas.lua util-soc-imp-ltn12.lua util-soc-imp-mime.lua util-soc-imp-url.lua util-soc-imp-headers.lua util-soc-imp-tp.lua util-soc-imp-http.lua util-soc-imp-ftp.lua util-soc-imp-smtp.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-tpl.lua util-sbx.lua util-mrg.lua util-env.lua luat-env.lua util-zip.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua libs-ini.lua luat-sta.lua luat-fmt.lua
+-- skipped libraries : -
+-- original bytes    : 1034927
+-- stripped bytes    : 407861
+
+-- end library merge
+
+-- We need this hack till luatex is fixed.
+--
+-- for k,v in pairs(arg) do print(k,v) end
+
+if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then
+    arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil
+end
+
+-- End of hack.
+
+local format, gsub, gmatch, match, find = string.format, string.gsub, string.gmatch, string.match, string.find
+local concat = table.concat
+
+local ownname = environment and environment.ownname or arg[0] or 'mtxrun.lua'
+local ownpath = gsub(match(ownname,"^(.+)[\\/].-$") or ".","\\","/")
+local owntree = environment and environment.ownpath or ownpath
+
+local ownlibs = { -- order can be made better
+
+    'l-bit32.lua',
+    'l-lua.lua',
+    'l-macro.lua',
+    'l-sandbox.lua',
+    'l-package.lua',
+    'l-lpeg.lua',
+    'l-function.lua',
+    'l-string.lua',
+    'l-table.lua',
+    'l-io.lua',
+    'l-number.lua',
+    'l-set.lua',
+    'l-os.lua',
+    'l-file.lua',
+    'l-gzip.lua',
+    'l-md5.lua',
+    'l-sha.lua',
+    'l-url.lua',
+    'l-dir.lua',
+    'l-boolean.lua',
+    'l-unicode.lua',
+    'l-math.lua',
+
+    'util-str.lua', -- code might move to l-string
+    'util-tab.lua',
+    'util-fil.lua',
+    'util-sac.lua',
+    'util-sto.lua',
+    'util-prs.lua',
+    'util-fmt.lua',
+
+    'util-soc-imp-reset.lua',
+    'util-soc-imp-socket.lua',
+    'util-soc-imp-copas.lua',
+    'util-soc-imp-ltn12.lua',
+ -- 'util-soc-imp-mbox.lua',
+    'util-soc-imp-mime.lua',
+    'util-soc-imp-url.lua',
+    'util-soc-imp-headers.lua',
+    'util-soc-imp-tp.lua',
+    'util-soc-imp-http.lua',
+    'util-soc-imp-ftp.lua',
+    'util-soc-imp-smtp.lua',
+
+    'trac-set.lua',
+    'trac-log.lua',
+    'trac-inf.lua', -- was before trac-set
+    'trac-pro.lua', -- not really needed
+    'util-lua.lua', -- indeed here?
+    'util-deb.lua',
+
+    'util-tpl.lua',
+    'util-sbx.lua',
+    'util-mrg.lua',
+
+    'util-env.lua',
+    'luat-env.lua', -- can come before inf (as in mkiv)
+
+    'util-zip.lua',
+
+    'lxml-tab.lua',
+    'lxml-lpt.lua',
+ -- 'lxml-ent.lua',
+    'lxml-mis.lua',
+    'lxml-aux.lua',
+    'lxml-xml.lua',
+
+    'trac-xml.lua',
+
+    'data-ini.lua',
+    'data-exp.lua',
+    'data-env.lua',
+    'data-tmp.lua',
+    'data-met.lua',
+    'data-res.lua',
+    'data-pre.lua',
+    'data-inp.lua',
+    'data-out.lua',
+    'data-fil.lua',
+    'data-con.lua',
+    'data-use.lua',
+--  'data-tex.lua',
+--  'data-bin.lua',
+    'data-zip.lua',
+    'data-tre.lua',
+    'data-sch.lua',
+    'data-lua.lua',
+    'data-aux.lua', -- updater
+    'data-tmf.lua',
+    'data-lst.lua',
+
+    'libs-ini.lua',
+
+    'luat-sta.lua',
+    'luat-fmt.lua',
+
+}
+
+-- c:/data/develop/tex-context/tex/texmf-win64/bin/../../texmf-context/tex/context/base/mkiv/data-tmf.lua
+-- c:/data/develop/context/sources/data-tmf.lua
+
+local ownlist = {
+ -- '.',
+ -- ownpath ,
+    owntree .. "/../../../../context/sources", -- HH's development path
+    --
+    owntree .. "/../../texmf-local/tex/context/base/mkiv",
+    owntree .. "/../../texmf-context/tex/context/base/mkiv",
+    owntree .. "/../../texmf/tex/context/base/mkiv",
+    owntree .. "/../../../texmf-local/tex/context/base/mkiv",
+    owntree .. "/../../../texmf-context/tex/context/base/mkiv",
+    owntree .. "/../../../texmf/tex/context/base/mkiv",
+    --
+    owntree .. "/../../texmf-local/tex/context/base",
+    owntree .. "/../../texmf-context/tex/context/base",
+    owntree .. "/../../texmf/tex/context/base",
+    owntree .. "/../../../texmf-local/tex/context/base",
+    owntree .. "/../../../texmf-context/tex/context/base",
+    owntree .. "/../../../texmf/tex/context/base",
+}
+
+if ownpath == "." then table.remove(ownlist,1) end
+
+own = {
+    name = ownname,
+    path = ownpath,
+    tree = owntree,
+    list = ownlist,
+    libs = ownlibs,
+}
+
+local function locate_libs()
+    for l=1,#ownlibs do
+        local lib = ownlibs[l]
+        for p =1,#ownlist do
+            local pth = ownlist[p]
+            local filename = pth .. "/" .. lib
+            local found = lfs.isfile(filename)
+            if found then
+                package.path = package.path .. ";" .. pth .. "/?.lua" -- in case l-* does a require
+                return pth
+            end
+        end
+    end
+end
+
+local function load_libs()
+    local found = locate_libs()
+    if found then
+        for l=1,#ownlibs do
+            local filename = found .. "/" .. ownlibs[l]
+            local codeblob = loadfile(filename)
+            if codeblob then
+                codeblob()
+            end
+        end
+    else
+        resolvers = nil
+    end
+end
+
+if not resolvers then
+    load_libs()
+end
+
+if not resolvers then
+    print("")
+    print("Mtxrun is unable to start up due to lack of libraries. You may")
+    print("try to run 'lua mtxrun.lua --selfmerge' in the path where this")
+    print("script is located (normally under ..../scripts/context/lua) which")
+    print("will make this script library independent.")
+    os.exit()
+end
+
+-- verbosity
+
+----- e_verbose = environment.arguments["verbose"]
+
+local e_verbose = false
+
+-- some common flags (also passed through environment)
+
+local e_silent       = environment.argument("silent")
+local e_errors       = environment.argument("errors")
+local e_noconsole    = environment.argument("noconsole")
+
+local e_trackers     = environment.argument("trackers")
+local e_directives   = environment.argument("directives")
+local e_experiments  = environment.argument("experiments")
+
+local t = { }
+
+if type(e_directives) == "string" then
+    t[#t+1] = e_directives
+end
+
+if type(e_silent) == "string" then
+    t[#t+1] = format("logs.blocked={%s}",e_silent)
+elseif e_silent == true then
+    t[#t+1] = "logs.blocked"
+end
+
+if type(e_errors) == "string" then
+    t[#t+1] = format("logs.errors={%s}",e_errors)
+elseif e_errors == true then
+    t[#t+1] = "logs.errors"
+end
+
+if e_noconsole then
+    t[#t+1] = format("logs.target=file")
+end
+
+if #t > 0 then
+    e_directives = concat(t,",")
+end
+
+if e_trackers    then trackers   .enable(e_trackers)    end
+if e_directives  then directives .enable(e_directives)  end
+if e_experiments then experiments.enable(e_experiments) end
+
+if not environment.trackers    then environment.trackers    = e_trackers    end
+if not environment.directives  then environment.directives  = e_directives  end
+if not environment.experiments then environment.experiments = e_experiments end
+
+--
+
+resolvers.reset()
+
+local helpinfo = [[
+<?xml version="1.0" ?>
+<application>
+ <metadata>
+  <entry name="name">mtxrun</entry>
+  <entry name="detail">ConTeXt TDS Runner Tool</entry>
+  <entry name="version">1.33</entry>
+ </metadata>
+ <flags>
+  <category name="basic">
+   <subcategory>
+    <flag name="script"><short>run an mtx script (lua prefered method) (<ref name="noquotes"/>), no script gives list</short></flag>
+    <flag name="evaluate"><short>run code passed on the commandline (between quotes) (=loop) (exit|quit aborts)</short></flag>
+    <flag name="execute"><short>run a script or program (texmfstart method) (<ref name="noquotes"/>)</short></flag>
+    <flag name="resolve"><short>resolve prefixed arguments</short></flag>
+    <flag name="ctxlua"><short>run internally (using preloaded libs)</short></flag>
+    <flag name="internal"><short>run script using built in libraries (same as <ref name="ctxlua"/>)</short></flag>
+    <flag name="locate"><short>locate given filename in database (default) or system (<ref name="first"/> <ref name="all"/> <ref name="detail"/>)</short></flag>
+   </subcategory>
+   <subcategory>
+    <flag name="tree" value="pathtotree"><short>use given texmf tree (default file: setuptex.tmf)</short></flag>
+    <flag name="path" value="runpath"><short>go to given path before execution</short></flag>
+    <flag name="ifchanged" value="filename"><short>only execute when given file has changed (md checksum)</short></flag>
+    <flag name="iftouched" value="old,new"><short>only execute when given file has changed (time stamp)</short></flag>
+   </subcategory>
+   <subcategory>
+    <flag name="makestubs"><short>create stubs for (context related) scripts</short></flag>
+    <flag name="removestubs"><short>remove stubs (context related) scripts</short></flag>
+    <flag name="stubpath" value="binpath"><short>paths where stubs wil be written</short></flag>
+    <flag name="windows"><short>create windows (mswin) stubs</short></flag>
+    <flag name="unix"><short>create unix (linux) stubs</short></flag>
+    <flag name="addbinarypath"><short>prepend the (found) binarypath to runners</short></flag>
+   </subcategory>
+   <subcategory>
+    <flag name="verbose"><short>give a bit more info</short></flag>
+    <flag name="trackers" value="list"><short>enable given trackers</short></flag>
+    <flag name="progname" value="str"><short>format or backend</short></flag>
+    <flag name="systeminfo" value="str"><short>show current operating system, processor, etc</short></flag>
+   </subcategory>
+   <subcategory>
+    <flag name="edit"><short>launch editor with found file</short></flag>
+    <flag name="launch"><short>launch files like manuals, assumes os support (<ref name="all"/>,<ref name="list"/>)</short></flag>
+   </subcategory>
+   <subcategory>
+    <flag name="timedrun"><short>run a script and time its run</short></flag>
+    <flag name="autogenerate"><short>regenerate databases if needed (handy when used to run context in an editor)</short></flag>
+   </subcategory>
+   <subcategory>
+    <flag name="usekpse"><short>use kpse as fallback (when no mkiv and cache installed, often slower)</short></flag>
+    <flag name="forcekpse"><short>force using kpse (handy when no mkiv and cache installed but less functionality)</short></flag>
+   </subcategory>
+   <subcategory>
+    <flag name="prefixes"><short>show supported prefixes</short></flag>
+   </subcategory>
+   <subcategory>
+    <flag name="generate"><short>generate file database</short></flag>
+   </subcategory>
+   <subcategory>
+    <flag name="variables"><short>show configuration variables</short></flag>
+    <flag name="configurations"><short>show configuration order</short></flag>
+   </subcategory>
+   <subcategory>
+    <flag name="directives"><short>show (known) directives</short></flag>
+    <flag name="trackers"><short>show (known) trackers</short></flag>
+    <flag name="experiments"><short>show (known) experiments</short></flag>
+   </subcategory>
+   <subcategory>
+    <flag name="expand-braces"><short>expand complex variable</short></flag>
+    <flag name="resolve-path"><short>expand variable (completely resolve paths)</short></flag>
+    <flag name="expand-path"><short>expand variable (resolve paths)</short></flag>
+    <flag name="expand-var"><short>expand variable (resolve references)</short></flag>
+    <flag name="show-path"><short>show path expansion of ...</short></flag>
+    <flag name="var-value"><short>report value of variable</short></flag>
+    <flag name="find-file"><short>report file location</short></flag>
+    <flag name="find-path"><short>report path of file</short></flag>
+   </subcategory>
+   <subcategory>
+    <flag name="pattern" value="string"><short>filter variables</short></flag>
+   </subcategory>
+  </category>
+ </flags>
+</application>
+]]
+
+local application = logs.application {
+    name     = "mtxrun",
+    banner   = "ConTeXt TDS Runner Tool 1.32",
+    helpinfo = helpinfo,
+}
+
+local report = application.report
+
+messages = messages or { } -- for the moment
+
+runners = runners  or { } -- global (might become local)
+
+runners.applications = {
+    ["lua"] = "luatex --luaonly",
+    ["luc"] = "luatex --luaonly",
+    ["pl"] = "perl",
+    ["py"] = "python",
+    ["rb"] = "ruby",
+}
+
+runners.suffixes = {
+    'rb', 'lua', 'py', 'pl'
+}
+
+runners.registered = {
+    texexec      = { 'texexec.rb',      false },  -- context mkii runner (only tool not to be luafied)
+    texutil      = { 'texutil.rb',      true  },  -- old perl based index sorter for mkii (old versions need it)
+    texfont      = { 'texfont.pl',      true  },  -- perl script that makes mkii font metric files
+    texfind      = { 'texfind.pl',      false },  -- perltk based tex searching tool, mostly used at pragma
+    texshow      = { 'texshow.pl',      false },  -- perltk based context help system, will be luafied
+ -- texwork      = { 'texwork.pl',      false },  -- perltk based editing environment, only used at pragma
+    makempy      = { 'makempy.pl',      true  },
+    mptopdf      = { 'mptopdf.pl',      true  },
+    pstopdf      = { 'pstopdf.rb',      true  },  -- converts ps (and some more) images, does some cleaning (replaced)
+ -- examplex     = { 'examplex.rb',     false },
+    concheck     = { 'concheck.rb',     false },
+    runtools     = { 'runtools.rb',     true  },
+    textools     = { 'textools.rb',     true  },
+    tmftools     = { 'tmftools.rb',     true  },
+    ctxtools     = { 'ctxtools.rb',     true  },
+    rlxtools     = { 'rlxtools.rb',     true  },
+    pdftools     = { 'pdftools.rb',     true  },
+    mpstools     = { 'mpstools.rb',     true  },
+ -- exatools     = { 'exatools.rb',     true  },
+    xmltools     = { 'xmltools.rb',     true  },
+ -- luatools     = { 'luatools.lua',    true  },
+    mtxtools     = { 'mtxtools.rb',     true  },
+    pdftrimwhite = { 'pdftrimwhite.pl', false },
+}
+
+runners.launchers = {
+    windows = { },
+    unix    = { },
+}
+
+-- like runners.libpath("framework"): looks on script's subpath
+
+function runners.libpath(...)
+    package.prepend_libpath(file.dirname(environment.ownscript),...)
+    package.prepend_libpath(file.dirname(environment.ownname)  ,...)
+end
+
+function runners.prepare()
+    local checkname = environment.argument("ifchanged")
+    if type(checkname) == "string" and checkname ~= "" then
+        local oldchecksum = file.loadchecksum(checkname)
+        local newchecksum = file.checksum(checkname)
+        if oldchecksum == newchecksum then
+            if e_verbose then
+                report("file '%s' is unchanged",checkname)
+            end
+            return "skip"
+        elseif e_verbose then
+            report("file '%s' is changed, processing started",checkname)
+        end
+        file.savechecksum(checkname)
+    end
+    local touchname = environment.argument("iftouched")
+    if type(touchname) == "string" and touchname ~= "" then
+        local oldname, newname = string.splitup(touchname, ",")
+        if oldname and newname and oldname ~= "" and newname ~= "" then
+            if not file.needs_updating(oldname,newname) then
+                if e_verbose then
+                    report("file '%s' and '%s' have same age",oldname,newname)
+                end
+                return "skip"
+            elseif e_verbose then
+                report("file '%s' is older than '%s'",oldname,newname)
+            end
+        end
+    end
+    local runpath = environment.argument("path")
+    if type(runpath) == "string" and not lfs.chdir(runpath) then
+        report("unable to change to path '%s'",runpath)
+        return "error"
+    end
+    runners.prepare = function() end
+    return "run"
+end
+
+function runners.execute_script(fullname,internal,nosplit)
+    local noquote = environment.argument("noquotes")
+    if fullname and fullname ~= "" then
+        local state = runners.prepare()
+        if state == 'error' then
+            return false
+        elseif state == 'skip' then
+            return true
+        elseif state == "run" then
+            local path, name, suffix = file.splitname(fullname)
+            local result = ""
+            if path ~= "" then
+                result = fullname
+            elseif name then
+                name = gsub(name,"^int[%a]*:",function()
+                    internal = true
+                    return ""
+                end )
+                name = gsub(name,"^script:","")
+                if suffix == "" and runners.registered[name] and runners.registered[name][1] then
+                    name = runners.registered[name][1]
+                    suffix = file.suffix(name)
+                end
+                if suffix == "" then
+                    -- loop over known suffixes
+                    for _,s in pairs(runners.suffixes) do
+                        result = resolvers.findfile(name .. "." .. s, 'texmfscripts')
+                        if result ~= "" then
+                            break
+                        end
+                    end
+                elseif runners.applications[suffix] then
+                    result = resolvers.findfile(name, 'texmfscripts')
+                else
+                    -- maybe look on path
+                    result = resolvers.findfile(name, 'other text files')
+                end
+            end
+            if result and result ~= "" then
+                if not no_split then
+                    local before, after = environment.splitarguments(fullname) -- already done
+                    environment.arguments_before, environment.arguments_after = before, after
+                end
+                if internal then
+                    arg = { } for _,v in pairs(environment.arguments_after) do arg[#arg+1] = v end
+                    environment.ownscript = result
+                    dofile(result)
+                else
+local texmfcnf =  resolvers.getenv("TEXMFCNF")
+if not texmfcnf or texmfcnf == "" then
+    texmfcnf = resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.resolve(resolvers.luacnfspec)))
+    resolvers.setenv("TEXMFCNF",table.concat(texmfcnf,";")) -- for running texexec etc (after tl change to texmf-dist)
+end
+                    local binary = runners.applications[file.suffix(result)]
+                    result = string.quoted(string.unquoted(result))
+                 -- if string.match(result,' ') and not string.match(result,"^\".*\"$") then
+                 --     result = '"' .. result .. '"'
+                 -- end
+                    if binary and binary ~= "" then
+                        result = binary .. " " .. result
+                    end
+                    local command = result .. " " .. environment.reconstructcommandline(environment.arguments_after,noquote)
+                    if e_verbose then
+                        report()
+                        report("executing: %s",command)
+                        report()
+                        report()
+                        io.flush()
+                    end
+                    local code = os.execute(command)
+                    if code == 0 then
+                        return true
+                    else
+                        if binary then
+                            binary = file.addsuffix(binary,os.binsuffix)
+                            for p in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
+                                if lfs.isfile(file.join(p,binary)) then
+                                    return false
+                                end
+                            end
+                            report()
+                            report("This script needs '%s' which seems not to be installed.",binary)
+                            report()
+                        end
+                        return false
+                    end
+                end
+            end
+        end
+    end
+    return false
+end
+
+function runners.execute_program(fullname)
+    local noquote = environment.argument("noquotes")
+    if fullname and fullname ~= "" then
+        local state = runners.prepare()
+        if state == 'error' then
+            return false
+        elseif state == 'skip' then
+            return true
+        elseif state == "run" then
+            local before, after = environment.splitarguments(fullname)
+            for k=1,#after do after[k] = resolvers.resolve(after[k]) end
+            environment.initializearguments(after)
+            fullname = gsub(fullname,"^bin:","")
+            local command = fullname .. " " .. (environment.reconstructcommandline(after or "",noquote) or "")
+            report()
+            report("executing: %s",command)
+            report()
+            report()
+            io.flush()
+            local code = os.execute(command)
+            return code == 0
+        end
+    end
+    return false
+end
+
+-- the --usekpse flag will fallback (not default) on kpse (hm, we can better update mtx-stubs)
+
+local windows_stub = '@echo off\013\010setlocal\013\010set ownpath=%%~dp0%%\013\010texlua "%%ownpath%%mtxrun.lua" --usekpse --execute %s %%*\013\010endlocal\013\010'
+local unix_stub    = '#!/bin/sh\010mtxrun --usekpse --execute %s \"$@\"\010'
+
+function runners.handle_stubs(create)
+    local stubpath = environment.argument('stubpath') or '.' -- 'auto' no longer subpathssupported
+    local windows  = environment.argument('windows') or environment.argument('mswin') or false
+    local unix     = environment.argument('unix') or environment.argument('linux') or false
+    if not windows and not unix then
+        if os.platform == "unix" then
+            unix = true
+        else
+            windows = true
+        end
+    end
+    for _,v in pairs(runners.registered) do
+        local name, doit = v[1], v[2]
+        if doit then
+            local base = gsub(file.basename(name), "%.(.-)$", "")
+            if create then
+                if windows then
+                    io.savedata(file.join(stubpath,base..".bat"),format(windows_stub,name))
+                    report("windows stub for '%s' created",base)
+                end
+                if unix then
+                    io.savedata(file.join(stubpath,base),format(unix_stub,name))
+                    report("unix stub for '%s' created",base)
+                end
+            else
+                if windows and (os.remove(file.join(stubpath,base..'.bat')) or os.remove(file.join(stubpath,base..'.cmd'))) then
+                    report("windows stub for '%s' removed", base)
+                end
+                if unix and (os.remove(file.join(stubpath,base)) or os.remove(file.join(stubpath,base..'.sh'))) then
+                    report("unix stub for '%s' removed",base)
+                end
+            end
+        end
+    end
+end
+
+function runners.resolve_string(filename)
+    if filename and filename ~= "" then
+        runners.report_location(resolvers.resolve(filename))
+    end
+end
+
+-- differs from texmfstart where locate appends .com .exe .bat ... todo
+
+function runners.locate_file(filename) -- was given file but only searches in tree
+    if filename and filename ~= "" then
+        if environment.argument("first") then
+            runners.report_location(resolvers.findfile(filename))
+         -- resolvers.dowithfilesandreport(resolvers.findfile,filename)
+        elseif environment.argument("all") then
+            local result, status = resolvers.findfiles(filename)
+            if status and environment.argument("detail") then
+                runners.report_location(status)
+            else
+                runners.report_location(result)
+            end
+        else
+            runners.report_location(resolvers.findgivenfile(filename))
+         -- resolvers.dowithfilesandreport(resolvers.findgivenfile,filename)
+        end
+    end
+end
+
+function runners.locate_platform()
+    runners.report_location(os.platform)
+end
+
+function runners.report_location(result)
+    if type(result) == "table" then
+        for i=1,#result do
+            if i > 1 then
+                io.write("\n")
+            end
+            io.write(result[i])
+        end
+    else
+        io.write(result)
+    end
+end
+
+function runners.edit_script(filename) -- we assume that gvim is present on most systems (todo: also in cnf file)
+    local editor = os.getenv("MTXRUN_EDITOR") or os.getenv("TEXMFSTART_EDITOR") or os.getenv("EDITOR") or 'gvim'
+    local rest = resolvers.resolve(filename)
+    if rest ~= "" then
+        local command = editor .. " " .. rest
+        if e_verbose then
+            report()
+            report("starting editor: %s",command)
+            report()
+            report()
+        end
+        os.launch(command)
+    end
+end
+
+function runners.save_script_session(filename, list)
+    if type(list) == "table" then
+        local t = { }
+        for i=1,#list do
+            local key = list[i]
+            t[key] = environment.arguments[key]
+        end
+        io.savedata(filename,table.serialize(t,true))
+    end
+end
+
+function runners.load_script_session(filename)
+    if lfs.isfile(filename) then
+        local t = io.loaddata(filename)
+        if t then
+            t = loadstring(t)
+            if t then t = t() end
+            for key, value in pairs(t) do
+                environment.arguments[key] = value
+            end
+        end
+    end
+end
+
+function resolvers.launch(str)
+    -- maybe we also need to test on mtxrun.launcher.suffix environment
+    -- variable or on windows consult the assoc and ftype vars and such
+    local launchers = runners.launchers[os.platform] if launchers then
+        local suffix = file.suffix(str) if suffix then
+            local runner = launchers[suffix] if runner then
+                str = runner .. " " .. str
+            end
+        end
+    end
+    os.launch(str)
+end
+
+function runners.launch_file(filename)
+    local allresults = environment.arguments["all"]
+    local pattern    = environment.arguments["pattern"]
+    local listonly   = environment.arguments["list"]
+    if not pattern or pattern == "" then
+        pattern = filename
+    end
+    if not pattern or pattern == "" then
+        report("provide name or --pattern=")
+    else
+        local t = resolvers.findfiles(pattern,nil,allresults)
+        if not t or #t == 0 then
+            t = resolvers.findfiles("*/" .. pattern,nil,allresults)
+        end
+        if not t or #t == 0 then
+            t = resolvers.findfiles("*/" .. pattern .. "*",nil,allresults)
+        end
+        if t and #t > 0 then
+            for i=1,#t do
+                local name = t[i]
+                if listonly then
+                    report("% 3i:  %-30s %s",i,file.basename(name),file.dirname(name))
+                else
+                    report("launching: %s",name)
+                    resolvers.launch(name)
+                    if not allresults then
+                        break
+                    end
+                end
+            end
+            if listonly then
+                io.write("\n")
+                io.write("\n[select number]\n\n>> ")
+                local answer = tonumber(io.read())
+                if answer then
+                    io.write("\n")
+                    local name = t[answer]
+                    if name then
+                        report("launching: %s",name)
+                        resolvers.launch(name)
+                    else
+                        report("invalid number")
+                    end
+                end
+            end
+        else
+            report("no match for %s", pattern)
+        end
+    end
+end
+
+local mtxprefixes = {
+    { "^mtx%-",    "mtx-"  },
+    { "^mtx%-t%-", "mtx-t-" },
+}
+
+function runners.find_mtx_script(filename)
+    local function found(name)
+        local path = file.dirname(name)
+        if path and path ~= "" then
+            return false
+        else
+            local fullname = own and own.path and file.join(own.path,name)
+            return io.exists(fullname) and fullname
+        end
+    end
+    filename = file.addsuffix(filename,"lua")
+    local basename = file.removesuffix(file.basename(filename))
+    local suffix = file.suffix(filename)
+    -- qualified path, raw name
+    local fullname = file.is_qualified_path(filename) and io.exists(filename) and filename
+    if fullname and fullname ~= "" then
+        return fullname
+    end
+    -- current path, raw name
+    fullname = "./" .. filename
+    fullname = io.exists(fullname) and fullname
+    if fullname and fullname ~= "" then
+        return fullname
+    end
+    -- mtx- prefix checking
+    for i=1,#mtxprefixes do
+        local mtxprefix = mtxprefixes[i]
+        mtxprefix = find(filename,mtxprefix[1]) and "" or mtxprefix[2]
+        -- context namespace, mtx-<filename>
+        fullname = mtxprefix .. filename
+        fullname = found(fullname) or resolvers.findfile(fullname)
+        if fullname and fullname ~= "" then
+            return fullname
+        end
+        -- context namespace, mtx-<filename>s
+        fullname = mtxprefix .. basename .. "s" .. "." .. suffix
+        fullname = found(fullname) or resolvers.findfile(fullname)
+        if fullname and fullname ~= "" then
+            return fullname
+        end
+        -- context namespace, mtx-<filename minus trailing s>
+        fullname = mtxprefix .. gsub(basename,"s$","") .. "." .. suffix
+        fullname = found(fullname) or resolvers.findfile(fullname)
+        if fullname and fullname ~= "" then
+            return fullname
+        end
+    end
+    -- context namespace, just <filename>
+    fullname = resolvers.findfile(filename)
+    return fullname
+end
+
+function runners.register_arguments(...)
+    local arguments = environment.arguments_after
+    local passedon = { ... }
+    for i=#passedon,1,-1 do
+        local pi = passedon[i]
+        if pi then
+            table.insert(arguments,1,pi)
+        end
+    end
+end
+
+function runners.execute_ctx_script(filename,...)
+    runners.register_arguments(...)
+    local arguments = environment.arguments_after
+    local fullname = runners.find_mtx_script(filename) or ""
+    if file.suffix(fullname) == "cld" then
+        -- handy in editors where we force --autopdf
+        report("running cld script: %s",filename)
+        table.insert(arguments,1,fullname)
+        table.insert(arguments,"--autopdf")
+        fullname = runners.find_mtx_script("context") or ""
+    end
+    -- retry after generate but only if --autogenerate
+    if fullname == "" and environment.argument("autogenerate") then -- might become the default
+        resolvers.renewcache()
+        trackers.enable("resolvers.locating")
+        resolvers.load()
+        --
+        fullname = runners.find_mtx_script(filename) or ""
+    end
+    -- that should do it
+    if fullname ~= "" then
+        local state = runners.prepare()
+        if state == 'error' then
+            return false
+        elseif state == 'skip' then
+            return true
+        elseif state == "run" then
+            -- load and save ... kind of undocumented
+            arg = { } for _,v in pairs(arguments) do arg[#arg+1] = resolvers.resolve(v) end
+            environment.initializearguments(arg)
+            local loadname = environment.arguments['load']
+            if loadname then
+                if type(loadname) ~= "string" then loadname = file.basename(fullname) end
+                loadname = file.replacesuffix(loadname,"cfg")
+                runners.load_script_session(loadname)
+            end
+            filename = environment.files[1]
+            if e_verbose then
+                report("using script: %s (if --path is used don't run on path where mtxrun lives)\n",fullname)
+            end
+            environment.ownscript = fullname
+            dofile(fullname)
+            local savename = environment.arguments['save']
+            if savename then
+                if type(savename) ~= "string" then savename = file.basename(fullname) end
+                savename = file.replacesuffix(savename,"cfg")
+                runners.save_script_session(savename,save_list)
+            end
+            return true
+        end
+    else
+        if filename == "" or filename == "help" then
+            local context = resolvers.findfile("mtx-context.lua")
+            trackers.enable("resolvers.locating")
+            if context ~= "" then
+                local result = dir.glob((gsub(context,"mtx%-context","mtx-*"))) -- () needed
+                local valid = { }
+                table.sort(result)
+                for i=1,#result do
+                    local scriptname = result[i]
+                    local scriptbase = match(scriptname,".*mtx%-([^%-]-)%.lua")
+                    if scriptbase then
+                        local data = io.loaddata(scriptname)
+                        local application = match(data,"local application.-=.-(%{.-%})")
+                        if application then
+                            application = loadstring("return " .. application)
+                            if application then
+                                application = application()
+                                local banner = application.banner
+                                if banner then
+                                    local description, version = match(banner,"^(.-) ([%d.]+)$")
+                                    if description then
+                                        valid[#valid+1] = { scriptbase, version, description }
+                                    else
+                                        valid[#valid+1] = { scriptbase, "", banner }
+                                    end
+                                end
+                            end
+                        end
+                    end
+                end
+                if #valid > 0 then
+                    application.identify()
+                    report("no script name given, known scripts:")
+                    report()
+                    for k=1,#valid do
+                        local v = valid[k]
+                        report("%-12s  %4s  %s",v[1],v[2],v[3])
+                    end
+                end
+            else
+                report("no script name given")
+            end
+        else
+            filename = file.addsuffix(filename,"lua")
+            if file.is_qualified_path(filename) then
+                report("unknown script '%s'",filename)
+            else
+                report("unknown script '%s' or 'mtx-%s'",filename,filename)
+            end
+        end
+        return false
+    end
+end
+
+function runners.prefixes()
+    application.identify()
+    report()
+    report(concat(resolvers.allprefixes(true)," "))
+end
+
+function runners.timedrun(filename) -- just for me
+    if filename and filename ~= "" then
+        runners.timed(function() os.execute(filename) end)
+    end
+end
+
+function runners.timed(action)
+    statistics.timed(action,true)
+end
+
+function runners.associate(filename)
+    os.launch(filename)
+end
+
+function runners.evaluate(code,filename) -- for Luigi
+    local environment = table.setmetatableindex(_G)
+    if code == "loop" then
+        while true do
+            io.write("lua > ")
+            local code = io.read()
+            if code == "quit" or code == "exit"  then
+                break
+            elseif code ~= "" then
+                local temp = string.match(code,"^= (.*)$")
+                if temp then
+                    code = "inspect("..temp..")"
+                end
+                local compiled, message = load(code,"console","t",environment)
+                if type(compiled) ~= "function" then
+                    compiled = load("inspect("..code..")","console","t",environment)
+                end
+                if type(compiled) ~= "function" then
+                    io.write("! " .. (message or code).."\n")
+                else
+                    io.write(compiled())
+                end
+            end
+        end
+    else
+        if type(code) ~= "string" or code == "" then
+            code = filename
+        end
+        if code ~= "" then
+            local compiled, message = load(code,"console","t",environment)
+            if type(compiled) ~= "function" then
+                compiled = load("inspect("..code..")","console","t",environment)
+            end
+            if type(compiled) ~= "function" then
+                io.write("invalid lua code: " .. (message or code))
+                return
+            end
+            io.write(compiled())
+        end
+    end
+end
+
+function runners.gethelp(filename)
+    local url = environment.argument("url")
+    if url and url ~= "" then
+        local command = string.gsub(environment.argument("command") or "unknown","^%s*\\*(.-)%s*$","%1")
+        url = utilities.templates.replace(url,{ command = command })
+        os.launch(url)
+    else
+        report("no --url given")
+    end
+end
+
+function runners.systeminfo()
+    report("architecture      : %s",os.platform  or "<unset>")
+    report("operating system  : %s",os.name      or "<unset>")
+    report("file architecture : %s",os.type      or "<unset>")
+    report("binary path       : %s",os.selfdir   or "<unset>")
+    report("binary suffix     : %s",os.binsuffix or "<unset>")
+    report("library suffix    : %s",os.libsuffix or "<unset>")
+end
+
+-- this is a bit dirty ... first we store the first filename and next we
+-- split the arguments so that we only see the ones meant for this script
+-- ... later we will use the second half
+
+local filename = environment.files[1] or ""
+local ok      = true
+
+local before, after = environment.splitarguments(filename)
+environment.arguments_before, environment.arguments_after = before, after
+environment.initializearguments(before)
+
+e_verbose = environment.arguments["verbose"] -- delayed till here (we need the ones before script)
+
+if e_verbose then
+    trackers.enable("resolvers.locating")
+end
+
+-- maybe the unset has to go to this level
+
+local is_mkii_stub = runners.registered[file.removesuffix(file.basename(filename))]
+
+local e_argument = environment.argument
+
+if e_argument("timedlog") then
+    logs.settimedlog()
+end
+
+if e_argument("usekpse") or e_argument("forcekpse") or is_mkii_stub then
+
+    resolvers.load_tree(e_argument('tree'),true) -- force resolve of TEXMFCNF
+
+    os.setenv("engine","")
+    os.setenv("progname","")
+
+    local remapper = {
+        otf   = "opentype fonts",
+        ttf   = "truetype fonts",
+        ttc   = "truetype fonts",
+        pfb   = "type1 fonts",
+        other = "other text files",
+    }
+
+    local progname = e_argument("progname") or 'context'
+
+    local function kpse_initialized()
+        texconfig.kpse_init = true
+        local t = os.clock()
+        local k = kpse.original.new("luatex",progname)
+        local dummy = k:find_file("mtxrun.lua") -- so that we're initialized
+        report("kpse fallback with progname '%s' initialized in %s seconds",progname,os.clock()-t)
+        kpse_initialized = function() return k end
+        return k
+    end
+
+    local findfile = resolvers.findfile
+    local showpath = resolvers.showpath
+
+    if e_argument("forcekpse") then
+
+        function resolvers.findfile(name,kind)
+            return (kpse_initialized():find_file(resolvers.cleanpath(name),(kind ~= "" and (remapper[kind] or kind)) or "tex") or "") or ""
+        end
+        function resolvers.showpath(name)
+            return (kpse_initialized():show_path(name)) or ""
+        end
+
+    elseif e_argument("usekpse") or is_mkii_stub then
+
+        resolvers.load()
+
+        function resolvers.findfile(name,kind)
+            local found = findfile(name,kind) or ""
+            if found ~= "" then
+                return found
+            else
+                return (kpse_initialized():find_file(resolvers.cleanpath(name),(kind ~= "" and (remapper[kind] or kind)) or "tex") or "") or ""
+            end
+        end
+        function resolvers.showpath(name)
+            local found = showpath(name) or ""
+            if found ~= "" then
+                return found
+            else
+                return (kpse_initialized():show_path(name)) or ""
+            end
+        end
+
+    end
+
+    function runners.loadbase()
+    end
+
+else
+
+    function runners.loadbase(...)
+        if not resolvers.load(...) then
+            report("forcing cache reload")
+            resolvers.renewcache()
+            trackers.enable("resolvers.locating")
+            if not resolvers.load(...) then
+                report("the resolver databases are not present or outdated")
+            end
+        end
+    end
+
+    resolvers.load_tree(e_argument('tree'),e_argument("resolve"))
+
+end
+
+-- joke .. reminds me of messing with gigi terminals
+
+do
+
+    local a_locale = e_argument("locale")
+
+    if a_locale then
+
+        -- I really hate this crap but am too tired of discussing it over and over
+        -- again so for the sake of usiage outside context we will provide ways to
+        -- use locales in an otherwise supposed to be locale agnostic system. And
+        -- forget about support in case of interferences.
+
+        report()
+        report(what == "force" and "forcing locale:" or "original locale:")
+        report()
+        report("  collate  : %s",status.lc_collate  or "<unset>")
+        report("  ctype    : %s",status.lc_ctype    or "<unset>")
+        report("  monetary : %s",status.lc_monetary or "<unset>")
+        report("  numeric  : %s",status.lc_numeric  or "<unset>")
+        report("  time     : %s",status.lc_time     or "<unset>")
+        report()
+
+    end
+
+    if a_locale == "force" then
+        os.setlocale(status.lc_collate ,"collate")
+        os.setlocale(status.lc_ctype   ,"ctype")
+        os.setlocale(status.lc_monetary,"monetary")
+        os.setlocale(status.lc_numeric ,"numeric")
+        os.setlocale(status.lc_time    ,"time")
+    else
+        function os.setlocale()
+        end
+    end
+
+end
+
+-- if e_argument("ansi") or e_argument("ansilog") then
+
+--     logs.setformatters(e_argument("ansi") and "ansi" or "ansilog")
+
+--  -- local script = e_argument("script") or e_argument("scripts")
+--  --
+--  -- if type(script) == "string" then
+--  --     logs.writer("]0;"..script.."") -- for Alan to test
+--  -- end
+
+-- end
+
+if e_argument("script") or e_argument("scripts") then
+
+    -- run a script by loading it (using libs), pass args
+
+    if e_argument("nofiledatabase") then
+        -- handy for mtx-update
+    else
+        runners.loadbase()
+    end
+    if is_mkii_stub then
+        ok = runners.execute_script(filename,false,true)
+    else
+        ok = runners.execute_ctx_script(filename)
+    end
+
+elseif e_argument("evaluate") then
+
+    runners.evaluate(e_argument("evaluate"),filename)
+
+elseif e_argument("selfmerge") then
+
+    -- embed used libraries
+
+    runners.loadbase()
+    local found = locate_libs()
+
+    if found then
+        local mtxrun = resolvers.findfile("mtxrun.lua") -- includes local name
+        if lfs.isfile(mtxrun) then
+            utilities.merger.selfmerge(mtxrun,own.libs,{ found })
+            application.report("runner updated on resolved path: %s",mtxrun)
+        else
+            utilities.merger.selfmerge(own.name,own.libs,{ found })
+            application.report("runner updated on relative path: %s",own.name)
+        end
+    end
+
+elseif e_argument("selfclean") then
+
+    -- remove embedded libraries
+
+    runners.loadbase()
+
+    local mtxrun = resolvers.findfile("mtxrun.lua") -- includes local name
+    if lfs.isfile(mtxrun) then
+        utilities.merger.selfclean(mtxrun)
+        application.report("runner cleaned on resolved path: %s",mtxrun)
+    else
+        utilities.merger.selfclean(own.name)
+        application.report("runner cleaned on relative path: %s",own.name)
+    end
+
+elseif e_argument("selfupdate") then
+
+    runners.loadbase()
+    trackers.enable("resolvers.locating")
+    resolvers.updatescript(own.name,"mtxrun")
+
+elseif e_argument("ctxlua") or e_argument("internal") then
+
+    -- run a script by loading it (using libs)
+
+    runners.loadbase()
+    ok = runners.execute_script(filename,true)
+
+elseif e_argument("execute") then
+
+    -- execute script
+
+    runners.loadbase()
+    ok = runners.execute_script(filename)
+
+elseif e_argument("direct") then
+
+    -- equals bin:
+
+    runners.loadbase()
+    ok = runners.execute_program(filename)
+
+elseif e_argument("edit") then
+
+    -- edit file
+
+    runners.loadbase()
+    runners.edit_script(filename)
+
+elseif e_argument("launch") then
+
+    runners.loadbase()
+    runners.launch_file(filename)
+
+elseif e_argument("associate") then
+
+    runners.associate(filename)
+
+elseif e_argument("gethelp") then
+
+    runners.gethelp()
+
+elseif e_argument("makestubs") then
+
+    -- make stubs (depricated)
+
+    runners.handle_stubs(true)
+
+elseif e_argument("removestubs") then
+
+    -- remove stub (depricated)
+
+    runners.loadbase()
+    runners.handle_stubs(false)
+
+elseif e_argument("resolve") then
+
+    -- resolve string
+
+    runners.loadbase()
+    runners.resolve_string(filename)
+
+elseif e_argument("locate") then
+
+    -- locate file (only database)
+
+    runners.loadbase()
+    runners.locate_file(filename)
+
+elseif e_argument("platform") or e_argument("show-platform") then
+
+    -- locate platform
+
+    runners.loadbase()
+    runners.locate_platform()
+
+elseif e_argument("prefixes") then
+
+    runners.loadbase()
+    runners.prefixes()
+
+elseif e_argument("timedrun") then
+
+    -- locate platform
+
+    runners.loadbase()
+    runners.timedrun(filename)
+
+elseif e_argument("variables") or e_argument("show-variables") or e_argument("expansions") or e_argument("show-expansions") then
+
+    -- luatools: runners.execute_ctx_script("mtx-base","--expansions",filename)
+
+    resolvers.load("nofiles")
+    resolvers.listers.variables(e_argument("pattern"))
+
+elseif e_argument("configurations") or e_argument("show-configurations") then
+
+    -- luatools: runners.execute_ctx_script("mtx-base","--configurations",filename)
+
+    resolvers.load("nofiles")
+    resolvers.listers.configurations()
+
+elseif e_argument("find-file") then
+
+    -- luatools: runners.execute_ctx_script("mtx-base","--find-file",filename)
+
+    resolvers.load()
+    local e_all     = e_argument("all")
+    local e_pattern = e_argument("pattern")
+    local e_format  = e_argument("format")
+    local finder    = e_all and resolvers.findfiles or resolvers.findfile
+    if not e_pattern then
+        runners.register_arguments(filename)
+        environment.initializearguments(environment.arguments_after)
+        resolvers.dowithfilesandreport(finder,environment.files,e_format)
+    elseif type(e_pattern) == "string" then
+        resolvers.dowithfilesandreport(finder,{ e_pattern },e_format)
+    end
+
+elseif e_argument("find-path") then
+
+    -- luatools: runners.execute_ctx_script("mtx-base","--find-path",filename)
+
+    resolvers.load()
+    local path = resolvers.findpath(filename)
+    if e_verbose then
+        report(path)
+    else
+        print(path)
+    end
+
+elseif e_argument("expand-braces") then
+
+    -- luatools: runners.execute_ctx_script("mtx-base","--expand-braces",filename)
+
+    resolvers.load("nofiles")
+    runners.register_arguments(filename)
+    environment.initializearguments(environment.arguments_after)
+    resolvers.dowithfilesandreport(resolvers.expandbraces, environment.files)
+
+elseif e_argument("expand-path") then
+
+    -- luatools: runners.execute_ctx_script("mtx-base","--expand-path",filename)
+
+    resolvers.load("nofiles")
+    runners.register_arguments(filename)
+    environment.initializearguments(environment.arguments_after)
+    resolvers.dowithfilesandreport(resolvers.expandpath, environment.files)
+
+elseif e_argument("resolve-path") then
+
+    resolvers.load("nofiles")
+    runners.register_arguments(filename)
+    environment.initializearguments(environment.arguments_after)
+    resolvers.dowithfilesandreport(resolvers.cleanedpathlist, environment.files)
+
+elseif e_argument("expand-var") or e_argument("expand-variable") then
+
+    -- luatools: runners.execute_ctx_script("mtx-base","--expand-var",filename)
+
+    resolvers.load("nofiles")
+    runners.register_arguments(filename)
+    environment.initializearguments(environment.arguments_after)
+    resolvers.dowithfilesandreport(resolvers.expansion, environment.files)
+
+elseif e_argument("show-path") or e_argument("path-value") then
+
+    -- luatools: runners.execute_ctx_script("mtx-base","--show-path",filename)
+
+    resolvers.load("nofiles")
+    runners.register_arguments(filename)
+    environment.initializearguments(environment.arguments_after)
+    resolvers.dowithfilesandreport(resolvers.showpath, environment.files)
+
+elseif e_argument("var-value") or e_argument("show-value") then
+
+    -- luatools: runners.execute_ctx_script("mtx-base","--show-value",filename)
+
+    resolvers.load("nofiles")
+    runners.register_arguments(filename)
+    environment.initializearguments(environment.arguments_after)
+    resolvers.dowithfilesandreport(resolvers.variable,environment.files)
+
+elseif e_argument("format-path") then
+
+    -- luatools: runners.execute_ctx_script("mtx-base","--format-path",filename)
+
+    resolvers.load()
+    report(caches.getwritablepath("format"))
+
+-- elseif e_argument("pattern") then
+--
+--     -- luatools
+--
+--     runners.execute_ctx_script("mtx-base","--pattern='" .. e_argument("pattern") .. "'",filename)
+
+elseif e_argument("generate") then
+
+    -- luatools
+
+    if filename and filename ~= "" then
+        resolvers.load("nofiles")
+        trackers.enable("resolvers.locating")
+        resolvers.renew(filename)
+    else
+        resolvers.renewcache()
+        trackers.enable("resolvers.locating")
+        resolvers.load()
+    end
+
+    e_verbose = true
+
+elseif e_argument("make") or e_argument("ini") or e_argument("compile") then
+
+    -- luatools: runners.execute_ctx_script("mtx-base","--make",filename)
+
+    resolvers.load()
+    trackers.enable("resolvers.locating")
+    environment.make_format(filename)
+
+elseif e_argument("run") then
+
+    -- luatools
+
+    runners.execute_ctx_script("mtx-base","--run",filename)
+
+elseif e_argument("fmt") then
+
+    -- luatools
+
+    runners.execute_ctx_script("mtx-base","--fmt",filename)
+
+elseif e_argument("help") and filename=='base' then
+
+    -- luatools
+
+    runners.execute_ctx_script("mtx-base","--help")
+
+elseif e_argument("version") then
+
+    application.version()
+
+    application.report("source path",environment.ownbin)
+
+elseif e_argument("directives") then
+
+    directives.show()
+
+elseif e_argument("trackers") then
+
+    trackers.show()
+
+elseif e_argument("experiments") then
+
+    experiments.show()
+
+elseif e_argument("exporthelp") then
+
+    runners.loadbase()
+    application.export(e_argument("exporthelp"),filename)
+
+elseif e_argument("systeminfo") then
+
+    runners.systeminfo()
+
+elseif e_argument("locale") then
+
+    -- already done
+
+elseif e_argument("help") or filename=='help' or filename == "" then
+
+    application.help()
+
+elseif find(filename,"^bin:") then
+
+    runners.loadbase()
+    ok = runners.execute_program(filename)
+
+elseif is_mkii_stub then
+
+    -- execute mkii script
+
+    runners.loadbase()
+    ok = runners.execute_script(filename,false,true)
+
+elseif false then
+
+    runners.loadbase()
+    ok = runners.execute_ctx_script(filename)
+    if not ok then
+        ok = runners.execute_script(filename)
+    end
+
+elseif environment.files[1] == 'texmfcnf.lua' then -- so that we don't need to load mtx-base
+
+    resolvers.load("nofiles")
+    resolvers.listers.configurations()
+
+else
+    runners.loadbase()
+    runners.execute_ctx_script("mtx-base",filename)
+
+end
+
+if e_verbose then
+    report()
+    report("elapsed lua time: %0.3f seconds",os.runtime())
+end
+
+if os.type ~= "windows" then
+    texio.write("\n") -- is this still valid?
+end
+
+if ok == false then ok = 1 elseif ok == true or ok == nil then ok = 0 end
+
+if lua and lua.getexitcode then
+    ok = lua.getexitcode()
+end
+
+-- os.exit(ok,true) -- true forces a cleanup in 5.2+
+
+os.exit(ok)         -- true forces a cleanup in 5.2+ but reports a wrong number then

Added: trunk/Master/bin/universal-darwin/context
===================================================================
--- trunk/Master/bin/universal-darwin/context	                        (rev 0)
+++ trunk/Master/bin/universal-darwin/context	2023-02-28 19:06:16 UTC (rev 66253)
@@ -0,0 +1 @@
+link luametatex
\ No newline at end of file


Property changes on: trunk/Master/bin/universal-darwin/context
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/bin/universal-darwin/context.lua
===================================================================
--- trunk/Master/bin/universal-darwin/context.lua	                        (rev 0)
+++ trunk/Master/bin/universal-darwin/context.lua	2023-02-28 19:06:16 UTC (rev 66253)
@@ -0,0 +1,41 @@
+-- This file is a companion to "context(.exe)" and is effectively the same
+-- as:
+--
+--     mtxrun -script context ...
+--
+-- which will locate "mtx-context.lua" and load that one. The binary is a
+-- copy of "luametatex(.exe)" aka luatex 2.0 for context lmtx. In a similar
+-- fashion "mtxrun(.exe)" will load the "mtrun.lua" script.
+--
+-- The installation of context should do this on Windows:
+--
+-- luametatex.exe -> tex/texmf-win64/bin/luatex.exe
+-- luametatex.exe -> tex/texmf-win64/bin/mtxrun.exe
+-- luametatex.exe -> tex/texmf-win64/bin/context.exe
+-- mtxrun.lua     -> tex/texmf-win64/bin/mtxrun.lua
+-- context.lua    -> tex/texmf-win64/bin/context.lua
+--
+-- and this on Unix:
+--
+-- luametatex     -> tex/texmf-linux-64/bin/luatex
+-- luametatex     -> tex/texmf-linux-64/bin/mtxrun
+-- luametatex     -> tex/texmf-linux-64/bin/context
+-- mtxrun.lua     -> tex/texmf-linux-64/bin/mtxrun.lua
+-- context.lua    -> tex/texmf-linux-64/bin/context.lua
+--
+-- The static binary is smaller than 3MB so the few copies provide no real
+-- overhead.
+
+local selfpath = os.selfpath
+
+if not arg or not selfpath then
+    print("invalid stub")
+    os.exit()
+end
+
+arg[0] = "mtxrun"
+
+table.insert(arg,1,"mtx-context")
+table.insert(arg,1,"--script")
+
+dofile(selfpath .. "/" .. "mtxrun.lua")

Added: trunk/Master/bin/universal-darwin/luametatex
===================================================================
(Binary files differ)

Index: trunk/Master/bin/universal-darwin/luametatex
===================================================================
--- trunk/Master/bin/universal-darwin/luametatex	2023-02-28 16:13:59 UTC (rev 66252)
+++ trunk/Master/bin/universal-darwin/luametatex	2023-02-28 19:06:16 UTC (rev 66253)

Property changes on: trunk/Master/bin/universal-darwin/luametatex
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+application/x-mach-binary
\ No newline at end of property
Added: trunk/Master/bin/universal-darwin/mtxrun
===================================================================
--- trunk/Master/bin/universal-darwin/mtxrun	                        (rev 0)
+++ trunk/Master/bin/universal-darwin/mtxrun	2023-02-28 19:06:16 UTC (rev 66253)
@@ -0,0 +1 @@
+link luametatex
\ No newline at end of file


Property changes on: trunk/Master/bin/universal-darwin/mtxrun
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/bin/universal-darwin/mtxrun.lua
===================================================================
--- trunk/Master/bin/universal-darwin/mtxrun.lua	                        (rev 0)
+++ trunk/Master/bin/universal-darwin/mtxrun.lua	2023-02-28 19:06:16 UTC (rev 66253)
@@ -0,0 +1,27610 @@
+#!/usr/bin/env texlua
+
+if not modules then modules = { } end modules ['mtxrun'] = {
+    version   = 1.001,
+    comment   = "runner, lua replacement for texmfstart.rb",
+    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+    copyright = "PRAGMA ADE / ConTeXt Development Team",
+    license   = "see context related readme files"
+}
+
+-- one can make a stub:
+
+-- mtxrun :
+--
+-- #!/bin/sh
+-- env LUATEXDIR=/....../texmf/scripts/context/lua luatex --luaonly mtxrun.lua "$@"
+
+-- mtxrun.cmd :
+--
+-- @luatex --luaonly %~d0%~p0mtxrun.lua %*
+
+-- filename : mtxrun.lua
+-- comment  : companion to context.tex
+-- author   : Hans Hagen, PRAGMA-ADE, Hasselt NL
+-- copyright: PRAGMA ADE / ConTeXt Development Team
+-- license  : see context related readme files
+
+-- This script is based on texmfstart.rb but does not use kpsewhich to locate files.
+-- Although kpse is a library it never came to opening up its interface to other
+-- programs (esp scripting languages) and so we do it ourselves. The lua variant
+-- evolved out of an experimental ruby one. Interesting is that using a scripting
+-- language instead of c does not have a speed penalty. Actually the lua variant is
+-- more efficient, especially when multiple calls to kpsewhich are involved. The lua
+-- library also gives way more control.
+
+-- When libraries used here are updates you can run
+--
+--   mtxrun --selfmerge
+--
+-- to update the embedded code. After that you might need to run
+--
+--   mtxrun --selfupdate
+--
+-- to copy the new script (from scripts/context/lua) to location where
+-- binaries are expected. If you want to remove the embedded code you can run
+--
+--   mtxxun --selfclean
+
+-- to be done / considered
+--
+-- support for --exec or make it default
+-- support for jar files (or maybe not, never used, too messy)
+-- support for $RUBYINPUTS cum suis (if still needed)
+-- remember for subruns: _CTX_K_V_#{original}_
+-- remember for subruns: _CTX_K_S_#{original}_
+-- remember for subruns: TEXMFSTART.#{original} [tex.rb texmfstart.rb]
+
+-- begin library merge
+
+
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-bit32"] = package.loaded["l-bit32"] or true
+
+-- original size: 3607, stripped down to: 3009
+
+if not modules then modules={} end modules ['l-bit32']={
+ version=1.001,
+ license="the same as regular Lua",
+ source="bitwise.lua, v 1.24 2014/12/26 17:20:53 roberto",
+ comment="drop-in for bit32, adapted a bit by Hans Hagen",
+}
+if bit32 then
+elseif utf8 then
+ load ([[
+local select = select -- instead of: arg = { ... }
+bit32 = {
+  bnot = function (a)
+    return ~a & 0xFFFFFFFF
+  end,
+  band = function (x, y, z, ...)
+    if not z then
+      return ((x or -1) & (y or -1)) & 0xFFFFFFFF
+    else
+      local res = x & y & z
+      for i=1,select("#",...) do
+        res = res & select(i,...)
+      end
+      return res & 0xFFFFFFFF
+    end
+  end,
+  bor = function (x, y, z, ...)
+    if not z then
+      return ((x or 0) | (y or 0)) & 0xFFFFFFFF
+    else
+      local res = x | y | z
+      for i=1,select("#",...) do
+        res = res | select(i,...)
+      end
+      return res & 0xFFFFFFFF
+    end
+  end,
+  bxor = function (x, y, z, ...)
+    if not z then
+      return ((x or 0) ~ (y or 0)) & 0xFFFFFFFF
+    else
+      local res = x ~ y ~ z
+      for i=1,select("#",...) do
+        res = res ~ select(i,...)
+      end
+      return res & 0xFFFFFFFF
+    end
+  end,
+  btest = function (x, y, z, ...)
+    if not z then
+      return (((x or -1) & (y or -1)) & 0xFFFFFFFF) ~= 0
+    else
+      local res = x & y & z
+      for i=1,select("#",...) do
+          res = res & select(i,...)
+      end
+      return (res & 0xFFFFFFFF) ~= 0
+    end
+  end,
+  lshift = function (a, b)
+    return ((a & 0xFFFFFFFF) << b) & 0xFFFFFFFF
+  end,
+  rshift = function (a, b)
+    return ((a & 0xFFFFFFFF) >> b) & 0xFFFFFFFF
+  end,
+  arshift = function (a, b)
+    a = a & 0xFFFFFFFF
+    if b <= 0 or (a & 0x80000000) == 0 then
+      return (a >> b) & 0xFFFFFFFF
+    else
+      return ((a >> b) | ~(0xFFFFFFFF >> b)) & 0xFFFFFFFF
+    end
+  end,
+  lrotate = function (a ,b)
+    b = b & 31
+    a = a & 0xFFFFFFFF
+    a = (a << b) | (a >> (32 - b))
+    return a & 0xFFFFFFFF
+  end,
+  rrotate = function (a, b)
+    b = -b & 31
+    a = a & 0xFFFFFFFF
+    a = (a << b) | (a >> (32 - b))
+    return a & 0xFFFFFFFF
+  end,
+  extract = function (a, f, w)
+    return (a >> f) & ~(-1 << (w or 1))
+  end,
+  replace = function (a, v, f, w)
+    local mask = ~(-1 << (w or 1))
+    return ((a & ~(mask << f)) | ((v & mask) << f)) & 0xFFFFFFFF
+  end,
+}
+        ]] ) ()
+elseif bit then
+ load ([[
+local band, bnot, rshift, lshift = bit.band, bit.bnot, bit.rshift, bit.lshift
+bit32 = {
+  arshift = bit.arshift,
+  band    = band,
+  bnot    = bnot,
+  bor     = bit.bor,
+  bxor    = bit.bxor,
+  btest   = function(...)
+    return band(...) ~= 0
+  end,
+  extract = function(a,f,w)
+    return band(rshift(a,f),2^(w or 1)-1)
+  end,
+  lrotate = bit.rol,
+  lshift  = lshift,
+  replace = function(a,v,f,w)
+    local mask = 2^(w or 1)-1
+    return band(a,bnot(lshift(mask,f)))+lshift(band(v,mask),f)
+  end,
+  rrotate = bit.ror,
+  rshift  = rshift,
+}
+        ]] ) ()
+else
+ xpcall(function() local _,t=require("bit32") if t then bit32=t end return end,function() end)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-lua"] = package.loaded["l-lua"] or true
+
+-- original size: 6405, stripped down to: 2865
+
+if not modules then modules={} end modules ['l-lua']={
+ version=1.001,
+ comment="companion to luat-lib.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local next,type,tonumber=next,type,tonumber
+LUAMAJORVERSION,LUAMINORVERSION=string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$")
+LUAMAJORVERSION=tonumber(LUAMAJORVERSION) or 5
+LUAMINORVERSION=tonumber(LUAMINORVERSION) or 1
+LUAVERSION=LUAMAJORVERSION+LUAMINORVERSION/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
+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
+FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load
+if not FFISUPPORTED then
+ local okay;okay,ffi=pcall(require,"ffi")
+ FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load
+end
+if not FFISUPPORTED then
+ ffi=nil
+elseif not ffi.number then
+ ffi.number=tonumber
+end
+if LUAVERSION>5.3 then
+end
+if status and os.setenv then
+ os.setenv("engine",string.lower(status.luatex_engine or "unknown"))
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-macro"] = package.loaded["l-macro"] or true
+
+-- original size: 10130, stripped down to: 5990
+
+if not modules then modules={} end modules ['l-macros']={
+ 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 S,P,R,V,C,Cs,Cc,Ct,Carg=lpeg.S,lpeg.P,lpeg.R,lpeg.V,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Ct,lpeg.Carg
+local lpegmatch=lpeg.match
+local concat=table.concat
+local format,sub,match=string.format,string.sub,string.match
+local next,load,type=next,load,type
+local newline=S("\n\r")^1
+local continue=P("\\")*newline
+local whitespace=S(" \t\n\r")
+local spaces=S(" \t")+continue
+local nametoken=R("az","AZ","__","09")
+local name=nametoken^1
+local body=((continue/""+1)-newline)^1
+local lparent=P("(")
+local rparent=P(")")
+local noparent=1-(lparent+rparent)
+local nested=P { lparent*(noparent+V(1))^0*rparent }
+local escaped=P("\\")*P(1)
+local squote=P("'")
+local dquote=P('"')
+local quoted=dquote*(escaped+(1-dquote))^0*dquote+squote*(escaped+(1-squote))^0*squote
+local arguments=lparent*Ct((Cs((nested+(quoted+1-S("),")))^1)+S(", "))^0)*rparent
+local macros=lua.macros or {}
+lua.macros=macros
+local patterns={}
+local definitions={}
+local resolve
+local subparser
+local report_lua=function(...)
+ if logs and logs.reporter then
+  report_lua=logs.reporter("system","lua")
+  report_lua(...)
+ else
+  print(format(...))
+ end
+end
+local safeguard=P("local")*whitespace^1*name*(whitespace+P("="))
+resolve=safeguard+C(C(name)*(arguments^-1))/function(raw,s,a)
+ local d=definitions[s]
+ if d then
+  if a then
+   local n=#a
+   local p=patterns[s][n]
+   if p then
+    local d=d[n]
+    for i=1,n do
+     a[i]=lpegmatch(subparser,a[i]) or a[i]
+    end
+    return lpegmatch(p,d,1,a) or d
+   else
+    return raw
+   end
+  else
+   return d[0] or raw
+  end
+ elseif a then
+  for i=1,#a do
+   a[i]=lpegmatch(subparser,a[i]) or a[i]
+  end
+  return s.."("..concat(a,",")..")"
+ else
+  return raw
+ end
+end
+subparser=Cs((resolve+P(1))^1)
+local enddefine=P("#enddefine")/""
+local beginregister=(C(name)*(arguments+Cc(false))*C((1-enddefine)^1)*enddefine)/function(k,a,v)
+ local n=0
+ if a then
+  n=#a
+  local pattern=P(false)
+  for i=1,n do
+   pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end
+  end
+  pattern=Cs((pattern+P(1))^1)
+  local p=patterns[k]
+  if not p then
+   p={ [0]=false,false,false,false,false,false,false,false,false }
+   patterns[k]=p
+  end
+  p[n]=pattern
+ end
+ local d=definitions[k]
+ if not d then
+  d={ a=a,[0]=false,false,false,false,false,false,false,false,false }
+  definitions[k]=d
+ end
+ d[n]=lpegmatch(subparser,v) or v
+ return ""
+end
+local register=(Cs(name)*(arguments+Cc(false))*spaces^0*Cs(body))/function(k,a,v)
+ local n=0
+ if a then
+  n=#a
+  local pattern=P(false)
+  for i=1,n do
+   pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end
+  end
+  pattern=Cs((pattern+P(1))^1)
+  local p=patterns[k]
+  if not p then
+   p={ [0]=false,false,false,false,false,false,false,false,false }
+   patterns[k]=p
+  end
+  p[n]=pattern
+ end
+ local d=definitions[k]
+ if not d then
+  d={ a=a,[0]=false,false,false,false,false,false,false,false,false }
+  definitions[k]=d
+ end
+ d[n]=lpegmatch(subparser,v) or v
+ return ""
+end
+local unregister=(C(name)*spaces^0*(arguments+Cc(false)))/function(k,a)
+ local n=0
+ if a then
+  n=#a
+  local p=patterns[k]
+  if p then
+   p[n]=false
+  end
+ end
+ local d=definitions[k]
+ if d then
+  d[n]=false
+ end
+ return ""
+end
+local begindefine=(P("begindefine")*spaces^0/"")*beginregister
+local define=(P("define"  )*spaces^0/"")*register
+local undefine=(P("undefine"   )*spaces^0/"")*unregister
+local parser=Cs((((P("#")/"")*(define+begindefine+undefine)*(newline^0/"") )+resolve+P(1) )^0 )
+function macros.reset()
+ definitions={}
+ patterns={}
+end
+function macros.showdefinitions()
+ for name,list in table.sortedhash(definitions) do
+  local arguments=list.a
+  if arguments then
+   arguments="("..concat(arguments,",")..")"
+  else
+   arguments=""
+  end
+  print("macro: "..name..arguments)
+  for i=0,#list do
+   local l=list[i]
+   if l then
+    print("  "..l)
+   end
+  end
+ end
+end
+function macros.resolvestring(str)
+ return lpegmatch(parser,str) or str
+end
+function macros.resolving()
+ return next(patterns)
+end
+local function reload(path,name,data)
+ local only=match(name,".-([^/]+)%.lua")
+ if only and only~="" then
+  local name=path.."/"..only
+  local f=io.open(name,"wb")
+  f:write(data)
+  f:close()
+  local f=loadfile(name)
+  os.remove(name)
+  return f
+ end
+end
+local function reload(path,name,data)
+ if path and path~="" then
+  local only=string.match(name,".-([^/]+)%.lua")
+  if only and only~="" then
+   local name=path.."/"..only.."-macro.lua"
+   local f=io.open(name,"wb")
+   if f then
+    f:write(data)
+    f:close()
+    local l=loadfile(name)
+    os.remove(name)
+    return l
+   end
+  end
+ end
+ return load(data,name)
+end
+local function loaded(name,trace,detail)
+ local f=io.open(name,"rb")
+ if not f then
+  return false,format("file '%s' not found",name)
+ end
+ local c=f:read("*a")
+ if not c then
+  return false,format("file '%s' is invalid",name)
+ end
+ f:close()
+ local n=lpegmatch(parser,c)
+ if trace then
+  if #n~=#c then
+   report_lua("macros expanded in '%s' (%i => %i bytes)",name,#c,#n)
+   if detail then
+    report_lua()
+    report_lua(n)
+    report_lua()
+   end
+  elseif detail then
+   report_lua("no macros expanded in '%s'",name)
+  end
+ end
+ return reload(lfs and lfs.currentdir(),name,n)
+end
+macros.loaded=loaded
+function required(name,trace)
+ local filename=file.addsuffix(name,"lua")
+ local fullname=resolvers and resolvers.findfile(filename) or filename
+ if not fullname or fullname=="" then
+  return false
+ end
+ local codeblob=package.loaded[fullname]
+ if codeblob then
+  return codeblob
+ end
+ local code,message=loaded(fullname,macros,trace,trace)
+ if type(code)=="function" then
+  code=code()
+ else
+  report_lua("error when loading '%s'",fullname)
+  return false,message
+ end
+ if code==nil then
+  code=false
+ end
+ package.loaded[fullname]=code
+ return code
+end
+macros.required=required
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-sandbox"] = package.loaded["l-sandbox"] or true
+
+-- original size: 9604, stripped down to: 6394
+
+if not modules then modules={} end modules ['l-sandbox']={
+ 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 global=_G
+local next=next
+local unpack=unpack or table.unpack
+local type=type
+local tprint=texio and texio.write_nl or print
+local tostring=tostring
+local format=string.format 
+local concat=table.concat
+local sort=table.sort
+local gmatch=string.gmatch
+local gsub=string.gsub
+local requiem=require
+sandbox={}
+local sandboxed=false
+local overloads={}
+local skiploads={}
+local initializers={}
+local finalizers={}
+local originals={}
+local comments={}
+local trace=false
+local logger=false
+local blocked={}
+local function report(...)
+ tprint("sandbox         ! "..format(...)) 
+end
+sandbox.report=report
+function sandbox.setreporter(r)
+ report=r
+ sandbox.report=r
+end
+function sandbox.settrace(v)
+ trace=v
+end
+function sandbox.setlogger(l)
+ logger=type(l)=="function" and l or false
+end
+local function register(func,overload,comment)
+ if type(func)=="function" then
+  if type(overload)=="string" then
+   comment=overload
+   overload=nil
+  end
+  local function f(...)
+   if sandboxed then
+    local overload=overloads[f]
+    if overload then
+     if logger then
+      local result={ overload(func,...) }
+      logger {
+       comment=comments[f] or tostring(f),
+       arguments={... },
+       result=result[1] and true or false,
+      }
+      return unpack(result)
+     else
+      return overload(func,...)
+     end
+    else
+    end
+   else
+    return func(...)
+   end
+  end
+  if comment then
+   comments[f]=comment
+   if trace then
+    report("registering function: %s",comment)
+   end
+  end
+  overloads[f]=overload or false
+  originals[f]=func
+  return f
+ end
+end
+local function redefine(func,comment)
+ if type(func)=="function" then
+  skiploads[func]=comment or comments[func] or "unknown"
+  if overloads[func]==false then
+   overloads[func]=nil 
+  end
+ end
+end
+sandbox.register=register
+sandbox.redefine=redefine
+function sandbox.original(func)
+ return originals and originals[func] or func
+end
+function sandbox.overload(func,overload,comment)
+ comment=comment or comments[func] or "?"
+ if type(func)~="function" then
+  if trace then
+   report("overloading unknown function: %s",comment)
+  end
+ elseif type(overload)~="function" then
+  if trace then
+   report("overloading function with bad overload: %s",comment)
+  end
+ elseif overloads[func]==nil then
+  if trace then
+   report("function is not registered: %s",comment)
+  end
+ elseif skiploads[func] then
+  if trace then
+   report("function is not skipped: %s",comment)
+  end
+ else
+  if trace then
+   report("overloading function: %s",comment)
+  end
+  overloads[func]=overload
+ end
+ return func
+end
+local function whatever(specification,what,target)
+ if type(specification)~="table" then
+  report("%s needs a specification",what)
+ elseif type(specification.category)~="string" or type(specification.action)~="function" then
+  report("%s needs a category and action",what)
+ elseif not sandboxed then
+  target[#target+1]=specification
+ elseif trace then
+  report("already enabled, discarding %s",what)
+ end
+end
+function sandbox.initializer(specification)
+ whatever(specification,"initializer",initializers)
+end
+function sandbox.finalizer(specification)
+ whatever(specification,"finalizer",finalizers)
+end
+function require(name)
+ local n=gsub(name,"^.*[\\/]","")
+ local n=gsub(n,"[%.].*$","")
+ local b=blocked[n]
+ if b==false then
+  return nil 
+ elseif b then
+  if trace then
+   report("using blocked: %s",n)
+  end
+  return b
+ else
+  if trace then
+   report("requiring: %s",name)
+  end
+  return requiem(name)
+ end
+end
+function blockrequire(name,lib)
+ if trace then
+  report("preventing reload of: %s",name)
+ end
+ blocked[name]=lib or _G[name] or false
+end
+function sandbox.enable()
+ if not sandboxed then
+  debug={
+   traceback=debug.traceback,
+  }
+  for i=1,#initializers do
+   initializers[i].action()
+  end
+  for i=1,#finalizers do
+   finalizers[i].action()
+  end
+  local nnot=0
+  local nyes=0
+  local cnot={}
+  local cyes={}
+  local skip={}
+  for k,v in next,overloads do
+   local c=comments[k]
+   if v then
+    if c then
+     cyes[#cyes+1]=c
+    else 
+     nyes=nyes+1
+    end
+   else
+    if c then
+     cnot[#cnot+1]=c
+    else 
+     nnot=nnot+1
+    end
+   end
+  end
+  for k,v in next,skiploads do
+   skip[#skip+1]=v
+  end
+  if #cyes>0 then
+   sort(cyes)
+   report("overloaded known: %s",concat(cyes," | "))
+  end
+  if nyes>0 then
+   report("overloaded unknown: %s",nyes)
+  end
+  if #cnot>0 then
+   sort(cnot)
+   report("not overloaded known: %s",concat(cnot," | "))
+  end
+  if nnot>0 then
+   report("not overloaded unknown: %s",nnot)
+  end
+  if #skip>0 then
+   sort(skip)
+   report("not overloaded redefined: %s",concat(skip," | "))
+  end
+  initializers=nil
+  finalizers=nil
+  originals=nil
+  sandboxed=true
+ end
+end
+blockrequire("lfs",lfs)
+blockrequire("io",io)
+blockrequire("os",os)
+blockrequire("ffi",ffi)
+local function supported(library)
+ local l=_G[library]
+ return l
+end
+loadfile=register(loadfile,"loadfile")
+if supported("lua") then
+ lua.openfile=register(lua.openfile,"lua.openfile")
+end
+if supported("io") then
+ io.open=register(io.open,"io.open")
+ io.popen=register(io.popen,"io.popen") 
+ io.lines=register(io.lines,"io.lines")
+ io.output=register(io.output,"io.output")
+ io.input=register(io.input,"io.input")
+end
+if supported("os") then
+ os.execute=register(os.execute,"os.execute")
+ os.spawn=register(os.spawn,"os.spawn")
+ os.exec=register(os.exec,"os.exec")
+ os.rename=register(os.rename,"os.rename")
+ os.remove=register(os.remove,"os.remove")
+end
+if supported("lfs") then
+ lfs.chdir=register(lfs.chdir,"lfs.chdir")
+ lfs.mkdir=register(lfs.mkdir,"lfs.mkdir")
+ lfs.rmdir=register(lfs.rmdir,"lfs.rmdir")
+ lfs.isfile=register(lfs.isfile,"lfs.isfile")
+ lfs.isdir=register(lfs.isdir,"lfs.isdir")
+ lfs.attributes=register(lfs.attributes,"lfs.attributes")
+ lfs.dir=register(lfs.dir,"lfs.dir")
+ lfs.lock_dir=register(lfs.lock_dir,"lfs.lock_dir")
+ lfs.touch=register(lfs.touch,"lfs.touch")
+ lfs.link=register(lfs.link,"lfs.link")
+ lfs.setmode=register(lfs.setmode,"lfs.setmode")
+ lfs.readlink=register(lfs.readlink,"lfs.readlink")
+ lfs.shortname=register(lfs.shortname,"lfs.shortname")
+ lfs.symlinkattributes=register(lfs.symlinkattributes,"lfs.symlinkattributes")
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-package"] = package.loaded["l-package"] or true
+
+-- original size: 12566, stripped down to: 8937
+
+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,unpack=type,unpack
+local gsub,format,find=string.gsub,string.format,string.find
+local insert,remove=table.insert,table.remove
+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={
+  "reset loaded",
+  "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 checkedfiles={}
+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
+end
+local function pushpath(tag,what,target,path)
+ local path=helpers.cleanpath(path)
+ insert(target,1,path)
+ if helpers.trace then
+  helpers.report("pushing %s path in front: %s",tag,path)
+ end
+end
+local function poppath(tag,what,target)
+ local path=remove(target,1)
+ if helpers.trace then
+  if path then
+   helpers.report("popping %s path from front: %s",tag,path)
+  else
+   helpers.report("no %s path to pop",tag)
+  end
+ end
+end
+helpers.registerpath=registerpath
+function package.extraluapath(...)
+ registerpath("extra lua","lua",extraluapaths,...)
+end
+function package.pushluapath(path)
+ pushpath("extra lua","lua",extraluapaths,path)
+end
+function package.popluapath()
+ poppath("extra lua","lua",extraluapaths)
+end
+function package.extralibpath(...)
+ registerpath("extra lib","lib",extralibpaths,...)
+end
+function package.pushlibpath(path)
+ pushpath("extra lib","lib",extralibpaths,path)
+end
+function package.poplibpath()
+ poppath("extra lib","lua",extralibpaths)
+end
+local function loadedaslib(resolved,rawname) 
+ local base=gsub(rawname,"%.","_")
+ local init="luaopen_"..gsub(base,"%.","_")
+ local data={ resolved,init,"" }
+ checkedfiles[#checkedfiles+1]=data
+ if helpers.trace then
+  helpers.report("calling loadlib with '%s' with init '%s'",resolved,init)
+ end
+ local a,b,c=package.loadlib(resolved,init)
+ if not a and type(b)=="string" then
+  data[3]=string.fullstrip(b or "unknown error")
+ end
+ return a,b,c 
+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["reset loaded"]=function(name)
+ checkedfiles={}
+ return false
+end
+methods["already loaded"]=function(name)
+ return package.loaded[name]
+end
+methods["preload table"]=function(name)
+ local f=builtin["preload table"]
+ if f then
+  return f(name)
+ end
+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)
+ local f=builtin["path specification"]
+ if f then
+  getluapaths() 
+  return f(name)
+ end
+end
+methods["cpath specification"]=function(name)
+ local f=builtin["cpath specification"]
+ if f then
+  getlibpaths() 
+  return f(name)
+ end
+end
+methods["all in one fallback"]=function(name)
+ local f=builtin["all in one fallback"]
+ if f then
+  return f(name)
+ end
+end
+methods["not loaded"]=function(name)
+ if helpers.trace then
+  helpers.report("unable to locate '%s'",name or "?")
+  for i=1,#checkedfiles do
+   helpers.report("checked file '%s', initializer '%s', message '%s'",unpack(checkedfiles[i]))
+  end
+ 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]
+  local lookup=method and methods[method]
+  if type(lookup)=="function" then
+   if helpers.trace then
+    helpers.report("%s, level '%s', method '%s', name '%s'","locating",level,method,name)
+   end
+   local result,rest=lookup(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
+ 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)
+if context then
+ package.path=""
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-lpeg"] = package.loaded["l-lpeg"] or true
+
+-- original size: 38742, stripped down to: 19489
+
+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") 
+local lpeg=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 digits=digit^1
+local octdigit=R("07")
+local octdigits=octdigit^1
+local lowercase=R("az")
+local uppercase=R("AZ")
+local underscore=P("_")
+local hexdigit=digit+lowercase+uppercase
+local hexdigits=hexdigit^1
+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 nospacer=Cs((whitespace^1/""+nonwhitespace^1)^0)
+local b_collapser=Cs(whitespace^0/""*(nonwhitespace^1+whitespace^1/" ")^0)
+local m_collapser=Cs((nonwhitespace^1+whitespace^1/" ")^0)
+local e_collapser=Cs((whitespace^1*endofstring/""+nonwhitespace^1+whitespace^1/" ")^0)
+local x_collapser=Cs((nonwhitespace^1+whitespace^1/"" )^0)
+local b_stripper=Cs(spacer^0/""*(nonspacer^1+spacer^1/" ")^0)
+local m_stripper=Cs((nonspacer^1+spacer^1/" ")^0)
+local e_stripper=Cs((spacer^1*endofstring/""+nonspacer^1+spacer^1/" ")^0)
+local x_stripper=Cs((nonspacer^1+spacer^1/"" )^0)
+patterns.stripper=stripper
+patterns.fullstripper=fullstripper
+patterns.collapser=collapser
+patterns.nospacer=nospacer
+patterns.b_collapser=b_collapser
+patterns.m_collapser=m_collapser
+patterns.e_collapser=e_collapser
+patterns.x_collapser=x_collapser
+patterns.b_stripper=b_stripper
+patterns.m_stripper=m_stripper
+patterns.e_stripper=e_stripper
+patterns.x_stripper=x_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.digits=digits
+patterns.octdigit=octdigit
+patterns.octdigits=octdigits
+patterns.hexdigit=hexdigit
+patterns.hexdigits=hexdigits
+patterns.sign=sign
+patterns.cardinal=digits
+patterns.integer=sign^-1*digits
+patterns.unsigned=digit^0*period*digits
+patterns.float=sign^-1*patterns.unsigned
+patterns.cunsigned=digit^0*comma*digits
+patterns.cpunsigned=digit^0*(period+comma)*digits
+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*octdigits 
+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")*hexdigits
+patterns.hexafloat=sign^-1*zero*S("xX")*(hexdigit^0*period*hexdigits+hexdigits*period*hexdigit^0+hexdigits)*(S("pP")*sign^-1*hexdigits)^-1
+patterns.decafloat=sign^-1*(digit^0*period*digits+digits*period*digit^0+digits)*S("eE")*sign^-1*digits
+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/""*(endofstring+Cc(" ")))^0))
+local function anywhere(pattern) 
+ return (1-P(pattern))^0*P(pattern)
+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)
+ if action then
+  return (((1-P(pattern))^1)/action+1)^0
+ else
+  return (Cs((1-P(pattern))^1)+1)^0
+ end
+end
+function lpeg.tsplitter(pattern,action)
+ if action then
+  return Ct((((1-P(pattern))^1)/action+1)^0)
+ else
+  return Ct((Cs((1-P(pattern))^1)+1)^0)
+ end
+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
+function lpeg.counter(pattern,action)
+ local n=0
+ local pattern=(P(pattern)/function() n=n+1 end+anything)^0
+ if action then
+  return function(str) n=0;lpegmatch(pattern,str);action(n) end
+ else
+  return function(str) n=0;lpegmatch(pattern,str);return n end
+ 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 lower=utf and utf.lower or string.lower
+local upper=utf and utf.upper or string.upper
+function lpeg.setutfcasers(l,u)
+ lower=l or lower
+ upper=u or upper
+end
+local function make1(t,rest)
+ 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)*make1(v,v[""])
+   end
+  end
+ end
+ if rest then
+  p=p+p_true
+ end
+ return p
+end
+local function make2(t,rest) 
+ 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(lower(k))+P(upper(k)))*p_true
+   elseif v==false then
+   else
+    p=p+(P(lower(k))+P(upper(k)))*make2(v,v[""])
+   end
+  end
+ end
+ if rest then
+  p=p+p_true
+ end
+ return p
+end
+local function utfchartabletopattern(list,insensitive) 
+ 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 (insensitive and make2 or make1)(tree)
+end
+lpeg.utfchartabletopattern=utfchartabletopattern
+function lpeg.utfreplacer(list,insensitive)
+ local pattern=Cs((utfchartabletopattern(list,insensitive)/list+utf8character)^0)
+ return function(str)
+  return lpegmatch(pattern,str) or str
+ end
+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
+do
+ local trailingzeros=zero^0*-digit 
+ local stripper=Cs((
+  digits*(
+   period*trailingzeros/""+period*(digit-trailingzeros)^1*(trailingzeros/"")
+  )+1
+ )^0)
+ lpeg.patterns.stripzeros=stripper 
+ local nonzero=digit-zero
+ local trailingzeros=zero^1*endofstring
+ local stripper=Cs((1-period)^0*(
+  period*trailingzeros/""+period*(nonzero^1+(trailingzeros/"")+zero^1)^0+endofstring
+ ))
+ lpeg.patterns.stripzero=stripper
+end
+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
+local patterns={} 
+local function containsws(what)
+ local p=patterns[what]
+ if not p then
+  local p1=P(what)*(whitespace+endofstring)*Cc(true)
+  local p2=whitespace*P(p1)
+  p=P(p1)+P(1-p2)^0*p2+Cc(false)
+  patterns[what]=p
+ end
+ return p
+end
+lpeg.containsws=containsws
+function string.containsws(str,what)
+ return lpegmatch(patterns[what] or containsws(what),str)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-function"] = package.loaded["l-function"] or true
+
+-- original size: 361, stripped down to: 317
+
+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 -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-string"] = package.loaded["l-string"] or true
+
+-- original size: 6955, stripped down to: 3504
+
+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,find=string.sub,string.gmatch,string.format,string.char,string.byte,string.rep,string.lower,string.find
+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
+ local i=1
+ local l=#pattern
+ while true do
+  i=find(str,pattern,i)
+  if i then
+   n=n+1
+   i=i+l
+  else
+   break
+  end
+ 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 nospacer=patterns.nospacer
+local longtostring=patterns.longtostring
+function string.strip(str)
+ return str and lpegmatch(stripper,str) or ""
+end
+function string.fullstrip(str)
+ return str and lpegmatch(fullstripper,str) or ""
+end
+function string.collapsespaces(str)
+ return str and lpegmatch(collapser,str) or ""
+end
+function string.nospaces(str)
+ return str and lpegmatch(nospacer,str) or ""
+end
+function string.longtostring(str)
+ return str and lpegmatch(longtostring,str) or ""
+end
+local pattern=P(" ")^0*P(-1)
+function string.is_empty(str)
+ if not str or str=="" then
+  return true
+ else
+  return lpegmatch(pattern,str) and true or false
+ end
+end
+local anything=patterns.anything
+local moreescapes=Cc("%")*S(".-+%?()[]*$^{}")
+local allescapes=Cc("%")*S(".-+%?()[]*")   
+local someescapes=Cc("%")*S(".-+%()[]")  
+local matchescapes=Cc(".")*S("*?")     
+local pattern_m=Cs ((moreescapes+anything )^0 )
+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=="all" then
+  str=lpegmatch(pattern_m,str)
+ 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
+if not string.bytetable then 
+ local limit=5000 
+ function string.bytetable(str) 
+  local n=#str
+  if n>limit then
+   local t={ byte(str,1,limit) }
+   for i=limit+1,n do
+    t[i]=byte(str,i)
+   end
+   return t
+  else
+   return { byte(str,1,n) }
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-table"] = package.loaded["l-table"] or true
+
+-- original size: 41758, stripped down to: 22643
+
+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,select,rawget=type,next,tostring,tonumber,select,rawget
+local table,string=table,string
+local concat,sort=table.concat,table.sort
+local format,lower,dump=string.format,string.lower,string.dump
+local getmetatable,setmetatable=getmetatable,setmetatable
+local lpegmatch,patterns=lpeg.match,lpeg.patterns
+local floor=math.floor
+local stripper=patterns.stripper
+function table.getn(t)
+ return t and #t 
+end
+function table.strip(tab)
+ local lst={}
+ local 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={}
+  local 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={}
+  local category=0 
+  local s=0
+  for key in next,tab do
+   s=s+1
+   srt[s]=key
+   if category~=3 then
+    local tkey=type(key)
+    if category==1 then
+     if tkey~="string" then
+      category=3
+     end
+    elseif category==2 then
+     if tkey~="number" then
+      category=3
+     end
+    else
+     if tkey=="string" then
+      category=1
+     elseif tkey=="number" then
+      category=2
+     else
+      category=3
+     end
+    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={}
+  local 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={}
+  local 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={}
+  local 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,...) 
+ if not t then
+  t={}
+ end
+ 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={}
+ local 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) 
+ if not tables then
+  tables={}
+ end
+ 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={}
+ local 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,metacheck,accurate
+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','const',
+}
+local function is_simple_table(t,hexify,accurate) 
+ 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=rawget(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
+     if hexify then
+      tt[i]=format("0x%X",v)
+     elseif accurate then
+      tt[i]=format("%q",v)
+     else
+      tt[i]=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
+  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
+     if hexify then
+      tt[i+1]=format("0x%X",v)
+     elseif accurate then
+      tt[i+1]=format("%q",v)
+     else
+      tt[i+1]=v 
+     end
+    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
+table.is_simple_table=is_simple_table
+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=nil
+  local last=0
+  if compact then
+   last=#root
+   for k=1,last do
+    if rawget(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))
+     elseif accurate then
+      handle(format("%s %q,",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=is_simple_table(v,hexify,accurate)
+      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))
+     elseif accurate then
+      handle(format("%s [%s]=%q,",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))
+     elseif accurate then
+      handle(format("%s [%s]=%q,",depth,k and "true" or "false",v))
+     else
+      handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) 
+     end
+    elseif tk~="string" then
+    elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
+     if hexify then
+      handle(format("%s %s=0x%X,",depth,k,v))
+     elseif accurate then
+      handle(format("%s %s=%q,",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))
+     elseif accurate then
+      handle(format("%s [%q]=%q,",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))
+     elseif accurate then
+      handle(format("%s [%q]=%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 tk~="string" then
+    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))
+      elseif accurate then
+       handle(format("%s [%q]={},",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 tk~="string" then
+     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=is_simple_table(v,hexify,accurate)
+     if st then
+      if tk=="number" then
+       if hexify then
+        handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", ")))
+       elseif accurate then
+        handle(format("%s [%q]={ %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 tk~="string" then
+      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"))
+     elseif accurate then
+      handle(format("%s [%q]=%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 tk~="string" then
+    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 getinfo=debug and debug.getinfo
+     if getinfo 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))
+       elseif accurate then
+        handle(format("%s [%q]=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 tk~="string" then
+      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
+    end
+   else
+    if tk=="number" then
+     if hexify then
+      handle(format("%s [0x%X]=%q,",depth,k,tostring(v)))
+     elseif accurate then
+      handle(format("%s [%q]=%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 tk~="string" then
+    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
+  accurate=specification.accurate
+  handle=_handle or specification.handle or print
+  functions=specification.functions
+  compact=specification.compact
+  inline=specification.inline and compact
+  metacheck=specification.metacheck
+  if functions==nil then
+   functions=true
+  end
+  if compact==nil then
+   compact=true
+  end
+  if inline==nil then
+   inline=compact
+  end
+  if metacheck==nil then
+   metacheck=true
+  end
+ else
+  noquotes=false
+  hexify=false
+  handle=_handle or print
+  compact=true
+  inline=true
+  functions=true
+  metacheck=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 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
+  if next(root)~=nil then
+   do_serialize(root,name,"",0)
+  end
+ end
+ handle("}")
+end
+function table.serialize(root,name,specification)
+ local t={}
+ local 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={}
+   local 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 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  
+table.collapsedhash=collapsedhash
+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==b then
+  return true
+ elseif a and b and #a==#b then
+  if not n then
+   n=1
+  end
+  if not m then
+   m=#a
+  end
+  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) 
+ if a~=b then
+  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
+ 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.hashed(t) 
+ for i=1,#t do
+  t[t[i]]=i
+ end
+ return t
+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={}
+  local 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
+  local m=n+1
+  for i=1,floor(n/2) do 
+   local j=m-i
+   t[i],t[j]=t[j],t[i]
+  end
+  return t
+ end
+end
+local function sequenced(t,sep,simple)
+ if not t then
+  return ""
+ elseif type(t)~="table" then
+  return t 
+ end
+ local n=#t
+ local s={}
+ if n>0 then
+  for i=1,n do
+   local v=t[i]
+   if type(v)=="table" then
+    s[i]="{"..sequenced(v,sep,simple).."}"
+   else
+    s[i]=tostring(t[i])
+   end
+  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
+     if type(v)=="table" then
+      s[n]=k.."={"..sequenced(v,sep,simple).."}"
+     else
+      s[n]=k.."="..tostring(v)
+     end
+    end
+   else
+    n=n+1
+    if type(v)=="table" then
+     s[n]=k.."={"..sequenced(v,sep,simple).."}"
+    else
+     s[n]=k.."="..tostring(v)
+    end
+   end
+  end
+ end
+ if sep==true then
+  return "{ "..concat(s,", ").." }"
+ else
+  return concat(s,sep or " | ")
+ end
+end
+table.sequenced=sequenced
+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={}
+  local keys={}
+  local 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
+if not table.move then
+ function table.move(a1,f,e,t,a2)
+  if a2 and a1~=a2 then
+   for i=f,e do
+    a2[t]=a1[i]
+    t=t+1
+   end
+   return a2
+  else
+   t=t+e-f
+   for i=e,f,-1 do
+    a1[t]=a1[i]
+    t=t-1
+   end
+   return a1
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-io"] = package.loaded["l-io"] or true
+
+-- original size: 11988, stripped down to: 6430
+
+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 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 type=type
+if string.find(os.getenv("PATH") or "",";",1,true) then
+ io.fileseparator,io.pathseparator="\\",";"
+else
+ io.fileseparator,io.pathseparator="/",":"
+end
+local large=0x01000000 
+local medium=0x00100000 
+local small=0x00020000
+local function readall(f)
+ local size=f:seek("end")
+ if size>0 then
+  f:seek("set",0)
+  return f:read(size)
+ else
+  return ""
+ end
+end
+io.readall=readall
+function io.loaddata(filename,textmode) 
+ local f=open(filename,(textmode and 'r') or 'rb')
+ if f then
+  local size=f:seek("end")
+  local data=nil
+  if size>0 then
+   f:seek("set",0)
+   data=f:read(size)
+  end
+  f:close()
+  return data
+ 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
+    f:seek("set",0)
+    local data=f:read(size)
+    if action then
+     data=action(data)
+    end
+    if data then
+     g:write(data)
+    end
+   end
+   g:close()
+  end
+  f:close()
+  flush()
+ end
+end
+function io.savedata(filename,data,joiner,append)
+ local f=open(filename,append and "ab" or "wb")
+ if f then
+  if append and joiner and f:seek("end")>0 then
+   f:write(joiner)
+  end
+  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()
+  flush()
+  return true
+ else
+  return false
+ end
+end
+if fio and fio.readline then
+ local readline=fio.readline
+ function io.loadlines(filename,n) 
+  local f=open(filename,'r')
+  if not f then
+  elseif n then
+   local lines={}
+   for i=1,n do
+    local line=readline(f)
+    if line then
+     lines[i]=line
+    else
+     break
+    end
+   end
+   f:close()
+   lines=concat(lines,"\n")
+   if #lines>0 then
+    return lines
+   end
+  else
+   local line=readline(f)
+   f:close()
+   if line and #line>0 then
+    return line
+   end
+  end
+ end
+else
+ function io.loadlines(filename,n) 
+  local f=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[i]=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
+end
+function io.loadchunk(filename,n)
+ local f=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=open(filename)
+ if f==nil then
+  return false
+ else
+  f:close()
+  return true
+ end
+end
+function io.size(filename)
+ local f=open(filename)
+ if f==nil then
+  return 0
+ else
+  local s=f:seek("end")
+  f:close()
+  return s
+ end
+end
+local function noflines(f)
+ if type(f)=="string" then
+  local f=open(filename)
+  if f then
+   local n=f and 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
+io.noflines=noflines
+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
+  write(question)
+  if options then
+   write(format(" [%s]",concat(options,"|")))
+  end
+  if default then
+   write(format(" [%s]",default))
+  end
+  write(format(" "))
+  flush()
+  local answer=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 0x100*a+b
+ elseif n==3 then
+  local a,b,c=byte(f:read(3),1,3)
+  return 0x10000*a+0x100*b+c
+ elseif n==4 then
+  local a,b,c,d=byte(f:read(4),1,4)
+  return 0x1000000*a+0x10000*b+0x100*c+d
+ elseif n==8 then
+  local a,b=readnumber(f,4),readnumber(f,4)
+  return 0x100*a+b
+ elseif n==12 then
+  local a,b,c=readnumber(f,4),readnumber(f,4),readnumber(f,4)
+  return 0x10000*a+0x100*b+c
+ elseif n==-2 then
+  local b,a=byte(f:read(2),1,2)
+  return 0x100*a+b
+ elseif n==-3 then
+  local c,b,a=byte(f:read(3),1,3)
+  return 0x10000*a+0x100*b+c
+ elseif n==-4 then
+  local d,c,b,a=byte(f:read(4),1,4)
+  return 0x1000000*a+0x10000*b+0x100*c+d
+ elseif n==-8 then
+  local h,g,f,e,d,c,b,a=byte(f:read(8),1,8)
+  return 0x100000000000000*a+0x1000000000000*b+0x10000000000*c+0x100000000*d+0x1000000*e+0x10000*f+0x100*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 -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-number"] = package.loaded["l-number"] or true
+
+-- original size: 4588, stripped down to: 2159
+
+if not modules then modules={} end modules ['l-number']={
+ version=1.001,
+ comment="companion to luat-lib.mkxl",
+ 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,match,rep=string.format,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
+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,w)
+  if not w then
+   w=32
+  end
+  local n=w
+  for i=0,w-1 do
+   local v=bextract(b,i)
+   local k=w-i
+   if v==1 then
+    n=k
+    t[k]="1"
+   else
+    t[k]="0"
+   end
+  end
+  if w then
+   return concat(t,"",1,w)
+  elseif m then
+   m=33-m*8
+   if m<1 then
+    m=1
+   end
+   return concat(t,"",1,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
+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
+function number.idiv(i,d)
+ return floor(i/d) 
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-set"] = package.loaded["l-set"] or true
+
+-- original size: 1923, stripped down to: 1044
+
+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 -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-os"] = package.loaded["l-os"] or true
+
+-- original size: 20585, stripped down to: 10701
+
+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,difftime=os.date,os.time,os.difftime
+local find,format,gsub,upper,gmatch=string.find,string.format,string.gsub,string.upper,string.gmatch
+local concat=table.concat
+local random,ceil,randomseed,modf=math.random,math.ceil,math.randomseed,math.modf
+local type,setmetatable,tonumber,tostring=type,setmetatable,tonumber,tostring
+do
+ local selfdir=os.selfdir
+ if selfdir=="" then
+  selfdir=nil
+ end
+ if not selfdir then
+  if arg then
+   for i=1,#arg do
+    local a=arg[i]
+    if find(a,"^%-%-[c:]*texmfbinpath=") then
+     selfdir=gsub(a,"^.-=","")
+     break
+    end
+   end
+  end
+  if not selfdir then
+   selfdir=os.selfbin or "luatex"
+   if find(selfdir,"[/\\]") then
+    selfdir=gsub(selfdir,"[/\\][^/\\]*$","")
+   elseif os.getenv then
+    local path=os.getenv("PATH")
+    local name=gsub(selfdir,"^.*[/\\][^/\\]","")
+    local patt="[^:]+"
+    if os.type=="windows" then
+     patt="[^;]+"
+     name=name..".exe"
+    end
+    local isfile
+    if lfs then
+     local attributes=lfs.attributes
+     isfile=function(name)
+      local a=attributes(name,"mode")
+      return a=="file" or a=="link" or nil
+     end
+    else
+     local open=io.open
+     isfile=function(name)
+      local f=open(name)
+      if f then
+       f:close()
+       return true
+      end
+     end
+    end
+    for p in gmatch(path,patt) do
+     if isfile(p.."/"..name) then
+      selfdir=p
+      break
+     end
+    end
+   end
+  end
+  os.selfdir=selfdir or "."
+ end
+end
+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
+if not io.fileseparator then
+ if find(os.getenv("PATH"),";",1,true) then
+  io.fileseparator,io.pathseparator,os.type="\\",";",os.type or "windows"
+ 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
+do
+ local execute=os.execute
+ local iopopen=io.popen
+ local ostype=os.type
+ local function resultof(command)
+  local handle=iopopen(command,ostype=="windows" and "rb" or "r")
+  if handle then
+   local result=handle:read("*all") or ""
+   handle:close()
+   return result
+  else
+   return ""
+  end
+ end
+ os.resultof=resultof
+ function os.pipeto(command)
+  return iopopen(command,"w") 
+ end
+ local launchers={
+  windows="start %s",
+  macosx="open %s",
+  unix="xdg-open %s &> /dev/null &",
+ }
+ function os.launch(str)
+  local command=format(launchers[os.name] or launchers.unix,str)
+  execute(command)
+ end
+end
+do
+ local gettimeofday=os.gettimeofday or os.clock
+ os.gettimeofday=gettimeofday
+ local startuptime=gettimeofday()
+ function os.runtime()
+  return gettimeofday()-startuptime
+ end
+end
+do
+ local name=os.name or "linux"
+ local platform=os.getenv("MTX_PLATFORM") or ""
+ local architecture=os.uname and os.uname().machine 
+ local bits=os.getenv("MTX_BITS") or find(platform,"64") and 64 or 32
+ if platform~="" then
+ elseif os.type=="windows" then
+  architecture=string.lower(architecture or os.getenv("PROCESSOR_ARCHITECTURE") or "")
+  if architecture=="x86_64" then
+   bits,platform=64,"win64"
+  elseif find(architecture,"amd64") then
+   bits,platform=64,"win64"
+  elseif find(architecture,"arm64") then
+   bits,platform=64,"windows-arm64"
+  elseif find(architecture,"arm32") then
+   bits,platform=32,"windows-arm32"
+  else
+   bits,platform=32,"mswin"
+  end
+ elseif name=="linux" then
+  architecture=architecture or os.getenv("HOSTTYPE") or resultof("uname -m") or ""
+  local musl=find(os.selfdir or "","linuxmusl")
+  if find(architecture,"x86_64") then
+   bits,platform=64,musl and "linuxmusl" or "linux-64"
+  elseif find(architecture,"ppc") then
+   bits,platform=32,"linux-ppc" 
+  else
+   bits,platform=32,musl and "linuxmusl" or "linux"
+  end
+ elseif name=="macosx" then
+  architecture=architecture or resultof("echo $HOSTTYPE") or ""
+  if architecture=="" then
+   bits,platform=64,"osx-intel"
+  elseif find(architecture,"i386") then
+   bits,platform=64,"osx-intel"
+  elseif find(architecture,"x86_64") then
+   bits,platform=64,"osx-64"
+  elseif find(architecture,"arm64") then
+   bits,platform=64,"osx-arm"
+  else
+   bits,platform=32,"osx-ppc"
+  end
+ elseif name=="sunos" then
+  architecture=architecture or resultof("uname -m") or ""
+  if find(architecture,"sparc") then
+   bits,platform=32,"solaris-sparc"
+  else 
+   bits,platform=32,"solaris-intel"
+  end
+ elseif name=="freebsd" then
+  architecture=architecture or os.getenv("MACHTYPE") or resultof("uname -m") or ""
+  if find(architecture,"amd64") or find(architecture,"AMD64") then
+   bits,platform=64,"freebsd-amd64"
+  else
+   bits,platform=32,"freebsd"
+  end
+ elseif name=="kfreebsd" then
+  architecture=architecture or os.getenv("HOSTTYPE") or resultof("uname -m") or ""
+  if architecture=="x86_64" then
+   bits,platform=64,"kfreebsd-amd64"
+  else
+   bits,platform=32,"kfreebsd-i386"
+  end
+ else
+  architecture=architecture or resultof("uname -m") or ""
+  if find(architecture,"aarch64") then
+   bits,platform="linux-aarch64"
+  elseif find(architecture,"armv7l") then
+   bits,platform=32,"linux-armhf"
+  elseif find(architecture,"mips64") or find(architecture,"mips64el") then
+   bits,platform=64,"linux-mipsel"
+  elseif find(architecture,"mipsel") or find(architecture,"mips") then
+   bits,platform=32,"linux-mipsel"
+  else
+   bits,platform=64,"linux-64" 
+  end
+ end
+ os.setenv("MTX_PLATFORM",platform)
+ os.setenv("MTX_BITS",bits)
+ os.platform=platform
+ os.bits=bits
+ os.newline=name=="windows" and "\013\010" or "\010" 
+end
+do
+ 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
+end
+do
+ local hour,min
+ function os.timezone(difference)
+  if not hour then
+   local current=time()
+   local utcdate=date("!*t",current)
+   local localdate=date("*t",current)
+   localdate.isdst=false
+   local timediff=difftime(time(localdate),time(utcdate))
+   hour,min=modf(timediff/3600)
+   min=min*60
+  end
+  if difference then
+   return hour,min
+  else
+   return format("%+03d:%02d",hour,min) 
+  end
+ end
+ local timeformat=format("%%s%s",os.timezone())
+ 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
+ function os.today()
+  return date("!*t")
+ end
+ function os.now()
+  return date("!%Y-%m-%d %H:%M:%S")
+ end
+end
+do
+ local cache={}
+ local function which(filename)
+  local fullname=cache[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
+   cache[filename]=fullname
+  end
+  return fullname
+ end
+ os.which=which
+ os.where=which
+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
+do
+ local function isleapyear(year)
+  return (year%4==0) and (year%100~=0 or year%400==0)
+ end
+ os.isleapyear=isleapyear
+ local days={ 31,28,31,30,31,30,31,31,30,31,30,31 }
+ local function nofdays(year,month,day)
+  if not month then
+   return isleapyear(year) and 365 or 364
+  elseif not day then
+   return month==2 and isleapyear(year) and 29 or days[month]
+  else
+   for i=1,month-1 do
+    day=day+days[i]
+   end
+   if month>2 and isleapyear(year) then
+    day=day+1
+   end
+   return day
+  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
+ function os.date(fmt,...)
+  if not fmt then
+   fmt="%Y-%m-%d %H:%M"
+  end
+  return date(fmt,...)
+ end
+end
+do
+ local osexit=os.exit
+ local exitcode=nil
+ function os.setexitcode(code)
+  exitcode=code
+ end
+ function os.exit(c)
+  if exitcode~=nil then
+   return osexit(exitcode)
+  end
+  if c~=nil then
+   return osexit(c)
+  end
+  return osexit()
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-file"] = package.loaded["l-file"] or true
+
+-- original size: 22186, stripped down to: 10313
+
+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 attributes=lfs.attributes
+function lfs.isdir(name)
+ if name then
+  return attributes(name,"mode")=="directory"
+ end
+end
+function lfs.isfile(name)
+ if name then
+  local a=attributes(name,"mode")
+  return a=="file" or a=="link" or nil
+ end
+end
+function lfs.isfound(name)
+ if name then
+  local a=attributes(name,"mode")
+  return (a=="file" or a=="link") and name or nil
+ end
+end
+function lfs.modification(name)
+ return name and attributes(name,"modification") or nil
+end
+if sandbox then
+ sandbox.redefine(lfs.isfile,"lfs.isfile")
+ sandbox.redefine(lfs.isdir,"lfs.isdir")
+ sandbox.redefine(lfs.isfound,"lfs.isfound")
+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
+if lfs.isreadablefile and lfs.iswritablefile then
+ file.is_readable=lfs.isreadablefile
+ file.is_writable=lfs.iswritablefile
+else
+ 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
+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(reslasher,one)
+ end
+ if not one or 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
+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=loaddata(oldname)
+  if data and data~="" then
+   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
+function file.withinbase(path) 
+ local l=0
+ if not find(path,"^/") then
+  path="/"..path
+ end
+ for dir in gmatch(path,"/([^/]+)") do
+  if dir==".." then
+   l=l-1
+  elseif dir~="." then
+   l=l+1
+  end
+  if l<0 then
+   return false
+  end
+ end
+ return true
+end
+local symlinkattributes=lfs.symlinkattributes
+function lfs.readlink(name)
+ return symlinkattributes(name,"target") or nil
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-gzip"] = package.loaded["l-gzip"] or true
+
+-- original size: 268, stripped down to: 216
+
+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"
+}
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-md5"] = package.loaded["l-md5"] or true
+
+-- original size: 3414, stripped down to: 2307
+
+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
+local modification,isfile,touch=lfs.modification,lfs.isfile,lfs.touch
+local loaddata,savedata=io.loaddata,io.savedata
+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
+  md5.sumhexa=md5.hex
+  md5.sumHEXA=md5.HEX
+ end
+end
+local md5HEX=md5.HEX
+function file.needsupdating(oldname,newname,threshold) 
+ local oldtime=modification(oldname)
+ if oldtime then
+  local newtime=modification(newname)
+  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=modification(oldname)
+ if oldtime and isfile(newname) then
+  touch(newname,oldtime,oldtime)
+ end
+end
+local function checksum(name)
+ if md5 then
+  local data=loaddata(name)
+  if data then
+   return md5HEX(data)
+  end
+ end
+ return nil
+end
+file.checksum=checksum
+function file.loadchecksum(name)
+ if md5 then
+  local data=loaddata(name..".md5")
+  return data and (gsub(data,"%s",""))
+ end
+ return nil
+end
+function file.savechecksum(name,checksum)
+ if not checksum then checksum=checksum(name) end
+ if checksum then
+  savedata(name..".md5",checksum)
+  return checksum
+ end
+ return nil
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-sha"] = package.loaded["l-sha"] or true
+
+-- original size: 1085, stripped down to: 969
+
+if not modules then modules={} end modules ['l-sha']={
+ 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"
+}
+if sha2 then
+ local lpegmatch=lpeg.match
+ local lpegpatterns=lpeg.patterns
+ local bytestohex=lpegpatterns.bytestohex
+ local bytestoHEX=lpegpatterns.bytestoHEX
+ local digest256=sha2.digest256
+ local digest384=sha2.digest384
+ local digest512=sha2.digest512
+ sha2.hash256=function(str) return lpegmatch(bytestohex,digest256(str)) end
+ sha2.hash384=function(str) return lpegmatch(bytestohex,digest384(str)) end
+ sha2.hash512=function(str) return lpegmatch(bytestohex,digest512(str)) end
+ sha2.HASH256=function(str) return lpegmatch(bytestoHEX,digest256(str)) end
+ sha2.HASH384=function(str) return lpegmatch(bytestoHEX,digest384(str)) end
+ sha2.HASH512=function(str) return lpegmatch(bytestoHEX,digest512(str)) end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-url"] = package.loaded["l-url"] or true
+
+-- original size: 14713, stripped down to: 6981
+
+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,next=tonumber,type,next
+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
+local sortedhash=table.sortedhash
+url=url or {}
+local url=url
+local unescapes={}
+local escapes={}
+setmetatable(unescapes,{ __index=function(t,k)
+ local v=char(tonumber(k,16))
+ t[k]=v
+ return v
+end })
+setmetatable(escapes,{ __index=function(t,k)
+ local v=format("%%%02X",byte(k))
+ t[k]=v
+ return v
+end })
+local colon=P(":")
+local qmark=P("?")
+local hash=P("#")
+local slash=P("/")
+local atsign=P("@")
+local percent=P("%")
+local endofstring=P(-1)
+local hexdigit=R("09","AF","af")
+local plus=P("+")
+local nothing=Cc("")
+local okay=R("09","AZ","az")+S("-_.,:=+*~!'()@&$")
+local escapedchar=(percent*C(hexdigit*hexdigit))/unescapes
+local unescapedchar=P(1)/escapes
+local escaped=(plus/" ")+escapedchar 
+local noslash=P("/")/""
+local plustospace=P("+")/" "
+local decoder=Cs((
+     plustospace+escapedchar+P("\r\n")/"\n"+P(1)
+    )^0 )
+local encoder=Cs((
+     R("09","AZ","az")^1+S("-./_")^1+P(" ")/"+"+P("\n")/"\r\n"+unescapedchar
+    )^0 )
+lpegpatterns.urldecoder=decoder
+lpegpatterns.urlencoder=encoder
+function url.decode  (str) return str and lpegmatch(decoder,str) or str end
+function url.encode  (str) return str and lpegmatch(encoder,str) or str end
+function url.unescape(str) return str and lpegmatch(unescaper,str) or str end
+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 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(((plustospace+escapedchar+1)-equal     )^0)
+local value=Cs(((plustospace+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 userpart=(1-atsign-colon)^1
+local serverpart=(1-colon)^1
+local splitauthority=((Cs(userpart)*colon*Cs(userpart)+Cs(userpart)*Cc(nil))*atsign+Cc(nil)*Cc(nil))*Cs(serverpart)*(colon*(serverpart/tonumber)+Cc(nil))
+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  
+ local username  
+ local password  
+ local host   
+ local port   
+ if authority~="" then
+  username,password,host,port=lpegmatch(splitauthority,authority)
+ end
+ 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,
+  host=host,
+  port=port,
+ }
+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 result,r={},0
+ local scheme=hash.scheme
+ local authority=hash.authority
+ local path=hash.path
+ local queries=hash.queries
+ local fragment=hash.fragment
+ if scheme and scheme~="" then
+  r=r+1;result[r]=lpegmatch(escaper,scheme)
+  r=r+1;result[r]="://"
+ end
+ if authority and authority~="" then
+  r=r+1;result[r]=lpegmatch(escaper,authority)
+ end
+ if path and path~="" then
+  r=r+1;result[r]="/"
+  r=r+1;result[r]=lpegmatch(escaper,path)
+ end
+ if queries then
+  local done=false
+  for k,v in sortedhash(queries) do
+   r=r+1;result[r]=done and "&" or "?"
+   r=r+1;result[r]=lpegmatch(escaper,k) 
+   r=r+1;result[r]="="
+   r=r+1;result[r]=lpegmatch(escaper,v) 
+   done=true
+  end
+ end
+ if fragment and fragment~="" then
+  r=r+1;result[r]="#"
+  r=r+1;result[r]=lpegmatch(escaper,fragment)
+ end
+ return concat(result)
+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 -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-dir"] = package.loaded["l-dir"] or true
+
+-- original size: 18217, stripped down to: 10792
+
+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
+  local nofdirs=0
+  for name,mode,size,time in walkdir(usedpath) do
+   if name~="." and name~=".." then
+    local full=path..name
+    if mode==nil then
+     mode=attributes(full,'mode')
+    end
+    if mode=='file' then
+     if not patt or find(full,patt) then
+      action(full,size,time)
+     end
+    elseif recurse and mode=="directory" then
+     if dirs then
+      nofdirs=nofdirs+1
+      dirs[nofdirs]=full
+     else
+      nofdirs=1
+      dirs={ full }
+     end
+    end
+   end
+  end
+  if dirs then
+   for i=1,nofdirs 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
+ local usedpath
+ if path=="/" then
+  usedpath="/."
+ elseif not find(path,"/$") then
+  usedpath=path.."/."
+  path=path.."/"
+ else
+  usedpath=path
+ end
+ local dirs
+ local nofdirs=0
+ local noffiles=#result
+ for name,mode in walkdir(usedpath) do
+  if name~="." and name~=".." then
+   local full=path..name
+   if mode==nil then
+    mode=attributes(full,'mode')
+   end
+   if mode=='file' then
+    if not patt or find(full,patt) then
+     noffiles=noffiles+1
+     result[noffiles]=full
+    end
+   elseif recurse and mode=="directory" then
+    if dirs then
+     nofdirs=nofdirs+1
+     dirs[nofdirs]=full
+    else
+     nofdirs=1
+     dirs={ full }
+    end
+   end
+  end
+ end
+ if dirs then
+  for i=1,nofdirs do
+   glob_pattern_table(dirs[i],patt,recurse,result)
+  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
+ local okay=isdir(path)
+ if kind=="function" then
+  return okay and glob_pattern_function(path,patt,recurse,method) or {}
+ elseif kind=="table" then
+  return okay and glob_pattern_table(path,patt,recurse,method) or method
+ else
+  return okay and glob_pattern_table(path,patt,recurse,{}) or {}
+ 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={
+  (Cs(P(".")+slash^1)+Cs(R("az","AZ")*P(":")*slash^0)+Cc("./"))*V(2)*V(3),
+  Cs(((1-S("*?/\\"))^0*slash)^0),
+  Cs(P(1)^0)
+ }
+else
+ pattern={
+  (C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3),
+  C(((1-S("*?/"))^0*P("/"))^0),
+  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,mode in walkdir(path) do
+  if find(name,"^%.") then
+  else
+   if mode==nil then
+    mode=attributes(name,'mode')
+   end
+   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
+local function globdirs(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,mode in walkdir(path) do
+  if find(name,"^%.") then
+  else
+   if mode==nil then
+    mode=attributes(name,'mode')
+   end
+   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
+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)
+ local curdir=currentdir()
+ insert(stack,curdir)
+ if newdir and newdir~="" and chdir(newdir) then
+  return newdir
+ else
+  return curdir
+ 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 -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-boolean"] = package.loaded["l-boolean"] or true
+
+-- original size: 1850, stripped down to: 1498
+
+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 -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-unicode"] = package.loaded["l-unicode"] or true
+
+-- original size: 41303, stripped down to: 17277
+
+if not modules then modules={} end modules ['l-unicode']={
+ version=1.001,
+ optimize=true,
+ 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=nil
+if not string.utfcharacters then
+ local gmatch=string.gmatch
+ function string.characters(str)
+  return gmatch(str,".[\128-\191]*")
+ end
+end
+utf.characters=string.utfcharacters
+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 p_utftype=patterns.utftype
+local p_utfstricttype=patterns.utfstricttype
+local p_utfoffset=patterns.utfoffset
+local p_utf8character=patterns.utf8character
+local p_utf8char=patterns.utf8char
+local p_utf8byte=patterns.utf8byte
+local p_utfbom=patterns.utfbom
+local p_newline=patterns.newline
+local p_whitespace=patterns.whitespace
+if not utf.char then
+ utf.char=string.utfcharacter or (utf8 and utf8.char)
+ if not utf.char then
+  local char=string.char
+  if bit32 then
+   local rshift=bit32.rshift
+   function utf.char(n)
+    if n<0x80 then
+     return char(n)
+    elseif n<0x800 then
+     return char(
+      0xC0+rshift(n,6),
+      0x80+(n%0x40)
+     )
+    elseif n<0x10000 then
+     return char(
+      0xE0+rshift(n,12),
+      0x80+(rshift(n,6)%0x40),
+      0x80+(n%0x40)
+     )
+    elseif n<0x200000 then
+     return char(
+      0xF0+rshift(n,18),
+      0x80+(rshift(n,12)%0x40),
+      0x80+(rshift(n,6)%0x40),
+      0x80+(n%0x40)
+     )
+    else
+     return ""
+    end
+   end
+  else
+   local floor=math.floor
+   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
+ end
+end
+if not utf.byte then
+ utf.byte=string.utfvalue or (utf8 and utf8.codepoint)
+ if not utf.byte then
+  function utf.byte(c)
+   return lpegmatch(p_utf8byte,c)
+  end
+ 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
+ utf.len=string.utflength or (utf8 and utf8.len)
+ 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
+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_utf8character,slide_zero)^0
+ local pattern_one=Cmt(p_utf8character,slide_one )^0
+ local pattern_two=Cmt(p_utf8character,slide_two )^0
+ local pattern_first=C(p_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_utf8character)^0)
+     end
+     return lpegmatch(pattern,str)
+    end
+   end
+  elseif option=="pattern" then
+   return Cs((tabletopattern(mapping)/action+p_utf8character)^0)
+  else
+   local pattern=Cs((tabletopattern(mapping)/action+p_utf8character)^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_utf8character/mapping+p_utf8character)^0)
+  else
+   local pattern=Cs((p_utf8character/mapping+p_utf8character)^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_utf8character)^0)
+local utfcharsplitter_iws=p_utfbom^-1*Ct((p_whitespace^1+C(p_utf8character))^0)
+local utfcharsplitter_raw=Ct(C(p_utf8character)^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
+if bit32 then
+ local rshift=bit32.rshift
+ local function little(b)
+  if b<0x10000 then
+   return char(b%256,rshift(b,8))
+  else
+   b=b-0x10000
+   local b1=rshift(b,10)+0xD800
+   local b2=b%1024+0xDC00
+   return char(b1%256,rshift(b1,8),b2%256,rshift(b2,8))
+  end
+ end
+ local function big(b)
+  if b<0x10000 then
+   return char(rshift(b,8),b%256)
+  else
+   b=b-0x10000
+   local b1=rshift(b,10)+0xD800
+   local b2=b%1024+0xDC00
+   return char(rshift(b1,8),b1%256,rshift(b2,8),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
+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
+do
+ local p_nany=p_utf8character/""
+ 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 string.utfvalues then
+ local find=string.find
+ local dummy=function()
+ end
+ function string.utfvalues(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
+end
+utf.values=string.utfvalues
+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
+if bit32 then
+ local extract=bit32.extract
+ local char=string.char
+ function utf.toutf32string(n)
+  if n<=0xFF then
+   return
+    char(n).."\000\000\000"
+  elseif n<=0xFFFF then
+   return
+    char(extract(n,0,8))..char(extract(n,8,8)).."\000\000"
+  elseif n<=0xFFFFFF then
+   return
+    char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8)).."\000"
+  else
+   return
+    char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8))..char(extract(n,24,8))
+  end
+ end
+end
+local len=utf.len
+local rep=rep
+function string.utfpadd(s,n)
+ if n and n~=0 then
+  local l=len(s)
+  if n>0 then
+   local d=n-l
+   if d>0 then
+    return rep(c or " ",d)..s
+   end
+  else
+   local d=- n-l
+   if d>0 then
+    return s..rep(c or " ",d)
+   end
+  end
+ end
+ return s
+end
+do
+ local utfcharacters=utf.characters or string.utfcharacters
+ local utfchar=utf.char    or string.utfcharacter
+ lpeg.UP=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
+ else
+  function lpeg.US(str)
+   local p=P(false)
+   local f=function(uc)
+    p=p+P(uc)
+   end
+   lpegmatch((p_utf8char/f)^0,str)
+   return p
+  end
+ end
+ local range=p_utf8byte*p_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)
+  end
+  if not utfchar then
+   utfchar=utf.char 
+  end
+  if 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 p_utf8byte/f 
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["l-math"] = package.loaded["l-math"] or true
+
+-- original size: 2679, stripped down to: 1909
+
+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"
+}
+if not math.ceiling then
+ math.ceiling=math.ceil
+end
+if not math.round then
+ if xmath then
+  math.round=xmath.round
+ else
+  local floor=math.floor
+  function math.round(x)
+   return x<0 and -floor(-x+0.5) or floor(x+0.5)
+  end
+ end
+end
+if not math.div then
+ local floor=math.floor
+ 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
+if not math.sind then
+ local sin,cos,tan=math.sin,math.cos,math.tan
+ local pipi=2*math.pi/360
+ 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
+if not math.cosh then
+ local exp=math.exp
+ function math.cosh(x)
+  local xx=exp(x)
+  return (xx+1/xx)/2
+ end
+ function math.sinh(x)
+  local xx=exp(x)
+  return (xx-1/xx)/2
+ end
+ function math.tanh(x)
+  local xx=exp(x)
+  return (xx-1/xx)/(xx+1/xx)
+ end
+end
+if not math.pow then
+ function math.pow(x,y)
+  return x^y
+ end
+end
+if not math.atan2 then
+ math.atan2=math.atan
+end
+if not math.ldexp then
+ function math.ldexp(x,e)
+  return x*2.0^e
+ end
+end
+if not math.log10 then
+ local log=math.log
+ function math.log10(x)
+  return log(x,10)
+ end
+end
+if not math.type then
+ function math.type()
+  return "float"
+ end
+end
+if not math.tointeger then
+ math.mininteger=-0x4FFFFFFFFFFF
+ math.maxinteger=0x4FFFFFFFFFFF
+ local floor=math.floor
+ function math.tointeger(n)
+  local f=floor(n)
+  return f==n and f or nil
+ end
+end
+if not math.ult then
+ local floor=math.floor
+ function math.ult(m,n)
+  return floor(m)<floor(n) 
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-str"] = package.loaded["util-str"] or true
+
+-- original size: 46322, stripped down to: 24128
+
+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,find,char=string.format,string.gsub,string.rep,string.sub,string.find,string.char
+local load,dump=load,string.dump
+local tonumber,type,tostring,next,setmetatable=tonumber,type,tostring,next,setmetatable
+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 tsplitat=lpeg.tsplitat
+local utfchar,utfbyte,utflen=utf.char,utf.byte,utf.len
+local 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
+if not number then number={} end 
+local stripzero=patterns.stripzero
+local stripzeros=patterns.stripzeros
+local newline=patterns.newline
+local endofstring=patterns.endofstring
+local anything=patterns.anything
+local whitespace=patterns.whitespace
+local space=patterns.space
+local spacer=patterns.spacer
+local spaceortab=patterns.spaceortab
+local digit=patterns.digit
+local sign=patterns.sign
+local period=patterns.period
+local ptf=1/65536
+local bpf=(7200/7227)/65536
+local function points(n)
+ if n==0 then
+  return "0pt"
+ end
+ n=tonumber(n)
+ if not n or n==0 then
+  return "0pt"
+ end
+ n=n*ptf
+ if n%1==0 then
+  return format("%ipt",n)
+ else
+  return lpegmatch(stripzeros,format("%.5fpt",n)) 
+ end
+end
+local function nupoints(n)
+ if n==0 then
+  return "0"
+ end
+ n=tonumber(n)
+ if not n or n==0 then
+  return "0"
+ end
+ n=n*ptf
+ if n%1==0 then
+  return format("%i",n)
+ else
+  return format("%.5f",n) 
+ end
+end
+local function basepoints(n)
+ if n==0 then
+  return "0bp"
+ end
+ n=tonumber(n)
+ if not n or n==0 then
+  return "0bp"
+ end
+ n=n*bpf
+ if n%1==0 then
+  return format("%ibp",n)
+ else
+  return lpegmatch(stripzeros,format("%.5fbp",n)) 
+ end
+end
+local function nubasepoints(n)
+ if n==0 then
+  return "0"
+ end
+ n=tonumber(n)
+ if not n or n==0 then
+  return "0"
+ end
+ n=n*bpf
+ if n%1==0 then
+  return format("%i",n)
+ else
+  return format("%.5f",n) 
+ end
+end
+number.points=points
+number.nupoints=nupoints
+number.basepoints=basepoints
+number.nubasepoints=nubasepoints
+local rubish=spaceortab^0*newline
+local anyrubish=spaceortab+newline
+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+anything
+  )^1)
+function strings.tabtospace(str,tab)
+ return lpegmatch(pattern,str,1,tab or 7)
+end
+function string.utfpadding(s,n)
+ if not n or n==0 then
+  return ""
+ end
+ local l=utflen(s)
+ if n>0 then
+  return nspaces[n-l]
+ else
+  return nspaces[-n-l]
+ end
+end
+local optionalspace=spacer^0
+local nospace=optionalspace/""
+local endofline=nospace*newline
+local stripend=(whitespace^1*endofstring)/""
+local normalline=(nospace*((1-optionalspace*(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 intospace=whitespace^1/" "
+local noleading=whitespace^1/""
+local notrailing=noleading*endofstring
+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_prune_intospace=Cs (noleading*(notrailing+intospace+1     )^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,
+ ["prune and to space"]=p_prune_intospace,
+ ["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
+function strings.collapse(str) 
+ return str and lpegmatch(p_prune_intospace,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 two=digit*digit
+local three=two*digit
+local prefix=(Carg(1)*three)^1
+local splitter=Cs (
+ (((1-(three^1*period))^1+C(three))*prefix+C((1-period)^1))*(anything/""*Carg(2))*C(2)
+)
+local splitter3=Cs (
+ three*prefix*endofstring+two*prefix*endofstring+digit*prefix*endofstring+three+two+digit
+)
+patterns.formattednumber=splitter
+function number.formatted(n,sep1,sep2)
+ if sep1==false then
+  if type(n)=="number" then
+   n=tostring(n)
+  end
+  return lpegmatch(splitter3,n,1,sep2 or ".")
+ else
+  if type(n)=="number" then
+   n=format("%0.2f",n)
+  end
+  if sep1==true then
+   return lpegmatch(splitter,n,1,".",",")
+  elseif sep1=="." then
+   return lpegmatch(splitter,n,1,sep1,sep2 or ",")
+  elseif sep1=="," then
+   return lpegmatch(splitter,n,1,sep1,sep2 or ".")
+  else
+   return lpegmatch(splitter,n,1,sep1 or ",",sep2 or ".")
+  end
+ end
+end
+local p=Cs(
+  P("-")^0*(P("0")^1/"")^0*(1-period)^0*(period*P("0")^1*endofstring/""+period^0)*P(1-P("0")^1*endofstring)^0
+ )
+function number.compactfloat(n,fmt)
+ if n==0 then
+  return "0"
+ elseif n==1 then
+  return "1"
+ end
+ n=lpegmatch(p,format(fmt or "%0.3f",n))
+ if n=="." or n=="" or n=="-" then
+  return "0"
+ end
+ return n
+end
+local zero=P("0")^1/""
+local plus=P("+")/""
+local minus=P("-")
+local separator=period
+local trailing=zero^1*#S("eE")
+local exponent=(S("eE")*(plus+Cs((minus*zero^0*endofstring)/"")+minus)*zero^0*(endofstring*Cc("0")+anything^1))
+local pattern_a=Cs(minus^0*digit^1*(separator/""*trailing+separator*(trailing+digit)^0)*exponent)
+local pattern_b=Cs((exponent+anything)^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 hf={}
+local hs={}
+setmetatable(hf,{ __index=function(t,k)
+ local v="%."..k.."f"
+ t[k]=v
+ return v
+end } )
+setmetatable(hs,{ __index=function(t,k)
+ local v="%"..k.."s"
+ t[k]=v
+ return v
+end } )
+function number.formattedfloat(n,b,a)
+ local s=format(hf[a],n)
+ local l=(b or 0)+(a or 0)+1
+ if #s<l then
+  return format(hs[l],s)
+ else
+  return s
+ end
+end
+local template=[[
+%s
+%s
+return function(%s) return %s end
+]]
+local pattern=Cs(Cc('"')*(
+ (1-S('"\\\n\r'))^1+P('"')/'\\"'+P('\\')/'\\\\'+P('\n')/'\\n'+P('\r')/'\\r'
+)^0*Cc('"'))
+patterns.escapedquotes=pattern
+function string.escapedquotes(s)
+ return lpegmatch(pattern,s)
+end
+local pattern=(1-P("\\"))^1;pattern=Cs (
+ pattern*((P("\\")/""*(digit^-3/function(s) return char(tonumber(s)) end))+pattern )^1
+)
+patterns.unescapedquotes=pattern
+function string.unescapedquotes(s)
+ return lpegmatch(pattern,s) or s
+end
+string.texnewlines=lpeg.replacer(patterns.newline,"\r",true)
+local preamble=""
+local 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,
+ nupoints=number.nupoints,
+ basepoints=number.basepoints,
+ nubasepoints=number.nubasepoints,
+ utfchar=utf.char,
+ utfbyte=utf.byte,
+ lpegmatch=lpeg.match,
+ nspaces=string.nspaces,
+ utfpadding=string.utfpadding,
+ tracedchar=string.tracedchar,
+ autosingle=string.autosingle,
+ autodouble=string.autodouble,
+ sequenced=table.sequenced,
+ formattednumber=number.formatted,
+ sparseexponent=number.sparseexponent,
+ formattedfloat=number.formattedfloat,
+ stripzero=patterns.stripzero,
+ stripzeros=patterns.stripzeros,
+ escapedquotes=string.escapedquotes,
+ FORMAT=string.f6,
+}
+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((sign+space+period+digit)^0)
+local prefix_sub=(C((sign+digit)^0)+Cc(0))*period*(C((sign+digit)^0)+Cc(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_right=function(f)
+ n=n+1
+ f=tonumber(f)
+ if not f or f==0 then
+  return format("(a%s or '')",n)
+ elseif f>0 then
+  return format("utfpadding(a%s,%i)..a%s",n,f,n)
+ else
+  return format("a%s..utfpadding(a%s,%i)",n,n,f)
+ end
+end
+local format_left=function(f)
+ n=n+1
+ f=tonumber(f)
+ if not f or f==0 then
+  return format("(a%s or '')",n)
+ end
+ if f<0 then
+  return format("utfpadding(a%s,%i)..a%s",n,-f,n)
+ else
+  return format("a%s..utfpadding(a%s,%i)",n,n,-f)
+ end
+end
+local format_q=JITSUPPORTED and function()
+ n=n+1
+ return format("(a%s ~= nil and format('%%q',tostring(a%s)) or '')",n,n)
+end or function()
+ n=n+1
+ return format("(a%s ~= nil and format('%%q',a%s) or '')",n,n)
+end
+local format_Q=function() 
+ n=n+1
+ return format("escapedquotes(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_k=function(b,a) 
+ n=n+1
+ return format("formattedfloat(a%s,%s,%s)",n,b or 0,a or 0)
+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_P=function()
+ n=n+1
+ return format("nupoints(a%s)",n)
+end
+local format_b=function()
+ n=n+1
+ return format("basepoints(a%s)",n)
+end
+local format_B=function()
+ n=n+1
+ return format("nubasepoints(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("((a%s %% 1 == 0) and format('%%i',a%s) or tostring(a%s))",n,n,n)
+end
+local format_N  if environment.FORMAT then
+ format_N=function(f)
+  n=n+1
+  if not f or f=="" then
+   return format("FORMAT(a%s,'%%.9f')",n)
+  elseif f==".6" or f=="0.6" then
+   return format("FORMAT(a%s)",n)
+  else
+   return format("FORMAT(a%s,'%%%sf')",n,f)
+  end
+ end
+else
+ format_N=function(f) 
+  n=n+1
+  if not f or f=="" then
+   f=".9"
+  end 
+  return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%%sf',a%s)))",n,n,f,n)
+ end
+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 format_m=function(f)
+ n=n+1
+ if not f or f=="" then
+  f=","
+ end
+ if f=="0" then
+  return format([[formattednumber(a%s,false)]],n)
+ else
+  return format([[formattednumber(a%s,%q,".")]],n,f)
+ end
+end
+local format_M=function(f)
+ n=n+1
+ if not f or f=="" then
+  f="."
+ end
+ if f=="0" then
+  return format([[formattednumber(a%s,false)]],n)
+ else
+  return format([[formattednumber(a%s,%q,",")]],n,f)
+ end
+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
+ 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) 
+ elseif f<0 then
+  if w then
+   extension=gsub(extension,"%.%.%.","")
+   return extension
+  else
+   local a="a"..(n+f+1)
+   return format(extension,a,a)
+  end
+ else
+  if w then
+   extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s")
+  end
+  local t={}
+  for i=1,f do
+   n=n+1
+   t[i]="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("N") 
++V("k")
++V("r")+V("h")+V("H")+V("u")+V("U")+V("p")+V("P")+V("b")+V("B")+V("t")+V("T")+V("l")+V("L")+V("I")+V("w") 
++V("W") 
++V("a") 
++V("A") 
++V("j")+V("J") 
++V("m")+V("M") 
++V("z")
++V(">") 
++V("<")
+   )+V("*")
+  )*(endofstring+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_Q,
+ ["n"]=(prefix_any*P("n"))/format_n,
+ ["N"]=(prefix_any*P("N"))/format_N,
+ ["k"]=(prefix_sub*P("k"))/format_k,
+ ["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,
+ ["P"]=(prefix_any*P("P"))/format_P,
+ ["b"]=(prefix_any*P("b"))/format_b,
+ ["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_any*P("m"))/format_m,
+ ["M"]=(prefix_any*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,
+ ["<"]=(prefix_any*P("<"))/format_left,
+ [">"]=(prefix_any*P(">"))/format_right,
+ ["*"]=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 xx=setmetatable({},{ __index=function(t,k) local v=format("%02x",k) t[k]=v return v end })
+local XX=setmetatable({},{ __index=function(t,k) local v=format("%02X",k) t[k]=v return v end })
+local preset={
+ ["%02x"]=function(n) return xx[n] end,
+ ["%02X"]=function(n) return XX[n] end,
+}
+local direct=P("%")*(sign+space+period+digit)^0*S("sqidfgGeExXo")*endofstring/[[local format = string.format return function(str) return format("%0",str) end]]
+local function make(t,str)
+ local f=preset[str]
+ if f then
+  return f
+ end
+ 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={}
+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
+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('"')/"""+anything)^0)
+patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+anything)^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('"'))
+add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape=patterns.xmlescape })
+add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=patterns.texescape })
+add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=patterns.luaescape })
+local dquote=patterns.dquote 
+local equote=patterns.escaped+dquote/'\\"'+1
+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
+function strings.newcollector()
+ local result,r={},0
+ return
+  function(fmt,str,...) 
+   r=r+1
+   result[r]=str==nil and fmt or formatters[fmt](str,...)
+  end,
+  function(connector) 
+   if result then
+    local str=concat(result,connector)
+    result,r={},0
+    return str
+   end
+  end
+end
+local f_16_16=formatters["%0.5N"]
+function number.to16dot16(n)
+ return f_16_16(n/65536.0)
+end
+if not string.explode then
+ local p_utf=patterns.utf8character
+ local p_check=C(p_utf)*(P("+")*Cc(true))^0
+ local p_split=Ct(C(p_utf)^0)
+ local p_space=Ct((C(1-P(" ")^1)+P(" ")^1)^0)
+ function string.explode(str,symbol)
+  if symbol=="" then
+   return lpegmatch(p_split,str)
+  elseif symbol then
+   local a,b=lpegmatch(p_check,symbol)
+   if b then
+    return lpegmatch(tsplitat(P(a)^1),str)
+   else
+    return lpegmatch(tsplitat(a),str)
+   end
+  else
+   return lpegmatch(p_space,str)
+  end
+ end
+end
+do
+ local p_whitespace=patterns.whitespace^1
+ local cache=setmetatable({},{ __index=function(t,k)
+  local p=tsplitat(p_whitespace*P(k)*p_whitespace)
+  local v=function(s)
+   return lpegmatch(p,s)
+  end
+  t[k]=v
+  return v
+ end })
+ function string.wordsplitter(s)
+  return cache[s]
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-tab"] = package.loaded["util-tab"] or true
+
+-- original size: 34148, stripped down to: 18419
+
+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,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
+local formatters=string.formatters
+local utftoeight=utf.toeight
+local splitter=lpeg.tsplitat(".")
+function utilities.tables.definetable(target,nofirst,nolast) 
+ local composed=nil
+ local t={}
+ 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 ","
+  local noffields=#fields
+  if specification.preamble==true then
+   for f=1,noffields 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,noffields do
+    local field=ti[fields[f]]
+    if type(field)=="string" then
+     r[f]=lpegmatch(escape,field)
+    else
+     r[f]=tostring(field)
+    end
+   end
+   result[i+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)
+ local r=#result
+ 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
+    r=r+1 result[r]=formatters["%s<entry n='%s'>"](s,k)
+    toxml(v,d+step,result,step)
+    r=r+1 result[r]=formatters["%s</entry>"](s,k)
+   else
+    r=r+1 result[r]=formatters["%s<%s>"](s,k)
+    toxml(v,d+step,result,step)
+    r=r+1 result[r]=formatters["%s</%s>"](s,k)
+   end
+  elseif tv=="string" then
+   if tk=="number" then
+    r=r+1 result[r]=formatters["%s<entry n='%s'>%!xml!</entry>"](s,k,v,k)
+   else
+    r=r+1 result[r]=formatters["%s<%s>%!xml!</%s>"](s,k,v,k)
+   end
+  elseif tk=="number" then
+   r=r+1 result[r]=formatters["%s<entry n='%s'>%S</entry>"](s,k,v,k)
+  else
+   r=r+1 result[r]=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
+if JITSUPPORTED then
+ 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
+    local v=t[0]
+    if v then
+     local tv=type(v)
+     if tv=="string" then
+      m=m+1 r[m]=f_indexed_string(0,v)
+     elseif tv=="number" then
+      m=m+1 r[m]=f_indexed_number(0,v)
+     elseif tv=="table" then
+      m=m+1 r[m]=f_indexed_table(0)
+      fastserialize(v)
+      m=m+1 r[m]=f_indexed_table(0)
+     elseif tv=="boolean" then
+      m=m+1 r[m]=f_indexed_boolean(0,v)
+     end
+    end
+    for i=1,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
+else
+ 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
+    local v=t[0]
+    if v then
+     m=m+1
+     r[m]="[0]="
+     if type(v)=="table" then
+      fastserialize(v)
+     else
+      r[m]=format("%q,",v)
+     end
+    end
+    for i=1,n do
+     local v=t[i]
+     m=m+1
+     if type(v)=="table" then
+      r[m]=format("[%i]=",i)
+      fastserialize(v)
+     else
+      r[m]=format("[%i]=%q,",i,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
+      m=m+1
+      if type(v)=="table" then
+       r[m]=format("[%i]=",k)
+       fastserialize(v)
+      else
+       r[m]=format("[%i]=%q,",k,v)
+      end
+     end
+    else
+     m=m+1
+     if type(v)=="table" then
+      r[m]=format("[%q]=",k)
+      fastserialize(v)
+     else
+      r[m]=format("[%q]=%q,",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
+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
+local selfmapper={ __index=function(t,k) t[k]=k return k end }
+function table.twowaymapper(t) 
+ if not t then     
+  t={}       
+ else        
+  local zero=rawget(t,0)  
+  for i=zero and 0 or 1,#t do
+   local ti=t[i]    
+   if ti then
+    local i=tostring(i)
+    t[i]=ti   
+    t[ti]=i    
+   end
+  end
+ end
+ setmetatable(t,selfmapper)
+ return t
+end
+local f_start_key_idx=formatters["%w{"]
+local f_start_key_num=JITSUPPORTED and formatters["%w[%s]={"] or formatters["%w[%q]={"]
+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=JITSUPPORTED and formatters["%w[%s]=%s,"] or formatters["%w[%s]=%q,"]
+local f_key_str_value_num=JITSUPPORTED and formatters["%w[%Q]=%s,"] or formatters["%w[%Q]=%q,"]
+local f_key_boo_value_num=JITSUPPORTED and formatters["%w[%l]=%s,"] or formatters["%w[%l]=%q,"]
+local f_key_num_value_str=JITSUPPORTED and formatters["%w[%s]=%Q,"] or formatters["%w[%q]=%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=JITSUPPORTED and formatters["%w[%s]=%l,"] or formatters["%w[%q]=%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=JITSUPPORTED and formatters["%w[%s]={},"] or formatters["%w[%q]={},"]
+local f_key_str_value_not=formatters["%w[%Q]={},"]
+local f_key_boo_value_not=formatters["%w[%l]={},"]
+local f_key_num_value_seq=JITSUPPORTED and formatters["%w[%s]={ %, t },"] or formatters["%w[%q]={ %, 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=JITSUPPORTED and formatters["%w%s,"] or formatters["%w%q,"]
+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 is_simple_table=table.is_simple_table
+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 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=#root
+   if last>0 then
+    for k=1,last do
+     if rawget(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 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=is_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=is_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=is_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",{ metacheck=false }))
+   return true
+  end
+ end)
+end
+local mt={
+ __newindex=function(t,k,v)
+  local n=t.last+1
+  t.last=n
+  t.list[n]=k
+  t.hash[k]=v
+ end,
+ __index=function(t,k)
+  return t.hash[k]
+ end,
+ __len=function(t)
+  return t.last
+ end,
+}
+function table.orderedhash()
+ return setmetatable({ list={},hash={},last=0 },mt)
+end
+function table.ordered(t)
+ local n=t.last
+ if n>0 then
+  local l=t.list
+  local i=1
+  local h=t.hash
+  local f=function()
+   if i<=n then
+    local k=i
+    local v=h[l[k]]
+    i=i+1
+    return k,v
+   end
+  end
+  return f,1,h[l[1]]
+ else
+  return function() end
+ end
+end
+function combine(target,source)
+ if target then
+  for k,v in next,source do
+   if type(v)=="table" then
+      target[k]=combine(target[k],source[k])
+   else
+      target[k]=v
+   end
+  end
+  return target
+ else
+  return source
+ end
+end
+table.combine=combine
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-fil"] = package.loaded["util-fil"] or true
+
+-- original size: 11474, stripped down to: 8973
+
+if not modules then modules={} end modules ['util-fil']={
+ version=1.001,
+ optimize=true,
+ 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 tonumber=tonumber
+local byte=string.byte
+local char=string.char
+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)
+ local current=f:seek()
+ local size=f:seek("end")
+ f:seek("set",current)
+ return size
+end
+files.getsize=files.size
+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.readbytetable(f,n)
+ local s=f:read(n or 1)
+ return { byte(s,1,#s) } 
+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-0x100
+ else
+  return n
+ end
+end
+files.readcardinal1=files.readbyte  
+files.readcardinal=files.readcardinal1
+files.readinteger=files.readinteger1
+files.readsignedbyte=files.readinteger1
+function files.readcardinal2(f)
+ 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)
+ if a>=0x80 then
+  return 0x100*a+b-0x10000
+ else
+  return 0x100*a+b
+ end
+end
+function files.readinteger2le(f)
+ local b,a=byte(f:read(2),1,2)
+ if a>=0x80 then
+  return 0x100*a+b-0x10000
+ else
+  return 0x100*a+b
+ 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)
+ if a>=0x80 then
+  return 0x10000*a+0x100*b+c-0x1000000
+ else
+  return 0x10000*a+0x100*b+c
+ end
+end
+function files.readinteger3le(f)
+ local c,b,a=byte(f:read(3),1,3)
+ if a>=0x80 then
+  return 0x10000*a+0x100*b+c-0x1000000
+ else
+  return 0x10000*a+0x100*b+c
+ 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)
+ if a>=0x80 then
+  return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000
+ else
+  return 0x1000000*a+0x10000*b+0x100*c+d
+ end
+end
+function files.readinteger4le(f)
+ local d,c,b,a=byte(f:read(4),1,4)
+ if a>=0x80 then
+  return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000
+ else
+  return 0x1000000*a+0x10000*b+0x100*c+d
+ end
+end
+function files.readfixed2(f)
+ local n1,n2=byte(f:read(2),1,2)
+ if n1>=0x80 then
+  n1=n1-0x100
+ end
+ return n1+n2/0xFF
+end
+function files.readfixed4(f)
+ local a,b,c,d=byte(f:read(4),1,4)
+ local n1=0x100*a+b
+ local n2=0x100*c+d
+ if n1>=0x8000 then
+  n1=n1-0x10000
+ end
+ return n1+n2/0xFFFF
+end
+if bit32 then
+ local extract=bit32.extract
+ local band=bit32.band
+ function files.read2dot14(f)
+  local a,b=byte(f:read(2),1,2)
+  if a>=0x80 then
+   local n=-(0x100*a+b)
+   return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0))
+  else
+   local n=0x100*a+b
+   return   (extract(n,14,2)+(band(n,0x3FFF)/16384.0))
+  end
+ 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
+if bit32 then
+ local rshift=bit32.rshift
+ function files.writecardinal2(f,n)
+  local a=char(n%256)
+  n=rshift(n,8)
+  local b=char(n%256)
+  f:write(b,a)
+ end
+ function files.writecardinal4(f,n)
+  local a=char(n%256)
+  n=rshift(n,8)
+  local b=char(n%256)
+  n=rshift(n,8)
+  local c=char(n%256)
+  n=rshift(n,8)
+  local d=char(n%256)
+  f:write(d,c,b,a)
+ end
+ function files.writecardinal2le(f,n)
+  local a=char(n%256)
+  n=rshift(n,8)
+  local b=char(n%256)
+  f:write(a,b)
+ end
+ function files.writecardinal4le(f,n)
+  local a=char(n%256)
+  n=rshift(n,8)
+  local b=char(n%256)
+  n=rshift(n,8)
+  local c=char(n%256)
+  n=rshift(n,8)
+  local d=char(n%256)
+  f:write(a,b,c,d)
+ end
+else
+ local floor=math.floor
+ 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.writecardinal2le(f,n)
+  local a=char(n%256)
+  n=floor(n/256)
+  local b=char(n%256)
+  f:write(a,b)
+ end
+ function files.writecardinal4le(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(a,b,c,d)
+ end
+end
+function files.writestring(f,s)
+ f:write(char(byte(s,1,#s)))
+end
+function files.writebyte(f,b)
+ f:write(char(b))
+end
+if fio and fio.readcardinal1 then
+ files.readcardinal1=fio.readcardinal1
+ files.readcardinal2=fio.readcardinal2
+ files.readcardinal3=fio.readcardinal3
+ files.readcardinal4=fio.readcardinal4
+ files.readcardinal1le=fio.readcardinal1le or files.readcardinal1le
+ files.readcardinal2le=fio.readcardinal2le or files.readcardinal2le
+ files.readcardinal3le=fio.readcardinal3le or files.readcardinal3le
+ files.readcardinal4le=fio.readcardinal4le or files.readcardinal4le
+ files.readinteger1=fio.readinteger1
+ files.readinteger2=fio.readinteger2
+ files.readinteger3=fio.readinteger3
+ files.readinteger4=fio.readinteger4
+ files.readinteger1le=fio.readinteger1le or files.readinteger1le
+ files.readinteger2le=fio.readinteger2le or files.readinteger2le
+ files.readinteger3le=fio.readinteger3le or files.readinteger3le
+ files.readinteger4le=fio.readinteger4le or files.readinteger4le
+ files.readfixed2=fio.readfixed2
+ files.readfixed4=fio.readfixed4
+ files.read2dot14=fio.read2dot14
+ files.setposition=fio.setposition
+ files.getposition=fio.getposition
+ files.readbyte=files.readcardinal1
+ files.readsignedbyte=files.readinteger1
+ files.readcardinal=files.readcardinal1
+ files.readinteger=files.readinteger1
+ local skipposition=fio.skipposition
+ files.skipposition=skipposition
+ files.readbytes=fio.readbytes
+ files.readbytetable=fio.readbytetable
+ function files.skipshort(f,n)
+  skipposition(f,2*(n or 1))
+ end
+ function files.skiplong(f,n)
+  skipposition(f,4*(n or 1))
+ end
+end
+if fio and fio.writecardinal1 then
+ files.writecardinal1=fio.writecardinal1
+ files.writecardinal2=fio.writecardinal2
+ files.writecardinal3=fio.writecardinal3
+ files.writecardinal4=fio.writecardinal4
+ files.writecardinal1le=fio.writecardinal1le
+ files.writecardinal2le=fio.writecardinal2le
+ files.writecardinal3le=fio.writecardinal3le
+ files.writecardinal4le=fio.writecardinal4le
+ files.writeinteger1=fio.writeinteger1 or fio.writecardinal1
+ files.writeinteger2=fio.writeinteger2 or fio.writecardinal2
+ files.writeinteger3=fio.writeinteger3 or fio.writecardinal3
+ files.writeinteger4=fio.writeinteger4 or fio.writecardinal4
+ files.writeinteger1le=files.writeinteger1le or fio.writecardinal1le
+ files.writeinteger2le=files.writeinteger2le or fio.writecardinal2le
+ files.writeinteger3le=files.writeinteger3le or fio.writecardinal3le
+ files.writeinteger4le=files.writeinteger4le or fio.writecardinal4le
+end
+if fio and fio.readcardinaltable then
+ files.readcardinaltable=fio.readcardinaltable
+ files.readintegertable=fio.readintegertable
+else
+ local readcardinal1=files.readcardinal1
+ local readcardinal2=files.readcardinal2
+ local readcardinal3=files.readcardinal3
+ local readcardinal4=files.readcardinal4
+ function files.readcardinaltable(f,n,b)
+  local t={}
+   if b==1 then for i=1,n do t[i]=readcardinal1(f) end
+  elseif b==2 then for i=1,n do t[i]=readcardinal2(f) end
+  elseif b==3 then for i=1,n do t[i]=readcardinal3(f) end
+  elseif b==4 then for i=1,n do t[i]=readcardinal4(f) end end
+  return t
+ end
+ local readinteger1=files.readinteger1
+ local readinteger2=files.readinteger2
+ local readinteger3=files.readinteger3
+ local readinteger4=files.readinteger4
+ function files.readintegertable(f,n,b)
+  local t={}
+   if b==1 then for i=1,n do t[i]=readinteger1(f) end
+  elseif b==2 then for i=1,n do t[i]=readinteger2(f) end
+  elseif b==3 then for i=1,n do t[i]=readinteger3(f) end
+  elseif b==4 then for i=1,n do t[i]=readinteger4(f) end end
+  return t
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-sac"] = package.loaded["util-sac"] or true
+
+-- original size: 14071, stripped down to: 10417
+
+if not modules then modules={} end modules ['util-sac']={
+ version=1.001,
+ optimize=true,
+ 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,sub=string.byte,string.sub
+local tonumber=tonumber
+utilities=utilities or {}
+local streams={}
+utilities.streams=streams
+function streams.open(filename,zerobased)
+ local f=filename and io.loaddata(filename)
+ if f then
+  return { f,1,#f,zerobased or false }
+ end
+end
+function streams.openstring(f,zerobased)
+ if f then
+  return { f,1,#f,zerobased or false }
+ end
+end
+function streams.getstring(f)
+ if f then
+  return f[1]
+ end
+end
+function streams.close()
+end
+function streams.size(f)
+ return f and f[3] or 0
+end
+streams.getsize=streams.size
+function streams.setposition(f,i)
+ if f[4] then
+  if i<=0 then
+   f[2]=1
+  else
+   f[2]=i+1
+  end
+ else
+  if i<=1 then
+   f[2]=1
+  else
+   f[2]=i
+  end
+ end
+end
+function streams.getposition(f)
+ if f[4] then
+  return f[2]-1
+ else
+  return f[2]
+ end
+end
+function streams.look(f,n,chars)
+ local b=f[2]
+ local e=b+n-1
+ if chars then
+  return sub(f[1],b,e)
+ else
+  return byte(f[1],b,e)
+ end
+end
+function streams.skip(f,n)
+ f[2]=f[2]+n
+end
+function streams.readbyte(f)
+ local i=f[2]
+ f[2]=i+1
+ return byte(f[1],i)
+end
+function streams.readbytes(f,n)
+ local i=f[2]
+ local j=i+n
+ f[2]=j
+ return byte(f[1],i,j-1)
+end
+function streams.readbytetable(f,n)
+ local i=f[2]
+ local j=i+n
+ f[2]=j
+ return { byte(f[1],i,j-1) }
+end
+function streams.skipbytes(f,n)
+ f[2]=f[2]+n
+end
+function streams.readchar(f)
+ local i=f[2]
+ f[2]=i+1
+ return sub(f[1],i,i)
+end
+function streams.readstring(f,n)
+ local i=f[2]
+ local j=i+n
+ f[2]=j
+ return sub(f[1],i,j-1)
+end
+function streams.readinteger1(f)  
+ local i=f[2]
+ f[2]=i+1
+ local n=byte(f[1],i)
+ if n>=0x80 then
+  return n-0x100
+ else
+  return n
+ end
+end
+streams.readcardinal1=streams.readbyte  
+streams.readcardinal=streams.readcardinal1
+streams.readinteger=streams.readinteger1
+function streams.readcardinal2(f)
+ local i=f[2]
+ local j=i+1
+ f[2]=j+1
+ local a,b=byte(f[1],i,j)
+ return 0x100*a+b
+end
+function streams.readcardinal2le(f)
+ local i=f[2]
+ local j=i+1
+ f[2]=j+1
+ local b,a=byte(f[1],i,j)
+ return 0x100*a+b
+end
+function streams.readinteger2(f)
+ local i=f[2]
+ local j=i+1
+ f[2]=j+1
+ local a,b=byte(f[1],i,j)
+ if a>=0x80 then
+  return 0x100*a+b-0x10000
+ else
+  return 0x100*a+b
+ end
+end
+function streams.readinteger2le(f)
+ local i=f[2]
+ local j=i+1
+ f[2]=j+1
+ local b,a=byte(f[1],i,j)
+ if a>=0x80 then
+  return 0x100*a+b-0x10000
+ else
+  return 0x100*a+b
+ end
+end
+function streams.readcardinal3(f)
+ local i=f[2]
+ local j=i+2
+ f[2]=j+1
+ local a,b,c=byte(f[1],i,j)
+ return 0x10000*a+0x100*b+c
+end
+function streams.readcardinal3le(f)
+ local i=f[2]
+ local j=i+2
+ f[2]=j+1
+ local c,b,a=byte(f[1],i,j)
+ return 0x10000*a+0x100*b+c
+end
+function streams.readinteger3(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local a,b,c=byte(f[1],i,j)
+ if a>=0x80 then
+  return 0x10000*a+0x100*b+c-0x1000000
+ else
+  return 0x10000*a+0x100*b+c
+ end
+end
+function streams.readinteger3le(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local c,b,a=byte(f[1],i,j)
+ if a>=0x80 then
+  return 0x10000*a+0x100*b+c-0x1000000
+ else
+  return 0x10000*a+0x100*b+c
+ end
+end
+function streams.readcardinal4(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local a,b,c,d=byte(f[1],i,j)
+ return 0x1000000*a+0x10000*b+0x100*c+d
+end
+function streams.readcardinal4le(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local d,c,b,a=byte(f[1],i,j)
+ return 0x1000000*a+0x10000*b+0x100*c+d
+end
+function streams.readinteger4(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local a,b,c,d=byte(f[1],i,j)
+ if a>=0x80 then
+  return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000
+ else
+  return 0x1000000*a+0x10000*b+0x100*c+d
+ end
+end
+function streams.readinteger4le(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local d,c,b,a=byte(f[1],i,j)
+ if a>=0x80 then
+  return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000
+ else
+  return 0x1000000*a+0x10000*b+0x100*c+d
+ end
+end
+function streams.readfixed2(f)
+ local i=f[2]
+ local j=i+1
+ f[2]=j+1
+ local n1,n2=byte(f[1],i,j)
+ if n1>=0x80 then
+  n1=n1-0x100
+ end
+ return n1+n2/0xFF
+end
+function streams.readfixed4(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local a,b,c,d=byte(f[1],i,j)
+ local n1=0x100*a+b
+ local n2=0x100*c+d
+ if n1>=0x8000 then
+  n1=n1-0x10000
+ end
+ return n1+n2/0xFFFF
+end
+if bit32 then
+ local extract=bit32.extract
+ local band=bit32.band
+ function streams.read2dot14(f)
+  local i=f[2]
+  local j=i+1
+  f[2]=j+1
+  local a,b=byte(f[1],i,j)
+  if a>=0x80 then
+   local n=-(0x100*a+b)
+   return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0))
+  else
+   local n=0x100*a+b
+   return   (extract(n,14,2)+(band(n,0x3FFF)/16384.0))
+  end
+ end
+end
+function streams.skipshort(f,n)
+ f[2]=f[2]+2*(n or 1)
+end
+function streams.skiplong(f,n)
+ f[2]=f[2]+4*(n or 1)
+end
+if sio and sio.readcardinal2 then
+ local readcardinal1=sio.readcardinal1
+ local readcardinal2=sio.readcardinal2
+ local readcardinal3=sio.readcardinal3
+ local readcardinal4=sio.readcardinal4
+ local readinteger1=sio.readinteger1
+ local readinteger2=sio.readinteger2
+ local readinteger3=sio.readinteger3
+ local readinteger4=sio.readinteger4
+ local readfixed2=sio.readfixed2
+ local readfixed4=sio.readfixed4
+ local read2dot14=sio.read2dot14
+ local readbytes=sio.readbytes
+ local readbytetable=sio.readbytetable
+ function streams.readcardinal1(f)
+  local i=f[2]
+  f[2]=i+1
+  return readcardinal1(f[1],i)
+ end
+ function streams.readcardinal2(f)
+  local i=f[2]
+  f[2]=i+2
+  return readcardinal2(f[1],i)
+ end
+ function streams.readcardinal3(f)
+  local i=f[2]
+  f[2]=i+3
+  return readcardinal3(f[1],i)
+ end
+ function streams.readcardinal4(f)
+  local i=f[2]
+  f[2]=i+4
+  return readcardinal4(f[1],i)
+ end
+ function streams.readinteger1(f)
+  local i=f[2]
+  f[2]=i+1
+  return readinteger1(f[1],i)
+ end
+ function streams.readinteger2(f)
+  local i=f[2]
+  f[2]=i+2
+  return readinteger2(f[1],i)
+ end
+ function streams.readinteger3(f)
+  local i=f[2]
+  f[2]=i+3
+  return readinteger3(f[1],i)
+ end
+ function streams.readinteger4(f)
+  local i=f[2]
+  f[2]=i+4
+  return readinteger4(f[1],i)
+ end
+ function streams.readfixed2(f) 
+  local i=f[2]
+  f[2]=i+2
+  return readfixed2(f[1],i)
+ end
+ function streams.readfixed4(f) 
+  local i=f[2]
+  f[2]=i+4
+  return readfixed4(f[1],i)
+ end
+ function streams.read2dot14(f)
+  local i=f[2]
+  f[2]=i+2
+  return read2dot14(f[1],i)
+ end
+ function streams.readbytes(f,n)
+  local i=f[2]
+  local s=f[3]
+  local p=i+n
+  if p>s then
+   f[2]=s+1
+  else
+   f[2]=p
+  end
+  return readbytes(f[1],i,n)
+ end
+ function streams.readbytetable(f,n)
+  local i=f[2]
+  local s=f[3]
+  local p=i+n
+  if p>s then
+   f[2]=s+1
+  else
+   f[2]=p
+  end
+  return readbytetable(f[1],i,n)
+ end
+ streams.readbyte=streams.readcardinal1
+ streams.readsignedbyte=streams.readinteger1
+ streams.readcardinal=streams.readcardinal1
+ streams.readinteger=streams.readinteger1
+end
+if sio and sio.readcardinaltable then
+ local readcardinaltable=sio.readcardinaltable
+ local readintegertable=sio.readintegertable
+ function utilities.streams.readcardinaltable(f,n,b)
+  local i=f[2]
+  local s=f[3]
+  local p=i+n*b
+  if p>s then
+   f[2]=s+1
+  else
+   f[2]=p
+  end
+  return readcardinaltable(f[1],i,n,b)
+ end
+ function utilities.streams.readintegertable(f,n,b)
+  local i=f[2]
+  local s=f[3]
+  local p=i+n*b
+  if p>s then
+   f[2]=s+1
+  else
+   f[2]=p
+  end
+  return readintegertable(f[1],i,n,b)
+ end
+else
+ local readcardinal1=streams.readcardinal1
+ local readcardinal2=streams.readcardinal2
+ local readcardinal3=streams.readcardinal3
+ local readcardinal4=streams.readcardinal4
+ function streams.readcardinaltable(f,n,b)
+  local i=f[2]
+  local s=f[3]
+  local p=i+n*b
+  if p>s then
+   f[2]=s+1
+  else
+   f[2]=p
+  end
+  local t={}
+   if b==1 then for i=1,n do t[i]=readcardinal1(f[1],i) end
+  elseif b==2 then for i=1,n do t[i]=readcardinal2(f[1],i) end
+  elseif b==3 then for i=1,n do t[i]=readcardinal3(f[1],i) end
+  elseif b==4 then for i=1,n do t[i]=readcardinal4(f[1],i) end end
+  return t
+ end
+ local readinteger1=streams.readinteger1
+ local readinteger2=streams.readinteger2
+ local readinteger3=streams.readinteger3
+ local readinteger4=streams.readinteger4
+ function streams.readintegertable(f,n,b)
+  local i=f[2]
+  local s=f[3]
+  local p=i+n*b
+  if p>s then
+   f[2]=s+1
+  else
+   f[2]=p
+  end
+  local t={}
+   if b==1 then for i=1,n do t[i]=readinteger1(f[1],i) end
+  elseif b==2 then for i=1,n do t[i]=readinteger2(f[1],i) end
+  elseif b==3 then for i=1,n do t[i]=readinteger3(f[1],i) end
+  elseif b==4 then for i=1,n do t[i]=readinteger4(f[1],i) end end
+  return t
+ end
+end
+do
+ local files=utilities.files
+ if files then
+  local openfile=files.open
+  local openstream=streams.open
+  local openstring=streams.openstring
+  local setmetatable=setmetatable
+  function io.newreader(str,method)
+   local f,m
+   if method=="string" then
+    f=openstring(str,true)
+    m=streams
+   elseif method=="stream" then
+    f=openstream(str,true)
+    m=streams
+   else
+    f=openfile(str,"rb")
+    m=files
+   end
+   if f then
+    local t={}
+    setmetatable(t,{
+     __index=function(t,k)
+      local r=m[k]
+      if k=="close" then
+       if f then
+        m.close(f)
+        f=nil
+       end
+       return function() end
+      elseif r then
+       local v=function(_,a,b) return r(f,a,b) end
+       t[k]=v
+       return v
+      else
+       print("unknown key",k)
+      end
+     end
+    } )
+    return t
+   end
+  end
+ end
+end
+if bit32 and not streams.tocardinal1 then
+ local extract=bit32.extract
+ local char=string.char
+    streams.tocardinal1=char
+ function streams.tocardinal2(n)   return char(extract(8,8),extract(0,8)) end
+ function streams.tocardinal3(n)   return char(extract(16,8),extract(8,8),extract(0,8)) end
+ function streams.tocardinal4(n)   return char(extract(24,8),extract(16,8),extract(8,8),extract(0,8)) end
+    streams.tocardinal1le=char
+ function streams.tocardinal2le(n) return char(extract(0,8),extract(8,8)) end
+ function streams.tocardinal3le(n) return char(extract(0,8),extract(8,8),extract(16,8)) end
+ function streams.tocardinal4le(n) return char(extract(0,8),extract(8,8),extract(16,8),extract(24,8)) end
+end
+if not streams.readcstring then
+ local readchar=streams.readchar
+ local concat=table.concat
+ function streams.readcstring(f)
+  local t={}
+  while true do
+   local c=readchar(f)
+   if c and c~="\0" then
+    t[#t+1]=c
+   else
+    return concat(t)
+   end
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-sto"] = package.loaded["util-sto"] or true
+
+-- original size: 6661, stripped down to: 3074
+
+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,rawset,type=setmetatable,getmetatable,rawset,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.setmetatableindices(t,f,n,c)
+ 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
+  m.__newindex=n
+  m.__call=c
+ else
+  setmetatable(t,{
+   __index=i,
+   __newindex=n,
+   __call=c,
+  })
+ 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
+function table.makeweak(t)
+ if not t then
+  t={}
+ end
+ local m=getmetatable(t)
+ if m then
+  m.__mode="v"
+ else
+  setmetatable(t,{ __mode="v" })
+ end
+ return t
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-prs"] = package.loaded["util-prs"] or true
+
+-- original size: 25542, stripped down to: 16783
+
+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 tonumber,tostring,type,next,rawset=tonumber,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={}
+parsers.hashes=hashes
+local digit=R("09")
+local space=P(' ')
+local equal=P("=")
+local colon=P(":")
+local comma=P(",")
+local lbrace=P("{")
+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
+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 nobracket=1-(lbracket+rbracket)
+local escape,left,right=P("\\"),P('{'),P('}')
+lpegpatterns.balanced=P {
+ ((escape*(left+right))+(1-(left+right))+V(2))^0,
+ left*V(1)*right
+}
+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   
+lpegpatterns.nestedparents=nestedparents  
+lpegpatterns.nestedbrackets=nestedbrackets 
+lpegpatterns.nested=nestedbraces   
+lpegpatterns.argument=argument    
+lpegpatterns.content=content  
+local value=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 pattern_d=(space+comma)^0*(key*(equal+colon)*value+key*C(""))
+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
+local pattern_d_s=(pattern_d/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
+patterns.settings_to_hash_d=pattern_d_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_colon_too(str)
+ if not str or str=="" then
+  return {}
+ elseif type(str)=="table" then
+  return str
+ else
+  hash={}
+  lpegmatch(pattern_d_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=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
+function parsers.settings_to_numbers(str)
+ if not str or str=="" then
+  return {}
+ end
+ if type(str)=="table" then
+ 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=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
+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=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={}
+  local tn=0
+  local s=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 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={}
+ local 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 parsers.options_to_hash(str,target)
+ return str and lpegmatch(splitter,str,1,target or {}) or {}
+end
+local splitter=lpeg.tsplitat(" ")
+function 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={}
+   local 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 numbers=specification.numbers
+ 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 quoteitem=(1-quotechar)^0
+   local quoteword=quotechar*(numbers and (quoteitem/tonumber) or C(quoteitem))*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 numbers=specification.numbers
+ local separator=specification.separator 
+ local quotechar=P(specification.quote)  
+ local dquotechar=quotechar*quotechar   
+/specification.quote
+ local separator=S(separator~="" and separator or ",")
+ local whatever=(dquotechar+(1-quotechar))^0
+ local escaped=quotechar*(numbers and (whatever/tonumber) or Cs(whatever))*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 morerecords=(newline^(specification.strict and -1 or 1)*record)^0
+ local headeryes=Ct(morerecords)
+ local headernop=Ct(record*morerecords)
+ return function(data,getheader)
+  if getheader then
+   local header,position=lpegmatch(headerline,data)
+   local data=lpegmatch(headeryes,data,position)
+   return data,header
+  else
+   return lpegmatch(headernop,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.hexadecimal+lpegpatterns.cardinal)/tonumber
+local spacers=lpegpatterns.spacer^0
+local endofstring=lpegpatterns.endofstring
+local stepper=spacers*(cardinal*(spacers*S(":-")*spacers*(cardinal+Cc(true) )+Cc(false) )*Carg(1)*Carg(2)/ranger*S(", ")^0 )^1
+local stepper=spacers*(cardinal*(spacers*S(":-")*spacers*(cardinal+(P("*")+endofstring)*Cc(true) )+Cc(false) )*Carg(1)*Carg(2)/ranger*S(", ")^0 )^1*endofstring 
+function parsers.stepper(str,n,action)
+ local ts=type(str)
+ if type(n)=="function" then
+  if ts=="number" then
+   n(str)
+  elseif ts=="table" then
+   for i=1,#str do
+    n(str[i])
+   end
+  else
+   lpegmatch(stepper,str,1,false,n or print)
+  end
+ elseif ts=="string" then
+  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=S(k) 
+ local value=(1-separator)^0
+ local pattern=spaces*C(value)*separator^0*Cp()
+ t[k]=pattern
+ return pattern
+end)
+local commalistiterator=cache[","]
+function 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 parsers.mergehashes(hash,list)
+ return lpegmatch(merge,list,1,hash)
+end
+function 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 parsers.splitmethod(str,default)
+ if str then
+  return lpegmatch(pattern,str,1,default or false)
+ else
+  return default or false,""
+ end
+end
+local p_year=lpegpatterns.digit^4/tonumber
+local pattern=Cf(Ct("")*(
+  (Cg(Cc("year")*p_year)*S("-/")*Cg(Cc("month")*cardinal)*S("-/")*Cg(Cc("day")*cardinal)
+  )+(Cg(Cc("day")*cardinal)*S("-/")*Cg(Cc("month")*cardinal)*S("-/")*Cg(Cc("year")*p_year)
+  )+(Cg(Cc("year")*p_year)*S("-/")*Cg(Cc("month")*cardinal)
+  )+(Cg(Cc("month")*cardinal)*S("-/")*Cg(Cc("year")*p_year)
+  )
+ )*(
+   P(" ")*Cg(Cc("hour")*cardinal)*P(":")*Cg(Cc("min")*cardinal)*(P(":")*Cg(Cc("sec")*cardinal))^-1+P(-1) )
+,rawset)
+lpegpatterns.splittime=pattern
+function parsers.totime(str)
+ return lpegmatch(pattern,str)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-fmt"] = package.loaded["util-fmt"] or true
+
+-- original size: 2541, stripped down to: 1624
+
+if not modules then modules={} end modules ['util-fmt']={
+ 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.formatters=utilities.formatters or {}
+local formatters=utilities.formatters
+local concat,format=table.concat,string.format
+local tostring,type=tostring,type
+local strip=string.strip
+local lpegmatch=lpeg.match
+local stripper=lpeg.patterns.stripzeros
+function formatters.stripzeros(str)
+ return lpegmatch(stripper,str)
+end
+function formatters.formatcolumns(result,between)
+ if result and #result>0 then
+  between=between or "   "
+  local widths,numbers={},{}
+  local first=result[1]
+  local n=#first
+  for i=1,n do
+   widths[i]=0
+  end
+  for i=1,#result do
+   local r=result[i]
+   for j=1,n do
+    local rj=r[j]
+    local tj=type(rj)
+    if tj=="number" then
+     numbers[j]=true
+     rj=tostring(rj)
+    elseif tj~="string" then
+     rj=tostring(rj)
+     r[j]=rj
+    end
+    local w=#rj
+    if w>widths[j] then
+     widths[j]=w
+    end
+   end
+  end
+  for i=1,n do
+   local w=widths[i]
+   if numbers[i] then
+    if w>80 then
+     widths[i]="%s"..between
+     else
+     widths[i]="%0"..w.."i"..between
+    end
+   else
+    if w>80 then
+     widths[i]="%s"..between
+     elseif w>0 then
+     widths[i]="%-"..w.."s"..between
+    else
+     widths[i]="%s"
+    end
+   end
+  end
+  local template=strip(concat(widths))
+  for i=1,#result do
+   local str=format(template,unpack(result[i]))
+   result[i]=strip(str)
+  end
+ end
+ return result
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-reset"] = package.loaded["util-soc-imp-reset"] or true
+
+-- original size: 374, stripped down to: 282
+
+local loaded=package.loaded
+loaded["socket"]=nil
+loaded["copas"]=nil
+loaded["ltn12"]=nil
+loaded["mbox"]=nil
+loaded["mime"]=nil
+loaded["socket.url"]=nil
+loaded["socket.headers"]=nil
+loaded["socket.tp"]=nil
+loaded["socket.http"]=nil
+loaded["socket.ftp"]=nil
+loaded["socket.smtp"]=nil
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-socket"] = package.loaded["util-soc-imp-socket"] or true
+
+-- original size: 4905, stripped down to: 3562
+
+
+local type,tostring,setmetatable=type,tostring,setmetatable
+local min=math.min
+local format=string.format
+local socket=socket or package.loaded.socket or require("socket.core")
+local connect=socket.connect
+local tcp4=socket.tcp4
+local tcp6=socket.tcp6
+local getaddrinfo=socket.dns.getaddrinfo
+local defaulthost="0.0.0.0"
+local function report(fmt,first,...)
+ if logs then
+  report=logs and logs.reporter("socket")
+  report(fmt,first,...)
+ elseif fmt then
+  fmt="socket: "..fmt
+  if first then
+   print(format(fmt,first,...))
+  else
+   print(fmt)
+  end
+ end
+end
+socket.report=report
+function socket.connect4(address,port,laddress,lport)
+ return connect(address,port,laddress,lport,"inet")
+end
+function socket.connect6(address,port,laddress,lport)
+ return connect(address,port,laddress,lport,"inet6")
+end
+function socket.bind(host,port,backlog)
+ if host=="*" or host=="" then
+  host=defaulthost
+ end
+ local addrinfo,err=getaddrinfo(host)
+ if not addrinfo then
+  return nil,err
+ end
+ for i=1,#addrinfo do
+  local alt=addrinfo[i]
+  local sock,err=(alt.family=="inet" and tcp4 or tcp6)()
+  if not sock then
+   return nil,err or "unknown error"
+  end
+  sock:setoption("reuseaddr",true)
+  local res,err=sock:bind(alt.addr,port)
+  if res then
+   res,err=sock:listen(backlog)
+   if res then
+    return sock
+   else
+    sock:close()
+   end
+  else
+   sock:close()
+  end
+ end
+ return nil,"invalid address"
+end
+socket.try=socket.newtry()
+function socket.choose(list)
+ return function(name,opt1,opt2)
+  if type(name)~="string" then
+   name,opt1,opt2="default",name,opt1
+  end
+  local f=list[name or "nil"]
+  if f then
+   return f(opt1,opt2)
+  else
+   report("error: unknown key '%s'",tostring(name))
+  end
+ end
+end
+local sourcet={}
+local sinkt={}
+socket.sourcet=sourcet
+socket.sinkt=sinkt
+socket.BLOCKSIZE=2048
+sinkt["close-when-done"]=function(sock)
+ return setmetatable (
+  {
+   getfd=function() return sock:getfd() end,
+   dirty=function() return sock:dirty() end,
+  },
+  {
+   __call=function(self,chunk,err)
+    if chunk then
+     return sock:send(chunk)
+    else
+     sock:close()
+     return 1 
+    end
+   end
+  }
+ )
+end
+sinkt["keep-open"]=function(sock)
+ return setmetatable (
+  {
+   getfd=function() return sock:getfd() end,
+   dirty=function() return sock:dirty() end,
+  },{
+   __call=function(self,chunk,err)
+    if chunk then
+     return sock:send(chunk)
+    else
+     return 1 
+    end
+   end
+  }
+ )
+end
+sinkt["default"]=sinkt["keep-open"]
+socket.sink=socket.choose(sinkt)
+sourcet["by-length"]=function(sock,length)
+ local blocksize=socket.BLOCKSIZE
+ return setmetatable (
+  {
+   getfd=function() return sock:getfd() end,
+   dirty=function() return sock:dirty() end,
+  },
+  {
+   __call=function()
+    if length<=0 then
+     return nil
+    end
+    local chunk,err=sock:receive(min(blocksize,length))
+    if err then
+     return nil,err
+    end
+    length=length-#chunk
+    return chunk
+   end
+  }
+ )
+end
+sourcet["until-closed"]=function(sock)
+ local blocksize=socket.BLOCKSIZE
+ local done=false
+ return setmetatable (
+  {
+   getfd=function() return sock:getfd() end,
+   dirty=function() return sock:dirty() end,
+  },{
+   __call=function()
+    if done then
+     return nil
+    end
+    local chunk,status,partial=sock:receive(blocksize)
+    if not status then
+     return chunk
+    elseif status=="closed" then
+     sock:close()
+     done=true
+     return partial
+    else
+     return nil,status
+    end
+   end
+  }
+ )
+end
+sourcet["default"]=sourcet["until-closed"]
+socket.source=socket.choose(sourcet)
+_G.socket=socket 
+package.loaded["socket"]=socket
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-copas"] = package.loaded["util-soc-imp-copas"] or true
+
+-- original size: 26186, stripped down to: 14893
+
+
+local socket=socket or require("socket")
+local ssl=ssl or nil 
+local WATCH_DOG_TIMEOUT=120
+local UDP_DATAGRAM_MAX=8192
+local type,next,pcall,getmetatable,tostring=type,next,pcall,getmetatable,tostring
+local min,max,random=math.min,math.max,math.random
+local find=string.find
+local insert,remove=table.insert,table.remove
+local gettime=socket.gettime
+local selectsocket=socket.select
+local createcoroutine=coroutine.create
+local resumecoroutine=coroutine.resume
+local yieldcoroutine=coroutine.yield
+local runningcoroutine=coroutine.running
+local function report(fmt,first,...)
+ if logs then
+  report=logs and logs.reporter("copas")
+  report(fmt,first,...)
+ elseif fmt then
+  fmt="copas: "..fmt
+  if first then
+   print(format(fmt,first,...))
+  else
+   print(fmt)
+  end
+ end
+end
+local copas={
+ _COPYRIGHT="Copyright (C) 2005-2016 Kepler Project",
+ _DESCRIPTION="Coroutine Oriented Portable Asynchronous Services",
+ _VERSION="Copas 2.0.1",
+ autoclose=true,
+ running=false,
+ report=report,
+ trace=false,
+}
+local function statushandler(status,...)
+ if status then
+  return...
+ end
+ local err=(...)
+ if type(err)=="table" then
+  err=err[1]
+ end
+ if copas.trace then
+  report("error: %s",tostring(err))
+ end
+ return nil,err
+end
+function socket.protect(func)
+ return function(...)
+  return statushandler(pcall(func,...))
+ end
+end
+function socket.newtry(finalizer)
+ return function (...)
+  local status=(...)
+  if not status then
+   local detail=select(2,...)
+   pcall(finalizer,detail)
+   if copas.trace then
+    report("error: %s",tostring(detail))
+   end
+   return
+  end
+  return...
+ end
+end
+local function newset()
+ local reverse={}
+ local set={}
+ local queue={}
+ setmetatable(set,{
+  __index={
+   insert=function(set,value)
+     if not reverse[value] then
+      local n=#set+1
+      set[n]=value
+      reverse[value]=n
+     end
+    end,
+   remove=function(set,value)
+     local index=reverse[value]
+     if index then
+      reverse[value]=nil
+      local n=#set
+      local top=set[n]
+      set[n]=nil
+      if top~=value then
+       reverse[top]=index
+       set[index]=top
+      end
+     end
+    end,
+   push=function (set,key,itm)
+     local entry=queue[key]
+     if entry==nil then 
+      queue[key]={ itm }
+     else
+      entry[#entry+1]=itm
+     end
+    end,
+   pop=function (set,key)
+     local top=queue[key]
+     if top~=nil then
+      local ret=remove(top,1)
+      if top[1]==nil then
+       queue[key]=nil
+      end
+      return ret
+     end
+    end
+  }
+ } )
+ return set
+end
+local _sleeping={
+ times={},
+ cos={},
+ lethargy={},
+ insert=function()
+  end,
+ remove=function()
+  end,
+ push=function(self,sleeptime,co)
+   if not co then
+    return
+   end
+   if sleeptime<0 then
+    self.lethargy[co]=true
+    return
+   else
+    sleeptime=gettime()+sleeptime
+   end
+   local t=self.times
+   local c=self.cos
+   local i=1
+   local n=#t
+   while i<=n and t[i]<=sleeptime do
+    i=i+1
+   end
+   insert(t,i,sleeptime)
+   insert(c,i,co)
+  end,
+ getnext=
+  function(self)
+   local t=self.times
+   local delay=t[1] and t[1]-gettime() or nil
+   return delay and max(delay,0) or nil
+  end,
+ pop=
+  function(self,time)
+   local t=self.times
+   local c=self.cos
+   if #t==0 or time<t[1] then
+    return
+   end
+   local co=c[1]
+   remove(t,1)
+   remove(c,1)
+   return co
+  end,
+  wakeup=function(self,co)
+    local let=self.lethargy
+    if let[co] then
+     self:push(0,co)
+     let[co]=nil
+    else
+     local c=self.cos
+     local t=self.times
+     for i=1,#c do
+      if c[i]==co then
+       remove(c,i)
+       remove(t,i)
+       self:push(0,co)
+       return
+      end
+     end
+    end
+   end
+}
+local _servers=newset() 
+local _reading=newset() 
+local _writing=newset() 
+local _reading_log={}
+local _writing_log={}
+local _is_timeout={  
+ timeout=true,
+ wantread=true,
+ wantwrite=true,
+}
+local function isTCP(socket)
+ return not find(tostring(socket),"^udp")
+end
+local function copasreceive(client,pattern,part)
+ if not pattern or pattern=="" then
+  pattern="*l"
+ end
+ local current_log=_reading_log
+ local s,err
+ repeat
+  s,err,part=client:receive(pattern,part)
+  if s or (not _is_timeout[err]) then
+   current_log[client]=nil
+   return s,err,part
+  end
+  if err=="wantwrite" then
+   current_log=_writing_log
+   current_log[client]=gettime()
+   yieldcoroutine(client,_writing)
+  else
+   current_log=_reading_log
+   current_log[client]=gettime()
+   yieldcoroutine(client,_reading)
+  end
+ until false
+end
+local function copasreceivefrom(client,size)
+ local s,err,port
+ if not size or size==0 then
+  size=UDP_DATAGRAM_MAX
+ end
+ repeat
+  s,err,port=client:receivefrom(size)
+  if s or err~="timeout" then
+   _reading_log[client]=nil
+   return s,err,port
+  end
+  _reading_log[client]=gettime()
+  yieldcoroutine(client,_reading)
+ until false
+end
+local function copasreceivepartial(client,pattern,part)
+ if not pattern or pattern=="" then
+  pattern="*l"
+ end
+ local logger=_reading_log
+ local queue=_reading
+ local s,err
+ repeat
+  s,err,part=client:receive(pattern,part)
+  if s or (type(pattern)=="number" and part~="" and part) or not _is_timeout[err] then
+    logger[client]=nil
+    return s,err,part
+  end
+  if err=="wantwrite" then
+   logger=_writing_log
+   queue=_writing
+  else
+   logger=_reading_log
+   queue=_reading
+  end
+  logger[client]=gettime()
+  yieldcoroutine(client,queue)
+ until false
+end
+local function copassend(client,data,from,to)
+ if not from then
+  from=1
+ end
+ local lastIndex=from-1
+ local logger=_writing_log
+ local queue=_writing
+ local s,err
+ repeat
+  s,err,lastIndex=client:send(data,lastIndex+1,to)
+  if random(100)>90 then
+   logger[client]=gettime()
+   yieldcoroutine(client,queue)
+  end
+  if s or not _is_timeout[err] then
+   logger[client]=nil
+   return s,err,lastIndex
+  end
+  if err=="wantread" then
+   logger=_reading_log
+   queue=_reading
+  else
+   logger=_writing_log
+   queue=_writing
+  end
+  logger[client]=gettime()
+  yieldcoroutine(client,queue)
+ until false
+end
+local function copassendto(client,data,ip,port)
+ repeat
+  local s,err=client:sendto(data,ip,port)
+  if random(100)>90 then
+   _writing_log[client]=gettime()
+   yieldcoroutine(client,_writing)
+  end
+  if s or err~="timeout" then
+   _writing_log[client]=nil
+   return s,err
+  end
+  _writing_log[client]=gettime()
+  yieldcoroutine(client,_writing)
+ until false
+end
+local function copasconnect(skt,host,port)
+ skt:settimeout(0)
+ local ret,err,tried_more_than_once
+ repeat
+  ret,err=skt:connect (host,port)
+  if ret or (err~="timeout" and err~="Operation already in progress") then
+   if not ret and err=="already connected" and tried_more_than_once then
+    ret=1
+    err=nil
+   end
+   _writing_log[skt]=nil
+   return ret,err
+  end
+  tried_more_than_once=tried_more_than_once or true
+  _writing_log[skt]=gettime()
+  yieldcoroutine(skt,_writing)
+ until false
+end
+local function copasdohandshake(skt,sslt) 
+ if not ssl then
+  ssl=require("ssl")
+ end
+ if not ssl then
+  report("error: no ssl library")
+  return
+ end
+ local nskt,err=ssl.wrap(skt,sslt)
+ if not nskt then
+  report("error: %s",tostring(err))
+  return
+ end
+ nskt:settimeout(0)
+ local queue
+ repeat
+  local success,err=nskt:dohandshake()
+  if success then
+   return nskt
+  elseif err=="wantwrite" then
+   queue=_writing
+  elseif err=="wantread" then
+   queue=_reading
+  else
+   report("error: %s",tostring(err))
+   return
+  end
+  yieldcoroutine(nskt,queue)
+ until false
+end
+local function copasflush(client)
+end
+copas.connect=copassconnect
+copas.send=copassend
+copas.sendto=copassendto
+copas.receive=copasreceive
+copas.receivefrom=copasreceivefrom
+copas.copasreceivepartial=copasreceivepartial
+copas.copasreceivePartial=copasreceivepartial
+copas.dohandshake=copasdohandshake
+copas.flush=copasflush
+local function _skt_mt_tostring(self)
+ return tostring(self.socket).." (copas wrapped)"
+end
+local _skt_mt_tcp_index={
+ send=function(self,data,from,to)
+   return copassend (self.socket,data,from,to)
+  end,
+ receive=function (self,pattern,prefix)
+   if self.timeout==0 then
+    return copasreceivePartial(self.socket,pattern,prefix)
+   else
+    return copasreceive(self.socket,pattern,prefix)
+   end
+  end,
+ flush=function (self)
+   return copasflush(self.socket)
+  end,
+ settimeout=function (self,time)
+   self.timeout=time
+   return true
+  end,
+ connect=function(self,...)
+   local res,err=copasconnect(self.socket,...)
+   if res and self.ssl_params then
+    res,err=self:dohandshake()
+   end
+   return res,err
+  end,
+ close=function(self,...)
+   return self.socket:close(...)
+  end,
+ bind=function(self,...)
+   return self.socket:bind(...)
+  end,
+ getsockname=function(self,...)
+   return self.socket:getsockname(...)
+  end,
+ getstats=function(self,...)
+   return self.socket:getstats(...)
+  end,
+ setstats=function(self,...)
+   return self.socket:setstats(...)
+  end,
+ listen=function(self,...)
+   return self.socket:listen(...)
+  end,
+ accept=function(self,...)
+   return self.socket:accept(...)
+  end,
+ setoption=function(self,...)
+   return self.socket:setoption(...)
+  end,
+ getpeername=function(self,...)
+   return self.socket:getpeername(...)
+  end,
+ shutdown=function(self,...)
+   return self.socket:shutdown(...)
+  end,
+ dohandshake=function(self,sslt)
+   self.ssl_params=sslt or self.ssl_params
+   local nskt,err=copasdohandshake(self.socket,self.ssl_params)
+   if not nskt then
+    return nskt,err
+   end
+   self.socket=nskt
+   return self
+  end,
+}
+local _skt_mt_tcp={
+ __tostring=_skt_mt_tostring,
+ __index=_skt_mt_tcp_index,
+}
+local _skt_mt_udp_index={
+ sendto=function (self,...)
+   return copassendto(self.socket,...)
+  end,
+ receive=function (self,size)
+   return copasreceive(self.socket,size or UDP_DATAGRAM_MAX)
+  end,
+ receivefrom=function (self,size)
+   return copasreceivefrom(self.socket,size or UDP_DATAGRAM_MAX)
+  end,
+ setpeername=function(self,...)
+   return self.socket:getpeername(...)
+  end,
+ setsockname=function(self,...)
+   return self.socket:setsockname(...)
+  end,
+ close=function(self,...)
+   return true
+  end
+}
+local _skt_mt_udp={
+ __tostring=_skt_mt_tostring,
+ __index=_skt_mt_udp_index,
+}
+for k,v in next,_skt_mt_tcp_index do
+ if not _skt_mt_udp_index[k] then
+  _skt_mt_udp_index[k]=v
+ end
+end
+local function wrap(skt,sslt)
+ if getmetatable(skt)==_skt_mt_tcp or getmetatable(skt)==_skt_mt_udp then
+  return skt 
+ end
+ skt:settimeout(0)
+ if isTCP(skt) then
+  return setmetatable ({ socket=skt,ssl_params=sslt },_skt_mt_tcp)
+ else
+  return setmetatable ({ socket=skt },_skt_mt_udp)
+ end
+end
+copas.wrap=wrap
+function copas.handler(handler,sslparams)
+ return function (skt,...)
+  skt=wrap(skt)
+  if sslparams then
+   skt:dohandshake(sslparams)
+  end
+  return handler(skt,...)
+ end
+end
+local _errhandlers={}
+function copas.setErrorHandler(err)
+ local co=runningcoroutine()
+ if co then
+  _errhandlers[co]=err
+ end
+end
+local function _deferror (msg,co,skt)
+ report("%s (%s) (%s)",msg,tostring(co),tostring(skt))
+end
+local function _doTick (co,skt,...)
+ if not co then
+  return
+ end
+ local ok,res,new_q=resumecoroutine(co,skt,...)
+ if ok and res and new_q then
+  new_q:insert(res)
+  new_q:push(res,co)
+ else
+  if not ok then
+   pcall(_errhandlers[co] or _deferror,res,co,skt)
+  end
+  if skt and copas.autoclose and isTCP(skt) then
+   skt:close()
+  end
+  _errhandlers[co]=nil
+ end
+end
+local function _accept(input,handler)
+ local client=input:accept()
+ if client then
+  client:settimeout(0)
+  local co=createcoroutine(handler)
+  _doTick (co,client)
+ end
+ return client
+end
+local function _tickRead(skt)
+ _doTick(_reading:pop(skt),skt)
+end
+local function _tickWrite(skt)
+ _doTick(_writing:pop(skt),skt)
+end
+local function addTCPserver(server,handler,timeout)
+ server:settimeout(timeout or 0)
+ _servers[server]=handler
+ _reading:insert(server)
+end
+local function addUDPserver(server,handler,timeout)
+ server:settimeout(timeout or 0)
+ local co=createcoroutine(handler)
+ _reading:insert(server)
+ _doTick(co,server)
+end
+function copas.addserver(server,handler,timeout)
+ if isTCP(server) then
+  addTCPserver(server,handler,timeout)
+ else
+  addUDPserver(server,handler,timeout)
+ end
+end
+function copas.removeserver(server,keep_open)
+ local s=server
+ local mt=getmetatable(server)
+ if mt==_skt_mt_tcp or mt==_skt_mt_udp then
+  s=server.socket
+ end
+ _servers[s]=nil
+ _reading:remove(s)
+ if keep_open then
+  return true
+ end
+ return server:close()
+end
+function copas.addthread(handler,...)
+ local thread=createcoroutine(function(_,...) return handler(...) end)
+ _doTick(thread,nil,...)
+ return thread
+end
+local _tasks={}
+local function addtaskRead(task)
+ task.def_tick=_tickRead
+ _tasks[task]=true
+end
+local function addtaskWrite(task)
+ task.def_tick=_tickWrite
+ _tasks[task]=true
+end
+local function tasks()
+ return next,_tasks
+end
+local _readable_t={
+ events=function(self)
+   local i=0
+   return function ()
+    i=i+1
+    return self._evs[i]
+   end
+  end,
+ tick=function(self,input)
+   local handler=_servers[input]
+   if handler then
+    input=_accept(input,handler)
+   else
+    _reading:remove(input)
+    self.def_tick(input)
+   end
+  end
+}
+addtaskRead(_readable_t)
+local _writable_t={
+ events=function(self)
+   local i=0
+   return function()
+    i=i+1
+    return self._evs[i]
+   end
+  end,
+ tick=function(self,output)
+   _writing:remove(output)
+   self.def_tick(output)
+  end
+}
+addtaskWrite(_writable_t)
+local _sleeping_t={
+ tick=function(self,time,...)
+  _doTick(_sleeping:pop(time),...)
+ end
+}
+function copas.sleep(sleeptime)
+ yieldcoroutine((sleeptime or 0),_sleeping)
+end
+function copas.wakeup(co)
+ _sleeping:wakeup(co)
+end
+local last_cleansing=0
+local function _select(timeout)
+ local now=gettime()
+ local r_evs,w_evs,err=selectsocket(_reading,_writing,timeout)
+ _readable_t._evs=r_evs
+ _writable_t._evs=w_evs
+ if (last_cleansing-now)>WATCH_DOG_TIMEOUT then
+  last_cleansing=now
+  for skt,time in next,_reading_log do
+   if not r_evs[skt] and (time-now)>WATCH_DOG_TIMEOUT then
+    local n=#r_evs+1
+    _reading_log[skt]=nil
+    r_evs[n]=skt
+    r_evs[skt]=n
+   end
+  end
+  for skt,time in next,_writing_log do
+   if not w_evs[skt] and (time-now)>WATCH_DOG_TIMEOUT then
+    local n=#w_evs+1
+    _writing_log[skt]=nil
+    w_evs[n]=skt
+    w_evs[skt]=n
+   end
+  end
+ end
+ if err=="timeout" and #r_evs+#w_evs>0 then
+  return nil
+ else
+  return err
+ end
+end
+local function copasfinished()
+ return not (next(_reading) or next(_writing) or _sleeping:getnext())
+end
+local function copasstep(timeout)
+ _sleeping_t:tick(gettime())
+ local nextwait=_sleeping:getnext()
+ if nextwait then
+  timeout=timeout and min(nextwait,timeout) or nextwait
+ elseif copasfinished() then
+  return false
+ end
+ local err=_select(timeout)
+ if err then
+  if err=="timeout" then
+   return false
+  end
+  return nil,err
+ end
+ for task in tasks() do
+  for event in task:events() do
+   task:tick(event)
+  end
+ end
+ return true
+end
+copas.finished=copasfinished
+copas.step=copasstep
+function copas.loop(timeout)
+ copas.running=true
+ while not copasfinished() do
+  copasstep(timeout)
+ end
+ copas.running=false
+end
+package.loaded["copas"]=copas
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-ltn12"] = package.loaded["util-soc-imp-ltn12"] or true
+
+-- original size: 8709, stripped down to: 5411
+
+
+local select,unpack=select,unpack
+local insert,remove=table.insert,table.remove
+local sub=string.sub
+local function report(fmt,first,...)
+ if logs then
+  report=logs and logs.reporter("ltn12")
+  report(fmt,first,...)
+ elseif fmt then
+  fmt="ltn12: "..fmt
+  if first then
+   print(format(fmt,first,...))
+  else
+   print(fmt)
+  end
+ end
+end
+local filter={}
+local source={}
+local sink={}
+local pump={}
+local ltn12={
+ _VERSION="LTN12 1.0.3",
+ BLOCKSIZE=2048,
+ filter=filter,
+ source=source,
+ sink=sink,
+ pump=pump,
+ report=report,
+}
+function filter.cycle(low,ctx,extra)
+ if low then
+  return function(chunk)
+   return (low(ctx,chunk,extra))
+  end
+ end
+end
+function filter.chain(...)
+ local arg={... }
+ local n=select('#',...)
+ local top=1
+ local index=1
+ local retry=""
+ return function(chunk)
+  retry=chunk and retry
+  while true do
+   local action=arg[index]
+   if index==top then
+    chunk=action(chunk)
+    if chunk=="" or top==n then
+     return chunk
+    elseif chunk then
+     index=index+1
+    else
+     top=top+1
+     index=top
+    end
+   else
+    chunk=action(chunk or "")
+    if chunk=="" then
+     index=index-1
+     chunk=retry
+    elseif chunk then
+     if index==n then
+      return chunk
+     else
+      index=index+1
+     end
+    else
+     report("error: filter returned inappropriate 'nil'")
+     return
+    end
+   end
+  end
+ end
+end
+local function empty()
+ return nil
+end
+function source.empty()
+ return empty
+end
+local function sourceerror(err)
+ return function()
+  return nil,err
+ end
+end
+source.error=sourceerror
+function source.file(handle,io_err)
+ if handle then
+  local blocksize=ltn12.BLOCKSIZE
+  return function()
+   local chunk=handle:read(blocksize)
+   if not chunk then
+    handle:close()
+   end
+   return chunk
+  end
+ else
+  return sourceerror(io_err or "unable to open file")
+ end
+end
+function source.simplify(src)
+ return function()
+  local chunk,err_or_new=src()
+  if err_or_new then
+   src=err_or_new
+  end
+  if chunk then
+   return chunk
+  else
+   return nil,err_or_new
+  end
+ end
+end
+function source.string(s)
+ if s then
+  local blocksize=ltn12.BLOCKSIZE
+  local i=1
+  return function()
+   local nexti=i+blocksize
+   local chunk=sub(s,i,nexti-1)
+   i=nexti
+   if chunk~="" then
+    return chunk
+   else
+    return nil
+   end
+  end
+ else return source.empty() end
+end
+function source.rewind(src)
+ local t={}
+ return function(chunk)
+  if chunk then
+   insert(t,chunk)
+  else
+   chunk=remove(t)
+   if chunk then
+    return chunk
+   else
+    return src()
+   end
+  end
+ end
+end
+function source.chain(src,f,...)
+ if... then
+  f=filter.chain(f,...)
+ end
+ local last_in=""
+ local last_out=""
+ local state="feeding"
+ local err
+ return function()
+  if not last_out then
+   report("error: source is empty")
+   return
+  end
+  while true do
+   if state=="feeding" then
+    last_in,err=src()
+    if err then
+     return nil,err
+    end
+    last_out=f(last_in)
+    if not last_out then
+     if last_in then
+      report("error: filter returned inappropriate 'nil'")
+     end
+     return nil
+    elseif last_out~="" then
+     state="eating"
+     if last_in then
+      last_in=""
+     end
+     return last_out
+    end
+   else
+    last_out=f(last_in)
+    if last_out=="" then
+     if last_in=="" then
+      state="feeding"
+     else
+      report("error: filter returned nothing")
+      return
+     end
+    elseif not last_out then
+     if last_in then
+      report("filter returned inappropriate 'nil'")
+     end
+     return nil
+    else
+     return last_out
+    end
+   end
+  end
+ end
+end
+function source.cat(...)
+ local arg={... }
+ local src=remove(arg,1)
+ return function()
+  while src do
+   local chunk,err=src()
+   if chunk then
+    return chunk
+   end
+   if err then
+    return nil,err
+   end
+   src=remove(arg,1)
+  end
+ end
+end
+function sink.table(t)
+ if not t then
+  t={}
+ end
+ local f=function(chunk,err)
+  if chunk then
+   insert(t,chunk)
+  end
+  return 1
+ end
+ return f,t
+end
+function sink.simplify(snk)
+ return function(chunk,err)
+  local ret,err_or_new=snk(chunk,err)
+  if not ret then
+   return nil,err_or_new
+  end
+  if err_or_new then
+   snk=err_or_new
+  end
+  return 1
+ end
+end
+local function null()
+ return 1
+end
+function sink.null()
+ return null
+end
+local function sinkerror(err)
+ return function()
+  return nil,err
+ end
+end
+sink.error=sinkerror
+function sink.file(handle,io_err)
+ if handle then
+  return function(chunk,err)
+   if not chunk then
+    handle:close()
+    return 1
+   else
+    return handle:write(chunk)
+   end
+  end
+ else
+  return sinkerror(io_err or "unable to open file")
+ end
+end
+function sink.chain(f,snk,...)
+ if... then
+  local args={ f,snk,... }
+  snk=remove(args,#args)
+  f=filter.chain(unpack(args))
+ end
+ return function(chunk,err)
+  if chunk~="" then
+   local filtered=f(chunk)
+   local done=chunk and ""
+   while true do
+    local ret,snkerr=snk(filtered,err)
+    if not ret then
+     return nil,snkerr
+    end
+    if filtered==done then
+     return 1
+    end
+    filtered=f(done)
+   end
+  else
+   return 1
+  end
+ end
+end
+function pump.step(src,snk)
+ local chunk,src_err=src()
+ local ret,snk_err=snk(chunk,src_err)
+ if chunk and ret then
+  return 1
+ else
+  return nil,src_err or snk_err
+ end
+end
+function pump.all(src,snk,step)
+ if not step then
+  step=pump.step
+ end
+ while true do
+  local ret,err=step(src,snk)
+  if not ret then
+   if err then
+    return nil,err
+   else
+    return 1
+   end
+  end
+ end
+end
+package.loaded["ltn12"]=ltn12
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-mime"] = package.loaded["util-soc-imp-mime"] or true
+
+-- original size: 2373, stripped down to: 1931
+
+
+local type,tostring=type,tostring
+local mime=mime  or package.loaded.mime  or require("mime.core")
+local ltn12=ltn12 or package.loaded.ltn12 or require("ltn12")
+local filtercycle=ltn12.filter.cycle
+local function report(fmt,first,...)
+ if logs then
+  report=logs and logs.reporter("mime")
+  report(fmt,first,...)
+ elseif fmt then
+  fmt="mime: "..fmt
+  if first then
+   print(format(fmt,first,...))
+  else
+   print(fmt)
+  end
+ end
+end
+mime.report=report
+local encodet={}
+local decodet={}
+local wrapt={}
+mime.encodet=encodet
+mime.decodet=decodet
+mime.wrapt=wrapt
+local mime_b64=mime.b64
+local mime_qp=mime.qp
+local mime_unb64=mime.unb64
+local mime_unqp=mime.unqp
+local mime_wrp=mime.wrp
+local mime_qpwrp=mime.qpwrp
+local mime_eol=mime_eol
+local mime_dot=mime_dot
+encodet['base64']=function()
+ return filtercycle(mime_b64,"")
+end
+encodet['quoted-printable']=function(mode)
+ return filtercycle(mime_qp,"",mode=="binary" and "=0D=0A" or "\r\n")
+end
+decodet['base64']=function()
+ return filtercycle(mime_unb64,"")
+end
+decodet['quoted-printable']=function()
+ return filtercycle(mime_unqp,"")
+end
+local wraptext=function(length)
+ if not length then
+  length=76
+ end
+ return filtercycle(mime_wrp,length,length)
+end
+local wrapquoted=function()
+ return filtercycle(mime_qpwrp,76,76)
+end
+wrapt['text']=wraptext
+wrapt['base64']=wraptext
+wrapt['default']=wraptext
+wrapt['quoted-printable']=wrapquoted
+function mime.normalize(marker)
+ return filtercycle(mime_eol,0,marker)
+end
+function mime.stuff()
+ return filtercycle(mime_dot,2)
+end
+local function choose(list)
+ return function(name,opt1,opt2)
+  if type(name)~="string" then
+   name,opt1,opt2="default",name,opt1
+  end
+  local filter=list[name or "nil"]
+  if filter then
+   return filter(opt1,opt2)
+  else
+   report("error: unknown key '%s'",tostring(name))
+  end
+ end
+end
+mime.encode=choose(encodet)
+mime.decode=choose(decodet)
+mime.wrap=choose(wrapt)
+package.loaded["mime"]=mime
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-url"] = package.loaded["util-soc-imp-url"] or true
+
+-- original size: 6863, stripped down to: 5269
+
+
+local tonumber,tostring,type=tonumber,tostring,type
+local gsub,sub,match,find,format,byte,char=string.gsub,string.sub,string.match,string.find,string.format,string.byte,string.char
+local insert=table.insert
+local socket=socket or require("socket")
+local url={
+ _VERSION="URL 1.0.3",
+}
+socket.url=url
+function url.escape(s)
+ return (gsub(s,"([^A-Za-z0-9_])",function(c)
+  return format("%%%02x",byte(c))
+ end))
+end
+local function make_set(t) 
+ local s={}
+ for i=1,#t do
+  s[t[i]]=true
+ end
+ return s
+end
+local segment_set=make_set {
+ "-","_",".","!","~","*","'","(",
+ ")",":","@","&","=","+","$",",",
+}
+local function protect_segment(s)
+ return gsub(s,"([^A-Za-z0-9_])",function(c)
+  if segment_set[c] then
+   return c
+  else
+   return format("%%%02X",byte(c))
+  end
+ end)
+end
+function url.unescape(s)
+ return (gsub(s,"%%(%x%x)",function(hex)
+  return char(tonumber(hex,16))
+ end))
+end
+local function absolute_path(base_path,relative_path)
+ if find(relative_path,"^/") then
+  return relative_path
+ end
+ local path=gsub(base_path,"[^/]*$","")
+ path=path..relative_path
+ path=gsub(path,"([^/]*%./)",function (s)
+  if s~="./" then
+   return s
+  else
+   return ""
+  end
+ end)
+ path=gsub(path,"/%.$","/")
+ local reduced
+ while reduced~=path do
+  reduced=path
+  path=gsub(reduced,"([^/]*/%.%./)",function (s)
+   if s~="../../" then
+    return ""
+   else
+    return s
+   end
+  end)
+ end
+ path=gsub(reduced,"([^/]*/%.%.)$",function (s)
+  if s~="../.." then
+   return ""
+  else
+   return s
+  end
+ end)
+ return path
+end
+function url.parse(url,default)
+ local parsed={}
+ for k,v in next,default or parsed do
+  parsed[k]=v
+ end
+ if not url or url=="" then
+  return nil,"invalid url"
+ end
+ url=gsub(url,"#(.*)$",function(f)
+  parsed.fragment=f
+  return ""
+ end)
+ url=gsub(url,"^([%w][%w%+%-%.]*)%:",function(s)
+  parsed.scheme=s
+  return ""
+ end)
+ url=gsub(url,"^//([^/]*)",function(n)
+  parsed.authority=n
+  return ""
+ end)
+ url=gsub(url,"%?(.*)",function(q)
+  parsed.query=q
+  return ""
+ end)
+ url=gsub(url,"%;(.*)",function(p)
+  parsed.params=p
+  return ""
+ end)
+ if url~="" then
+  parsed.path=url
+ end
+ local authority=parsed.authority
+ if not authority then
+  return parsed
+ end
+ authority=gsub(authority,"^([^@]*)@",function(u)
+  parsed.userinfo=u
+  return ""
+ end)
+ authority=gsub(authority,":([^:%]]*)$",function(p)
+  parsed.port=p
+  return ""
+ end)
+ if authority~="" then
+  parsed.host=match(authority,"^%[(.+)%]$") or authority
+ end
+ local userinfo=parsed.userinfo
+ if not userinfo then
+  return parsed
+ end
+ userinfo=gsub(userinfo,":([^:]*)$",function(p)
+  parsed.password=p
+  return ""
+ end)
+ parsed.user=userinfo
+ return parsed
+end
+function url.build(parsed)
+ local url=parsed.path or ""
+ if parsed.params then
+  url=url..";"..parsed.params
+ end
+ if parsed.query then
+  url=url.."?"..parsed.query
+ end
+ local authority=parsed.authority
+ if parsed.host then
+  authority=parsed.host
+  if find(authority,":") then 
+   authority="["..authority.."]"
+  end
+  if parsed.port then
+   authority=authority..":"..tostring(parsed.port)
+  end
+  local userinfo=parsed.userinfo
+  if parsed.user then
+   userinfo=parsed.user
+   if parsed.password then
+    userinfo=userinfo..":"..parsed.password
+   end
+  end
+  if userinfo then authority=userinfo.."@"..authority end
+ end
+ if authority then
+  url="//"..authority..url
+ end
+ if parsed.scheme then
+  url=parsed.scheme..":"..url
+ end
+ if parsed.fragment then
+  url=url.."#"..parsed.fragment
+ end
+ return url
+end
+function url.absolute(base_url,relative_url)
+ local base_parsed
+ if type(base_url)=="table" then
+  base_parsed=base_url
+  base_url=url.build(base_parsed)
+ else
+  base_parsed=url.parse(base_url)
+ end
+ local relative_parsed=url.parse(relative_url)
+ if not base_parsed then
+  return relative_url
+ elseif not relative_parsed then
+  return base_url
+ elseif relative_parsed.scheme then
+  return relative_url
+ else
+  relative_parsed.scheme=base_parsed.scheme
+  if not relative_parsed.authority then
+   relative_parsed.authority=base_parsed.authority
+   if not relative_parsed.path then
+    relative_parsed.path=base_parsed.path
+    if not relative_parsed.params then
+     relative_parsed.params=base_parsed.params
+     if not relative_parsed.query then
+      relative_parsed.query=base_parsed.query
+     end
+    end
+   else
+    relative_parsed.path=absolute_path(base_parsed.path or "",relative_parsed.path)
+   end
+  end
+  return url.build(relative_parsed)
+ end
+end
+function url.parse_path(path)
+ local parsed={}
+ path=path or ""
+ gsub(path,"([^/]+)",function (s)
+  insert(parsed,s)
+ end)
+ for i=1,#parsed do
+  parsed[i]=url.unescape(parsed[i])
+ end
+ if sub(path,1,1)=="/" then
+  parsed.is_absolute=1
+ end
+ if sub(path,-1,-1)=="/" then
+  parsed.is_directory=1
+ end
+ return parsed
+end
+function url.build_path(parsed,unsafe)
+ local path=""
+ local n=#parsed
+ if unsafe then
+  for i=1,n-1 do
+   path=path..parsed[i].."/"
+  end
+  if n>0 then
+   path=path..parsed[n]
+   if parsed.is_directory then
+    path=path.."/"
+   end
+  end
+ else
+  for i=1,n-1 do
+   path=path..protect_segment(parsed[i]).."/"
+  end
+  if n>0 then
+   path=path..protect_segment(parsed[n])
+   if parsed.is_directory then
+    path=path.."/"
+   end
+  end
+ end
+ if parsed.is_absolute then
+  path="/"..path
+ end
+ return path
+end
+package.loaded["socket.url"]=url
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-headers"] = package.loaded["util-soc-imp-headers"] or true
+
+-- original size: 5721, stripped down to: 3754
+
+
+local next=next
+local lower=string.lower
+local concat=table.concat
+local socket=socket or require("socket")
+local headers={}
+socket.headers=headers
+local canonic={
+ ["accept"]="Accept",
+ ["accept-charset"]="Accept-Charset",
+ ["accept-encoding"]="Accept-Encoding",
+ ["accept-language"]="Accept-Language",
+ ["accept-ranges"]="Accept-Ranges",
+ ["action"]="Action",
+ ["alternate-recipient"]="Alternate-Recipient",
+ ["age"]="Age",
+ ["allow"]="Allow",
+ ["arrival-date"]="Arrival-Date",
+ ["authorization"]="Authorization",
+ ["bcc"]="Bcc",
+ ["cache-control"]="Cache-Control",
+ ["cc"]="Cc",
+ ["comments"]="Comments",
+ ["connection"]="Connection",
+ ["content-description"]="Content-Description",
+ ["content-disposition"]="Content-Disposition",
+ ["content-encoding"]="Content-Encoding",
+ ["content-id"]="Content-ID",
+ ["content-language"]="Content-Language",
+ ["content-length"]="Content-Length",
+ ["content-location"]="Content-Location",
+ ["content-md5"]="Content-MD5",
+ ["content-range"]="Content-Range",
+ ["content-transfer-encoding"]="Content-Transfer-Encoding",
+ ["content-type"]="Content-Type",
+ ["cookie"]="Cookie",
+ ["date"]="Date",
+ ["diagnostic-code"]="Diagnostic-Code",
+ ["dsn-gateway"]="DSN-Gateway",
+ ["etag"]="ETag",
+ ["expect"]="Expect",
+ ["expires"]="Expires",
+ ["final-log-id"]="Final-Log-ID",
+ ["final-recipient"]="Final-Recipient",
+ ["from"]="From",
+ ["host"]="Host",
+ ["if-match"]="If-Match",
+ ["if-modified-since"]="If-Modified-Since",
+ ["if-none-match"]="If-None-Match",
+ ["if-range"]="If-Range",
+ ["if-unmodified-since"]="If-Unmodified-Since",
+ ["in-reply-to"]="In-Reply-To",
+ ["keywords"]="Keywords",
+ ["last-attempt-date"]="Last-Attempt-Date",
+ ["last-modified"]="Last-Modified",
+ ["location"]="Location",
+ ["max-forwards"]="Max-Forwards",
+ ["message-id"]="Message-ID",
+ ["mime-version"]="MIME-Version",
+ ["original-envelope-id"]="Original-Envelope-ID",
+ ["original-recipient"]="Original-Recipient",
+ ["pragma"]="Pragma",
+ ["proxy-authenticate"]="Proxy-Authenticate",
+ ["proxy-authorization"]="Proxy-Authorization",
+ ["range"]="Range",
+ ["received"]="Received",
+ ["received-from-mta"]="Received-From-MTA",
+ ["references"]="References",
+ ["referer"]="Referer",
+ ["remote-mta"]="Remote-MTA",
+ ["reply-to"]="Reply-To",
+ ["reporting-mta"]="Reporting-MTA",
+ ["resent-bcc"]="Resent-Bcc",
+ ["resent-cc"]="Resent-Cc",
+ ["resent-date"]="Resent-Date",
+ ["resent-from"]="Resent-From",
+ ["resent-message-id"]="Resent-Message-ID",
+ ["resent-reply-to"]="Resent-Reply-To",
+ ["resent-sender"]="Resent-Sender",
+ ["resent-to"]="Resent-To",
+ ["retry-after"]="Retry-After",
+ ["return-path"]="Return-Path",
+ ["sender"]="Sender",
+ ["server"]="Server",
+ ["smtp-remote-recipient"]="SMTP-Remote-Recipient",
+ ["status"]="Status",
+ ["subject"]="Subject",
+ ["te"]="TE",
+ ["to"]="To",
+ ["trailer"]="Trailer",
+ ["transfer-encoding"]="Transfer-Encoding",
+ ["upgrade"]="Upgrade",
+ ["user-agent"]="User-Agent",
+ ["vary"]="Vary",
+ ["via"]="Via",
+ ["warning"]="Warning",
+ ["will-retry-until"]="Will-Retry-Until",
+ ["www-authenticate"]="WWW-Authenticate",
+ ["x-mailer"]="X-Mailer",
+}
+headers.canonic=setmetatable(canonic,{
+ __index=function(t,k)
+  socket.report("invalid header: %s",k)
+  t[k]=k
+  return k
+ end
+})
+function headers.normalize(headers)
+ if not headers then
+  return {}
+ end
+ local normalized={}
+ for k,v in next,headers do
+  normalized[#normalized+1]=canonic[k]..": "..v
+ end
+ normalized[#normalized+1]=""
+ normalized[#normalized+1]=""
+ return concat(normalized,"\r\n")
+end
+function headers.lower(lowered,headers)
+ if not lowered then
+  return {}
+ end
+ if not headers then
+  lowered,headers={},lowered
+ end
+ for k,v in next,headers do
+  lowered[lower(k)]=v
+ end
+ return lowered
+end
+socket.headers=headers
+package.loaded["socket.headers"]=headers
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-tp"] = package.loaded["util-soc-imp-tp"] or true
+
+-- original size: 3116, stripped down to: 2533
+
+
+local setmetatable,next,type,tonumber=setmetatable,next,type,tonumber
+local find,upper=string.find,string.upper
+local socket=socket or require("socket")
+local ltn12=ltn12  or require("ltn12")
+local skipsocket=socket.skip
+local sinksocket=socket.sink
+local tcpsocket=socket.tcp
+local ltn12pump=ltn12.pump
+local pumpall=ltn12pump.all
+local pumpstep=ltn12pump.step
+local tp={
+ TIMEOUT=60,
+}
+socket.tp=tp
+local function get_reply(c)
+ local line,err=c:receive()
+ local reply=line
+ if err then return
+  nil,err
+ end
+ local code,sep=skipsocket(2,find(line,"^(%d%d%d)(.?)"))
+ if not code then
+  return nil,"invalid server reply"
+ end
+ if sep=="-" then
+  local current
+  repeat
+   line,err=c:receive()
+   if err then
+    return nil,err
+   end
+   current,sep=skipsocket(2,find(line,"^(%d%d%d)(.?)"))
+   reply=reply.."\n"..line
+  until code==current and sep==" "
+ end
+ return code,reply
+end
+local methods={}
+local mt={ __index=methods }
+function methods.getpeername(self)
+ return self.c:getpeername()
+end
+function methods.getsockname(self)
+ return self.c:getpeername()
+end
+function methods.check(self,ok)
+ local code,reply=get_reply(self.c)
+ if not code then
+  return nil,reply
+ end
+ local c=tonumber(code)
+ local t=type(ok)
+ if t=="function" then
+  return ok(c,reply)
+ elseif t=="table" then
+  for i=1,#ok do
+   if find(code,ok[i]) then
+    return c,reply
+   end
+  end
+  return nil,reply
+ elseif find(code,ok) then
+  return c,reply
+ else
+  return nil,reply
+ end
+end
+function methods.command(self,cmd,arg)
+ cmd=upper(cmd)
+ if arg then
+  cmd=cmd.." "..arg.."\r\n"
+ else
+  cmd=cmd.."\r\n"
+ end
+ return self.c:send(cmd)
+end
+function methods.sink(self,snk,pat)
+ local chunk,err=self.c:receive(pat)
+ return snk(chunk,err)
+end
+function methods.send(self,data)
+ return self.c:send(data)
+end
+function methods.receive(self,pat)
+ return self.c:receive(pat)
+end
+function methods.getfd(self)
+ return self.c:getfd()
+end
+function methods.dirty(self)
+ return self.c:dirty()
+end
+function methods.getcontrol(self)
+ return self.c
+end
+function methods.source(self,source,step)
+ local sink=sinksocket("keep-open",self.c)
+ local ret,err=pumpall(source,sink,step or pumpstep)
+ return ret,err
+end
+function methods.close(self)
+ self.c:close()
+ return 1
+end
+function tp.connect(host,port,timeout,create)
+ local c,e=(create or tcpsocket)()
+ if not c then
+  return nil,e
+ end
+ c:settimeout(timeout or tp.TIMEOUT)
+ local r,e=c:connect(host,port)
+ if not r then
+  c:close()
+  return nil,e
+ end
+ return setmetatable({ c=c },mt)
+end
+package.loaded["socket.tp"]=tp
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-http"] = package.loaded["util-soc-imp-http"] or true
+
+-- original size: 12624, stripped down to: 9598
+
+
+local tostring,tonumber,setmetatable,next,type=tostring,tonumber,setmetatable,next,type
+local find,lower,format,gsub,match=string.find,string.lower,string.format,string.gsub,string.match
+local concat=table.concat
+local socket=socket   or require("socket")
+local url=socket.url  or require("socket.url")
+local ltn12=ltn12    or require("ltn12")
+local mime=mime     or require("mime")
+local headers=socket.headers or require("socket.headers")
+local normalizeheaders=headers.normalize
+local parseurl=url.parse
+local buildurl=url.build
+local absoluteurl=url.absolute
+local unescapeurl=url.unescape
+local skipsocket=socket.skip
+local sinksocket=socket.sink
+local sourcesocket=socket.source
+local trysocket=socket.try
+local tcpsocket=socket.tcp
+local newtrysocket=socket.newtry
+local protectsocket=socket.protect
+local emptysource=ltn12.source.empty
+local stringsource=ltn12.source.string
+local rewindsource=ltn12.source.rewind
+local pumpstep=ltn12.pump.step
+local pumpall=ltn12.pump.all
+local sinknull=ltn12.sink.null
+local sinktable=ltn12.sink.table
+local lowerheaders=headers.lower
+local mimeb64=mime.b64
+local http={
+ TIMEOUT=60,
+ USERAGENT=socket._VERSION,
+}
+socket.http=http
+local PORT=80
+local SCHEMES={
+ http=true,
+}
+local function receiveheaders(sock,headers)
+ if not headers then
+  headers={}
+ end
+ local line,err=sock:receive("*l") 
+ if err then
+  return nil,err
+ end
+ while line~="" do
+  local name,value=skipsocket(2,find(line,"^(.-):%s*(.*)"))
+  if not (name and value) then
+   return nil,"malformed reponse headers"
+  end
+  name=lower(name)
+  line,err=sock:receive("*l")
+  if err then
+   return nil,err
+  end
+  while find(line,"^%s") do
+   value=value..line
+   line=sock:receive("*l")
+   if err then
+    return nil,err
+   end
+  end
+  local found=headers[name]
+  if found then
+   value=found..", "..value
+  end
+  headers[name]=value
+ end
+ return headers
+end
+socket.sourcet["http-chunked"]=function(sock,headers)
+ return setmetatable (
+  {
+   getfd=function() return sock:getfd() end,
+   dirty=function() return sock:dirty() end,
+  },{
+   __call=function()
+    local line,err=sock:receive("*l")
+    if err then
+     return nil,err
+    end
+    local size=tonumber(gsub(line,";.*",""),16)
+    if not size then
+     return nil,"invalid chunk size"
+    end
+    if size>0 then
+     local chunk,err,part=sock:receive(size)
+     if chunk then
+      sock:receive("*a")
+     end
+     return chunk,err
+    else
+     headers,err=receiveheaders(sock,headers)
+     if not headers then
+      return nil,err
+     end
+    end
+   end
+  }
+ )
+end
+socket.sinkt["http-chunked"]=function(sock)
+ return setmetatable(
+  {
+   getfd=function() return sock:getfd() end,
+   dirty=function() return sock:dirty() end,
+  },
+  {
+   __call=function(self,chunk,err)
+    if not chunk then
+     chunk=""
+    end
+    return sock:send(format("%X\r\n%s\r\n",#chunk,chunk))
+   end
+ })
+end
+local methods={}
+local mt={ __index=methods }
+local function openhttp(host,port,create)
+ local c=trysocket((create or tcpsocket)())
+ local h=setmetatable({ c=c },mt)
+ local try=newtrysocket(function() h:close() end)
+ h.try=try
+ try(c:settimeout(http.TIMEOUT))
+ try(c:connect(host,port or PORT))
+ return h
+end
+http.open=openhttp
+function methods.sendrequestline(self,method,uri)
+ local requestline=format("%s %s HTTP/1.1\r\n",method or "GET",uri)
+ return self.try(self.c:send(requestline))
+end
+function methods.sendheaders(self,headers)
+ self.try(self.c:send(normalizeheaders(headers)))
+ return 1
+end
+function methods.sendbody(self,headers,source,step)
+ if not source then
+  source=emptysource()
+ end
+ if not step then
+  step=pumpstep
+ end
+ local mode="http-chunked"
+ if headers["content-length"] then
+  mode="keep-open"
+ end
+ return self.try(pumpall(source,sinksocket(mode,self.c),step))
+end
+function methods.receivestatusline(self)
+ local try=self.try
+ local status=try(self.c:receive(5))
+ if status~="HTTP/" then
+  return nil,status 
+ end
+ status=try(self.c:receive("*l",status))
+ local code=skipsocket(2,find(status,"HTTP/%d*%.%d* (%d%d%d)"))
+ return try(tonumber(code),status)
+end
+function methods.receiveheaders(self)
+ return self.try(receiveheaders(self.c))
+end
+function methods.receivebody(self,headers,sink,step)
+ if not sink then
+  sink=sinknull()
+ end
+ if not step then
+  step=pumpstep
+ end
+ local length=tonumber(headers["content-length"])
+ local encoding=headers["transfer-encoding"] 
+ local mode="default" 
+ if encoding and encoding~="identity" then
+  mode="http-chunked"
+ elseif length then
+  mode="by-length"
+ end
+ return self.try(pumpall(sourcesocket(mode,self.c,length),sink,step))
+end
+function methods.receive09body(self,status,sink,step)
+ local source=rewindsource(sourcesocket("until-closed",self.c))
+ source(status)
+ return self.try(pumpall(source,sink,step))
+end
+function methods.close(self)
+ return self.c:close()
+end
+local function adjusturi(request)
+ if not request.proxy and not http.PROXY then
+  request={
+     path=trysocket(request.path,"invalid path 'nil'"),
+     params=request.params,
+     query=request.query,
+     fragment=request.fragment,
+  }
+ end
+ return buildurl(request)
+end
+local function adjustheaders(request)
+ local headers={
+  ["user-agent"]=http.USERAGENT,
+  ["host"]=gsub(request.authority,"^.-@",""),
+  ["connection"]="close, TE",
+  ["te"]="trailers"
+ }
+ local username=request.user
+ local password=request.password
+ if username and password then
+  headers["authorization"]="Basic "..(mimeb64(username..":"..unescapeurl(password)))
+ end
+ local proxy=request.proxy or http.PROXY
+ if proxy then
+  proxy=parseurl(proxy)
+  local username=proxy.user
+  local password=proxy.password
+  if username and password then
+   headers["proxy-authorization"]="Basic "..(mimeb64(username..":"..password))
+  end
+ end
+ local requestheaders=request.headers
+ if requestheaders then
+  headers=lowerheaders(headers,requestheaders)
+ end
+ return headers
+end
+local default={
+ host="",
+ port=PORT,
+ path="/",
+ scheme="http"
+}
+local function adjustrequest(originalrequest)
+ local url=originalrequest.url
+ local request=url and parseurl(url,default) or {}
+ for k,v in next,originalrequest do
+  request[k]=v
+ end
+ local host=request.host
+ local port=request.port
+ local uri=request.uri
+ if not host or host=="" then
+  trysocket(nil,"invalid host '"..tostring(host).."'")
+ end
+ if port=="" then
+  request.port=PORT
+ end
+ if not uri or uri=="" then
+  request.uri=adjusturi(request)
+ end
+ request.headers=adjustheaders(request)
+ local proxy=request.proxy or http.PROXY
+ if proxy then
+  proxy=parseurl(proxy)
+  request.host=proxy.host
+  request.port=proxy.port or 3128
+ end
+ return request
+end
+local maxredericts=4
+local validredirects={ [301]=true,[302]=true,[303]=true,[307]=true }
+local validmethods={ [false]=true,GET=true,HEAD=true }
+local function shouldredirect(request,code,headers)
+ local location=headers.location
+ if not location then
+  return false
+ end
+ location=gsub(location,"%s","")
+ if location=="" then
+  return false
+ end
+ local scheme=match(location,"^([%w][%w%+%-%.]*)%:")
+ if scheme and not SCHEMES[scheme] then
+  return false
+ end
+ local method=request.method
+ local redirect=request.redirect
+ local redirects=request.nredirects or 0
+ return redirect and validredirects[code] and validmethods[method] and redirects<=maxredericts
+end
+local function shouldreceivebody(request,code)
+ if request.method=="HEAD" then
+  return nil
+ end
+ if code==204 or code==304 then
+  return nil
+ end
+ if code>=100 and code<200 then
+  return nil
+ end
+ return 1
+end
+local tredirect,trequest,srequest
+tredirect=function(request,location)
+ local result,code,headers,status=trequest {
+  url=absoluteurl(request.url,location),
+  source=request.source,
+  sink=request.sink,
+  headers=request.headers,
+  proxy=request.proxy,
+  nredirects=(request.nredirects or 0)+1,
+  create=request.create,
+ }
+ if not headers then
+  headers={}
+ end
+ if not headers.location then
+  headers.location=location
+ end
+ return result,code,headers,status
+end
+trequest=function(originalrequest)
+ local request=adjustrequest(originalrequest)
+ local connection=openhttp(request.host,request.port,request.create)
+ local headers=request.headers
+ connection:sendrequestline(request.method,request.uri)
+ connection:sendheaders(headers)
+ if request.source then
+  connection:sendbody(headers,request.source,request.step)
+ end
+ local code,status=connection:receivestatusline()
+ if not code then
+  connection:receive09body(status,request.sink,request.step)
+  return 1,200
+ end
+ while code==100 do
+  headers=connection:receiveheaders()
+  code,status=connection:receivestatusline()
+ end
+ headers=connection:receiveheaders()
+ if shouldredirect(request,code,headers) and not request.source then
+  connection:close()
+  return tredirect(originalrequest,headers.location)
+ end
+ if shouldreceivebody(request,code) then
+  connection:receivebody(headers,request.sink,request.step)
+ end
+ connection:close()
+ return 1,code,headers,status
+end
+local function genericform(url,body)
+ local buffer={}
+ local request={
+  url=url,
+  sink=sinktable(buffer),
+  target=buffer,
+ }
+ if body then
+  request.source=stringsource(body)
+  request.method="POST"
+  request.headers={
+   ["content-length"]=#body,
+   ["content-type"]="application/x-www-form-urlencoded"
+  }
+ end
+ return request
+end
+http.genericform=genericform
+srequest=function(url,body)
+ local request=genericform(url,body)
+ local _,code,headers,status=trequest(request)
+ return concat(request.target),code,headers,status
+end
+http.request=protectsocket(function(request,body)
+ if type(request)=="string" then
+  return srequest(request,body)
+ else
+  return trequest(request)
+ end
+end)
+package.loaded["socket.http"]=http
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-ftp"] = package.loaded["util-soc-imp-ftp"] or true
+
+-- original size: 10357, stripped down to: 8548
+
+
+local setmetatable,type,next=setmetatable,type,next
+local find,format,gsub,match=string.find,string.format,string.gsub,string.match
+local concat=table.concat
+local mod=math.mod
+local socket=socket  or require("socket")
+local url=socket.url or require("socket.url")
+local tp=socket.tp  or require("socket.tp")
+local ltn12=ltn12   or require("ltn12")
+local tcpsocket=socket.tcp
+local trysocket=socket.try
+local skipsocket=socket.skip
+local sinksocket=socket.sink
+local selectsocket=socket.select
+local bindsocket=socket.bind
+local newtrysocket=socket.newtry
+local sourcesocket=socket.source
+local protectsocket=socket.protect
+local parseurl=url.parse
+local unescapeurl=url.unescape
+local pumpall=ltn12.pump.all
+local pumpstep=ltn12.pump.step
+local sourcestring=ltn12.source.string
+local sinktable=ltn12.sink.table
+local ftp={
+ TIMEOUT=60,
+ USER="ftp",
+ PASSWORD="anonymous at anonymous.org",
+}
+socket.ftp=ftp
+local PORT=21
+local methods={}
+local mt={ __index=methods }
+function ftp.open(server,port,create)
+ local tp=trysocket(tp.connect(server,port or PORT,ftp.TIMEOUT,create))
+ local f=setmetatable({ tp=tp },metat)
+ f.try=newtrysocket(function() f:close() end)
+ return f
+end
+function methods.portconnect(self)
+ local try=self.try
+ local server=self.server
+ try(server:settimeout(ftp.TIMEOUT))
+ self.data=try(server:accept())
+ try(self.data:settimeout(ftp.TIMEOUT))
+end
+function methods.pasvconnect(self)
+ local try=self.try
+ self.data=try(tcpsocket())
+ self(self.data:settimeout(ftp.TIMEOUT))
+ self(self.data:connect(self.pasvt.address,self.pasvt.port))
+end
+function methods.login(self,user,password)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("user",user or ftp.USER))
+ local code,reply=try(tp:check{"2..",331})
+ if code==331 then
+  try(tp:command("pass",password or ftp.PASSWORD))
+  try(tp:check("2.."))
+ end
+ return 1
+end
+function methods.pasv(self)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("pasv"))
+ local code,reply=try(self.tp:check("2.."))
+ local pattern="(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)"
+ local a,b,c,d,p1,p2=skipsocket(2,find(reply,pattern))
+ try(a and b and c and d and p1 and p2,reply)
+ local address=format("%d.%d.%d.%d",a,b,c,d)
+ local port=p1*256+p2
+ local server=self.server
+ self.pasvt={
+  address=address,
+  port=port,
+ }
+ if server then
+  server:close()
+  self.server=nil
+ end
+ return address,port
+end
+function methods.epsv(self)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("epsv"))
+ local code,reply=try(tp:check("229"))
+ local pattern="%((.)(.-)%1(.-)%1(.-)%1%)"
+ local d,prt,address,port=match(reply,pattern)
+ try(port,"invalid epsv response")
+ local address=tp:getpeername()
+ local server=self.server
+ self.pasvt={
+  address=address,
+  port=port,
+ }
+ if self.server then
+  server:close()
+  self.server=nil
+ end
+ return address,port
+end
+function methods.port(self,address,port)
+ local try=self.try
+ local tp=self.tp
+ self.pasvt=nil
+ if not address then
+  address,port=try(tp:getsockname())
+  self.server=try(bindsocket(address,0))
+  address,port=try(self.server:getsockname())
+  try(self.server:settimeout(ftp.TIMEOUT))
+ end
+ local pl=mod(port,256)
+ local ph=(port-pl)/256
+ local arg=gsub(format("%s,%d,%d",address,ph,pl),"%.",",")
+ try(tp:command("port",arg))
+ try(tp:check("2.."))
+ return 1
+end
+function methods.eprt(self,family,address,port)
+ local try=self.try
+ local tp=self.tp
+ self.pasvt=nil
+ if not address then
+  address,port=try(tp:getsockname())
+  self.server=try(bindsocket(address,0))
+  address,port=try(self.server:getsockname())
+  try(self.server:settimeout(ftp.TIMEOUT))
+ end
+ local arg=format("|%s|%s|%d|",family,address,port)
+ try(tp:command("eprt",arg))
+ try(tp:check("2.."))
+ return 1
+end
+function methods.send(self,sendt)
+ local try=self.try
+ local tp=self.tp
+ try(self.pasvt or self.server,"need port or pasv first")
+ if self.pasvt then
+  self:pasvconnect()
+ end
+ local argument=sendt.argument or unescapeurl(gsub(sendt.path or "","^[/\\]",""))
+ if argument=="" then
+  argument=nil
+ end
+ local command=sendt.command or "stor"
+ try(tp:command(command,argument))
+ local code,reply=try(tp:check{"2..","1.."})
+ if not self.pasvt then
+  self:portconnect()
+ end
+ local step=sendt.step or pumpstep
+ local readt={ tp }
+ local checkstep=function(src,snk)
+  local readyt=selectsocket(readt,nil,0)
+  if readyt[tp] then
+   code=try(tp:check("2.."))
+  end
+  return step(src,snk)
+ end
+ local sink=sinksocket("close-when-done",self.data)
+ try(pumpall(sendt.source,sink,checkstep))
+ if find(code,"1..") then
+  try(tp:check("2.."))
+ end
+ self.data:close()
+ local sent=skipsocket(1,self.data:getstats())
+ self.data=nil
+ return sent
+end
+function methods.receive(self,recvt)
+ local try=self.try
+ local tp=self.tp
+ try(self.pasvt or self.server,"need port or pasv first")
+ if self.pasvt then self:pasvconnect() end
+ local argument=recvt.argument or unescapeurl(gsub(recvt.path or "","^[/\\]",""))
+ if argument=="" then
+  argument=nil
+ end
+ local command=recvt.command or "retr"
+ try(tp:command(command,argument))
+ local code,reply=try(tp:check{"1..","2.."})
+ if code>=200 and code<=299 then
+  recvt.sink(reply)
+  return 1
+ end
+ if not self.pasvt then
+  self:portconnect()
+ end
+ local source=sourcesocket("until-closed",self.data)
+ local step=recvt.step or pumpstep
+ try(pumpall(source,recvt.sink,step))
+ if find(code,"1..") then
+  try(tp:check("2.."))
+ end
+ self.data:close()
+ self.data=nil
+ return 1
+end
+function methods.cwd(self,dir)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("cwd",dir))
+ try(tp:check(250))
+ return 1
+end
+function methods.type(self,typ)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("type",typ))
+ try(tp:check(200))
+ return 1
+end
+function methods.greet(self)
+ local try=self.try
+ local tp=self.tp
+ local code=try(tp:check{"1..","2.."})
+ if find(code,"1..") then
+  try(tp:check("2.."))
+ end
+ return 1
+end
+function methods.quit(self)
+ local try=self.try
+ try(self.tp:command("quit"))
+ try(self.tp:check("2.."))
+ return 1
+end
+function methods.close(self)
+ local data=self.data
+ if data then
+  data:close()
+ end
+ local server=self.server
+ if server then
+  server:close()
+ end
+ local tp=self.tp
+ if tp then
+  tp:close()
+ end
+end
+local function override(t)
+ if t.url then
+  local u=parseurl(t.url)
+  for k,v in next,t do
+   u[k]=v
+  end
+  return u
+ else
+  return t
+ end
+end
+local function tput(putt)
+ putt=override(putt)
+ local host=putt.host
+ trysocket(host,"missing hostname")
+ local f=ftp.open(host,putt.port,putt.create)
+ f:greet()
+ f:login(putt.user,putt.password)
+ local typ=putt.type
+ if typ then
+  f:type(typ)
+ end
+ f:epsv()
+ local sent=f:send(putt)
+ f:quit()
+ f:close()
+ return sent
+end
+local default={
+ path="/",
+ scheme="ftp",
+}
+local function genericform(u)
+ local t=trysocket(parseurl(u,default))
+ trysocket(t.scheme=="ftp","wrong scheme '"..t.scheme.."'")
+ trysocket(t.host,"missing hostname")
+ local pat="^type=(.)$"
+ if t.params then
+  local typ=skipsocket(2,find(t.params,pat))
+  t.type=typ
+  trysocket(typ=="a" or typ=="i","invalid type '"..typ.."'")
+ end
+ return t
+end
+ftp.genericform=genericform
+local function sput(u,body)
+ local putt=genericform(u)
+ putt.source=sourcestring(body)
+ return tput(putt)
+end
+ftp.put=protectsocket(function(putt,body)
+ if type(putt)=="string" then
+  return sput(putt,body)
+ else
+  return tput(putt)
+ end
+end)
+local function tget(gett)
+ gett=override(gett)
+ local host=gett.host
+ trysocket(host,"missing hostname")
+ local f=ftp.open(host,gett.port,gett.create)
+ f:greet()
+ f:login(gett.user,gett.password)
+ if gett.type then
+  f:type(gett.type)
+ end
+ f:epsv()
+ f:receive(gett)
+ f:quit()
+ return f:close()
+end
+local function sget(u)
+ local gett=genericform(u)
+ local t={}
+ gett.sink=sinktable(t)
+ tget(gett)
+ return concat(t)
+end
+ftp.command=protectsocket(function(cmdt)
+ cmdt=override(cmdt)
+ local command=cmdt.command
+ local argument=cmdt.argument
+ local check=cmdt.check
+ local host=cmdt.host
+ trysocket(host,"missing hostname")
+ trysocket(command,"missing command")
+ local f=ftp.open(host,cmdt.port,cmdt.create)
+ local try=f.try
+ local tp=f.tp
+ f:greet()
+ f:login(cmdt.user,cmdt.password)
+ if type(command)=="table" then
+  local argument=argument or {}
+  for i=1,#command do
+   local cmd=command[i]
+   try(tp:command(cmd,argument[i]))
+   if check and check[i] then
+    try(tp:check(check[i]))
+   end
+  end
+ else
+  try(tp:command(command,argument))
+  if check then
+   try(tp:check(check))
+  end
+ end
+ f:quit()
+ return f:close()
+end)
+ftp.get=protectsocket(function(gett)
+ if type(gett)=="string" then
+  return sget(gett)
+ else
+  return tget(gett)
+ end
+end)
+package.loaded["socket.ftp"]=ftp
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-soc-imp-smtp"] = package.loaded["util-soc-imp-smtp"] or true
+
+-- original size: 7018, stripped down to: 5883
+
+
+local type,setmetatable,next=type,setmetatable,next
+local find,lower,format=string.find,string.lower,string.format
+local osdate,osgetenv=os.date,os.getenv
+local random=math.random
+local socket=socket   or require("socket")
+local headers=socket.headers or require("socket.headers")
+local ltn12=ltn12    or require("ltn12")
+local tp=socket.tp   or require("socket.tp")
+local mime=mime     or require("mime")
+local mimeb64=mime.b64
+local mimestuff=mime.stuff
+local skipsocket=socket.skip
+local trysocket=socket.try
+local newtrysocket=socket.newtry
+local protectsocket=socket.protect
+local normalizeheaders=headers.normalize
+local lowerheaders=headers.lower
+local createcoroutine=coroutine.create
+local resumecoroutine=coroutine.resume
+local yieldcoroutine=coroutine.resume
+local smtp={
+ TIMEOUT=60,
+ SERVER="localhost",
+ PORT=25,
+ DOMAIN=osgetenv("SERVER_NAME") or "localhost",
+ ZONE="-0000",
+}
+socket.smtp=smtp
+local methods={}
+local mt={ __index=methods }
+function methods.greet(self,domain)
+ local try=self.try
+ local tp=self.tp
+ try(tp:check("2.."))
+ try(tp:command("EHLO",domain or _M.DOMAIN))
+ return skipsocket(1,try(tp:check("2..")))
+end
+function methods.mail(self,from)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("MAIL","FROM:"..from))
+ return try(tp:check("2.."))
+end
+function methods.rcpt(self,to)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("RCPT","TO:"..to))
+ return try(tp:check("2.."))
+end
+function methods.data(self,src,step)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("DATA"))
+ try(tp:check("3.."))
+ try(tp:source(src,step))
+ try(tp:send("\r\n.\r\n"))
+ return try(tp:check("2.."))
+end
+function methods.quit(self)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("QUIT"))
+ return try(tp:check("2.."))
+end
+function methods.close(self)
+ return self.tp:close()
+end
+function methods.login(self,user,password)
+ local try=self.try
+ local tp=self.tp
+ try(tp:command("AUTH","LOGIN"))
+ try(tp:check("3.."))
+ try(tp:send(mimeb64(user).."\r\n"))
+ try(tp:check("3.."))
+ try(tp:send(mimeb64(password).."\r\n"))
+ return try(tp:check("2.."))
+end
+function methods.plain(self,user,password)
+ local try=self.try
+ local tp=self.tp
+ local auth="PLAIN "..mimeb64("\0"..user.."\0"..password)
+ try(tp:command("AUTH",auth))
+ return try(tp:check("2.."))
+end
+function methods.auth(self,user,password,ext)
+ if not user or not password then
+  return 1
+ end
+ local try=self.try
+ if find(ext,"AUTH[^\n]+LOGIN") then
+  return self:login(user,password)
+ elseif find(ext,"AUTH[^\n]+PLAIN") then
+  return self:plain(user,password)
+ else
+  try(nil,"authentication not supported")
+ end
+end
+function methods.send(self,mail)
+ self:mail(mail.from)
+ local receipt=mail.rcpt
+ if type(receipt)=="table" then
+  for i=1,#receipt do
+   self:rcpt(receipt[i])
+  end
+ elseif receipt then
+  self:rcpt(receipt)
+ end
+ self:data(ltn12.source.chain(mail.source,mimestuff()),mail.step)
+end
+local function opensmtp(self,server,port,create)
+ if not server or server=="" then
+  server=smtp.SERVER
+ end
+ if not port or port=="" then
+  port=smtp.PORT
+ end
+ local s={
+  tp=trysocket(tp.connect(server,port,smtp.TIMEOUT,create)),
+  try=newtrysocket(function()
+   s:close()
+  end),
+ }
+ setmetatable(s,mt)
+ return s
+end
+smtp.open=opensmtp
+local nofboundaries=0
+local function newboundary()
+ nofboundaries=nofboundaries+1
+ return format('%s%05d==%05u',osdate('%d%m%Y%H%M%S'),random(0,99999),nofboundaries)
+end
+local send_message
+local function send_headers(headers)
+ yieldcoroutine(normalizeheaders(headers))
+end
+local function send_multipart(message)
+ local boundary=newboundary()
+ local headers=lowerheaders(message.headers)
+ local body=message.body
+ local preamble=body.preamble
+ local epilogue=body.epilogue
+ local content=headers['content-type'] or 'multipart/mixed'
+ headers['content-type']=content..'; boundary="'..boundary..'"'
+ send_headers(headers)
+ if preamble then
+  yieldcoroutine(preamble)
+  yieldcoroutine("\r\n")
+ end
+ for i=1,#body do
+  yieldcoroutine("\r\n--"..boundary.."\r\n")
+  send_message(body[i])
+ end
+ yieldcoroutine("\r\n--"..boundary.."--\r\n\r\n")
+ if epilogue then
+  yieldcoroutine(epilogue)
+  yieldcoroutine("\r\n")
+ end
+end
+local default_content_type='text/plain; charset="UTF-8"'
+local function send_source(message)
+ local headers=lowerheaders(message.headers)
+ if not headers['content-type'] then
+  headers['content-type']=default_content_type
+ end
+ send_headers(headers)
+ local getchunk=message.body
+ while true do
+  local chunk,err=getchunk()
+  if err then
+   yieldcoroutine(nil,err)
+  elseif chunk then
+   yieldcoroutine(chunk)
+  else
+   break
+  end
+ end
+end
+local function send_string(message)
+ local headers=lowerheaders(message.headers)
+ if not headers['content-type'] then
+  headers['content-type']=default_content_type
+ end
+ send_headers(headers)
+ yieldcoroutine(message.body)
+end
+function send_message(message)
+ local body=message.body
+ if type(body)=="table" then
+  send_multipart(message)
+ elseif type(body)=="function" then
+  send_source(message)
+ else
+  send_string(message)
+ end
+end
+local function adjust_headers(message)
+ local headers=lowerheaders(message.headers)
+ if not headers["date"] then
+  headers["date"]=osdate("!%a, %d %b %Y %H:%M:%S ")..(message.zone or smtp.ZONE)
+ end
+ if not headers["x-mailer"] then
+  headers["x-mailer"]=socket._VERSION
+ end
+ headers["mime-version"]="1.0"
+ return headers
+end
+function smtp.message(message)
+ message.headers=adjust_headers(message)
+ local action=createcoroutine(function()
+  send_message(message)
+ end)
+ return function()
+  local ret,a,b=resumecoroutine(action)
+  if ret then
+   return a,b
+  else
+   return nil,a
+  end
+ end
+end
+smtp.send=protectsocket(function(mail)
+ local snd=opensmtp(smtp,mail.server,mail.port,mail.create)
+ local ext=snd:greet(mail.domain)
+ snd:auth(mail.user,mail.password,ext)
+ snd:send(mail)
+ snd:quit()
+ return snd:close()
+end)
+package.loaded["socket.smtp"]=smtp
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["trac-set"] = package.loaded["trac-set"] or true
+
+-- original size: 14568, stripped down to: 9644
+
+if not modules then modules={} end modules ['trac-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"
+}
+local type,next,tostring,tonumber=type,next,tostring,tonumber
+local print=print
+local concat,sortedhash=table.concat,table.sortedhash
+local formatters,find,lower,gsub,topattern=string.formatters,string.find,string.lower,string.gsub,string.topattern
+local is_boolean=string.is_boolean
+local settings_to_hash=utilities.parsers.settings_to_hash
+local allocate=utilities.storage.allocate
+utilities=utilities or {}
+local utilities=utilities
+local setters=utilities.setters or {}
+utilities.setters=setters
+local data={}
+local trace_initialize=false 
+local frozen=true  
+local function initialize_setter(filename,name,values) 
+ local setter=data[name]
+ if setter then
+  local data=setter.data
+  if data then
+   for key,newvalue in sortedhash(values) do
+    local newvalue=is_boolean(newvalue,newvalue,true) 
+    local functions=data[key]
+    if functions then
+     local oldvalue=functions.value
+     if functions.frozen then
+      if trace_initialize then
+       setter.report("%s: %a is %s to %a",filename,key,"frozen",oldvalue)
+      end
+     elseif #functions>0 and not oldvalue then
+      if trace_initialize then
+       setter.report("%s: %a is %s to %a",filename,key,"set",newvalue)
+      end
+      for i=1,#functions do
+       functions[i](newvalue)
+      end
+      functions.value=newvalue
+      functions.frozen=functions.frozen or frozen
+     else
+      if trace_initialize then
+       setter.report("%s: %a is %s as %a",filename,key,"kept",oldvalue)
+      end
+     end
+    else
+     functions={ default=newvalue,frozen=frozen }
+     data[key]=functions
+     if trace_initialize then
+      setter.report("%s: %a is %s to %a",filename,key,"defaulted",newvalue)
+     end
+    end
+   end
+   return true
+  end
+ end
+end
+local function set(t,what,newvalue)
+ local data=t.data 
+ if data and not data.frozen then
+  local done=t.done
+  if type(what)=="string" then
+   what=settings_to_hash(what) 
+  end
+  if type(what)~="table" then
+   return
+  end
+  if not done then 
+   done={}
+   t.done=done
+  end
+  for w,value in sortedhash(what) do
+   if value=="" then
+    value=newvalue
+   elseif not value then
+    value=false 
+   else
+    value=is_boolean(value,value,true) 
+   end
+   w=topattern(w,true,true)
+   for name,functions in sortedhash(data) do
+    if done[name] then
+    elseif find(name,w) then
+     done[name]=true
+     for i=1,#functions do
+      functions[i](value)
+     end
+     functions.value=value
+    end
+   end
+  end
+ end
+end
+local function reset(t)
+ local data=t.data
+ if data and not data.frozen then
+  for name,functions in sortedthash(data) do
+   for i=1,#functions do
+    functions[i](false)
+   end
+   functions.value=false
+  end
+ end
+end
+local function enable(t,what)
+ set(t,what,true)
+end
+local function disable(t,what)
+ local data=t.data
+ if not what or what=="" then
+  t.done={}
+  reset(t)
+ else
+  set(t,what,false)
+ end
+end
+local function register_setter(t,what,...)
+ local data=t.data
+ what=lower(what)
+ local functions=data[what]
+ if not functions then
+  functions={}
+  data[what]=functions
+  if trace_initialize then
+   t.report("defining %a",what)
+  end
+ end
+ local default=functions.default 
+ for i=1,select("#",...) do
+  local fnc=select(i,...)
+  local typ=type(fnc)
+  if typ=="string" then
+   if trace_initialize then
+    t.report("coupling %a to %a",what,fnc)
+   end
+   local s=fnc 
+   fnc=function(value) set(t,s,value) end
+  elseif typ=="table" then
+   functions.values=fnc
+   fnc=nil
+  elseif typ~="function" then
+   fnc=nil
+  end
+  if fnc then
+   functions[#functions+1]=fnc
+   local value=functions.value or default
+   if value~=nil then
+    fnc(value)
+    functions.value=value
+   end
+  end
+ end
+ return false 
+end
+local function enable_setter(t,what)
+ local e=t.enable
+ t.enable,t.done=enable,{}
+ set(t,what,true)
+ enable(t,what)
+ t.enable,t.done=e,{}
+end
+local function disable_setter(t,what)
+ local e=t.disable
+ t.disable,t.done=disable,{}
+ disable(t,what)
+ t.disable,t.done=e,{}
+end
+local function reset_setter(t)
+ t.done={}
+ reset(t)
+end
+local function list_setter(t) 
+ local list=table.sortedkeys(t.data)
+ local user,system={},{}
+ for l=1,#list do
+  local what=list[l]
+  if find(what,"^%*") then
+   system[#system+1]=what
+  else
+   user[#user+1]=what
+  end
+ end
+ return user,system
+end
+local function show_setter(t,pattern)
+ local list=list_setter(t)
+ t.report()
+ for k=1,#list do
+  local name=list[k]
+  if not pattern or find(name,pattern) then
+   local functions=t.data[name]
+   if functions then
+    local value=functions.value
+    local default=functions.default
+    local values=functions.values
+    local modules=#functions
+    if default==nil then
+     default="unset"
+    elseif type(default)=="table" then
+     default=concat(default,"|")
+    else
+     default=tostring(default)
+    end
+    if value==nil then
+     value="unset"
+    elseif type(value)=="table" then
+     value=concat(value,"|")
+    else
+     value=tostring(value)
+    end
+    t.report(name)
+    t.report("    modules : %i",modules)
+    t.report("    default : %s",default)
+    t.report("    value   : %s",value)
+   if values then
+    local v={} for i=1,#values do v[i]=tostring(values[i]) end
+    t.report("    values  : % t",v)
+   end
+    t.report()
+   end
+  end
+ end
+end
+function setters.report(setter,fmt,...)
+ if fmt then
+  print(formatters["%-15s : %s"](setter.name,formatters[fmt](...)))
+ else
+  print("")
+ end
+end
+local function setter_default(setter,name)
+ local d=setter.data[name]
+ return d and d.default
+end
+local function setter_value(setter,name)
+ local d=setter.data[name]
+ return d and (d.value or d.default)
+end
+local function setter_values(setter,name)
+ local d=setter.data[name]
+ return d and d.values
+end
+local function new_setter(name) 
+ local setter 
+ setter={
+  data=allocate(),
+  name=name,
+  report=function(...)   setters.report (setter,...) end,
+  enable=function(...)   enable_setter  (setter,...) end,
+  disable=function(...)   disable_setter (setter,...) end,
+  reset=function(...)   reset_setter   (setter,...) end,
+  register=function(...)   register_setter(setter,...) end,
+  list=function(...)  return list_setter (setter,...) end,
+  show=function(...)   show_setter (setter,...) end,
+  default=function(...)  return setter_default (setter,...) end,
+  value=function(...)  return setter_value   (setter,...) end,
+  values=function(...)  return setter_values  (setter,...) end,
+ }
+ data[name]=setter
+ return setter
+end
+setters.enable=enable_setter
+setters.disable=disable_setter
+setters.register=register_setter
+setters.list=list_setter
+setters.show=show_setter
+setters.reset=reset_setter
+setters.new=new_setter
+setters.initialize=initialize_setter
+trackers=new_setter("trackers")
+directives=new_setter("directives")
+experiments=new_setter("experiments")
+local t_enable,t_disable=trackers   .enable,trackers   .disable
+local d_enable,d_disable=directives .enable,directives .disable
+local e_enable,e_disable=experiments.enable,experiments.disable
+local trace_directives=false local trace_directives=false  trackers.register("system.directives",function(v) trace_directives=v end)
+local trace_experiments=false local trace_experiments=false  trackers.register("system.experiments",function(v) trace_experiments=v end)
+function directives.enable(...)
+ if trace_directives then
+  directives.report("enabling: % t",{...})
+ end
+ d_enable(...)
+end
+function directives.disable(...)
+ if trace_directives then
+  directives.report("disabling: % t",{...})
+ end
+ d_disable(...)
+end
+function experiments.enable(...)
+ if trace_experiments then
+  experiments.report("enabling: % t",{...})
+ end
+ e_enable(...)
+end
+function experiments.disable(...)
+ if trace_experiments then
+  experiments.report("disabling: % t",{...})
+ end
+ e_disable(...)
+end
+directives.register("system.nostatistics",function(v)
+ if statistics then
+  statistics.enable=not v
+ else
+ end
+end)
+directives.register("system.nolibraries",function(v)
+ if libraries then
+  libraries=nil 
+ else
+ end
+end)
+if environment then
+ local engineflags=environment.engineflags
+ if engineflags then
+  local list=engineflags["c:trackers"] or engineflags["trackers"]
+  if type(list)=="string" then
+   initialize_setter("commandline flags","trackers",settings_to_hash(list))
+  end
+  local list=engineflags["c:directives"] or engineflags["directives"]
+  if type(list)=="string" then
+   initialize_setter("commandline flags","directives",settings_to_hash(list))
+  end
+ end
+end
+if texconfig then
+ local function set(k,v)
+  local v=tonumber(v)
+  if v then
+   texconfig[k]=v
+  end
+ end
+ directives.register("luatex.expanddepth",function(v) set("expand_depth",v)   end)
+ directives.register("luatex.hashextra",function(v) set("hash_extra",v)  end)
+ directives.register("luatex.nestsize",function(v) set("nest_size",v)   end)
+ directives.register("luatex.maxinopen",function(v) set("max_in_open",v) end)
+ directives.register("luatex.maxprintline",function(v) set("max_print_line",v) end)
+ directives.register("luatex.maxstrings",function(v) set("max_strings",v) end)
+ directives.register("luatex.paramsize",function(v) set("param_size",v)  end)
+ directives.register("luatex.savesize",function(v) set("save_size",v)   end)
+ directives.register("luatex.stacksize",function(v) set("stack_size",v)  end)
+end
+local data=table.setmetatableindex("table")
+updaters={
+ register=function(what,f)
+  local d=data[what]
+  d[#d+1]=f
+ end,
+ apply=function(what,...)
+  local d=data[what]
+  for i=1,#d do
+   d[i](...)
+  end
+ end,
+}
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["trac-log"] = package.loaded["trac-log"] or true
+
+-- original size: 16017, stripped down to: 11045
+
+if not modules then modules={} end modules ['trac-log']={
+ version=1.001,
+ comment="companion to trac-log.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local next,type,select,print=next,type,select,print
+local format,gmatch,find=string.format,string.gmatch,string.find
+local concat,insert,remove=table.concat,table.insert,table.remove
+local topattern=string.topattern
+local utfchar=utf.char
+local datetime=os.date
+local openfile=io.open
+local write_nl=print
+local write=io.write
+local setmetatableindex=table.setmetatableindex
+local formatters=string.formatters
+local settings_to_hash=utilities.parsers.settings_to_hash
+local sortedkeys=table.sortedkeys
+local variant="default"
+logs=logs or {}
+local logs=logs
+local moreinfo=[[
+More information about ConTeXt and the tools that come with it can be found at:
+]].."\n"..[[
+maillist : ntg-context at ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
+webpage  : http://www.pragma-ade.nl / http://tex.aanhet.net
+wiki     : http://contextgarden.net
+]]
+formatters.add (
+ formatters,"unichr",
+ [["U+" .. format("%%05X",%s) .. " (" .. utfchar(%s) .. ")"]]
+)
+formatters.add (
+ formatters,"chruni",
+ [[utfchar(%s) .. " (U+" .. format("%%05X",%s) .. ")"]]
+)
+local function ignore() end
+setmetatableindex(logs,function(t,k) t[k]=ignore;return ignore end)
+local report,subreport,status,settarget,setformats,settranslations
+local direct,subdirect,writer,pushtarget,poptarget,setlogfile,settimedlog,setprocessor,setformatters,newline
+local function ansisupported(specification)
+ if specification~="ansi" and specification~="ansilog" then
+  return false
+ elseif os and os.enableansi then
+  return os.enableansi()
+ else
+  return false
+ end
+end
+do
+ local report_yes,subreport_yes,status_yes
+ local report_nop,subreport_nop,status_nop
+ local variants={
+  default={
+   formats={
+    report_yes=formatters["%-15s | %s"],
+    report_nop=formatters["%-15s |"],
+    subreport_yes=formatters["%-15s | %s | %s"],
+    subreport_nop=formatters["%-15s | %s |"],
+    status_yes=formatters["%-15s : %s\n"],
+    status_nop=formatters["%-15s :\n"],
+   },
+  },
+  ansi={
+   formats={
+    report_yes=formatters["%-15s | %s"],
+    report_nop=formatters["%-15s |"],
+    subreport_yes=formatters["%-15s | %s | %s"],
+    subreport_nop=formatters["%-15s | %s |"],
+    status_yes=formatters["%-15s : %s\n"],
+    status_nop=formatters["%-15s :\n"],
+   },
+  },
+ }
+ logs.flush=ignore
+ writer=function(s)
+  write_nl(s)
+ end
+ newline=function()
+  write_nl("\n")
+ end
+ report=function(a,b,c,...)
+  if c then
+   write_nl(report_yes(a,formatters[b](c,...)))
+  elseif b then
+   write_nl(report_yes(a,b))
+  elseif a then
+   write_nl(report_nop(a))
+  else
+   write_nl("")
+  end
+ end
+ subreport=function(a,sub,b,c,...)
+  if c then
+   write_nl(subreport_yes(a,sub,formatters[b](c,...)))
+  elseif b then
+   write_nl(subreport_yes(a,sub,b))
+  elseif a then
+   write_nl(subreport_nop(a,sub))
+  else
+   write_nl("")
+  end
+ end
+ status=function(a,b,c,...) 
+  if c then
+   write_nl(status_yes(a,formatters[b](c,...)))
+  elseif b then
+   write_nl(status_yes(a,b)) 
+  elseif a then
+   write_nl(status_nop(a))
+  else
+   write_nl("\n")
+  end
+ end
+ direct=ignore
+ subdirect=ignore
+ settarget=ignore
+ pushtarget=ignore
+ poptarget=ignore
+ setformats=ignore
+ settranslations=ignore
+ setprocessor=function(f)
+  local writeline=write_nl
+  write_nl=function(s)
+   writeline(f(s))
+  end
+ end
+ setformatters=function(specification)
+  local f=nil
+  local d=variants.default
+  if specification then
+   if type(specification)=="table" then
+    f=specification.formats or specification
+   else
+    if not ansisupported(specification) then
+     specification="default"
+    end
+    local v=variants[specification]
+    if v then
+     f=v.formats
+    end
+   end
+  end
+  if f then
+   d=d.formats
+  else
+   f=d.formats
+   d=f
+  end
+  setmetatableindex(f,d)
+  report_yes=f.report_yes
+  report_nop=f.report_nop
+  subreport_yes=f.subreport_yes
+  subreport_nop=f.subreport_nop
+  status_yes=f.status_yes
+  status_nop=f.status_nop
+ end
+ setformatters(variant)
+ setlogfile=function(name,keepopen)
+  if name and name~="" then
+   local localtime=os.localtime
+   local writeline=write_nl
+   if keepopen then
+    local f=io.open(name,"ab")
+    write_nl=function(s)
+     writeline(s)
+     f:write(localtime()," | ",s,"\n")
+    end
+   else
+    write_nl=function(s)
+     writeline(s)
+     local f=io.open(name,"ab")
+     f:write(localtime()," | ",s,"\n")
+     f:close()
+    end
+   end
+  end
+  setlogfile=ignore
+ end
+ settimedlog=function()
+  local localtime=os.localtime
+  local writeline=write_nl
+  write_nl=function(s)
+   writeline(localtime().." | "..s)
+  end
+  settimedlog=ignore
+ end
+end
+logs.report=report
+logs.subreport=subreport
+logs.status=status
+logs.settarget=settarget
+logs.pushtarget=pushtarget
+logs.poptarget=poptarget
+logs.setformats=setformats
+logs.settranslations=settranslations
+logs.setlogfile=setlogfile
+logs.settimedlog=settimedlog
+logs.setprocessor=setprocessor
+logs.setformatters=setformatters
+logs.direct=direct
+logs.subdirect=subdirect
+logs.writer=writer
+logs.newline=newline
+local data={}
+local states=nil
+local force=false
+function logs.reporter(category,subcategory)
+ local logger=data[category]
+ if not logger then
+  local state=states==true
+  if not state and type(states)=="table" then
+   for c,_ in next,states do
+    if find(category,c) then
+     state=true
+     break
+    end
+   end
+  end
+  logger={
+   reporters={},
+   state=state,
+  }
+  data[category]=logger
+ end
+ local reporter=logger.reporters[subcategory or "default"]
+ if not reporter then
+  if subcategory then
+   reporter=function(...)
+    if force or not logger.state then
+     subreport(category,subcategory,...)
+    end
+   end
+   logger.reporters[subcategory]=reporter
+  else
+   local tag=category
+   reporter=function(...)
+    if force or not logger.state then
+     report(category,...)
+    end
+   end
+   logger.reporters.default=reporter
+  end
+ end
+ return reporter
+end
+logs.new=logs.reporter
+local ctxreport=logs.writer
+function logs.setmessenger(m)
+ ctxreport=m
+end
+function logs.messenger(category,subcategory)
+ if subcategory then
+  return function(...)
+   ctxreport(subdirect(category,subcategory,...))
+  end
+ else
+  return function(...)
+   ctxreport(direct(category,...))
+  end
+ end
+end
+local function setblocked(category,value) 
+ if category==true or category=="all" then
+  category,value="*",true
+ elseif category==false then
+  category,value="*",false
+ elseif value==nil then
+  value=true
+ end
+ if category=="*" then
+  states=value
+  for k,v in next,data do
+   v.state=value
+  end
+ else
+  alllocked=false
+  states=settings_to_hash(category,type(states)=="table" and states or nil)
+  for c in next,states do
+   local v=data[c]
+   if v then
+    v.state=value
+   else
+    c=topattern(c,true,true)
+    for k,v in next,data do
+     if find(k,c) then
+      v.state=value
+     end
+    end
+   end
+  end
+ end
+end
+function logs.disable(category,value)
+ setblocked(category,value==nil and true or value)
+end
+function logs.enable(category)
+ setblocked(category,false)
+end
+function logs.categories()
+ return sortedkeys(data)
+end
+function logs.show()
+ local n,c,s,max=0,0,0,0
+ for category,v in table.sortedpairs(data) do
+  n=n+1
+  local state=v.state
+  local reporters=v.reporters
+  local nc=#category
+  if nc>c then
+   c=nc
+  end
+  for subcategory,_ in next,reporters do
+   local ns=#subcategory
+   if ns>c then
+    s=ns
+   end
+   local m=nc+ns
+   if m>max then
+    max=m
+   end
+  end
+  local subcategories=concat(sortedkeys(reporters),", ")
+  if state==true then
+   state="disabled"
+  elseif state==false then
+   state="enabled"
+  else
+   state="unknown"
+  end
+  report("logging","category %a, subcategories %a, state %a",category,subcategories,state)
+ end
+ report("logging","categories: %s, max category: %s, max subcategory: %s, max combined: %s",n,c,s,max)
+end
+local delayed_reporters={}
+setmetatableindex(delayed_reporters,function(t,k)
+ local v=logs.reporter(k.name)
+ t[k]=v
+ return v
+end)
+function utilities.setters.report(setter,...)
+ delayed_reporters[setter](...)
+end
+directives.register("logs.blocked",function(v)
+ setblocked(v,true)
+end)
+directives.register("logs.target",function(v)
+ settarget(v)
+end)
+local nesting=0
+local verbose=false
+local hasscheme=url.hasscheme
+local simple=logs.reporter("comment")
+logs.simple=simple
+logs.simpleline=simple
+logs.setprogram=ignore 
+logs.extendbanner=ignore 
+logs.reportlines=ignore 
+logs.reportbanner=ignore 
+logs.reportline=ignore 
+logs.simplelines=ignore 
+logs.help=ignore
+local Carg,C,lpegmatch=lpeg.Carg,lpeg.C,lpeg.match
+local p_newline=lpeg.patterns.newline
+local linewise=(
+ Carg(1)*C((1-p_newline)^1)/function(t,s) t.report(s) end+Carg(1)*p_newline^2/function(t)   t.report()  end+p_newline
+)^1
+local function reportlines(t,str)
+ if str then
+  lpegmatch(linewise,str,1,t)
+ end
+end
+local function reportbanner(t)
+ local banner=t.banner
+ if banner then
+  t.report(banner)
+  t.report()
+ end
+end
+local function reportversion(t)
+ local banner=t.banner
+ if banner then
+  t.report(banner)
+ end
+end
+local function reporthelp(t,...)
+ local helpinfo=t.helpinfo
+ if type(helpinfo)=="string" then
+  reportlines(t,helpinfo)
+ elseif type(helpinfo)=="table" then
+  for i=1,select("#",...) do
+   reportlines(t,t.helpinfo[select(i,...)])
+   if i<n then
+    t.report()
+   end
+  end
+ end
+end
+local function reportinfo(t)
+ t.report()
+ reportlines(t,t.moreinfo)
+end
+local function reportexport(t,method)
+ report(t.helpinfo)
+end
+local reporters={
+ lines=reportlines,
+ banner=reportbanner,
+ version=reportversion,
+ help=reporthelp,
+ info=reportinfo,
+ export=reportexport,
+}
+local exporters={
+}
+logs.reporters=reporters
+logs.exporters=exporters
+function logs.application(t)
+ local arguments=environment and environment.arguments
+ if arguments then
+  local ansi=arguments.ansi or arguments.ansilog
+  if ansi then
+   logs.setformatters(arguments.ansi and "ansi" or "ansilog")
+  end
+ end
+ t.name=t.name   or "unknown"
+ t.banner=t.banner
+ t.moreinfo=moreinfo
+ t.report=logs.reporter(t.name)
+ t.help=function(...)
+  reporters.banner(t)
+  reporters.help(t,...)
+  reporters.info(t)
+ end
+ t.export=function(...)
+  reporters.export(t,...)
+ end
+ t.identify=function()
+  reporters.banner(t)
+ end
+ t.version=function()
+  reporters.version(t)
+ end
+ return t
+end
+local f_syslog=formatters["%s %s => %s => %s => %s\r"]
+function logs.system(whereto,process,jobname,category,fmt,arg,...)
+ local message=f_syslog(datetime("%d/%m/%y %H:%m:%S"),process,jobname,category,arg==nil and fmt or format(fmt,arg,...))
+ for i=1,10 do
+  local f=openfile(whereto,"a") 
+  if f then
+   f:write(message)
+   f:close()
+   break
+  else
+   sleep(0.1)
+  end
+ end
+end
+local report_system=logs.reporter("system","logs")
+if utilities then
+ utilities.report=report_system
+end
+if package.helpers.report then
+ package.helpers.report=logs.reporter("package loader") 
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["trac-inf"] = package.loaded["trac-inf"] or true
+
+-- original size: 9740, stripped down to: 7296
+
+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,offset=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,offset=0 }
+end
+local ticks=clock
+local seconds=function(n) return n or 0 end
+if os.type~="windows" then
+elseif lua.getpreciseticks then
+ ticks=lua.getpreciseticks
+ seconds=lua.getpreciseseconds
+elseif FFISUPPORTED then
+ local okay,kernel=pcall(ffi.load,"kernel32")
+ if kernel then
+  local tonumber=ffi.number or tonumber
+  ffi.cdef[[
+            int QueryPerformanceFrequency(int64_t *lpFrequency);
+            int QueryPerformanceCounter(int64_t *lpPerformanceCount);
+        ]]
+  local target=ffi.new("__int64[1]")
+  ticks=function()
+   if kernel.QueryPerformanceCounter(target)==1 then
+    return tonumber(target[0])
+   else
+    return 0
+   end
+  end
+  local target=ffi.new("__int64[1]")
+  seconds=function(ticks)
+   if kernel.QueryPerformanceFrequency(target)==1 then
+    return ticks/tonumber(target[0])
+   else
+    return 0
+   end
+  end
+ end
+else
+end
+local function starttiming(instance,reset)
+ local timer=timers[instance or "notimer"]
+ local it=timer.timing
+ if reset then
+  it=0
+  timer.loadtime=0
+ end
+ if it==0 then
+  timer.starttime=ticks()
+  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 and starttime>0 then
+   local stoptime=ticks()
+   local loadtime=stoptime-starttime
+   timer.stoptime=stoptime
+   timer.loadtime=timer.loadtime+loadtime
+   timer.timing=0
+   timer.starttime=0
+  end
+ end
+end
+local function benchmarktimer(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 and starttime>0 then
+   timer.offset=ticks()-starttime
+  else
+   timer.offset=0
+  end
+ end
+end
+local function elapsed(instance)
+ if type(instance)=="number" then
+  return instance
+ else
+  local timer=timers[instance or "notimer"]
+  return timer and seconds(timer.loadtime-2*(timer.offset or 0)) or 0
+ end
+end
+local function currenttime(instance)
+ if type(instance)=="number" then
+  return instance
+ else
+  local timer=timers[instance or "notimer"]
+  local it=timer.timing
+  if it>1 then
+  else
+   local starttime=timer.starttime
+   if starttime and starttime>0 then
+    return seconds(timer.loadtime+ticks()-starttime-2*(timer.offset or 0))
+   end
+  end
+  return 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.currenttime=currenttime
+statistics.elapsed=elapsed
+statistics.elapsedtime=elapsedtime
+statistics.elapsedindeed=elapsedindeed
+statistics.elapsedseconds=elapsedseconds
+statistics.benchmarktimer=benchmarktimer
+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("used engine",function()
+   return format("%s version: %s, functionality level: %s, banner: %s",
+    LUATEXENGINE,LUATEXVERSION,LUATEXFUNCTIONALITY,lower(status.banner))
+  end)
+  register("used hash slots",function()
+   return format("%s of %s + %s",status.cs_count,status.hash_size,status.hash_extra)
+  end)
+  register("callbacks",statistics.callbacks)
+  if JITSUPPORTED then
+   local jitstatus=jit.status
+   if jitstatus then
+    local jitstatus={ jitstatus() }
+    if jitstatus[1] then
+     register("luajit options",concat(jitstatus," ",2))
+    end
+   end
+  end
+  register("lua properties",function()
+   local hash=2^status.luatex_hashchars
+   local mask=load([[τεχ = 1]]) and "utf" or "ascii"
+   return format("engine: %s %s, used memory: %s, hash chars: min(%i,40), symbol mask: %s (%s)",
+    jit and "luajit" or "lua",LUAVERSION,statistics.memused(),hash,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, max: %s MB",
+  round(collectgarbage("count")/1000),
+  round(status.luastate_bytes/1000000),
+  status.luastate_bytes_max and round(status.luastate_bytes_max/1000000) or "unknown"
+ )
+end
+starttiming(statistics)
+function statistics.formatruntime(runtime) 
+ return format("%s seconds",runtime)   
+end
+function statistics.runtime()
+ stoptiming(statistics)
+ local runtime=lua.getruntime and lua.getruntime() or elapsedtime(statistics)
+ return statistics.formatruntime(runtime)
+end
+local report=logs.reporter("system")
+function statistics.timed(action,all)
+ starttiming("run")
+ action()
+ stoptiming("run")
+ local runtime=tonumber(elapsedtime("run"))
+ if all then
+  local alltime=tonumber(lua.getruntime and lua.getruntime() or elapsedtime(statistics))
+  if alltime and alltime>0 then
+   report("total runtime: %0.3f seconds of %0.3f seconds",runtime,alltime)
+   return
+  end
+ end
+ report("total runtime: %0.3f seconds",runtime)
+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
+function status.getreadstate()
+ return {
+  filename=status.filename   or "?",
+  linenumber=status.linenumber or 0,
+  iocode=status.inputid or 0,
+ }
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["trac-pro"] = package.loaded["trac-pro"] or true
+
+-- original size: 5841, stripped down to: 3352
+
+if not modules then modules={} end modules ['trac-pro']={
+ 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 getmetatable,setmetatable,rawset,type,next=getmetatable,setmetatable,rawset,type,next
+local trace_namespaces=false  trackers.register("system.namespaces",function(v) trace_namespaces=v end)
+local report_system=logs.reporter("system","protection")
+namespaces=namespaces or {}
+local namespaces=namespaces
+local registered={}
+local function report_index(k,name)
+ if trace_namespaces then
+  report_system("reference to %a in protected namespace %a: %s",k,name)
+  debugger.showtraceback(report_system)
+ else
+  report_system("reference to %a in protected namespace %a",k,name)
+ end
+end
+local function report_newindex(k,name)
+ if trace_namespaces then
+  report_system("assignment to %a in protected namespace %a: %s",k,name)
+  debugger.showtraceback(report_system)
+ else
+  report_system("assignment to %a in protected namespace %a",k,name)
+ end
+end
+local function register(name)
+ local data=name=="global" and _G or _G[name]
+ if not data then
+  return 
+ end
+ registered[name]=data
+ local m=getmetatable(data)
+ if not m then
+  m={}
+  setmetatable(data,m)
+ end
+ local index,newindex={},{}
+ m.__saved__index=m.__index
+ m.__no__index=function(t,k)
+  if not index[k] then
+   index[k]=true
+   report_index(k,name)
+  end
+  return nil
+ end
+ m.__saved__newindex=m.__newindex
+ m.__no__newindex=function(t,k,v)
+  if not newindex[k] then
+   newindex[k]=true
+   report_newindex(k,name)
+  end
+  rawset(t,k,v)
+ end
+ m.__protection__depth=0
+end
+local function private(name) 
+ local data=registered[name]
+ if not data then
+  data=_G[name]
+  if not data then
+   data={}
+   _G[name]=data
+  end
+  register(name)
+ end
+ return data
+end
+local function protect(name)
+ local data=registered[name]
+ if not data then
+  return
+ end
+ local m=getmetatable(data)
+ local pd=m.__protection__depth
+ if pd>0 then
+  m.__protection__depth=pd+1
+ else
+  m.__save_d_index,m.__saved__newindex=m.__index,m.__newindex
+  m.__index,m.__newindex=m.__no__index,m.__no__newindex
+  m.__protection__depth=1
+ end
+end
+local function unprotect(name)
+ local data=registered[name]
+ if not data then
+  return
+ end
+ local m=getmetatable(data)
+ local pd=m.__protection__depth
+ if pd>1 then
+  m.__protection__depth=pd-1
+ else
+  m.__index,m.__newindex=m.__saved__index,m.__saved__newindex
+  m.__protection__depth=0
+ end
+end
+local function protectall()
+ for name,_ in next,registered do
+  if name~="global" then
+   protect(name)
+  end
+ end
+end
+local function unprotectall()
+ for name,_ in next,registered do
+  if name~="global" then
+   unprotect(name)
+  end
+ end
+end
+namespaces.register=register  
+namespaces.private=private   
+namespaces.protect=protect
+namespaces.unprotect=unprotect
+namespaces.protectall=protectall
+namespaces.unprotectall=unprotectall
+namespaces.private("namespaces") registered={} register("global") 
+directives.register("system.protect",function(v)
+ if v then
+  protectall()
+ else
+  unprotectall()
+ end
+end)
+directives.register("system.checkglobals",function(v)
+ if v then
+  report_system("enabling global namespace guard")
+  protect("global")
+ else
+  report_system("disabling global namespace guard")
+  unprotect("global")
+ end
+end)
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-lua"] = package.loaded["util-lua"] or true
+
+-- original size: 7149, stripped down to: 4997
+
+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,collectgarbage=load,loadfile,type,collectgarbage
+utilities=utilities or {}
+utilities.lua=utilities.lua or {}
+local luautilities=utilities.lua
+local report_lua=logs.reporter("system","lua")
+local report_mem=logs.reporter("system","lua memory")
+local tracestripping=false
+local tracememory=false
+luautilities.stripcode=true  
+luautilities.alwaysstripcode=false 
+luautilities.nofstrippedchunks=0
+luautilities.nofstrippedbytes=0
+local strippedchunks={} 
+luautilities.strippedchunks=strippedchunks
+if not LUATEXENGINE then
+ LUATEXENGINE=status.luatex_engine and string.lower(status.luatex_engine)
+ JITSUPPORTED=LUATEXENGINE=="luajittex" or jit
+ CONTEXTLMTXMODE=CONTEXTLMTXMODE or (LUATEXENGINE=="luametatex" and 1) or 0
+end
+luautilities.suffixes={
+ tma="tma",
+ tmc=(CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 and "tmd") or (jit and "tmb") or "tmc",
+ lua="lua",
+ luc=(CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 and "lud") or (jit and "lub") or "luc",
+ lui="lui",
+ luv="luv",
+ luj="luj",
+ tua="tua",
+ tuc=(CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 and "tud") or (jit and "tub") or "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,macros)
+ name=name or fullname
+ if macros then
+  macros=lua.macros
+ end
+ local code,message
+ if macros then
+  code,message=macros.loaded(fullname,true,false)
+ 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")
+  code,message=loadfile(fullname)
+ 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,name,forcestrip) 
+ 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.loadstring(code,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
+ return code,0
+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
+local finalizers={}
+setmetatable(finalizers,{
+ __gc=function(t)
+  for i=1,#t do
+   pcall(t[i]) 
+  end
+ end
+} )
+function luautilities.registerfinalizer(f)
+ finalizers[#finalizers+1]=f
+end
+function luautilities.checkmemory(previous,threshold,trace) 
+ local current=collectgarbage("count")
+ if previous then
+  local checked=(threshold or 64)*1024
+  local delta=current-previous
+  if current-previous>checked then
+   collectgarbage("collect")
+   local afterwards=collectgarbage("count")
+   if trace or tracememory then
+    report_mem("previous %r MB, current %r MB, delta %r MB, threshold %r MB, afterwards %r MB",
+     previous/1024,current/1024,delta/1024,threshold,afterwards)
+   end
+   return afterwards
+  elseif trace or tracememory then
+   report_mem("previous %r MB, current %r MB, delta %r MB, threshold %r MB",
+    previous/1024,current/1024,delta/1024,threshold)
+  end
+ end
+ return current
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-deb"] = package.loaded["util-deb"] or true
+
+-- original size: 10593, stripped down to: 7102
+
+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 type,next,tostring,tonumber=type,next,tostring,tonumber
+local format,find,sub,gsub=string.format,string.find,string.sub,string.gsub
+local insert,remove,sort=table.insert,table.remove,table.sort
+local setmetatableindex=table.setmetatableindex
+utilities=utilities or {}
+local debugger=utilities.debugger or {}
+utilities.debugger=debugger
+local report=logs.reporter("debugger")
+local ticks=os.gettimeofday or os.clock
+local seconds=function(n) return n or 0 end
+local overhead=0
+local dummycalls=10*1000
+local nesting=0
+local names={}
+local initialize=false
+if lua.getpreciseticks then
+ initialize=function()
+  ticks=lua.getpreciseticks
+  seconds=lua.getpreciseseconds
+  initialize=false
+ end
+elseif not (FFISUPPORTED and ffi) then
+elseif os.type=="windows" then
+ initialize=function()
+  local kernel=ffilib("kernel32","system") 
+  if kernel then
+   local tonumber=ffi.number or tonumber
+   ffi.cdef[[
+                int QueryPerformanceFrequency(int64_t *lpFrequency);
+                int QueryPerformanceCounter(int64_t *lpPerformanceCount);
+            ]]
+   local target=ffi.new("__int64[1]")
+   ticks=function()
+    if kernel.QueryPerformanceCounter(target)==1 then
+     return tonumber(target[0])
+    else
+     return 0
+    end
+   end
+   local target=ffi.new("__int64[1]")
+   seconds=function(ticks)
+    if kernel.QueryPerformanceFrequency(target)==1 then
+     return ticks/tonumber(target[0])
+    else
+     return 0
+    end
+   end
+  end
+  initialize=false
+ end
+elseif os.type=="unix" then
+ initialize=function()
+  local C=ffi.C
+  local tonumber=ffi.number or tonumber
+  ffi.cdef [[
+            /* what a mess */
+            typedef int clk_id_t;
+            typedef enum { CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID } clk_id;
+            typedef struct timespec { long sec; long nsec; } ctx_timespec;
+            int clock_gettime(clk_id_t timerid, struct timespec *t);
+        ]]
+  local target=ffi.new("ctx_timespec[?]",1)
+  local clock=C.CLOCK_PROCESS_CPUTIME_ID
+  ticks=function ()
+   C.clock_gettime(clock,target)
+   return tonumber(target[0].sec*1000000000+target[0].nsec)
+  end
+  seconds=function(ticks)
+   return ticks/1000000000
+  end
+  initialize=false
+ end
+end
+setmetatableindex(names,function(t,name)
+ local v=setmetatableindex(function(t,source)
+  local v=setmetatableindex(function(t,line)
+   local v={ total=0,count=0,nesting=0 }
+   t[line]=v
+   return v
+  end)
+  t[source]=v
+  return v
+ end)
+ t[name]=v
+ return v
+end)
+local getinfo=nil
+local sethook=nil
+local function hook(where)
+ local f=getinfo(2,"nSl")
+ if f then
+  local source=f.short_src
+  if not source then
+   return
+  end
+  local line=f.linedefined or 0
+  local name=f.name
+  if not name then
+   local what=f.what
+   if what=="C" then
+    name="<anonymous>"
+   else
+    name=f.namewhat or what or "<unknown>"
+   end
+  end
+  local data=names[name][source][line]
+  if where=="call" then
+   local nesting=data.nesting
+   if nesting==0 then
+    data.count=data.count+1
+    insert(data,ticks())
+    data.nesting=1
+   else
+    data.nesting=nesting+1
+   end
+  elseif where=="return" then
+   local nesting=data.nesting
+   if nesting==1 then
+    local t=remove(data)
+    if t then
+     data.total=data.total+ticks()-t
+    end
+    data.nesting=0
+   else
+    data.nesting=nesting-1
+   end
+  end
+ end
+end
+function debugger.showstats(printer,threshold)
+ local printer=printer or report
+ local calls=0
+ local functions=0
+ local dataset={}
+ local length=0
+ local realtime=0
+ local totaltime=0
+ local threshold=threshold or 0
+ for name,sources in next,names do
+  for source,lines in next,sources do
+   for line,data in next,lines do
+    local count=data.count
+    if count>threshold then
+     if #name>length then
+      length=#name
+     end
+     local total=data.total
+     local real=total
+     if real>0 then
+      real=total-(count*overhead/dummycalls)
+      if real<0 then
+       real=0
+      end
+      realtime=realtime+real
+     end
+     totaltime=totaltime+total
+     if line<0 then
+      line=0
+     end
+     dataset[#dataset+1]={ real,total,count,name,source,line }
+    end
+   end
+  end
+ end
+ sort(dataset,function(a,b)
+  if a[1]==b[1] then
+   if a[2]==b[2] then
+    if a[3]==b[3] then
+     if a[4]==b[4] then
+      if a[5]==b[5] then
+       return a[6]<b[6]
+      else
+       return a[5]<b[5]
+      end
+     else
+      return a[4]<b[4]
+     end
+    else
+     return b[3]<a[3]
+    end
+   else
+    return b[2]<a[2]
+   end
+  else
+   return b[1]<a[1]
+  end
+ end)
+ if length>50 then
+  length=50
+ end
+ local fmt=string.formatters["%4.9k s  %3.3k %%  %4.9k s  %3.3k %%  %8i #  %-"..length.."s  %4i  %s"]
+ for i=1,#dataset do
+  local data=dataset[i]
+  local real=data[1]
+  local total=data[2]
+  local count=data[3]
+  local name=data[4]
+  local source=data[5]
+  local line=data[6]
+  calls=calls+count
+  functions=functions+1
+  name=gsub(name,"%s+"," ")
+  if #name>length then
+   name=sub(name,1,length)
+  end
+  printer(fmt(seconds(total),100*total/totaltime,seconds(real),100*real/realtime,count,name,line,source))
+ end
+ printer("")
+ printer(format("functions : %i",functions))
+ printer(format("calls     : %i",calls))
+ printer(format("overhead  : %f",seconds(overhead/1000)))
+end
+local function getdebug()
+ if sethook and getinfo then
+  return
+ end
+ if not debug then
+  local okay
+  okay,debug=pcall(require,"debug")
+ end
+ if type(debug)~="table" then
+  return
+ end
+ getinfo=debug.getinfo
+ sethook=debug.sethook
+ if type(getinfo)~="function" then
+  getinfo=nil
+ end
+ if type(sethook)~="function" then
+  sethook=nil
+ end
+end
+function debugger.savestats(filename,threshold)
+ local f=io.open(filename,'w')
+ if f then
+  debugger.showstats(function(str) f:write(str,"\n") end,threshold)
+  f:close()
+ end
+end
+function debugger.enable()
+ getdebug()
+ if sethook and getinfo and nesting==0 then
+  running=true
+  if initialize then
+   initialize()
+  end
+  sethook(hook,"cr")
+  local function dummy() end
+  local t=ticks()
+  for i=1,dummycalls do
+   dummy()
+  end
+  overhead=ticks()-t
+ end
+ if nesting>0 then
+  nesting=nesting+1
+ end
+end
+function debugger.disable()
+ if nesting>0 then
+  nesting=nesting-1
+ end
+ if sethook and getinfo and nesting==0 then
+  sethook()
+ end
+end
+local function showtraceback(rep) 
+ getdebug()
+ if getinfo then
+  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
+end
+debugger.showtraceback=showtraceback
+if luac then
+ local show,dump=luac.print,string.dump
+ function luac.inspect(v)
+  if type(v)=="function" then
+   local ok,str=xpcall(dump,function() end,v)
+   if ok then
+    v=str
+   end
+  end
+  if type(v)=="string" then
+   show(v,true)
+  else
+   print(v)
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-tpl"] = package.loaded["util-tpl"] or true
+
+-- original size: 7722, stripped down to: 4212
+
+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,next=tostring,next
+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 formatters=string.formatters
+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 function replaceformatted(l,m,r,t,how,recurse)
+ local v=t[r]
+ return v and formatters[l](v)
+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 nolformatted=P(":")/"%%"
+local norformatted=P(":")/""
+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 formatted=nosingle*((Cs(nolformatted*(1-norformatted )^1)*norformatted*C((1-nosingle)^1)*args)/replaceformatted)*nosingle
+local any=P(1)
+   replacer=Cs((unquoted+quoted+formatted+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 -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-sbx"] = package.loaded["util-sbx"] or true
+
+-- original size: 21145, stripped down to: 13271
+
+if not modules then modules={} end modules ['util-sbx']={
+ 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"
+}
+if not sandbox then require("l-sandbox") end 
+local next,type=next,type
+local replace=utilities.templates.replace
+local collapsepath=file.collapsepath
+local expandname=dir.expandname
+local sortedhash=table.sortedhash
+local lpegmatch=lpeg.match
+local platform=os.type
+local P,S,C=lpeg.P,lpeg.S,lpeg.C
+local gsub=string.gsub
+local lower=string.lower
+local find=string.find
+local concat=string.concat
+local unquoted=string.unquoted
+local optionalquoted=string.optionalquoted
+local basename=file.basename
+local nameonly=file.nameonly
+local sandbox=sandbox
+local validroots={}
+local validrunners={}
+local validbinaries=true 
+local validlibraries=true 
+local validators={}
+local finalized=nil
+local trace=false
+local p_validroot=nil
+local p_split=lpeg.firstofsplit(" ")
+local report=logs.reporter("sandbox")
+trackers.register("sandbox",function(v) trace=v end) 
+sandbox.setreporter(report)
+sandbox.finalizer {
+ category="files",
+ action=function()
+  finalized=true
+ end
+}
+local function registerroot(root,what) 
+ if finalized then
+  report("roots are already finalized")
+ else
+  if type(root)=="table" then
+   root,what=root[1],root[2]
+  end
+  if type(root)=="string" and root~="" then
+   root=collapsepath(expandname(root))
+   if what=="r" or what=="ro" or what=="readable" then
+    what="read"
+   elseif what=="w" or what=="wo" or what=="writable" then
+    what="write"
+   end
+   validroots[root]=what=="write" or false
+  end
+ end
+end
+sandbox.finalizer {
+ category="files",
+ action=function() 
+  if p_validroot then
+   report("roots are already initialized")
+  else
+   sandbox.registerroot(".","write")
+   for name in sortedhash(validroots) do
+    if p_validroot then
+     p_validroot=P(name)+p_validroot
+    else
+     p_validroot=P(name)
+    end
+   end
+   p_validroot=p_validroot/validroots
+  end
+ end
+}
+local function registerbinary(name)
+ if finalized then
+  report("binaries are already finalized")
+ elseif type(name)=="string" and name~="" then
+  if not validbinaries then
+   return
+  end
+  if validbinaries==true then
+   validbinaries={ [name]=true }
+  else
+   validbinaries[name]=true
+  end
+ elseif name==true then
+  validbinaries={}
+ end
+end
+local function registerlibrary(name)
+ if finalized then
+  report("libraries are already finalized")
+ elseif type(name)=="string" and name~="" then
+  if not validlibraries then
+   return
+  end
+  if validlibraries==true then
+   validlibraries={ [nameonly(name)]=true }
+  else
+   validlibraries[nameonly(name)]=true
+  end
+ elseif name==true then
+  validlibraries={}
+ end
+end
+local p_write=S("wa")    p_write=(1-p_write)^0*p_write
+local p_path=S("\\/~$%:")  p_path=(1-p_path )^0*p_path  
+local function normalized(name) 
+ if platform=="windows" then
+  name=gsub(name,"/","\\")
+ end
+ return name
+end
+function sandbox.possiblepath(name)
+ return lpegmatch(p_path,name) and true or false
+end
+local filenamelogger=false
+function sandbox.setfilenamelogger(l)
+ filenamelogger=type(l)=="function" and l or false
+end
+local function validfilename(name,what)
+ if p_validroot and type(name)=="string" and lpegmatch(p_path,name) then
+  local asked=collapsepath(expandname(name))
+  local okay=lpegmatch(p_validroot,asked)
+  if okay==true then
+   if filenamelogger then
+    filenamelogger(name,"w",asked,true)
+   end
+   return name
+  elseif okay==false then
+   if not what then
+    if filenamelogger then
+     filenamelogger(name,"r",asked,true)
+    end
+    return name
+   elseif lpegmatch(p_write,what) then
+    if filenamelogger then
+     filenamelogger(name,"w",asked,false)
+    end
+    return 
+   else
+    if filenamelogger then
+     filenamelogger(name,"r",asked,true)
+    end
+    return name
+   end
+  elseif filenamelogger then
+   filenamelogger(name,"*",name,false)
+  end
+ else
+  return name
+ end
+end
+local function readable(name,finalized)
+ return validfilename(name,"r")
+end
+local function normalizedreadable(name,finalized)
+ local valid=validfilename(name,"r")
+ if valid then
+  return normalized(valid)
+ end
+end
+local function writeable(name,finalized)
+ return validfilename(name,"w")
+end
+local function normalizedwriteable(name,finalized)
+ local valid=validfilename(name,"w")
+ if valid then
+  return normalized(valid)
+ end
+end
+validators.readable=readable
+validators.writeable=normalizedwriteable
+validators.normalizedreadable=normalizedreadable
+validators.normalizedwriteable=writeable
+validators.filename=readable
+table.setmetatableindex(validators,function(t,k)
+ if k then
+  t[k]=readable
+ end
+ return readable
+end)
+function validators.string(s,finalized)
+ if finalized and suspicious(s) then
+  return ""
+ else
+  return s
+ end
+end
+function validators.cache(s)
+ if finalized then
+  return basename(s)
+ else
+  return s
+ end
+end
+function validators.url(s)
+ if finalized and find("^file:") then
+  return ""
+ else
+  return s
+ end
+end
+local function filehandlerone(action,one,...)
+ local checkedone=validfilename(one)
+ if checkedone then
+  return action(one,...)
+ else
+ end
+end
+local function filehandlertwo(action,one,two,...)
+ local checkedone=validfilename(one)
+ if checkedone then
+  local checkedtwo=validfilename(two)
+  if checkedtwo then
+   return action(one,two,...)
+  else
+  end
+ else
+ end
+end
+local function iohandler(action,one,...)
+ if type(one)=="string" then
+  local checkedone=validfilename(one)
+  if checkedone then
+   return action(one,...)
+  end
+ elseif one then
+  return action(one,...)
+ else
+  return action()
+ end
+end
+local osexecute=sandbox.original(os.execute)
+local iopopen=sandbox.original(io.popen)
+local reported={}
+local function validcommand(name,program,template,checkers,defaults,variables,reporter,strict)
+ if validbinaries~=false and (validbinaries==true or validbinaries[program]) then
+  local binpath=nil
+  if variables then
+   for variable,value in next,variables do
+    local chktype=checkers[variable]
+    if chktype=="verbose" then
+    else
+     local checker=validators[chktype]
+     if checker and type(value)=="string" then
+      value=checker(unquoted(value),strict)
+      if value then
+       variables[variable]=optionalquoted(value)
+      else
+       report("variable %a with value %a fails the check",variable,value)
+       return
+      end
+     else
+      report("variable %a has no checker",variable)
+      return
+     end
+    end
+   end
+   for variable,default in next,defaults do
+    local value=variables[variable]
+    if not value or value=="" then
+     local chktype=checkers[variable]
+     if chktype=="verbose" then
+     elseif type(default)=="string" then
+      local checker=validators[chktype]
+      if checker then
+       default=checker(unquoted(default),strict)
+       if default then
+        variables[variable]=optionalquoted(default)
+       else
+        report("variable %a with default %a fails the check",variable,default)
+        return
+       end
+      end
+     end
+    end
+   end
+   binpath=variables.binarypath
+  end
+  if type(binpath)=="string" and binpath~="" then
+   program=binpath.."/"..program
+  end
+  local command=program.." "..replace(template,variables)
+  if reporter then
+   reporter("executing runner %a: %s",name,command)
+  elseif trace then
+   report("executing runner %a: %s",name,command)
+  end
+  return command
+ elseif not reported[name] then
+  report("executing program %a of runner %a is not permitted",program,name)
+  reported[name]=true
+ end
+end
+local runners={
+ resultof=function(...)
+  local command=validcommand(...)
+  if command then
+   if trace then
+    report("resultof: %s",command)
+   end
+   local handle=iopopen(command,"r") 
+   if handle then
+    local result=handle:read("*all") or ""
+    handle:close()
+    return result
+   end
+  end
+ end,
+ execute=function(...)
+  local command=validcommand(...)
+  if command then
+   if trace then
+    report("execute: %s",command)
+   end
+   local okay=osexecute(command)
+   return okay
+  end
+ end,
+ pipeto=function(...)
+  local command=validcommand(...)
+  if command then
+   if trace then
+    report("pipeto: %s",command)
+   end
+   return iopopen(command,"w") 
+  end
+ end,
+}
+function sandbox.registerrunner(specification)
+ if type(specification)=="string" then
+  local wrapped=validrunners[specification]
+  inspect(table.sortedkeys(validrunners))
+  if wrapped then
+   return wrapped
+  else
+   report("unknown predefined runner %a",specification)
+   return
+  end
+ end
+ if type(specification)~="table" then
+  report("specification should be a table (or string)")
+  return
+ end
+ local name=specification.name
+ if type(name)~="string" then
+  report("invalid name, string expected",name)
+  return
+ end
+ if validrunners[name] then
+  report("invalid name, runner %a already defined",name)
+  return
+ end
+ local program=specification.program
+ if type(program)=="string" then
+ elseif type(program)=="table" then
+  program=program[platform] or program.default or program.unix
+ end
+ if type(program)~="string" or program=="" then
+  report("invalid runner %a specified for platform %a",name,platform)
+  return
+ end
+ local template=specification.template
+ if not template then
+  report("missing template for runner %a",name)
+  return
+ end
+ local method=specification.method   or "execute"
+ local checkers=specification.checkers or {}
+ local defaults=specification.defaults or {}
+ local runner=runners[method]
+ if runner then
+  local finalized=finalized 
+  local wrapped=function(variables)
+   return runner(name,program,template,checkers,defaults,variables,specification.reporter,finalized)
+  end
+  validrunners[name]=wrapped
+  return wrapped
+ else
+  validrunners[name]=nil
+  report("invalid method for runner %a",name)
+ end
+end
+function sandbox.getrunner(name)
+ return name and validrunners[name]
+end
+local function suspicious(str)
+ return (find(str,"[/\\]") or find(command,"..",1,true)) and true or false
+end
+local function binaryrunner(action,command,...)
+ if validbinaries==false then
+  report("no binaries permitted, ignoring command: %s",command)
+  return
+ end
+ if type(command)~="string" then
+  report("command should be a string")
+  return
+ end
+ local program=lpegmatch(p_split,command)
+ if not program or program=="" then
+  report("unable to filter binary from command: %s",command)
+  return
+ end
+ if validbinaries==true then
+ elseif not validbinaries[program] then
+  report("binary not permitted, ignoring command: %s",command)
+  return
+ elseif suspicious(command) then
+  report("/ \\ or .. found, ignoring command (use sandbox.registerrunner): %s",command)
+  return
+ end
+ return action(command,...)
+end
+local function dummyrunner(action,command,...)
+ if type(command)=="table" then
+  command=concat(command," ",command[0] and 0 or 1)
+ end
+ report("ignoring command: %s",command)
+end
+sandbox.filehandlerone=filehandlerone
+sandbox.filehandlertwo=filehandlertwo
+sandbox.iohandler=iohandler
+function sandbox.disablerunners()
+ validbinaries=false
+end
+function sandbox.disablelibraries()
+ validlibraries=false
+end
+if FFISUPPORTED and ffi then
+ function sandbox.disablelibraries()
+  validlibraries=false
+  for k,v in next,ffi do
+   if k~="gc" then
+    ffi[k]=nil
+   end
+  end
+ end
+ local fiiload=ffi.load
+ if fiiload then
+  local reported={}
+  function ffi.load(name,...)
+   if validlibraries==false then
+   elseif validlibraries==true then
+    return fiiload(name,...)
+   elseif validlibraries[nameonly(name)] then
+    return fiiload(name,...)
+   else
+   end
+   if not reported[name] then
+    report("using library %a is not permitted",name)
+    reported[name]=true
+   end
+   return nil
+  end
+ end
+end
+local overload=sandbox.overload
+local register=sandbox.register
+ overload(loadfile,filehandlerone,"loadfile") 
+if io then
+ overload(io.open,filehandlerone,"io.open")
+ overload(io.popen,binaryrunner,"io.popen")
+ overload(io.input,iohandler,"io.input")
+ overload(io.output,iohandler,"io.output")
+ overload(io.lines,filehandlerone,"io.lines")
+end
+if os then
+ overload(os.execute,binaryrunner,"os.execute")
+ overload(os.spawn,dummyrunner,"os.spawn") 
+ overload(os.exec,dummyrunner,"os.exec")  
+ overload(os.resultof,binaryrunner,"os.resultof")
+ overload(os.pipeto,binaryrunner,"os.pipeto")
+ overload(os.rename,filehandlertwo,"os.rename")
+ overload(os.remove,filehandlerone,"os.remove")
+end
+if lfs then
+ overload(lfs.chdir,filehandlerone,"lfs.chdir")
+ overload(lfs.mkdir,filehandlerone,"lfs.mkdir")
+ overload(lfs.rmdir,filehandlerone,"lfs.rmdir")
+ overload(lfs.isfile,filehandlerone,"lfs.isfile")
+ overload(lfs.isdir,filehandlerone,"lfs.isdir")
+ overload(lfs.attributes,filehandlerone,"lfs.attributes")
+ overload(lfs.dir,filehandlerone,"lfs.dir")
+ overload(lfs.lock_dir,filehandlerone,"lfs.lock_dir")
+ overload(lfs.touch,filehandlerone,"lfs.touch")
+ overload(lfs.link,filehandlertwo,"lfs.link")
+ overload(lfs.setmode,filehandlerone,"lfs.setmode")
+ overload(lfs.readlink,filehandlerone,"lfs.readlink")
+ overload(lfs.shortname,filehandlerone,"lfs.shortname")
+ overload(lfs.symlinkattributes,filehandlerone,"lfs.symlinkattributes")
+end
+if zip then
+ zip.open=register(zip.open,filehandlerone,"zip.open")
+end
+sandbox.registerroot=registerroot
+sandbox.registerbinary=registerbinary
+sandbox.registerlibrary=registerlibrary
+sandbox.validfilename=validfilename
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-mrg"] = package.loaded["util-mrg"] or true
+
+-- original size: 7819, stripped down to: 5881
+
+if not modules then modules={} end modules ['util-mrg']={
+ 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 gsub,format=string.gsub,string.format
+local concat=table.concat
+local type,next=type,next
+local P,R,S,V,Ct,C,Cs,Cc,Cp,Cmt,Cb,Cg=lpeg.P,lpeg.R,lpeg.S,lpeg.V,lpeg.Ct,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Cp,lpeg.Cmt,lpeg.Cb,lpeg.Cg
+local lpegmatch,patterns=lpeg.match,lpeg.patterns
+utilities=utilities or {}
+local merger=utilities.merger or {}
+utilities.merger=merger
+merger.strip_comment=true
+local report=logs.reporter("system","merge")
+utilities.report=report
+local m_begin_merge="begin library merge"
+local m_end_merge="end library merge"
+local m_begin_closure="do -- create closure to overcome 200 locals limit"
+local m_end_closure="end -- of closure"
+local m_pattern="%c+".."%-%-%s+"..m_begin_merge.."%c+(.-)%c+".."%-%-%s+"..m_end_merge.."%c+"
+local m_format="\n\n-- "..m_begin_merge.."\n%s\n".."-- "..m_end_merge.."\n\n"
+local m_faked="-- ".."created merged file".."\n\n".."-- "..m_begin_merge.."\n\n".."-- "..m_end_merge.."\n\n"
+local m_report=[[
+-- used libraries    : %s
+-- skipped libraries : %s
+-- original bytes    : %s
+-- stripped bytes    : %s
+]]
+local m_preloaded=[[package.loaded[%q] = package.loaded[%q] or true]]
+local function self_fake()
+ return m_faked
+end
+local function self_nothing()
+ return ""
+end
+local function self_load(name)
+ local data=io.loaddata(name) or ""
+ if data=="" then
+  report("unknown file %a",name)
+ else
+  report("inserting file %a",name)
+ end
+ return data or ""
+end
+local space=patterns.space
+local eol=patterns.newline
+local equals=P("=")^0
+local open=P("[")*Cg(equals,"init")*P("[")*P("\n")^-1
+local close=P("]")*C(equals)*P("]")
+local closeeq=Cmt(close*Cb("init"),function(s,i,a,b) return a==b end)
+local longstring=open*(1-closeeq)^0*close
+local quoted=patterns.quoted
+local digit=patterns.digit
+local emptyline=space^0*eol
+local operator1=P("<=")+P(">=")+P("~=")+P("..")+S("/^<>=*+%%")
+local operator2=S("*+/")
+local operator3=S("-")
+local operator4=P("..")
+local separator=S(",;")
+local ignore=(P("]")*space^1*P("=")*space^1*P("]"))/"]=["+(P("=")*space^1*P("{"))/"={"+(P("(")*space^1)/"("+(P("{")*(space+eol)^1*P("}"))/"{}"
+local strings=quoted 
+local longcmt=(emptyline^0*P("--")*longstring*emptyline^0)/""
+local longstr=longstring
+local comment=emptyline^0*P("--")*P("-")^0*(1-eol)^0*emptyline^1/"\n"
+local optionalspaces=space^0/""
+local mandatespaces=space^1/""
+local optionalspacing=(eol+space)^0/""
+local mandatespacing=(eol+space)^1/""
+local pack=digit*space^1*operator4*optionalspacing+optionalspacing*operator1*optionalspacing+optionalspacing*operator2*optionalspaces+mandatespacing*operator3*mandatespaces+optionalspaces*separator*optionalspaces
+local lines=emptyline^2/"\n"
+local spaces=(space*space)/" "
+local spaces=(space*space*space*space)/" "
+local compact=Cs ((
+ ignore+strings+longcmt+longstr+comment+pack+lines+spaces+1
+)^1 )
+local strip=Cs((emptyline^2/"\n"+1)^0)
+local stripreturn=Cs((1-P("return")*space^1*P(1-space-eol)^1*(space+eol)^0*P(-1))^1)
+function merger.compact(data)
+ return lpegmatch(strip,lpegmatch(compact,data))
+end
+local function self_compact(data)
+ local delta=0
+ if merger.strip_comment then
+  local before=#data
+  data=lpegmatch(compact,data)
+  data=lpegmatch(strip,data)
+  local after=#data
+  delta=before-after
+  report("original size %s, compacted to %s, stripped %s",before,after,delta)
+  data=format("-- original size: %s, stripped down to: %s\n\n%s",before,after,data)
+ end
+ return lpegmatch(stripreturn,data) or data,delta
+end
+local function self_save(name,data)
+ if data~="" then
+  io.savedata(name,data)
+  report("saving %s with size %s",name,#data)
+ end
+end
+local function self_swap(data,code)
+ return data~="" and (gsub(data,m_pattern,function() return format(m_format,code) end,1)) or ""
+end
+local function self_libs(libs,list)
+ local result,f,frozen,foundpath={},nil,false,nil
+ result[#result+1]="\n"
+ if type(libs)=='string' then libs={ libs } end
+ if type(list)=='string' then list={ list } end
+ for i=1,#libs do
+  local lib=libs[i]
+  for j=1,#list do
+   local pth=gsub(list[j],"\\","/") 
+   report("checking library path %a",pth)
+   local name=pth.."/"..lib
+   if lfs.isfile(name) then
+    foundpath=pth
+   end
+  end
+  if foundpath then break end
+ end
+ if foundpath then
+  report("using library path %a",foundpath)
+  local right,wrong,original,stripped={},{},0,0
+  for i=1,#libs do
+   local lib=libs[i]
+   local fullname=foundpath.."/"..lib
+   if lfs.isfile(fullname) then
+    report("using library %a",fullname)
+    local preloaded=file.nameonly(lib)
+    local data=io.loaddata(fullname,true)
+    original=original+#data
+    local data,delta=self_compact(data)
+    right[#right+1]=lib
+    result[#result+1]=m_begin_closure
+    result[#result+1]=format(m_preloaded,preloaded,preloaded)
+    result[#result+1]=data
+    result[#result+1]=m_end_closure
+    stripped=stripped+delta
+   else
+    report("skipping library %a",fullname)
+    wrong[#wrong+1]=lib
+   end
+  end
+  right=#right>0 and concat(right," ") or "-"
+  wrong=#wrong>0 and concat(wrong," ") or "-"
+  report("used libraries: %a",right)
+  report("skipped libraries: %a",wrong)
+  report("original bytes: %a",original)
+  report("stripped bytes: %a",stripped)
+  result[#result+1]=format(m_report,right,wrong,original,stripped)
+ else
+  report("no valid library path found")
+ end
+ return concat(result,"\n\n")
+end
+function merger.selfcreate(libs,list,target)
+ if target then
+  self_save(target,self_swap(self_fake(),self_libs(libs,list)))
+ end
+end
+function merger.selfmerge(name,libs,list,target)
+ self_save(target or name,self_swap(self_load(name),self_libs(libs,list)))
+end
+function merger.selfclean(name)
+ self_save(name,self_swap(self_load(name),self_nothing()))
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-env"] = package.loaded["util-env"] or true
+
+-- original size: 9738, stripped down to: 5531
+
+if not modules then modules={} end modules ['util-env']={
+ 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 allocate,mark=utilities.storage.allocate,utilities.storage.mark
+local format,sub,match,gsub,find=string.format,string.sub,string.match,string.gsub,string.find
+local unquoted,quoted,optionalquoted=string.unquoted,string.quoted,string.optionalquoted
+local concat,insert,remove=table.concat,table.insert,table.remove
+environment=environment or {}
+local environment=environment
+local setlocale=os.setlocale
+setlocale(nil,nil)
+local report=logs.reporter("system")
+function os.setlocale(a,b)
+ if a or b then
+  if report then
+   report()
+   report("You're messing with os.locale in a supposedly locale neutral enviroment. From")
+   report("now on are on your own and without support. Crashes or unexpected side effects")
+   report("can happen but don't bother the luatex and context developer team with it.")
+   report()
+   report=nil
+  end
+  setlocale(a,b)
+ end
+end
+local validengines=allocate {
+ ["luatex"]=true,
+ ["luajittex"]=true,
+}
+local basicengines=allocate {
+ ["luatex"]="luatex",
+ ["texlua"]="luatex",
+ ["texluac"]="luatex",
+ ["luajittex"]="luajittex",
+ ["texluajit"]="luajittex",
+}
+local luaengines=allocate {
+ ["lua"]=true,
+ ["luajit"]=true,
+}
+environment.validengines=validengines
+environment.basicengines=basicengines
+if not arg then
+ environment.used_as_library=true
+elseif luaengines[file.removesuffix(arg[-1])] then
+elseif validengines[file.removesuffix(arg[0])] then
+ if arg[1]=="--luaonly" then
+  arg[-1]=arg[0]
+  arg[ 0]=arg[2]
+  for k=3,#arg do
+   arg[k-2]=arg[k]
+  end
+  remove(arg) 
+  remove(arg) 
+ else
+ end
+ local originalzero=file.basename(arg[0])
+ local specialmapping={ luatools=="base" }
+ if originalzero~="mtxrun" and originalzero~="mtxrun.lua" then
+    arg[0]=specialmapping[originalzero] or originalzero
+    insert(arg,0,"--script")
+    insert(arg,0,"mtxrun")
+ end
+end
+environment.arguments=allocate()
+environment.files=allocate()
+environment.sortedflags=nil
+function environment.initializearguments(arg)
+ local arguments={}
+ local files={}
+ environment.arguments=arguments
+ environment.files=files
+ environment.sortedflags=nil
+ for index=1,#arg do
+  local argument=arg[index]
+  if index>0 then
+   local flag,value=match(argument,"^%-+(.-)=(.-)$")
+   if flag then
+    flag=gsub(flag,"^c:","")
+    arguments[flag]=unquoted(value or "")
+   else
+    flag=match(argument,"^%-+(.+)")
+    if flag then
+     flag=gsub(flag,"^c:","")
+     arguments[flag]=true
+    else
+     files[#files+1]=argument
+    end
+   end
+  end
+ end
+ if not environment.ownname then
+  if os.selfpath and os.selfname then
+   environment.ownname=file.addsuffix(file.join(os.selfpath,os.selfname),"lua")
+  end
+ end
+ environment.ownname=file.reslash(environment.ownname or arg[0] or 'unknown.lua')
+end
+function environment.setargument(name,value)
+ environment.arguments[name]=value
+end
+function environment.getargument(name,partial)
+ local arguments,sortedflags=environment.arguments,environment.sortedflags
+ if arguments[name] then
+  return arguments[name]
+ elseif partial then
+  if not sortedflags then
+   sortedflags=allocate(table.sortedkeys(arguments))
+   for k=1,#sortedflags do
+    sortedflags[k]="^"..sortedflags[k]
+   end
+   environment.sortedflags=sortedflags
+  end
+  for k=1,#sortedflags do
+   local v=sortedflags[k]
+   if find(name,v) then
+    return arguments[sub(v,2,#v)]
+   end
+  end
+ end
+ return nil
+end
+environment.argument=environment.getargument
+function environment.splitarguments(separator) 
+ local done,before,after=false,{},{}
+ local originalarguments=environment.originalarguments
+ for k=1,#originalarguments do
+  local v=originalarguments[k]
+  if not done and v==separator then
+   done=true
+  elseif done then
+   after[#after+1]=v
+  else
+   before[#before+1]=v
+  end
+ end
+ return before,after
+end
+function environment.reconstructcommandline(arg,noquote)
+ local resolveprefix=resolvers.resolve 
+ arg=arg or environment.originalarguments
+ if noquote and #arg==1 then
+  return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1])
+ elseif #arg>0 then
+  local result={}
+  for i=1,#arg do
+   result[i]=optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix)
+  end
+  return concat(result," ")
+ else
+  return ""
+ end
+end
+function environment.relativepath(path,root)
+ if not path then
+  path=""
+ end
+ if not file.is_rootbased_path(path) then
+  if not root then
+   root=file.pathpart(environment.ownscript or environment.ownname or ".")
+  end
+  if root=="" then
+   root="."
+  end
+  path=root.."/"..path
+ end
+ return file.collapsepath(path,true)
+end
+if arg then
+ local newarg,instring={},false
+ for index=1,#arg do
+  local argument=arg[index]
+  if find(argument,"^\"") then
+   if find(argument,"\"$") then
+    newarg[#newarg+1]=gsub(argument,"^\"(.-)\"$","%1")
+    instring=false
+   else
+    newarg[#newarg+1]=gsub(argument,"^\"","")
+    instring=true
+   end
+  elseif find(argument,"\"$") then
+   if instring then
+    newarg[#newarg]=newarg[#newarg].." "..gsub(argument,"\"$","")
+    instring=false
+   else
+    newarg[#newarg+1]=argument
+   end
+  elseif instring then
+   newarg[#newarg]=newarg[#newarg].." "..argument
+  else
+   newarg[#newarg+1]=argument
+  end
+ end
+ for i=1,-5,-1 do
+  newarg[i]=arg[i]
+ end
+ environment.initializearguments(newarg)
+ environment.originalarguments=mark(newarg)
+ environment.rawarguments=mark(arg)
+ arg={} 
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["luat-env"] = package.loaded["luat-env"] or true
+
+-- original size: 6267, stripped down to: 4115
+
+ if not modules then modules={} end modules ['luat-env']={
+ 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 rawset,loadfile=rawset,loadfile
+local gsub=string.gsub
+local trace_locating=false  trackers.register("resolvers.locating",function(v) trace_locating=v end)
+local report_lua=logs.reporter("resolvers","lua")
+local luautilities=utilities.lua
+local luasuffixes=luautilities.suffixes
+local texgettoks=tex and tex.gettoks
+environment=environment or {}
+local environment=environment
+local mt={
+ __index=function(_,k)
+  if k=="version" then
+   local version=texgettoks and texgettoks("contextversiontoks")
+   if version and version~="" then
+    rawset(environment,"version",version)
+    return version
+   else
+    return "unknown"
+   end
+  elseif k=="jobname" or k=="formatname" then
+   local name=tex and tex[k]
+   if name or name=="" then
+    rawset(environment,k,name)
+    return name
+   else
+    return "unknown"
+   end
+  elseif k=="outputfilename" then
+   local name=environment.jobname
+   rawset(environment,k,name)
+   return name
+  end
+ end
+}
+setmetatable(environment,mt)
+function environment.texfile(filename)
+ return resolvers.findfile(filename,'tex')
+end
+function environment.luafile(filename) 
+ if CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 and file.suffix(filename)=="lua" then
+  local resolved=resolvers.findfile(file.replacesuffix(filename,"lmt")) or ""
+  if resolved~="" then
+   return resolved
+  end
+ end
+ local resolved=resolvers.findfile(filename,'tex') or ""
+ if resolved~="" then
+  return resolved
+ end
+ resolved=resolvers.findfile(filename,'texmfscripts') or ""
+ if resolved~="" then
+  return resolved
+ end
+ return resolvers.findfile(filename,'luatexlibs') or ""
+end
+local stripindeed=false  directives.register("system.compile.strip",function(v) stripindeed=v end)
+local function strippable(filename)
+ if stripindeed then
+  local modu=modules[file.nameonly(filename)]
+  return modu and modu.dataonly
+ else
+  return false
+ end
+end
+function environment.luafilechunk(filename,silent,macros) 
+ filename=file.replacesuffix(filename,"lua")
+ local fullname=environment.luafile(filename)
+ if fullname and fullname~="" then
+  local data=luautilities.loadedluacode(fullname,strippable,filename,macros)
+  if not silent then
+   report_lua("loading file %a %s",fullname,not data and "failed" or "succeeded")
+  end
+  return data
+ else
+  if not silent then
+   report_lua("unknown file %a",filename)
+  end
+  return nil
+ end
+end
+function environment.loadluafile(filename,version)
+ local lucname,luaname,chunk
+ local basename=file.removesuffix(filename)
+ if basename==filename then
+  luaname=file.addsuffix(basename,luasuffixes.lua)
+  lucname=file.addsuffix(basename,luasuffixes.luc)
+ else
+  luaname=filename 
+  lucname=nil
+ end
+ local fullname=(lucname and environment.luafile(lucname)) or ""
+ if fullname~="" then
+  if trace_locating then
+   report_lua("loading %a",fullname)
+  end
+  chunk=loadfile(fullname) 
+ end
+ if chunk then
+  chunk()
+  if version then
+   local v=version 
+   if modules and modules[filename] then
+    v=modules[filename].version 
+   elseif versions and versions[filename] then
+    v=versions[filename]  
+   end
+   if v==version then
+    return true
+   else
+    if trace_locating then
+     report_lua("version mismatch for %a, lua version %a, luc version %a",filename,v,version)
+    end
+    environment.loadluafile(filename)
+   end
+  else
+   return true
+  end
+ end
+ fullname=(luaname and environment.luafile(luaname)) or ""
+ if fullname~="" then
+  if trace_locating then
+   report_lua("loading %a",fullname)
+  end
+  chunk=loadfile(fullname) 
+  if not chunk then
+   if trace_locating then
+    report_lua("unknown file %a",filename)
+   end
+  else
+   chunk()
+   return true
+  end
+ end
+ return false
+end
+environment.filenames=setmetatable({},{
+ __index=function(t,k)
+  local v=environment.files[k]
+  if v then
+   return (gsub(v,"%.+$",""))
+  end
+ end,
+ __newindex=function(t,k)
+ end,
+ __len=function(t)
+  return #environment.files
+ end,
+} )
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["util-zip"] = package.loaded["util-zip"] or true
+
+-- original size: 23730, stripped down to: 14293
+
+if not modules then modules={} end modules ['util-zip']={
+ version=1.001,
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local type,tostring,tonumber=type,tostring,tonumber
+local sort,concat=table.sort,table.concat
+local find,format,sub,gsub=string.find,string.format,string.sub,string.gsub
+local osdate,ostime,osclock=os.date,os.time,os.clock
+local ioopen=io.open
+local loaddata,savedata=io.loaddata,io.savedata
+local filejoin,isdir,dirname,mkdirs=file.join,lfs.isdir,file.dirname,dir.mkdirs
+local suffix,suffixes=file.suffix,file.suffixes
+local openfile=io.open
+gzip=gzip or {} 
+if not zlib then
+ zlib=xzip 
+elseif not xzip then
+ xzip=zlib
+end
+local files=utilities.files
+local openfile=files.open
+local closefile=files.close
+local readstring=files.readstring
+local readcardinal2=files.readcardinal2le
+local readcardinal4=files.readcardinal4le
+local setposition=files.setposition
+local getposition=files.getposition
+local band=bit32.band
+local rshift=bit32.rshift
+local lshift=bit32.lshift
+local zlibdecompress=zlib.decompress
+local zlibdecompresssize=zlib.decompresssize
+local zlibchecksum=zlib.crc32
+if not CONTEXTLMTXMODE or CONTEXTLMTXMODE==0 then
+ local cs=zlibchecksum
+ zlibchecksum=function(str,n) return cs(n or 0,str) end
+end
+local decompress=function(source)   return zlibdecompress (source,-15)   end 
+local decompresssize=function(source,targetsize) return zlibdecompresssize(source,targetsize,-15) end 
+local calculatecrc=function(buffer,initial) return zlibchecksum   (initial or 0,buffer)   end
+local zipfiles={}
+utilities.zipfiles=zipfiles
+local openzipfile,closezipfile,unzipfile,foundzipfile,getziphash,getziplist  do
+ function openzipfile(name)
+  return {
+   name=name,
+   handle=openfile(name,0),
+  }
+ end
+ local function collect(z)
+  if not z.list then
+   local list={}
+   local hash={}
+   local position=0
+   local index=0
+   local handle=z.handle
+   while true do
+    setposition(handle,position)
+    local signature=readstring(handle,4)
+    if signature=="PK\3\4" then
+     local version=readcardinal2(handle)
+     local flag=readcardinal2(handle)
+     local method=readcardinal2(handle)
+     local filetime=readcardinal2(handle)
+     local filedate=readcardinal2(handle)
+     local crc32=readcardinal4(handle)
+     local compressed=readcardinal4(handle)
+     local uncompressed=readcardinal4(handle)
+     local namelength=readcardinal2(handle)
+     local extralength=readcardinal2(handle)
+     local filename=readstring(handle,namelength)
+     local descriptor=band(flag,8)~=0
+     local encrypted=band(flag,1)~=0
+     local acceptable=method==0 or method==8
+     local skipped=0
+     local size=0
+     if encrypted then
+      size=readcardinal2(handle)
+      skipbytes(size)
+      skipped=skipped+size+2
+      skipbytes(8)
+      skipped=skipped+8
+      size=readcardinal2(handle)
+      skipbytes(size)
+      skipped=skipped+size+2
+      size=readcardinal4(handle)
+      skipbytes(size)
+      skipped=skipped+size+4
+      size=readcardinal2(handle)
+      skipbytes(size)
+      skipped=skipped+size+2
+     end
+     position=position+30+namelength+extralength+skipped
+     if descriptor then
+      setposition(handle,position+compressed)
+      crc32=readcardinal4(handle)
+      compressed=readcardinal4(handle)
+      uncompressed=readcardinal4(handle)
+     end
+     if acceptable then
+      index=index+1
+      local data={
+       filename=filename,
+       index=index,
+       position=position,
+       method=method,
+       compressed=compressed,
+       uncompressed=uncompressed,
+       crc32=crc32,
+       encrypted=encrypted,
+      }
+      hash[filename]=data
+      list[index]=data
+     else
+     end
+     position=position+compressed
+    else
+     break
+    end
+    z.list=list
+    z.hash=hash
+   end
+  end
+ end
+ function getziplist(z)
+  local list=z.list
+  if not list then
+   collect(z)
+  end
+  return z.list
+ end
+ function getziphash(z)
+  local hash=z.hash
+  if not hash then
+   collect(z)
+  end
+  return z.hash
+ end
+ function foundzipfile(z,name)
+  return getziphash(z)[name]
+ end
+ function closezipfile(z)
+  local f=z.handle
+  if f then
+   closefile(f)
+   z.handle=nil
+  end
+ end
+ function unzipfile(z,filename,check)
+  local hash=z.hash
+  if not hash then
+   hash=zipfiles.hash(z)
+  end
+  local data=hash[filename] 
+  if not data then
+  end
+  if data then
+   local handle=z.handle
+   local position=data.position
+   local compressed=data.compressed
+   if compressed>0 then
+    setposition(handle,position)
+    local result=readstring(handle,compressed)
+    if data.method==8 then
+     if decompresssize then
+      result=decompresssize(result,data.uncompressed)
+     else
+      result=decompress(result)
+     end
+    end
+    if check and data.crc32~=calculatecrc(result) then
+     print("checksum mismatch")
+     return ""
+    end
+    return result
+   else
+    return ""
+   end
+  end
+ end
+ zipfiles.open=openzipfile
+ zipfiles.close=closezipfile
+ zipfiles.unzip=unzipfile
+ zipfiles.hash=getziphash
+ zipfiles.list=getziplist
+ zipfiles.found=foundzipfile
+end
+if xzip then 
+ local writecardinal1=files.writebyte
+ local writecardinal2=files.writecardinal2le
+ local writecardinal4=files.writecardinal4le
+ local logwriter=logs.writer
+ local globpattern=dir.globpattern
+ local compress=xzip.compress
+ local checksum=xzip.crc32
+ local function fromdostime(dostime,dosdate)
+  return ostime {
+   year=rshift(dosdate,9)+1980,
+   month=band(rshift(dosdate,5),0x0F),
+   day=band((dosdate   ),0x1F),
+   hour=band(rshift(dostime,11)    ),
+   min=band(rshift(dostime,5),0x3F),
+   sec=band((dostime   ),0x1F),
+  }
+ end
+ local function todostime(time)
+  local t=osdate("*t",time)
+  return
+   lshift(t.year-1980,9)+lshift(t.month,5)+t.day,
+   lshift(t.hour,11)+lshift(t.min,5)+rshift(t.sec,1)
+ end
+ local function openzip(filename,level,comment,verbose)
+  local f=ioopen(filename,"wb")
+  if f then
+   return {
+    filename=filename,
+    handle=f,
+    list={},
+    level=tonumber(level) or 3,
+    comment=tostring(comment),
+    verbose=verbose,
+    uncompressed=0,
+    compressed=0,
+   }
+  end
+ end
+ local function writezip(z,name,data,level,time)
+  local f=z.handle
+  local list=z.list
+  local level=tonumber(level) or z.level or 3
+  local method=8
+  local zipped=compress(data,level)
+  local checksum=checksum(data)
+  local verbose=z.verbose
+  if not zipped then
+   method=0
+   zipped=data
+  end
+  local start=f:seek()
+  local compressed=#zipped
+  local uncompressed=#data
+  z.compressed=z.compressed+compressed
+  z.uncompressed=z.uncompressed+uncompressed
+  if verbose then
+   local pct=100*compressed/uncompressed
+   if pct>=100 then
+    logwriter(format("%10i        %s",uncompressed,name))
+   else
+    logwriter(format("%10i  %02.1f  %s",uncompressed,pct,name))
+   end
+  end
+  f:write("\x50\x4b\x03\x04")
+  writecardinal2(f,0)   
+  writecardinal2(f,0)   
+  writecardinal2(f,method)    
+  writecardinal2(f,0)   
+  writecardinal2(f,0)   
+  writecardinal4(f,checksum)  
+  writecardinal4(f,compressed)   
+  writecardinal4(f,uncompressed) 
+  writecardinal2(f,#name)  
+  writecardinal2(f,0)
+  f:write(name)      
+  f:write(zipped)
+  list[#list+1]={ #zipped,#data,name,checksum,start,time or 0 }
+ end
+ local function closezip(z)
+  local f=z.handle
+  local list=z.list
+  local comment=z.comment
+  local verbose=z.verbose
+  local count=#list
+  local start=f:seek()
+  for i=1,count do
+   local l=list[i]
+   local compressed=l[1]
+   local uncompressed=l[2]
+   local name=l[3]
+   local checksum=l[4]
+   local start=l[5]
+   local time=l[6]
+   local date,time=todostime(time)
+   f:write('\x50\x4b\x01\x02')
+   writecardinal2(f,0)   
+   writecardinal2(f,0)   
+   writecardinal2(f,0)   
+   writecardinal2(f,8)   
+   writecardinal2(f,time)   
+   writecardinal2(f,date)   
+   writecardinal4(f,checksum)  
+   writecardinal4(f,compressed)   
+   writecardinal4(f,uncompressed) 
+   writecardinal2(f,#name)  
+   writecardinal2(f,0)   
+   writecardinal2(f,0)   
+   writecardinal2(f,0)   
+   writecardinal2(f,0)   
+   writecardinal4(f,0)   
+   writecardinal4(f,start)  
+   f:write(name)      
+  end
+  local stop=f:seek()
+  local size=stop-start
+  f:write('\x50\x4b\x05\x06')
+  writecardinal2(f,0)   
+  writecardinal2(f,0)   
+  writecardinal2(f,count)  
+  writecardinal2(f,count)  
+  writecardinal4(f,size)   
+  writecardinal4(f,start)  
+  if type(comment)=="string" and comment~="" then
+   writecardinal2(f,#comment) 
+   f:write(comment)     
+  else
+   writecardinal2(f,0)
+  end
+  if verbose then
+   local compressed=z.compressed
+   local uncompressed=z.uncompressed
+   local filename=z.filename
+   local pct=100*compressed/uncompressed
+   logwriter("")
+   if pct>=100 then
+    logwriter(format("%10i        %s",uncompressed,filename))
+   else
+    logwriter(format("%10i  %02.1f  %s",uncompressed,pct,filename))
+   end
+  end
+  f:close()
+ end
+ local function zipdir(zipname,path,level,verbose)
+  if type(zipname)=="table" then
+   verbose=zipname.verbose
+   level=zipname.level
+   path=zipname.path
+   zipname=zipname.zipname
+  end
+  if not zipname or zipname=="" then
+   return
+  end
+  if not path or path=="" then
+   path="."
+  end
+  if not isdir(path) then
+   return
+  end
+  path=gsub(path,"\\+","/")
+  path=gsub(path,"/+","/")
+  local list={}
+  local count=0
+  globpattern(path,"",true,function(name,size,time)
+   count=count+1
+   list[count]={ name,time }
+  end)
+  sort(list,function(a,b)
+   return a[1]<b[1]
+  end)
+  local zipf=openzip(zipname,level,comment,verbose)
+  if zipf then
+   local p=#path+2
+   for i=1,count do
+    local li=list[i]
+    local name=li[1]
+    local time=li[2]
+    local data=loaddata(name)
+    local name=sub(name,p,#name)
+    writezip(zipf,name,data,level,time,verbose)
+   end
+   closezip(zipf)
+  end
+ end
+ local function unzipdir(zipname,path,verbose)
+  if type(zipname)=="table" then
+   verbose=zipname.verbose
+   path=zipname.path
+   zipname=zipname.zipname
+  end
+  if not zipname or zipname=="" then
+   return
+  end
+  if not path or path=="" then
+   path="."
+  end
+  local z=openzipfile(zipname)
+  if z then
+   local list=getziplist(z)
+   if list then
+    local total=0
+    local count=#list
+    local step=number.idiv(count,10)
+    local done=0
+    local steps=verbose=="steps"
+    local time=steps and osclock()
+    for i=1,count do
+     local l=list[i]
+     local n=l.filename
+     local d=unzipfile(z,n) 
+     if d then
+      local p=filejoin(path,n)
+      if mkdirs(dirname(p)) then
+       if steps then
+        total=total+#d
+        done=done+1
+        if done>=step then
+         done=0
+         logwriter(format("%4i files of %4i done, %10i bytes, %0.3f seconds",i,count,total,osclock()-time))
+        end
+       elseif verbose then
+        logwriter(n)
+       end
+       savedata(p,d)
+      end
+     else
+      logwriter(format("problem with file %s",n))
+     end
+    end
+    if steps then
+     logwriter(format("%4i files of %4i done, %10i bytes, %0.3f seconds",count,count,total,osclock()-time))
+    end
+    closezipfile(z)
+    return true
+   else
+    closezipfile(z)
+   end
+  end
+ end
+ zipfiles.zipdir=zipdir
+ zipfiles.unzipdir=unzipdir
+end
+local pattern="^\x1F\x8B\x08"
+local gziplevel=3
+function gzip.suffix(filename)
+ local suffix,extra=suffixes(filename)
+ local gzipped=extra=="gz"
+ return suffix,gzipped
+end
+function gzip.compressed(s)
+ return s and find(s,pattern)
+end
+local getdecompressed
+local putcompressed
+if gzip.compress then
+ local gzipwindow=15+16 
+ local compress=zlib.compress
+ local decompress=zlib.decompress
+ getdecompressed=function(str)
+  return decompress(str,gzipwindow) 
+ end
+ putcompressed=function(str,level)
+  return compress(str,level or gziplevel,nil,gzipwindow)
+ end
+else
+ local gzipwindow=-15 
+ local identifier="\x1F\x8B"
+ local compress=zlib.compress
+ local decompress=zlib.decompress
+ local zlibchecksum=zlib.crc32
+ if not CONTEXTLMTXMODE or CONTEXTLMTXMODE==0 then
+  local cs=zlibchecksum
+  zlibchecksum=function(str,n) return cs(n or 0,str) end
+ end
+ local streams=utilities.streams
+ local openstream=streams.openstring
+ local closestream=streams.close
+ local getposition=streams.getposition
+ local readbyte=streams.readbyte
+ local readcardinal4=streams.readcardinal4le
+ local readcardinal2=streams.readcardinal2le
+ local readstring=streams.readstring
+ local readcstring=streams.readcstring
+ local skipbytes=streams.skip
+ local tocardinal1=streams.tocardinal1
+ local tocardinal4=streams.tocardinal4le
+ getdecompressed=function(str)
+  local s=openstream(str)
+  local identifier=readstring(s,2)
+  local method=readbyte(s,1)
+  local flags=readbyte(s,1)
+  local timestamp=readcardinal4(s)
+  local compression=readbyte(s,1)
+  local operating=readbyte(s,1)
+  local isjusttext=band(flags,0x01)~=0 and true    or false
+  local extrasize=band(flags,0x04)~=0 and readcardinal2(s) or 0
+  local filename=band(flags,0x08)~=0 and readcstring(s)   or ""
+  local comment=band(flags,0x10)~=0 and readcstring(s)   or ""
+  local checksum=band(flags,0x02)~=0 and readcardinal2(s) or 0
+  local compressed=readstring(s,#str)
+  local data=decompress(compressed,gzipwindow) 
+  return data
+ end
+ putcompressed=function(str,level,originalname)
+  return concat {
+   identifier,
+   tocardinal1(0x08),
+   tocardinal1(0x08),
+   tocardinal4(os.time()),
+   tocardinal1(0x02),
+   tocardinal1(0xFF),
+   (originalname or "unknownname").."\0",
+   compress(str,level,nil,gzipwindow),
+   tocardinal4(zlibchecksum(str)),
+   tocardinal4(#str),
+  }
+ end
+end
+function gzip.load(filename)
+ local f=openfile(filename,"rb")
+ if not f then
+ else
+  local data=f:read("*all")
+  f:close()
+  if data and data~="" then
+   if suffix(filename)=="gz" then
+    data=getdecompressed(data)
+   end
+   return data
+  end
+ end
+end
+function gzip.save(filename,data,level,originalname)
+ if suffix(filename)~="gz" then
+  filename=filename..".gz"
+ end
+ local f=openfile(filename,"wb")
+ if f then
+  data=putcompressed(data or "",level or gziplevel,originalname)
+  f:write(data)
+  f:close()
+  return #data
+ end
+end
+function gzip.compress(s,level)
+ if s and not find(s,pattern) then
+  if not level then
+   level=gziplevel
+  elseif level<=0 then
+   return s
+  elseif level>9 then
+   level=9
+  end
+  return putcompressed(s,level or gziplevel) or s
+ end
+end
+function gzip.decompress(s)
+ if s and find(s,pattern) then
+  return getdecompressed(s)
+ else
+  return s
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["lxml-tab"] = package.loaded["lxml-tab"] or true
+
+-- original size: 62810, stripped down to: 36225
+
+if not modules then modules={} end modules ['lxml-tab']={
+ version=1.001,
+ comment="this module is the basis for the lxml-* ones",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local trace_entities=false  trackers.register("xml.entities",function(v) trace_entities=v end)
+local report_xml=logs and logs.reporter("xml","core") or function(...) print(string.format(...)) end
+if lpeg.setmaxstack then lpeg.setmaxstack(1000) end 
+xml=xml or {}
+local xml=xml
+local concat,remove,insert=table.concat,table.remove,table.insert
+local type,next,setmetatable,getmetatable,tonumber,rawset,select=type,next,setmetatable,getmetatable,tonumber,rawset,select
+local lower,find,match,gsub=string.lower,string.find,string.match,string.gsub
+local sort=table.sort
+local utfchar=utf.char
+local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns
+local P,S,R,C,V,C,Cs=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.V,lpeg.C,lpeg.Cs
+local formatters=string.formatters
+do 
+xml.xmlns=xml.xmlns or {}
+local check=P(false)
+local parse=check
+function xml.registerns(namespace,pattern) 
+ check=check+C(P(lower(pattern)))/namespace
+ parse=P { P(check)+1*V(1) }
+end
+function xml.checkns(namespace,url)
+ local ns=lpegmatch(parse,lower(url))
+ if ns and namespace~=ns then
+  xml.xmlns[namespace]=ns
+ end
+end
+function xml.resolvens(url)
+  return lpegmatch(parse,lower(url)) or ""
+end
+end
+local nsremap,resolvens=xml.xmlns,xml.resolvens
+local stack,level,top,at,xmlnms,errorstr
+local entities,parameters
+local strip,utfize,resolve,cleanup,resolve_predefined,unify_predefined
+local dcache,hcache,acache
+local mt,dt,nt
+local currentfilename,currentline,linenumbers
+local grammar_parsed_text_one
+local grammar_parsed_text_two
+local grammar_unparsed_text
+local handle_hex_entity
+local handle_dec_entity
+local handle_any_entity_dtd
+local handle_any_entity_text
+local function preparexmlstate(settings)
+ if settings then
+  linenumbers=settings.linenumbers
+  stack={}
+  level=0
+  top={}
+  at={}
+  mt={}
+  dt={}
+  nt=0   
+  xmlns={}
+  errorstr=nil
+  strip=settings.strip_cm_and_dt
+  utfize=settings.utfize_entities
+  resolve=settings.resolve_entities   
+  resolve_predefined=settings.resolve_predefined_entities 
+  unify_predefined=settings.unify_predefined_entities   
+  cleanup=settings.text_cleanup
+  entities=settings.entities or {}
+  currentfilename=settings.currentresource
+  currentline=1
+  parameters={}
+  reported_at_errors={}
+  dcache={}
+  hcache={}
+  acache={}
+  if utfize==nil then
+   settings.utfize_entities=true
+   utfize=true
+  end
+  if resolve_predefined==nil then
+   settings.resolve_predefined_entities=true
+   resolve_predefined=true
+  end
+ else
+  linenumbers=false
+  stack=nil
+  level=nil
+  top=nil
+  at=nil
+  mt=nil
+  dt=nil
+  nt=nil
+  xmlns=nil
+  errorstr=nil
+  strip=nil
+  utfize=nil
+  resolve=nil
+  resolve_predefined=nil
+  unify_predefined=nil
+  cleanup=nil
+  entities=nil
+  parameters=nil
+  reported_at_errors=nil
+  dcache=nil
+  hcache=nil
+  acache=nil
+  currentfilename=nil
+  currentline=1
+ end
+end
+local function initialize_mt(root)
+ mt={ __index=root } 
+end
+function xml.setproperty(root,k,v)
+ getmetatable(root).__index[k]=v
+end
+function xml.checkerror(top,toclose)
+ return "" 
+end
+local checkns=xml.checkns
+local function add_attribute(namespace,tag,value)
+ if cleanup and value~="" then
+  value=cleanup(value) 
+ end
+ if tag=="xmlns" then
+  xmlns[#xmlns+1]=resolvens(value)
+  at[tag]=value
+ elseif namespace=="" then
+  at[tag]=value
+ elseif namespace=="xmlns" then
+  checkns(tag,value)
+  at["xmlns:"..tag]=value
+ else
+  at[namespace..":"..tag]=value
+ end
+end
+local function add_empty(spacing,namespace,tag)
+ if spacing~="" then
+  nt=nt+1
+  dt[nt]=spacing
+ end
+ local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace
+ top=stack[level]
+ dt=top.dt
+ nt=#dt+1
+ local t=linenumbers and {
+  ns=namespace or "",
+  rn=resolved,
+  tg=tag,
+  at=at,
+  dt={},
+  ni=nt,
+  cf=currentfilename,
+  cl=currentline,
+  __p__=top,
+ } or {
+  ns=namespace or "",
+  rn=resolved,
+  tg=tag,
+  at=at,
+  dt={},
+  ni=nt,
+  __p__=top,
+ }
+ dt[nt]=t
+ setmetatable(t,mt)
+ if at.xmlns then
+  remove(xmlns)
+ end
+ at={}
+end
+local function add_begin(spacing,namespace,tag)
+ if spacing~="" then
+  nt=nt+1
+  dt[nt]=spacing
+ end
+ local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace
+ dt={}
+ top=linenumbers and {
+  ns=namespace or "",
+  rn=resolved,
+  tg=tag,
+  at=at,
+  dt=dt,
+  ni=nil,
+  cf=currentfilename,
+  cl=currentline,
+  __p__=stack[level],
+ } or {
+  ns=namespace or "",
+  rn=resolved,
+  tg=tag,
+  at=at,
+  dt=dt,
+  ni=nil,
+  __p__=stack[level],
+ }
+ setmetatable(top,mt)
+ nt=0
+ level=level+1
+ stack[level]=top
+ at={}
+end
+local function add_end(spacing,namespace,tag)
+ if spacing~="" then
+  nt=nt+1
+  dt[nt]=spacing
+ end
+ local toclose=stack[level]
+ level=level-1
+ top=stack[level]
+ if level<1 then
+  errorstr=formatters["unable to close %s %s"](tag,xml.checkerror(top,toclose) or "")
+  report_xml(errorstr)
+ elseif toclose.tg~=tag then 
+  errorstr=formatters["unable to close %s with %s %s"](toclose.tg,tag,xml.checkerror(top,toclose) or "")
+  report_xml(errorstr)
+ end
+ dt=top.dt
+ nt=#dt+1
+ dt[nt]=toclose
+ toclose.ni=nt 
+ if toclose.at.xmlns then
+  remove(xmlns)
+ end
+end
+local function add_text(text)
+ if text=="" then
+  return
+ elseif cleanup then
+  if nt>0 then
+   local s=dt[nt]
+   if type(s)=="string" then
+    dt[nt]=s..cleanup(text)
+   else
+    nt=nt+1
+    dt[nt]=cleanup(text)
+   end
+  else
+   nt=1
+   dt[1]=cleanup(text)
+  end
+ else
+  if nt>0 then
+   local s=dt[nt]
+   if type(s)=="string" then
+    dt[nt]=s..text
+   else
+    nt=nt+1
+    dt[nt]=text
+   end
+  else
+   nt=1
+   dt[1]=text
+  end
+ end
+end
+local function add_special(what,spacing,text)
+ if spacing~="" then
+  nt=nt+1
+  dt[nt]=spacing
+ end
+ if strip and (what=="@cm@" or what=="@dt@") then
+ else
+  nt=nt+1
+  dt[nt]=linenumbers and {
+   special=true,
+   ns="",
+   tg=what,
+   ni=nil,
+   dt={ text },
+   cf=currentfilename,
+   cl=currentline,
+  } or {
+   special=true,
+   ns="",
+   tg=what,
+   ni=nil,
+   dt={ text },
+  }
+ end
+end
+local function set_message(txt)
+ errorstr="garbage at the end of the file: "..gsub(txt,"([ \n\r\t]*)","")
+end
+local function attribute_value_error(str)
+ if not reported_at_errors[str] then
+  report_xml("invalid attribute value %a",str)
+  reported_at_errors[str]=true
+  at._error_=str
+ end
+ return str
+end
+local function attribute_specification_error(str)
+ if not reported_at_errors[str] then
+  report_xml("invalid attribute specification %a",str)
+  reported_at_errors[str]=true
+  at._error_=str
+ end
+ return str
+end
+do
+ local badentity="&" 
+ xml.placeholders={
+  unknown_dec_entity=function(str) return str=="" and badentity or formatters["&%s;"](str) end,
+  unknown_hex_entity=function(str) return formatters["&#x%s;"](str) end,
+  unknown_any_entity=function(str) return formatters["&#x%s;"](str) end,
+ }
+ local function fromhex(s)
+  local n=tonumber(s,16)
+  if n then
+   return utfchar(n)
+  else
+   return formatters["h:%s"](s),true
+  end
+ end
+ local function fromdec(s)
+  local n=tonumber(s)
+  if n then
+   return utfchar(n)
+  else
+   return formatters["d:%s"](s),true
+  end
+ end
+ local p_rest=(1-P(";"))^0
+ local p_many=P(1)^0
+ local parsedentity=P("&#")*(P("x")*(p_rest/fromhex)+(p_rest/fromdec))*P(";")*P(-1)+P ("#")*(P("x")*(p_many/fromhex)+(p_many/fromdec))
+ xml.parsedentitylpeg=parsedentity
+ local predefined_unified={
+  [38]="&",
+  [42]=""",
+  [47]="'",
+  [74]="<",
+  [76]=">",
+ }
+ local predefined_simplified={
+  [38]="&",amp="&",
+  [42]='"',quot='"',
+  [47]="'",apos="'",
+  [74]="<",lt="<",
+  [76]=">",gt=">",
+ }
+ local nofprivates=0xF0000 
+ local privates_u={ 
+  [ [[&]] ]="&",
+  [ [["]] ]=""",
+  [ [[']] ]="'",
+  [ [[<]] ]="<",
+  [ [[>]] ]=">",
+ }
+ local privates_p={ 
+ }
+ local privates_s={ 
+  [ [["]] ]="&U+22;",
+  [ [[#]] ]="&U+23;",
+  [ [[$]] ]="&U+24;",
+  [ [[%]] ]="&U+25;",
+  [ [[&]] ]="&U+26;",
+  [ [[']] ]="&U+27;",
+  [ [[<]] ]="&U+3C;",
+  [ [[>]] ]="&U+3E;",
+  [ [[\]] ]="&U+5C;",
+  [ [[{]] ]="&U+7B;",
+  [ [[|]] ]="&U+7C;",
+  [ [[}]] ]="&U+7D;",
+  [ [[~]] ]="&U+7E;",
+ }
+ local privates_x={ 
+  [ [["]] ]="&U+22;",
+  [ [[#]] ]="&U+23;",
+  [ [[$]] ]="&U+24;",
+  [ [[%]] ]="&U+25;",
+  [ [[']] ]="&U+27;",
+  [ [[\]] ]="&U+5C;",
+  [ [[{]] ]="&U+7B;",
+  [ [[|]] ]="&U+7C;",
+  [ [[}]] ]="&U+7D;",
+  [ [[~]] ]="&U+7E;",
+ }
+ local privates_n={ 
+ }
+ local escaped=utf.remapper(privates_u,"dynamic")
+ local unprivatized=utf.remapper(privates_p,"dynamic")
+ local unspecialized=utf.remapper(privates_s,"dynamic")
+ local despecialized=utf.remapper(privates_x,"dynamic")
+ xml.unprivatized=unprivatized
+ xml.unspecialized=unspecialized
+ xml.despecialized=despecialized
+ xml.escaped=escaped
+ local function unescaped(s)
+  local p=privates_n[s]
+  if not p then
+   nofprivates=nofprivates+1
+   p=utfchar(nofprivates)
+   privates_n[s]=p
+   s="&"..s..";" 
+   privates_u[p]=s
+   privates_p[p]=s
+   privates_s[p]=s
+  end
+  return p
+ end
+ xml.privatetoken=unescaped
+ xml.privatecodes=privates_n
+ xml.specialcodes=privates_s
+ function xml.addspecialcode(key,value)
+  privates_s[key]=value or "&"..s..";"
+ end
+ handle_hex_entity=function(str)
+  local h=hcache[str]
+  if not h then
+   local n=tonumber(str,16)
+   h=unify_predefined and predefined_unified[n]
+   if h then
+    if trace_entities then
+     report_xml("utfize, converting hex entity &#x%s; into %a",str,h)
+    end
+   elseif utfize then
+    h=(n and utfchar(n)) or xml.unknown_hex_entity(str) or ""
+    if not n then
+     report_xml("utfize, ignoring hex entity &#x%s;",str)
+    elseif trace_entities then
+     report_xml("utfize, converting hex entity &#x%s; into %a",str,h)
+    end
+   else
+    if trace_entities then
+     report_xml("found entity &#x%s;",str)
+    end
+    h="&#x"..str..";"
+   end
+   hcache[str]=h
+  end
+  return h
+ end
+ handle_dec_entity=function(str)
+  local d=dcache[str]
+  if not d then
+   local n=tonumber(str)
+   d=unify_predefined and predefined_unified[n]
+   if d then
+    if trace_entities then
+     report_xml("utfize, converting dec entity &#%s; into %a",str,d)
+    end
+   elseif utfize then
+    d=(n and utfchar(n)) or placeholders.unknown_dec_entity(str) or ""
+    if not n then
+     report_xml("utfize, ignoring dec entity &#%s;",str)
+    elseif trace_entities then
+     report_xml("utfize, converting dec entity &#%s; into %a",str,d)
+    end
+   else
+    if trace_entities then
+     report_xml("found entity &#%s;",str)
+    end
+    d="&#"..str..";"
+   end
+   dcache[str]=d
+  end
+  return d
+ end
+ handle_any_entity_dtd=function(str)
+  if resolve then
+   local a=resolve_predefined and predefined_simplified[str] 
+   if a then
+    if trace_entities then
+     report_xml("resolving entity &%s; to predefined %a",str,a)
+    end
+   else
+    if type(resolve)=="function" then
+     a=resolve(str,entities) or entities[str]
+    else
+     a=entities[str]
+    end
+    if a then
+     if type(a)=="function" then
+      if trace_entities then
+       report_xml("expanding entity &%s; to function call",str)
+      end
+      a=a(str) or ""
+     end
+     a=lpegmatch(parsedentity,a) or a 
+     if trace_entities then
+      report_xml("resolving entity &%s; to internal %a",str,a)
+     end
+    else
+     local unknown_any_entity=placeholders.unknown_any_entity
+     if unknown_any_entity then
+      a=unknown_any_entity(str) or ""
+     end
+     if a then
+      if trace_entities then
+       report_xml("resolving entity &%s; to external %s",str,a)
+      end
+     else
+      if trace_entities then
+       report_xml("keeping entity &%s;",str)
+      end
+      if str=="" then
+       a=badentity
+      else
+       a="&"..str..";"
+      end
+     end
+    end
+   end
+   return a
+  else
+   local a=acache[str]
+   if not a then
+    a=resolve_predefined and predefined_simplified[str]
+    if a then
+     acache[str]=a
+     if trace_entities then
+      report_xml("entity &%s; becomes %a",str,a)
+     end
+    elseif str=="" then
+     if trace_entities then
+      report_xml("invalid entity &%s;",str)
+     end
+     a=badentity
+     acache[str]=a
+    else
+     if trace_entities then
+      report_xml("entity &%s; is made private",str)
+     end
+     a=unescaped(str)
+     acache[str]=a
+    end
+   end
+   return a
+  end
+ end
+ handle_any_entity_text=function(str)
+  if resolve then
+   local a=resolve_predefined and predefined_simplified[str]
+   if a then
+    if trace_entities then
+     report_xml("resolving entity &%s; to predefined %a",str,a)
+    end
+   else
+    if type(resolve)=="function" then
+     a=resolve(str,entities) or entities[str]
+    else
+     a=entities[str]
+    end
+    if a then
+     if type(a)=="function" then
+      if trace_entities then
+       report_xml("expanding entity &%s; to function call",str)
+      end
+      a=a(str) or ""
+     end
+     a=lpegmatch(grammar_parsed_text_two,a) or a
+     if type(a)=="number" then
+      return ""
+     else
+      a=lpegmatch(parsedentity,a) or a 
+      if trace_entities then
+       report_xml("resolving entity &%s; to internal %a",str,a)
+      end
+     end
+     if trace_entities then
+      report_xml("resolving entity &%s; to internal %a",str,a)
+     end
+    else
+     local unknown_any_entity=placeholders.unknown_any_entity
+     if unknown_any_entity then
+      a=unknown_any_entity(str) or ""
+     end
+     if a then
+      if trace_entities then
+       report_xml("resolving entity &%s; to external %s",str,a)
+      end
+     else
+      if trace_entities then
+       report_xml("keeping entity &%s;",str)
+      end
+      if str=="" then
+       a=badentity
+      else
+       a="&"..str..";"
+      end
+     end
+    end
+   end
+   return a
+  else
+   local a=acache[str]
+   if not a then
+    a=resolve_predefined and predefined_simplified[str]
+    if a then
+     acache[str]=a
+     if trace_entities then
+      report_xml("entity &%s; becomes %a",str,a)
+     end
+    elseif str=="" then
+     if trace_entities then
+      report_xml("invalid entity &%s;",str)
+     end
+     a=badentity
+     acache[str]=a
+    else
+     if trace_entities then
+      report_xml("entity &%s; is made private",str)
+     end
+     a=unescaped(str)
+     acache[str]=a
+    end
+   end
+   return a
+  end
+ end
+ local p_rest=(1-P(";"))^1
+ local spec={
+  [0x23]="\\Ux{23}",
+  [0x24]="\\Ux{24}",
+  [0x25]="\\Ux{25}",
+  [0x5C]="\\Ux{5C}",
+  [0x7B]="\\Ux{7B}",
+  [0x7C]="\\Ux{7C}",
+  [0x7D]="\\Ux{7D}",
+  [0x7E]="\\Ux{7E}",
+ }
+ local hash=table.setmetatableindex(spec,function(t,k)
+  local v=utfchar(k)
+  t[k]=v
+  return v
+ end)
+ local function fromuni(s)
+  local n=tonumber(s,16)
+  if n then
+   return hash[n]
+  else
+   return formatters["u:%s"](s),true
+  end
+ end
+ local function fromhex(s)
+  local n=tonumber(s,16)
+  if n then
+   return hash[n]
+  else
+   return formatters["h:%s"](s),true
+  end
+ end
+ local function fromdec(s)
+  local n=tonumber(s)
+  if n then
+   return hash[n]
+  else
+   return formatters["d:%s"](s),true
+  end
+ end
+ local reparsedentity=P("U+")*(p_rest/fromuni)+P("#")*(
+   P("x")*(p_rest/fromhex)+p_rest/fromdec
+  )
+ local hash=table.setmetatableindex(function(t,k)
+  local v=utfchar(k)
+  t[k]=v
+  return v
+ end)
+ local function fromuni(s)
+  local n=tonumber(s,16)
+  if n then
+   return hash[n]
+  else
+   return formatters["u:%s"](s),true
+  end
+ end
+ local function fromhex(s)
+  local n=tonumber(s,16)
+  if n then
+   return hash[n]
+  else
+   return formatters["h:%s"](s),true
+  end
+ end
+ local function fromdec(s)
+  local n=tonumber(s)
+  if n then
+   return hash[n]
+  else
+   return formatters["d:%s"](s),true
+  end
+ end
+ local unescapedentity=P("U+")*(p_rest/fromuni)+P("#")*(
+   P("x")*(p_rest/fromhex)+p_rest/fromdec
+  )
+ xml.reparsedentitylpeg=reparsedentity   
+ xml.unescapedentitylpeg=unescapedentity  
+end
+local escaped=xml.escaped
+local unescaped=xml.unescaped
+local placeholders=xml.placeholders
+local function handle_end_entity(str)
+ report_xml("error in entity, %a found without ending %a",str,";")
+ return str
+end
+local function handle_crap_error(chr)
+ report_xml("error in parsing, unexpected %a found ",chr)
+ add_text(chr)
+ return chr
+end
+local function handlenewline()
+ currentline=currentline+1
+end
+local spacetab=S(' \t')
+local space=S(' \r\n\t')
+local newline=lpegpatterns.newline/handlenewline
+local anything=P(1)
+local open=P('<')
+local close=P('>')
+local squote=S("'")
+local dquote=S('"')
+local equal=P('=')
+local slash=P('/')
+local colon=P(':')
+local semicolon=P(';')
+local ampersand=P('&')
+local valid_0=R("\128\255") 
+local valid_1=R('az','AZ')+S('_')+valid_0
+local valid_2=valid_1+R('09')+S('-.')
+local valid=valid_1*valid_2^0
+local name_yes=C(valid^1)*colon*C(valid^1)
+local name_nop=C(P(true))*C(valid^1)
+local name=name_yes+name_nop
+local utfbom=lpegpatterns.utfbom 
+local spacing=C(space^0)
+local space_nl=spacetab+newline
+local spacing_nl=Cs((space_nl)^0)
+local anything_nl=newline+P(1)
+local function weirdentity(k,v)
+ if trace_entities then
+  report_xml("registering %s entity %a as %a","weird",k,v)
+ end
+ parameters[k]=v
+end
+local function normalentity(k,v)
+ if trace_entities then
+  report_xml("registering %s entity %a as %a","normal",k,v)
+ end
+ entities[k]=v
+end
+local function systementity(k,v,n)
+ if trace_entities then
+  report_xml("registering %s entity %a as %a","system",k,v)
+ end
+ entities[k]=v
+end
+local function publicentity(k,v,n)
+ if trace_entities then
+  report_xml("registering %s entity %a as %a","public",k,v)
+ end
+ entities[k]=v
+end
+local function entityfile(pattern,k,v,n)
+ if n then
+  local okay,data
+  local loadbinfile=resolvers and resolvers.loadbinfile
+  if loadbinfile then
+   okay,data=loadbinfile(n)
+  else
+   data=io.loaddata(n)
+   okay=data and data~=""
+  end
+  if okay then
+   if trace_entities then
+    report_xml("loading public entities %a as %a from %a",k,v,n)
+   end
+   lpegmatch(pattern,data)
+   return
+  end
+ end
+ report_xml("ignoring public entities %a as %a from %a",k,v,n)
+end
+local function install(spacenewline,spacing,anything)
+ local anyentitycontent=(1-open-semicolon-space-close-ampersand)^0
+ local hexentitycontent=R("AF","af","09")^1
+ local decentitycontent=R("09")^1
+ local parsedentity=P("#")/""*(
+         P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity)
+        )+(anyentitycontent/handle_any_entity_dtd) 
+ local parsedentity_text=P("#")/""*(
+         P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity)
+        )+(anyentitycontent/handle_any_entity_text) 
+ local entity=(ampersand/"")*parsedentity*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity)
+ local entity_text=(ampersand/"")*parsedentity_text*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity)
+ local text_unparsed=Cs((anything-open)^1)
+ local text_parsed=(Cs((anything-open-ampersand)^1)/add_text+Cs(entity_text)/add_text)^1
+ local somespace=(spacenewline)^1
+ local optionalspace=(spacenewline)^0
+ local value=(squote*Cs((entity+(anything-squote))^0)*squote)+(dquote*Cs((entity+(anything-dquote))^0)*dquote) 
+ local endofattributes=slash*close+close 
+ local whatever=space*name*optionalspace*equal
+ local wrongvalue=Cs(P(entity+(1-space-endofattributes))^1)/attribute_value_error
+ local attributevalue=value+wrongvalue
+ local attribute=(somespace*name*optionalspace*equal*optionalspace*attributevalue)/add_attribute
+ local attributes=(attribute+somespace^-1*(((anything-endofattributes)^1)/attribute_specification_error))^0
+ local parsedtext=text_parsed   
+ local unparsedtext=text_unparsed/add_text
+ local balanced=P { "["*((anything-S"[]")+V(1))^0*"]" }
+ local emptyelement=(spacing*open*name*attributes*optionalspace*slash*close)/add_empty
+ local beginelement=(spacing*open*name*attributes*optionalspace*close)/add_begin
+ local endelement=(spacing*open*slash*name*optionalspace*close)/add_end
+ local begincomment=open*P("!--")
+ local endcomment=P("--")*close
+ local begininstruction=open*P("?")
+ local endinstruction=P("?")*close
+ local begincdata=open*P("![CDATA[")
+ local endcdata=P("]]")*close
+ local someinstruction=C((anything-endinstruction)^0)
+ local somecomment=C((anything-endcomment )^0)
+ local somecdata=C((anything-endcdata   )^0)
+ local begindoctype=open*P("!DOCTYPE")
+ local enddoctype=close
+ local beginset=P("[")
+ local endset=P("]")
+ local wrdtypename=C((anything-somespace-P(";"))^1)
+ local doctypename=C((anything-somespace-close)^0)
+ local elementdoctype=optionalspace*P("<!ELEMENT")*(anything-close)^0*close
+ local basiccomment=begincomment*((anything-endcomment)^0)*endcomment
+ local weirdentitytype=P("%")*(somespace*doctypename*somespace*value)/weirdentity
+ local normalentitytype=(doctypename*somespace*value)/normalentity
+ local publicentitytype=(doctypename*somespace*P("PUBLIC")*somespace*value)/publicentity
+ local systementitytype=(doctypename*somespace*P("SYSTEM")*somespace*value*somespace*P("NDATA")*somespace*doctypename)/systementity
+ local entitydoctype=optionalspace*P("<!ENTITY")*somespace*(systementitytype+publicentitytype+normalentitytype+weirdentitytype)*optionalspace*close
+ local publicentityfile=(doctypename*somespace*P("PUBLIC")*somespace*value*(somespace*value)^0)/function(...)
+  entityfile(entitydoctype,...)
+ end
+ local function weirdresolve(s)
+  lpegmatch(entitydoctype,parameters[s])
+ end
+ local function normalresolve(s)
+  lpegmatch(entitydoctype,entities[s])
+ end
+ local entityresolve=P("%")*(wrdtypename/weirdresolve )*P(";")+P("&")*(wrdtypename/normalresolve)*P(";")
+ entitydoctype=entitydoctype+entityresolve
+ local doctypeset=beginset*optionalspace*P(elementdoctype+entitydoctype+entityresolve+basiccomment+space)^0*optionalspace*endset
+ local definitiondoctype=doctypename*somespace*doctypeset
+ local publicdoctype=doctypename*somespace*P("PUBLIC")*somespace*value*somespace*value*somespace*doctypeset
+ local systemdoctype=doctypename*somespace*P("SYSTEM")*somespace*value*somespace*doctypeset
+ local simpledoctype=(anything-close)^1 
+ local somedoctype=C((somespace*(publicentityfile+publicdoctype+systemdoctype+definitiondoctype+simpledoctype)*optionalspace)^0)
+ local instruction=(spacing*begininstruction*someinstruction*endinstruction)/function(...) add_special("@pi@",...) end
+ local comment=(spacing*begincomment*somecomment*endcomment )/function(...) add_special("@cm@",...) end
+ local cdata=(spacing*begincdata*somecdata*endcdata   )/function(...) add_special("@cd@",...) end
+ local doctype=(spacing*begindoctype*somedoctype*enddoctype )/function(...) add_special("@dt@",...) end
+ local crap_parsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata-ampersand
+ local crap_unparsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata
+ local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error
+ local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error
+ local unparsedcrap=Cs((crap_unparsed     )^1)/handle_crap_error
+ local trailer=space^0*(text_unparsed/set_message)^0
+ local grammar_parsed_text_one=P { "preamble",
+  preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0,
+ }
+ local grammar_parsed_text_two=P { "followup",
+  followup=V("parent")*trailer,
+  parent=beginelement*V("children")^0*endelement,
+  children=parsedtext+V("parent")+emptyelement+comment+cdata+instruction+parsedcrap,
+ }
+ local grammar_unparsed_text=P { "preamble",
+  preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0*V("parent")*trailer,
+  parent=beginelement*V("children")^0*endelement,
+  children=unparsedtext+V("parent")+emptyelement+comment+cdata+instruction+unparsedcrap,
+ }
+ return grammar_parsed_text_one,grammar_parsed_text_two,grammar_unparsed_text
+end
+local
+ grammar_parsed_text_one_nop,
+ grammar_parsed_text_two_nop,
+ grammar_unparsed_text_nop=install(space,spacing,anything)
+local
+ grammar_parsed_text_one_yes,
+ grammar_parsed_text_two_yes,
+ grammar_unparsed_text_yes=install(space_nl,spacing_nl,anything_nl)
+local function _xmlconvert_(data,settings,detail)
+ settings=settings or {} 
+ preparexmlstate(settings)
+ if settings.linenumbers then
+  grammar_parsed_text_one=grammar_parsed_text_one_yes
+  grammar_parsed_text_two=grammar_parsed_text_two_yes
+  grammar_unparsed_text=grammar_unparsed_text_yes
+ else
+  grammar_parsed_text_one=grammar_parsed_text_one_nop
+  grammar_parsed_text_two=grammar_parsed_text_two_nop
+  grammar_unparsed_text=grammar_unparsed_text_nop
+ end
+ local preprocessor=settings.preprocessor
+ if data and data~="" and type(preprocessor)=="function" then
+  data=preprocessor(data,settings) or data 
+ end
+ if settings.parent_root then
+  mt=getmetatable(settings.parent_root)
+ else
+  initialize_mt(top)
+ end
+ level=level+1
+ stack[level]=top
+ top.dt={}
+ dt=top.dt
+ nt=0
+ if not data or data=="" then
+  errorstr="empty xml file"
+ elseif data==true then
+  errorstr=detail or "problematic xml file"
+ elseif utfize or resolve then
+  local m=lpegmatch(grammar_parsed_text_one,data)
+  if m then
+   m=lpegmatch(grammar_parsed_text_two,data,m)
+  end
+  if m then
+  else
+   errorstr="invalid xml file - parsed text"
+  end
+ elseif type(data)=="string" then
+  if lpegmatch(grammar_unparsed_text,data) then
+   errorstr=""
+  else
+   errorstr="invalid xml file - unparsed text"
+  end
+ else
+  errorstr="invalid xml file - no text at all"
+ end
+ local result
+ if errorstr and errorstr~="" then
+  result={ dt={ { ns="",tg="error",dt={ errorstr },at={},er=true } } }
+  setmetatable(result,mt)
+  setmetatable(result.dt[1],mt)
+  setmetatable(stack,mt)
+  local errorhandler=settings.error_handler
+  if errorhandler==false then
+  else
+   errorhandler=errorhandler or xml.errorhandler
+   if errorhandler then
+    local currentresource=settings.currentresource
+    if currentresource and currentresource~="" then
+     xml.errorhandler(formatters["load error in [%s]: %s"](currentresource,errorstr),currentresource)
+    else
+     xml.errorhandler(formatters["load error: %s"](errorstr))
+    end
+   end
+  end
+ else
+  result=stack[1]
+ end
+ if not settings.no_root then
+  result={ special=true,ns="",tg='@rt@',dt=result.dt,at={},entities=entities,settings=settings }
+  setmetatable(result,mt)
+  local rdt=result.dt
+  for k=1,#rdt do
+   local v=rdt[k]
+   if type(v)=="table" and not v.special then 
+    result.ri=k 
+    v.__p__=result  
+    break
+   end
+  end
+ end
+ if errorstr and errorstr~="" then
+  result.error=true
+ else
+  errorstr=nil
+ end
+ result.statistics={
+  errormessage=errorstr,
+  entities={
+   decimals=dcache,
+   hexadecimals=hcache,
+   names=acache,
+   intermediates=parameters,
+  }
+ }
+ preparexmlstate() 
+ return result
+end
+local function xmlconvert(data,settings)
+ local ok,result=pcall(function() return _xmlconvert_(data,settings) end)
+ if ok then
+  return result
+ elseif type(result)=="string" then
+  return _xmlconvert_(true,settings,result)
+ else
+  return _xmlconvert_(true,settings)
+ end
+end
+xml.convert=xmlconvert
+function xml.inheritedconvert(data,xmldata,cleanup) 
+ local settings=xmldata.settings
+ if settings then
+  settings.parent_root=xmldata 
+ end
+ local xc=xmlconvert(data,settings) 
+ if cleanup then
+  local x=xc.dt
+  if x then
+   x=x[1]
+   if x and x.tg=="@pi@" then
+    local dt=x.dt
+    local pi=dt and dt[1]
+    if type(pi)=="string" and find(pi,"^xml") then
+     remove(dt,1)
+    end
+   end
+  end
+ end
+ return xc
+end
+function xml.is_valid(root)
+ return root and root.dt and root.dt[1] and type(root.dt[1])=="table" and not root.dt[1].er
+end
+function xml.package(tag,attributes,data)
+ local ns,tg=match(tag,"^(.-):?([^:]+)$")
+ local t={ ns=ns,tg=tg,dt=data or "",at=attributes or {} }
+ setmetatable(t,mt)
+ return t
+end
+function xml.is_valid(root)
+ return root and not root.error
+end
+xml.errorhandler=report_xml
+function xml.load(filename,settings)
+ local data=""
+ if type(filename)=="string" then
+  local f=io.open(filename,'r') 
+  if f then
+   data=f:read("*all") 
+   f:close()
+  end
+ elseif filename then 
+  data=filename:read("*all") 
+ end
+ if settings then
+  settings.currentresource=filename
+  local result=xmlconvert(data,settings)
+  settings.currentresource=nil
+  return result
+ else
+  return xmlconvert(data,{ currentresource=filename })
+ end
+end
+local no_root={ no_root=true }
+function xml.toxml(data)
+ if type(data)=="string" then
+  local root={ xmlconvert(data,no_root) }
+  return (#root>1 and root) or root[1]
+ else
+  return data
+ end
+end
+local function copy(old,p)
+ if old then
+  local new={}
+  for k,v in next,old do
+   local t=type(v)=="table"
+   if k=="at" then
+    local t={}
+    for k,v in next,v do
+     t[k]=v
+    end
+    new[k]=t
+   elseif k=="dt" then
+    v.__p__=nil
+    local t={}
+    for i=1,#v do
+     local vi=v[i]
+     if type(vi)=="table" then
+      t[i]=copy(vi,new)
+     else
+      t[i]=vi
+     end
+    end
+    new[k]=t
+    t.__p__=p
+   else
+    new[k]=v 
+   end
+  end
+  local mt=getmetatable(old)
+  if mt then
+   setmetatable(new,mt)
+  end
+  return new
+ else
+  return {}
+ end
+end
+xml.copy=copy
+function xml.checkbom(root) 
+ if root.ri then
+  local dt=root.dt
+  for k=1,#dt do
+   local v=dt[k]
+   if type(v)=="table" and v.special and v.tg=="@pi@" and find(v.dt[1],"xml.*version=") then
+    return
+   end
+  end
+  insert(dt,1,{ special=true,ns="",tg="@pi@",dt={ "xml version='1.0' standalone='yes'" } } )
+  insert(dt,2,"\n" )
+ end
+end
+local f_attribute=formatters['%s=%q']
+local function verbose_element(e,handlers,escape) 
+ local handle=handlers.handle
+ local serialize=handlers.serialize
+ local ens,etg,eat,edt,ern=e.ns,e.tg,e.at,e.dt,e.rn
+ local ats=eat and next(eat) and {}
+ if ats then
+  local n=0
+  for k in next,eat do
+   n=n+1
+   ats[n]=k
+  end
+  if n==1 then
+   local k=ats[1]
+   ats=f_attribute(k,escaped(eat[k]))
+  else
+   sort(ats)
+   for i=1,n do
+    local k=ats[i]
+    ats[i]=f_attribute(k,escaped(eat[k]))
+   end
+   ats=concat(ats," ")
+  end
+ end
+ if ern and trace_entities and ern~=ens then
+  ens=ern
+ end
+ local n=edt and #edt
+ if ens~="" then
+  if n and n>0 then
+   if ats then
+    handle("<",ens,":",etg," ",ats,">")
+   else
+    handle("<",ens,":",etg,">")
+   end
+   for i=1,n do
+    local e=edt[i]
+    if type(e)=="string" then
+     handle(escaped(e))
+    else
+     serialize(e,handlers)
+    end
+   end
+   handle("</",ens,":",etg,">")
+  else
+   if ats then
+    handle("<",ens,":",etg," ",ats,"/>")
+   else
+    handle("<",ens,":",etg,"/>")
+   end
+  end
+ else
+  if n and n>0 then
+   if ats then
+    handle("<",etg," ",ats,">")
+   else
+    handle("<",etg,">")
+   end
+   for i=1,n do
+    local e=edt[i]
+    if type(e)=="string" then
+     handle(escaped(e)) 
+    else
+     serialize(e,handlers)
+    end
+   end
+   handle("</",etg,">")
+  else
+   if ats then
+    handle("<",etg," ",ats,"/>")
+   else
+    handle("<",etg,"/>")
+   end
+  end
+ end
+end
+local function verbose_pi(e,handlers)
+ handlers.handle("<?",e.dt[1],"?>")
+end
+local function verbose_comment(e,handlers)
+ handlers.handle("<!--",e.dt[1],"-->")
+end
+local function verbose_cdata(e,handlers)
+ handlers.handle("<![CDATA[",e.dt[1],"]]>")
+end
+local function verbose_doctype(e,handlers)
+ handlers.handle("<!DOCTYPE",e.dt[1],">") 
+end
+local function verbose_root(e,handlers)
+ handlers.serialize(e.dt,handlers)
+end
+local function verbose_text(e,handlers)
+ handlers.handle(escaped(e))
+end
+local function verbose_document(e,handlers)
+ local serialize=handlers.serialize
+ local functions=handlers.functions
+ for i=1,#e do
+  local ei=e[i]
+  if type(ei)=="string" then
+   functions["@tx@"](ei,handlers)
+  else
+   serialize(ei,handlers)
+  end
+ end
+end
+local function serialize(e,handlers,...)
+ if e then
+  local initialize=handlers.initialize
+  local finalize=handlers.finalize
+  local functions=handlers.functions
+  if initialize then
+   local state=initialize(...)
+   if not state==true then
+    return state
+   end
+  end
+  local etg=e.tg
+  if etg then
+   (functions[etg] or functions["@el@"])(e,handlers)
+  else
+   functions["@dc@"](e,handlers) 
+  end
+  if finalize then
+   return finalize()
+  end
+ end
+end
+local function xserialize(e,handlers)
+ if e then
+  local functions=handlers.functions
+  local etg=e.tg
+  if etg then
+   (functions[etg] or functions["@el@"])(e,handlers)
+  else
+   functions["@dc@"](e,handlers)
+  end
+ end
+end
+local handlers={}
+local function newhandlers(settings)
+ local t=table.copy(handlers[settings and settings.parent or "verbose"] or {}) 
+ if settings then
+  for k,v in next,settings do
+   if type(v)=="table" then
+    local tk=t[k] if not tk then tk={} t[k]=tk end
+    for kk,vv in next,v do
+     tk[kk]=vv
+    end
+   else
+    t[k]=v
+   end
+  end
+  if settings.name then
+   handlers[settings.name]=t
+  end
+ end
+ utilities.storage.mark(t)
+ return t
+end
+local nofunction=function() end
+function xml.sethandlersfunction(handler,name,fnc)
+ handler.functions[name]=fnc or nofunction
+end
+function xml.gethandlersfunction(handler,name)
+ return handler.functions[name]
+end
+function xml.gethandlers(name)
+ return handlers[name]
+end
+newhandlers {
+ name="verbose",
+ initialize=false,
+ finalize=false,
+ serialize=xserialize,
+ handle=print,
+ functions={
+  ["@dc@"]=verbose_document,
+  ["@dt@"]=verbose_doctype,
+  ["@rt@"]=verbose_root,
+  ["@el@"]=verbose_element,
+  ["@pi@"]=verbose_pi,
+  ["@cm@"]=verbose_comment,
+  ["@cd@"]=verbose_cdata,
+  ["@tx@"]=verbose_text,
+ }
+}
+local result
+local xmlfilehandler=newhandlers {
+ name="file",
+ initialize=function(name)
+  result=io.open(name,"wb")
+  return result
+ end,
+ finalize=function()
+  result:close()
+  return true
+ end,
+ handle=function(...)
+  result:write(...)
+ end,
+}
+function xml.save(root,name)
+ serialize(root,xmlfilehandler,name)
+end
+local result,r,threshold={},0,512
+local xmlstringhandler=newhandlers {
+ name="string",
+ initialize=function()
+  r=0
+  return result
+ end,
+ finalize=function()
+  local done=concat(result,"",1,r)
+  r=0
+  if r>threshold then
+   result={}
+  end
+  return done
+ end,
+ handle=function(...)
+  for i=1,select("#",...) do
+   r=r+1
+   result[r]=select(i,...)
+  end
+ end,
+}
+local function xmltostring(root) 
+ if not root then
+  return ""
+ elseif type(root)=="string" then
+  return root
+ else 
+  return serialize(root,xmlstringhandler) or ""
+ end
+end
+local function __tostring(root) 
+ return (root and xmltostring(root)) or ""
+end
+initialize_mt=function(root) 
+ mt={ __tostring=__tostring,__index=root }
+end
+xml.defaulthandlers=handlers
+xml.newhandlers=newhandlers
+xml.serialize=serialize
+xml.tostring=xmltostring
+local function xmlstring(e,handle)
+ if not handle or (e.special and e.tg~="@rt@") then
+ elseif e.tg then
+  local edt=e.dt
+  if edt then
+   for i=1,#edt do
+    xmlstring(edt[i],handle)
+   end
+  end
+ else
+  handle(e)
+ end
+end
+xml.string=xmlstring
+function xml.settings(e)
+ while e do
+  local s=e.settings
+  if s then
+   return s
+  else
+   e=e.__p__
+  end
+ end
+ return nil
+end
+function xml.root(e)
+ local r=e
+ while e do
+  e=e.__p__
+  if e then
+   r=e
+  end
+ end
+ return r
+end
+function xml.parent(root)
+ return root.__p__
+end
+function xml.body(root)
+ return root.ri and root.dt[root.ri] or root 
+end
+function xml.name(root)
+ if not root then
+  return ""
+ end
+ local ns=root.ns
+ local tg=root.tg
+ if ns=="" then
+  return tg
+ else
+  return ns..":"..tg
+ end
+end
+function xml.erase(dt,k)
+ if dt then
+  if k then
+   dt[k]=""
+  else for k=1,#dt do
+   dt[1]={ "" }
+  end end
+ end
+end
+function xml.assign(dt,k,root)
+ if dt and k then
+  dt[k]=type(root)=="table" and xml.body(root) or root
+  return dt[k]
+ else
+  return xml.body(root)
+ end
+end
+function xml.tocdata(e,wrapper) 
+ local whatever=type(e)=="table" and xmltostring(e.dt) or e or ""
+ if wrapper then
+  whatever=formatters["<%s>%s</%s>"](wrapper,whatever,wrapper)
+ end
+ local t={ special=true,ns="",tg="@cd@",at={},rn="",dt={ whatever },__p__=e }
+ setmetatable(t,getmetatable(e))
+ e.dt={ t }
+end
+function xml.makestandalone(root)
+ if root.ri then
+  local dt=root.dt
+  for k=1,#dt do
+   local v=dt[k]
+   if type(v)=="table" and v.special and v.tg=="@pi@" then
+    local txt=v.dt[1]
+    if find(txt,"xml.*version=") then
+     v.dt[1]=txt.." standalone='yes'"
+     break
+    end
+   end
+  end
+ end
+ return root
+end
+function xml.kind(e)
+ local dt=e and e.dt
+ if dt then
+  local n=#dt
+  if n==1 then
+   local d=dt[1]
+   if d.special then
+    local tg=d.tg
+    if tg=="@cd@" then
+     return "cdata"
+    elseif tg=="@cm@" then
+     return "comment"
+    elseif tg=="@pi@" then
+     return "instruction"
+    elseif tg=="@dt@" then
+     return "declaration"
+    end
+   elseif type(d)=="string" then
+    return "text"
+   end
+   return "element"
+  elseif n>0 then
+   return "mixed"
+  end
+ end
+ return "empty"
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["lxml-lpt"] = package.loaded["lxml-lpt"] or true
+
+-- original size: 54733, stripped down to: 31258
+
+if not modules then modules={} end modules ['lxml-lpt']={
+ version=1.001,
+ comment="this module is the basis for the lxml-* ones",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local concat,remove,insert=table.concat,table.remove,table.insert
+local type,next,tonumber,tostring,setmetatable,load,select=type,next,tonumber,tostring,setmetatable,load,select
+local format,upper,lower,gmatch,gsub,find,rep=string.format,string.upper,string.lower,string.gmatch,string.gsub,string.find,string.rep
+local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns
+local setmetatableindex=table.setmetatableindex
+local formatters=string.formatters
+local trace_lpath=false
+local trace_lparse=false
+local trace_lprofile=false
+local report_lpath=logs.reporter("xml","lpath")
+if trackers then
+ trackers.register("xml.path",function(v)
+  trace_lpath=v
+ end)
+ trackers.register("xml.parse",function(v)
+  trace_lparse=v
+ end)
+ trackers.register("xml.profile",function(v)
+  trace_lpath=v
+  trace_lparse=v
+  trace_lprofile=v
+ end)
+end
+local xml=xml
+local lpathcalls=0  function xml.lpathcalls () return lpathcalls  end
+local lpathcached=0  function xml.lpathcached() return lpathcached end
+xml.functions=xml.functions or {} 
+local functions=xml.functions
+xml.expressions=xml.expressions or {} 
+local expressions=xml.expressions
+xml.finalizers=xml.finalizers or {} 
+local finalizers=xml.finalizers
+xml.specialhandler=xml.specialhandler or {}
+local specialhandler=xml.specialhandler
+lpegpatterns.xml=lpegpatterns.xml or {}
+local xmlpatterns=lpegpatterns.xml
+finalizers.xml=finalizers.xml or {}
+finalizers.tex=finalizers.tex or {}
+local function fallback (t,name)
+ local fn=finalizers[name]
+ if fn then
+  t[name]=fn
+ else
+  report_lpath("unknown sub finalizer %a",name)
+  fn=function() end
+ end
+ return fn
+end
+setmetatableindex(finalizers.xml,fallback)
+setmetatableindex(finalizers.tex,fallback)
+xml.defaultprotocol="xml"
+local apply_axis={}
+apply_axis['root']=function(list)
+ local collected={}
+ for l=1,#list do
+  local ll=list[l]
+  local rt=ll
+  while ll do
+   ll=ll.__p__
+   if ll then
+    rt=ll
+   end
+  end
+  collected[l]=rt
+ end
+ return collected
+end
+apply_axis['self']=function(list)
+ return list
+end
+apply_axis['child']=function(list)
+ local collected={}
+ local c=0
+ for l=1,#list do
+  local ll=list[l]
+  local dt=ll.dt
+  if dt then 
+   local n=#dt
+   if n==0 then
+    ll.en=0
+   elseif n==1 then
+    local dk=dt[1]
+    if dk.tg then
+     c=c+1
+     collected[c]=dk
+     dk.ni=1 
+     dk.ei=1
+     ll.en=1
+    end
+   else
+    local en=0
+    for k=1,#dt do
+     local dk=dt[k]
+     if dk.tg then
+      c=c+1
+      en=en+1
+      collected[c]=dk
+      dk.ni=k 
+      dk.ei=en
+     end
+    end
+    ll.en=en
+   end
+  end
+ end
+ return collected
+end
+local function collect(list,collected,c)
+ local dt=list.dt
+ if dt then
+  local n=#dt
+  if n==0 then
+   list.en=0
+  elseif n==1 then
+   local dk=dt[1]
+   if dk.tg then
+    c=c+1
+    collected[c]=dk
+    dk.ni=1 
+    dk.ei=1
+    c=collect(dk,collected,c)
+    list.en=1
+   else
+    list.en=0
+   end
+  else
+   local en=0
+   for k=1,n do
+    local dk=dt[k]
+    if dk.tg then
+     c=c+1
+     en=en+1
+     collected[c]=dk
+     dk.ni=k 
+     dk.ei=en
+     c=collect(dk,collected,c)
+    end
+   end
+   list.en=en
+  end
+ end
+ return c
+end
+apply_axis['descendant']=function(list)
+ local collected={}
+ local c=0
+ for l=1,#list do
+  c=collect(list[l],collected,c)
+ end
+ return collected
+end
+local function collect(list,collected,c)
+ local dt=list.dt
+ if dt then
+  local n=#dt
+  if n==0 then
+   list.en=0
+  elseif n==1 then
+   local dk=dt[1]
+   if dk.tg then
+    c=c+1
+    collected[c]=dk
+    dk.ni=1 
+    dk.ei=1
+    c=collect(dk,collected,c)
+    list.en=1
+   end
+  else
+   local en=0
+   for k=1,#dt do
+    local dk=dt[k]
+    if dk.tg then
+     c=c+1
+     en=en+1
+     collected[c]=dk
+     dk.ni=k 
+     dk.ei=en
+     c=collect(dk,collected,c)
+    end
+   end
+   list.en=en
+  end
+ end
+ return c
+end
+apply_axis['descendant-or-self']=function(list)
+ local collected={}
+ local c=0
+ for l=1,#list do
+  local ll=list[l]
+  if ll.special~=true then 
+   c=c+1
+   collected[c]=ll
+  end
+  c=collect(ll,collected,c)
+ end
+ return collected
+end
+apply_axis['ancestor']=function(list)
+ local collected={}
+ local c=0
+ for l=1,#list do
+  local ll=list[l]
+  while ll do
+   ll=ll.__p__
+   if ll then
+    c=c+1
+    collected[c]=ll
+   end
+  end
+ end
+ return collected
+end
+apply_axis['ancestor-or-self']=function(list)
+ local collected={}
+ local c=0
+ for l=1,#list do
+  local ll=list[l]
+  c=c+1
+  collected[c]=ll
+  while ll do
+   ll=ll.__p__
+   if ll then
+    c=c+1
+    collected[c]=ll
+   end
+  end
+ end
+ return collected
+end
+apply_axis['parent']=function(list)
+ local collected={}
+ local c=0
+ for l=1,#list do
+  local pl=list[l].__p__
+  if pl then
+   c=c+1
+   collected[c]=pl
+  end
+ end
+ return collected
+end
+apply_axis['attribute']=function(list)
+ return {}
+end
+apply_axis['namespace']=function(list)
+ return {}
+end
+apply_axis['following']=function(list)
+ return {}
+end
+apply_axis['preceding']=function(list)
+ return {}
+end
+apply_axis['following-sibling']=function(list)
+ local collected={}
+ local c=0
+ for l=1,#list do
+  local ll=list[l]
+  local p=ll.__p__
+  local d=p.dt
+  for i=ll.ni+1,#d do
+   local di=d[i]
+   if type(di)=="table" then
+    c=c+1
+    collected[c]=di
+   end
+  end
+ end
+ return collected
+end
+apply_axis['preceding-sibling']=function(list)
+ local collected={}
+ local c=0
+ for l=1,#list do
+  local ll=list[l]
+  local p=ll.__p__
+  local d=p.dt
+  for i=1,ll.ni-1 do
+   local di=d[i]
+   if type(di)=="table" then
+    c=c+1
+    collected[c]=di
+   end
+  end
+ end
+ return collected
+end
+apply_axis['reverse-sibling']=function(list) 
+ local collected={}
+ local c=0
+ for l=1,#list do
+  local ll=list[l]
+  local p=ll.__p__
+  local d=p.dt
+  for i=ll.ni-1,1,-1 do
+   local di=d[i]
+   if type(di)=="table" then
+    c=c+1
+    collected[c]=di
+   end
+  end
+ end
+ return collected
+end
+apply_axis['auto-descendant-or-self']=apply_axis['descendant-or-self']
+apply_axis['auto-descendant']=apply_axis['descendant']
+apply_axis['auto-child']=apply_axis['child']
+apply_axis['auto-self']=apply_axis['self']
+apply_axis['initial-child']=apply_axis['child']
+local function apply_nodes(list,directive,nodes)
+ local maxn=#nodes
+ if maxn==3 then 
+  local nns=nodes[2]
+  local ntg=nodes[3]
+  if not nns and not ntg then 
+   if directive then
+    return list
+   else
+    return {}
+   end
+  else
+   local collected={}
+   local c=0
+   local m=0
+   local p=nil
+   if not nns then 
+    for l=1,#list do
+     local ll=list[l]
+     local ltg=ll.tg
+     if ltg then
+      if directive then
+       if ntg==ltg then
+        local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end
+        c=c+1
+        collected[c]=ll
+        ll.mi=m
+       end
+      elseif ntg~=ltg then
+       local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end
+       c=c+1
+       collected[c]=ll
+       ll.mi=m
+      end
+     end
+    end
+   elseif not ntg then 
+    for l=1,#list do
+     local ll=list[l]
+     local lns=ll.rn or ll.ns
+     if lns then
+      if directive then
+       if lns==nns then
+        local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end
+        c=c+1
+        collected[c]=ll
+        ll.mi=m
+       end
+      elseif lns~=nns then
+       local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end
+       c=c+1
+       collected[c]=ll
+       ll.mi=m
+      end
+     end
+    end
+   else 
+    for l=1,#list do
+     local ll=list[l]
+     local ltg=ll.tg
+     if ltg then
+      local lns=ll.rn or ll.ns
+      local ok=ltg==ntg and lns==nns
+      if directive then
+       if ok then
+        local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end
+        c=c+1
+        collected[c]=ll
+        ll.mi=m
+       end
+      elseif not ok then
+       local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end
+       c=c+1
+       collected[c]=ll
+       ll.mi=m
+      end
+     end
+    end
+   end
+   return collected
+  end
+ else
+  local collected={}
+  local c=0
+  local m=0
+  local p=nil
+  for l=1,#list do
+   local ll=list[l]
+   local ltg=ll.tg
+   if ltg then
+    local lns=ll.rn or ll.ns
+    local ok=false
+    for n=1,maxn,3 do
+     local nns=nodes[n+1]
+     local ntg=nodes[n+2]
+     ok=(not ntg or ltg==ntg) and (not nns or lns==nns)
+     if ok then
+      break
+     end
+    end
+    if directive then
+     if ok then
+      local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end
+      c=c+1
+      collected[c]=ll
+      ll.mi=m
+     end
+    elseif not ok then
+     local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end
+     c=c+1
+     collected[c]=ll
+     ll.mi=m
+    end
+   end
+  end
+  return collected
+ end
+end
+local quit_expression=false
+local function apply_expression(list,expression,order)
+ local collected={}
+ local c=0
+ quit_expression=false
+ for l=1,#list do
+  local ll=list[l]
+  if expression(list,ll,l,order) then 
+   c=c+1
+   collected[c]=ll
+  end
+  if quit_expression then
+   break
+  end
+ end
+ return collected
+end
+local function apply_selector(list,specification)
+ if xml.applyselector then
+  apply_selector=xml.applyselector
+  return apply_selector(list,specification)
+ else
+  return list
+ end
+end
+local P,V,C,Cs,Cc,Ct,R,S,Cg,Cb=lpeg.P,lpeg.V,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Ct,lpeg.R,lpeg.S,lpeg.Cg,lpeg.Cb
+local spaces=S(" \n\r\t\f")^0
+local lp_space=S(" \n\r\t\f")
+local lp_any=P(1)
+local lp_noequal=P("!=")/"~="+P("<=")+P(">=")+P("==")
+local lp_doequal=P("=")/"=="
+local lp_or=P("|")/" or "
+local lp_and=P("&")/" and "
+local builtin={
+ text="(ll.dt[1] or '')",
+ content="ll.dt",
+ name="((ll.ns~='' and ll.ns..':'..ll.tg) or ll.tg)",
+ tag="ll.tg",
+ position="l",
+ firstindex="1",
+ firstelement="1",
+ first="1",
+ lastindex="(#ll.__p__.dt or 1)",
+ lastelement="(ll.__p__.en or 1)",
+ last="#list",
+ list="list",
+ self="ll",
+ rootposition="order",
+ order="order",
+ element="(ll.ei or 1)",
+ index="(ll.ni or 1)",
+ match="(ll.mi or 1)",
+ namespace="ll.ns",
+ ns="ll.ns",
+}
+local lp_builtin=lpeg.utfchartabletopattern(builtin)/builtin*((spaces*P("(")*spaces*P(")"))/"")
+local lp_attribute=(P("@")+P("attribute::"))/""*Cc("(ll.at and ll.at['")*((R("az","AZ")+S("-_:"))^1)*Cc("'])")
+local lp_fastpos_p=P("+")^0*R("09")^1*P(-1)/"l==%0"
+local lp_fastpos_n=P("-")*R("09")^1*P(-1)/"(%0<0 and (#list+%0+1==l))" 
+local lp_fastpos=lp_fastpos_n+lp_fastpos_p
+local lp_reserved=C("and")+C("or")+C("not")+C("div")+C("mod")+C("true")+C("false")
+local lp_lua_function=Cs((R("az","AZ","__")^1*(P(".")*R("az","AZ","__")^1)^1)*("("))/"%0"
+local lp_function=C(R("az","AZ","__")^1)*P("(")/function(t) 
+ if expressions[t] then
+  return "expr."..t.."("
+ else
+  return "expr.error("
+ end
+end
+local lparent=P("(")
+local rparent=P(")")
+local noparent=1-(lparent+rparent)
+local nested=P{lparent*(noparent+V(1))^0*rparent}
+local value=P(lparent*C((noparent+nested)^0)*rparent) 
+local lp_child=Cc("expr.child(ll,'")*R("az","AZ")*R("az","AZ","--","__")^0*Cc("')")
+local lp_number=S("+-")*R("09")^1
+local lp_string=Cc("'")*R("az","AZ","--","__")^1*Cc("'")
+local lp_content=(P("'")*(1-P("'"))^0*P("'")+P('"')*(1-P('"'))^0*P('"'))
+local cleaner
+local lp_special=(C(P("name")+P("text")+P("tag")+P("count")+P("child")))*value/function(t,s)
+ if expressions[t] then
+  s=s and s~="" and lpegmatch(cleaner,s)
+  if s and s~="" then
+   return "expr."..t.."(ll,"..s..")"
+  else
+   return "expr."..t.."(ll)"
+  end
+ else
+  return "expr.error("..t..")"
+ end
+end
+local content=lp_builtin+lp_attribute+lp_special+lp_noequal+lp_doequal+lp_or+lp_and+lp_reserved+lp_lua_function+lp_function+lp_content+
+ lp_child+lp_any
+local converter=Cs (
+ lp_fastpos+(P { lparent*(V(1))^0*rparent+content } )^0
+)
+cleaner=Cs ((
+ lp_reserved+lp_number+lp_string+1 )^1 )
+local template_e=[[
+    local expr = xml.expressions
+    return function(list,ll,l,order)
+        return %s
+    end
+]]
+local template_f_y=[[
+    local finalizer = xml.finalizers['%s']['%s']
+    return function(collection)
+        return finalizer(collection,%s)
+    end
+]]
+local template_f_n=[[
+    return xml.finalizers['%s']['%s']
+]]
+local register_last_match={ kind="axis",axis="last-match"     } 
+local register_self={ kind="axis",axis="self"     } 
+local register_parent={ kind="axis",axis="parent"      } 
+local register_descendant={ kind="axis",axis="descendant"     } 
+local register_child={ kind="axis",axis="child"       } 
+local register_descendant_or_self={ kind="axis",axis="descendant-or-self"   } 
+local register_root={ kind="axis",axis="root"     } 
+local register_ancestor={ kind="axis",axis="ancestor"    } 
+local register_ancestor_or_self={ kind="axis",axis="ancestor-or-self"  } 
+local register_attribute={ kind="axis",axis="attribute"      } 
+local register_namespace={ kind="axis",axis="namespace"      } 
+local register_following={ kind="axis",axis="following"      } 
+local register_following_sibling={ kind="axis",axis="following-sibling"    } 
+local register_preceding={ kind="axis",axis="preceding"      } 
+local register_preceding_sibling={ kind="axis",axis="preceding-sibling"    } 
+local register_reverse_sibling={ kind="axis",axis="reverse-sibling"   } 
+local register_auto_descendant_or_self={ kind="axis",axis="auto-descendant-or-self" } 
+local register_auto_descendant={ kind="axis",axis="auto-descendant"   } 
+local register_auto_self={ kind="axis",axis="auto-self"      } 
+local register_auto_child={ kind="axis",axis="auto-child"     } 
+local register_initial_child={ kind="axis",axis="initial-child"     } 
+local register_all_nodes={ kind="nodes",nodetest=true,nodes={ true,false,false } }
+local skip={}
+local function errorrunner_e(str,cnv)
+ if not skip[str] then
+  report_lpath("error in expression: %s => %s",str,cnv)
+  skip[str]=cnv or str
+ end
+ return false
+end
+local function errorrunner_f(str,arg)
+ report_lpath("error in finalizer: %s(%s)",str,arg or "")
+ return false
+end
+local function register_nodes(nodetest,nodes)
+ return { kind="nodes",nodetest=nodetest,nodes=nodes }
+end
+local function register_selector(specification)
+ return { kind="selector",specification=specification }
+end
+local function register_expression(expression)
+ local converted=lpegmatch(converter,expression)
+ local wrapped=format(template_e,converted)
+ local runner=load(wrapped)
+ runner=(runner and runner()) or function() errorrunner_e(expression,converted) end
+ return { kind="expression",expression=expression,converted=converted,evaluator=runner }
+end
+local function register_finalizer(protocol,name,arguments)
+ local runner
+ if arguments and arguments~="" then
+  runner=load(format(template_f_y,protocol or xml.defaultprotocol,name,arguments))
+ else
+  runner=load(format(template_f_n,protocol or xml.defaultprotocol,name))
+ end
+ runner=(runner and runner()) or function() errorrunner_f(name,arguments) end
+ return { kind="finalizer",name=name,arguments=arguments,finalizer=runner }
+end
+local expression=P { "ex",
+ ex="["*C((V("sq")+V("dq")+(1-S("[]"))+V("ex"))^0)*"]",
+ sq="'"*(1-S("'"))^0*"'",
+ dq='"'*(1-S('"'))^0*'"',
+}
+local arguments=P { "ar",
+ ar="("*Cs((V("sq")+V("dq")+V("nq")+P(1-P(")")))^0)*")",
+ nq=((1-S("),'\""))^1)/function(s) return format("%q",s) end,
+ sq=P("'")*(1-P("'"))^0*P("'"),
+ dq=P('"')*(1-P('"'))^0*P('"'),
+}
+local function register_error(str)
+ return { kind="error",error=format("unparsed: %s",str) }
+end
+local special_1=P("*")*Cc(register_auto_descendant)*Cc(register_all_nodes) 
+local special_2=P("/")*Cc(register_auto_self)
+local special_3=P("")*Cc(register_auto_self)
+local no_nextcolon=P(-1)+#(1-P(":")) 
+local no_nextlparent=P(-1)+#(1-P("(")) 
+local pathparser=Ct { "patterns",
+ patterns=spaces*V("protocol")*spaces*(
+         (V("special")*spaces*P(-1)               )+(V("initial")*spaces*V("step")*spaces*(P("/")*spaces*V("step")*spaces)^0 )
+         ),
+ protocol=Cg(V("letters"),"protocol")*P("://")+Cg(Cc(nil),"protocol"),
+ step=((V("shortcuts")+V("selector")+P("/")+V("axis"))*spaces*V("nodes")^0+V("error"))*spaces*V("expressions")^0*spaces*V("finalizer")^0,
+ axis=V("last_match")+V("descendant")+V("child")+V("parent")+V("self")+V("root")+V("ancestor")+V("descendant_or_self")+V("following_sibling")+V("following")+V("reverse_sibling")+V("preceding_sibling")+V("preceding")+V("ancestor_or_self")+#(1-P(-1))*Cc(register_auto_child),
+ special=special_1+special_2+special_3,
+ initial=(P("/")*spaces*Cc(register_initial_child))^-1,
+ error=(P(1)^1)/register_error,
+ shortcuts_a=V("s_descendant_or_self")+V("s_descendant")+V("s_child")+V("s_parent")+V("s_self")+V("s_root")+V("s_ancestor")+V("s_lastmatch"),
+ shortcuts=V("shortcuts_a")*(spaces*"/"*spaces*V("shortcuts_a"))^0,
+ s_descendant_or_self=(P("***/")+P("/"))*Cc(register_descendant_or_self),
+ s_descendant=P("**")*Cc(register_descendant),
+ s_child=P("*")*no_nextcolon*Cc(register_child),
+ s_parent=P("..")*Cc(register_parent),
+ s_self=P("." )*Cc(register_self),
+ s_root=P("^^")*Cc(register_root),
+ s_ancestor=P("^")*Cc(register_ancestor),
+ s_lastmatch=P("=")*Cc(register_last_match),
+ descendant=P("descendant::")*Cc(register_descendant),
+ child=P("child::")*Cc(register_child),
+ parent=P("parent::")*Cc(register_parent),
+ self=P("self::")*Cc(register_self),
+ root=P('root::')*Cc(register_root),
+ ancestor=P('ancestor::')*Cc(register_ancestor),
+ descendant_or_self=P('descendant-or-self::')*Cc(register_descendant_or_self),
+ ancestor_or_self=P('ancestor-or-self::')*Cc(register_ancestor_or_self),
+ following=P('following::')*Cc(register_following),
+ following_sibling=P('following-sibling::')*Cc(register_following_sibling),
+ preceding=P('preceding::')*Cc(register_preceding),
+ preceding_sibling=P('preceding-sibling::')*Cc(register_preceding_sibling),
+ reverse_sibling=P('reverse-sibling::')*Cc(register_reverse_sibling),
+ last_match=P('last-match::')*Cc(register_last_match),
+ selector=P("{")*C((1-P("}"))^1)*P("}")/register_selector,
+ nodes=(V("nodefunction")*spaces*P("(")*V("nodeset")*P(")")+V("nodetest")*V("nodeset"))/register_nodes,
+ expressions=expression/register_expression,
+ letters=R("az")^1,
+ name=(1-S("/[]()|:*!"))^1,
+ negate=P("!")*Cc(false),
+ nodefunction=V("negate")+P("not")*Cc(false)+Cc(true),
+ nodetest=V("negate")+Cc(true),
+ nodename=(V("negate")+Cc(true))*spaces*((V("wildnodename")*P(":")*V("wildnodename"))+(Cc(false)*V("wildnodename"))),
+ wildnodename=(C(V("name"))+P("*")*Cc(false))*no_nextlparent,
+ nodeset=spaces*Ct(V("nodename")*(spaces*P("|")*spaces*V("nodename"))^0)*spaces,
+ finalizer=(Cb("protocol")*P("/")^-1*C(V("name"))*arguments*P(-1))/register_finalizer,
+}
+xmlpatterns.pathparser=pathparser
+local cache={}
+local function nodesettostring(set,nodetest)
+ local t={}
+ for i=1,#set,3 do
+  local directive,ns,tg=set[i],set[i+1],set[i+2]
+  if not ns or ns=="" then ns="*" end
+  if not tg or tg=="" then tg="*" end
+  tg=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg)
+  t[#t+1]=(directive and tg) or format("not(%s)",tg)
+ end
+ if nodetest==false then
+  return format("not(%s)",concat(t,"|"))
+ else
+  return concat(t,"|")
+ end
+end
+local function tagstostring(list)
+ if #list==0 then
+  return "no elements"
+ else
+  local t={}
+  for i=1,#list do
+   local li=list[i]
+   local ns=li.ns
+   local tg=li.tg
+   if not ns or ns=="" then ns="*" end
+   if not tg or tg=="" then tg="*" end
+   t[i]=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg)
+  end
+  return concat(t," ")
+ end
+end
+xml.nodesettostring=nodesettostring
+local lpath 
+local function lshow(parsed)
+ if type(parsed)=="string" then
+  parsed=lpath(parsed)
+ end
+ report_lpath("%s://%s => %s",parsed.protocol or xml.defaultprotocol,parsed.pattern,
+  table.serialize(parsed,false))
+end
+xml.lshow=lshow
+local function add_comment(p,str)
+ local pc=p.comment
+ if not pc then
+  p.comment={ str }
+ else
+  pc[#pc+1]=str
+ end
+end
+lpath=function (pattern) 
+ lpathcalls=lpathcalls+1
+ if type(pattern)=="table" then
+  return pattern
+ else
+  local parsed=cache[pattern]
+  if parsed then
+   lpathcached=lpathcached+1
+  else
+   parsed=lpegmatch(pathparser,pattern)
+   if parsed then
+    parsed.pattern=pattern
+    local np=#parsed
+    if np==0 then
+     parsed={ pattern=pattern,register_self,state="parsing error" }
+     report_lpath("parsing error in pattern: %s",pattern)
+     lshow(parsed)
+    else
+     local pi=parsed[1]
+     if pi.axis=="auto-child" then
+      if false then
+       add_comment(parsed,"auto-child replaced by auto-descendant-or-self")
+       parsed[1]=register_auto_descendant_or_self
+      else
+       add_comment(parsed,"auto-child replaced by auto-descendant")
+       parsed[1]=register_auto_descendant
+      end
+     elseif pi.axis=="initial-child" and np>1 and parsed[2].axis then
+      add_comment(parsed,"initial-child removed") 
+      remove(parsed,1)
+     end
+     local np=#parsed 
+     if np>1 then
+      local pnp=parsed[np]
+      if pnp.kind=="nodes" and pnp.nodetest==true then
+       local nodes=pnp.nodes
+       if nodes[1]==true and nodes[2]==false and nodes[3]==false then
+        add_comment(parsed,"redundant final wildcard filter removed")
+        remove(parsed,np)
+       end
+      end
+     end
+    end
+   else
+    parsed={ pattern=pattern }
+   end
+   cache[pattern]=parsed
+   if trace_lparse and not trace_lprofile then
+    lshow(parsed)
+   end
+  end
+  return parsed
+ end
+end
+xml.lpath=lpath
+do
+ local profiled={}
+ xml.profiled=profiled
+ local lastmatch=nil  
+ local keepmatch=nil  
+ if directives then
+  directives.register("xml.path.keeplastmatch",function(v)
+   keepmatch=v
+   lastmatch=nil
+  end)
+ end
+ apply_axis["last-match"]=function()
+  return lastmatch or {}
+ end
+ local function profiled_apply(list,parsed,nofparsed,order)
+  local p=profiled[parsed.pattern]
+  if p then
+   p.tested=p.tested+1
+  else
+   p={ tested=1,matched=0,finalized=0 }
+   profiled[parsed.pattern]=p
+  end
+  local collected=list
+  for i=1,nofparsed do
+   local pi=parsed[i]
+   local kind=pi.kind
+   if kind=="axis" then
+    collected=apply_axis[pi.axis](collected)
+   elseif kind=="nodes" then
+    collected=apply_nodes(collected,pi.nodetest,pi.nodes)
+   elseif kind=="expression" then
+    collected=apply_expression(collected,pi.evaluator,order)
+   elseif kind=="selector" then
+    collected=apply_selector(collected,pi.specification)
+   elseif kind=="finalizer" then
+    collected=pi.finalizer(collected) 
+    p.matched=p.matched+1
+    p.finalized=p.finalized+1
+    return collected
+   end
+   if not collected or #collected==0 then
+    local pn=i<nofparsed and parsed[nofparsed]
+    if pn and pn.kind=="finalizer" then
+     collected=pn.finalizer(collected) 
+     p.finalized=p.finalized+1
+     return collected
+    end
+    return nil
+   end
+  end
+  if collected then
+   p.matched=p.matched+1
+  end
+  return collected
+ end
+ local function traced_apply(list,parsed,nofparsed,order)
+  if trace_lparse then
+   lshow(parsed)
+  end
+  report_lpath("collecting: %s",parsed.pattern)
+  report_lpath("root tags : %s",tagstostring(list))
+  report_lpath("order     : %s",order or "unset")
+  local collected=list
+  for i=1,nofparsed do
+   local pi=parsed[i]
+   local kind=pi.kind
+   if kind=="axis" then
+    collected=apply_axis[pi.axis](collected)
+    report_lpath("% 10i : ax : %s",(collected and #collected) or 0,pi.axis)
+   elseif kind=="nodes" then
+    collected=apply_nodes(collected,pi.nodetest,pi.nodes)
+    report_lpath("% 10i : ns : %s",(collected and #collected) or 0,nodesettostring(pi.nodes,pi.nodetest))
+   elseif kind=="expression" then
+    collected=apply_expression(collected,pi.evaluator,order)
+    report_lpath("% 10i : ex : %s -> %s",(collected and #collected) or 0,pi.expression,pi.converted)
+   elseif kind=="selector" then
+    collected=apply_selector(collected,pi.specification)
+    report_lpath("% 10i : se : %s ",(collected and #collected) or 0,pi.specification)
+   elseif kind=="finalizer" then
+    collected=pi.finalizer(collected)
+    report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pi.name,pi.arguments or "")
+    return collected
+   end
+   if not collected or #collected==0 then
+    local pn=i<nofparsed and parsed[nofparsed]
+    if pn and pn.kind=="finalizer" then
+     collected=pn.finalizer(collected)
+     report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pn.name,pn.arguments or "")
+     return collected
+    end
+    return nil
+   end
+  end
+  return collected
+ end
+ local function normal_apply(list,parsed,nofparsed,order)
+  local collected=list
+  for i=1,nofparsed do
+   local pi=parsed[i]
+   local kind=pi.kind
+   if kind=="axis" then
+    local axis=pi.axis
+    if axis~="self" then
+     collected=apply_axis[axis](collected)
+    end
+   elseif kind=="nodes" then
+    collected=apply_nodes(collected,pi.nodetest,pi.nodes)
+   elseif kind=="expression" then
+    collected=apply_expression(collected,pi.evaluator,order)
+   elseif kind=="selector" then
+    collected=apply_selector(collected,pi.specification)
+   elseif kind=="finalizer" then
+    return pi.finalizer(collected)
+   end
+   if not collected or #collected==0 then
+    local pf=i<nofparsed and parsed[nofparsed].finalizer
+    if pf then
+     return pf(collected) 
+    end
+    return nil
+   end
+  end
+  return collected
+ end
+ local apply=normal_apply
+ if trackers then
+  trackers.register("xml.path,xml.parse,xml.profile",function()
+   if trace_lprofile then
+    apply=profiled_apply
+   elseif trace_lpath then
+    apply=traced_apply
+   else
+    apply=normal_apply
+   end
+  end)
+ end
+ function xml.applylpath(list,pattern)
+  if not list then
+   lastmatch=nil
+   return
+  end
+  local parsed=cache[pattern]
+  if parsed then
+   lpathcalls=lpathcalls+1
+   lpathcached=lpathcached+1
+  elseif type(pattern)=="table" then
+   lpathcalls=lpathcalls+1
+   parsed=pattern
+  else
+   parsed=lpath(pattern) or pattern
+  end
+  if not parsed then
+   lastmatch=nil
+   return
+  end
+  local nofparsed=#parsed
+  if nofparsed==0 then
+   lastmatch=nil
+   return 
+  end
+  local collected=apply({ list },parsed,nofparsed,list.mi)
+  lastmatch=keepmatch and collected or nil
+  return collected
+ end
+ function xml.lastmatch()
+  return lastmatch
+ end
+ local stack={}
+ function xml.pushmatch()
+  insert(stack,lastmatch)
+ end
+ function xml.popmatch()
+  lastmatch=remove(stack)
+ end
+end
+local applylpath=xml.applylpath
+function xml.filter(root,pattern) 
+ return applylpath(root,pattern)
+end
+expressions.child=function(e,pattern)
+ return applylpath(e,pattern) 
+end
+expressions.count=function(e,pattern) 
+ local collected=applylpath(e,pattern) 
+ return pattern and (collected and #collected) or 0
+end
+expressions.attribute=function(e,name,value)
+ if type(e)=="table" and name then
+  local a=e.at
+  if a then
+   local v=a[name]
+   if value then
+    return v==value
+   else
+    return v
+   end
+  end
+ end
+ return nil
+end
+expressions.oneof=function(s,...)
+ for i=1,select("#",...) do
+  if s==select(i,...) then
+   return true
+  end
+ end
+ return false
+end
+expressions.error=function(str)
+ xml.errorhandler(format("unknown function in lpath expression: %s",tostring(str or "?")))
+ return false
+end
+expressions.undefined=function(s)
+ return s==nil
+end
+expressions.quit=function(s)
+ if s or s==nil then
+  quit_expression=true
+ end
+ return true
+end
+expressions.print=function(...)
+ print(...)
+ return true
+end
+expressions.find=find
+expressions.upper=upper
+expressions.lower=lower
+expressions.number=tonumber
+expressions.boolean=toboolean
+function expressions.contains(str,pattern)
+ local t=type(str)
+ if t=="string" then
+  if find(str,pattern) then
+   return true
+  end
+ elseif t=="table" then
+  for i=1,#str do
+   local d=str[i]
+   if type(d)=="string" and find(d,pattern) then
+    return true
+   end
+  end
+ end
+ return false
+end
+function expressions.idstring(str)
+ return type(str)=="string" and gsub(str,"^#","") or ""
+end
+local function traverse(root,pattern,handle)
+ local collected=applylpath(root,pattern)
+ if collected then
+  for c=1,#collected do
+   local e=collected[c]
+   local r=e.__p__
+   handle(r,r.dt,e.ni)
+  end
+ end
+end
+local function selection(root,pattern,handle)
+ local collected=applylpath(root,pattern)
+ if collected then
+  if handle then
+   for c=1,#collected do
+    handle(collected[c])
+   end
+  else
+   return collected
+  end
+ end
+end
+xml.traverse=traverse     
+xml.selection=selection
+local function dofunction(collected,fnc,...)
+ if collected then
+  local f=functions[fnc]
+  if f then
+   for c=1,#collected do
+    f(collected[c],...)
+   end
+  else
+   report_lpath("unknown function %a",fnc)
+  end
+ end
+end
+finalizers.xml["function"]=dofunction
+finalizers.tex["function"]=dofunction
+expressions.text=function(e,n)
+ local rdt=e.__p__.dt
+ return rdt and rdt[n] or ""
+end
+expressions.name=function(e,n) 
+ local found=false
+ n=tonumber(n) or 0
+ if n==0 then
+  found=type(e)=="table" and e
+ elseif n<0 then
+  local d=e.__p__.dt
+  local k=e.ni
+  for i=k-1,1,-1 do
+   local di=d[i]
+   if type(di)=="table" then
+    if n==-1 then
+     found=di
+     break
+    else
+     n=n+1
+    end
+   end
+  end
+ else
+  local d=e.__p__.dt
+  local k=e.ni
+  for i=k+1,#d,1 do
+   local di=d[i]
+   if type(di)=="table" then
+    if n==1 then
+     found=di
+     break
+    else
+     n=n-1
+    end
+   end
+  end
+ end
+ if found then
+  local ns=found.rn or found.ns or ""
+  local tg=found.tg
+  if ns~="" then
+   return ns..":"..tg
+  else
+   return tg
+  end
+ else
+  return ""
+ end
+end
+expressions.tag=function(e,n) 
+ if not e then
+  return ""
+ else
+  local found=false
+  n=tonumber(n) or 0
+  if n==0 then
+   found=(type(e)=="table") and e 
+  elseif n<0 then
+   local d=e.__p__.dt
+   local k=e.ni
+   for i=k-1,1,-1 do
+    local di=d[i]
+    if type(di)=="table" then
+     if n==-1 then
+      found=di
+      break
+     else
+      n=n+1
+     end
+    end
+   end
+  else
+   local d=e.__p__.dt
+   local k=e.ni
+   for i=k+1,#d,1 do
+    local di=d[i]
+    if type(di)=="table" then
+     if n==1 then
+      found=di
+      break
+     else
+      n=n-1
+     end
+    end
+   end
+  end
+  return (found and found.tg) or ""
+ end
+end
+local dummy=function() end
+function xml.elements(root,pattern,reverse) 
+ local collected=applylpath(root,pattern)
+ if not collected then
+  return dummy
+ end
+ local n=#collected
+ if n==0 then
+  return dummy
+ end
+ if reverse then
+  local c=n+1
+  return function()
+   if c>1 then
+    c=c-1
+    local e=collected[c]
+    local r=e.__p__
+    return r,r.dt,e.ni
+   end
+  end
+ else
+  local c=0
+  return function()
+   if c<n then
+    c=c+1
+    local e=collected[c]
+    local r=e.__p__
+    return r,r.dt,e.ni
+   end
+  end
+ end
+end
+function xml.collected(root,pattern,reverse) 
+ local collected=applylpath(root,pattern)
+ if not collected then
+  return dummy
+ end
+ local n=#collected
+ if n==0 then
+  return dummy
+ end
+ if reverse then
+  local c=n+1
+  return function()
+   if c>1 then
+    c=c-1
+    return collected[c]
+   end
+  end
+ else
+  local c=0
+  return function()
+   if c<n then
+    c=c+1
+    return collected[c]
+   end
+  end
+ end
+end
+function xml.inspect(collection,pattern)
+ pattern=pattern or "."
+ for e in xml.collected(collection,pattern or ".") do
+  report_lpath("pattern: %s\n\n%s\n",pattern,xml.tostring(e))
+ end
+end
+local function split(e) 
+ local dt=e.dt
+ if dt then
+  for i=1,#dt do
+   local dti=dt[i]
+   if type(dti)=="string" then
+    dti=gsub(dti,"^[\n\r]*(.-)[\n\r]*","%1")
+    dti=gsub(dti,"[\n\r]+","\n\n")
+    dt[i]=dti
+   else
+    split(dti)
+   end
+  end
+ end
+ return e
+end
+function xml.finalizers.paragraphs(c)
+ for i=1,#c do
+  split(c[i])
+ end
+ return c
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["lxml-mis"] = package.loaded["lxml-mis"] or true
+
+-- original size: 3574, stripped down to: 1808
+
+if not modules then modules={} end modules ['lxml-mis']={
+ version=1.001,
+ comment="this module is the basis for the lxml-* ones",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local xml,lpeg,string=xml,lpeg,string
+local type=type
+local concat=table.concat
+local format,gsub,match=string.format,string.gsub,string.match
+local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns
+local P,S,R,C,V,Cc,Cs=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.V,lpeg.Cc,lpeg.Cs
+lpegpatterns.xml=lpegpatterns.xml or {}
+local xmlpatterns=lpegpatterns.xml
+local function xmlgsub(t,old,new) 
+ local dt=t.dt
+ if dt then
+  for k=1,#dt do
+   local v=dt[k]
+   if type(v)=="string" then
+    dt[k]=gsub(v,old,new)
+   else
+    xmlgsub(v,old,new)
+   end
+  end
+ end
+end
+function xml.stripleadingspaces(dk,d,k) 
+ if d and k then
+  local dkm=d[k-1]
+  if dkm and type(dkm)=="string" then
+   local s=match(dkm,"\n(%s+)")
+   xmlgsub(dk,"\n"..rep(" ",#s),"\n")
+  end
+ end
+end
+local normal=(1-S("<&>"))^0
+local special=P("<")/"<"+P(">")/">"+P("&")/"&"
+local escaped=Cs(normal*(special*normal)^0)
+local normal=(1-S"&")^0
+local special=P("<")/"<"+P(">")/">"+P("&")/"&"
+local unescaped=Cs(normal*(special*normal)^0)
+local cleansed=Cs(((P("<")*(1-P(">"))^0*P(">"))/""+1)^0)
+xmlpatterns.escaped=escaped
+xmlpatterns.unescaped=unescaped
+xmlpatterns.cleansed=cleansed
+function xml.escaped  (str) return lpegmatch(escaped,str)   end
+function xml.unescaped(str) return lpegmatch(unescaped,str) end
+function xml.cleansed (str) return lpegmatch(cleansed,str)  end
+function xml.fillin(root,pattern,str,check)
+ local e=xml.first(root,pattern)
+ if e then
+  local n=#e.dt
+  if not check or n==0 or (n==1 and e.dt[1]=="") then
+   e.dt={ str }
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["lxml-aux"] = package.loaded["lxml-aux"] or true
+
+-- original size: 34661, stripped down to: 21511
+
+if not modules then modules={} end modules ['lxml-aux']={
+ version=1.001,
+ comment="this module is the basis for the lxml-* ones",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local trace_manipulations=false  trackers.register("lxml.manipulations",function(v) trace_manipulations=v end)
+local trace_inclusions=false  trackers.register("lxml.inclusions",function(v) trace_inclusions=v end)
+local report_xml=logs.reporter("xml")
+local xml=xml
+local xmlcopy,xmlname=xml.copy,xml.name
+local xmlinheritedconvert=xml.inheritedconvert
+local xmlapplylpath=xml.applylpath
+local type,next,setmetatable,getmetatable=type,next,setmetatable,getmetatable
+local insert,remove,fastcopy,concat=table.insert,table.remove,table.fastcopy,table.concat
+local gmatch,gsub,format,find,strip,match=string.gmatch,string.gsub,string.format,string.find,string.strip,string.match
+local utfbyte=utf.byte
+local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns
+local striplinepatterns=utilities.strings.striplinepatterns
+local function report(what,pattern,c,e)
+ report_xml("%s element %a, root %a, position %a, index %a, pattern %a",what,xmlname(e),xmlname(e.__p__),c,e.ni,pattern)
+end
+local function withelements(e,handle,depth)
+ if e and handle then
+  local edt=e.dt
+  if edt then
+   depth=depth or 0
+   for i=1,#edt do
+    local e=edt[i]
+    if type(e)=="table" then
+     handle(e,depth)
+     withelements(e,handle,depth+1)
+    end
+   end
+  end
+ end
+end
+xml.withelements=withelements
+function xml.withelement(e,n,handle) 
+ if e and n~=0 and handle then
+  local edt=e.dt
+  if edt then
+   if n>0 then
+    for i=1,#edt do
+     local ei=edt[i]
+     if type(ei)=="table" then
+      if n==1 then
+       handle(ei)
+       return
+      else
+       n=n-1
+      end
+     end
+    end
+   elseif n<0 then
+    for i=#edt,1,-1 do
+     local ei=edt[i]
+     if type(ei)=="table" then
+      if n==-1 then
+       handle(ei)
+       return
+      else
+       n=n+1
+      end
+     end
+    end
+   end
+  end
+ end
+end
+function xml.each(root,pattern,handle,reverse)
+ local collected=xmlapplylpath(root,pattern)
+ if collected then
+  if handle then
+   if reverse then
+    for c=#collected,1,-1 do
+     handle(collected[c])
+    end
+   else
+    for c=1,#collected do
+     handle(collected[c])
+    end
+   end
+  end
+  return collected
+ end
+end
+function xml.processattributes(root,pattern,handle)
+ local collected=xmlapplylpath(root,pattern)
+ if collected and handle then
+  for c=1,#collected do
+   handle(collected[c].at)
+  end
+ end
+ return collected
+end
+function xml.collect(root,pattern)
+ return xmlapplylpath(root,pattern)
+end
+function xml.collecttexts(root,pattern,flatten) 
+ local collected=xmlapplylpath(root,pattern)
+ if collected and flatten then
+  local xmltostring=xml.tostring
+  for c=1,#collected do
+   collected[c]=xmltostring(collected[c].dt)
+  end
+ end
+ return collected or {}
+end
+function xml.collect_tags(root,pattern,nonamespace)
+ local collected=xmlapplylpath(root,pattern)
+ if collected then
+  local t={}
+  local n=0
+  for c=1,#collected do
+   local e=collected[c]
+   local ns=e.ns
+   local tg=e.tg
+   n=n+1
+   if nonamespace then
+    t[n]=tg
+   elseif ns=="" then
+    t[n]=tg
+   else
+    t[n]=ns..":"..tg
+   end
+  end
+  return t
+ end
+end
+local no_root={ no_root=true }
+local function redo_ni(d)
+ for k=1,#d do
+  local dk=d[k]
+  if type(dk)=="table" then
+   dk.ni=k
+  end
+ end
+end
+xml.reindex=redo_ni
+local function xmltoelement(whatever,root)
+ if not whatever then
+  return nil
+ end
+ local element
+ if type(whatever)=="string" then
+  element=xmlinheritedconvert(whatever,root,true) 
+ else
+  element=whatever 
+ end
+ if element.error then
+  return whatever 
+ end
+ if element then
+ end
+ return element
+end
+xml.toelement=xmltoelement
+local function copiedelement(element,newparent)
+ if type(element)~="string" then
+  element=xmlcopy(element).dt
+  if newparent and type(element)=="table" then
+   for i=1,#element do
+    local e=element[i]
+    if type(e)=="table" then
+     e.__p__=newparent
+    end
+   end
+  end
+ end
+ return element
+end
+function xml.delete(root,pattern)
+ if not pattern or pattern=="" then
+  local p=root.__p__
+  if p then
+   if trace_manipulations then
+    report('deleting',"--",c,root)
+   end
+   local d=p.dt
+   remove(d,root.ni)
+   redo_ni(d) 
+  end
+ else
+  local collected=xmlapplylpath(root,pattern)
+  if collected then
+   for c=1,#collected do
+    local e=collected[c]
+    local p=e.__p__
+    if p then
+     if trace_manipulations then
+      report('deleting',pattern,c,e)
+     end
+     local d=p.dt
+     local ni=e.ni
+     if ni<=#d then
+      if false then
+       p.dt[ni]=""
+      else
+       remove(d,ni)
+       redo_ni(d) 
+      end
+     else
+     end
+    end
+   end
+  end
+ end
+end
+function xml.wipe(root,pattern) 
+ local collected=xmlapplylpath(root,pattern)
+ if collected then
+  for c=1,#collected do
+   local e=collected[c]
+   local p=e.__p__
+   if p then
+    local d=p.dt
+    local ni=e.ni
+    if ni<=#d then
+     local dt=e.dt
+     if #dt==1 then
+      local d1=dt[1]
+      if type(d1)=="string" and match(d1,"^%s*$") then
+       if trace_manipulations then
+        report('wiping',pattern,c,e)
+       end
+       remove(d,ni)
+       redo_ni(d) 
+      end
+     end
+    end
+   end
+  end
+ end
+end
+function xml.replace(root,pattern,whatever)
+ local element=root and xmltoelement(whatever,root)
+ local collected=element and xmlapplylpath(root,pattern)
+ if collected then
+  for c=1,#collected do
+   local e=collected[c]
+   local p=e.__p__
+   if p then
+    if trace_manipulations then
+     report('replacing',pattern,c,e)
+    end
+    local d=p.dt
+    local n=e.ni
+    local t=copiedelement(element,p)
+    if type(t)=="table" then
+     d[n]=t[1]
+     for i=2,#t do
+      n=n+1
+      insert(d,n,t[i])
+     end
+    else
+     d[n]=t
+    end
+    redo_ni(d) 
+   end
+  end
+ end
+end
+function xml.expand(root,pattern,whatever)
+ local collected=root and xmlapplylpath(root,pattern)
+ if collected then
+  for c=1,#collected do
+   local e=collected[c]
+   local p=e.__p__
+   if p then
+    if trace_manipulations then
+     report('expanding',pattern,c,e)
+    end
+    local d=p.dt
+    local n=e.ni
+    local t=whatever(e,p)
+    if t then
+     if type(t)=="table" then
+      t=xmlcopy(t)
+      d[n]=t[1]
+      for i=2,#t do
+       n=n+1
+       insert(d,n,t[i])
+      end
+     else
+      d[n]=t
+     end
+     redo_ni(d) 
+    end
+   end
+  end
+ end
+end
+local function wrap(e,wrapper)
+ local t={
+  rn=e.rn,
+  tg=e.tg,
+  ns=e.ns,
+  at=e.at,
+  dt=e.dt,
+  __p__=e,
+ }
+ setmetatable(t,getmetatable(e))
+ e.rn=wrapper.rn or e.rn or ""
+ e.tg=wrapper.tg or e.tg or ""
+ e.ns=wrapper.ns or e.ns or ""
+ e.at=fastcopy(wrapper.at)
+ e.dt={ t }
+end
+function xml.wrap(root,pattern,whatever)
+ if whatever then
+  local wrapper=xmltoelement(whatever,root)
+  local collected=xmlapplylpath(root,pattern)
+  if collected then
+   for c=1,#collected do
+    local e=collected[c]
+    if trace_manipulations then
+     report('wrapping',pattern,c,e)
+    end
+    wrap(e,wrapper)
+   end
+  end
+ else
+  wrap(root,xmltoelement(pattern))
+ end
+end
+local function inject_element(root,pattern,whatever,prepend)
+ local element=root and xmltoelement(whatever,root)
+ local collected=element and xmlapplylpath(root,pattern)
+ local function inject_e(e)
+  local r=e.__p__
+  local d=r.dt
+  local k=e.ni
+  local rri=r.ri
+  local edt=(rri and d[rri].dt) or (d and d[k] and d[k].dt)
+  if edt then
+   local be,af
+   local cp=copiedelement(element,e)
+   if prepend then
+    be,af=cp,edt
+   else
+    be,af=edt,cp
+   end
+   local bn=#be
+   for i=1,#af do
+    bn=bn+1
+    be[bn]=af[i]
+   end
+   if rri then
+    r.dt[rri].dt=be
+   else
+    d[k].dt=be
+   end
+   redo_ni(d)
+  end
+ end
+ if not collected then
+ elseif collected.tg then
+  inject_e(collected)
+ else
+  for c=1,#collected do
+   inject_e(collected[c])
+  end
+ end
+end
+local function insert_element(root,pattern,whatever,before) 
+ local element=root and xmltoelement(whatever,root)
+ local collected=element and xmlapplylpath(root,pattern)
+ local function insert_e(e)
+  local r=e.__p__
+  local d=r.dt
+  local k=e.ni
+  if not before then
+   k=k+1
+  end
+  insert(d,k,copiedelement(element,r))
+  redo_ni(d)
+ end
+ if not collected then
+ elseif collected.tg then
+  insert_e(collected)
+ else
+  for c=1,#collected do
+   insert_e(collected[c])
+  end
+ end
+end
+xml.insert_element=insert_element
+xml.insertafter=insert_element
+xml.insertbefore=function(r,p,e) insert_element(r,p,e,true) end
+xml.injectafter=inject_element
+xml.injectbefore=function(r,p,e) inject_element(r,p,e,true) end
+local function include(xmldata,pattern,attribute,recursive,loaddata,level)
+ pattern=pattern or 'include'
+ loaddata=loaddata or io.loaddata
+ local collected=xmlapplylpath(xmldata,pattern)
+ if collected then
+  if not level then
+   level=1
+  end
+  for c=1,#collected do
+   local ek=collected[c]
+   local name=nil
+   local ekdt=ek.dt
+   if ekdt then
+    local ekat=ek.at
+    local ekrt=ek.__p__
+    if ekrt then
+     local epdt=ekrt.dt
+     if not attribute or attribute=="" then
+      name=(type(ekdt)=="table" and ekdt[1]) or ekdt 
+     end
+     if not name then
+      for a in gmatch(attribute or "href","([^|]+)") do
+       name=ekat[a]
+       if name then
+        break
+       end
+      end
+     end
+     local data=nil
+     if name and name~="" then
+      local d,n=loaddata(name)
+      data=d or ""
+      name=n or name
+      if trace_inclusions then
+       report_xml("including %s bytes from %a at level %s by pattern %a and attribute %a (%srecursing)",#data,name,level,pattern,attribute or "",recursive and "" or "not ")
+      end
+     end
+     if not data or data=="" then
+      epdt[ek.ni]="" 
+     elseif ekat["parse"]=="text" then
+      epdt[ek.ni]=xml.escaped(data) 
+     else
+      local settings=xmldata.settings
+      local savedresource=settings.currentresource
+      settings.currentresource=name
+      local xi=xmlinheritedconvert(data,xmldata,true)
+      if not xi then
+       epdt[ek.ni]="" 
+      else
+       if recursive then
+        include(xi,pattern,attribute,recursive,loaddata,level+1)
+       end
+       local child=xml.body(xi) 
+       child.__p__=ekrt
+       child.__f__=name 
+       child.cf=name
+       epdt[ek.ni]=child
+       local settings=xmldata.settings
+       local inclusions=settings and settings.inclusions
+       if inclusions then
+        inclusions[#inclusions+1]=name
+       elseif settings then
+        settings.inclusions={ name }
+       else
+        settings={ inclusions={ name } }
+        xmldata.settings=settings
+       end
+       if child.er then
+        local badinclusions=settings.badinclusions
+        if badinclusions then
+         badinclusions[#badinclusions+1]=name
+        else
+         settings.badinclusions={ name }
+        end
+       end
+      end
+settings.currentresource=savedresource
+     end
+    end
+   end
+  end
+ end
+end
+xml.include=include
+function xml.inclusion(e,default)
+ while e do
+  local f=e.__f__
+  if f then
+   return f
+  else
+   e=e.__p__
+  end
+ end
+ return default
+end
+local function getinclusions(key,e,sorted)
+ while e do
+  local settings=e.settings
+  if settings then
+   local inclusions=settings[key]
+   if inclusions then
+    inclusions=table.unique(inclusions) 
+    if sorted then
+     table.sort(inclusions) 
+    end
+    return inclusions 
+   else
+    e=e.__p__
+   end
+  else
+   e=e.__p__
+  end
+ end
+end
+function xml.inclusions(e,sorted)
+ return getinclusions("inclusions",e,sorted)
+end
+function xml.badinclusions(e,sorted)
+ return getinclusions("badinclusions",e,sorted)
+end
+local b_collapser=lpegpatterns.b_collapser
+local m_collapser=lpegpatterns.m_collapser
+local e_collapser=lpegpatterns.e_collapser
+local x_collapser=lpegpatterns.x_collapser
+local b_stripper=lpegpatterns.b_stripper
+local m_stripper=lpegpatterns.m_stripper
+local e_stripper=lpegpatterns.e_stripper
+local x_stripper=lpegpatterns.x_stripper
+local function stripelement(e,nolines,anywhere,everything)
+ local edt=e.dt
+ if edt then
+  local n=#edt
+  if n==0 then
+   return e 
+  elseif everything then
+   local t={}
+   local m=0
+   for i=1,n do
+    local str=edt[i]
+    if type(str)~="string" then
+     m=m+1
+     t[m]=str
+    elseif str~="" then
+     str=lpegmatch(x_collapser,str)
+     if str~="" then
+      m=m+1
+      t[m]=str
+     end
+    end
+   end
+   e.dt=t
+  elseif anywhere then
+   local t={}
+   local m=0
+   for i=1,n do
+    local str=edt[i]
+    if type(str)~="string" then
+     m=m+1
+     t[m]=str
+    elseif str~="" then
+     if nolines then
+      str=lpegmatch((i==1 and b_collapser) or (i==m and e_collapser) or m_collapser,str)
+     else
+      str=lpegmatch((i==1 and b_stripper) or (i==m and e_stripper) or m_stripper,str)
+     end
+     if str~="" then
+      m=m+1
+      t[m]=str
+     end
+    end
+   end
+   e.dt=t
+  else
+   local str=edt[1]
+   if type(str)=="string" then
+    if str~="" then
+     str=lpegmatch(nolines and b_collapser or b_stripper,str)
+    end
+    if str=="" then
+     remove(edt,1)
+     n=n-1
+    else
+     edt[1]=str
+    end
+   end
+   if n>0 then
+    str=edt[n]
+    if type(str)=="string" then
+     if str=="" then
+      remove(edt)
+     else
+      str=lpegmatch(nolines and e_collapser or e_stripper,str)
+      if str=="" then
+       remove(edt)
+      else
+       edt[n]=str
+      end
+     end
+    end
+   end
+  end
+ end
+ return e 
+end
+xml.stripelement=stripelement
+function xml.strip(root,pattern,nolines,anywhere,everything) 
+ local collected=xmlapplylpath(root,pattern) 
+ if collected then
+  for i=1,#collected do
+   stripelement(collected[i],nolines,anywhere,everything)
+  end
+ end
+end
+local function compactelement(e)
+ local edt=e.dt
+ if edt then
+  for e=1,#edt do
+   local str=edt[e]
+   if type(str)=="string" and not find(str,"%S") then
+    edt[e]=""
+   end
+  end
+ end
+ return e 
+end
+xml.compactelement=compactelement
+local function renamespace(root,oldspace,newspace) 
+ local ndt=#root.dt
+ for i=1,ndt or 0 do
+  local e=root[i]
+  if type(e)=="table" then
+   if e.ns==oldspace then
+    e.ns=newspace
+    if e.rn then
+     e.rn=newspace
+    end
+   end
+   local edt=e.dt
+   if edt then
+    renamespace(edt,oldspace,newspace)
+   end
+  end
+ end
+end
+xml.renamespace=renamespace
+function xml.remaptag(root,pattern,newtg)
+ local collected=xmlapplylpath(root,pattern)
+ if collected then
+  for c=1,#collected do
+   collected[c].tg=newtg
+  end
+ end
+end
+function xml.remapnamespace(root,pattern,newns)
+ local collected=xmlapplylpath(root,pattern)
+ if collected then
+  for c=1,#collected do
+   collected[c].ns=newns
+  end
+ end
+end
+function xml.checknamespace(root,pattern,newns)
+ local collected=xmlapplylpath(root,pattern)
+ if collected then
+  for c=1,#collected do
+   local e=collected[c]
+   if (not e.rn or e.rn=="") and e.ns=="" then
+    e.rn=newns
+   end
+  end
+ end
+end
+function xml.remapname(root,pattern,newtg,newns,newrn)
+ local collected=xmlapplylpath(root,pattern)
+ if collected then
+  for c=1,#collected do
+   local e=collected[c]
+   e.tg,e.ns,e.rn=newtg,newns,newrn
+  end
+ end
+end
+function xml.cdatatotext(e)
+ local dt=e.dt
+ if #dt==1 then
+  local first=dt[1]
+  if first.tg=="@cd@" then
+   e.dt=first.dt
+  end
+ else
+ end
+end
+function xml.texttocdata(e) 
+ local dt=e.dt
+ local s=xml.tostring(dt) 
+ e.tg="@cd@"
+ e.special=true
+ e.ns=""
+ e.rn=""
+ e.dt={ s }
+ e.at=nil
+end
+function xml.elementtocdata(e) 
+ local dt=e.dt
+ local s=xml.tostring(e) 
+ e.tg="@cd@"
+ e.special=true
+ e.ns=""
+ e.rn=""
+ e.dt={ s }
+ e.at=nil
+end
+xml.builtinentities=table.tohash { "amp","quot","apos","lt","gt" } 
+local entities=characters and characters.entities or nil
+local builtinentities=xml.builtinentities
+function xml.addentitiesdoctype(root,option) 
+ if not entities then
+  require("char-ent")
+  entities=characters.entities
+ end
+ if entities and root and root.tg=="@rt@" and root.statistics then
+  local list={}
+  local hexify=option=="hexadecimal"
+  for k,v in table.sortedhash(root.statistics.entities.names) do
+   if not builtinentities[k] then
+    local e=entities[k]
+    if not e then
+     e=format("[%s]",k)
+    elseif hexify then
+     e=format("&#%05X;",utfbyte(k))
+    end
+    list[#list+1]=format("  <!ENTITY %s %q >",k,e)
+   end
+  end
+  local dt=root.dt
+  local n=dt[1].tg=="@pi@" and 2 or 1
+  if #list>0 then
+   insert(dt,n,{ "\n" })
+   insert(dt,n,{
+      tg="@dt@",
+      dt={ format("Something [\n%s\n] ",concat(list)) },
+      ns="",
+      special=true,
+   })
+   insert(dt,n,{ "\n\n" })
+  else
+  end
+ end
+end
+xml.all=xml.each
+xml.insert=xml.insertafter
+xml.inject=xml.injectafter
+xml.after=xml.insertafter
+xml.before=xml.insertbefore
+xml.process=xml.each
+xml.obsolete=xml.obsolete or {}
+local obsolete=xml.obsolete
+xml.strip_whitespace=xml.strip     obsolete.strip_whitespace=xml.strip
+xml.collect_elements=xml.collect      obsolete.collect_elements=xml.collect
+xml.delete_element=xml.delete    obsolete.delete_element=xml.delete
+xml.replace_element=xml.replace      obsolete.replace_element=xml.replace
+xml.each_element=xml.each      obsolete.each_element=xml.each
+xml.process_elements=xml.process      obsolete.process_elements=xml.process
+xml.insert_element_after=xml.insertafter     obsolete.insert_element_after=xml.insertafter
+xml.insert_element_before=xml.insertbefore    obsolete.insert_element_before=xml.insertbefore
+xml.inject_element_after=xml.injectafter     obsolete.inject_element_after=xml.injectafter
+xml.inject_element_before=xml.injectbefore    obsolete.inject_element_before=xml.injectbefore
+xml.process_attributes=xml.processattributes  obsolete.process_attributes=xml.processattributes
+xml.collect_texts=xml.collecttexts    obsolete.collect_texts=xml.collecttexts
+xml.inject_element=xml.inject    obsolete.inject_element=xml.inject
+xml.remap_tag=xml.remaptag     obsolete.remap_tag=xml.remaptag
+xml.remap_name=xml.remapname    obsolete.remap_name=xml.remapname
+xml.remap_namespace=xml.remapnamespace  obsolete.remap_namespace=xml.remapnamespace
+function xml.cdata(e)
+ if e then
+  local dt=e.dt
+  if dt and #dt==1 then
+   local first=dt[1]
+   return first.tg=="@cd@" and first.dt[1] or ""
+  end
+ end
+ return ""
+end
+function xml.finalizers.xml.cdata(collected)
+ if collected then
+  local e=collected[1]
+  if e then
+   local dt=e.dt
+   if dt and #dt==1 then
+    local first=dt[1]
+    return first.tg=="@cd@" and first.dt[1] or ""
+   end
+  end
+ end
+ return ""
+end
+function xml.insertcomment(e,str,n)
+ insert(e.dt,n or 1,{
+  tg="@cm@",
+  ns="",
+  special=true,
+  at={},
+  dt={ str },
+ })
+end
+function xml.insertcdata(e,str,n)
+ insert(e.dt,n or 1,{
+  tg="@cd@",
+  ns="",
+  special=true,
+  at={},
+  dt={ str },
+ })
+end
+function xml.setcomment(e,str,n)
+ e.dt={ {
+  tg="@cm@",
+  ns="",
+  special=true,
+  at={},
+  dt={ str },
+ } }
+end
+function xml.setcdata(e,str)
+ e.dt={ {
+  tg="@cd@",
+  ns="",
+  special=true,
+  at={},
+  dt={ str },
+ } }
+end
+function xml.separate(x,pattern)
+ local collected=xmlapplylpath(x,pattern)
+ if collected then
+  for c=1,#collected do
+   local e=collected[c]
+   local d=e.dt
+   if d==x then
+    report_xml("warning: xml.separate changes root")
+    x=d
+   end
+   local t={ "\n" }
+   local n=1
+   local i=1
+   local nd=#d
+   while i<=nd do
+    while i<=nd do
+     local di=d[i]
+     if type(di)=="string" then
+      if di=="\n" or find(di,"^%s+$") then 
+       i=i+1
+      else
+       d[i]=strip(di)
+       break
+      end
+     else
+      break
+     end
+    end
+    if i>nd then
+     break
+    end
+    t[n+1]="\n"
+    t[n+2]=d[i]
+    t[n+3]="\n"
+    n=n+3
+    i=i+1
+   end
+   t[n+1]="\n"
+   setmetatable(t,getmetatable(d))
+   e.dt=t
+  end
+ end
+ return x
+end
+local helpers=xml.helpers or {}
+xml.helpers=helpers
+local function normal(e,action)
+ local edt=e.dt
+ if edt then
+  for i=1,#edt do
+   local str=edt[i]
+   if type(str)=="string" and str~="" then
+    edt[i]=action(str)
+   end
+  end
+ end
+end
+local function recurse(e,action)
+ local edt=e.dt
+ if edt then
+  for i=1,#edt do
+   local str=edt[i]
+   if type(str)~="string" then
+    recurse(str,action) 
+   elseif str~="" then
+    edt[i]=action(str)
+   end
+  end
+ end
+end
+function helpers.recursetext(collected,action,recursive)
+ if recursive then
+  for i=1,#collected do
+   recurse(collected[i],action)
+  end
+ else
+  for i=1,#collected do
+     normal(collected[i],action)
+  end
+ end
+end
+local specials={
+ ["@rt@"]="root",
+ ["@pi@"]="instruction",
+ ["@cm@"]="comment",
+ ["@dt@"]="declaration",
+ ["@cd@"]="cdata",
+}
+local function convert(x,strip,flat)
+ local ns=x.ns
+ local tg=x.tg
+ local at=x.at
+ local dt=x.dt
+ local node=flat and {
+  [0]=(not x.special and (ns~="" and ns..":"..tg or tg)) or nil,
+ } or {
+  _namespace=ns~="" and ns or nil,
+  _tag=not x.special and tg or nil,
+  _type=specials[tg] or "_element",
+ }
+ if at then
+  for k,v in next,at do
+   node[k]=v
+  end
+ end
+ local n=0
+ for i=1,#dt do
+  local di=dt[i]
+  if type(di)=="table" then
+   if flat and di.special then
+   else
+    di=convert(di,strip,flat)
+    if di then
+     n=n+1
+     node[n]=di
+    end
+   end
+  elseif strip then
+   di=lpegmatch(strip,di)
+   if di~="" then
+    n=n+1
+    node[n]=di
+   end
+  else
+   n=n+1
+   node[n]=di
+  end
+ end
+ if next(node) then
+  return node
+ end
+end
+function xml.totable(x,strip,flat)
+ if type(x)=="table" then
+  if strip then
+   strip=striplinepatterns[strip]
+  end
+  return convert(x,strip,flat)
+ end
+end
+function xml.rename(e,namespace,name,attributes)
+ if type(e)~="table" or not e.tg then
+  return
+ end
+ if type(name)=="table" then
+  attributes=name
+  name=namespace
+  namespace=""
+ elseif type(name)~="string" then
+  attributes={}
+  name=namespace
+  namespace=""
+ end
+ if type(attributes)~="table" then
+  attributes={}
+ end
+ e.ns=namespace
+ e.rn=namespace
+ e.tg=name
+ e.at=attributes
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["lxml-xml"] = package.loaded["lxml-xml"] or true
+
+-- original size: 11096, stripped down to: 7702
+
+if not modules then modules={} end modules ['lxml-xml']={
+ version=1.001,
+ comment="this module is the basis for the lxml-* ones",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local tonumber,next=tonumber,next
+local concat=table.concat
+local find,lower,upper=string.find,string.lower,string.upper
+local xml=xml
+local finalizers=xml.finalizers.xml
+local xmlfilter=xml.filter 
+local xmltostring=xml.tostring
+local xmlserialize=xml.serialize
+local xmlcollected=xml.collected
+local xmlnewhandlers=xml.newhandlers
+local reparsedentity=xml.reparsedentitylpeg   
+local unescapedentity=xml.unescapedentitylpeg
+local parsedentity=reparsedentity
+local function first(collected) 
+ return collected and collected[1]
+end
+local function last(collected)
+ return collected and collected[#collected]
+end
+local function all(collected)
+ return collected
+end
+local reverse=table.reversed
+local function attribute(collected,name)
+ if collected and #collected>0 then
+  local at=collected[1].at
+  return at and at[name]
+ end
+end
+local function att(id,name)
+ local at=id.at
+ return at and at[name]
+end
+local function count(collected)
+ return collected and #collected or 0
+end
+local function position(collected,n)
+ if not collected then
+  return 0
+ end
+ local nc=#collected
+ if nc==0 then
+  return 0
+ end
+ n=tonumber(n) or 0
+ if n<0 then
+  return collected[nc+n+1]
+ elseif n>0 then
+  return collected[n]
+ else
+  return collected[1].mi or 0
+ end
+end
+local function match(collected)
+ return collected and #collected>0 and collected[1].mi or 0 
+end
+local function index(collected)
+ return collected and #collected>0 and collected[1].ni or 0 
+end
+local function attributes(collected,arguments)
+ if collected and #collected>0 then
+  local at=collected[1].at
+  if arguments then
+   return at[arguments]
+  elseif next(at) then
+   return at 
+  end
+ end
+end
+local function chainattribute(collected,arguments) 
+ if collected and #collected>0 then
+  local e=collected[1]
+  while e do
+   local at=e.at
+   if at then
+    local a=at[arguments]
+    if a then
+     return a
+    end
+   else
+    break 
+   end
+   e=e.__p__
+  end
+ end
+ return ""
+end
+local function raw(collected) 
+ if collected and #collected>0 then
+  local e=collected[1] or collected
+  return e and xmltostring(e) or "" 
+ else
+  return ""
+ end
+end
+local xmltexthandler=xmlnewhandlers {
+ name="string",
+ initialize=function()
+  result={}
+  return result
+ end,
+ finalize=function()
+  return concat(result)
+ end,
+ handle=function(...)
+  result[#result+1]=concat {... }
+ end,
+ escape=false,
+}
+local function xmltotext(root)
+ local dt=root.dt
+ if not dt then
+  return ""
+ end
+ local nt=#dt 
+ if nt==0 then
+  return ""
+ elseif nt==1 and type(dt[1])=="string" then
+  return dt[1] 
+ else
+  return xmlserialize(root,xmltexthandler) or ""
+ end
+end
+function xml.serializetotext(root)
+ return root and xmlserialize(root,xmltexthandler) or ""
+end
+local function text(collected) 
+ if collected then 
+  local e=collected[1] or collected 
+  return e and xmltotext(e) or ""
+ else
+  return ""
+ end
+end
+local function texts(collected)
+ if not collected then
+  return {} 
+ end
+ local nc=#collected
+ if nc==0 then
+  return {} 
+ end
+ local t,n={},0
+ for c=1,nc do
+  local e=collected[c]
+  if e and e.dt then
+   n=n+1
+   t[n]=e.dt
+  end
+ end
+ return t
+end
+local function tag(collected,n)
+ if not collected then
+  return
+ end
+ local nc=#collected
+ if nc==0 then
+  return
+ end
+ local c
+ if n==0 or not n then
+  c=collected[1]
+ elseif n>1 then
+  c=collected[n]
+ else
+  c=collected[nc-n+1]
+ end
+ return c and c.tg
+end
+local function name(collected,n)
+ if not collected then
+  return
+ end
+ local nc=#collected
+ if nc==0 then
+  return
+ end
+ local c
+ if n==0 or not n then
+  c=collected[1]
+ elseif n>1 then
+  c=collected[n]
+ else
+  c=collected[nc-n+1]
+ end
+ if not c then
+ elseif c.ns=="" then
+  return c.tg
+ else
+  return c.ns..":"..c.tg
+ end
+end
+local function tags(collected,nonamespace)
+ if not collected then
+  return
+ end
+ local nc=#collected
+ if nc==0 then
+  return
+ end
+ local t,n={},0
+ for c=1,nc do
+  local e=collected[c]
+  local ns,tg=e.ns,e.tg
+  n=n+1
+  if nonamespace or ns=="" then
+   t[n]=tg
+  else
+   t[n]=ns..":"..tg
+  end
+ end
+ return t
+end
+local function empty(collected,spacesonly)
+ if not collected then
+  return true
+ end
+ local nc=#collected
+ if nc==0 then
+  return true
+ end
+ for c=1,nc do
+  local e=collected[c]
+  if e then
+   local edt=e.dt
+   if edt then
+    local n=#edt
+    if n==1 then
+     local edk=edt[1]
+     local typ=type(edk)
+     if typ=="table" then
+      return false
+     elseif edk~="" then
+      return false
+     elseif spacesonly and not find(edk,"%S") then
+      return false
+     end
+    elseif n>1 then
+     return false
+    end
+   end
+  end
+ end
+ return true
+end
+finalizers.first=first
+finalizers.last=last
+finalizers.all=all
+finalizers.reverse=reverse
+finalizers.elements=all
+finalizers.default=all
+finalizers.attribute=attribute
+finalizers.att=att
+finalizers.count=count
+finalizers.position=position
+finalizers.match=match
+finalizers.index=index
+finalizers.attributes=attributes
+finalizers.chainattribute=chainattribute
+finalizers.text=text
+finalizers.texts=texts
+finalizers.tag=tag
+finalizers.name=name
+finalizers.tags=tags
+finalizers.empty=empty
+function xml.first(id,pattern)
+ return first(xmlfilter(id,pattern))
+end
+function xml.last(id,pattern)
+ return last(xmlfilter(id,pattern))
+end
+function xml.count(id,pattern)
+ return count(xmlfilter(id,pattern))
+end
+function xml.attribute(id,pattern,a,default)
+ return attribute(xmlfilter(id,pattern),a,default)
+end
+function xml.raw(id,pattern)
+ if pattern then
+  return raw(xmlfilter(id,pattern))
+ else
+  return raw(id)
+ end
+end
+function xml.text(id,pattern) 
+ if pattern then
+  local collected=xmlfilter(id,pattern)
+  return collected and #collected>0 and xmltotext(collected[1]) or ""
+ elseif id then
+  return xmltotext(id) or ""
+ else
+  return ""
+ end
+end
+function xml.pure(id,pattern)
+ if pattern then
+  local collected=xmlfilter(id,pattern)
+  if collected and #collected>0 then
+   parsedentity=unescapedentity
+   local s=collected and #collected>0 and xmltotext(collected[1]) or ""
+   parsedentity=reparsedentity
+   return s
+  else
+   return ""
+  end
+ else
+  parsedentity=unescapedentity
+  local s=xmltotext(id) or ""
+  parsedentity=reparsedentity
+  return s
+ end
+end
+xml.content=text
+function xml.position(id,pattern,n) 
+ return position(xmlfilter(id,pattern),n)
+end
+function xml.match(id,pattern) 
+ return match(xmlfilter(id,pattern))
+end
+function xml.empty(id,pattern,spacesonly)
+ return empty(xmlfilter(id,pattern),spacesonly)
+end
+xml.all=xml.filter
+xml.index=xml.position
+xml.found=xml.filter
+local function totable(x)
+ local t={}
+ for e in xmlcollected(x[1] or x,"/*") do
+  t[e.tg]=xmltostring(e.dt) or ""
+ end
+ return next(t) and t or nil
+end
+xml.table=totable
+finalizers.table=totable
+local function textonly(e,t)
+ if e then
+  local edt=e.dt
+  if edt then
+   for i=1,#edt do
+    local e=edt[i]
+    if type(e)=="table" then
+     textonly(e,t)
+    else
+     t[#t+1]=e
+    end
+   end
+  end
+ end
+ return t
+end
+function xml.textonly(e) 
+ return concat(textonly(e,{}))
+end
+function finalizers.lowerall(collected)
+ for c=1,#collected do
+  local e=collected[c]
+  if not e.special then
+   e.tg=lower(e.tg)
+   local eat=e.at
+   if eat then
+    local t={}
+    for k,v in next,eat do
+     t[lower(k)]=v
+    end
+    e.at=t
+   end
+  end
+ end
+end
+function finalizers.upperall(collected)
+ for c=1,#collected do
+  local e=collected[c]
+  if not e.special then
+   e.tg=upper(e.tg)
+   local eat=e.at
+   if eat then
+    local t={}
+    for k,v in next,eat do
+     t[upper(k)]=v
+    end
+    e.at=t
+   end
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["trac-xml"] = package.loaded["trac-xml"] or true
+
+-- original size: 6407, stripped down to: 4640
+
+if not modules then modules={} end modules ['trac-xml']={
+ version=1.001,
+ comment="companion to trac-log.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local formatters=string.formatters
+local reporters=logs.reporters
+local xmlserialize=xml.serialize
+local xmlcollected=xml.collected
+local xmltext=xml.text
+local xmlfirst=xml.first
+local function showhelp(specification,...)
+ local root=xml.convert(specification.helpinfo or "")
+ if not root then
+  return
+ end
+ local xs=xml.gethandlers("string")
+ xml.sethandlersfunction(xs,"short",function(e,handler) xmlserialize(e.dt,handler) end)
+ xml.sethandlersfunction(xs,"ref",function(e,handler) handler.handle("--"..e.at.name) end)
+ local wantedcategories=select("#",...)==0 and true or table.tohash {... }
+ local nofcategories=xml.count(root,"/application/flags/category")
+ local report=specification.report
+ for category in xmlcollected(root,"/application/flags/category") do
+  local categoryname=category.at.name or ""
+  if wantedcategories==true or wantedcategories[categoryname] then
+   if nofcategories>1 then
+    report("%s options:",categoryname)
+    report()
+   end
+   for subcategory in xmlcollected(category,"/subcategory") do
+    for flag in xmlcollected(subcategory,"/flag") do
+     local name=flag.at.name
+     local value=flag.at.value
+     local short=xmltext(xmlfirst(flag,"/short"))
+     if value then
+      report("--%-20s %s",formatters["%s=%s"](name,value),short)
+     else
+      report("--%-20s %s",name,short)
+     end
+    end
+    report()
+   end
+  end
+ end
+ for category in xmlcollected(root,"/application/examples/category") do
+  local title=xmltext(xmlfirst(category,"/title"))
+  if title and title~="" then
+   report()
+   report(title)
+   report()
+  end
+  for subcategory in xmlcollected(category,"/subcategory") do
+   for example in xmlcollected(subcategory,"/example") do
+    local command=xmltext(xmlfirst(example,"/command"))
+    local comment=xmltext(xmlfirst(example,"/comment"))
+    report(command)
+   end
+   report()
+  end
+ end
+ for comment in xmlcollected(root,"/application/comments/comment") do
+  local comment=xmltext(comment)
+  report()
+  report(comment)
+  report()
+ end
+end
+local reporthelp=reporters.help
+local exporthelp=reporters.export
+local function xmlfound(t)
+ local helpinfo=t.helpinfo
+ if type(helpinfo)=="table" then
+  return false
+ end
+ if type(helpinfo)~="string" then
+  helpinfo="Warning: no helpinfo found."
+  t.helpinfo=helpinfo
+  return false
+ end
+ if string.find(helpinfo,".xml$") then
+  local ownscript=environment.ownscript
+  local helpdata=false
+  if ownscript then
+   local helpfile=file.join(file.pathpart(ownscript),helpinfo)
+   helpdata=io.loaddata(helpfile)
+   if helpdata=="" then
+    helpdata=false
+   end
+  end
+  if not helpdata then
+   local helpfile=resolvers.findfile(helpinfo,"tex")
+   helpdata=helpfile and io.loaddata(helpfile)
+  end
+  if helpdata and helpdata~="" then
+   helpinfo=helpdata
+  else
+   helpinfo=formatters["Warning: help file %a is not found."](helpinfo)
+  end
+ end
+ t.helpinfo=helpinfo
+ return string.find(t.helpinfo,"^<%?xml") and true or false
+end
+function reporters.help(t,...)
+ if xmlfound(t) then
+  showhelp(t,...)
+ else
+  reporthelp(t,...)
+ end
+end
+function reporters.export(t,methods,filename)
+ if not xmlfound(t) then
+  return exporthelp(t)
+ end
+ if not methods or methods=="" then
+  methods=environment.arguments["exporthelp"]
+ end
+ if not filename or filename=="" then
+  filename=environment.files[1]
+ end
+ dofile(resolvers.findfile("trac-exp.lua","tex"))
+ local exporters=logs.exporters
+ if not exporters or not methods then
+  return exporthelp(t)
+ end
+ if methods=="all" then
+  methods=table.keys(exporters)
+ elseif type(methods)=="string" then
+  methods=utilities.parsers.settings_to_array(methods)
+ else
+  return exporthelp(t)
+ end
+ if type(filename)~="string" or filename=="" then
+  filename=false
+ elseif file.pathpart(filename)=="" then
+  t.report("export file %a will not be saved on the current path (safeguard)",filename)
+  return
+ end
+ for i=1,#methods do
+  local method=methods[i]
+  local exporter=exporters[method]
+  if exporter then
+   local result=exporter(t,method)
+   if result and result~="" then
+    if filename then
+     local fullname=file.replacesuffix(filename,method)
+     t.report("saving export in %a",fullname)
+     dir.mkdirs(file.pathpart(fullname))
+     io.savedata(fullname,result)
+    else
+     reporters.lines(t,result)
+    end
+   else
+    t.report("no output from exporter %a",method)
+   end
+  else
+   t.report("unknown exporter %a",method)
+  end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-ini"] = package.loaded["data-ini"] or true
+
+-- original size: 10947, stripped down to: 7176
+
+if not modules then modules={} end modules ['data-ini']={
+ 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 next,type,getmetatable,rawset=next,type,getmetatable,rawset
+local gsub,find,gmatch,char=string.gsub,string.find,string.gmatch,string.char
+local filedirname,filebasename,filejoin=file.dirname,file.basename,file.join
+local ostype,osname,osuname,ossetenv,osgetenv=os.type,os.name,os.uname,os.setenv,os.getenv
+local sortedpairs=table.sortedpairs
+local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match
+local trace_locating=false  trackers.register("resolvers.locating",function(v) trace_locating=v end)
+local trace_expansions=false  trackers.register("resolvers.expansions",function(v) trace_expansions=v end)
+local report_initialization=logs.reporter("resolvers","initialization")
+resolvers=resolvers or {}
+local resolvers=resolvers
+texconfig.kpse_init=false
+texconfig.shell_escape='t'
+if not (environment and environment.default_texmfcnf) and kpse and kpse.default_texmfcnf then
+ local default_texmfcnf=kpse.default_texmfcnf()
+ default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOLOC","selfautoloc:")
+ default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTODIR","selfautodir:")
+ default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOPARENT","selfautoparent:")
+ default_texmfcnf=gsub(default_texmfcnf,"$HOME","home:")
+ environment.default_texmfcnf=default_texmfcnf
+end
+kpse={ original=kpse }
+setmetatable(kpse,{
+ __index=function(kp,name)
+  report_initialization("fatal error: kpse library is accessed (key: %s)",name)
+  os.exit()
+ end
+} )
+do
+ local osfontdir=osgetenv("OSFONTDIR")
+ if osfontdir and osfontdir~="" then
+ elseif osname=="windows" then
+  ossetenv("OSFONTDIR","c:/windows/fonts//")
+ elseif osname=="macosx" then
+  ossetenv("OSFONTDIR","$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//")
+ end
+end
+if not environment.homedir then
+ local oldhome=osgetenv('HOME')
+ local homedir=osgetenv(ostype=="windows" and 'USERPROFILE' or 'HOME') or ''
+ if not homedir or homedir=="" then
+  homedir=char(127) 
+ end
+ homedir=file.collapsepath(homedir)
+ ossetenv("HOME",homedir) 
+ ossetenv("USERPROFILE",homedir) 
+ environment.oldhome=oldhome
+ environment.homedir=homedir
+end
+do
+ local args=environment.originalarguments or arg 
+ if not environment.ownmain then
+  environment.ownmain=status and string.match(string.lower(status.banner),"this is ([%a]+)") or "luatex"
+ end
+ local ownbin=environment.ownbin  or args[-2] or arg[-2] or args[-1] or arg[-1] or arg[0] or "luatex"
+ local ownpath=environment.ownpath or os.selfdir
+ ownbin=file.collapsepath(ownbin)
+ ownpath=file.collapsepath(ownpath)
+ if not ownpath or ownpath=="" or ownpath=="unset" then
+  ownpath=args[-1] or arg[-1]
+  ownpath=ownpath and filedirname(gsub(ownpath,"\\","/"))
+  if not ownpath or ownpath=="" then
+   ownpath=args[-0] or arg[-0]
+   ownpath=ownpath and filedirname(gsub(ownpath,"\\","/"))
+  end
+  local binary=ownbin
+  if not ownpath or ownpath=="" then
+   ownpath=ownpath and filedirname(binary)
+  end
+  if not ownpath or ownpath=="" then
+   if os.binsuffix~="" then
+    binary=file.replacesuffix(binary,os.binsuffix)
+   end
+   local path=osgetenv("PATH")
+   if path then
+    for p in gmatch(path,"[^"..io.pathseparator.."]+") do
+     local b=filejoin(p,binary)
+     if lfs.isfile(b) then
+      local olddir=lfs.currentdir()
+      if lfs.chdir(p) then
+       local pp=lfs.currentdir()
+       if trace_locating and p~=pp then
+        report_initialization("following symlink %a to %a",p,pp)
+       end
+       ownpath=pp
+       lfs.chdir(olddir)
+      else
+       if trace_locating then
+        report_initialization("unable to check path %a",p)
+       end
+       ownpath=p
+      end
+      break
+     end
+    end
+   end
+  end
+  if not ownpath or ownpath=="" then
+   ownpath="."
+   report_initialization("forcing fallback to ownpath %a",ownpath)
+  elseif trace_locating then
+   report_initialization("using ownpath %a",ownpath)
+  end
+ end
+ environment.ownbin=ownbin
+ environment.ownpath=ownpath
+end
+resolvers.ownpath=environment.ownpath
+function resolvers.getownpath()
+ return environment.ownpath
+end
+do
+ local ownpath=environment.ownpath or dir.current()
+ if ownpath then
+  ossetenv('SELFAUTOLOC',file.collapsepath(ownpath))
+  ossetenv('SELFAUTODIR',file.collapsepath(ownpath.."/.."))
+  ossetenv('SELFAUTOPARENT',file.collapsepath(ownpath.."/../.."))
+ else
+  report_initialization("error: unable to locate ownpath")
+  os.exit()
+ end
+end
+local texos=environment.texos   or osgetenv("TEXOS")
+local texmfos=environment.texmfos or osgetenv('SELFAUTODIR')
+if not texos or texos=="" then
+ texos=file.basename(texmfos)
+end
+ossetenv('TEXMFOS',texmfos)   
+ossetenv('TEXOS',texos)  
+ossetenv('SELFAUTOSYSTEM',os.platform)  
+environment.texos=texos
+environment.texmfos=texmfos
+local texroot=environment.texroot or osgetenv("TEXROOT")
+if not texroot or texroot=="" then
+ texroot=osgetenv('SELFAUTOPARENT')
+ ossetenv('TEXROOT',texroot)
+end
+environment.texroot=file.collapsepath(texroot)
+local prefixes=utilities.storage.allocate()
+resolvers.prefixes=prefixes
+local resolved={}
+local abstract={}
+local dynamic={}
+function resolvers.resetresolve(str)
+ resolved,abstract={},{}
+end
+function resolvers.allprefixes(separator)
+ local all=table.sortedkeys(prefixes)
+ if separator then
+  for i=1,#all do
+   all[i]=all[i]..":"
+  end
+ end
+ return all
+end
+local function _resolve_(method,target)
+ local action=prefixes[method]
+ if action then
+  return action(target)
+ else
+  return method..":"..target
+ end
+end
+function resolvers.unresolve(str)
+ return abstract[str] or str
+end
+function resolvers.setdynamic(str)
+ dynamic[str]=true
+end
+local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0)
+local prefix=C(R("az")^2)*P(":")
+local target=C((1-S(" \"\';,"))^1)
+local notarget=(#S(";,")+P(-1))*Cc("")
+local p_resolve=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0)
+local p_simple=prefix*P(-1)
+local function resolve(str) 
+ if type(str)=="table" then
+  local res={}
+  for i=1,#str do
+   res[i]=resolve(str[i])
+  end
+  return res
+ end
+ local res=resolved[str]
+ if res then
+  return res
+ end
+ local simple=lpegmatch(p_simple,str)
+ local action=prefixes[simple]
+ if action then
+  local res=action(res)
+  if not dynamic[simple] then
+   resolved[simple]=res
+   abstract[res]=simple
+  end
+  return res
+ end
+ res=lpegmatch(p_resolve,str)
+ resolved[str]=res
+ abstract[res]=str
+ return res
+end
+resolvers.resolve=resolve
+if type(osuname)=="function" then
+ for k,v in next,osuname() do
+  if not prefixes[k] then
+   prefixes[k]=function() return v end
+  end
+ end
+end
+if ostype=="unix" then
+ local pattern
+ local function makepattern(t,k,v)
+  if t then
+   rawset(t,k,v)
+  end
+  local colon=P(":")
+  for k,v in sortedpairs(prefixes) do
+   if p then
+    p=P(k)+p
+   else
+    p=P(k)
+   end
+  end
+  pattern=Cs((p*colon+colon/";"+P(1))^0)
+ end
+ makepattern()
+ table.setmetatablenewindex(prefixes,makepattern)
+ function resolvers.repath(str)
+  return lpegmatch(pattern,str)
+ end
+else 
+ function resolvers.repath(str)
+  return str
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-exp"] = package.loaded["data-exp"] or true
+
+-- original size: 18179, stripped down to: 10432
+
+if not modules then modules={} end modules ['data-exp']={
+ 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 format,find,gmatch,lower,char,sub=string.format,string.find,string.gmatch,string.lower,string.char,string.sub
+local concat,sort=table.concat,table.sort
+local sortedkeys=table.sortedkeys
+local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns
+local Ct,Cs,Cc,Carg,P,C,S=lpeg.Ct,lpeg.Cs,lpeg.Cc,lpeg.Carg,lpeg.P,lpeg.C,lpeg.S
+local type,next=type,next
+local isdir=lfs.isdir
+local collapsepath,joinpath,basename=file.collapsepath,file.join,file.basename
+local trace_locating=false  trackers.register("resolvers.locating",function(v) trace_locating=v end)
+local trace_expansions=false  trackers.register("resolvers.expansions",function(v) trace_expansions=v end)
+local trace_globbing=true   trackers.register("resolvers.globbing",function(v) trace_globbing=v end)
+local report_expansions=logs.reporter("resolvers","expansions")
+local report_globbing=logs.reporter("resolvers","globbing")
+local resolvers=resolvers
+local resolveprefix=resolvers.resolve
+local function f_both(a,b)
+ local t,n={},0
+ for sb in gmatch(b,"[^,]+") do     
+  for sa in gmatch(a,"[^,]+") do    
+   n=n+1;t[n]=sa..sb
+  end
+ end
+ return concat(t,",")
+end
+local comma=P(",")
+local nocomma=(1-comma)^1
+local docomma=comma^1/","
+local before=Cs((nocomma*Carg(1)+docomma)^0)
+local after=Cs((Carg(1)*nocomma+docomma)^0)
+local both=Cs(((C(nocomma)*Carg(1))/function(a,b) return lpegmatch(before,b,1,a) end+docomma)^0)
+local function f_first (a,b) return lpegmatch(after,b,1,a) end
+local function f_second(a,b) return lpegmatch(before,a,1,b) end
+local function f_both  (a,b) return lpegmatch(both,b,1,a) end
+local left=P("{")
+local right=P("}")
+local var=P((1-S("{}" ))^0)
+local set=P((1-S("{},"))^0)
+local other=P(1)
+local l_first=Cs((Cc("{")*(C(set)*left*C(var)*right/f_first)*Cc("}")+other )^0 )
+local l_second=Cs((Cc("{")*(left*C(var)*right*C(set)/f_second)*Cc("}")+other )^0 )
+local l_both=Cs((Cc("{")*(left*C(var)*right*left*C(var)*right/f_both)*Cc("}")+other )^0 )
+local l_rest=Cs((left*var*(left/"")*var*(right/"")*var*right+other )^0 )
+local stripper_1=lpeg.stripper ("{}@")
+local replacer_1=lpeg.replacer { { ",}",",@}" },{ "{,","{@," },}
+local function splitpathexpr(str,newlist,validate) 
+ if trace_expansions then
+  report_expansions("expanding variable %a",str)
+ end
+ local t,ok,done=newlist or {},false,false
+ local n=#t
+ str=lpegmatch(replacer_1,str)
+ repeat
+  local old=str
+  repeat
+   local old=str
+   str=lpegmatch(l_first,str)
+  until old==str
+  repeat
+   local old=str
+   str=lpegmatch(l_second,str)
+  until old==str
+  repeat
+   local old=str
+   str=lpegmatch(l_both,str)
+  until old==str
+  repeat
+   local old=str
+   str=lpegmatch(l_rest,str)
+  until old==str
+ until old==str 
+ str=lpegmatch(stripper_1,str)
+ if validate then
+  for s in gmatch(str,"[^,]+") do
+   s=validate(s)
+   if s then
+    n=n+1
+    t[n]=s
+   end
+  end
+ else
+  for s in gmatch(str,"[^,]+") do
+   n=n+1
+   t[n]=s
+  end
+ end
+ if trace_expansions then
+  for k=1,#t do
+   report_expansions("% 4i: %s",k,t[k])
+  end
+ end
+ return t
+end
+local function validate(s)
+ s=collapsepath(s) 
+ return s~="" and not find(s,"^!*unset/*$") and s
+end
+resolvers.validatedpath=validate 
+function resolvers.expandedpathfromlist(pathlist)
+ local newlist={}
+ for k=1,#pathlist do
+  splitpathexpr(pathlist[k],newlist,validate)
+ end
+ return newlist
+end
+local usedhomedir=nil
+local donegation=(P("!")/""  )^0
+local doslashes=(P("\\")/"/"+1)^0
+local function expandedhome()
+ if not usedhomedir then
+  usedhomedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "")
+  if usedhomedir=="~" or usedhomedir=="" or not isdir(usedhomedir) then
+   if trace_expansions then
+    report_expansions("no home dir set, ignoring dependent path using current path")
+   end
+   usedhomedir="."
+  end
+ end
+ return usedhomedir
+end
+local dohome=((P("~")+P("$HOME")+P("%HOME%"))/expandedhome)^0
+local cleanup=Cs(donegation*dohome*doslashes)
+resolvers.cleanpath=function(str)
+ return str and lpegmatch(cleanup,str) or ""
+end
+local expandhome=P("~")/"$HOME"
+local dodouble=P('"')/""*(expandhome+(1-P('"')))^0*P('"')/""
+local dosingle=P("'")/""*(expandhome+(1-P("'")))^0*P("'")/""
+local dostring=(expandhome+1     )^0
+local stripper=Cs(
+ lpegpatterns.unspacer*(dosingle+dodouble+dostring)*lpegpatterns.unspacer
+)
+function resolvers.checkedvariable(str) 
+ return type(str)=="string" and lpegmatch(stripper,str) or str
+end
+local cache={}
+local splitter=lpeg.tsplitat(";") 
+local backslashswapper=lpeg.replacer("\\","/")
+local function splitconfigurationpath(str) 
+ if str then
+  local found=cache[str]
+  if not found then
+   if str=="" then
+    found={}
+   else
+    local split=lpegmatch(splitter,lpegmatch(backslashswapper,str)) 
+    found={}
+    local noffound=0
+    for i=1,#split do
+     local s=split[i]
+     if not find(s,"^{*unset}*") then
+      noffound=noffound+1
+      found[noffound]=s
+     end
+    end
+    if trace_expansions then
+     report_expansions("splitting path specification %a",str)
+     for k=1,noffound do
+      report_expansions("% 4i: %s",k,found[k])
+     end
+    end
+    cache[str]=found
+   end
+  end
+  return found
+ end
+end
+resolvers.splitconfigurationpath=splitconfigurationpath
+function resolvers.splitpath(str)
+ if type(str)=='table' then
+  return str
+ else
+  return splitconfigurationpath(str)
+ end
+end
+function resolvers.joinpath(str)
+ if type(str)=='table' then
+  return joinpath(str)
+ else
+  return str
+ end
+end
+local attributes,directory=lfs.attributes,lfs.dir
+local weird=P(".")^1+lpeg.anywhere(S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
+local lessweird=P(".")^1+lpeg.anywhere(S("~`#$%^&*:;\"\'||<>,?\n\r\t"))
+local timer={}
+local scanned={}
+local nofscans=0
+local scancache={}
+local fullcache={}
+local nofsharedscans=0
+local addcasecraptoo=true
+local function scan(files,remap,spec,path,n,m,r,onlyone,tolerant)
+ local full=path=="" and spec or (spec..path..'/')
+ local dirlist={}
+ local nofdirs=0
+ local pattern=tolerant and lessweird or weird
+ local filelist={}
+ local noffiles=0
+ for name,mode in directory(full) do
+  if not lpegmatch(pattern,name) then
+   if not mode then
+    mode=attributes(full..name,"mode")
+   end
+   if mode=="file" then
+    n=n+1
+    noffiles=noffiles+1
+    filelist[noffiles]=name
+   elseif mode=="directory" then
+    m=m+1
+    nofdirs=nofdirs+1
+    if path~="" then
+     dirlist[nofdirs]=path.."/"..name
+    else
+     dirlist[nofdirs]=name
+    end
+   end
+  end
+ end
+ if noffiles>0 then
+  sort(filelist)
+  for i=1,noffiles do
+   local name=filelist[i]
+   local lower=lower(name)
+   local paths=files[lower]
+   if paths then
+    if onlyone then
+    else
+     if name~=lower then
+      local rl=remap[lower]
+      if not rl then
+       remap[lower]=name
+       r=r+1
+      elseif trace_globbing and rl~=name then
+       report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl)
+      end
+      if addcasecraptoo then
+       local paths=files[name]
+       if not paths then
+        files[name]=path
+       elseif type(paths)=="string" then
+        files[name]={ paths,path }
+       else
+        paths[#paths+1]=path
+       end
+      end
+     end
+     if type(paths)=="string" then
+      files[lower]={ paths,path }
+     else
+      paths[#paths+1]=path
+     end
+    end
+   else 
+    files[lower]=path
+    if name~=lower then
+     local rl=remap[lower]
+     if not rl then
+      remap[lower]=name
+      r=r+1
+     elseif trace_globbing and rl~=name then
+      report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl)
+     end
+    end
+   end
+  end
+ end
+ if nofdirs>0 then
+  sort(dirlist)
+  for i=1,nofdirs do
+   files,remap,n,m,r=scan(files,remap,spec,dirlist[i],n,m,r,onlyonce,tolerant)
+  end
+ end
+ scancache[sub(full,1,-2)]=files
+ return files,remap,n,m,r
+end
+local function scanfiles(path,branch,usecache,onlyonce,tolerant)
+ local realpath=resolveprefix(path)
+ if usecache then
+  local content=fullcache[realpath]
+  if content then
+   if trace_locating then
+    report_expansions("using cached scan of path %a, branch %a",path,branch or path)
+   end
+   nofsharedscans=nofsharedscans+1
+   return content
+  end
+ end
+ statistics.starttiming(timer)
+ if trace_locating then
+  report_expansions("scanning path %a, branch %a",path,branch or path)
+ end
+ local content
+ if isdir(realpath) then
+  local files,remap,n,m,r=scan({},{},realpath..'/',"",0,0,0,onlyonce,tolerant)
+  content={
+   metadata={
+    path=path,
+    files=n,
+    directories=m,
+    remappings=r,
+   },
+   files=files,
+   remap=remap,
+  }
+  if trace_locating then
+   report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r)
+  end
+ else
+  content={
+   metadata={
+    path=path,
+    files=0,
+    directories=0,
+    remappings=0,
+   },
+   files={},
+   remap={},
+  }
+  if trace_locating then
+   report_expansions("invalid path %a",realpath)
+  end
+ end
+ if usecache then
+  scanned[#scanned+1]=realpath
+  fullcache[realpath]=content
+ end
+ nofscans=nofscans+1
+ statistics.stoptiming(timer)
+ return content
+end
+resolvers.scanfiles=scanfiles
+function resolvers.simplescanfiles(path,branch,usecache)
+ return scanfiles(path,branch,usecache,true,true) 
+end
+function resolvers.scandata()
+ table.sort(scanned)
+ return {
+  n=nofscans,
+  shared=nofsharedscans,
+  time=statistics.elapsedtime(timer),
+  paths=scanned,
+ }
+end
+function resolvers.get_from_content(content,path,name) 
+ if not content then
+  return
+ end
+ local files=content.files
+ if not files then
+  return
+ end
+ local remap=content.remap
+ if not remap then
+  return
+ end
+ if name then
+  local used=lower(name)
+  return path,remap[used] or used
+ else
+  local name=path
+  local used=lower(name)
+  local path=files[used]
+  if path then
+   return path,remap[used] or used
+  end
+ end
+end
+local nothing=function() end
+function resolvers.filtered_from_content(content,pattern)
+ if content and type(pattern)=="string" then
+  local pattern=lower(pattern)
+  local files=content.files 
+  local remap=content.remap
+  if files and remap then
+   local f=sortedkeys(files)
+   local n=#f
+   local i=0
+   local function iterator()
+    while i<n do
+     i=i+1
+     local k=f[i]
+     if find(k,pattern) then
+      return files[k],remap and remap[k] or k
+     end
+    end
+   end
+   return iterator
+  end
+ end
+ return nothing
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-env"] = package.loaded["data-env"] or true
+
+-- original size: 9501, stripped down to: 6413
+
+if not modules then modules={} end modules ['data-env']={
+ 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 lower,gsub=string.lower,string.gsub
+local next,rawget=next,rawget
+local resolvers=resolvers
+local allocate=utilities.storage.allocate
+local setmetatableindex=table.setmetatableindex
+local suffixonly=file.suffixonly
+local formats=allocate()
+local suffixes=allocate()
+local dangerous=allocate()
+local suffixmap=allocate()
+local usertypes=allocate()
+resolvers.formats=formats
+resolvers.suffixes=suffixes
+resolvers.dangerous=dangerous
+resolvers.suffixmap=suffixmap
+resolvers.usertypes=usertypes
+local luasuffixes=utilities.lua.suffixes
+local relations=allocate { 
+ core={
+  ofm={ 
+   names={ "ofm","omega font metric","omega font metrics" },
+   variable='OFMFONTS',
+   suffixes={ 'ofm','tfm' },
+  },
+  ovf={ 
+   names={ "ovf","omega virtual font","omega virtual fonts" },
+   variable='OVFFONTS',
+   suffixes={ 'ovf','vf' },
+  },
+  tfm={
+   names={ "tfm","tex font metric","tex font metrics" },
+   variable='TFMFONTS',
+   suffixes={ 'tfm' },
+  },
+  vf={
+   names={ "vf","virtual font","virtual fonts" },
+   variable='VFFONTS',
+   suffixes={ 'vf' },
+  },
+  otf={
+   names={ "otf","opentype","opentype font","opentype fonts"},
+   variable='OPENTYPEFONTS',
+   suffixes={ 'otf' },
+  },
+  ttf={
+   names={ "ttf","truetype","truetype font","truetype fonts","truetype collection","truetype collections","truetype dictionary","truetype dictionaries" },
+   variable='TTFONTS',
+   suffixes={ 'ttf','ttc','dfont' },
+  },
+  afm={
+   names={ "afm","adobe font metric","adobe font metrics" },
+   variable="AFMFONTS",
+   suffixes={ "afm" },
+  },
+  pfb={
+   names={ "pfb","type1","type 1","type1 font","type 1 font","type1 fonts","type 1 fonts" },
+   variable='T1FONTS',
+   suffixes={ 'pfb','pfa' },
+  },
+  fea={
+   names={ "fea","font feature","font features","font feature file","font feature files" },
+   variable='FONTFEATURES',
+   suffixes={ 'fea' },
+  },
+  cid={
+   names={ "cid","cid map","cid maps","cid file","cid files" },
+   variable='FONTCIDMAPS',
+   suffixes={ 'cid','cidmap' },
+  },
+  fmt={
+   names={ "fmt","format","tex format" },
+   variable='TEXFORMATS',
+   suffixes={ 'fmt' },
+  },
+  mem={ 
+   names={ 'mem',"metapost format" },
+   variable='MPMEMS',
+   suffixes={ 'mem' },
+  },
+  mp={
+   names={ "mp" },
+   variable='MPINPUTS',
+   suffixes=CONTEXTLMTXMODE>0
+    and { 'mpxl','mpvi','mpiv','mpii','mp' }
+    or  {   'mpvi','mpiv','mpii','mp' },
+   usertype=true,
+  },
+  tex={
+   names={ "tex" },
+   variable='TEXINPUTS',
+   suffixes={ "tex","mkiv","mkvi","mkxl","mklx","mkii","cld","lfg","xml" },
+   usertype=true,
+  },
+  icc={
+   names={ "icc","icc profile","icc profiles" },
+   variable='ICCPROFILES',
+   suffixes={ 'icc' },
+  },
+  texmfscripts={
+   names={ "texmfscript","texmfscripts","script","scripts" },
+   variable='TEXMFSCRIPTS',
+   suffixes={ 'lua','rb','pl','py' },
+  },
+  lua={
+   names={ "lua" },
+   variable='LUAINPUTS',
+   suffixes={ luasuffixes.lua,luasuffixes.luc,luasuffixes.tma,luasuffixes.tmc },
+   usertype=true,
+  },
+  lib={
+   names={ "lib" },
+   variable='CLUAINPUTS',
+   suffixes=os.libsuffix and { os.libsuffix } or { 'dll','so' },
+  },
+  bib={
+   names={ 'bib' },
+   variable='BIBINPUTS',
+   suffixes={ 'bib' },
+   usertype=true,
+  },
+  bst={
+   names={ 'bst' },
+   variable='BSTINPUTS',
+   suffixes={ 'bst' },
+   usertype=true,
+  },
+  fontconfig={
+   names={ 'fontconfig','fontconfig file','fontconfig files' },
+   variable='FONTCONFIG_PATH',
+  },
+  pk={
+   names={ "pk" },
+   variable='PKFONTS',
+   suffixes={ 'pk' },
+  },
+ },
+ obsolete={
+  enc={
+   names={ "enc","enc files","enc file","encoding files","encoding file" },
+   variable='ENCFONTS',
+   suffixes={ 'enc' },
+  },
+  map={
+   names={ "map","map files","map file" },
+   variable='TEXFONTMAPS',
+   suffixes={ 'map' },
+  },
+  lig={
+   names={ "lig files","lig file","ligature file","ligature files" },
+   variable='LIGFONTS',
+   suffixes={ 'lig' },
+  },
+  opl={
+   names={ "opl" },
+   variable='OPLFONTS',
+   suffixes={ 'opl' },
+  },
+  ovp={
+   names={ "ovp" },
+   variable='OVPFONTS',
+   suffixes={ 'ovp' },
+  },
+ },
+ kpse={ 
+  base={
+   names={ 'base',"metafont format" },
+   variable='MFBASES',
+   suffixes={ 'base','bas' },
+  },
+  cmap={
+   names={ 'cmap','cmap files','cmap file' },
+   variable='CMAPFONTS',
+   suffixes={ 'cmap' },
+  },
+  cnf={
+   names={ 'cnf' },
+   suffixes={ 'cnf' },
+  },
+  web={
+   names={ 'web' },
+   suffixes={ 'web','ch' }
+  },
+  cweb={
+   names={ 'cweb' },
+   suffixes={ 'w','web','ch' },
+  },
+  gf={
+   names={ 'gf' },
+   suffixes={ '<resolution>gf' },
+  },
+  mf={
+   names={ 'mf' },
+   variable='MFINPUTS',
+   suffixes={ 'mf' },
+  },
+  mft={
+   names={ 'mft' },
+   suffixes={ 'mft' },
+  },
+  pk={
+   names={ 'pk' },
+   suffixes={ '<resolution>pk' },
+  },
+ },
+}
+resolvers.relations=relations
+function resolvers.updaterelations()
+ for category,categories in next,relations do
+  for name,relation in next,categories do
+   local rn=relation.names
+   local rv=relation.variable
+   if rn and rv then
+    local rs=relation.suffixes
+    local ru=relation.usertype
+    for i=1,#rn do
+     local rni=lower(gsub(rn[i]," ",""))
+     formats[rni]=rv
+     if rs then
+      suffixes[rni]=rs
+      for i=1,#rs do
+       local rsi=rs[i]
+       suffixmap[rsi]=rni
+      end
+     end
+    end
+    if ru then
+     usertypes[name]=true
+    end
+   end
+  end
+ end
+end
+resolvers.updaterelations() 
+local function simplified(t,k)
+ return k and rawget(t,lower(gsub(k," ",""))) or nil
+end
+setmetatableindex(formats,simplified)
+setmetatableindex(suffixes,simplified)
+setmetatableindex(suffixmap,simplified)
+function resolvers.suffixofformat(str)
+ local s=suffixes[str]
+ return s and s[1] or ""
+end
+function resolvers.suffixofformat(str)
+ return suffixes[str] or {}
+end
+for name,format in next,formats do
+ dangerous[name]=true 
+end
+dangerous.tex=nil
+function resolvers.formatofvariable(str)
+ return formats[str] or ''
+end
+function resolvers.formatofsuffix(str) 
+ return suffixmap[suffixonly(str)] or 'tex' 
+end
+function resolvers.variableofformat(str)
+ return formats[str] or ''
+end
+function resolvers.variableofformatorsuffix(str)
+ local v=formats[str]
+ if v then
+  return v
+ end
+ v=suffixmap[suffixonly(str)]
+ if v then
+  return formats[v]
+ end
+ return ''
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+package.loaded["data-tmp"] = package.loaded["data-tmp"] or true
+
+-- original size: 16456, stripped down to: 11636
+
+if not modules then modules={} end modules ['data-tmp']={
+ version=1.100,
+ comment="companion to luat-lib.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local next,type=next,type
+local pcall,loadfile,collectgarbage=pcall,loadfile,collectgarbage
+local format,lower,gsub=string.format,string.lower,string.gsub
+local concat,serialize,fastserialize,serializetofile=table.concat,table.serialize,table.fastserialize,table.tofile
+local mkdirs,expanddirname,isdir,isfile=dir.mkdirs,dir.expandname,lfs.isdir,lfs.isfile
+local is_writable,is_readable=file.is_writable,file.is_readable
+local collapsepath,joinfile,addsuffix,dirname=file.collapsepath,file.join,file.addsuffix,file.dirname
+local savedata=file.savedata
+local formatters=string.formatters
+local osexit,osdate,osuuid=os.exit,os.date,os.uuid
+local removefile=os.remove
+local md5hex=md5.hex
+local trace_locating=false  trackers.register("resolvers.locating",function(v) trace_locating=v end)
+local trace_cache=false  trackers.register("resolvers.cache",function(v) trace_cache=v end)
+local report_caches=logs.reporter("resolvers","caches")
+local report_resolvers=logs.reporter("resolvers","caching")
+local resolvers=resolvers
+local cleanpath=resolvers.cleanpath
+local resolvepath=resolvers.resolve
+local luautilities=utilities.lua
+do
+ local directive_cleanup=false  directives.register("system.compile.cleanup",function(v) directive_cleanup=v end)
+ local directive_strip=false  directives.register("system.compile.strip",function(v) directive_strip=v end)
+ local compilelua=luautilities.compile
+ function luautilities.compile(luafile,lucfile,cleanup,strip)
+  if cleanup==nil then cleanup=directive_cleanup end
+  if strip==nil then strip=directive_strip   end
+  return compilelua(luafile,lucfile,cleanup,strip)
+ end
+end
+caches=caches or {}
+local caches=caches
+local writable=nil
+local readables={}
+local usedreadables={}
+local compilelua=luautilities.compile
+local luasuffixes=luautilities.suffixes
+caches.base=caches.base or (LUATEXENGINE and LUATEXENGINE.."-cache") or "luatex-cache"  
+caches.more=caches.more or "context"    
+caches.defaults={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" }
+local direct_cache=false 
+local fast_cache=false
+local cache_tree=false
+directives.register("system.caches.direct",function(v) direct_cache=true end)
+directives.register("system.caches.fast",function(v) fast_cache=true end)
+local function configfiles()
+ return concat(resolvers.configurationfiles(),";")
+end
+local function hashed(tree)
+ tree=gsub(tree,"[\\/]+$","")
+ tree=lower(tree)
+ local hash=md5hex(tree)
+ if trace_cache or trace_locating then
+  report_caches("hashing tree %a, hash %a",tree,hash)
+ end
+ return hash
+end
+local function treehash()
+ local tree=configfiles()
+ if not tree or tree=="" then
+  return false
+ else
+  return hashed(tree)
+ end
+end
+caches.hashed=hashed
+caches.treehash=treehash
+caches.configfiles=configfiles
+local function identify()
+ local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") 
+ if texmfcaches then
+  for k=1,#texmfcaches do
+   local cachepath=texmfcaches[k]
+   if cachepath~="" then
+    cachepath=resolvepath(cachepath)
+    cachepath=cleanpath(cachepath)
+    cachepath=collapsepath(cachepath)
+    local valid=isdir(cachepath)
+    if valid then
+     if is_readable(cachepath) then
+      readables[#readables+1]=cachepath
+      if not writable and is_writable(cachepath) then
+       writable=cachepath
+      end
+     end
+    elseif not writable then
+     local cacheparent=dirname(cachepath)
+     if is_writable(cacheparent) then 
+      mkdirs(cachepath)
+      if isdir(cachepath) and is_writable(cachepath) then
+       report_caches("path %a created",cachepath)
+       writable=cachepath
+       readables[#readables+1]=cachepath
+      end
+     end
+    end
+   end
+  end
+ end
+ local texmfcaches=caches.defaults
+ if texmfcaches then
+  for k=1,#texmfcaches do
+   local cachepath=texmfcaches[k]
+   cachepath=resolvers.expansion(cachepath) 
+   if cachepath~="" then
+    cachepath=resolvepath(cachepath)
+    cachepath=cleanpath(cachepath)
+    local valid=isdir(cachepath)
+    if valid and is_readable(cachepath) then
+     if not writable and is_writable(cachepath) then
+      readables[#readables+1]=cachepath
+      writable=cachepath
+      break
+     end
+    end
+   end
+  end
+ end
+ if not writable then
+  report_caches("fatal error: there is no valid writable cache path defined")
+  osexit()
+ elseif #readables==0 then
+  report_caches("fatal error: there is no valid readable cache path defined")
+  osexit()
+ end
+ writable=expanddirname(cleanpath(writable))
+ local base=caches.base
+ local more=caches.more
+ local tree=cache_tree or treehash() 
+ if tree then
+  cache_tree=tree
+  writable=mkdirs(writable,base,more,tree)
+  for i=1,#readables do
+   readables[i]=joinfile(readables[i],base,more,tree)
+  end
+ else
+  writable=mkdirs(writable,base,more)
+  for i=1,#readables do
+   readables[i]=joinfile(readables[i],base,more)
+  end
+ end
+ if trace_cache then
+  for i=1,#readables do
+   report_caches("using readable path %a (order %s)",readables[i],i)
+  end
+  report_caches("using writable path %a",writable)
+ end
+ identify=function()
+  return writable,readables
+ end
+ return writable,readables
+end
+function caches.usedpaths(separator)
+ local writable,readables=identify()
+ if #readables>1 then
+  local result={}
+  local done={}
+  for i=1,#readables do
+   local readable=readables[i]
+   if readable==writable then
+    done[readable]=true
+    result[#result+1]=formatters["readable+writable: %a"](readable)
+   elseif usedreadables[i] then
+    done[readable]=true
+    result[#result+1]=formatters["readable: %a"](readable)
+   end
+  end
+  if not done[writable] then
+   result[#result+1]=formatters["writable: %a"](writable)
+  end
+  return concat(result,separator or " | ")
+ else
+  return writable or "?"
+ end
+end
+local r_cache={}
+local w_cache={}
+local function getreadablepaths(...)
+ local tags={... }
+ local hash=concat(tags,"/")
+ local done=r_cache[hash]
+ if not done then
+  local writable,readables=identify() 
+  if #tags>0 then
+   done={}
+   for i=1,#readables do
+    done[i]=joinfile(readables[i],...)
+   end
+  else
+   done=readables
+  end
+  r_cache[hash]=done
+ end
+ return done
+end
+local function getwritablepath(...)
+ local tags={... }
+ local hash=concat(tags,"/")
+ local done=w_cache[hash]
+ if not done then
+  local writable,readables=identify() 
+  if #tags>0 then
+   done=mkdirs(writable,...)
+  else
+   done=writable
+  end
+  w_cache[hash]=done
+ end
+ return done
+end
+local function setfirstwritablefile(filename,...)
+ local wr=getwritablepath(...)
+ local fullname=joinfile(wr,filename)
+ return fullname,wr
+end
+local function setluanames(path,name)
+ return
+  format("%s/%s.%s",path,name,luasuffixes.tma),
+  format("%s/%s.%s",path,name,luasuffixes.tmc)
+end
+local function getfirstreadablefile(filename,...)
+ local fullname,path=setfirstwritablefile(filename,...)
+ if is_readable(fullname) then
+  return fullname,path 
+ end
+ local rd=getreadablepaths(...)
+ for i=1,#rd do
+  local path=rd[i]
+  local fullname=joinfile(path,filename)
+  if is_readable(fullname) then
+   usedreadables[i]=true
+   return fullname,path 
+  end
+ end
+ return fullname,path 
+end
+caches.getreadablepaths=getreadablepaths
+caches.getwritablepath=getwritablepath
+caches.setfirstwritablefile=setfirstwritablefile
+caches.getfirstreadablefile=getfirstreadablefile
+caches.setluanames=setluanames
+local checkmemory=utilities and utilities.lua and utilities.lua.checkmemory
+local threshold=100 
+function caches.loaddata(readables,name,writable)
+ local used=checkmemory and checkmemory()
+ if type(readables)=="string" then
+  readables={ readables }
+ end
+ for i=1,#readables do
+  local path=readables[i]
+  local loader=false
+  local state=false
+  local tmaname,tmcname=setluanames(path,name)
+  if isfile(tmcname) then
+   state,loader=pcall(loadfile,tmcname)
+  end
+  if not loader and isfile(tmaname) then
+   local tmacrap,tmcname=setluanames(writable,name)
+   if isfile(tmcname) then
+    state,loader=pcall(loadfile,tmcname)
+   end
+   compilelua(tmaname,tmcname)
+   if isfile(tmcname) then
+    state,loader=pcall(loadfile,tmcname)
+   end
+   if not loader then
+    state,loader=pcall(loadfile,tmaname)
+   end
+  end
+  if loader then
+   loader=loader()
+   if checkmemory then
+    checkmemory(used,threshold)
+   else 
+    collectgarbage("step") 
+   end
+   return loader
+  end
+ end
+ return false
+end
+function caches.is_writable(filepath,filename)
+ local tmaname,tmcname=setluanames(filepath,filename)
+ return is_writable(tmaname)
+end
+local saveoptions={ compact=true,accurate=not JITSUPPORTED }
+function caches.savedata(filepath,filename,data,fast)
+ local tmaname,tmcname=setluanames(filepath,filename)
+ data.cache_uuid=osuuid()
+ if fast or fast_cache then
+  savedata(tmaname,fastserialize(data,true))
+ elseif direct_cache then
+  savedata(tmaname,serialize(data,true,saveoptions))
+ else
+  serializetofile(tmaname,data,true,saveoptions)
+ end
+ compilelua(tmaname,tmcname)
+end
+local content_state={}
+function caches.contentstate()
+ return content_state or {}
+end

@@ Diff output truncated at 1234567 characters. @@


More information about the tex-live-commits mailing list.