write_xlsx 0.72.2 → 0.72.3.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/{README.rdoc → Changes} +3 -94
- data/README.md +96 -0
- data/lib/write_xlsx/chart.rb +115 -259
- data/lib/write_xlsx/chart/axis.rb +4 -4
- data/lib/write_xlsx/chart/bar.rb +1 -1
- data/lib/write_xlsx/chart/column.rb +1 -1
- data/lib/write_xlsx/chart/pie.rb +3 -3
- data/lib/write_xlsx/chart/radar.rb +1 -1
- data/lib/write_xlsx/chart/scatter.rb +1 -1
- data/lib/write_xlsx/chart/series.rb +0 -37
- data/lib/write_xlsx/chartsheet.rb +25 -37
- data/lib/write_xlsx/col_name.rb +40 -0
- data/lib/write_xlsx/drawing.rb +95 -85
- data/lib/write_xlsx/format.rb +32 -32
- data/lib/write_xlsx/package/app.rb +18 -23
- data/lib/write_xlsx/package/button.rb +15 -12
- data/lib/write_xlsx/package/comments.rb +33 -30
- data/lib/write_xlsx/package/conditional_format.rb +18 -14
- data/lib/write_xlsx/package/content_types.rb +22 -17
- data/lib/write_xlsx/package/core.rb +19 -24
- data/lib/write_xlsx/package/relationships.rb +10 -13
- data/lib/write_xlsx/package/shared_strings.rb +8 -16
- data/lib/write_xlsx/package/styles.rb +59 -64
- data/lib/write_xlsx/package/table.rb +27 -37
- data/lib/write_xlsx/package/vml.rb +23 -21
- data/lib/write_xlsx/package/xml_writer_simple.rb +3 -6
- data/lib/write_xlsx/sheets.rb +4 -4
- data/lib/write_xlsx/sparkline.rb +22 -22
- data/lib/write_xlsx/utility.rb +61 -33
- data/lib/write_xlsx/version.rb +1 -1
- data/lib/write_xlsx/workbook.rb +46 -50
- data/lib/write_xlsx/worksheet.rb +149 -133
- data/lib/write_xlsx/worksheet/cell_data.rb +8 -6
- data/lib/write_xlsx/worksheet/data_validation.rb +14 -14
- data/lib/write_xlsx/worksheet/hyperlink.rb +97 -65
- data/lib/write_xlsx/worksheet/page_setup.rb +23 -22
- data/test/chart/test_write_a_latin.rb +3 -3
- data/test/regression/test_chart_font01.rb +1 -1
- data/test/regression/test_chart_font02.rb +1 -1
- data/test/regression/test_chart_font03.rb +1 -1
- data/test/regression/test_chart_font04.rb +1 -1
- data/test/regression/test_chart_font05.rb +1 -1
- data/test/regression/test_chart_font06.rb +1 -1
- data/test/test_xml_writer_simple.rb +3 -3
- data/test/worksheet/test_write_hyperlink.rb +4 -4
- data/test/worksheet/test_write_worksheet_attributes.rb +3 -3
- data/write_xlsx.gemspec +2 -1
- metadata +9 -8
- data/test/package/table/test_write_xml_declaration.rb +0 -20
@@ -57,17 +57,14 @@ def set_xml_writer(filename)
|
|
57
57
|
# Assemble and writes the XML file.
|
58
58
|
#
|
59
59
|
def assemble_xml_file
|
60
|
-
write_xml_declaration
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
60
|
+
write_xml_declaration do
|
61
|
+
# Write the table element.
|
62
|
+
@writer.tag_elements('table', write_table_attributes) do
|
63
|
+
write_auto_filter
|
64
|
+
write_table_columns
|
65
|
+
write_table_style_info
|
66
|
+
end
|
66
67
|
end
|
67
|
-
|
68
|
-
# Close the XML writer object and filehandle.
|
69
|
-
@writer.crlf
|
70
|
-
@writer.close
|
71
68
|
end
|
72
69
|
|
73
70
|
def add_the_table_columns
|
@@ -284,33 +281,26 @@ def set_the_autofilter_range
|
|
284
281
|
@autofilter = @a_range if ptrue?(@param[:autofilter])
|
285
282
|
end
|
286
283
|
|
287
|
-
#
|
288
|
-
# Write the XML declaration.
|
289
|
-
#
|
290
|
-
def write_xml_declaration
|
291
|
-
@writer.xml_decl('UTF-8', 1)
|
292
|
-
end
|
293
|
-
|
294
284
|
def write_table_attributes
|
295
285
|
schema = 'http://schemas.openxmlformats.org/'
|
296
286
|
xmlns = "#{schema}spreadsheetml/2006/main"
|
297
287
|
|
298
288
|
attributes = [
|
299
|
-
'xmlns', xmlns,
|
300
|
-
'id', @id,
|
301
|
-
'name', @name,
|
302
|
-
'displayName', @name,
|
303
|
-
'ref', @range
|
289
|
+
['xmlns', xmlns],
|
290
|
+
['id', @id],
|
291
|
+
['name', @name],
|
292
|
+
['displayName', @name],
|
293
|
+
['ref', @range]
|
304
294
|
]
|
305
295
|
|
306
296
|
unless ptrue?(@header_row_count)
|
307
|
-
attributes << 'headerRowCount'
|
297
|
+
attributes << ['headerRowCount', 0]
|
308
298
|
end
|
309
299
|
|
310
300
|
if ptrue?(@totals_row_shown)
|
311
|
-
attributes << 'totalsRowCount'
|
301
|
+
attributes << ['totalsRowCount', 1]
|
312
302
|
else
|
313
|
-
attributes << 'totalsRowShown'
|
303
|
+
attributes << ['totalsRowShown', 0]
|
314
304
|
end
|
315
305
|
end
|
316
306
|
|
@@ -320,7 +310,7 @@ def write_table_attributes
|
|
320
310
|
def write_auto_filter
|
321
311
|
return unless ptrue?(@autofilter)
|
322
312
|
|
323
|
-
attributes = ['ref', @autofilter]
|
313
|
+
attributes = [ ['ref', @autofilter] ]
|
324
314
|
|
325
315
|
@writer.empty_tag('autoFilter', attributes)
|
326
316
|
end
|
@@ -331,7 +321,7 @@ def write_auto_filter
|
|
331
321
|
def write_table_columns
|
332
322
|
count = @columns.size
|
333
323
|
|
334
|
-
attributes = ['count', count]
|
324
|
+
attributes = [ ['count', count] ]
|
335
325
|
|
336
326
|
@writer.tag_elements('tableColumns', attributes) do
|
337
327
|
@columns.each {|col_data| write_table_column(col_data)}
|
@@ -343,18 +333,18 @@ def write_table_columns
|
|
343
333
|
#
|
344
334
|
def write_table_column(col_data)
|
345
335
|
attributes = [
|
346
|
-
'id', col_data.id,
|
347
|
-
'name', col_data.name
|
336
|
+
['id', col_data.id],
|
337
|
+
['name', col_data.name]
|
348
338
|
]
|
349
339
|
|
350
340
|
if ptrue?(col_data.total_string)
|
351
|
-
attributes << :totalsRowLabel
|
341
|
+
attributes << [:totalsRowLabel, col_data.total_string]
|
352
342
|
elsif ptrue?(col_data.total_function)
|
353
|
-
attributes << :totalsRowFunction
|
343
|
+
attributes << [:totalsRowFunction, col_data.total_function]
|
354
344
|
end
|
355
345
|
|
356
346
|
if col_data.format
|
357
|
-
attributes << :dataDxfId
|
347
|
+
attributes << [:dataDxfId, col_data.format]
|
358
348
|
end
|
359
349
|
|
360
350
|
if ptrue?(col_data.formula)
|
@@ -372,11 +362,11 @@ def write_table_column(col_data)
|
|
372
362
|
#
|
373
363
|
def write_table_style_info
|
374
364
|
attributes = [
|
375
|
-
'name', @style,
|
376
|
-
'showFirstColumn', @show_first_col,
|
377
|
-
'showLastColumn', @show_last_col,
|
378
|
-
'showRowStripes', @show_row_stripes,
|
379
|
-
'showColumnStripes', @show_col_stripes
|
365
|
+
['name', @style],
|
366
|
+
['showFirstColumn', @show_first_col],
|
367
|
+
['showLastColumn', @show_last_col],
|
368
|
+
['showRowStripes', @show_row_stripes],
|
369
|
+
['showColumnStripes', @show_col_stripes]
|
380
370
|
]
|
381
371
|
|
382
372
|
@writer.empty_tag('tableStyleInfo', attributes)
|
@@ -72,9 +72,9 @@ def write_xml_namespace
|
|
72
72
|
def xml_attributes
|
73
73
|
schema = 'urn:schemas-microsoft-com:'
|
74
74
|
[
|
75
|
-
'xmlns:v', "#{schema}vml",
|
76
|
-
'xmlns:o', "#{schema}office:office",
|
77
|
-
'xmlns:x', "#{schema}office:excel"
|
75
|
+
['xmlns:v', "#{schema}vml"],
|
76
|
+
['xmlns:o', "#{schema}office:office"],
|
77
|
+
['xmlns:x', "#{schema}office:excel"]
|
78
78
|
]
|
79
79
|
end
|
80
80
|
|
@@ -82,7 +82,9 @@ def xml_attributes
|
|
82
82
|
# Write the <o:shapelayout> element.
|
83
83
|
#
|
84
84
|
def write_shapelayout(data_id)
|
85
|
-
attributes = [
|
85
|
+
attributes = [
|
86
|
+
['v:ext', 'edit']
|
87
|
+
]
|
86
88
|
|
87
89
|
@writer.tag_elements('o:shapelayout', attributes) do
|
88
90
|
# Write the o:idmap element.
|
@@ -95,8 +97,8 @@ def write_shapelayout(data_id)
|
|
95
97
|
#
|
96
98
|
def write_idmap(data_id)
|
97
99
|
attributes = [
|
98
|
-
'v:ext', 'edit',
|
99
|
-
'data', data_id
|
100
|
+
['v:ext', 'edit'],
|
101
|
+
['data', data_id]
|
100
102
|
]
|
101
103
|
|
102
104
|
@writer.empty_tag('o:idmap', attributes)
|
@@ -107,10 +109,10 @@ def write_idmap(data_id)
|
|
107
109
|
#
|
108
110
|
def write_comment_shapetype
|
109
111
|
attributes = [
|
110
|
-
'id', '_x0000_t202',
|
111
|
-
'coordsize', '21600,21600',
|
112
|
-
'o:spt', 202,
|
113
|
-
'path', 'm,l,21600r21600,l21600,xe'
|
112
|
+
['id', '_x0000_t202'],
|
113
|
+
['coordsize', '21600,21600'],
|
114
|
+
['o:spt', 202],
|
115
|
+
['path', 'm,l,21600r21600,l21600,xe']
|
114
116
|
]
|
115
117
|
|
116
118
|
@writer.tag_elements('v:shapetype', attributes) do
|
@@ -126,10 +128,10 @@ def write_comment_shapetype
|
|
126
128
|
#
|
127
129
|
def write_button_shapetype
|
128
130
|
attributes = [
|
129
|
-
'id', '_x0000_t201',
|
130
|
-
'coordsize', '21600,21600',
|
131
|
-
'o:spt', 201,
|
132
|
-
'path', 'm,l,21600r21600,l21600,xe'
|
131
|
+
['id', '_x0000_t201'],
|
132
|
+
['coordsize', '21600,21600'],
|
133
|
+
['o:spt', 201],
|
134
|
+
['path', 'm,l,21600r21600,l21600,xe']
|
133
135
|
]
|
134
136
|
|
135
137
|
@writer.tag_elements('v:shapetype', attributes) do
|
@@ -147,11 +149,11 @@ def write_button_shapetype
|
|
147
149
|
#
|
148
150
|
def write_button_path
|
149
151
|
attributes = [
|
150
|
-
'shadowok', 'f',
|
151
|
-
'o:extrusionok', 'f',
|
152
|
-
'strokeok', 'f',
|
153
|
-
'fillok', 'f',
|
154
|
-
'o:connecttype', 'rect'
|
152
|
+
['shadowok', 'f'],
|
153
|
+
['o:extrusionok', 'f'],
|
154
|
+
['strokeok', 'f'],
|
155
|
+
['fillok', 'f'],
|
156
|
+
['o:connecttype', 'rect']
|
155
157
|
]
|
156
158
|
@writer.empty_tag('v:path', attributes)
|
157
159
|
end
|
@@ -161,8 +163,8 @@ def write_button_path
|
|
161
163
|
#
|
162
164
|
def write_shapetype_lock
|
163
165
|
attributes = [
|
164
|
-
'v:ext', 'edit',
|
165
|
-
'shapetype', 't'
|
166
|
+
['v:ext', 'edit'],
|
167
|
+
['shapetype', 't']
|
166
168
|
]
|
167
169
|
@writer.empty_tag('o:lock', attributes)
|
168
170
|
end
|
@@ -110,12 +110,9 @@ def key_val(key, val)
|
|
110
110
|
%Q{ #{key}="#{val}"}
|
111
111
|
end
|
112
112
|
|
113
|
-
def key_vals(
|
114
|
-
|
115
|
-
|
116
|
-
array << key_val(attr[i], escape_attributes(attr[i+1]))
|
117
|
-
end
|
118
|
-
array.join('')
|
113
|
+
def key_vals(attribute)
|
114
|
+
attribute.
|
115
|
+
inject('') { |str, attr| str + key_val(attr.first, escape_attributes(attr.last)) }
|
119
116
|
end
|
120
117
|
|
121
118
|
def escape_attributes(str = '')
|
data/lib/write_xlsx/sheets.rb
CHANGED
@@ -215,14 +215,14 @@ def write_sheet_files(dir, sheet, index)
|
|
215
215
|
|
216
216
|
def write_sheet(writer, sheet, sheet_id) #:nodoc:
|
217
217
|
attributes = [
|
218
|
-
'name', sheet.name,
|
219
|
-
'sheetId', sheet_id
|
218
|
+
['name', sheet.name],
|
219
|
+
['sheetId', sheet_id]
|
220
220
|
]
|
221
221
|
|
222
222
|
if sheet.hidden?
|
223
|
-
attributes << 'state'
|
223
|
+
attributes << ['state', 'hidden']
|
224
224
|
end
|
225
|
-
attributes
|
225
|
+
attributes << r_id_attributes(sheet_id)
|
226
226
|
writer.empty_tag_encoded('sheet', attributes)
|
227
227
|
end
|
228
228
|
end
|
data/lib/write_xlsx/sparkline.rb
CHANGED
@@ -113,27 +113,27 @@ def group_attributes
|
|
113
113
|
cust_min = cust_max_min(@min) if @min
|
114
114
|
|
115
115
|
a = []
|
116
|
-
a << 'manualMax'
|
117
|
-
a << 'manualMin'
|
116
|
+
a << ['manualMax', @max] if @max && @max != 'group'
|
117
|
+
a << ['manualMin', @min] if @min && @min != 'group'
|
118
118
|
|
119
119
|
# Ignore the default type attribute (line).
|
120
|
-
a << 'type'
|
121
|
-
|
122
|
-
a << 'lineWeight'
|
123
|
-
a << 'dateAxis'
|
124
|
-
a << 'displayEmptyCellsAs'
|
125
|
-
|
126
|
-
a << 'markers'
|
127
|
-
a << 'high'
|
128
|
-
a << 'low'
|
129
|
-
a << 'first'
|
130
|
-
a << 'last'
|
131
|
-
a << 'negative'
|
132
|
-
a << 'displayXAxis'
|
133
|
-
a << 'displayHidden'
|
134
|
-
a << 'minAxisType'
|
135
|
-
a << 'maxAxisType'
|
136
|
-
a << 'rightToLeft'
|
120
|
+
a << ['type', @type] if @type != 'line'
|
121
|
+
|
122
|
+
a << ['lineWeight', @weight] if @weight
|
123
|
+
a << ['dateAxis', 1] if @date_axis
|
124
|
+
a << ['displayEmptyCellsAs', @empty] if ptrue?(@empty)
|
125
|
+
|
126
|
+
a << ['markers', 1] if @markers
|
127
|
+
a << ['high', 1] if @high
|
128
|
+
a << ['low', 1] if @low
|
129
|
+
a << ['first', 1] if @first
|
130
|
+
a << ['last', 1] if @last
|
131
|
+
a << ['negative', 1] if @negative
|
132
|
+
a << ['displayXAxis', 1] if @axis
|
133
|
+
a << ['displayHidden', 1] if @hidden
|
134
|
+
a << ['minAxisType', cust_min] if cust_min
|
135
|
+
a << ['maxAxisType', cust_max] if cust_max
|
136
|
+
a << ['rightToLeft', 1] if @reverse
|
137
137
|
a
|
138
138
|
end
|
139
139
|
|
@@ -272,9 +272,9 @@ def write_sparklines # :nodoc:
|
|
272
272
|
def write_spark_color(element, color) # :nodoc:
|
273
273
|
attr = []
|
274
274
|
|
275
|
-
attr << 'rgb'
|
276
|
-
attr << 'theme'
|
277
|
-
attr << 'tint'
|
275
|
+
attr << ['rgb', color[:_rgb]] if color[:_rgb]
|
276
|
+
attr << ['theme', color[:_theme]] if color[:_theme]
|
277
|
+
attr << ['tint', color[:_tint]] if color[:_tint]
|
278
278
|
|
279
279
|
@writer.empty_tag(element, attr)
|
280
280
|
end
|
data/lib/write_xlsx/utility.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
+
require 'write_xlsx/col_name'
|
3
|
+
|
2
4
|
module Writexlsx
|
3
5
|
module Utility
|
4
6
|
ROW_MAX = 1048576 # :nodoc:
|
@@ -50,25 +52,7 @@ def xl_cell_to_rowcol(cell)
|
|
50
52
|
end
|
51
53
|
|
52
54
|
def xl_col_to_name(col, col_absolute)
|
53
|
-
|
54
|
-
col += 1
|
55
|
-
col_str = ''
|
56
|
-
|
57
|
-
while col > 0
|
58
|
-
# Set remainder from 1 .. 26
|
59
|
-
remainder = col % 26
|
60
|
-
remainder = 26 if remainder == 0
|
61
|
-
|
62
|
-
# Convert the remainder to a character. C-ishly.
|
63
|
-
col_letter = ("A".ord + remainder - 1).chr
|
64
|
-
|
65
|
-
# Accumulate the column letters, right to left.
|
66
|
-
col_str = col_letter + col_str
|
67
|
-
|
68
|
-
# Get the next order of magnitude.
|
69
|
-
col = (col - 1) / 26
|
70
|
-
end
|
71
|
-
|
55
|
+
col_str = ColName.instance.col_str(col)
|
72
56
|
"#{absolute_char(col_absolute)}#{col_str}"
|
73
57
|
end
|
74
58
|
|
@@ -285,11 +269,11 @@ def substitute_cellref(cell, *args) #:nodoc:
|
|
285
269
|
|
286
270
|
def underline_attributes(underline)
|
287
271
|
if underline == 2
|
288
|
-
['val', 'double']
|
272
|
+
[['val', 'double']]
|
289
273
|
elsif underline == 33
|
290
|
-
['val', 'singleAccounting']
|
274
|
+
[['val', 'singleAccounting']]
|
291
275
|
elsif underline == 34
|
292
|
-
['val', 'doubleAccounting']
|
276
|
+
[['val', 'doubleAccounting']]
|
293
277
|
else
|
294
278
|
[] # Default to single underline.
|
295
279
|
end
|
@@ -299,7 +283,7 @@ def underline_attributes(underline)
|
|
299
283
|
# Write the <color> element.
|
300
284
|
#
|
301
285
|
def write_color(writer, name, value) #:nodoc:
|
302
|
-
attributes = [name, value]
|
286
|
+
attributes = [[name, value]]
|
303
287
|
|
304
288
|
writer.empty_tag('color', attributes)
|
305
289
|
end
|
@@ -378,9 +362,9 @@ def pixels_to_points(vertices)
|
|
378
362
|
|
379
363
|
def v_shape_attributes_base(id, z_index)
|
380
364
|
[
|
381
|
-
'id', "_x0000_s#{id}",
|
382
|
-
'type', type,
|
383
|
-
'style', (v_shape_style_base(z_index, vertices) + style_addition).join
|
365
|
+
['id', "_x0000_s#{id}"],
|
366
|
+
['type', type],
|
367
|
+
['style', (v_shape_style_base(z_index, vertices) + style_addition).join]
|
384
368
|
]
|
385
369
|
end
|
386
370
|
|
@@ -425,8 +409,8 @@ def write_fill
|
|
425
409
|
def write_comment_path(gradientshapeok, connecttype)
|
426
410
|
attributes = []
|
427
411
|
|
428
|
-
attributes << 'gradientshapeok'
|
429
|
-
attributes << 'o:connecttype'
|
412
|
+
attributes << ['gradientshapeok', 't'] if gradientshapeok
|
413
|
+
attributes << ['o:connecttype', connecttype]
|
430
414
|
|
431
415
|
@writer.empty_tag('v:path', attributes)
|
432
416
|
end
|
@@ -453,7 +437,7 @@ def write_auto_fill
|
|
453
437
|
#
|
454
438
|
def write_div(align, font = nil)
|
455
439
|
style = "text-align:#{align}"
|
456
|
-
attributes = ['style', style]
|
440
|
+
attributes = [['style', style]]
|
457
441
|
|
458
442
|
@writer.tag_elements('div', attributes) do
|
459
443
|
if font
|
@@ -473,9 +457,9 @@ def write_font(font)
|
|
473
457
|
color = '#000000'
|
474
458
|
|
475
459
|
attributes = [
|
476
|
-
'face', face,
|
477
|
-
'size', size,
|
478
|
-
'color', color
|
460
|
+
['face', face],
|
461
|
+
['size', size],
|
462
|
+
['color', color]
|
479
463
|
]
|
480
464
|
@writer.data_element('font', caption, attributes)
|
481
465
|
end
|
@@ -484,7 +468,7 @@ def write_font(font)
|
|
484
468
|
# Write the <v:stroke> element.
|
485
469
|
#
|
486
470
|
def write_stroke
|
487
|
-
attributes = ['joinstyle', 'miter']
|
471
|
+
attributes = [['joinstyle', 'miter']]
|
488
472
|
|
489
473
|
@writer.empty_tag('v:stroke', attributes)
|
490
474
|
end
|
@@ -492,5 +476,49 @@ def write_stroke
|
|
492
476
|
def r_id_attributes(id)
|
493
477
|
['r:id', "rId#{id}"]
|
494
478
|
end
|
479
|
+
|
480
|
+
def write_xml_declaration
|
481
|
+
@writer.xml_decl
|
482
|
+
yield
|
483
|
+
@writer.crlf
|
484
|
+
@writer.close
|
485
|
+
end
|
486
|
+
|
487
|
+
#
|
488
|
+
# Convert user defined line properties to the structure required internally.
|
489
|
+
#
|
490
|
+
def line_properties(line) # :nodoc:
|
491
|
+
return { :_defined => 0 } unless line
|
492
|
+
|
493
|
+
dash_types = {
|
494
|
+
:solid => 'solid',
|
495
|
+
:round_dot => 'sysDot',
|
496
|
+
:square_dot => 'sysDash',
|
497
|
+
:dash => 'dash',
|
498
|
+
:dash_dot => 'dashDot',
|
499
|
+
:long_dash => 'lgDash',
|
500
|
+
:long_dash_dot => 'lgDashDot',
|
501
|
+
:long_dash_dot_dot => 'lgDashDotDot',
|
502
|
+
:dot => 'dot',
|
503
|
+
:system_dash_dot => 'sysDashDot',
|
504
|
+
:system_dash_dot_dot => 'sysDashDotDot'
|
505
|
+
}
|
506
|
+
|
507
|
+
# Check the dash type.
|
508
|
+
dash_type = line[:dash_type]
|
509
|
+
|
510
|
+
if dash_type
|
511
|
+
line[:dash_type] = value_or_raise(dash_types, dash_type, 'dash type')
|
512
|
+
end
|
513
|
+
|
514
|
+
line[:_defined] = 1
|
515
|
+
|
516
|
+
line
|
517
|
+
end
|
518
|
+
|
519
|
+
def value_or_raise(hash, key, msg)
|
520
|
+
raise "Unknown #{msg} '#{key}'" unless hash[key.to_sym]
|
521
|
+
hash[key.to_sym]
|
522
|
+
end
|
495
523
|
end
|
496
524
|
end
|