wirb 0.3.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +8 -0
- data/README.rdoc +31 -9
- data/data/wirb/classic_paint.yml +137 -0
- data/data/wirb/classic_wirb0.yml +69 -0
- data/lib/wirb.rb +103 -30
- data/lib/wirb/colorizer.rb +26 -0
- data/lib/wirb/colorizer/highline.rb +16 -0
- data/lib/wirb/colorizer/paint.rb +11 -0
- data/lib/wirb/{colors.rb → colorizer/wirb0.rb} +9 -3
- data/lib/wirb/colorizer/wirb0_highline.rb +73 -0
- data/lib/wirb/colorizer/wirb0_paint.rb +71 -0
- data/lib/wirb/colorizer/wirble.rb +30 -0
- data/lib/wirb/tokenizer.rb +1 -1
- data/lib/wirb/version.rb +1 -1
- data/spec/colorizer_highline_spec.rb +23 -0
- data/spec/colorizer_paint_spec.rb +33 -0
- data/spec/colorizer_spec.rb +67 -0
- data/spec/colorizer_wirb0_highline_spec.rb +78 -0
- data/spec/colorizer_wirb0_paint_spec.rb +35 -0
- data/spec/colorizer_wirb0_spec.rb +11 -0
- data/spec/colorizer_wirble_spec.rb +24 -0
- data/spec/spec_helper.rb +117 -6
- data/wirb.gemspec +6 -4
- metadata +31 -6
- data/lib/wirb/schema.rb +0 -72
@@ -0,0 +1,26 @@
|
|
1
|
+
# Jan:
|
2
|
+
# General philosophical question: Would it be more flexible to have @colorizer point
|
3
|
+
# to an _instance_ of a Colorizer object, rather than a Colorizer class? (And therefore
|
4
|
+
# to have run and color be instance methods of Colorizer, rather than class methods.)
|
5
|
+
# In certain circumstances this could give greater flexibility, for instance to set
|
6
|
+
# colorizer options...
|
7
|
+
|
8
|
+
module Wirb
|
9
|
+
module Colorizer
|
10
|
+
class << self
|
11
|
+
def const_missing(colorizer)
|
12
|
+
path = File.dirname(__FILE__) + '/colorizer/' + colorizer.to_s.downcase
|
13
|
+
|
14
|
+
begin
|
15
|
+
require path
|
16
|
+
rescue LoadError => e
|
17
|
+
raise LoadError, "Could not load colorizer #{colorizer} at #{path}: #{e}"
|
18
|
+
end
|
19
|
+
|
20
|
+
raise LoadError, "Colorizer definition at #{path} does not appear to define #{self}::#{colorizer}" \
|
21
|
+
unless const_defined?(colorizer)
|
22
|
+
const_get colorizer
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'highline'
|
2
|
+
|
3
|
+
module Wirb::Colorizer::HighLine
|
4
|
+
@highline = ::HighLine.new
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def run(string, *color_args)
|
9
|
+
@highline.color(string, *color_args.flatten)
|
10
|
+
end
|
11
|
+
|
12
|
+
def color(*color_args)
|
13
|
+
@highline.color_code(*color_args.flatten)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module Wirb
|
1
|
+
module Wirb::Colorizer::Wirb0
|
2
2
|
COLORS = {
|
3
3
|
:nothing => '0;0',
|
4
4
|
|
@@ -42,6 +42,12 @@ module Wirb
|
|
42
42
|
:cyan_background => '7;36',
|
43
43
|
:white_background => '7;37',
|
44
44
|
}
|
45
|
-
end
|
46
45
|
|
47
|
-
|
46
|
+
def self.run(string, *color_args)
|
47
|
+
color(*color_args) + string.to_s + color(:nothing)
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.color(*color_args)
|
51
|
+
color_args.first && COLORS[color_args.first.to_sym] ? "\e[#{COLORS[color_args.first.to_sym]}m" : ''
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# Colorizer for using HighLine colors with Wirb
|
2
|
+
#
|
3
|
+
# Automatically translates Wirb color to Highline colors:
|
4
|
+
# HighLineConnector.color(s, :brown_underline) #=> calls HighLine.color(s, :yellow, :underline)
|
5
|
+
#
|
6
|
+
# You can mix and match using HighLine color names and Wirb color names. Prefix HighLine color names
|
7
|
+
# with :highline. For instance:
|
8
|
+
#
|
9
|
+
# Wirb.colorizer.run(s, :highline, :yellow) #=> calls HighLine.color(s, :yellow)
|
10
|
+
# Wirb.colorizer.run(s, :yellow) #=> calls HighLine.color(s, :bold, :yellow) because
|
11
|
+
# # Wirb uses :yellow to mean bold yellow
|
12
|
+
|
13
|
+
require 'highline'
|
14
|
+
|
15
|
+
module Wirb::Colorizer::Wirb0_HighLine
|
16
|
+
def self.color(*colors)
|
17
|
+
::HighLine.color_code(*color_name(*colors))
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.run(s, *colors)
|
21
|
+
::HighLine.color(s, *color_name(*colors))
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def self.color_name(*colors)
|
26
|
+
colors = colors.flatten.compact
|
27
|
+
if colors.first == :highline # In this case, colors already use HighLine's names
|
28
|
+
colors[1..-1]
|
29
|
+
else
|
30
|
+
translated_colors = colors.map do |color|
|
31
|
+
color = color.to_s
|
32
|
+
case color
|
33
|
+
when "nothing"
|
34
|
+
color = "clear"
|
35
|
+
when /light_gray/
|
36
|
+
color = color.sub("light_gray", "white")
|
37
|
+
when /dark_gray/
|
38
|
+
color = color.sub("dark_gray", "light_black") # Changed to [:bold, :black] below
|
39
|
+
when /yellow/
|
40
|
+
color = color.sub("yellow", "light_yellow") # Changed to [:bold, :yellow] below
|
41
|
+
when /white/
|
42
|
+
color = color.sub("white", "light_white") # Changed to [:bold, :white] below
|
43
|
+
when /brown/
|
44
|
+
color = color.sub("brown", "yellow")
|
45
|
+
when /purple/
|
46
|
+
color = color.sub("purple", "magenta")
|
47
|
+
end
|
48
|
+
color_set = [color.to_sym]
|
49
|
+
if color_set.first.to_s =~ /^light_(.*)/
|
50
|
+
color_set[0] = $1.to_sym
|
51
|
+
color_set << :bold
|
52
|
+
end
|
53
|
+
case color_set.first.to_s
|
54
|
+
when /(.*)_underline$/
|
55
|
+
color_set[0] = [$1.to_sym]
|
56
|
+
color_set << :underline
|
57
|
+
when /(.*)_background$/
|
58
|
+
color_set[0] = [('on_'+$1).to_sym]
|
59
|
+
end
|
60
|
+
color_set
|
61
|
+
end
|
62
|
+
translated_colors.flatten
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def color_code(*args)
|
67
|
+
self.class.color_code(*args)
|
68
|
+
end
|
69
|
+
|
70
|
+
def color(*args)
|
71
|
+
self.class.color(*args)
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'paint'
|
2
|
+
|
3
|
+
Paint::SHORTCUTS[:wirb] = {
|
4
|
+
:nothing => Paint::NOTHING,
|
5
|
+
|
6
|
+
# light
|
7
|
+
:black => Paint.color(:black),
|
8
|
+
:red => Paint.color(:red),
|
9
|
+
:green => Paint.color(:green),
|
10
|
+
:brown => Paint.color(:yellow),
|
11
|
+
:blue => Paint.color(:blue),
|
12
|
+
:purple => Paint.color(:magenta),
|
13
|
+
:cyan => Paint.color(:cyan),
|
14
|
+
:light_gray => Paint.color(:white),
|
15
|
+
|
16
|
+
# bold
|
17
|
+
:dark_gray => Paint.color(:black, :bold),
|
18
|
+
:light_red => Paint.color(:red, :bold),
|
19
|
+
:light_green => Paint.color(:green, :bold),
|
20
|
+
:yellow => Paint.color(:yellow, :bold),
|
21
|
+
:light_blue => Paint.color(:blue, :bold),
|
22
|
+
:light_purple => Paint.color(:magenta, :bold),
|
23
|
+
:light_cyan => Paint.color(:cyan, :bold),
|
24
|
+
:white => Paint.color(:white, :bold),
|
25
|
+
|
26
|
+
# underline
|
27
|
+
:black_underline => Paint.color(:black, :underline),
|
28
|
+
:red_underline => Paint.color(:red, :underline),
|
29
|
+
:green_underline => Paint.color(:green, :underline),
|
30
|
+
:brown_underline => Paint.color(:yellow, :underline),
|
31
|
+
:blue_underline => Paint.color(:blue, :underline),
|
32
|
+
:purple_underline => Paint.color(:magenta, :underline),
|
33
|
+
:cyan_underline => Paint.color(:cyan, :underline),
|
34
|
+
:white_underline => Paint.color(:white, :underline),
|
35
|
+
|
36
|
+
# background
|
37
|
+
:black_background => Paint.color(nil, :black), # first color passed is foreground, second one is background
|
38
|
+
:red_background => Paint.color(nil, :red),
|
39
|
+
:green_background => Paint.color(nil, :green),
|
40
|
+
:brown_background => Paint.color(nil, :yellow),
|
41
|
+
:blue_background => Paint.color(nil, :blue),
|
42
|
+
:purple_background => Paint.color(nil, :magenta),
|
43
|
+
:cyan_background => Paint.color(nil, :cyan),
|
44
|
+
:white_background => Paint.color(nil, :white),
|
45
|
+
}
|
46
|
+
|
47
|
+
module Wirb::Colorizer::Wirb0_Paint
|
48
|
+
def self.run(string, *color_args)
|
49
|
+
if color_args.first && color_args.size == 1 && color_args.first.is_a?(Symbol)
|
50
|
+
if color_args.first == :paint # force usage of paint colors
|
51
|
+
Paint[string, *color_args[1..-1]]
|
52
|
+
else
|
53
|
+
Paint::Wirb.send(color_args.first, string)
|
54
|
+
end
|
55
|
+
else
|
56
|
+
Paint[string, *color_args]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.color(*color_args)
|
61
|
+
if color_args.first && color_args.size == 1 && color_args.first.is_a?(Symbol)
|
62
|
+
if color_args.first == :paint # force usage of paint colors
|
63
|
+
Paint[string, *color_args[1..-1]]
|
64
|
+
else
|
65
|
+
Paint::Wirb.send(color_args.first)
|
66
|
+
end
|
67
|
+
else
|
68
|
+
Paint.color(*color_args)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Wirb::Colorizer::Wirble
|
2
|
+
COLORS = {
|
3
|
+
:nothing => '0;0',
|
4
|
+
:black => '0;30',
|
5
|
+
:red => '0;31',
|
6
|
+
:green => '0;32',
|
7
|
+
:brown => '0;33',
|
8
|
+
:blue => '0;34',
|
9
|
+
:cyan => '0;36',
|
10
|
+
:purple => '0;35',
|
11
|
+
:light_gray => '0;37',
|
12
|
+
:dark_gray => '1;30',
|
13
|
+
:light_red => '1;31',
|
14
|
+
:light_green => '1;32',
|
15
|
+
:yellow => '1;33',
|
16
|
+
:light_blue => '1;34',
|
17
|
+
:light_cyan => '1;36',
|
18
|
+
:light_purple => '1;35',
|
19
|
+
:white => '1;37',
|
20
|
+
}
|
21
|
+
|
22
|
+
|
23
|
+
def self.run(string, *color_args)
|
24
|
+
color(*color_args) + string.to_s + color(:nothing)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.color(*color_args)
|
28
|
+
color_args.first && COLORS[color_args.first.to_sym] ? "\e[#{COLORS[color_args.first.to_sym]}m" : ''
|
29
|
+
end
|
30
|
+
end
|
data/lib/wirb/tokenizer.rb
CHANGED
data/lib/wirb/version.rb
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
begin # only test if highline is available
|
2
|
+
require 'highline'
|
3
|
+
|
4
|
+
describe Wirb::Colorizer::HighLine do
|
5
|
+
before :each do
|
6
|
+
Wirb.colorizer = Wirb::Colorizer::HighLine
|
7
|
+
end
|
8
|
+
|
9
|
+
it "creates good color codes based on Highline color symbols" do
|
10
|
+
Wirb.get_color(:reverse, :underline, :magenta).should match_colors(4,7,35)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "colorizes strings based on Highline color symbols" do
|
14
|
+
Wirb.colorize_string('Dantooine', :blink, :on_red).should match_colored_string('Dantooine', 5,41)
|
15
|
+
end
|
16
|
+
|
17
|
+
after :each do
|
18
|
+
Wirb.colorizer = nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
rescue LoadError
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
begin # only test if paint is available
|
2
|
+
require 'paint'
|
3
|
+
|
4
|
+
describe Wirb::Colorizer::Paint do
|
5
|
+
before :each do
|
6
|
+
Wirb.colorizer = Wirb::Colorizer::Paint
|
7
|
+
end
|
8
|
+
|
9
|
+
it "creates good color codes based on Paint color symbols" do
|
10
|
+
Wirb.get_color(:red).should match_colors(31)
|
11
|
+
Wirb.get_color(:red, :bright).should match_colors(1,31)
|
12
|
+
Wirb.get_color(:bright, :red).should match_colors(1,31)
|
13
|
+
Wirb.get_color(:red, :bright, :underline).should match_colors(1,4,31)
|
14
|
+
Wirb.get_color(:red, :blue).should match_colors(31,44)
|
15
|
+
Wirb.get_color(nil, :blue).should match_colors(44)
|
16
|
+
Wirb.get_color([43,86,129]).should match_colors('38;5;'+(16 + 1*36 + 2*6 + 3*1).to_s)
|
17
|
+
Wirb.get_color("medium sea green").should match_colors('38;5;78')
|
18
|
+
Wirb.get_color("#81562b").should match_colors('38;5;' + (16 + 3*36 + 2*6 + 1*1).to_s)
|
19
|
+
Wirb.get_color("#863").should match_colors('38;5;' + (16 + 3*36 + 2*6 + 1*1).to_s)
|
20
|
+
Wirb.get_color(:red, :encircle).should match_colors(52,31)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "colorizes strings based on Paint color symbols" do
|
24
|
+
Wirb.colorize_string('Dantooine', :red, :bright, :underline).should match_colored_string('Dantooine', 1,4,31)
|
25
|
+
end
|
26
|
+
|
27
|
+
after :each do
|
28
|
+
Wirb.colorizer = nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
rescue LoadError
|
33
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
describe "Colorizer interface" do
|
2
|
+
before(:each) { Wirb.colorizer = @colorizer = double() }
|
3
|
+
|
4
|
+
it "invokes Colorizer.color to get color codes" do
|
5
|
+
@colorizer.should_receive(:color).with(:c3po)
|
6
|
+
wirb = Wirb.get_color(:c3po)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "invokes Colorizer.run to colorize strings" do
|
10
|
+
@colorizer.should_receive(:run).with('chewbacca', 'r2d2')
|
11
|
+
wirb = Wirb.colorize_string('chewbacca', 'r2d2')
|
12
|
+
end
|
13
|
+
|
14
|
+
after(:each) {Wirb.colorizer = nil}
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "Colorizer loading" do
|
18
|
+
before(:each) {Wirb.colorizer = nil}
|
19
|
+
|
20
|
+
it "defaults to using the Wirb0 colorizer" do
|
21
|
+
Wirb.colorizer = nil
|
22
|
+
Wirb.instance_variable_get(:@colorizer).should be_nil
|
23
|
+
foo = Wirb.colorizer # Force a colorizer to be loaded
|
24
|
+
Wirb.colorizer.should == Wirb::Colorizer::Wirb0
|
25
|
+
end
|
26
|
+
|
27
|
+
it "attempts to load the appropriate colorizer" do
|
28
|
+
Wirb.colorizer = nil
|
29
|
+
Wirb.instance_variable_get(:@colorizer).should be_nil
|
30
|
+
Wirb::Colorizer.should_receive(:require).
|
31
|
+
with(File.dirname(File.dirname(__FILE__)) + '/lib/wirb/colorizer/notloaded').
|
32
|
+
and_return(true)
|
33
|
+
expect {
|
34
|
+
Wirb.colorizer = Wirb::Colorizer::NotLoaded
|
35
|
+
}.to raise_error(LoadError) # Because the Colorizer doesn't actually exist, wasn't loaded
|
36
|
+
# and didn't define Wirb::Colorizer::NotLoaded
|
37
|
+
end
|
38
|
+
|
39
|
+
it "fails if the colorizer is not found" do
|
40
|
+
expect {
|
41
|
+
Wirb.colorizer = Wirb::Colorizer::DoesntExist
|
42
|
+
}.to raise_error(LoadError)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "fails if the colorizer definition doesn't define the colorizer class" do
|
46
|
+
Wirb::Colorizer.should_receive(:require).
|
47
|
+
with(File.dirname(File.dirname(__FILE__)) + '/lib/wirb/colorizer/badcolorizer').
|
48
|
+
and_return(true)
|
49
|
+
expect {
|
50
|
+
Wirb.colorizer = Wirb::Colorizer::BadColorizer
|
51
|
+
}.to raise_error(LoadError)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "sets the Colorizer object" do
|
55
|
+
Wirb.colorizer = nil
|
56
|
+
Wirb.instance_variable_get(:@colorizer).should be_nil
|
57
|
+
Wirb.colorizer = Wirb::Colorizer::Wirble
|
58
|
+
Wirb::Colorizer.const_defined?(:Wirble).should be_true
|
59
|
+
Wirb.colorizer.should == Wirb::Colorizer::Wirble
|
60
|
+
end
|
61
|
+
|
62
|
+
it "doesn't load Colorizers until they are referenced" do
|
63
|
+
# Can't figure out how to test for this, actually
|
64
|
+
end
|
65
|
+
|
66
|
+
after(:each) {Wirb.colorizer = nil}
|
67
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
begin # only test if highline is available
|
2
|
+
require 'highline'
|
3
|
+
|
4
|
+
describe Wirb::Colorizer::Wirb0_HighLine do
|
5
|
+
before :each do
|
6
|
+
Wirb.colorizer = Wirb::Colorizer::Wirb0_HighLine
|
7
|
+
end
|
8
|
+
|
9
|
+
it "creates good color codes based on Highline color symbols" do
|
10
|
+
Wirb.get_color(:highline, :reverse, :underline, :magenta).should == "\e[7m\e[4m\e[35m"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "colorizes strings based on Highline color symbols" do
|
14
|
+
Wirb.colorize_string('Dantooine', :highline, :blink, :on_red).should == "\e[5m\e[41mDantooine\e[0m"
|
15
|
+
end
|
16
|
+
|
17
|
+
it_behaves_like "a Wirb0 colorizer"
|
18
|
+
|
19
|
+
context "when using basic color names" do
|
20
|
+
it "understands the differences between HighLine and Wirb0" do
|
21
|
+
Wirb.get_color(:nothing).should match_colors(0) # Wirb0 calls this nothing
|
22
|
+
Wirb.get_color(:highline, :clear).should match_colors(0) # HighLine calls it clear
|
23
|
+
|
24
|
+
Wirb.get_color(:brown).should match_colors(0,33) # Wirb0 calls this brown
|
25
|
+
Wirb.get_color(:highline, :yellow).should match_colors(0,33) # HighLine calls it yellow
|
26
|
+
|
27
|
+
Wirb.get_color(:purple).should match_colors(0,35) # Wirb0 calls this purple
|
28
|
+
Wirb.get_color(:highline, :magenta).should match_colors(0,35) # HighLine calls it magenta
|
29
|
+
|
30
|
+
Wirb.get_color(:light_gray).should match_colors(0,37) # Wirb0 calls this light_gray
|
31
|
+
Wirb.get_color(:highline, :white).should match_colors(0,37) # HighLine calls it white
|
32
|
+
|
33
|
+
Wirb.get_color(:light_black).should match_colors(1,30) # Wirb0 calls this light_black
|
34
|
+
Wirb.get_color(:highline, :bold, :black).should match_colors(1,30) # HighLine calls it bold black
|
35
|
+
|
36
|
+
Wirb.get_color(:yellow).should match_colors(1,33) # Wirb0 calls this yellow
|
37
|
+
Wirb.get_color(:highline, :bold, :yellow).should match_colors(1,33) # HighLine calls it bold yellow
|
38
|
+
|
39
|
+
Wirb.get_color(:white).should match_colors(1,37) # Wirb0 calls this white
|
40
|
+
Wirb.get_color(:highline, :bold, :white).should match_colors(1,37) # HighLine calls it bold white
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when using light/bold colors" do
|
45
|
+
it "understands the differences between HighLine and Wirb0" do
|
46
|
+
Wirb.get_color(:light_purple).should match_colors(1,35) # Wirb0 says :light_<color>
|
47
|
+
Wirb.get_color(:highline, :magenta, :bold).should match_colors(1,35) # HighLine says :bold, :<color>
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when using underlined colors" do
|
52
|
+
it "understands the differences between HighLine and Wirb0" do
|
53
|
+
Wirb.get_color(:light_gray_underline).should match_colors(4,37) # Wirb0 says :<color>_underline
|
54
|
+
Wirb.get_color(:highline, :underline, :white).should match_colors(4,37) # HighLine says :underline, :<color>
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "when using background colors" do
|
59
|
+
it "understands the differences between HighLine and Wirb0" do
|
60
|
+
Wirb.get_color(:brown_background).should match_colors(43) # Wirb0 says :<color>_background
|
61
|
+
Wirb.get_color(:highline, :on_yellow).should match_colors(43) # HighLine says :on_<color>
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when encoding strings" do
|
66
|
+
it "understands the differences between HighLine and Wirb0" do
|
67
|
+
Wirb.colorize_string('Alderaan', :purple).should match_colored_string('Alderaan', 35) # Wirb0 calls this purple
|
68
|
+
Wirb.colorize_string('Alderaan', :highline, :magenta).should match_colored_string('Alderaan', 35) # HighLine calls it magenta
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
after :each do
|
73
|
+
Wirb.colorizer = nil
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
rescue LoadError
|
78
|
+
end
|