rdoc 2.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rdoc might be problematic. Click here for more details.

Files changed (62) hide show
  1. data/History.txt +13 -0
  2. data/Manifest.txt +61 -0
  3. data/README.txt +34 -0
  4. data/Rakefile +10 -0
  5. data/bin/rdoc +22 -0
  6. data/bin/ri +6 -0
  7. data/lib/rdoc.rb +277 -0
  8. data/lib/rdoc/code_objects.rb +776 -0
  9. data/lib/rdoc/diagram.rb +338 -0
  10. data/lib/rdoc/dot.rb +249 -0
  11. data/lib/rdoc/generator.rb +1048 -0
  12. data/lib/rdoc/generator/chm.rb +113 -0
  13. data/lib/rdoc/generator/chm/chm.rb +98 -0
  14. data/lib/rdoc/generator/html.rb +370 -0
  15. data/lib/rdoc/generator/html/hefss.rb +414 -0
  16. data/lib/rdoc/generator/html/html.rb +704 -0
  17. data/lib/rdoc/generator/html/kilmer.rb +418 -0
  18. data/lib/rdoc/generator/html/one_page_html.rb +121 -0
  19. data/lib/rdoc/generator/ri.rb +229 -0
  20. data/lib/rdoc/generator/xml.rb +120 -0
  21. data/lib/rdoc/generator/xml/rdf.rb +113 -0
  22. data/lib/rdoc/generator/xml/xml.rb +111 -0
  23. data/lib/rdoc/markup.rb +473 -0
  24. data/lib/rdoc/markup/attribute_manager.rb +274 -0
  25. data/lib/rdoc/markup/formatter.rb +14 -0
  26. data/lib/rdoc/markup/fragments.rb +337 -0
  27. data/lib/rdoc/markup/inline.rb +101 -0
  28. data/lib/rdoc/markup/lines.rb +152 -0
  29. data/lib/rdoc/markup/preprocess.rb +71 -0
  30. data/lib/rdoc/markup/to_flow.rb +185 -0
  31. data/lib/rdoc/markup/to_html.rb +353 -0
  32. data/lib/rdoc/markup/to_html_crossref.rb +86 -0
  33. data/lib/rdoc/markup/to_latex.rb +328 -0
  34. data/lib/rdoc/markup/to_test.rb +50 -0
  35. data/lib/rdoc/options.rb +616 -0
  36. data/lib/rdoc/parsers/parse_c.rb +775 -0
  37. data/lib/rdoc/parsers/parse_f95.rb +1841 -0
  38. data/lib/rdoc/parsers/parse_rb.rb +2584 -0
  39. data/lib/rdoc/parsers/parse_simple.rb +40 -0
  40. data/lib/rdoc/parsers/parserfactory.rb +99 -0
  41. data/lib/rdoc/rdoc.rb +277 -0
  42. data/lib/rdoc/ri.rb +4 -0
  43. data/lib/rdoc/ri/cache.rb +188 -0
  44. data/lib/rdoc/ri/descriptions.rb +150 -0
  45. data/lib/rdoc/ri/display.rb +274 -0
  46. data/lib/rdoc/ri/driver.rb +452 -0
  47. data/lib/rdoc/ri/formatter.rb +616 -0
  48. data/lib/rdoc/ri/paths.rb +102 -0
  49. data/lib/rdoc/ri/reader.rb +106 -0
  50. data/lib/rdoc/ri/util.rb +81 -0
  51. data/lib/rdoc/ri/writer.rb +68 -0
  52. data/lib/rdoc/stats.rb +25 -0
  53. data/lib/rdoc/template.rb +64 -0
  54. data/lib/rdoc/tokenstream.rb +33 -0
  55. data/test/test_rdoc_c_parser.rb +261 -0
  56. data/test/test_rdoc_markup.rb +613 -0
  57. data/test/test_rdoc_markup_attribute_manager.rb +224 -0
  58. data/test/test_rdoc_ri_attribute_formatter.rb +42 -0
  59. data/test/test_rdoc_ri_default_display.rb +295 -0
  60. data/test/test_rdoc_ri_formatter.rb +318 -0
  61. data/test/test_rdoc_ri_overstrike_formatter.rb +69 -0
  62. metadata +134 -0
