Open main menu

Changes

=Introduction=
 
'''After [http://www.ntg.nl/EuroTeX2009 eurotex meeting 2009],
I'm going to fix some typos here and there and
maybe expand some examples too. I estimated that around 20 September article and site will be in synch.'''
 
 
----
'''!! W A R N I N G !! '''
'''!! THIS CODE WORKS ONLY UNDER LINUX !!'''
----
'''!! THIS CODE WORKS ONLY WITH luatex 0.38 42 !!'''----'''!! THIS CODE WORKS ONLY WITH ConTeXt version: 2009.07.17 17:23 '''
----
* to prevent symbols collisions between luatex and an arbitrary library
Having a A python interpreter hosted in luatex can make easy easier to use existing python's bindings ;also the ctype modules (also Python included in python releases includes at least from 2.5 a ctypes module that permit version) permits a binding to a .so without using SWIG or similar,similar to (almost like loadlib of lua's loadlib) .
As general rule, I want the smallest set of patches ; so, for example, I have choose to not use a system libpng, even if it's easy to modify
build.sh.linux to do so.
Also, I'm not concerned about portability: so I will talk only about Linux .
''Please note that '''luatex_lunatic''' was born to answer to (my) question "Can I apply lunatic to luatex ?" and nothing else.''
I prefear to put a bash script
that can help to compile a luatex-lunatic binary.
<!-- I have put all patches files [http://wiki.contextgarden.net/Image:Files.zip here] -->
It's clear that some skills are needed,
so I hope that in this is barrier way to avoid useless questions .
Of course, I will try to correct all errors .
The trick is "''hide all, then unhide what is needed" ;after that, "unhide", then make only what is needed and in the end re-compile luatex '' .<br/>
The changes are :
* in <tt>build.sh.linux</tt> add
<pre>
34a3528a29,4036
> export CONFIG_SHELL=/bin/bash
> STRIP_LUATEX=FALSE
> CFLAGS="-g -O2 -Wno-write-strings -fvisibility=hidden"
> CXXFLAGS="$CFLAGS -fvisibility-inlines-hidden"
> export CFLAGS
> export CXXFLAGS
>
>
>
</pre>
* in <tt>source/texk/web2c/luatexdir/lua51/loadlib.c</tt> <pre>
69c69
< void *lib = dlopen(path, RTLD_NOW);
</pre>
* in <tt>source/texk/web2c/Makefile.in</tt>:
<pre>
74c7498c98< @MINGW32_FALSE@am__append_7 am__append_14 = -DLUA_USE_POSIX
---
> @MINGW32_FALSE@am__append_7 am__append_14 = -DLUA_USE_LINUX1427c14271674c1674< $(CXXLINK) $(luatex_OBJECTS) $(luatex_LDADD) $(LIBS)
---
> $(CXXLINK) $(luatex_OBJECTS) $(luatex_LDADD) $(LIBS) -Wl,-E -uluaL_openlibs -fvisibility=hidden -fvisibility-inlines-hidden -ldl -lreadline -lhistory -lncurses 
</pre>
=Python packages=
* numpy These are python packages that are not in standard libraries ; "" means that I have made only small lua wrapper .<br/> * numpy,scipy * matplot ✔[[#Scipy| here]]
* odfpy ✔
* PIL, python imaging library ✔[[#Python_Imaging_Library_.28PIL.29| PILhere]] For these, I still have to decide what todo. 
* TO FIX ; pygegl (I like its syntax, but need too much and it's easy only in python)
* TODO: binding of libtiff with ctypes (or use [http://www.gdal.org gdal] ?)
* TODO :[http://glx.sourceforge.net gle ] (for Massimiliano "Max" Dominici, GUIT)
* TODO : using the binding of VIPS
=Bindings=
These are shared lib that come with native python binding, or eventually I have made a wrapper using ctypes .
* ghostscript 8.64 ✔ [[#Ghostscript|here]]
* graphviz 2.2224.0 ✔ [[#Graphviz|here]] * ImageMagick-6.4.9 with pythonmagickwand ✔[[#ImageMagick|here]]
* fontforge 20090224 ✔ [[#Fontforge|here]] Useful to check symbols collision, and if one want to play with the last fontforge, eg to draw the outline of a glyph .
* R-2.8.1 with rpy2-2.0.3 (For Maurizio "Mau" Himmelman , GUIT) ✔ need an example with output in pdf . See [[#R|here]] (someone says also [http://micahelliott.com/2009/03/considering-r-as-python-supplement hereconsidering-r-as-python-supplement ] ) .* quantlib 0.9.7 ✔ (need an example with output in pdf)* dbxml-2.4.16 (and sqlite) [[#dbxml|here]]
= Dedicated systems =
$HOME_LUN/sage/local/bin/python setup.py build
cd $HOME_LUN
mkdir tests-SAGEMATH && cd tests-SAGEMATH
##
## I have already installed prev. python.so, I don't want mess things
[[Image:Test-ode.png|900px]]
 
 
(other examples follows...)
==ROOT (CERN) ==
For more infos, see [http://root.cern.ch here] ([http://root.cern.ch/cgi-bin/print_hit_bold.pl/root/HowtoPyROOT.html?python#first_hit here] for python stuffs).
Under Linux installation is not difficult at all, so but in this case I choose to not create a luatex-lunatic apart, as done above for sagemath.<br/>See an example [[#ROOT| here]] . = ConTeXt mkIV examples=Here I will collect some tex snippets,just to show some ideas.
== Python Imaging Library (PIL) ==
<texcode>
\startluacode
function testPIL(imageorig,imagesepia)
require("python")
PIL_Image = python.import("PIL.Image")
PIL_ImageOps = python.import("PIL.ImageOps")
python.execute([[
def make_linear_ramp(white):
ramp = []
r, g, b = white
for i in range(255):
ramp.extend((r*i/255, g*i/255, b*i/255))
return ramp
]])
-- make sepia ramp (tweak color as necessary)
sepia = python.eval("make_linear_ramp((255, 240, 192))")
im = PIL_Image.open(imageorig)
-- convert to grayscale
if not(im.mode == "L")
then
im = im.convert("L")
end
-- optional: apply contrast enhancement here, e.g.
im = PIL_ImageOps.autocontrast(im)
 
-- apply sepia palette
im.putpalette(sepia)
 
-- convert back to RGB so we can save it as JPEG
-- (alternatively, save it in PNG or similar)
im = im.convert("RGB")
 
im.save(imagesepia)
end
\stopluacode
 
\def\SepiaImage#1#2{%
\ctxlua{testPIL("#1","#2")}%
\startcombination[2*1]
{\externalfigure[#1]}{\ss Orig.}
{\externalfigure[#2]}{\ss Sepia}
\stopcombination
}
 
 
\starttext
\startTEXpage
\SepiaImage{lena.jpg}{lena-sepia.jpg}
\stopTEXpage
\stoptext
</texcode>
 
[[Image:TestPIL.jpg]]
 
 
== ROOT ==
This example shot how to literally embed
original python source code .
{|<table>|-<tr>|<td><texcode>
\startluacode
function test_ROOT(filename)
\stopTEXpage
\stoptext
</texcode> </td> | <td> [[Image:Testsin.jpg|512px]]</td> </tr>|}</table>
We can do a bit better: separate python code from lua code .<br/>
|}
= ConTeXt mkIV examples=
Here I will collect some tex snippets,
just to show some ideas.
 
== Scipy ==
Watch how python code <tt> z = x*np.exp(-x**2-y**2) </tt>
is translated in lua code <tt> z = x.__mul__( np.exp( (x.__pow__(2).__add__(y.__pow__(2))).__neg__() ) )</tt>
 
 
{| class="wikitable"
|-
|<texcode>
\startluacode
function testSCIPY(figname,dpi)
require("python")
pg = python.globals()
python.apply = python.eval('apply') or {}
np = python.import("numpy")
mlab = python.import("matplotlib.mlab")
griddata = mlab.griddata
plt = python.import("matplotlib.pyplot")
ma = np.ma
random = python.import("numpy.random")
uniform = random.uniform
 
-- make up some randomly distributed data
npts = 200
x = uniform(-2,2,npts)
y = uniform(-2,2,npts)
-- z = x*np.exp(-x**2-y**2)
z = x.__mul__( np.exp( (x.__pow__(2).__add__(y.__pow__(2))).__neg__() ) )
-- define grid.
xi = np.linspace(-2.1,2.1,100)
yi = np.linspace(-2.1,2.1,100)
-- grid the data.
zi = griddata(x,y,z,xi,yi)
-- contour the gridded data, plotting dots
-- at the randomly spaced data points.
-- we put this in python globals space
-- CS = plt.contour(xi,yi,zi,15,linewidths=0.5,colors='k')
pg.xi = xi ; pg.yi = yi ; pg.zi = zi
args = python.eval("[xi,yi,zi,15]")
kv = python.eval("{'linewidth': 0.5 ,'colors' :'k'}")
CS = python.apply(plt.contour, args,kv)
--
pg.jet = plt.cm.jet
args = python.eval("[xi,yi,zi,15]")
kv = python.eval("{'cmap': jet}")
CS = python.apply(plt.contourf, args,kv)
-- draw colorbar
plt.colorbar()
-- plot data points.
pg.x = x; pg.y = y
args = python.eval("[x,y]")
kv = python.eval("{'marker': 'o', 'c':'b','s':5}")
CS = python.apply(plt.scatter, args,kv)
plt.xlim(-2,2)
plt.ylim(-2,2)
plt.title(string.format('griddata test (%i points)',npts))
--plt.savefig(figname, dpi, 'white')
--
pg.figname = figname ; pg.dpi = dpi
args = python.eval("[figname]")
kv = python.eval("{'dpi': dpi ,'facecolor' :'white'}")
CS = python.apply(plt.savefig, args,kv)
end
\stopluacode
 
 
\def\testSCIPY[#1]{%
\getparameters[scipy][#1]%
\ctxlua{testSCIPY("\csname scipyfigname\endcsname",
"\csname scipydpi\endcsname")}%
\externalfigure[\csname scipyfigname\endcsname]%
}
 
\starttext
\startTEXpage
\testSCIPY[figname={test-scipy-1.pdf},dpi={150}]
\stopTEXpage
\stoptext
</texcode>|| [[Image:Test-scipy.png|600px]]
|}
 
== Python Imaging Library (PIL) ==
 
{| class="wikitable"
|-
|<texcode>
\startluacode
function testPIL(imageorig,imagesepia)
require("python")
PIL_Image = python.import("PIL.Image")
PIL_ImageOps = python.import("PIL.ImageOps")
python.execute([[
def make_linear_ramp(white):
ramp = []
r, g, b = white
for i in range(255):
ramp.extend((r*i/255, g*i/255, b*i/255))
return ramp
]])
-- make sepia ramp (tweak color as necessary)
sepia = python.eval("make_linear_ramp((255, 240, 192))")
im = PIL_Image.open(imageorig)
-- convert to grayscale
if not(im.mode == "L")
then
im = im.convert("L")
end
-- optional: apply contrast enhancement here, e.g.
im = PIL_ImageOps.autocontrast(im)
 
-- apply sepia palette
im.putpalette(sepia)
 
-- convert back to RGB so we can save it as JPEG
-- (alternatively, save it in PNG or similar)
im = im.convert("RGB")
 
im.save(imagesepia)
end
\stopluacode
 
\def\SepiaImage#1#2{%
\ctxlua{testPIL("#1","#2")}%
\startcombination[2*1]
{\externalfigure[#1]}{\ss Orig.}
{\externalfigure[#2]}{\ss Sepia}
\stopcombination
}
 
 
\starttext
\startTEXpage
\SepiaImage{lena.jpg}{lena-sepia.jpg}
\stopTEXpage
\stoptext
</texcode> || [[Image:Test-PIL.png|330px]]
|}
 
 
 
== ImageMagick ==
''ImageMagick® '' ([http://www.imagemagick.org/script/index.php here]) ''is a software suite to create, edit, and compose bitmap images. It can read, convert and write images in a variety of formats (over 100) including DPX, EXR, GIF, JPEG, JPEG-2000, PDF, PhotoCD, PNG, Postscript, SVG, and TIFF. Use ImageMagick to translate, flip, mirror, rotate, scale, shear and transform images, adjust image colors, apply various special effects, or draw text, lines, polygons, ellipses and Bézier curves.
''
There are at least two python bindings, and this time I consider
[http://www.procoders.net/?p=39 PythonMagickWand] which is a binding "ala" ctypes way .
 
Code is simple
<texcode>
\usetypescriptfile[type-gentium]
\usetypescript[gentium]
\setupbodyfont[gentium,10pt]
\setuppapersize[A5][A5]
\setuplayout[height=middle,topspace=1cm,header={2\lineheight},footer=0pt,backspace=1cm,margin=1cm, width=middle]
 
 
\startluacode
function testimagemagick(box,t)
local w
local h
local d
local f
local res = 118.11023622047244094488 -- 300 dpi
local opacity = 25
local sigma = 15
local x = 10
local y = 10
 
require("python")
pg = python.globals()
PythonMagickWand = python.import("PythonMagickWand")
w = math.floor((tex.wd[box] / 65536 ) / 72.27 * 2.54 * res )
h = math.floor(((tex.ht[box] / 65536) + (tex.dp[box] / 65536)) / 72.27 *2.54 *res )
f = string.format("%s.png",t)
 
wand = PythonMagickWand.NewMagickWand()
background = PythonMagickWand.NewPixelWand(0)
-- PythonMagickWand.MagickNewImage(wand,w,h,background)
PythonMagickWand.MagickNewImage(wand,w,h,background)
 
PythonMagickWand.MagickSetImageResolution(wand,res,res)
PythonMagickWand.MagickSetImageUnits(wand,PythonMagickWand.PixelsPerCentimeterResolution)
PythonMagickWand.MagickShadowImage(wand,opacity,sigma,x,y)
PythonMagickWand.MagickWriteImage(wand ,f)
 
print(w,h,f)
end
\stopluacode
 
 
 
 
\def\testimagemagick[#1]{%
\getparameters[imagemagick][#1]%
\ctxlua{testimagemagick(\csname imagemagickbox\endcsname,"\csname imagemagickfilename\endcsname")}%
}
 
\newcount\shdw
\long\def\startShadowtext#1\stopShadowtext{%
\bgroup%
\setbox0=\vbox{#1}%
\testimagemagick[box=0,filename={shd-\the\shdw}]%
%%
\defineoverlay[backg][{\externalfigure[shd-\the\shdw.png]}]%
\framed[background=backg,frame=off,offset=4pt]{\box0}%
%%\framed{\box0}
\global\advance\shdw by 1%
\egroup%
}
 
\starttext
\startTEXpage%
\startShadowtext%
\input tufte
\stopShadowtext%
\stopTEXpage
\stoptext
</texcode>
And here is the result:
 
[[Image:Test-imagemagick.png]]
== Fontforge ==
In this example, we will use Metapost to draw a bezier curve of a glyph(''Note: starting from Metapost 1.200 it is now possible to get the actual path drawing routines from a font glyph, so this example is only to show how to translate a path in metapost'').<br/>
We will use 3-layer approach:
# a python layer that export a class,
def getcurve(self,letter):
self.glname = letter
res_Array = []
res = dict()
try :
#glyph_letter = [ g for g in self.font.glyphs() if g.glyphname == self.glname][0] g = self.font[letter]
except Exception ,e :
res['err'] = str(e)
res_Array.append(res) return resres_Array layer_idx = 0; cntfor layer_name in g.layers: layer = glyph_letterg.layers[1layer_name] for contour_idx in range(len(layer)): res = dict() contour = layer[contour_idx] contour_name = contour.name res[0'name']= contour.name res['is_quadratic'] = cntcontour.is_quadratic res['closed'] = cntcontour.closed res['points'] = [(p.x,p.y,"%i" %p.on_curve) for p in cnt contour ] res['design_size'] = self.font.design_size res['em'] = self.font.em res_Array.append(res) return resres_Array
def getmpostoutlinedrawmpostpath(self,letter): res res_Array = self.getcurve(letter) path state = 0 paths = '' for res in res_Array: temp = '' for p in res['points'] : if p[2]= ='1' : if state == 1 : temp = temp + '-- (%s,%s)' %(p[0] ,p[1]) ; state = 1; continue else: temp = temp + '..(%s,%s)'.join%( p[0] ,p[str1]) ; state = 1; continue if state == 1 : temp = temp + ' .. controls (%s,%s)' %(p[0],p[1]); state =2; continue if state == 2 : temp = temp + ' and (%s,%s) for ' %(p[0],p in [1]) ; state =0; continue if res['pointsclosed'] : if pstate == 1 : temp = 'draw ' + temp[2:] + " -- cycle;\n" else: temp ='draw ' + temp[2:] + " .. cycle;\n" else: temp = '1draw '+ temp[2:] )+ ";\n" paths = paths + temp return pathpaths
def getmpostpoints(self,letter):
res = self.getcurve(letter)
path = [str((p[0],p[1])) for p in res['points'] if p[2] == '1']
return path
  def getmpostpointsSugardrawmpostpoints(self,letter): res res_Array = self.getcurve(letter) path dots = '' for res in res_Array: temp = 'drawdot \n'.join( ["drawdot %s;" %str((p[0],p[1])) for p in res['points'] if p[2] == '1'] )+ "\n" dots = dots + temp return 'drawdot ' +pathdots
if __name__ == '__main__':
s = simpledraw("koeieletterslmmono10-regular.pfbotf") #res = s.getmpostpointsSugar('C') #print res #print s.getmpostoutline('C') print s.getcurve('e') print s.drawmpostpath('e') print s.drawmpostpoints('e') 
</pre>
Next lua layer, which in this case is embed in a tex file:
<texcode>
 
\setupcolors[state=start]
 
 
\startluacode
function testFontforge(fontfile,letter)
testoutlines = python.import("test-fontforge")
s = testoutlines.simpledraw(fontfile)
g = s.getmpostoutlinedrawmpostpath(letter) p = s.getmpostpointsSugardrawmpostpoints(letter) --print( string.format("\%s = \%s ==", letter,g )) tex.sprint(tex.ctxcatcodes,"\\startMPcode") tex.sprint(tex.ctxcatcodes,"pickup pencircle scaled 1pt;") tex.sprint(tex.ctxcatcodes,string.format("draw \%s .. cycle;",g) ) tex.sprint(tex.ctxcatcodes,"pickup pencircle scaled 8pt;") tex.sprint(tex.ctxcatcodes,string.format("\%s",p) ) tex.sprint(tex.ctxcatcodes,"\\stopMPcode")
end
\stopluacode
And this is the result: <br/>
[[Image:Test-fontforge.png|900px]]
 
...ok,it's not correct (why?), but it looks funny :)
 
== Ghostscript ==
For the first case, we consider an implementation of eps2pdf, being ps2pdf virtually the same .<br/>
Actually there is not a python binding of ghostscript, so we build a simple wrapper
using ctypes module<tt>testgs.py</tt> :
<pre>
[[Image:Test-ghostscript-barcode.png|900px]]
 
== Graphviz ==
[http://www.graphviz.org Graphviz] is a Graph Visualization Software .<br/>
Standard distribution comes with several binding (lua and python among others) so it's not difficult to integrate in luatex lunatic .<br/>
In this example, we draw a graph of the nodes of <context>\TeX</context>
<pre>
\def\StudyBox#1{%
\startluacode
require "python"
gv = python.import("gv")
g = gv.digraph("G")
gv.setv(g,'rankdir','LR')
 
nodes = nodes or {}
 
local nd = {};
local kd = {};
 
local k = 0;
local function nodesprint(head,n)
while head do
local id = head.id
local oldn = n
ndlbl = string.format("nd_\%03d",k)
texio.write_nl(string.format("id=\%s, ndlbl=\%s",id,ndlbl))
 
if id == node.id("vlist") then
k = k + 1
nd[n] = gv.node(g,ndlbl)
res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " ..
"vlist" .. "\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|width:" .. tostring(head.width) ..
"\|depth:" .. tostring(head.depth) .. "\|height:" .. tostring(head.height) ..
"\|dir:" .. tostring(head.dir) .. "\|shift:" .. tostring(head.shift) ..
"\|glue_order:" .. tostring(head.glue_order) ..
"\|glue_sign:" .. tostring(head.glue_sign) ..
"\|glue_set:" .. tostring(head.glue_set) ..
"\|list:" .. string.gsub(tostring(head.list),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
 
if id == node.id("rule") then
k = k + 1
nd[n] = gv.node(g,ndlbl)
res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "rule" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|width:" .. tostring(head.width) ..
"\|depth:" .. tostring(head.depth) ..
"\|height:" .. tostring(head.height) ..
"\|dir:" .. tostring(head.dir) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("ins") then
k = k + 1
nd[n] = gv.node(g,ndlbl)
res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "ins" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|cost:" .. tostring(head.cost) ..
"\|depth:" .. tostring(head.depth) ..
"\|height:" .. tostring(head.height) ..
"\|spec:" .. string.gsub(tostring(head.spec),"([><])","\\\%1") ..
"\|list:" .. string.gsub(tostring(head.list),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("mark") then
k = k + 1
nd[n] = gv.node(g,ndlbl)
res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "mark" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|class:" .. tostring(head.class) ..
"\|mark:" .. tostring(head.mark) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("adjust") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "adjust" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|list:" .. string.gsub(tostring(head.list),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("disc") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "disc" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|pre:" .. string.gsub(tostring(head.pre),"([><])","\\\%1") ..
"\|post:" .. string.gsub(tostring(head.post),"([><])","\\\%1") ..
"\|replace:" .. string.gsub(tostring(head.replace),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("whatsit") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
if head.subtype == node.subtype("write") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:write" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|stream:" .. tostring(head.stream) ..
"\|data:" .. tostring(head.data) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if head.subtype == node.subtype("close") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:close" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|stream:" .. tostring(head.stream) ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("special") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:special" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|data:" .. tostring(head.data) ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("local_par") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:local_par" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|pen_inter:" .. tostring(head.pen_inter) ..
"\|pen_broken:" .. tostring(head.pen_broken) ..
"\|dir:" .. tostring(head.dir) ..
"\|box_left:" .. tostring(head.box_left) ..
"\|box_left_width:" .. tostring(head.box_left_width) ..
"\|box_right:" .. tostring(head.box_right) ..
"\|box_right_width:" .. tostring(head.box_right_width) ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("dir") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:dir" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|dir:" .. tostring(head.dir) ..
"\|level:" .. tostring(head.level) ..
"\|dvi_ptr:" .. tostring(head.dvi_ptr) ..
"\|dvi_h:" .. tostring(head.dvi_h) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if head.subtype == node.subtype("pdf_literal") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:pdf_literal" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|mode:" .. tostring(head.mode) ..
"\|data:" .. tostring(head.data) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if head.subtype == node.subtype("pdf_refobj") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:pdf_refobj" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|objnum:" .. tostring(head.objnum) ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("pdf_refxform") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:pdf_refxform" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|width:" .. tostring(head.width) ..
"\|height:" .. tostring(head.height) ..
"\|depth:" .. tostring(head.depth) ..
"\|objnum:" .. tostring(head.objnum) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if head.subtype == node.subtype("pdf_refximage") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:pdf_refximage" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|width:" .. tostring(head.width) ..
"\|height:" .. tostring(head.height) ..
"\|depth:" .. tostring(head.depth) ..
"\|objnum:" .. tostring(head.objnum) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if head.subtype == node.subtype("pdf_annot") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:pdf_annot" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|width:" .. tostring(head.width) ..
"\|height:" .. tostring(head.height) ..
"\|depth:" .. tostring(head.depth) ..
"\|objnum:" .. tostring(head.objnum) ..
"\|data:" .. tostring(head.data) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if head.subtype == node.subtype("pdf_start_link") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:pdf_start_link" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|width:" .. tostring(head.width) ..
"\|height:" .. tostring(head.height) ..
"\|depth:" .. tostring(head.depth) ..
"\|objnum:" .. tostring(head.objnum) ..
"\|link_attr:" .. tostring(head.link_attr) ..
"\|action:" .. tostring(head.action) ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("pdf_end_link") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:pdf_end_link" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("pdf_dest") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:pdf_dest" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|width:" .. tostring(head.width) ..
"\|height:" .. tostring(head.height) ..
"\|depth:" .. tostring(head.depth) ..
"\|named_id:" .. tostring(head.named_id) ..
"\|dest_id:" .. tostring(head.dest_id) ..
"\|dest_type:" .. tostring(head.dest_type) ..
"\|xyz_zoom:" .. tostring(head.xyz_zoom) ..
"\|objnum:" .. tostring(head.objnum) ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("pdf_thread") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:pdf_thread" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|width:" .. tostring(head.width) ..
"\|height:" .. tostring(head.height) ..
"\|depth:" .. tostring(head.depth) ..
"\|named_id:" .. tostring(head.named_id) ..
"\|thread_id:" .. tostring(head.thread_id) ..
"\|thread_attr:" .. tostring(head.thread_attr) ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("pdf_start_thread") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:pdf_start_thread" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|width:" .. tostring(head.width) ..
"\|height:" .. tostring(head.height) ..
"\|depth:" .. tostring(head.depth) ..
"\|named_id:" .. tostring(head.named_id) ..
"\|thread_id:" .. tostring(head.thread_id) ..
"\|thread_attr:" .. tostring(head.thread_attr) ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("pdf_end_thread") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:pdf_end_thread" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("pdf_save_pos") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:pdf_save_pos" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("pdf_thread_data") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:pdf_thread_data" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("pdf_link_data") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:pdf_link_data" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("open") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:open" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|stream:" .. tostring(head.stream) ..
"\|name:" .. tostring(head.name) ..
"\|area:" .. tostring(head.area) ..
"\|ext:" .. tostring(head.ext) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if head.subtype == node.subtype("late_lua") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:late_lua" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|reg:" .. tostring(head.reg) ..
"\|data:" .. tostring(head.data) ..
"\|name:" .. tostring(head.name) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if head.subtype == node.subtype("fake") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:fake" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("pdf_colorstack") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:pdf_colorstack" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|stack:" .. tostring(head.stack) ..
"\|cmd:" .. tostring(head.cmd) ..
"\|data:" .. tostring(head.data) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if head.subtype == node.subtype("pdf_save") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:pdf_save" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("cancel_boundary") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:cancel_boundary" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("close_lua") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:close_lua" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|reg:" .. tostring(head.reg) ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("pdf_setmatrix") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:pdf_setmatrix" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|data:" .. tostring(head.data) ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("pdf_restore") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:pdf_restore" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if head.subtype == node.subtype("user_defined") then
res = gv.setv(nd[n],"label",tostring(k) .. " " .."whatsit:user_defined" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|user_id:" .. tostring(head.user_id) ..
"\|type:" .. tostring(head.type) ..
"\|value:" .. tostring(head.value) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
end
if id == node.id("math") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "math" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|surround:" .. tostring(head.surround) ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("glue") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "glue" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|spec:" .. string.gsub(tostring(head.spec),"([><])","\\\%1") ..
"\|leader:" .. tostring(head.leader) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("kern") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "kern" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|kern:" .. tostring(head.kern) ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("penalty") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "penalty" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|penalty:" .. tostring(head.penalty) ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("unset") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "unset" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|width:" .. tostring(head.width) ..
"\|depth:" .. tostring(head.depth) ..
"\|height:" .. tostring(head.height) ..
"\|dir:" .. tostring(head.dir) ..
"\|shrink:" .. tostring(head.shrink) ..
"\|glue_order:" .. tostring(head.glue_order) ..
"\|glue_sign:" .. tostring(head.glue_sign) ..
"\|stretch:" .. tostring(head.stretch) ..
"\|span:" .. tostring(head.span) ..
"\|list:" .. string.gsub(tostring(head.list),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("style") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "style" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|style:" .. tostring(head.style) ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("choice") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "choice" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|display:" .. tostring(head.display) ..
"\|text:" .. tostring(head.text) ..
"\|script:" .. tostring(head.script) ..
"\|scriptscript:" .. tostring(head.scriptscript) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("noad") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "noad" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|nucleus:" .. tostring(head.nucleus) ..
"\|sub:" .. tostring(head.sub) ..
"\|sup:" .. tostring(head.sup) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("op") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "op" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|nucleus:" .. tostring(head.nucleus) ..
"\|sub:" .. tostring(head.sub) ..
"\|sup:" .. tostring(head.sup) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("bin") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "bin" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|nucleus:" .. tostring(head.nucleus) ..
"\|sub:" .. tostring(head.sub) ..
"\|sup:" .. tostring(head.sup) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("rel") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "rel" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|nucleus:" .. tostring(head.nucleus) ..
"\|sub:" .. tostring(head.sub) ..
"\|sup:" .. tostring(head.sup) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("open") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "open" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|nucleus:" .. tostring(head.nucleus) ..
"\|sub:" .. tostring(head.sub) ..
"\|sup:" .. tostring(head.sup) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("close") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "close" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|nucleus:" .. tostring(head.nucleus) ..
"\|sub:" .. tostring(head.sub) ..
"\|sup:" .. tostring(head.sup) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("punct") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "punct" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|nucleus:" .. tostring(head.nucleus) ..
"\|sub:" .. tostring(head.sub) ..
"\|sup:" .. tostring(head.sup) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("inner") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "inner" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|nucleus:" .. tostring(head.nucleus) ..
"\|sub:" .. tostring(head.sub) ..
"\|sup:" .. tostring(head.sup) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("radical") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "radical" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|nucleus:" .. tostring(head.nucleus) ..
"\|sub:" .. tostring(head.sub) ..
"\|sup:" .. tostring(head.sup) ..
"\|left:" .. tostring(head.left) ..
"\|degree:" .. tostring(head.degree) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("fraction") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "fraction" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|width:" .. tostring(head.width) ..
"\|num:" .. tostring(head.num) ..
"\|denom:" .. tostring(head.denom) ..
"\|left:" .. tostring(head.left) ..
"\|right:" .. tostring(head.right) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("under") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "under" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|nucleus:" .. tostring(head.nucleus) ..
"\|sub:" .. tostring(head.sub) ..
"\|sup:" .. tostring(head.sup) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("over") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "over" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|nucleus:" .. tostring(head.nucleus) ..
"\|sub:" .. tostring(head.sub) ..
"\|sup:" .. tostring(head.sup) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("accent") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "accent" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|nucleus:" .. tostring(head.nucleus) ..
"\|sub:" .. tostring(head.sub) ..
"\|sup:" .. tostring(head.sup) ..
"\|accent:" .. tostring(head.accent) ..
"\|bot_accent:" .. tostring(head.bot_accent) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("vcenter") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "vcenter" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|nucleus:" .. tostring(head.nucleus) ..
"\|sub:" .. tostring(head.sub) ..
"\|sup:" .. tostring(head.sup) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("fence") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "fence" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|delim:" .. tostring(head.delim) ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("math_char") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "math_char" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|fam:" .. tostring(head.fam) ..
"\|char:" .. tostring(head.char) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("sub_box") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "sub_box" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|list:" .. string.gsub(tostring(head.list),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("sub_mlist") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "sub_mlist" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|list:" .. string.gsub(tostring(head.list),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("math_text_char") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "math_text_char" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|fam:" .. tostring(head.fam) ..
"\|char:" .. tostring(head.char) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("delim") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "delim" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|small_fam:" .. tostring(head.small_fam) ..
"\|small_char:" .. tostring(head.small_char) ..
"\|large_fam:" .. tostring(head.large_fam) ..
"\|large_char:" .. tostring(head.large_char) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("margin_kern") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "margin_kern" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|width:" .. tostring(head.width) ..
"\|glyph:" .. tostring(head.glyph) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("glyph") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "glyph" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|char:" .. tostring(head.char) ..
"\|font:" .. tostring(head.font) ..
"\|lang:" .. tostring(head.lang) ..
"\|left:" .. tostring(head.left) ..
"\|right:" .. tostring(head.right) ..
"\|uchyph:" .. tostring(head.uchyph) ..
"\|components:" .. string.gsub(tostring(head.components),"([><])","\\\%1") ..
"\|xoffset:" .. tostring(head.xoffset) ..
"\|yoffset:" .. tostring(head.yoffset) ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("align_record") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "align_record" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("pseudo_file") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "pseudo_file" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("pseudo_line") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "pseudo_line" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("page_insert") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "page_insert" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|height:" .. tostring(head.height) ..
"\|last_ins_ptr:" .. tostring(head.last_ins_ptr) ..
"\|best_ins_ptr:" .. tostring(head.best_ins_ptr) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("split_insert") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "split_insert" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|height:" .. tostring(head.height) ..
"\|last_ins_ptr:" .. tostring(head.last_ins_ptr) ..
"\|best_ins_ptr:" .. tostring(head.best_ins_ptr) ..
"\|broken_ptr:" .. tostring(head.broken_ptr) ..
"\|broken_ins:" .. tostring(head.broken_ins) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("expr_stack") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "expr_stack" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("nested_list") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "nested_list" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("span") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "span" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("attribute") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "attribute" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|number:" .. tostring(head.number) ..
"\|value:" .. tostring(head.value) ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("glue_spec") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "glue_spec" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|width:" .. tostring(head.width) ..
"\|stretch:" .. tostring(head.stretch) ..
"\|shrink:" .. tostring(head.shrink) ..
"\|stretch_order:" .. tostring(head.stretch_order) ..
"\|shrink_order:" .. tostring(head.shrink_order) ..
"\|ref_count:" .. tostring(head.ref_count) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("attribute_list") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "attribute_list" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1"))
end
if id == node.id("action") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "action" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|action_type:" .. tostring(head.action_type) ..
"\|named_id:" .. tostring(head.named_id) ..
"\|action_id:" .. tostring(head.action_id) ..
"\|file:" .. tostring(head.file) ..
"\|new_window:" .. tostring(head.new_window) ..
"\|data:" .. tostring(head.data) ..
"\|ref_count:" .. tostring(head.ref_count) ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("temp") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "temp" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("align_stack") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "align_stack" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("movement_stack") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "movement_stack" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("if_stack") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "if_stack" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("unhyphenated") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "unhyphenated" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("hyphenated") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "hyphenated" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("delta") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "delta" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("passive") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "passive" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("shape") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "shape" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("hlist") then
k = k + 1
nd[n] = gv.node(g,ndlbl) res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "hlist" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|attr:" .. string.gsub(tostring(head.attr),"([><])","\\\%1") ..
"\|width:" .. tostring(head.width) ..
"\|depth:" .. tostring(head.depth) ..
"\|height:" .. tostring(head.height) ..
"\|dir:" .. tostring(head.dir) ..
"\|shift:" .. tostring(head.shift) ..
"\|glue_order:" .. tostring(head.glue_order) ..
"\|glue_sign:" .. tostring(head.glue_sign) ..
"\|glue_set:" .. tostring(head.glue_set) ..
"\|list:" .. string.gsub(tostring(head.list),"([><])","\\\%1") ..
"\|prev:" .. string.gsub(tostring(head.prev),"([><])","\\\%1") ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
if id == node.id("fake") then
k = k + 1
nd[n] = gv.node(g,ndlbl)
res = gv.setv(nd[n],"shape","record")
res = gv.setv(nd[n],"label",tostring(k) .. " " .. "fake" ..
"\|id:" .. tostring(head.id) ..
"\|subtype:" .. tostring(head.subtype) ..
"\|next:" .. string.gsub(tostring(head.next),"([><])","\\\%1"))
end
kd[k] = nd[n]
e1 = gv.edge(kd[k-1],kd[k])
if id == node.id('hlist') or id == node.id('vlist') then
%% If we want to connect nested (h|v)list
%%
%%e = gv.edge(nd[n-1],nd[n])
%%gv.setv(e,'arrowhead','diamond')
nodesprint(head.list,( n or 0) +1)
end
head = head.next
end
end
 
local head = tex.box[#1]
nodesprint(head,0)
r = gv.layout(g,"dot")
r = gv.render(g,'pdf',string.format('box\%d.pdf',#1))
\stopluacode%%
}
 
\starttext
\startTEXpage
\setbox0=\hbox{\TeX}
\hbox to 29cm{\strut\hss\copy0\hss}
\StudyBox{0}%
\externalfigure[box0.pdf][width=29cm]
\stopTEXpage
\stoptext
</pre>
[[Image:Graphviz.png|900px]]
 
== R ==
R is a language and environment for statistical computing and graphics [http://www.r-project.org (see here)] . <br/>
RPy is a very simple, yet robust, Python interface to the R Programming Language [http://rpy.sourceforge.net (see here)] . <br/>
As example, let's try to plot a discrete distribution of probability for a set of pseudorandom number (around 100000 samples) .
<pre>
import rpy2.robjects as robjects
import rpy2.rinterface as rinterface
 
class density(object):
 
def __init__(self,samples,outpdf,w,h,kernel):
self.samples = samples
self.outpdf= outpdf
self.kernel = kernel
self.width=w
self.height=h
 
def run(self):
r = robjects.r
data = [int(k.strip()) for k in file(self.samples,'r').readlines()]
x = robjects.IntVector(data)
r.pdf(file=self.outpdf,width=self.width,height=self.height)
z = r.density(x,kernel=self.kernel)
#r.plot(z[0],z[1],xlab='',ylab='',xlim=robjects.IntVector([0,2**16-1]))
r.plot(z[0],z[1],xlab='',ylab='')
r['dev.off']()
 
 
if __name__ == '__main__' :
dens = density('u-random-int','test-001.pdf',10,7,'o')
dens.run()
</pre>
 
 
 
<texcode>
\startluacode
function testR(samples,outpdf,w,h,kernel)
require("python")
testR = python.import("test-R")
dens = testR.density(samples,outpdf,w,h,kernel)
dens.run()
end
\stopluacode
 
\def\plotdenstiy[#1]{%
\getparameters[R][#1]%
\expanded{\ctxlua{testR("\Rsamples","\Routpdf",\Rwidth,\Rheight,"\Rkernel")}}%
}
 
\setupbodyfont[sans,10pt]
\starttext
\startTEXpage
\plotdenstiy[samples={u-random-int},outpdf={test-001.pdf},width={10},height={7},kernel={o}]
\setupcombinations[location=top]
\startcombination[1*2]
{\vbox{\hsize=400bp
This is a density plot of around {\tt 100 000} random numbers between $0$ and $2^{16}-1$ generated from {\tt \hbox{/dev/urandom}}}}{}
{\externalfigure[test-001.pdf][width={400bp}]}{}
\stopcombination
\stopTEXpage
\stoptext
</texcode>
 
And here is the plot <br/>
 
[[Image:Test-R.png]]
 
== dbxml ==
From site [http://www.oracle.com/database/berkeley-db/xml/index.html (see here)] :
 
''Oracle Berkeley DB XML is an open source, embeddable XML database with XQuery-based access to documents stored in containers and indexed based on their content. Oracle Berkeley DB XML is built on top of Oracle Berkeley DB and inherits its rich features and attributes. Like Oracle Berkeley DB, it runs in process with the application with no need for human administration. Oracle Berkeley DB XML adds a document parser, XML indexer and XQuery engine on top of Oracle Berkeley DB to enable the fastest, most efficient retrieval of data.
''
 
As test, we can use a dump from wikiversity [http://en.wikiversity.org/wiki/Getting_stats_out_of_Wikiversity_XML_dumps (see here)] .
 
 
=== Build the cointainer ===
First we build the container 'Data.dbxml' in the directory "wikienv" (that must exists) :
<pre>
"""
---
"""
from bsddb3.db import *
from dbxml import *
import sys
import re
import time
 
def createEnvironment(home):
"""Create DBEnv and initialize XmlManager"""
try:
environment = DBEnv()
#
environment.set_cachesize(0,512 * 1024 *1024,1)
environment.set_lk_max_lockers(10000)
environment.set_lk_max_locks(10000)
environment.set_lk_max_objects(10000)
# initialize DBEnv for transactions
environment.open(home, DB_RECOVER|DB_CREATE|DB_INIT_LOCK|DB_DSYNC_LOG|
DB_INIT_LOG|DB_INIT_MPOOL|DB_INIT_TXN, 0)
except DBError, exc:
print exc
sys.exit()
try:
mgr = XmlManager(environment, 0)
mgr.setDefaultPageSize(4096)
except XmlException, se:
print xe
sys.exit()
return mgr
 
def createContainer(mgr, containerName, flags):
"""create/open a node container"""
try:
uc = mgr.createUpdateContext()
container = mgr.openContainer(containerName,
flags|DB_CREATE,
XmlContainer.WholedocContainer)
container.addIndex("","title","edge-element-substring-string",uc)
container.addIndex("","username","edge-element-substring-string",uc)
container.addIndex("","text","edge-element-substring-string",uc)
return container
except XmlException, ex:
print ex
sys.exit()
 
 
def loadcontent(mgr, container,content,printmsg,k):
""" -- """
id= re.compile(r"<id>(.*)</id>")
title = re.compile(r"<title>(.*)</title>",re.MULTILINE|re.DOTALL)
 
id_text = id.search(content,re.MULTILINE|re.DOTALL).group(1)
title_text = title.search(content).group(1)
docName = '_'.join(title_text.split()) + '_' +id_text
txn = False
try:
# all Container modification operations need XmlUpdateContext
uc = mgr.createUpdateContext()
# create XmlTransaction for the operation
txn = mgr.createTransaction()
# use the DBXML_GEN_NAME flag to make sure this
# succeeds by creating a new, unique name
# Use a try/except block to allow the transaction to
# be aborted in the proper scope upon error
try:
docName = container.putDocument(txn, docName,
content, uc,
DBXML_GEN_NAME)
txn.commit()
except XmlException, ex:
print k,ex
txn.abort()
if printmsg:
# now, get the document in a new transaction
txn = mgr.createTransaction()
doc = container.getDocument(txn, docName)
name = doc.getName()
docContent = doc.getContentAsString()
txn.commit() # done with data
# print the name and content
print name
pass
except XmlException, inst:
print inst
if txn:
txn.abort()
 
# "main"
def main():
home = "wikienv"
# some configuration...
containerName = "Data.dbxml"
# initialize...
mgr = createEnvironment(home)
# create/open a transactional container
container = createContainer(mgr, containerName,
DBXML_TRANSACTIONAL)
 
startpage = re.compile(r"^\s*<page>\s*$")
endpage = re.compile(r"^\s*</page>\s*$")
id= re.compile(r"<id>(.*)</id>")
title = re.compile(r"<title>(.*)</title>",re.MULTILINE|re.DOTALL)
text = re.compile(r"<text ([^>]*)>(.*)</text>",re.MULTILINE|re.DOTALL)
k,k1,k2 = 0,0,0
startcollect = False
#src = file("enwiki-latest-pages-articles.xml","rb")
src = file("enwikiversity-20090627-pages-articles.xml",'rb')
for line in src:
try:
k1 = k1 +1
except:
k1 = 0
if divmod(k1,10000)[0]>0 and divmod(k1,10000)[1] == 0 :
print "k1=%012d,k=%012d ,sleep 1 sec." % (k1,k)
#time.sleep(1)
if startcollect and endpage.match(line) is None:
temp = ''.join((temp,line))
continue
if startpage.match(line) is not None:
temp = line
startcollect = True
pos = src.tell()
continue
if endpage.match(line) is not None:
content = ''.join((temp,line))
startcollect = False
if title.search(content) is not None and id.search(content) is not None:
#title_text = title.search(temp).group(1)
#id_text , content_len = id.search(temp,re.MULTILINE|re.DOTALL).group(1), len(temp)
#text_text = ((text.search(temp) is not None and text.search(temp).group(2)) or '' )+ ' ' + title_text
#keywords = [kk.lower() for kk in re.split("\W",text_text)
# if len(kk) >4 and kk.lower() != 'redirect'
# and kk.lower() != 'disambiguation' ]
#keywords.append(title_text)
#keywords = list(set(keywords))
#keywords.sort()
printmesg = False
if divmod(k,100)[1] == 0 and divmod(k,100)[0] >0:
print "%012d sync" %k
container.sync()
#del container
#container = mgr.openContainer(containerName,DBXML_TRANSACTIONAL)
#if divmod(k,1200)[1] == 0 and divmod(k,1200)[0] == 1:
#print k,title_text,id_text ,pos,content_len,keywords#,temp
#printmesg = True
#print '%09d insert data...'%k,
#return
loadcontent(mgr,container,content,printmesg,k)
k = k+1
src.close()
 
if __name__ == "__main__":
main()
</pre>
 
=== Make pdf ===
We use this modules <tt>wikidbxml_queryTxn.py</tt>
to retrive a page, given a title (it can be also used as basis to build more complex queries, but for now it's adeguate ):
 
<pre>
from lxml import etree
from bsddb3.db import *
from dbxml import *
import StringIO
import fcntl
import os
import pprint
import sys
import time
import mwlib.docbookwriter
from mwlib.dummydb import DummyDB
from mwlib.uparser import parseString
 
 
def getXML(title,res):
db = DummyDB()
r = parseString(title=title, raw=res, wikidb=db)
dbw = mwlib.docbookwriter.DocBookWriter()
dbw.writeBook(r)
pprint.pprint( dbw.getTree() )
return dbw.asstring()
 
 
def getConTeXt(title,res):
db = DummyDB()
r = parseString(title=title, raw=res, wikidb=db)
dbw = mwlib.docbookwriter.DocBookWriter()
dbw.writeBook(r)
article = dbw.getTree()
res = []
 
def managepara(c,res):
if c.tag == 'para' and (c.text is not None):
res.append(c.text.strip()+r"\par")
if c.tag == 'para' and (len(c.getchildren())>0):
for c1 in c.iterchildren('ulink'):
res.append(r'cfr~\type{%s}\par' %c1.get('url'))
 
 
def managetable(c,res):
if c.tag == 'informaltable' :
res.append(r'\bTABLE')
for row in c.iterchildren():
res.append(r'\bTR')
for col in row.iterchildren():
res.append(r'\bTD '+ col.text.strip()+ r'\eTD')
res.append(r'\eTR')
res.append(r'\eTABLE')
 
def section_content(c,res):
managepara(c,res)
if c.tag == 'section' :
subsection = c
subsection_title = subsection.find("sectioninfo").find("title").text.strip()
res.append(r"\subsection{%s}" % subsection_title)
for sc in subsection.iterchildren():
subsection_content(sc,res)
 
def subsection_content(c,res):
managepara(c,res)
if c.tag == 'section' :
subsubsection = c
subsubsection_title = subsubsection.find("sectioninfo").find("title").text.strip()
res.append(r"\subsubsection{%s}" % subsubsection_title)
for sc in subsubsection.iterchildren():
subsubsection_content(sc,res)
if c.tag == 'informaltable' :
managetable(c,res)
 
 
def subsubsection_content(c,res):
managepara(c,res)
 
 
chapter_title = article.find("articleinfo").find("title").text
res.append(r"\chapter{%s}" % chapter_title)
 
section = article.find("section")
section_title = section.find("sectioninfo").find("title").text
res.append(r"\section{%s}" % section_title)
 
for c in section.iterchildren():
section_content(c,res)
#pprint.pprint(res)
return '\n'.join(res)
 
 
 
 
 
def query(env=None,mgr=None,container=None,querystring='Foo'):
""" Always check with queryPlan
(for example matches is not optimized for indexes)
"""
anID = env.lock_id()
lock = env.lock_get(anID, "shared lock", DB_LOCK_READ)
updateContext = mgr.createUpdateContext();
try:
txn = mgr.createTransaction()
resultsContext = mgr.createQueryContext()
#queryString = "collection('%s')/page[contains(title,'%s')]" % (container.getName(),data)
#queryString = "collection('%s')%s" % (container.getName(),querystring)
results = mgr.query(txn, querystring, resultsContext)
res = [res.asString() for res in results]
txn.commit()
return res
#print "START",book_name
##
##
except XmlException, inst:
txn.abort()
print "XmlException (", inst.exceptionCode,"): ", inst.what#,'name=',theName
if inst.exceptionCode == DATABASE_ERROR:
print "Database error code:",inst.dbError
env.lock_put(lock)
env.lock_id_free(anID)
print 'OK exit'
 
def getArtitleByTitle(title):
pass
env = DBEnv()
env.set_cachesize(0, 64 * 1024 * 1024, 1)
path2DbEnv ='wikienv'
env.open(path2DbEnv,DB_THREAD|DB_REGISTER|DB_RECOVER|DB_INIT_MPOOL|DB_CREATE|DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN, 0)
mgr = XmlManager(env,0)
containerTxn = mgr.createTransaction()
theContainer = "Data.dbxml"
container = mgr.openContainer(containerTxn, theContainer)
containerTxn.commit()
##
lockfile = open("lock.kmgr", "w")
fcntl.flock(lockfile, fcntl.LOCK_EX)
try:
res = set()
querystring = 'collection("%s")/page[contains(title,"%s")]/revision/text/text()' % (theContainer,title)
res = res.union(query(env,mgr,container,querystring=querystring))
res = ''.join(list(res)).decode('utf8')
#res = getXML(title,res)
#open('res.dbk','w').write( " ".join(res.split()) )
res = getConTeXt(title,res)
return res
except Exception,e:
print "error on read:" ,e
fcntl.flock(lockfile, fcntl.LOCK_UN)
lockfile.close()
 
def writeres(title,preamble,postamble,filename):
 
res = getArtitleByTitle(title=title)
if res is not None :
res = res.replace('&',r'\&')
res = res.replace('#',r'\#')
else:
res = ''
open(filename,'wb').write( '\n'.join((preamble,res,postamble)) )
 
pass
 
if __name__ == '__main__':
 
preamble = r"""\usetypescriptfile[type-gentium]
\usetypescript[gentium]
\setupbodyfont[gentium,10pt]
\setuppapersize[A5][A5]
\setuplayout[height=middle,topspace=1cm,header={2\lineheight},footer=0pt,backspace=1cm,margin=1cm, width=middle]
\starttext"""
 
postamble = r"""\stoptext"""
 
 
title="Primary mathematics/Numbers"
filename = 'res.tex'
writeres(title,preamble,postamble,filename)
</pre>
 
And in the end mkiv wrapper:
<texcode>
\usetypescriptfile[type-gentium]
\usetypescript[gentium]
\setupbodyfont[gentium,10pt]
\setuppapersize[A5][A5]
\setuplayout[height=middle,topspace=1cm,header={2\lineheight},footer=0pt,backspace=1cm,margin=1cm, width=middle]
 
 
\startluacode
function testdbxml(title,preamble,postamble,filename)
require("python")
pg = python.globals()
wikiversity = python.import("wikidbxml_queryTxn")
wikiversity.writeres(title,preamble,postamble,filename)
end
\stopluacode
 
\def\testdbxml[#1]{%
\getparameters[dbxml][#1]%
\ctxlua{testdbxml("\csname dbxmltitle\endcsname","\csname dbxmlpreamble\endcsname",
"\csname dbxmlpostamble\endcsname","\csname dbxmlfilename\endcsname")}%
\input \csname dbxmlfilename\endcsname %
}
 
 
 
\starttext
\testdbxml[title={Primary mathematics/Numbers},
preamble={},
postamble={},
filename={testres.tex}]
\stoptext
</texcode>
 
Here here the result:
 
<table class="wikitable">
<tr><td></td> <td>[[Image:Dbxml-1.png]]</td></tr>
<tr><td>[[Image:Dbxml-2.png]]</td> <td>[[Image:Dbxml-3.png]]</td></tr>
</table>
 
One can also use sqlite that comes with python to query for titles <tt>category.db</tt>
made from (for example) <tt>enwikiversity-20090627-category.sql</tt>,
so reports are more simpler:
just put this in python code above, right before 'if __name__' ...:
<pre>
import sqlite3
def querycategory(title):
conn = sqlite3.connect('category.db')
c = conn.cursor()
t = (title,)
c.execute('select cat_title from category where cat_title like "%%%s%%" ;' % t)
res = [row[0] for row in c]
conn.commit()
c.close()
return res
 
 
def simplereports(title):
res = querycategory(title)
j = 0
for r in res:
g = r.replace('_',' ')
print g
title= g.encode('utf8')
filename = 'reps%04d.tex' % j
writeres(title,'','',filename)
j = j+1
return j
 
</pre>
 
Similary, add this to tex code
<texcode>
\startluacode
function listtitles(title)
require("python")
pg = python.globals()
wikiversity = python.import("wikidbxml_queryTxn")
r = wikiversity.querycategory(title)
local j = 0
local res = r[j] or {}
while res do
local d = string.format("\%s\\par",string.gsub(tostring(res),'_',' '))
tex.sprint(tex.ctxcatcodes,d)
j = j+1
res = r[j]
end
end
\stopluacode
 
 
\startluacode
function simplereports(title)
require("python")
pg = python.globals()
wikiversity = python.import("wikidbxml_queryTxn")
r = wikiversity.simplereports(title)
local j = tonumber(r)
for v = 0,j-1 do
local d = string.format("\\input reps\%04d ",v)
tex.sprint(tex.ctxcatcodes,d)
end
print( j )
end
\stopluacode
</texcode>
 
and test it with
 
<texcode>
\starttext
{\bfb Query for 'geometr':}
\ctxlua{listtitles("geometr")}%
\ctxlua{simplereports("geometr")}%
\stoptext
</texcode>
 
(query results are stored in reps0001.tex ,reps0002.tex ,..and so on.)