tty 0.0.9 → 0.0.10
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.
- data/.rspec +2 -1
- data/.travis.yml +3 -6
- data/README.md +232 -134
- data/lib/tty/plugins/plugin.rb +56 -0
- data/lib/tty/plugins.rb +75 -0
- data/lib/tty/shell/suggestion.rb +102 -0
- data/lib/tty/shell.rb +41 -14
- data/lib/tty/system/editor.rb +111 -0
- data/lib/tty/system/which.rb +13 -1
- data/lib/tty/system.rb +44 -28
- data/lib/tty/table/border/null.rb +0 -9
- data/lib/tty/table/border/row_line.rb +21 -0
- data/lib/tty/table/border.rb +63 -32
- data/lib/tty/table/border_dsl.rb +1 -1
- data/lib/tty/table/column_set.rb +16 -17
- data/lib/tty/table/field.rb +27 -7
- data/lib/tty/table/header.rb +18 -9
- data/lib/tty/table/operation/alignment_set.rb +20 -25
- data/lib/tty/table/operation/escape.rb +30 -0
- data/lib/tty/table/operation/filter.rb +36 -0
- data/lib/tty/table/operation/truncation.rb +22 -11
- data/lib/tty/table/operation/wrapped.rb +21 -10
- data/lib/tty/table/operations.rb +10 -8
- data/lib/tty/table/orientation/horizontal.rb +1 -1
- data/lib/tty/table/renderer/ascii.rb +3 -3
- data/lib/tty/table/renderer/basic.rb +135 -65
- data/lib/tty/table/renderer/color.rb +1 -4
- data/lib/tty/table/renderer/unicode.rb +3 -3
- data/lib/tty/table/renderer.rb +48 -61
- data/lib/tty/table/row.rb +30 -3
- data/lib/tty/table/transformation.rb +38 -0
- data/lib/tty/table/validatable.rb +7 -5
- data/lib/tty/table.rb +78 -99
- data/lib/tty/terminal/color.rb +2 -2
- data/lib/tty/terminal/echo.rb +1 -1
- data/lib/tty/terminal/pager/basic.rb +52 -0
- data/lib/tty/terminal/pager/system.rb +39 -0
- data/lib/tty/terminal/pager.rb +95 -0
- data/lib/tty/terminal.rb +30 -1
- data/lib/tty/version.rb +1 -1
- data/lib/tty.rb +41 -1
- data/spec/spec_helper.rb +20 -0
- data/spec/tty/plugins/find_spec.rb +28 -0
- data/spec/tty/plugins/load_spec.rb +20 -0
- data/spec/tty/plugins/plugin/load_spec.rb +30 -0
- data/spec/tty/plugins/plugin/new_spec.rb +18 -0
- data/spec/tty/shell/suggest_spec.rb +50 -0
- data/spec/tty/support/conversion_spec.rb +3 -3
- data/spec/tty/support/delegatable_spec.rb +1 -1
- data/spec/tty/support/equatable_spec.rb +6 -9
- data/spec/tty/system/editor/available_spec.rb +40 -0
- data/spec/tty/system/editor/build_spec.rb +40 -0
- data/spec/tty/system/editor/command_spec.rb +16 -0
- data/spec/tty/system/editor/executables_spec.rb +13 -0
- data/spec/tty/system/editor/invoke_spec.rb +38 -0
- data/spec/tty/system/editor/open_spec.rb +27 -0
- data/spec/tty/system/platform_spec.rb +4 -6
- data/spec/tty/system/which/which_spec.rb +48 -0
- data/spec/tty/system/which_spec.rb +8 -34
- data/spec/tty/table/border/ascii/rendering_spec.rb +19 -5
- data/spec/tty/table/border/new_spec.rb +1 -1
- data/spec/tty/table/border/null/rendering_spec.rb +24 -8
- data/spec/tty/table/border/unicode/rendering_spec.rb +19 -5
- data/spec/tty/table/column_set/extract_widths_spec.rb +4 -15
- data/spec/tty/table/column_set/total_width_spec.rb +15 -0
- data/spec/tty/table/data_spec.rb +14 -0
- data/spec/tty/table/each_spec.rb +17 -4
- data/spec/tty/table/each_with_index_spec.rb +34 -6
- data/spec/tty/table/field/length_spec.rb +21 -0
- data/spec/tty/table/field/lines_spec.rb +21 -0
- data/spec/tty/table/filter_spec.rb +23 -0
- data/spec/tty/table/header/call_spec.rb +1 -1
- data/spec/tty/table/header/height_spec.rb +27 -0
- data/spec/tty/table/initialize_spec.rb +6 -6
- data/spec/tty/table/operation/alignment_set/call_spec.rb +39 -0
- data/spec/tty/table/operation/escape/call_spec.rb +16 -0
- data/spec/tty/table/operation/filter/call_spec.rb +17 -0
- data/spec/tty/table/operation/truncation/call_spec.rb +15 -10
- data/spec/tty/table/operation/truncation/truncate_spec.rb +1 -1
- data/spec/tty/table/operation/wrapped/call_spec.rb +15 -10
- data/spec/tty/table/operation/wrapped/wrap_spec.rb +1 -1
- data/spec/tty/table/operations/new_spec.rb +4 -4
- data/spec/tty/table/options_spec.rb +0 -28
- data/spec/tty/table/orientation_spec.rb +5 -6
- data/spec/tty/table/properties_spec.rb +1 -4
- data/spec/tty/table/render_spec.rb +57 -0
- data/spec/tty/table/{renders_with_spec.rb → render_with_spec.rb} +29 -10
- data/spec/tty/table/renderer/ascii/render_spec.rb +68 -0
- data/spec/tty/table/renderer/ascii/separator_spec.rb +28 -0
- data/spec/tty/table/renderer/basic/alignment_spec.rb +18 -16
- data/spec/tty/table/renderer/basic/extract_column_widths_spec.rb +17 -12
- data/spec/tty/table/renderer/basic/filter_spec.rb +53 -0
- data/spec/tty/table/renderer/basic/multiline_content_spec.rb +135 -0
- data/spec/tty/table/renderer/basic/new_spec.rb +13 -2
- data/spec/tty/table/renderer/basic/options_spec.rb +48 -0
- data/spec/tty/table/renderer/basic/render_spec.rb +19 -121
- data/spec/tty/table/renderer/basic/separator_spec.rb +14 -48
- data/spec/tty/table/renderer/basic/truncation_spec.rb +35 -0
- data/spec/tty/table/renderer/basic/wrapping_spec.rb +40 -0
- data/spec/tty/table/{border_spec.rb → renderer/border_spec.rb} +17 -20
- data/spec/tty/table/renderer/select_spec.rb +22 -0
- data/spec/tty/table/{border → renderer}/style_spec.rb +13 -14
- data/spec/tty/table/renderer/unicode/render_spec.rb +68 -0
- data/spec/tty/table/renderer/unicode/separator_spec.rb +26 -0
- data/spec/tty/table/rotate_spec.rb +2 -3
- data/spec/tty/table/row/call_spec.rb +1 -1
- data/spec/tty/table/row/each_spec.rb +31 -0
- data/spec/tty/table/row/height_spec.rb +27 -0
- data/spec/tty/table/to_s_spec.rb +3 -3
- data/spec/tty/table/transformation/extract_tuples_spec.rb +35 -0
- data/spec/tty/table/validatable/validate_options_spec.rb +1 -2
- data/spec/tty/terminal/home_spec.rb +3 -3
- data/spec/tty/terminal/page_spec.rb +13 -0
- data/spec/tty/terminal/pager/available_spec.rb +40 -0
- data/spec/tty/terminal/pager/basic/page_spec.rb +54 -0
- data/spec/tty/terminal/pager/command_spec.rb +16 -0
- data/spec/tty/terminal/pager/executables_spec.rb +13 -0
- data/spec/tty/terminal/pager/page_spec.rb +47 -0
- data/spec/tty/terminal/pager/system/page_spec.rb +29 -0
- data/spec/tty/text/distance/distance_spec.rb +12 -0
- data/tty.gemspec +7 -3
- metadata +160 -27
- data/spec/tty/table/operation/alignment_set/align_rows_spec.rb +0 -53
- data/spec/tty/table/renderer/pick_renderer_spec.rb +0 -25
- data/spec/tty/table/renderer_spec.rb +0 -49
data/lib/tty/table/column_set.rb
CHANGED
@@ -6,12 +6,12 @@ module TTY
|
|
6
6
|
# A class that represents table columns properties.
|
7
7
|
class ColumnSet
|
8
8
|
include Equatable
|
9
|
-
extend Delegatable
|
10
9
|
|
11
10
|
attr_reader :table
|
12
11
|
|
13
|
-
|
14
|
-
|
12
|
+
# Initialize a ColumnSet
|
13
|
+
#
|
14
|
+
# @api public
|
15
15
|
def initialize(table)
|
16
16
|
@table = table
|
17
17
|
end
|
@@ -22,7 +22,7 @@ module TTY
|
|
22
22
|
#
|
23
23
|
# @api public
|
24
24
|
def total_width
|
25
|
-
|
25
|
+
extract_widths.reduce(:+)
|
26
26
|
end
|
27
27
|
|
28
28
|
# Calcualte maximum column widths
|
@@ -30,15 +30,11 @@ module TTY
|
|
30
30
|
# @return [Array] column widths
|
31
31
|
#
|
32
32
|
# @api private
|
33
|
-
def extract_widths
|
34
|
-
|
35
|
-
|
36
|
-
rows = table.to_a
|
37
|
-
data = table.header ? rows + [table.header] : rows
|
33
|
+
def extract_widths
|
34
|
+
data = table.data
|
38
35
|
colcount = data.max { |row_a, row_b| row_a.size <=> row_b.size }.size
|
39
36
|
|
40
|
-
|
41
|
-
self
|
37
|
+
self.class.find_maximas(colcount, data)
|
42
38
|
end
|
43
39
|
|
44
40
|
private
|
@@ -51,25 +47,28 @@ module TTY
|
|
51
47
|
# the table's header and rows
|
52
48
|
#
|
53
49
|
# @api private
|
54
|
-
def find_maximas(colcount, data)
|
50
|
+
def self.find_maximas(colcount, data)
|
55
51
|
maximas = []
|
56
52
|
start = 0
|
57
53
|
|
58
|
-
start.upto(colcount - 1) do |
|
59
|
-
maximas << find_maximum(data,
|
54
|
+
start.upto(colcount - 1) do |col_index|
|
55
|
+
maximas << find_maximum(data, col_index)
|
60
56
|
end
|
61
57
|
maximas
|
62
58
|
end
|
63
59
|
|
64
|
-
# Find a maximum column width.
|
60
|
+
# Find a maximum column width. The calculation takes into account
|
61
|
+
# wether the content is escaped or not.
|
65
62
|
#
|
66
63
|
# @param [Array] data
|
64
|
+
# the table data
|
67
65
|
#
|
68
66
|
# @param [Integer] index
|
67
|
+
# the column index
|
69
68
|
#
|
70
69
|
# @api private
|
71
|
-
def find_maximum(data, index)
|
72
|
-
data.map { |row| row
|
70
|
+
def self.find_maximum(data, index)
|
71
|
+
data.map { |row| (value=row.call(index)) ? value.length : 0 }.max
|
73
72
|
end
|
74
73
|
|
75
74
|
end # ColumnSet
|
data/lib/tty/table/field.rb
CHANGED
@@ -69,20 +69,40 @@ module TTY
|
|
69
69
|
@height
|
70
70
|
end
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
# Return number of lines this value spans
|
72
|
+
# Return number of lines this value spans. A distinction is being made
|
73
|
+
# between escaped and non-escaped strings.
|
74
|
+
#
|
75
|
+
# @return [Array[String]]
|
77
76
|
#
|
77
|
+
# @api public
|
78
78
|
def lines
|
79
|
-
value.to_s.
|
79
|
+
escaped = value.to_s.scan(/(\\n|\\t|\\r)/)
|
80
|
+
escaped.empty? ? value.to_s.split(/\n/) : [value.to_s]
|
80
81
|
end
|
81
82
|
|
82
|
-
|
83
|
+
# If the string contains unescaped new lines then the longest token
|
84
|
+
# deterimines the actual field length.
|
85
|
+
#
|
86
|
+
# @return [Integer]
|
87
|
+
#
|
88
|
+
# @api public
|
89
|
+
def length
|
83
90
|
lines.max_by(&:length).size
|
84
91
|
end
|
85
92
|
|
93
|
+
# Extract the number of lines this value spans
|
94
|
+
#
|
95
|
+
# @return [Integer]
|
96
|
+
#
|
97
|
+
# @api public
|
98
|
+
def height
|
99
|
+
lines.size
|
100
|
+
end
|
101
|
+
|
102
|
+
def chars
|
103
|
+
value.chars
|
104
|
+
end
|
105
|
+
|
86
106
|
# Render value inside this field box
|
87
107
|
#
|
88
108
|
# @api public
|
data/lib/tty/table/header.rb
CHANGED
@@ -28,6 +28,7 @@ module TTY
|
|
28
28
|
#
|
29
29
|
# @api private
|
30
30
|
attr_reader :attributes
|
31
|
+
alias :fields :attributes
|
31
32
|
|
32
33
|
# Initialize a Header
|
33
34
|
#
|
@@ -46,13 +47,6 @@ module TTY
|
|
46
47
|
Field.new(options)
|
47
48
|
end
|
48
49
|
|
49
|
-
# Filter header names including styling background,
|
50
|
-
# text color and capitalization
|
51
|
-
#
|
52
|
-
#
|
53
|
-
def filter
|
54
|
-
end
|
55
|
-
|
56
50
|
# Lookup a column in the header given a name
|
57
51
|
#
|
58
52
|
# @api public
|
@@ -66,7 +60,13 @@ module TTY
|
|
66
60
|
end
|
67
61
|
end
|
68
62
|
end
|
69
|
-
|
63
|
+
|
64
|
+
# Lookup attribute without evaluation
|
65
|
+
#
|
66
|
+
# @api public
|
67
|
+
def call(attribute)
|
68
|
+
@attributes[attribute]
|
69
|
+
end
|
70
70
|
|
71
71
|
# Set value at index
|
72
72
|
#
|
@@ -86,11 +86,20 @@ module TTY
|
|
86
86
|
end
|
87
87
|
alias :length :size
|
88
88
|
|
89
|
+
# Find maximum header height
|
90
|
+
#
|
91
|
+
# @return [Integer]
|
92
|
+
#
|
93
|
+
# @api public
|
94
|
+
def height
|
95
|
+
attributes.map { |field| field.height }.max
|
96
|
+
end
|
97
|
+
|
89
98
|
# Convert the Header into an Array
|
90
99
|
#
|
91
100
|
# @api public
|
92
101
|
def to_ary
|
93
|
-
attributes.map { |attr| attr.value if attr
|
102
|
+
attributes.map { |attr| attr.value if attr }
|
94
103
|
end
|
95
104
|
|
96
105
|
# Check if this header is equivalent to another header
|
@@ -7,6 +7,13 @@ module TTY
|
|
7
7
|
# A class which responsiblity is to align table rows and header.
|
8
8
|
class AlignmentSet < Vector
|
9
9
|
|
10
|
+
attr_reader :widths
|
11
|
+
|
12
|
+
def initialize(aligns, widths=nil)
|
13
|
+
@elements = convert_to_array(aligns)
|
14
|
+
@widths = widths
|
15
|
+
end
|
16
|
+
|
10
17
|
# Lookup an alignment by index
|
11
18
|
#
|
12
19
|
# @param [Integer]
|
@@ -34,44 +41,32 @@ module TTY
|
|
34
41
|
# @param [Hash] options
|
35
42
|
# the table options
|
36
43
|
#
|
37
|
-
# @return [
|
44
|
+
# @return [TTY::Table::Field]
|
38
45
|
#
|
39
46
|
# @api public
|
40
|
-
def call(row,
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
|
-
# Align the supplied rows with the correct alignment.
|
45
|
-
#
|
46
|
-
# @param [Array] rows
|
47
|
-
#
|
48
|
-
# @return [Array[Array]]
|
49
|
-
# the aligned rows
|
50
|
-
#
|
51
|
-
# @api private
|
52
|
-
def align_rows(rows, options={})
|
53
|
-
rows.map { |row| align_row(row, options) }
|
47
|
+
def call(field, row, col)
|
48
|
+
align_field(field, col)
|
54
49
|
end
|
55
50
|
|
56
51
|
private
|
57
52
|
|
58
53
|
# Align each field in a row
|
59
54
|
#
|
60
|
-
# @param [
|
55
|
+
# @param [TTY::Table::Field] field
|
56
|
+
# the table field
|
57
|
+
#
|
58
|
+
# @param [Integer] col
|
59
|
+
# the table column index
|
61
60
|
#
|
62
61
|
# @param [Hash] options
|
63
62
|
#
|
64
|
-
# @return [
|
63
|
+
# @return [TTY::Table::Field]
|
65
64
|
#
|
66
65
|
# @api private
|
67
|
-
def
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
alignment = Alignment.new(field.align || self[index])
|
72
|
-
index += 1
|
73
|
-
alignment.format(field, column_width)
|
74
|
-
end
|
66
|
+
def align_field(field, col)
|
67
|
+
column_width = widths[col]
|
68
|
+
alignment = Alignment.new(field.align || self[col])
|
69
|
+
field.value = alignment.format(field, column_width)
|
75
70
|
end
|
76
71
|
|
77
72
|
end # AlignmentSet
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
class Table
|
5
|
+
module Operation
|
6
|
+
|
7
|
+
# A class responsible for escaping special chars in a table field
|
8
|
+
class Escape
|
9
|
+
|
10
|
+
# Escape special characters in a table field
|
11
|
+
#
|
12
|
+
# @param [TTY::Table::Field] field
|
13
|
+
#
|
14
|
+
# @param [Integer] row
|
15
|
+
# the field row index
|
16
|
+
#
|
17
|
+
# @param [Integer] col
|
18
|
+
# the field column index
|
19
|
+
#
|
20
|
+
# @api public
|
21
|
+
def call(field, row, col)
|
22
|
+
field.value = field.value.gsub(/(\t|\r|\n)/) do |val|
|
23
|
+
val.dump.gsub('"', '')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end # Escape
|
28
|
+
end # Operation
|
29
|
+
end # Table
|
30
|
+
end # TTY
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
class Table
|
5
|
+
module Operation
|
6
|
+
|
7
|
+
# A class responsible for transforming table field
|
8
|
+
class Filter
|
9
|
+
|
10
|
+
# Initialize a Filter
|
11
|
+
#
|
12
|
+
# @api public
|
13
|
+
def initialize(filter)
|
14
|
+
@filter = filter
|
15
|
+
end
|
16
|
+
|
17
|
+
# Apply filer to the provided table field
|
18
|
+
#
|
19
|
+
# @param [TTY::Table::Field] field
|
20
|
+
#
|
21
|
+
# @param [Integer] row
|
22
|
+
# the field row index
|
23
|
+
#
|
24
|
+
# @param [Integer] col
|
25
|
+
# the field column index
|
26
|
+
#
|
27
|
+
# @api public
|
28
|
+
def call(field, row, col)
|
29
|
+
field.value = @filter.call(field.value, row, col)
|
30
|
+
end
|
31
|
+
|
32
|
+
end # Filter
|
33
|
+
|
34
|
+
end # Operation
|
35
|
+
end # Table
|
36
|
+
end # TTY
|
@@ -7,21 +7,32 @@ module TTY
|
|
7
7
|
# A class responsible for shortening text.
|
8
8
|
class Truncation
|
9
9
|
|
10
|
-
|
10
|
+
attr_reader :widths
|
11
|
+
|
12
|
+
# Initialize a Truncation
|
13
|
+
#
|
14
|
+
# @api public
|
15
|
+
def initialize(widths)
|
16
|
+
@widths = widths
|
17
|
+
end
|
18
|
+
|
19
|
+
# Apply truncation to a field
|
20
|
+
#
|
21
|
+
# @param [TTY::Table::Field] field
|
22
|
+
# the table field
|
23
|
+
#
|
24
|
+
# @param [Integer] row
|
25
|
+
# the field row index
|
11
26
|
#
|
12
|
-
# @param [
|
13
|
-
# the
|
27
|
+
# @param [Integer] col
|
28
|
+
# the field column index
|
14
29
|
#
|
15
|
-
# @return [
|
30
|
+
# @return [TTY::Table::Field]
|
16
31
|
#
|
17
32
|
# @api public
|
18
|
-
def call(row,
|
19
|
-
|
20
|
-
|
21
|
-
width = options.fetch(:column_widths, {})[index] || field.width
|
22
|
-
index += 1
|
23
|
-
field.value = truncate(field.value, width)
|
24
|
-
end
|
33
|
+
def call(field, row, col)
|
34
|
+
width = widths[col] || field.width
|
35
|
+
field.value = truncate(field.value, width)
|
25
36
|
end
|
26
37
|
|
27
38
|
# Shorten given string with traling character.
|
@@ -7,21 +7,32 @@ module TTY
|
|
7
7
|
# A class responsible for wrapping text.
|
8
8
|
class Wrapped
|
9
9
|
|
10
|
-
|
10
|
+
attr_reader :widths
|
11
|
+
|
12
|
+
# Initialize a Wrapped
|
13
|
+
#
|
14
|
+
# @api public
|
15
|
+
def initialize(widths)
|
16
|
+
@widths = widths
|
17
|
+
end
|
18
|
+
|
19
|
+
# Apply wrapping to a field
|
20
|
+
#
|
21
|
+
# @param [TTY::Table::Field] field
|
22
|
+
# the table field
|
23
|
+
#
|
24
|
+
# @param [Integer] row
|
25
|
+
# the field row index
|
11
26
|
#
|
12
|
-
# @param [
|
13
|
-
# the
|
27
|
+
# @param [Integer] col
|
28
|
+
# the field column index
|
14
29
|
#
|
15
30
|
# @return [Array[String]]
|
16
31
|
#
|
17
32
|
# @api public
|
18
|
-
def call(row,
|
19
|
-
|
20
|
-
|
21
|
-
width = options.fetch(:column_widths, {})[index] || field.width
|
22
|
-
index += 1
|
23
|
-
field.value = wrap(field.value, width)
|
24
|
-
end
|
33
|
+
def call(field, row, col)
|
34
|
+
width = widths[col] || field.width
|
35
|
+
field.value = wrap(field.value, width)
|
25
36
|
end
|
26
37
|
|
27
38
|
# Wrap a long string according to the width.
|
data/lib/tty/table/operations.rb
CHANGED
@@ -49,19 +49,21 @@ module TTY
|
|
49
49
|
|
50
50
|
# Apply operations to a table row
|
51
51
|
#
|
52
|
-
# @param [Symbol]
|
53
|
-
# the operation
|
54
|
-
# @param [#to_ary, Row] row
|
55
|
-
# the row to apply operation to
|
52
|
+
# @param [Array[Symbol]] types
|
53
|
+
# the operation types
|
56
54
|
# @param [Hash] options
|
57
55
|
# the options for the row
|
58
56
|
#
|
59
|
-
# @return [
|
57
|
+
# @return [TTY::Table]
|
60
58
|
#
|
61
59
|
# @api public
|
62
|
-
def run_operations(
|
63
|
-
|
64
|
-
|
60
|
+
def run_operations(*args)
|
61
|
+
types = args
|
62
|
+
table.each_with_index do |val, row, col|
|
63
|
+
types.each do |type|
|
64
|
+
operations[type].each { |op| op.call(val, row, col) }
|
65
|
+
end
|
66
|
+
end
|
65
67
|
end
|
66
68
|
|
67
69
|
end # Operations
|
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
module TTY
|
4
4
|
class Table
|
5
|
-
|
5
|
+
class Renderer
|
6
6
|
class ASCII < Basic
|
7
7
|
|
8
|
-
def
|
9
|
-
super
|
8
|
+
def initialize(table, options={})
|
9
|
+
super(table, options.merge(:border_class => TTY::Table::Border::ASCII))
|
10
10
|
end
|
11
11
|
|
12
12
|
end # ASCII
|