##// END OF EJS Templates
deprecated @ipy header prefix, use @cl alone as first body line instead...
Ville M. Vainio -
Show More
@@ -1,317 +1,334 b''
1 """ Leo plugin for IPython
1 """ ILeo - Leo plugin for IPython
2
2
3 Example use:
4
5 nodes.foo = "hello world"
6
7 -> create '@ipy foo' node with text "hello world"
8
9 Access works also, and so does tab completion.
10
3
11 """
4 """
12 import IPython.ipapi
5 import IPython.ipapi
13 import IPython.genutils
6 import IPython.genutils
14 import IPython.generics
7 import IPython.generics
15 import re
8 import re
16
9 import UserDict
17
10
18
11
19 ip = IPython.ipapi.get()
12 ip = IPython.ipapi.get()
20 leo = ip.user_ns['leox']
13 leo = ip.user_ns['leox']
21 c,g = leo.c, leo.g
14 c,g = leo.c, leo.g
22
15
23 # will probably be overwritten by user, but handy for experimentation early on
16 # will probably be overwritten by user, but handy for experimentation early on
24 ip.user_ns['c'] = c
17 ip.user_ns['c'] = c
25 ip.user_ns['g'] = g
18 ip.user_ns['g'] = g
26
19
27
20
28 from IPython.external.simplegeneric import generic
21 from IPython.external.simplegeneric import generic
29 import pprint
22 import pprint
30
23
31 def es(s):
24 def es(s):
32 g.es(s, tabName = 'IPython')
25 g.es(s, tabName = 'IPython')
33 pass
26 pass
34
27
35 @generic
28 @generic
36 def format_for_leo(obj):
29 def format_for_leo(obj):
37 """ Convert obj to string representiation (for editing in Leo)"""
30 """ Convert obj to string representiation (for editing in Leo)"""
38 return pprint.pformat(obj)
31 return pprint.pformat(obj)
39
32
40 @format_for_leo.when_type(list)
33 @format_for_leo.when_type(list)
41 def format_list(obj):
34 def format_list(obj):
42 return "\n".join(str(s) for s in obj)
35 return "\n".join(str(s) for s in obj)
43
36
44 nodename_re = r'^(@ipy\w*\s+)?(\w+)$'
37 attribute_re = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$')
38 def valid_attribute(s):
39 return attribute_re.match(s)
45
40
46 def all_cells():
41 def all_cells():
47 d = {}
42 d = {}
48 for p in c.allNodes_iter():
43 for p in c.allNodes_iter():
49 h = p.headString()
44 h = p.headString()
50 if h.startswith('@') and len(h.split()) == 1:
45 if not valid_attribute(h):
51 continue
46 continue
52 mo = re.match(nodename_re, h)
47 d[h] = p.copy()
53 if not mo:
54 continue
55 d[mo.group(2)] = p.copy()
56 return d
48 return d
57
49
58
50
59 class TrivialLeoWorkbook:
60 """ class to find cells with simple syntax
61
62 """
63 def __getattr__(self, key):
64 cells = all_cells()
65 p = cells[key]
66 body = p.bodyString()
67 return eval_body(body)
68 def __setattr__(self,key,val):
69 cells = all_cells()
70 p = cells.get(key,None)
71 if p is None:
72 add_var(key,val)
73 else:
74 c.setBodyString(p,format_for_leo(val))
75 def __str__(self):
76 return "<TrivialLeoWorkbook>"
77 __repr__ = __str__
78
79 ip.user_ns['nodes'] = TrivialLeoWorkbook()
80
51
81 def eval_node(n):
52 def eval_node(n):
82 body = n.b
53 body = n.b
83 if not body.startswith('@cl'):
54 if not body.startswith('@cl'):
84 # plain python repr node, just eval it
55 # plain python repr node, just eval it
85 return ip.ev(n.b)
56 return ip.ev(n.b)
86 # @cl nodes deserve special treatment - first eval the first line (minus cl), then use it to call the rest of body
57 # @cl nodes deserve special treatment - first eval the first line (minus cl), then use it to call the rest of body
87 first, rest = body.split('\n',1)
58 first, rest = body.split('\n',1)
88 cl, hd = first.split(None, 1)
59 tup = first.split(None, 1)
89 if cl != '@cl':
60 # @cl alone SPECIAL USE-> dump var to user_ns
90 return None
61 if len(tup) == 1:
62 val = ip.ev(rest)
63 ip.user_ns[n.h] = val
64 es("%s = %s" % (n.h, repr(val)[:20] ))
65 return val
66
67 cl, hd = tup
68
91 xformer = ip.ev(hd.strip())
69 xformer = ip.ev(hd.strip())
92 es('Transform w/ %s' % repr(xformer))
70 es('Transform w/ %s' % repr(xformer))
93 return xformer(rest)
71 return xformer(rest)
94
72
95 class LeoNode(object):
73 class LeoNode(object, UserDict.DictMixin):
96 def __init__(self,p):
74 def __init__(self,p):
97 self.p = p.copy()
75 self.p = p.copy()
98
76
99 def get_h(self): return self.p.headString()
77 def get_h(self): return self.p.headString()
100 def set_h(self,val):
78 def set_h(self,val):
101 print "set head",val
79 print "set head",val
102 c.beginUpdate()
80 c.beginUpdate()
103 try:
81 try:
104 c.setHeadString(self.p,val)
82 c.setHeadString(self.p,val)
105 finally:
83 finally:
106 c.endUpdate()
84 c.endUpdate()
107
85
108 h = property( get_h, set_h)
86 h = property( get_h, set_h)
109
87
110 def get_b(self): return self.p.bodyString()
88 def get_b(self): return self.p.bodyString()
111 def set_b(self,val):
89 def set_b(self,val):
112 print "set body",val
90 print "set body",val
113 c.beginUpdate()
91 c.beginUpdate()
114 try:
92 try:
115 c.setBodyString(self.p, val)
93 c.setBodyString(self.p, val)
116 finally:
94 finally:
117 c.endUpdate()
95 c.endUpdate()
118
96
119 b = property(get_b, set_b)
97 b = property(get_b, set_b)
120
98
121 def set_val(self, val):
99 def set_val(self, val):
122 self.b = pprint.pformat(val)
100 self.b = pprint.pformat(val)
123
101
124 v = property(lambda self: eval_node(self), set_val)
102 v = property(lambda self: eval_node(self), set_val)
125
103
126 def set_l(self,val):
104 def set_l(self,val):
127 self.b = '\n'.join(val )
105 self.b = '\n'.join(val )
128 l = property(lambda self : IPython.genutils.SList(self.b.splitlines()),
106 l = property(lambda self : IPython.genutils.SList(self.b.splitlines()),
129 set_l)
107 set_l)
130
108
131 def __iter__(self):
109 def __iter__(self):
132 return (LeoNode(p) for p in self.p.children_iter())
110 return (LeoNode(p) for p in self.p.children_iter())
133
111
112 def _children(self):
113 d = {}
114 for child in self:
115 head = child.h
116 tup = head.split(None,1)
117 if len(tup) > 1 and tup[0] == '@k':
118 d[tup[1]] = child
119 continue
120
121 if not valid_attribute(head):
122 d[head] = child
123 continue
124 return d
125 def keys(self):
126 d = self._children()
127 return d.keys()
128 def __getitem__(self, key):
129 key = str(key)
130 d = self._children()
131 return d[key]
132 def __setitem__(self, key, val):
133 key = str(key)
134 d = self._children()
135 if key in d:
136 d[key].v = val
137 return
138
139 if not valid_attribute(key):
140 head = key
141 else:
142 head = '@k ' + key
143 p = c.createLastChildNode(self.p, head, '')
144 LeoNode(p).v = val
145 def __delitem__(self,key):
146 pass
147
134
148
135 class LeoWorkbook:
149 class LeoWorkbook:
136 """ class for 'advanced' node access """
150 """ class for 'advanced' node access """
137 def __getattr__(self, key):
151 def __getattr__(self, key):
138 if key.startswith('_') or key == 'trait_names':
152 if key.startswith('_') or key == 'trait_names' or not valid_attribute(key):
139 raise AttributeError
153 raise AttributeError
140 cells = all_cells()
154 cells = all_cells()
141 p = cells.get(key, None)
155 p = cells.get(key, None)
142 if p is None:
156 if p is None:
143 p = add_var(key,None)
157 p = add_var(key,None)
144
158
145 return LeoNode(p)
159 return LeoNode(p)
146
160
147 def __str__(self):
161 def __str__(self):
148 return "<LeoWorkbook>"
162 return "<LeoWorkbook>"
163 def __setattr__(self,key, val):
164 raise AttributeError("Direct assignment to workbook denied, try wb.%s.v = %s" % (key,val))
165
149 __repr__ = __str__
166 __repr__ = __str__
150 ip.user_ns['wb'] = LeoWorkbook()
167 ip.user_ns['wb'] = LeoWorkbook()
151
168
152
169
153 _dummyval = object()
170 _dummyval = object()
154 @IPython.generics.complete_object.when_type(LeoWorkbook)
171 @IPython.generics.complete_object.when_type(LeoWorkbook)
155 def workbook_complete(obj, prev):
172 def workbook_complete(obj, prev):
156 return all_cells().keys()
173 return all_cells().keys()
157
174
158
175
159 def add_var(varname, value = _dummyval):
176 def add_var(varname, value = _dummyval):
160 c.beginUpdate()
177 c.beginUpdate()
161 try:
178 try:
162
179
163 nodename = '@ipy-var ' + varname
180 nodename = '@ipy-var ' + varname
164 p2 = g.findNodeAnywhere(c,nodename)
181 p2 = g.findNodeAnywhere(c,nodename)
165 if not c.positionExists(p2):
182 if not c.positionExists(p2):
166 p2 = c.currentPosition().insertAfter()
183 p2 = c.currentPosition().insertAfter()
167 c.setHeadString(p2,'@ipy ' + varname)
184 c.setHeadString(p2,'@ipy ' + varname)
168
185
169 c.setCurrentPosition(p2)
186 c.setCurrentPosition(p2)
170 if value is _dummyval:
187 if value is _dummyval:
171 val = ip.user_ns[varname]
188 val = ip.user_ns[varname]
172 else:
189 else:
173 val = value
190 val = value
174 if val is not None:
191 if val is not None:
175 formatted = format_for_leo(val)
192 formatted = format_for_leo(val)
176 c.setBodyString(p2,formatted)
193 c.setBodyString(p2,formatted)
177 return p2
194 return p2
178 finally:
195 finally:
179 c.endUpdate()
196 c.endUpdate()
180
197
181 def add_file(self,fname):
198 def add_file(self,fname):
182 p2 = c.currentPosition().insertAfter()
199 p2 = c.currentPosition().insertAfter()
183
200
184 def push_script(p):
201 def push_script(p):
185 c.beginUpdate()
202 c.beginUpdate()
186 try:
203 try:
187 ohist = ip.IP.output_hist
204 ohist = ip.IP.output_hist
188 hstart = len(ip.IP.input_hist)
205 hstart = len(ip.IP.input_hist)
189 script = g.getScript(c,p,useSelectedText=False,forcePythonSentinels=False,useSentinels=False)
206 script = g.getScript(c,p,useSelectedText=False,forcePythonSentinels=False,useSentinels=False)
190
207
191 script = g.splitLines(script + '\n')
208 script = g.splitLines(script + '\n')
192 script = ''.join(z for z in script if z.strip())
209 script = ''.join(z for z in script if z.strip())
193
210
194 ip.runlines(script)
211 ip.runlines(script)
195
212
196 has_output = False
213 has_output = False
197 for idx in range(hstart,len(ip.IP.input_hist)):
214 for idx in range(hstart,len(ip.IP.input_hist)):
198 val = ohist.get(idx,None)
215 val = ohist.get(idx,None)
199 if val is None:
216 if val is None:
200 continue
217 continue
201 has_output = True
218 has_output = True
202 inp = ip.IP.input_hist[idx]
219 inp = ip.IP.input_hist[idx]
203 if inp.strip():
220 if inp.strip():
204 es('In: %s' % (inp[:40], ))
221 es('In: %s' % (inp[:40], ))
205
222
206 es('<%d> %s' % (idx, pprint.pformat(ohist[idx],width = 40)))
223 es('<%d> %s' % (idx, pprint.pformat(ohist[idx],width = 40)))
207
224
208 if not has_output:
225 if not has_output:
209 es('ipy run: %s' %( p.headString(),))
226 es('ipy run: %s' %( p.headString(),))
210 finally:
227 finally:
211 c.endUpdate()
228 c.endUpdate()
212
229
213
230
214 def eval_body(body):
231 def eval_body(body):
215 try:
232 try:
216 val = ip.ev(body)
233 val = ip.ev(body)
217 except:
234 except:
218 # just use stringlist if it's not completely legal python expression
235 # just use stringlist if it's not completely legal python expression
219 val = IPython.genutils.SList(body.splitlines())
236 val = IPython.genutils.SList(body.splitlines())
220 return val
237 return val
221
238
222 def push_variable(p,varname):
239 def push_variable(p,varname):
223 try:
240 try:
224 val = eval_node(LeoNode(p))
241 val = eval_node(LeoNode(p))
225 except:
242 except:
226
243
227 body = p.bodyString()
244 body = p.bodyString()
228 val = IPython.genutils.SList(body.splitlines())
245 val = IPython.genutils.SList(body.splitlines())
229
246
230 ip.user_ns[varname] = val
247 ip.user_ns[varname] = val
231 es('ipy var: %s' % (varname,))
248 es('ipy var: %s' % (varname,))
232
249
233 def push_plain_python(p):
250 def push_plain_python(p):
234 script = g.getScript(c,p,useSelectedText=False,forcePythonSentinels=False,useSentinels=False)
251 script = g.getScript(c,p,useSelectedText=False,forcePythonSentinels=False,useSentinels=False)
235 exec script in ip.user_ns
252 exec script in ip.user_ns
236 es('ipy plain: %s' % (p.headString(),))
253 es('ipy plain: %s' % (p.headString(),))
237
254
238 def push_from_leo(p):
255 def push_from_leo(p):
239 nod = LeoNode(p)
256 nod = LeoNode(p)
240 h = p.headString()
257 h = p.headString()
241 tup = h.split(None,1)
258 tup = h.split(None,1)
242 # @ipy foo is variable foo
259 # @ipy foo is variable foo
243 if len(tup) == 2 and tup[0] == '@ipy':
260 if len(tup) == 2 and tup[0] == '@ipy':
244 varname = tup[1]
261 varname = tup[1]
245 push_variable(p,varname)
262 push_variable(p,varname)
246 return
263 return
247 if h.endswith('P'):
264 if h.endswith('P'):
248 push_plain_python(p)
265 push_plain_python(p)
249 return
266 return
250 if nod.b.startswith('@cl'):
267 if nod.b.startswith('@cl'):
251 es(nod.v)
268 es(nod.v)
252 return
269 return
253
270
254 push_script(p)
271 push_script(p)
255 return
272 return
256
273
257
274
258 ip.user_ns['leox'].push = push_from_leo
275 ip.user_ns['leox'].push = push_from_leo
259
276
260 def leo_f(self,s):
277 def leo_f(self,s):
261 """ open file(s) in Leo
278 """ open file(s) in Leo
262
279
263 Takes an mglob pattern, e.g. '%leo *.cpp' or %leo 'rec:*.cpp'
280 Takes an mglob pattern, e.g. '%leo *.cpp' or %leo 'rec:*.cpp'
264 """
281 """
265 import os
282 import os
266 from IPython.external import mglob
283 from IPython.external import mglob
267
284
268 files = mglob.expand(s)
285 files = mglob.expand(s)
269 c.beginUpdate()
286 c.beginUpdate()
270 try:
287 try:
271 for fname in files:
288 for fname in files:
272 p = g.findNodeAnywhere(c,'@auto ' + fname)
289 p = g.findNodeAnywhere(c,'@auto ' + fname)
273 if not p:
290 if not p:
274 p = c.currentPosition().insertAfter()
291 p = c.currentPosition().insertAfter()
275
292
276 p.setHeadString('@auto ' + fname)
293 p.setHeadString('@auto ' + fname)
277 if os.path.isfile(fname):
294 if os.path.isfile(fname):
278 c.setBodyString(p,open(fname).read())
295 c.setBodyString(p,open(fname).read())
279 c.selectPosition(p)
296 c.selectPosition(p)
280 finally:
297 finally:
281 c.endUpdate()
298 c.endUpdate()
282
299
283 ip.expose_magic('leo',leo_f)
300 ip.expose_magic('leo',leo_f)
284
301
285 def leoref_f(self,s):
302 def leoref_f(self,s):
286 import textwrap
303 import textwrap
287 print textwrap.dedent("""\
304 print textwrap.dedent("""\
288 %leo file - open file in leo
305 %leo file - open file in leo
289 wb.foo.v - eval node foo (i.e. headstring is 'foo' or '@ipy foo')
306 wb.foo.v - eval node foo (i.e. headstring is 'foo' or '@ipy foo')
290 wb.foo.v = 12 - assign to body of node foo
307 wb.foo.v = 12 - assign to body of node foo
291 wb.foo.b - read or write the body of node foo
308 wb.foo.b - read or write the body of node foo
292 wb.foo.l - body of node foo as string list
309 wb.foo.l - body of node foo as string list
293
310
294 for el in wb.foo:
311 for el in wb.foo:
295 print el.v
312 print el.v
296
313
297 """
314 """
298 )
315 )
299 ip.expose_magic('leoref',leoref_f)
316 ip.expose_magic('leoref',leoref_f)
300
317
301 def show_welcome():
318 def show_welcome():
302 print "------------------"
319 print "------------------"
303 print "Welcome to Leo-enabled IPython session!"
320 print "Welcome to Leo-enabled IPython session!"
304 print "Try %leoref for quick reference."
321 print "Try %leoref for quick reference."
305 import IPython.platutils
322 import IPython.platutils
306 IPython.platutils.set_term_title('ILeo')
323 IPython.platutils.set_term_title('ILeo')
307 IPython.platutils.freeze_term_title()
324 IPython.platutils.freeze_term_title()
308
325
309 def run_leo_startup_node():
326 def run_leo_startup_node():
310 p = g.findNodeAnywhere(c,'@ipy-startup')
327 p = g.findNodeAnywhere(c,'@ipy-startup')
311 if p:
328 if p:
312 print "Running @ipy-startup"
329 print "Running @ipy-startup"
313 push_script(p)
330 push_script(p)
314
331
315 run_leo_startup_node()
332 run_leo_startup_node()
316 show_welcome()
333 show_welcome()
317
334
@@ -1,86 +1,79 b''
1 <?xml version="1.0" encoding="utf-8"?>
1 <?xml version="1.0" encoding="utf-8"?>
2 <?xml-stylesheet ekr_test?>
2 <?xml-stylesheet ekr_test?>
3 <leo_file>
3 <leo_file>
4 <leo_header file_format="2" tnodes="0" max_tnode_index="0" clone_windows="0"/>
4 <leo_header file_format="2" tnodes="0" max_tnode_index="0" clone_windows="0"/>
5 <globals body_outline_ratio="0.5">
5 <globals body_outline_ratio="0.5">
6 <global_window_position top="167" left="763" height="600" width="800"/>
6 <global_window_position top="262" left="259" height="600" width="800"/>
7 <global_log_window_position top="0" left="0" height="0" width="0"/>
7 <global_log_window_position top="0" left="0" height="0" width="0"/>
8 </globals>
8 </globals>
9 <preferences/>
9 <preferences/>
10 <find_panel_settings/>
10 <find_panel_settings/>
11 <vnodes>
11 <vnodes>
12 <v t="vivainio.20080218184525"><vh>@chapters</vh></v>
12 <v t="vivainio.20080218184525"><vh>@chapters</vh></v>
13 <v t="vivainio.20080218184540" a="E"><vh>@ipy-startup</vh>
13 <v t="vivainio.20080218184540" a="ET"><vh>@ipy-startup</vh>
14 <v t="vivainio.20080218184613"><vh>a</vh></v>
14 <v t="vivainio.20080218184613.1" a="V"><vh>b</vh></v>
15 <v t="vivainio.20080218184613.1"><vh>b</vh></v>
15 <v t="vivainio.20080218200031"><vh>Some classes</vh>
16 <v t="vivainio.20080218200031" a="E"><vh>Some classes</vh>
17 <v t="vivainio.20080218190816"><vh>File-like access</vh></v>
16 <v t="vivainio.20080218190816"><vh>File-like access</vh></v>
18 <v t="vivainio.20080218200106"><vh>csv data</vh></v>
17 <v t="vivainio.20080218200106"><vh>csv data</vh></v>
19 </v>
18 </v>
20 </v>
19 </v>
21 <v t="vivainio.20080218195413"><vh>Class tests</vh>
20 <v t="vivainio.20080218195413" a="E"><vh>Class tests</vh>
22 <v t="vivainio.20080218200509"><vh>csvr</vh></v>
21 <v t="vivainio.20080218200509"><vh>csvr</vh></v>
23 <v t="vivainio.20080218191007"><vh>tempfile</vh></v>
22 <v t="vivainio.20080218191007"><vh>tempfile</vh></v>
24 <v t="vivainio.20080218195413.1"><vh>rfile</vh></v>
23 <v t="vivainio.20080218195413.1"><vh>rfile</vh></v>
25 </v>
24 </v>
26 <v t="vivainio.20080218201219" a="E"><vh>Direct variables</vh>
25 <v t="vivainio.20080218201219" a="E"><vh>Direct variables</vh>
27 <v t="vivainio.20080218201219.1" a="TV"><vh>@ipy foo</vh></v>
26 <v t="vivainio.20080218201219.2"><vh>bar</vh></v>
28 <v t="vivainio.20080218201622"><vh>@ipy </vh></v>
29 <v t="vivainio.20080218201219.2"><vh>@ipy bar</vh></v>
30 </v>
27 </v>
31 </vnodes>
28 </vnodes>
32 <tnodes>
29 <tnodes>
33 <t tx="vivainio.20080218184525">?</t>
30 <t tx="vivainio.20080218184525">?</t>
34 <t tx="vivainio.20080218184540"># this stuff will be pushed at ipython bridge startup
31 <t tx="vivainio.20080218184540"># this stuff will be pushed at ipython bridge startup
35
32
36 @others</t>
33 @others</t>
37 <t tx="vivainio.20080218184613">print "hello"</t>
38 <t tx="vivainio.20080218184613.1">print "world"</t>
34 <t tx="vivainio.20080218184613.1">print "world"</t>
39 <t tx="vivainio.20080218190816">def rfile(body):
35 <t tx="vivainio.20080218190816">def rfile(body):
40 """ @cl rfile
36 """ @cl rfile
41
37
42 produces a StringIO (file like obj of the rest of the body) """
38 produces a StringIO (file like obj of the rest of the body) """
43
39
44 import StringIO
40 import StringIO
45 return StringIO.StringIO(body)
41 return StringIO.StringIO(body)
46
42
47 def tmpfile(body):
43 def tmpfile(body):
48 """ @cl tmpfile
44 """ @cl tmpfile
49
45
50 Produces a temporary file, with node body as contents
46 Produces a temporary file, with node body as contents
51
47
52 """
48 """
53 import tempfile
49 import tempfile
54 h, fname = tempfile.mkstemp()
50 h, fname = tempfile.mkstemp()
55 f = open(fname,'w')
51 f = open(fname,'w')
56 f.write(body)
52 f.write(body)
57 f.close()
53 f.close()
58 return fname
54 return fname
59 </t>
55 </t>
60 <t tx="vivainio.20080218191007">@cl tmpfile
56 <t tx="vivainio.20080218191007">@cl tmpfile
61
57
62 Hello</t>
58 Hello</t>
63 <t tx="vivainio.20080218195413"></t>
59 <t tx="vivainio.20080218195413">?</t>
64 <t tx="vivainio.20080218195413.1">@cl rfile
60 <t tx="vivainio.20080218195413.1">@cl rfile
65 These
61 These
66 lines
62 lines
67 should
63 should
68 be
64 be
69 readable </t>
65 readable </t>
70 <t tx="vivainio.20080218200031"></t>
66 <t tx="vivainio.20080218200031"></t>
71 <t tx="vivainio.20080218200106">def csvdata(body):
67 <t tx="vivainio.20080218200106">def csvdata(body):
72 import csv
68 import csv
73 d = csv.Sniffer().sniff(body)
69 d = csv.Sniffer().sniff(body)
74 reader = csv.reader(body.splitlines(), dialect = d)
70 reader = csv.reader(body.splitlines(), dialect = d)
75 return reader</t>
71 return reader</t>
76 <t tx="vivainio.20080218200509">@cl csvdata
72 <t tx="vivainio.20080218200509">@cl csvdata
77
73
78 a,b,b
74 a,b,b
79 1,2,2</t>
75 1,2,2</t>
80 <t tx="vivainio.20080218201219"></t>
76 <t tx="vivainio.20080218201219"></t>
81 <t tx="vivainio.20080218201219.1">@cl rfile
82 121212</t>
83 <t tx="vivainio.20080218201219.2">"hello world"</t>
77 <t tx="vivainio.20080218201219.2">"hello world"</t>
84 <t tx="vivainio.20080218201622"></t>
85 </tnodes>
78 </tnodes>
86 </leo_file>
79 </leo_file>
General Comments 0
You need to be logged in to leave comments. Login now