stomp 1.4.4 → 1.4.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +13 -0
- data/README.md +96 -100
- data/examples/EXAMPLES.md +251 -0
- data/examples/amqdurasub.rb +14 -17
- data/examples/artemis/cliwaiter_not_reliable.rb +12 -5
- data/examples/artemis/{cliwaiter_reliable.rb → cliwaiter_reliable_hb.rb} +24 -23
- data/examples/client_conndisc.rb +66 -0
- data/examples/client_putget.rb +94 -0
- data/examples/conn_conndisc.rb +102 -0
- data/examples/conn_putget.rb +124 -0
- data/examples/contrib.sh +2 -3
- data/examples/contributors.rb +26 -14
- data/examples/examplogger.rb +1 -1
- data/examples/{consumer.rb → historical/consumer.rb} +0 -0
- data/examples/{publisher.rb → historical/publisher.rb} +0 -0
- data/examples/{topic_consumer.rb → historical/topic_consumer.rb} +0 -0
- data/examples/{topic_publisher.rb → historical/topic_publisher.rb} +0 -0
- data/examples/logexamp.rb +23 -14
- data/examples/putget_file.rb +79 -0
- data/examples/{putget11_rh1.rb → putget_rephdrs.rb} +16 -15
- data/examples/ssl/SSL.md +189 -0
- data/examples/{ssl_ctxoptions.rb → ssl/misc/ssl_ctxoptions.rb} +23 -14
- data/examples/ssl/misc/ssl_newparm.rb +53 -0
- data/examples/ssl/misc/ssl_ucx_default_ciphers.rb +54 -0
- data/examples/ssl/ssl_common.rb +96 -0
- data/examples/ssl/sslexall.sh +17 -0
- data/examples/{ssl_uc1.rb → ssl/uc1/ssl_uc1.rb} +15 -11
- data/examples/ssl/uc1/ssl_uc1_ciphers.rb +60 -0
- data/examples/{ssl_uc2.rb → ssl/uc2/ssl_uc2.rb} +17 -10
- data/examples/ssl/uc2/ssl_uc2_ciphers.rb +67 -0
- data/examples/{ssl_uc3.rb → ssl/uc3/ssl_uc3.rb} +15 -16
- data/examples/ssl/uc3/ssl_uc3_ciphers.rb +65 -0
- data/examples/{ssl_uc4.rb → ssl/uc4/ssl_uc4.rb} +15 -15
- data/examples/ssl/uc4/ssl_uc4_ciphers.rb +66 -0
- data/examples/stomp_common.rb +97 -0
- data/lib/connection/netio.rb +83 -37
- data/lib/connection/utf8.rb +0 -7
- data/lib/connection/utils.rb +4 -1
- data/lib/stomp/client.rb +5 -1
- data/lib/stomp/connection.rb +25 -15
- data/lib/stomp/constants.rb +109 -0
- data/lib/stomp/errors.rb +11 -0
- data/lib/stomp/sslparams.rb +3 -4
- data/lib/stomp/version.rb +2 -2
- data/stomp.gemspec +31 -37
- data/test/test_anonymous.rb +4 -0
- data/test/test_client.rb +2 -0
- data/test/test_connection.rb +4 -0
- data/test/test_connection1p.rb +2 -4
- data/test/test_helper.rb +11 -0
- metadata +30 -36
- data/examples/artemis/artlogger.rb +0 -41
- data/examples/client11_ex1.rb +0 -89
- data/examples/client11_putget1.rb +0 -71
- data/examples/conn11_ex1.rb +0 -112
- data/examples/conn11_ex2.rb +0 -87
- data/examples/conn11_hb1.rb +0 -57
- data/examples/consume_file.rb +0 -63
- data/examples/get11conn_ex1.rb +0 -117
- data/examples/get11conn_ex2.rb +0 -77
- data/examples/lflogger.rb +0 -316
- data/examples/logexamp_ssl.rb +0 -81
- data/examples/publish_file.rb +0 -76
- data/examples/publish_file_conn.rb +0 -75
- data/examples/put11conn_ex1.rb +0 -56
- data/examples/ssl_common.rb +0 -73
- data/examples/ssl_newparm.rb +0 -43
- data/examples/ssl_uc1_ciphers.rb +0 -53
- data/examples/ssl_uc2_ciphers.rb +0 -60
- data/examples/ssl_uc3_ciphers.rb +0 -64
- data/examples/ssl_uc4_ciphers.rb +0 -65
- data/examples/ssl_ucx_default_ciphers.rb +0 -41
- data/examples/stomp11_common.rb +0 -54
@@ -0,0 +1,66 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
#
|
4
|
+
# The current require dance for different Ruby versions.
|
5
|
+
# Change this to suit your requirements.
|
6
|
+
#
|
7
|
+
if Kernel.respond_to?(:require_relative)
|
8
|
+
require_relative("./stomp_common")
|
9
|
+
else
|
10
|
+
$LOAD_PATH << File.dirname(__FILE__)
|
11
|
+
require "stomp_common"
|
12
|
+
end
|
13
|
+
include Stomp1xCommon
|
14
|
+
|
15
|
+
#
|
16
|
+
# == Stomp Client Example
|
17
|
+
#
|
18
|
+
# Purpose: to demonstrate a connect and disconnect sequence using Stomp 1.x
|
19
|
+
# with the Stomp#Client interface.
|
20
|
+
#
|
21
|
+
class Client1xExample
|
22
|
+
# Initialize.
|
23
|
+
def initialize
|
24
|
+
end
|
25
|
+
# Run example.
|
26
|
+
def run
|
27
|
+
#
|
28
|
+
# Get a client
|
29
|
+
# ============
|
30
|
+
#
|
31
|
+
client = get_client()
|
32
|
+
#
|
33
|
+
# Let's just do some sanity checks, and look around.
|
34
|
+
#
|
35
|
+
raise "Connection failed!!" unless client.open?()
|
36
|
+
#
|
37
|
+
# The broker _could_ have returned an ERROR frame (unlikely).
|
38
|
+
#
|
39
|
+
raise "Connect error: #{client.connection_frame().body}" if client.connection_frame().command == Stomp::CMD_ERROR
|
40
|
+
#
|
41
|
+
puts "Client Connect complete"
|
42
|
+
#
|
43
|
+
# Show protocol level.
|
44
|
+
#
|
45
|
+
puts "Negotiated Protocol Level: #{client.protocol()}"
|
46
|
+
#
|
47
|
+
# Examine the CONNECT response (the connection_frame).
|
48
|
+
#
|
49
|
+
puts "\nActual Connected Headers depend on broker and protocol level:"
|
50
|
+
puts "Connect version - #{client.connection_frame().headers['version']}"
|
51
|
+
puts "Connect server - #{client.connection_frame().headers['server']}"
|
52
|
+
puts "Session ID - #{client.connection_frame().headers['session']}"
|
53
|
+
puts "Server requested heartbeats - #{client.connection_frame().headers['heart-beat']}"
|
54
|
+
|
55
|
+
#
|
56
|
+
# Finally close
|
57
|
+
# =============
|
58
|
+
#
|
59
|
+
client.close() # Business as usual
|
60
|
+
puts "\nClient close complete"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
#
|
64
|
+
e = Client1xExample.new
|
65
|
+
e.run
|
66
|
+
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
#
|
4
|
+
# The current require dance for different Ruby versions.
|
5
|
+
# Change this to suit your requirements.
|
6
|
+
#
|
7
|
+
if Kernel.respond_to?(:require_relative)
|
8
|
+
require_relative("./stomp_common")
|
9
|
+
else
|
10
|
+
$LOAD_PATH << File.dirname(__FILE__)
|
11
|
+
require "stomp_common"
|
12
|
+
end
|
13
|
+
include Stomp1xCommon
|
14
|
+
|
15
|
+
#
|
16
|
+
# == Stomp Client Example
|
17
|
+
#
|
18
|
+
# Purpose: to demonstrate using a Stomp 1.x client to put and get messages.
|
19
|
+
#
|
20
|
+
class ClientPutGetExample
|
21
|
+
# Initialize.
|
22
|
+
def initialize
|
23
|
+
end
|
24
|
+
# Run example.
|
25
|
+
def run
|
26
|
+
#
|
27
|
+
# Get a client
|
28
|
+
# ============
|
29
|
+
#
|
30
|
+
client = get_client()
|
31
|
+
#
|
32
|
+
# Let's just do some sanity checks, and look around.
|
33
|
+
#
|
34
|
+
raise "Connection failed!!" unless client.open?()
|
35
|
+
#
|
36
|
+
# The broker _could_ have returned an ERROR frame (unlikely).
|
37
|
+
#
|
38
|
+
raise "Connect error: #{client.connection_frame().body}" if client.connection_frame().command == Stomp::CMD_ERROR
|
39
|
+
#
|
40
|
+
puts "Client Connect complete"
|
41
|
+
#
|
42
|
+
# Get Destination
|
43
|
+
#
|
44
|
+
qname = dest()
|
45
|
+
#
|
46
|
+
# Publish/put messages
|
47
|
+
#
|
48
|
+
puts "Client start puts"
|
49
|
+
nm = nmsgs()
|
50
|
+
1.upto(nm) do |n|
|
51
|
+
data = "message payload: #{n} #{Time.now.to_f}"
|
52
|
+
client.publish(qname, data)
|
53
|
+
puts "Sent: #{data}"
|
54
|
+
end
|
55
|
+
#
|
56
|
+
# Receives
|
57
|
+
#
|
58
|
+
uuid = client.uuid() # uuid for Stomp::Client is a public method
|
59
|
+
done = false # done flag
|
60
|
+
mc = 0 # running message count
|
61
|
+
#
|
62
|
+
# Clients must pass a receive block. This is business as usual, required for 1.0.
|
63
|
+
# For 1.1+, a unique subscription id is required.
|
64
|
+
#
|
65
|
+
puts "\nClient start receives"
|
66
|
+
client.subscribe(qname, {'id' => uuid}) {|m|
|
67
|
+
message = m
|
68
|
+
puts "Received: #{message.body}"
|
69
|
+
mc += 1
|
70
|
+
if mc >= nm
|
71
|
+
done = true
|
72
|
+
Thread::exit
|
73
|
+
end
|
74
|
+
}
|
75
|
+
#
|
76
|
+
# Wait for done flag
|
77
|
+
#
|
78
|
+
sleep 0.1 until done
|
79
|
+
#
|
80
|
+
# And to be polite to the broker, we unsubscribe.
|
81
|
+
#
|
82
|
+
client.unsubscribe(qname, {'id' => uuid})
|
83
|
+
#
|
84
|
+
# Finally close
|
85
|
+
# =============
|
86
|
+
#
|
87
|
+
client.close() # Business as usual
|
88
|
+
puts "\nClient close complete"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
#
|
92
|
+
e = ClientPutGetExample.new
|
93
|
+
e.run
|
94
|
+
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
#
|
4
|
+
# The current require dance for different Ruby versions.
|
5
|
+
# Change this to suit your requirements.
|
6
|
+
#
|
7
|
+
if Kernel.respond_to?(:require_relative)
|
8
|
+
require_relative("./stomp_common")
|
9
|
+
else
|
10
|
+
$LOAD_PATH << File.dirname(__FILE__)
|
11
|
+
require "stomp_common"
|
12
|
+
end
|
13
|
+
include Stomp1xCommon
|
14
|
+
|
15
|
+
#
|
16
|
+
# == Stomp 1.x Connection Example
|
17
|
+
#
|
18
|
+
# Purpose: to demonstrate a connect and disconnect sequence using Stomp 1.x.
|
19
|
+
#
|
20
|
+
# Note: this example assumes that you have at least the 1.2.0 gem release
|
21
|
+
# installed.
|
22
|
+
#
|
23
|
+
# When you:
|
24
|
+
#
|
25
|
+
# * Use a Stomp compliant broker
|
26
|
+
# * Want a Stomp 1.1+ connection and functionality
|
27
|
+
#
|
28
|
+
# then your code *must* specifically request that environment.
|
29
|
+
#
|
30
|
+
# You need to supply all of the normal values expected of course:
|
31
|
+
#
|
32
|
+
# * login - the user name
|
33
|
+
# * passcode - the password
|
34
|
+
# * host - the host to connect to
|
35
|
+
# * port - the port to connect to
|
36
|
+
#
|
37
|
+
# Additionaly you are required to supply the 1.1+ connection data as documented
|
38
|
+
# in the Stomp 1.1+ specifications:
|
39
|
+
#
|
40
|
+
# http://stomp.github.com/stomp-specification-1.0.html
|
41
|
+
# http://stomp.github.com/stomp-specification-1.1.html
|
42
|
+
# http://stomp.github.com/stomp-specification-1.2.html
|
43
|
+
#
|
44
|
+
# You are urged to become familiar with the specs. They are short documents.
|
45
|
+
#
|
46
|
+
# This includes:
|
47
|
+
#
|
48
|
+
# * The Stomp version(s) you wish the broker to consider
|
49
|
+
# * The broker vhost to connect to
|
50
|
+
#
|
51
|
+
# You may optionally specify other 1.1+ data:
|
52
|
+
#
|
53
|
+
# * heartbeat request
|
54
|
+
#
|
55
|
+
# Using the stomp gem, you should specify this data in the "connect_headers" Hash
|
56
|
+
# parameter. This example uses the common get_connection() method to
|
57
|
+
# get a connection.
|
58
|
+
#
|
59
|
+
class Connection1xExample
|
60
|
+
# Initialize
|
61
|
+
def initialize
|
62
|
+
end
|
63
|
+
# Run example
|
64
|
+
def run
|
65
|
+
#
|
66
|
+
# Get a connection
|
67
|
+
# ================
|
68
|
+
#
|
69
|
+
conn = get_connection()
|
70
|
+
#
|
71
|
+
# Let's just do some sanity checks, and look around.
|
72
|
+
#
|
73
|
+
raise "Connection failed!!" unless conn.open?()
|
74
|
+
#
|
75
|
+
# The broker _could_ have returned an ERROR frame (unlikely).
|
76
|
+
#
|
77
|
+
raise "Connect error: #{conn.connection_frame.body}" if conn.connection_frame.command == Stomp::CMD_ERROR
|
78
|
+
#
|
79
|
+
puts "Connection complete."
|
80
|
+
#
|
81
|
+
# Show protocol level.
|
82
|
+
#
|
83
|
+
puts "Negotiated Protocol Level: #{conn.protocol()}"
|
84
|
+
#
|
85
|
+
# Examine the CONNECT response (the connection_frame).
|
86
|
+
#
|
87
|
+
puts "\nActual Connected Headers depend on broker and protocol level:"
|
88
|
+
puts "Connect version - #{conn.connection_frame.headers['version']}"
|
89
|
+
puts "Connect server - #{conn.connection_frame.headers['server']}"
|
90
|
+
puts "Session ID - #{conn.connection_frame.headers['session']}"
|
91
|
+
puts "Server requested heartbeats - #{conn.connection_frame.headers['heart-beat']}"
|
92
|
+
#
|
93
|
+
# Finally disconnect
|
94
|
+
# ==================
|
95
|
+
#
|
96
|
+
conn.disconnect() # Business as usual
|
97
|
+
puts "\nConnection disconnect complete"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
#
|
101
|
+
e = Connection1xExample.new()
|
102
|
+
e.run
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
#
|
4
|
+
# The current require dance for different Ruby versions.
|
5
|
+
# Change this to suit your requirements.
|
6
|
+
#
|
7
|
+
if Kernel.respond_to?(:require_relative)
|
8
|
+
require_relative("./stomp_common")
|
9
|
+
else
|
10
|
+
$LOAD_PATH << File.dirname(__FILE__)
|
11
|
+
require "stomp_common"
|
12
|
+
end
|
13
|
+
include Stomp1xCommon
|
14
|
+
|
15
|
+
#
|
16
|
+
# == Stomp 1.x Putt / Get Example
|
17
|
+
#
|
18
|
+
# Purpose: to demonstrate producing and consuming messages using a
|
19
|
+
# Stomp#Connection instance.
|
20
|
+
#
|
21
|
+
# Note: this example assumes that you have at least the 1.2.0 gem release
|
22
|
+
# installed.
|
23
|
+
#
|
24
|
+
# When you:
|
25
|
+
#
|
26
|
+
# * Use a Stomp compliant broker
|
27
|
+
# * Want a Stomp 1.1+ connection and functionality
|
28
|
+
#
|
29
|
+
# then your code *must* specifically request that environment.
|
30
|
+
#
|
31
|
+
# You need to supply all of the normal values expected of course:
|
32
|
+
#
|
33
|
+
# * login - the user name
|
34
|
+
# * passcode - the password
|
35
|
+
# * host - the host to connect to
|
36
|
+
# * port - the port to connect to
|
37
|
+
#
|
38
|
+
# Additionaly you are required to supply the 1.1+ connection data as documented
|
39
|
+
# in the Stomp 1.1+ specifications:
|
40
|
+
#
|
41
|
+
# http://stomp.github.com/stomp-specification-1.0.html
|
42
|
+
# http://stomp.github.com/stomp-specification-1.1.html
|
43
|
+
# http://stomp.github.com/stomp-specification-1.2.html
|
44
|
+
#
|
45
|
+
# You are urged to become familiar with the specs. They are short documents.
|
46
|
+
#
|
47
|
+
# This includes:
|
48
|
+
#
|
49
|
+
# * The Stomp version(s) you wish the broker to consider
|
50
|
+
# * The broker vhost to connect to
|
51
|
+
#
|
52
|
+
# You may optionally specify other 1.1+ data:
|
53
|
+
#
|
54
|
+
# * heartbeat request
|
55
|
+
#
|
56
|
+
# Using the stomp gem, you should specify this data in the "connect_headers" Hash
|
57
|
+
# parameter. This example uses the common get_connection() method to
|
58
|
+
# get a connection.
|
59
|
+
#
|
60
|
+
class ConnectionPutGetExample
|
61
|
+
# Initialize
|
62
|
+
def initialize
|
63
|
+
end
|
64
|
+
# Run example
|
65
|
+
def run
|
66
|
+
#
|
67
|
+
# Get a connection
|
68
|
+
# ================
|
69
|
+
#
|
70
|
+
conn = get_connection()
|
71
|
+
#
|
72
|
+
# Let's just do some sanity checks, and look around.
|
73
|
+
#
|
74
|
+
raise "Connection failed!!" unless conn.open?()
|
75
|
+
#
|
76
|
+
# The broker _could_ have returned an ERROR frame (unlikely).
|
77
|
+
#
|
78
|
+
raise "Connect error: #{conn.connection_frame.body}" if conn.connection_frame.command == Stomp::CMD_ERROR
|
79
|
+
#
|
80
|
+
puts "Connection complete."
|
81
|
+
#
|
82
|
+
# Get Destination
|
83
|
+
#
|
84
|
+
qname = dest()
|
85
|
+
#
|
86
|
+
# Publish/put messages
|
87
|
+
#
|
88
|
+
puts "\nConnection start puts"
|
89
|
+
nm = nmsgs()
|
90
|
+
1.upto(nm) do |n|
|
91
|
+
data = "message payload: #{n} #{Time.now.to_f}"
|
92
|
+
conn.publish(qname, data)
|
93
|
+
puts "Sent: #{data}"
|
94
|
+
end
|
95
|
+
puts
|
96
|
+
puts "Connection start receives"
|
97
|
+
# Receives
|
98
|
+
#
|
99
|
+
# Subscribe
|
100
|
+
#
|
101
|
+
uuid = conn.uuid() # uuid for Stomp::Connection is a public method
|
102
|
+
conn.subscribe(qname, {'id' => uuid}) # Subscribe
|
103
|
+
#
|
104
|
+
# Run gets
|
105
|
+
#
|
106
|
+
1.upto(nm) do
|
107
|
+
received = conn.receive()
|
108
|
+
puts "Received data: #{received.body}"
|
109
|
+
end
|
110
|
+
#
|
111
|
+
# And be polite, unsubscribe.
|
112
|
+
#
|
113
|
+
conn.unsubscribe(qname, {'id' => uuid})
|
114
|
+
#
|
115
|
+
# Finally disconnect
|
116
|
+
# ==================
|
117
|
+
#
|
118
|
+
conn.disconnect() # Business as usual
|
119
|
+
puts "\nConnection disconnect complete"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
#
|
123
|
+
e = ConnectionPutGetExample.new()
|
124
|
+
e.run
|
data/examples/contrib.sh
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
#!/bin/bash
|
2
2
|
#
|
3
|
-
|
4
|
-
|
3
|
+
git log --all --no-merges --date=short --reverse --pretty | egrep "(^Author|^Date)" | \
|
4
|
+
sed 's/^Author://;s/Date://' | sed 'N;s/\n/ /' | \
|
5
5
|
ruby $HOME/bin/contributors.rb
|
6
|
-
|
data/examples/contributors.rb
CHANGED
@@ -4,14 +4,14 @@ class UserData
|
|
4
4
|
|
5
5
|
public
|
6
6
|
attr_accessor :count
|
7
|
-
attr_reader :ad
|
7
|
+
attr_reader :ad
|
8
8
|
#
|
9
|
-
def initialize(ad = nil
|
10
|
-
@count, @ad
|
9
|
+
def initialize(ad = nil)
|
10
|
+
@count, @ad = 1, ad
|
11
11
|
end
|
12
12
|
#
|
13
13
|
def to_s
|
14
|
-
"UserData: AuthorDate=>#{@ad},
|
14
|
+
"UserData: AuthorDate=>#{@ad}, AuthorDate=>#{@ad}, CommitCount =>#{@count}"
|
15
15
|
end
|
16
16
|
end
|
17
17
|
# tABLE Data
|
@@ -31,26 +31,34 @@ th_e = "</th>\n"
|
|
31
31
|
td_s = "<td style=\"border: 1px solid black;padding-left: 10px;\" >\n"
|
32
32
|
td_e = "</td>\n"
|
33
33
|
#
|
34
|
-
puts ttab_s # table start
|
35
34
|
#
|
36
35
|
userList = {}
|
37
36
|
while s = gets do
|
38
37
|
s.chomp!
|
39
|
-
|
38
|
+
##puts
|
39
|
+
##puts s
|
40
|
+
sa = s.split(" ")
|
41
|
+
## puts sa
|
42
|
+
ad = sa[-1]
|
43
|
+
##puts ad
|
44
|
+
e = sa[-2]
|
45
|
+
##puts e
|
46
|
+
na = sa[0..-3]
|
47
|
+
n = na.join(" ")
|
48
|
+
##puts n
|
49
|
+
#
|
40
50
|
hk = "#{n}|#{e}"
|
51
|
+
##puts hk
|
41
52
|
if userList.has_key?(hk)
|
42
53
|
userList[hk].count += 1
|
54
|
+
##puts "BUMP"
|
43
55
|
else
|
44
|
-
userList[hk] = UserData.new(ad
|
45
|
-
|
46
|
-
|
47
|
-
puts "NE: #{ad}, #{cd}, #{n}, #{e}"
|
48
|
-
end
|
49
|
-
=end
|
50
|
-
end
|
56
|
+
userList[hk] = UserData.new(ad)
|
57
|
+
##puts "ADD"
|
58
|
+
end
|
51
59
|
|
52
60
|
end
|
53
|
-
#
|
61
|
+
puts ttab_s # table start
|
54
62
|
puts trow_s
|
55
63
|
#
|
56
64
|
puts th_s
|
@@ -74,7 +82,11 @@ puts th_e
|
|
74
82
|
puts trow_e
|
75
83
|
#
|
76
84
|
userList.each do |k, v|
|
85
|
+
##puts "K: #{k}"
|
77
86
|
n, e = k.split("|")
|
87
|
+
##puts "N: #{n}"
|
88
|
+
e = "<" + e[1..-2] + ">"
|
89
|
+
##puts "E: #{e}"
|
78
90
|
oc = "(" + sprintf("%04d", v.count) + ")"
|
79
91
|
# puts "# #{v.time} (#{oc}) #{n} #{e}"
|
80
92
|
puts trow_s
|