webgen 0.3.4 → 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +201 -0
- data/Rakefile +3 -2
- data/TODO +31 -4
- data/VERSION +1 -1
- data/data/webgen/example/config.yaml +2 -0
- data/data/webgen/example/src/default.css +84 -0
- data/data/webgen/example/src/default.template +32 -0
- data/data/webgen/example/src/index.page +8 -0
- data/{doc/src → data/webgen/images}/generated_by_webgen.png +0 -0
- data/data/webgen/images/valid-css.gif +0 -0
- data/data/webgen/images/valid-xhtml11.png +0 -0
- data/data/webgen/images/webgen_logo.png +0 -0
- data/doc/config.yaml +2 -0
- data/doc/plugin/extension.rb +8 -4
- data/doc/plugin/resources.rb +30 -0
- data/doc/src/default.css +251 -149
- data/doc/src/default.template +8 -8
- data/doc/src/documentation/gettingstarted.page +1 -1
- data/doc/src/documentation/index.page +6 -2
- data/doc/src/documentation/plugins/filehandler/backing.page +22 -9
- data/doc/src/documentation/plugins/filehandler/galleryhandler.page +1 -1
- data/doc/src/documentation/plugins/filehandler/index.page +9 -4
- data/doc/src/documentation/plugins/filehandler/pagehandler.page +33 -10
- data/doc/src/documentation/plugins/index.page +9 -1
- data/doc/src/documentation/plugins/menustyles/horizontal-dropdown.page +42 -0
- data/doc/src/documentation/plugins/menustyles/horizontal.page +21 -0
- data/doc/src/documentation/plugins/menustyles/index.page +12 -0
- data/doc/src/documentation/plugins/menustyles/partial.page +27 -0
- data/doc/src/documentation/plugins/menustyles/vertical-dropdown.page +23 -0
- data/doc/src/documentation/plugins/menustyles/vertical.page +32 -0
- data/doc/src/documentation/plugins/resourcemanager.page +30 -0
- data/doc/src/documentation/plugins/tags/index.page +2 -2
- data/doc/src/documentation/plugins/tags/langbar.page +4 -4
- data/doc/src/documentation/plugins/tags/menu.page +6 -17
- data/doc/src/documentation/plugins/tags/navbar.page +2 -1
- data/doc/src/documentation/plugins/tags/resource.page +22 -0
- data/doc/src/download.page +1 -1
- data/doc/src/features.page +32 -9
- data/doc/src/index.page +24 -10
- data/doc/src/meta.info +16 -6
- data/install.rb +1 -1
- data/lib/webgen/configuration.rb +24 -2
- data/lib/webgen/node.rb +29 -5
- data/lib/webgen/plugin.rb +1 -5
- data/lib/webgen/plugins/contenthandler/textile.rb +3 -3
- data/lib/webgen/plugins/filehandler/backing.rb +5 -4
- data/lib/webgen/plugins/filehandler/directory.rb +3 -3
- data/lib/webgen/plugins/filehandler/filehandler.rb +8 -4
- data/lib/webgen/plugins/filehandler/page.rb +33 -18
- data/lib/webgen/plugins/filehandler/picturegallery.rb +10 -8
- data/lib/webgen/plugins/menustyles/defaultmenustyle.rb +73 -0
- data/lib/webgen/plugins/menustyles/horizontal.rb +93 -0
- data/lib/webgen/plugins/menustyles/horizontal_dropdown.rb +113 -0
- data/lib/webgen/plugins/menustyles/partial.rb +95 -0
- data/lib/webgen/plugins/menustyles/vertical.rb +107 -0
- data/lib/webgen/plugins/menustyles/vertical_dropdown.rb +107 -0
- data/lib/webgen/plugins/resourcemanager.rb +264 -0
- data/lib/webgen/plugins/tags/langbar.rb +9 -5
- data/lib/webgen/plugins/tags/menu.rb +4 -66
- data/lib/webgen/plugins/treewalker.rb +7 -6
- data/lib/webgen/webgen.rb +72 -161
- metadata +37 -6
- data/doc/src/logo.png +0 -0
@@ -1,7 +1,7 @@
|
|
1
1
|
#
|
2
2
|
#--
|
3
3
|
#
|
4
|
-
# $Id: langbar.rb
|
4
|
+
# $Id: langbar.rb 293 2005-06-11 08:37:51Z thomas $
|
5
5
|
#
|
6
6
|
# webgen: template based static website generator
|
7
7
|
# Copyright (C) 2004 Thomas Leitner
|
@@ -25,12 +25,14 @@ require 'webgen/plugins/tags/tags'
|
|
25
25
|
module Tags
|
26
26
|
|
27
27
|
# Generates a list with all the languages for a page.
|
28
|
-
class
|
28
|
+
class LangbarTag < DefaultTag
|
29
29
|
|
30
30
|
summary 'Provides links to translations of the page'
|
31
31
|
add_param 'separator', ' | ', 'Separates the languages from each other.'
|
32
|
-
add_param 'showSingleLang', true, '
|
33
|
-
'although the page is only available in one language
|
32
|
+
add_param 'showSingleLang', true, 'Should the link be shown '\
|
33
|
+
'although the page is only available in one language?'
|
34
|
+
add_param 'showOwnLang', true, 'Should the link to the currently displayed '\
|
35
|
+
'language page be shown? '
|
34
36
|
depends_on 'Tags'
|
35
37
|
|
36
38
|
def initialize
|
@@ -39,7 +41,9 @@ module Tags
|
|
39
41
|
end
|
40
42
|
|
41
43
|
def process_tag( tag, node, refNode )
|
42
|
-
output = node.parent.find_all
|
44
|
+
output = node.parent.find_all do |a|
|
45
|
+
a['int:pagename'] == node['int:pagename'] && (node['lang'] != a['lang'] || get_param( 'showOwnLang' ))
|
46
|
+
end.sort {|a, b| a['lang'] <=> b['lang']}.collect do |n|
|
43
47
|
n['processor'].get_html_link( n, n, n['lang'] )
|
44
48
|
end.join( get_param( 'separator' ) )
|
45
49
|
return ( get_param( 'showSingleLang' ) || node.parent.children.length > 1 ? output : "" )
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#
|
2
2
|
#--
|
3
3
|
#
|
4
|
-
# $Id: menu.rb
|
4
|
+
# $Id: menu.rb 293 2005-06-11 08:37:51Z thomas $
|
5
5
|
#
|
6
6
|
# webgen: template based static website generator
|
7
7
|
# Copyright (C) 2004 Thomas Leitner
|
@@ -31,11 +31,6 @@ module Tags
|
|
31
31
|
#
|
32
32
|
# The order in which the menu items are listed can be controlled via the meta information
|
33
33
|
# +orderInfo+. By default the menu items are sorted by the file names.
|
34
|
-
#
|
35
|
-
# Tag parameters:
|
36
|
-
# [<b>level</b>]
|
37
|
-
# The depth of the menu. A level of one only displays the top level menu files. A level of two
|
38
|
-
# also displays the menu files in the direct subdirectories and so on.
|
39
34
|
class MenuTag < DefaultTag
|
40
35
|
|
41
36
|
class ::Node
|
@@ -98,19 +93,8 @@ module Tags
|
|
98
93
|
summary 'Builds a menu'
|
99
94
|
depends_on 'Tags'
|
100
95
|
|
101
|
-
add_param '
|
102
|
-
add_param '
|
103
|
-
add_param 'submenuClass', 'webgen-submenu', 'Specifies the class of a submenu'
|
104
|
-
add_param 'selectedMenuitemClass', 'webgen-menuitem-selected', 'Specifies the class of the selected menu item'
|
105
|
-
add_param 'level', 1, \
|
106
|
-
'Specifies how many levels the menu should have by default, ie. how deep it is. ' \
|
107
|
-
'For example, if level = 3, then three levels are always shown at least.'
|
108
|
-
add_param 'subtreeLevel', 3, \
|
109
|
-
'Specifies how many levels should be shown for subtrees. The number specifies ' \
|
110
|
-
'the maximum depth the menu will have.'
|
111
|
-
add_param 'showCurrentSubtreeOnly', true, \
|
112
|
-
'True if only the current subtree should be shown in the menu. If set to false, ' \
|
113
|
-
'each subtree will be shown.'
|
96
|
+
add_param 'menuStyle', 'vertical', 'Specifies the style of the menu.'
|
97
|
+
add_param 'options', {}, 'Optional options that are passed on to the plugin which is layouts the menu.'
|
114
98
|
|
115
99
|
used_meta_info 'orderInfo', 'inMenu'
|
116
100
|
|
@@ -128,7 +112,7 @@ module Tags
|
|
128
112
|
Webgen::Plugin['TreeWalker'].execute( @menuTree, Webgen::Plugin['DebugTreePrinter'] )
|
129
113
|
end
|
130
114
|
end
|
131
|
-
build_menu( node, @menuTree,
|
115
|
+
Webgen::Plugin['DefaultMenuStyle'].get_menu_style( get_param( 'menuStyle' ) ).build_menu( node, @menuTree, get_param( 'options' ) )
|
132
116
|
end
|
133
117
|
|
134
118
|
|
@@ -136,52 +120,6 @@ module Tags
|
|
136
120
|
private
|
137
121
|
#######
|
138
122
|
|
139
|
-
|
140
|
-
def build_menu( srcNode, node, level )
|
141
|
-
if node.nil? \
|
142
|
-
|| level > get_param( 'subtreeLevel' ) \
|
143
|
-
|| ( level > get_param( 'level' ) \
|
144
|
-
&& ( node['node'].level > srcNode.level \
|
145
|
-
|| ( get_param( 'showCurrentSubtreeOnly' ) && !srcNode.in_subtree?( node['node'] ) )
|
146
|
-
)
|
147
|
-
)
|
148
|
-
return ''
|
149
|
-
end
|
150
|
-
|
151
|
-
out = "<#{get_param( 'menuTag' )}>"
|
152
|
-
node.each do |child|
|
153
|
-
menu = child['node']['int:directory?'] ? build_menu( srcNode, child, level + 1 ) : ''
|
154
|
-
before, after = menu_entry( srcNode, child['node'] )
|
155
|
-
|
156
|
-
out << before
|
157
|
-
out << menu
|
158
|
-
out << after
|
159
|
-
end
|
160
|
-
out << "</#{get_param( 'menuTag' )}>"
|
161
|
-
|
162
|
-
return out
|
163
|
-
end
|
164
|
-
|
165
|
-
|
166
|
-
def menu_entry( srcNode, node )
|
167
|
-
langNode = node['processor'].get_node_for_lang( node, srcNode['lang'] )
|
168
|
-
isDir = node['int:directory?']
|
169
|
-
|
170
|
-
styles = []
|
171
|
-
styles << get_param( 'submenuClass' ) if isDir
|
172
|
-
styles << get_param( 'selectedMenuitemClass' ) if langNode.recursive_value( 'dest' ) == srcNode.recursive_value( 'dest' )
|
173
|
-
|
174
|
-
style = " class=\"#{styles.join(' ')}\"" if styles.length > 0
|
175
|
-
link = node['processor'].get_html_link( node, srcNode )
|
176
|
-
|
177
|
-
before = "<#{get_param( 'itemTag' )}#{style}>#{link}"
|
178
|
-
after = "</#{get_param( 'itemTag' )}>"
|
179
|
-
|
180
|
-
self.logger.debug { [before, after] }
|
181
|
-
return before, after
|
182
|
-
end
|
183
|
-
|
184
|
-
|
185
123
|
def create_menu_tree( node, parent )
|
186
124
|
menuNode = MenuNode.new( parent, node )
|
187
125
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#
|
2
2
|
#--
|
3
3
|
#
|
4
|
-
# $Id: treewalker.rb
|
4
|
+
# $Id: treewalker.rb 287 2005-05-26 09:33:38Z thomas $
|
5
5
|
#
|
6
6
|
# webgen: template based static website generator
|
7
7
|
# Copyright (C) 2004 Thomas Leitner
|
@@ -38,10 +38,10 @@ module TreeWalkers
|
|
38
38
|
|
39
39
|
# Uses either all registered walkers or the specified +walker+. Walks the +tree+ for each walker
|
40
40
|
# separately.
|
41
|
-
def execute( tree, walker = nil )
|
41
|
+
def execute( tree, walker = nil, direction = :forward )
|
42
42
|
walkers = ( walker.nil? ? @walkers : [walker] )
|
43
43
|
walkers.each do |walker|
|
44
|
-
walk_tree( tree, walker, 0 )
|
44
|
+
walk_tree( tree, walker, 0, direction )
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
@@ -50,11 +50,12 @@ module TreeWalkers
|
|
50
50
|
#######
|
51
51
|
|
52
52
|
# Walks the tree and calls the plugin +walker+ for each and every node.
|
53
|
-
def walk_tree( node, walker, level )
|
54
|
-
walker.handle_node( node, level )
|
53
|
+
def walk_tree( node, walker, level, direction = :forward )
|
54
|
+
walker.handle_node( node, level ) if direction == :forward
|
55
55
|
node.each do |child|
|
56
|
-
walk_tree( child, walker, level + 1 )
|
56
|
+
walk_tree( child, walker, level + 1, direction )
|
57
57
|
end
|
58
|
+
walker.handle_node( node, level ) if direction == :backward
|
58
59
|
end
|
59
60
|
|
60
61
|
end
|
data/lib/webgen/webgen.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#
|
2
2
|
#--
|
3
3
|
#
|
4
|
-
# $Id: webgen.rb
|
4
|
+
# $Id: webgen.rb 293 2005-06-11 08:37:51Z thomas $
|
5
5
|
#
|
6
6
|
# webgen: template based static website generator
|
7
7
|
# Copyright (C) 2004 Thomas Leitner
|
@@ -22,6 +22,7 @@
|
|
22
22
|
|
23
23
|
require 'optparse'
|
24
24
|
require 'rbconfig'
|
25
|
+
require 'fileutils'
|
25
26
|
require 'cmdparse'
|
26
27
|
require 'webgen/plugin'
|
27
28
|
|
@@ -143,175 +144,90 @@ module Webgen
|
|
143
144
|
if args.length == 0
|
144
145
|
raise OptionParser::MissingArgument.new( 'DIR' )
|
145
146
|
else
|
146
|
-
|
147
|
-
create_dir( File.join( args[0], 'src' ) )
|
148
|
-
create_dir( File.join( args[0], 'output' ) )
|
149
|
-
create_dir( File.join( args[0], 'log' ) )
|
150
|
-
create_dir( File.join( args[0], 'plugin' ) )
|
151
|
-
create_file( File.join( args[0], 'config.yaml' ), content_config_yaml )
|
152
|
-
create_file( File.join( args[0], 'src', 'default.template' ), content_default_template )
|
153
|
-
create_file( File.join( args[0], 'src', 'default.css' ), content_default_css )
|
154
|
-
create_file( File.join( args[0], 'src', 'index.page' ), content_index_page )
|
147
|
+
FileUtils.cp_r( File.join( Webgen::Configuration.data_dir, 'example' ), args[0] )
|
155
148
|
end
|
156
149
|
end
|
157
150
|
|
158
|
-
|
159
|
-
Dir.mkdir( dir ) unless File.exists?( dir )
|
160
|
-
end
|
151
|
+
end
|
161
152
|
|
162
|
-
def create_file( file, content )
|
163
|
-
File.open( file, 'w') do |f|
|
164
|
-
f.puts( content )
|
165
|
-
end unless File.exists?( file )
|
166
|
-
end
|
167
153
|
|
168
|
-
|
169
|
-
|
154
|
+
class CleanCommand < CommandParser::Command
|
155
|
+
|
156
|
+
module ::FileUtils
|
157
|
+
|
158
|
+
def fu_output_message( msg )
|
159
|
+
logger.info { msg }
|
160
|
+
end
|
161
|
+
|
162
|
+
def ask_before_delete( ask, func, list, options = {} )
|
163
|
+
newlist = [*list].collect {|e| "'" + e + "'"}.join(', ')
|
164
|
+
if ask
|
165
|
+
print "Really delete #{newlist}? "
|
166
|
+
return unless /y|Y/ =~ gets.strip
|
167
|
+
end
|
168
|
+
self.send( func, list, options.merge( :verbose => true ) )
|
169
|
+
end
|
170
|
+
|
170
171
|
end
|
171
172
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
{menu: {subtreeLevel: 4}}
|
194
|
-
</div>
|
195
|
-
|
196
|
-
<div id=\"body\">
|
197
|
-
{content: }
|
198
|
-
</div>
|
199
|
-
|
200
|
-
<div id=\"footer\" class=\"bar\">
|
201
|
-
generated with <a href=\"http://webgen.rubyforge.org\"><em><b>webgen</b></em></a> on <b>{date: }</b>
|
202
|
-
</div>
|
203
|
-
</body>
|
204
|
-
</html>
|
205
|
-
"
|
173
|
+
class CleanWalker < Webgen::Plugin
|
174
|
+
|
175
|
+
summary "Deletes the output file for each node."
|
176
|
+
depends_on 'TreeWalker'
|
177
|
+
|
178
|
+
attr_writer :ask
|
179
|
+
|
180
|
+
def handle_node( node, level )
|
181
|
+
file = node.recursive_value( 'dest' )
|
182
|
+
return if !File.exists?( file ) || node['int:virtualNode']
|
183
|
+
if File.directory?( file )
|
184
|
+
begin
|
185
|
+
FileUtils.ask_before_delete( @ask, :rmdir, file )
|
186
|
+
rescue Errno::ENOTEMPTY => e
|
187
|
+
logger.info "Cannot delete directory #{file}, as it is not empty!"
|
188
|
+
end
|
189
|
+
else
|
190
|
+
FileUtils.ask_before_delete( @ask, :rm, file, :force => true )
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
206
194
|
end
|
207
195
|
|
208
|
-
def
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
background-color: #888888;
|
216
|
-
}
|
217
|
-
#header h1 {
|
218
|
-
margin: 0ex;
|
219
|
-
font-size: 300%;
|
220
|
-
font-style: italic;
|
221
|
-
font-weight: normal;
|
222
|
-
}
|
223
|
-
|
224
|
-
, #headerbar { border-bottom: 1px solid black; }
|
225
|
-
#footer { border-top: 1px solid black; }
|
226
|
-
|
227
|
-
#body {
|
228
|
-
margin-left: 250px;
|
229
|
-
margin-right: 20px;
|
230
|
-
padding: 10px;
|
231
|
-
}
|
232
|
-
|
233
|
-
#menu {
|
234
|
-
float: left;
|
235
|
-
width: 230px;
|
236
|
-
padding: 20px 0px 0px 2px;
|
237
|
-
}
|
238
|
-
|
239
|
-
.bar {
|
240
|
-
clear: both;
|
241
|
-
padding: 3px;
|
242
|
-
text-align: center;
|
243
|
-
font-size: 90%;
|
244
|
-
background-color: #AAAAAA;
|
245
|
-
}
|
246
|
-
|
247
|
-
.left, .right {
|
248
|
-
padding: 0px 1em;
|
249
|
-
}
|
250
|
-
|
251
|
-
.left {
|
252
|
-
float: left;
|
253
|
-
text-align: left;
|
254
|
-
}
|
255
|
-
|
256
|
-
.right {
|
257
|
-
float: right;
|
258
|
-
text-align: right;
|
259
|
-
}
|
260
|
-
|
261
|
-
/* styling the menu */
|
262
|
-
|
263
|
-
#menu a {
|
264
|
-
text-decoration: none;
|
265
|
-
font-weight: bold;
|
266
|
-
font-size: 130%;
|
267
|
-
}
|
268
|
-
|
269
|
-
#menu a:hover {
|
270
|
-
text-decoration: underline;
|
271
|
-
}
|
272
|
-
|
273
|
-
#menu .webgen-menuitem-selected {
|
274
|
-
border-left: 3px solid black;
|
275
|
-
}
|
276
|
-
|
277
|
-
#menu ul {
|
278
|
-
list-style-type: none;
|
279
|
-
padding: 0px;
|
280
|
-
margin-left: 10px;
|
281
|
-
}
|
282
|
-
|
283
|
-
#menu li > ul {
|
284
|
-
font-size: 95%;
|
285
|
-
}
|
286
|
-
|
287
|
-
#menu li {
|
288
|
-
margin: 0.0em 0px;
|
289
|
-
padding: 2px 0px;
|
290
|
-
padding-left: 5px;
|
291
|
-
border-left: 3px solid #CCCCCC;
|
292
|
-
}
|
293
|
-
"
|
196
|
+
def initialize;
|
197
|
+
super( 'clean' )
|
198
|
+
@all = false
|
199
|
+
@ask = false
|
200
|
+
options.separator( "Options" )
|
201
|
+
options.on( '--all', '-a', "Removes ALL files from the output directory" ) { @all = true }
|
202
|
+
options.on( '--interactive', '-i', "Ask for each file" ) { @ask = true }
|
294
203
|
end
|
295
204
|
|
296
|
-
def
|
297
|
-
|
298
|
-
|
299
|
-
inMenu: true
|
300
|
-
directoryName: New Website
|
301
|
-
---
|
302
|
-
h2. Empty index file
|
205
|
+
def description; "Removes the generated or all files from the output directory"; end
|
206
|
+
|
207
|
+
def usage; "Usage: #{@options.program_name} [global options] clean [options]"; end
|
303
208
|
|
304
|
-
|
305
|
-
|
209
|
+
def execute( commandParser, args )
|
210
|
+
if @all
|
211
|
+
logger.info( "Deleting all files from output directory..." )
|
212
|
+
outDir = Plugin['Configuration']['outDirectory']
|
213
|
+
FileUtils.ask_before_delete( @ask, :rm_rf, outDir ) if File.exists?( outDir )
|
214
|
+
else
|
215
|
+
tree = Plugin['FileHandler'].build_tree
|
216
|
+
logger.info( "Deleting generated files from output directory..." )
|
217
|
+
Plugin['CleanWalker'].ask = @ask
|
218
|
+
Plugin['TreeWalker'].execute( tree, Plugin['CleanWalker'], :backward )
|
219
|
+
end
|
220
|
+
logger.info( "Webgen finished 'clean' command" )
|
306
221
|
end
|
307
222
|
|
308
|
-
|
223
|
+
private
|
309
224
|
|
225
|
+
end
|
310
226
|
|
311
227
|
class WebgenCommandParser < CommandParser
|
312
228
|
|
313
229
|
def initialize
|
314
|
-
super
|
230
|
+
super( true )
|
315
231
|
self.options do |opts|
|
316
232
|
opts.program_name = "webgen"
|
317
233
|
opts.version = Webgen::VERSION
|
@@ -332,6 +248,7 @@ Fill this file with your own data!!!
|
|
332
248
|
self.add_command( RunWebgenCommand.new, true )
|
333
249
|
self.add_command( ShowCommand.new )
|
334
250
|
self.add_command( CreateCommand.new )
|
251
|
+
self.add_command( CleanCommand.new )
|
335
252
|
self.add_command( CommandParser::HelpCommand.new )
|
336
253
|
self.add_command( CommandParser::VersionCommand.new )
|
337
254
|
end
|
@@ -343,16 +260,10 @@ Fill this file with your own data!!!
|
|
343
260
|
|
344
261
|
def main( cmdOptions )
|
345
262
|
Color.colorify if $stdout.isatty && !Config::CONFIG['arch'].include?( 'mswin32' )
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
wcp.execute
|
351
|
-
rescue CommandParser::InvalidCommandError => e
|
352
|
-
puts "Error: invalid command given"
|
353
|
-
puts
|
354
|
-
wcp.commands['help'].execute( wcp, {} )
|
355
|
-
end
|
263
|
+
wcp = WebgenCommandParser.new
|
264
|
+
wcp.parse!( ARGV, false )
|
265
|
+
Plugin['Configuration'].init_all
|
266
|
+
wcp.execute
|
356
267
|
end
|
357
268
|
|
358
269
|
end
|