@@ -0,0 +1,338 @@
1
+ # A wonderful hack by to draw package diagrams using the dot package.
2
+ # Originally written by Jah, team Enticla.
3
+ #
4
+ # You must have the V1.7 or later in your path
5
+ # http://www.research.att.com/sw/tools/graphviz/
6
+
7
+ require 'rdoc/dot'
8
+
9
+ module RDoc
10
+
11
+ ##
12
+ # Draw a set of diagrams representing the modules and classes in the
13
+ # system. We draw one diagram for each file, and one for each toplevel
14
+ # class or module. This means there will be overlap. However, it also
15
+ # means that you'll get better context for objects.
16
+ #
17
+ # To use, simply
18
+ #
19
+ # d = Diagram.new(info) # pass in collection of top level infos
20
+ # d.draw
21
+ #
22
+ # The results will be written to the +dot+ subdirectory. The process
23
+ # also sets the +diagram+ attribute in each object it graphs to
24
+ # the name of the file containing the image. This can be used
25
+ # by output generators to insert images.
26
+
27
+ class Diagram
28
+
29
+ FONT = "Arial"
30
+
31
+ DOT_PATH = "dot"
32
+
33
+ ##
34
+ # Pass in the set of top level objects. The method also creates the
35
+ # subdirectory to hold the images
36
+
37
+ def initialize(info, options)
38
+ @info = info
39
+ @options = options
40
+ @counter = 0
41
+ FileUtils.mkdir_p(DOT_PATH)
42
+ @diagram_cache = {}
43
+ end
44
+
45
+ ##
46
+ # Draw the diagrams. We traverse the files, drawing a diagram for each. We
47
+ # also traverse each top-level class and module in that file drawing a
48
+ # diagram for these too.
49
+
50
+ def draw
51
+ unless @options.quiet
52
+ $stderr.print "Diagrams: "
53
+ $stderr.flush
54
+ end
55
+
56
+ @info.each_with_index do |i, file_count|
57
+ @done_modules = {}
58
+ @local_names = find_names(i)
59
+ @global_names = []
60
+ @global_graph = graph = DOT::Digraph.new('name' => 'TopLevel',
61
+ 'fontname' => FONT,
62
+ 'fontsize' => '8',
63
+ 'bgcolor' => 'lightcyan1',
64
+ 'compound' => 'true')
65
+
66
+ # it's a little hack %) i'm too lazy to create a separate class
67
+ # for default node
68
+ graph << DOT::Node.new('name' => 'node',
69
+ 'fontname' => FONT,
70
+ 'color' => 'black',
71
+ 'fontsize' => 8)
72
+
73
+ i.modules.each do |mod|
74
+ draw_module(mod, graph, true, i.file_relative_name)
75
+ end
76
+ add_classes(i, graph, i.file_relative_name)
77
+
78
+ i.diagram = convert_to_png("f_#{file_count}", graph)
79
+
80
+ # now go through and document each top level class and
81
+ # module independently
82
+ i.modules.each_with_index do |mod, count|
83
+ @done_modules = {}
84
+ @local_names = find_names(mod)
85
+ @global_names = []
86
+
87
+ @global_graph = graph = DOT::Digraph.new('name' => 'TopLevel',
88
+ 'fontname' => FONT,
89
+ 'fontsize' => '8',
90
+ 'bgcolor' => 'lightcyan1',
91
+ 'compound' => 'true')
92
+
93
+ graph << DOT::Node.new('name' => 'node',
94
+ 'fontname' => FONT,
95
+ 'color' => 'black',
96
+ 'fontsize' => 8)
97
+ draw_module(mod, graph, true)
98
+ mod.diagram = convert_to_png("m_#{file_count}_#{count}",
99
+ graph)
100
+ end
101
+ end
102
+ $stderr.puts unless @options.quiet
103
+ end
104
+
105
+ private
106
+
107
+ def find_names(mod)
108
+ return [mod.full_name] + mod.classes.collect{|cl| cl.full_name} +
109
+ mod.modules.collect{|m| find_names(m)}.flatten
110
+ end
111
+
112
+ def find_full_name(name, mod)
113
+ full_name = name.dup
114
+ return full_name if @local_names.include?(full_name)
115
+ mod_path = mod.full_name.split('::')[0..-2]
116
+ unless mod_path.nil?
117
+ until mod_path.empty?
118
+ full_name = mod_path.pop + '::' + full_name
119
+ return full_name if @local_names.include?(full_name)
120
+ end
121
+ end
122
+ return name
123
+ end
124
+
125
+ def draw_module(mod, graph, toplevel = false, file = nil)
126
+ return if @done_modules[mod.full_name] and not toplevel
127
+
128
+ @counter += 1
129
+ url = mod.http_url("classes")
130
+ m = DOT::Subgraph.new('name' => "cluster_#{mod.full_name.gsub( /:/,'_' )}",
131
+ 'label' => mod.name,
132
+ 'fontname' => FONT,
133
+ 'color' => 'blue',
134
+ 'style' => 'filled',
135
+ 'URL' => %{"#{url}"},
136
+ 'fillcolor' => toplevel ? 'palegreen1' : 'palegreen3')
137
+
138
+ @done_modules[mod.full_name] = m
139
+ add_classes(mod, m, file)
140
+ graph << m
141
+
142
+ unless mod.includes.empty?
143
+ mod.includes.each do |inc|
144
+ m_full_name = find_full_name(inc.name, mod)
145
+ if @local_names.include?(m_full_name)
146
+ @global_graph << DOT::Edge.new('from' => "#{m_full_name.gsub( /:/,'_' )}",
147
+ 'to' => "#{mod.full_name.gsub( /:/,'_' )}",
148
+ 'ltail' => "cluster_#{m_full_name.gsub( /:/,'_' )}",
149
+ 'lhead' => "cluster_#{mod.full_name.gsub( /:/,'_' )}")
150
+ else
151
+ unless @global_names.include?(m_full_name)
152
+ path = m_full_name.split("::")
153
+ url = File.join('classes', *path) + ".html"
154
+ @global_graph << DOT::Node.new('name' => "#{m_full_name.gsub( /:/,'_' )}",
155
+ 'shape' => 'box',
156
+ 'label' => "#{m_full_name}",
157
+ 'URL' => %{"#{url}"})
158
+ @global_names << m_full_name
159
+ end
160
+ @global_graph << DOT::Edge.new('from' => "#{m_full_name.gsub( /:/,'_' )}",
161
+ 'to' => "#{mod.full_name.gsub( /:/,'_' )}",
162
+ 'lhead' => "cluster_#{mod.full_name.gsub( /:/,'_' )}")
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ def add_classes(container, graph, file = nil )
169
+
170
+ use_fileboxes = @options.fileboxes
171
+
172
+ files = {}
173
+
174
+ # create dummy node (needed if empty and for module includes)
175
+ if container.full_name
176
+ graph << DOT::Node.new('name' => "#{container.full_name.gsub( /:/,'_' )}",
177
+ 'label' => "",
178
+ 'width' => (container.classes.empty? and
179
+ container.modules.empty?) ?
180
+ '0.75' : '0.01',
181
+ 'height' => '0.01',
182
+ 'shape' => 'plaintext')
183
+ end
184
+
185
+ container.classes.each_with_index do |cl, cl_index|
186
+ last_file = cl.in_files[-1].file_relative_name
187
+
188
+ if use_fileboxes && !files.include?(last_file)
189
+ @counter += 1
190
+ files[last_file] =
191
+ DOT::Subgraph.new('name' => "cluster_#{@counter}",
192
+ 'label' => "#{last_file}",
193
+ 'fontname' => FONT,
194
+ 'color'=>
195
+ last_file == file ? 'red' : 'black')
196
+ end
197
+
198
+ next if cl.name == 'Object' || cl.name[0,2] == "<<"
199
+
200
+ url = cl.http_url("classes")
201
+
202
+ label = cl.name.dup
203
+ if use_fileboxes && cl.in_files.length > 1
204
+ label << '\n[' +
205
+ cl.in_files.collect {|i|
206
+ i.file_relative_name
207
+ }.sort.join( '\n' ) +
208
+ ']'
209
+ end
210
+
211
+ attrs = {
212
+ 'name' => "#{cl.full_name.gsub( /:/, '_' )}",
213
+ 'fontcolor' => 'black',
214
+ 'style'=>'filled',
215
+ 'color'=>'palegoldenrod',
216
+ 'label' => label,
217
+ 'shape' => 'ellipse',
218
+ 'URL' => %{"#{url}"}
219
+ }
220
+
221
+ c = DOT::Node.new(attrs)
222
+
223
+ if use_fileboxes
224
+ files[last_file].push c
225
+ else
226
+ graph << c
227
+ end
228
+ end
229
+
230
+ if use_fileboxes
231
+ files.each_value do |val|
232
+ graph << val
233
+ end
234
+ end
235
+
236
+ unless container.classes.empty?
237
+ container.classes.each_with_index do |cl, cl_index|
238
+ cl.includes.each do |m|
239
+ m_full_name = find_full_name(m.name, cl)
240
+ if @local_names.include?(m_full_name)
241
+ @global_graph << DOT::Edge.new('from' => "#{m_full_name.gsub( /:/,'_' )}",
242
+ 'to' => "#{cl.full_name.gsub( /:/,'_' )}",
243
+ 'ltail' => "cluster_#{m_full_name.gsub( /:/,'_' )}")
244
+ else
245
+ unless @global_names.include?(m_full_name)
246
+ path = m_full_name.split("::")
247
+ url = File.join('classes', *path) + ".html"
248
+ @global_graph << DOT::Node.new('name' => "#{m_full_name.gsub( /:/,'_' )}",
249
+ 'shape' => 'box',
250
+ 'label' => "#{m_full_name}",
251
+ 'URL' => %{"#{url}"})
252
+ @global_names << m_full_name
253
+ end
254
+ @global_graph << DOT::Edge.new('from' => "#{m_full_name.gsub( /:/,'_' )}",
255
+ 'to' => "#{cl.full_name.gsub( /:/, '_')}")
256
+ end
257
+ end
258
+
259
+ sclass = cl.superclass
260
+ next if sclass.nil? || sclass == 'Object'
261
+ sclass_full_name = find_full_name(sclass,cl)
262
+ unless @local_names.include?(sclass_full_name) or @global_names.include?(sclass_full_name)
263
+ path = sclass_full_name.split("::")
264
+ url = File.join('classes', *path) + ".html"
265
+ @global_graph << DOT::Node.new('name' => "#{sclass_full_name.gsub( /:/, '_' )}",
266
+ 'label' => sclass_full_name,
267
+ 'URL' => %{"#{url}"})
268
+ @global_names << sclass_full_name
269
+ end
270
+ @global_graph << DOT::Edge.new('from' => "#{sclass_full_name.gsub( /:/,'_' )}",
271
+ 'to' => "#{cl.full_name.gsub( /:/, '_')}")
272
+ end
273
+ end
274
+
275
+ container.modules.each do |submod|
276
+ draw_module(submod, graph)
277
+ end
278
+
279
+ end
280
+
281
+ def convert_to_png(file_base, graph)
282
+ str = graph.to_s
283
+ return @diagram_cache[str] if @diagram_cache[str]
284
+ op_type = @options.image_format
285
+ dotfile = File.join(DOT_PATH, file_base)
286
+ src = dotfile + ".dot"
287
+ dot = dotfile + "." + op_type
288
+
289
+ unless @options.quiet
290
+ $stderr.print "."
291
+ $stderr.flush
292
+ end
293
+
294
+ File.open(src, 'w+' ) do |f|
295
+ f << str << "\n"
296
+ end
297
+
298
+ system "dot", "-T#{op_type}", src, "-o", dot
299
+
300
+ # Now construct the imagemap wrapper around
301
+ # that png
302
+
303
+ ret = wrap_in_image_map(src, dot)
304
+ @diagram_cache[str] = ret
305
+ return ret
306
+ end
307
+
308
+ ##
309
+ # Extract the client-side image map from dot, and use it to generate the
310
+ # imagemap proper. Return the whole <map>..<img> combination, suitable for
311
+ # inclusion on the page
312
+
313
+ def wrap_in_image_map(src, dot)
314
+ res = %{<map id="map" name="map">\n}
315
+ dot_map = `dot -Tismap #{src}`
316
+ dot_map.split($/).each do |area|
317
+ unless area =~ /^rectangle \((\d+),(\d+)\) \((\d+),(\d+)\) ([\/\w.]+)\s*(.*)/
318
+ $stderr.puts "Unexpected output from dot:\n#{area}"
319
+ return nil
320
+ end
321
+
322
+ xs, ys = [$1.to_i, $3.to_i], [$2.to_i, $4.to_i]
323
+ url, area_name = $5, $6
324
+
325
+ res << %{ <area shape="rect" coords="#{xs.min},#{ys.min},#{xs.max},#{ys.max}" }
326
+ res << %{ href="#{url}" alt="#{area_name}" />\n}
327
+ end
328
+ res << "</map>\n"
329
+ # map_file = src.sub(/.dot/, '.map')
330
+ # system("dot -Timap #{src} -o #{map_file}")
331
+ res << %{<img src="#{dot}" usemap="#map" border="0" alt="#{dot}">}
332
+ return res
333
+ end
334
+
335
+ end
336
+
337
+ end
338
+
@@ -0,0 +1,249 @@
1
+ module RDoc; end
2
+
3
+ module RDoc::DOT
4
+
5
+ TAB = ' '
6
+ TAB2 = TAB * 2
7
+
8
+ # options for node declaration
9
+ NODE_OPTS = [
10
+ 'bgcolor',
11
+ 'color',
12
+ 'fontcolor',
13
+ 'fontname',
14
+ 'fontsize',
15
+ 'height',
16
+ 'width',
17
+ 'label',
18
+ 'layer',
19
+ 'rank',
20
+ 'shape',
21
+ 'shapefile',
22
+ 'style',
23
+ 'URL',
24
+ ]
25
+
26
+ # options for edge declaration
27
+ EDGE_OPTS = [
28
+ 'color',
29
+ 'decorate',
30
+ 'dir',
31
+ 'fontcolor',
32
+ 'fontname',
33
+ 'fontsize',
34
+ 'id',
35
+ 'label',
36
+ 'layer',
37
+ 'lhead',
38
+ 'ltail',
39
+ 'minlen',
40
+ 'style',
41
+ 'weight'
42
+ ]
43
+
44
+ # options for graph declaration
45
+ GRAPH_OPTS = [
46
+ 'bgcolor',
47
+ 'center',
48
+ 'clusterrank',
49
+ 'color',
50
+ 'compound',
51
+ 'concentrate',
52
+ 'fillcolor',
53
+ 'fontcolor',
54
+ 'fontname',
55
+ 'fontsize',
56
+ 'label',
57
+ 'layerseq',
58
+ 'margin',
59
+ 'mclimit',
60
+ 'nodesep',
61
+ 'nslimit',
62
+ 'ordering',
63
+ 'orientation',
64
+ 'page',
65
+ 'rank',
66
+ 'rankdir',
67
+ 'ranksep',
68
+ 'ratio',
69
+ 'size',
70
+ 'style',
71
+ 'URL'
72
+ ]
73
+
74
+ # a root class for any element in dot notation
75
+ class SimpleElement
76
+ attr_accessor :name
77
+
78
+ def initialize( params = {} )
79
+ @label = params['name'] ? params['name'] : ''
80
+ end
81
+
82
+ def to_s
83
+ @name
84
+ end
85
+ end
86
+
87
+ # an element that has options ( node, edge or graph )
88
+ class Element < SimpleElement
89
+ #attr_reader :parent
90
+ attr_accessor :name, :options
91
+
92
+ def initialize( params = {}, option_list = [] )
93
+ super( params )
94
+ @name = params['name'] ? params['name'] : nil
95
+ @parent = params['parent'] ? params['parent'] : nil
96
+ @options = {}
97
+ option_list.each{ |i|
98
+ @options[i] = params[i] if params[i]
99
+ }
100
+ @options['label'] ||= @name if @name != 'node'
101
+ end
102
+
103
+ def each_option
104
+ @options.each{ |i| yield i }
105
+ end
106
+
107
+ def each_option_pair
108
+ @options.each_pair{ |key, val| yield key, val }
109
+ end
110
+
111
+ #def parent=( thing )
112
+ # @parent.delete( self ) if defined?( @parent ) and @parent
113
+ # @parent = thing
114
+ #end
115
+ end
116
+
117
+
118
+ # this is used when we build nodes that have shape=record
119
+ # ports don't have options :)
120
+ class Port < SimpleElement
121
+ attr_accessor :label
122
+
123
+ def initialize( params = {} )
124
+ super( params )
125
+ @name = params['label'] ? params['label'] : ''
126
+ end
127
+ def to_s
128
+ ( @name && @name != "" ? "<#{@name}>" : "" ) + "#{@label}"
129
+ end
130
+ end
131
+
132
+ # node element
133
+ class Node < Element
134
+
135
+ def initialize( params = {}, option_list = NODE_OPTS )
136
+ super( params, option_list )
137
+ @ports = params['ports'] ? params['ports'] : []
138
+ end
139
+
140
+ def each_port
141
+ @ports.each{ |i| yield i }
142
+ end
143
+
144
+ def << ( thing )
145
+ @ports << thing
146
+ end
147
+
148
+ def push ( thing )
149
+ @ports.push( thing )
150
+ end
151
+
152
+ def pop
153
+ @ports.pop
154
+ end
155
+
156
+ def to_s( t = '' )
157
+
158
+ label = @options['shape'] != 'record' && @ports.length == 0 ?
159
+ @options['label'] ?
160
+ t + TAB + "label = \"#{@options['label']}\"\n" :
161
+ '' :
162
+ t + TAB + 'label = "' + " \\\n" +
163
+ t + TAB2 + "#{@options['label']}| \\\n" +
164
+ @ports.collect{ |i|
165
+ t + TAB2 + i.to_s
166
+ }.join( "| \\\n" ) + " \\\n" +
167
+ t + TAB + '"' + "\n"
168
+
169
+ t + "#{@name} [\n" +
170
+ @options.to_a.collect{ |i|
171
+ i[1] && i[0] != 'label' ?
172
+ t + TAB + "#{i[0]} = #{i[1]}" : nil
173
+ }.compact.join( ",\n" ) + ( label != '' ? ",\n" : "\n" ) +
174
+ label +
175
+ t + "]\n"
176
+ end
177
+ end
178
+
179
+ # subgraph element is the same to graph, but has another header in dot
180
+ # notation
181
+ class Subgraph < Element
182
+
183
+ def initialize( params = {}, option_list = GRAPH_OPTS )
184
+ super( params, option_list )
185
+ @nodes = params['nodes'] ? params['nodes'] : []
186
+ @dot_string = 'subgraph'
187
+ end
188
+
189
+ def each_node
190
+ @nodes.each{ |i| yield i }
191
+ end
192
+
193
+ def << ( thing )
194
+ @nodes << thing
195
+ end
196
+
197
+ def push( thing )
198
+ @nodes.push( thing )
199
+ end
200
+
201
+ def pop
202
+ @nodes.pop
203
+ end
204
+
205
+ def to_s( t = '' )
206
+ hdr = t + "#{@dot_string} #{@name} {\n"
207
+
208
+ options = @options.to_a.collect{ |name, val|
209
+ val && name != 'label' ?
210
+ t + TAB + "#{name} = #{val}" :
211
+ name ? t + TAB + "#{name} = \"#{val}\"" : nil
212
+ }.compact.join( "\n" ) + "\n"
213
+
214
+ nodes = @nodes.collect{ |i|
215
+ i.to_s( t + TAB )
216
+ }.join( "\n" ) + "\n"
217
+ hdr + options + nodes + t + "}\n"
218
+ end
219
+ end
220
+
221
+ # this is graph
222
+ class Digraph < Subgraph
223
+ def initialize( params = {}, option_list = GRAPH_OPTS )
224
+ super( params, option_list )
225
+ @dot_string = 'digraph'
226
+ end
227
+ end
228
+
229
+ # this is edge
230
+ class Edge < Element
231
+ attr_accessor :from, :to
232
+ def initialize( params = {}, option_list = EDGE_OPTS )
233
+ super( params, option_list )
234
+ @from = params['from'] ? params['from'] : nil
235
+ @to = params['to'] ? params['to'] : nil
236
+ end
237
+
238
+ def to_s( t = '' )
239
+ t + "#{@from} -> #{to} [\n" +
240
+ @options.to_a.collect{ |i|
241
+ i[1] && i[0] != 'label' ?
242
+ t + TAB + "#{i[0]} = #{i[1]}" :
243
+ i[1] ? t + TAB + "#{i[0]} = \"#{i[1]}\"" : nil
244
+ }.compact.join( "\n" ) + "\n" + t + "]\n"
245
+ end
246
+ end
247
+
248
+ end
249
+