if not modules then modules = { } end modules ['node-ini'] = {
    version   = 1.001,
    comment   = "companion to node-ini.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

local next, type, tostring = next, type, tostring
local gsub = string.gsub
local concat, remove = table.concat, table.remove
local sortedhash, sortedkeys, swapped = table.sortedhash, table.sortedkeys, table.swapped

-- Access to nodes is what gives LuaTeX its power. Here we implement a few helper
-- functions. These functions are rather optimized.

nodes                = nodes or { }
local nodes          = nodes
nodes.handlers       = nodes.handlers or { }

local mark           = utilities.storage.mark
local allocate       = utilities.storage.allocate
local formatcolumns  = utilities.formatters.formatcolumns

local getsubtypes    = node.subtypes
----- getvalues      = node.values

local listcodes      = mark(getsubtypes("list"))
local rulecodes      = mark(getsubtypes("rule"))
local dircodes       = mark(getsubtypes("dir"))
local markcodes      = mark(getsubtypes("mark"))
local glyphcodes     = mark(getsubtypes("glyph"))
local disccodes      = mark(getsubtypes("disc"))
local gluecodes      = mark(getsubtypes("glue"))
local boundarycodes  = mark(getsubtypes("boundary"))
local penaltycodes   = mark(getsubtypes("penalty"))
local kerncodes      = mark(getsubtypes("kern"))
local mathcodes      = mark(getsubtypes("math"))
local noadcodes      = mark(getsubtypes("noad"))
local radicalcodes   = mark(getsubtypes("radical"))
local accentcodes    = mark(getsubtypes("accent"))
local fencecodes     = mark(getsubtypes("fence"))
local choicecodes    = mark(getsubtypes("choice"))
local fractioncodes  = mark(getsubtypes("fraction"))
local parcodes       = mark(getsubtypes("par"))
-- local attributecodes = mark(getsubtypes("attribute"))

local function simplified(t)
    local r = { }
    for k, v in next, t do
        r[k] = gsub(v,"_","")
    end
    return r
end

local nodecodes = simplified(node.types())

gluecodes      = allocate(swapped(gluecodes,gluecodes))
dircodes       = allocate(swapped(dircodes,dircodes))
markcodes      = allocate(swapped(markcodes,markcodes))
boundarycodes  = allocate(swapped(boundarycodes,boundarycodes))
noadcodes      = allocate(swapped(noadcodes,noadcodes))
radicalcodes   = allocate(swapped(radicalcodes,radicalcodes))
nodecodes      = allocate(swapped(nodecodes,nodecodes))
listcodes      = allocate(swapped(listcodes,listcodes))
glyphcodes     = allocate(swapped(glyphcodes,glyphcodes))
kerncodes      = allocate(swapped(kerncodes,kerncodes))
penaltycodes   = allocate(swapped(penaltycodes,penaltycodes))
mathcodes      = allocate(swapped(mathcodes,mathcodes))
disccodes      = allocate(swapped(disccodes,disccodes))
accentcodes    = allocate(swapped(accentcodes,accentcodes))
fencecodes     = allocate(swapped(fencecodes,fencecodes))
choicecodes    = allocate(swapped(choicecodes,choicecodes))
fractioncodes  = allocate(swapped(fractioncodes,fractioncodes))
parcodes       = allocate(swapped(parcodes,parcodes))
-- attributecodes = allocate(swapped(attributecodes,attributecodes))
rulecodes      = allocate(swapped(rulecodes,rulecodes))

nodes.gluecodes      = gluecodes
nodes.dircodes       = dircodes
nodes.markcodes      = markcodes
nodes.boundarycodes  = boundarycodes
nodes.noadcodes      = noadcodes
nodes.listcodes      = listcodes
nodes.glyphcodes     = glyphcodes
nodes.kerncodes      = kerncodes
nodes.penaltycodes   = penaltycodes
nodes.mathcodes      = mathcodes
nodes.disccodes      = disccodes
nodes.accentcodes    = accentcodes
nodes.radicalcodes   = radicalcodes
nodes.fencecodes     = fencecodes
nodes.choicecodes    = choicecodes
nodes.fractioncodes  = fractioncodes
nodes.parcodes       = parcodes
-- nodes.attributecodes = attributecodes
nodes.rulecodes      = rulecodes

nodes.nodecodes      = nodecodes

-- these are now in tex namespace but we keep them for old times sake

nodes.fillvalues      = tex.fillcodes
nodes.fillcodes       = tex.fillcodes
nodes.dirvalues       = tex.directioncodes
nodes.directionvalues = tex.directioncodes
nodes.mathvalues      = tex.mathparametercodes

-- we will transition to more verbose subtypes (after other math is done)

noadcodes.ord      = noadcodes.ord   or noadcodes.ordinary
noadcodes.operator = noadcodes.op    or noadcodes.operator
noadcodes.bin      = noadcodes.bin   or noadcodes.binary
noadcodes.rel      = noadcodes.rel   or noadcodes.relation
noadcodes.punct    = noadcodes.punct or noadcodes.punctuation
noadcodes.rad      = noadcodes.rad   or noadcodes.radical
noadcodes.frac     = noadcodes.frac  or noadcodes.fraction
noadcodes.acc      = noadcodes.acc   or noadcodes.accent

-- so for now:

noadcodes.ordinary    = noadcodes.ordinary    or noadcodes.ord
noadcodes.operator    = noadcodes.operator    or noadcodes.op
noadcodes.binary      = noadcodes.binary      or noadcodes.bin
noadcodes.relation    = noadcodes.relation    or noadcodes.rel
noadcodes.punctuation = noadcodes.punctuation or noadcodes.punct
noadcodes.radical     = noadcodes.radical     or noadcodes.rad
noadcodes.fraction    = noadcodes.fraction    or noadcodes.frac
noadcodes.accent      = noadcodes.accent      or noadcodes.acc

local subtypes = allocate {
    glue      = gluecodes,
    dir       = dircodes,
    mark      = markcodes,
    boundary  = boundarycodes,
    noad      = noadcodes,
    glyph     = glyphcodes,
    kern      = kerncodes,
    penalty   = penaltycodes,
    math      = mathcodes,
    disc      = disccodes,
    accent    = accentcodes,
    radical   = radicalcodes,
    fence     = fencecodes,
    choice    = choicecodes,
    par       = parcodes,
--     attribute = attributecodes,
    rule      = rulecodes,

    vlist     = listcodes,
    hlist     = listcodes,

 -- list      = listcodes,

 -- parameter = parametercodes,
 -- user      = usercodes,
}

for k, v in table.sortedhash(subtypes) do
    local i = nodecodes[k]
    if i and not subtypes[i] then
        subtypes[i] = v
    end
end

nodes.subtypes = subtypes

-- a few more friendly aliases:

nodes.skipcodes            = gluecodes
nodes.directioncodes       = dircodes
nodes.discretionarycodes   = disccodes

glyphcodes.glyph           = glyphcodes.character

gluecodes.parfillrightskip = gluecodes.parfillrightskip or gluecodes.parfillskip
gluecodes.parfillskip      = gluecodes.parfillskip      or gluecodes.parfillrightskip

listcodes.row              = listcodes.alignment
listcodes.column           = listcodes.alignment

kerncodes.italiccorrection = kerncodes.italiccorrection
kerncodes.italickern       = kerncodes.italiccorrection -- compatibility

-- We use the real node code numbers.

local texsetintegervalue = tex.setintegervalue

for i=0,nodecodes.glyph do
    texsetintegervalue(nodecodes[i] .. "nodecode",i,"immutable")
end
texsetintegervalue("tempnodecode",nodecodes.temp,"immutable") -- can happen in tables

for i=0,#gluecodes do
    texsetintegervalue(gluecodes[i] .. "subtypecode",i,"immutable")
end

nodes.specialskipcodes = {
    [gluecodes.leftskip]                             = true,
    [gluecodes.rightskip]                            = true,
    [gluecodes.lefthangskip]                         = true,
    [gluecodes.righthangskip]                        = true,
    [gluecodes.parfillleftskip  or parfillskip_code] = true,
    [gluecodes.parfillrightskip or parfillskip_code] = true,
    [gluecodes.indentskip]                           = true,
    [gluecodes.correctionskip]                       = true,
}

-- at this time mathematics is not yet defined but it will be

table.setmetatableindex(listcodes,function(t,k)
    local v
 -- if mathematics then
        if type(k) == "string" then
            v = mathematics.classes[k] + 0x100
        else
            local i = k - 0x100
            v = mathematics.classes[i] or mathematics.classnames[i]
        end
 -- end
    if not v then
        v = listcodes.unknown
    end
    t[k] = v
    return v
end)
