ffi-rzmq 0.8.0 → 0.8.2
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/AUTHORS.txt +18 -0
- data/History.txt +14 -0
- data/README.rdoc +3 -5
- data/ffi-rzmq.gemspec +2 -2
- data/lib/ffi-rzmq/exceptions.rb +1 -1
- data/lib/ffi-rzmq/message.rb +0 -1
- data/lib/ffi-rzmq/poll.rb +3 -0
- data/lib/ffi-rzmq/socket.rb +40 -7
- data/lib/ffi-rzmq/wrapper.rb +4 -6
- data/lib/ffi-rzmq/zmq.rb +3 -4
- data/spec/device_spec.rb +1 -0
- data/spec/socket_spec.rb +6 -0
- data/version.txt +1 -1
- metadata +63 -77
data/AUTHORS.txt
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Chuck Remes, github: chuckremes
|
2
|
+
|
3
|
+
Andrew Cholakian, github: andrewvc
|
4
|
+
|
5
|
+
Ar Vicco, github: arvicco
|
6
|
+
|
7
|
+
Ben Mabey, github: bmabey
|
8
|
+
|
9
|
+
Julien Ammous, github: schmurfy
|
10
|
+
|
11
|
+
Zachary Belzer, github: zbelzer
|
12
|
+
|
13
|
+
Cory Forsyth, github: bantic
|
14
|
+
|
15
|
+
Stefan Kaes, github: skaes
|
16
|
+
|
17
|
+
Dmitry Ustalov, github: eveel
|
18
|
+
|
data/History.txt
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
== 0.8.2 / 20110728
|
2
|
+
* Fixed major bug with Socket#setsockopt when writing 8-byte longs.
|
3
|
+
|
4
|
+
* Clarified a bit of logic for non-blocking sends.
|
5
|
+
|
6
|
+
* Improved readability of exceptions.
|
7
|
+
|
8
|
+
== 0.8.1 / 20110504
|
9
|
+
* Fixed bug where Socket#setsockopt was using a size from the current
|
10
|
+
runtime to determine how many bytes to use for HWM, et al. This was
|
11
|
+
incorrect. All of those socket options require 8 bytes. Discovered
|
12
|
+
this while getting the code running under mingw on Windows using a
|
13
|
+
32-bit Ruby runtime.
|
14
|
+
|
1
15
|
== 0.8.0 / 20110307
|
2
16
|
* API change!
|
3
17
|
Socket#send_message no longer automatically calls
|
data/README.rdoc
CHANGED
@@ -32,11 +32,7 @@ The 'ffi' gem has dropped support for MRI 1.8.x. Since this project relies
|
|
32
32
|
on that gem to load and run this code, then this project also no longer
|
33
33
|
supports MRI 1.8.x.
|
34
34
|
|
35
|
-
All features are implemented
|
36
|
-
(forwarder, queue, streamer). For implementations of these devices, see
|
37
|
-
the 0mq Ruby reactor project:
|
38
|
-
|
39
|
-
http://github.com/chuckremes/zmqmachine
|
35
|
+
All features are implemented.
|
40
36
|
|
41
37
|
== SYNOPSIS:
|
42
38
|
|
@@ -111,6 +107,8 @@ I highly recommend visiting the Learn Ruby 0mq project for a bunch of good code
|
|
111
107
|
The ZeroMQ library must be installed on your system in a well-known location
|
112
108
|
like /usr/local/lib. This is the default for new ZeroMQ installs.
|
113
109
|
|
110
|
+
If you have installed ZeroMQ using brew, you need to `brew link zeromq` before installing this gem.
|
111
|
+
|
114
112
|
Future releases may include the library as a C extension built at
|
115
113
|
time of installation.
|
116
114
|
|
data/ffi-rzmq.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{ffi-rzmq}
|
5
|
-
s.version = "0.8.
|
5
|
+
s.version = "0.8.2"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Chuck Remes"]
|
@@ -12,7 +12,7 @@ function interface). It's a pure ruby wrapper so this gem can be loaded
|
|
12
12
|
and run by any ruby runtime that supports FFI. That's all of them:
|
13
13
|
MRI 1.9.x, Rubinius and JRuby.}
|
14
14
|
s.email = %q{cremes@mac.com}
|
15
|
-
s.extra_rdoc_files = ["History.txt", "README.rdoc", "examples/README.rdoc", "version.txt"]
|
15
|
+
s.extra_rdoc_files = ["AUTHORS.txt", "History.txt", "README.rdoc", "examples/README.rdoc", "version.txt"]
|
16
16
|
s.files = [".bnsignore", "History.txt", "README.rdoc", "Rakefile", "examples/README.rdoc", "examples/local_lat.rb", "examples/local_lat_poll.rb", "examples/local_lat_zerocopy.rb", "examples/local_throughput.rb", "examples/publish_subscribe.rb", "examples/remote_lat.rb", "examples/remote_lat_zerocopy.rb", "examples/remote_throughput.rb", "examples/reqrep_poll.rb", "examples/request_response.rb", "ffi-rzmq.gemspec", "lib/ffi-rzmq.rb", "lib/ffi-rzmq/context.rb", "lib/ffi-rzmq/device.rb", "lib/ffi-rzmq/exceptions.rb", "lib/ffi-rzmq/message.rb", "lib/ffi-rzmq/poll.rb", "lib/ffi-rzmq/poll_items.rb", "lib/ffi-rzmq/socket.rb", "lib/ffi-rzmq/wrapper.rb", "lib/ffi-rzmq/zmq.rb", "spec/context_spec.rb", "spec/device_spec.rb", "spec/message_spec.rb", "spec/pushpull_spec.rb", "spec/reqrep_spec.rb", "spec/socket_spec.rb", "spec/spec_helper.rb", "version.txt"]
|
17
17
|
s.homepage = %q{http://github.com/chuckremes/ffi-rzmq}
|
18
18
|
s.rdoc_options = ["--main", "README.rdoc"]
|
data/lib/ffi-rzmq/exceptions.rb
CHANGED
data/lib/ffi-rzmq/message.rb
CHANGED
data/lib/ffi-rzmq/poll.rb
CHANGED
@@ -142,6 +142,9 @@ module ZMQ
|
|
142
142
|
# end
|
143
143
|
def delete sock
|
144
144
|
removed = false
|
145
|
+
deregister_readable sock
|
146
|
+
deregister_writable sock
|
147
|
+
|
145
148
|
size = @sockets.size
|
146
149
|
@sockets.delete_if { |socket| socket.socket.address == sock.socket.address }
|
147
150
|
socket_deleted = size != @sockets.size
|
data/lib/ffi-rzmq/socket.rb
CHANGED
@@ -84,13 +84,13 @@ module ZMQ
|
|
84
84
|
#
|
85
85
|
def setsockopt option_name, option_value, option_len = nil
|
86
86
|
option_value = sanitize_value option_name, option_value
|
87
|
-
option_len ||= option_value.size
|
88
87
|
|
89
88
|
begin
|
90
89
|
case option_name
|
91
90
|
when HWM, SWAP, AFFINITY, RATE, RECOVERY_IVL, MCAST_LOOP, SNDBUF, RCVBUF, RECOVERY_IVL_MSEC
|
91
|
+
option_len = 8 # all of these options are defined as int64_t or uint64_t
|
92
92
|
option_value_ptr = LibC.malloc option_len
|
93
|
-
option_value_ptr.
|
93
|
+
option_value_ptr.write_long_long option_value
|
94
94
|
|
95
95
|
when LINGER, RECONNECT_IVL, BACKLOG
|
96
96
|
option_len = 4 # hard-code "int" length to 4 bytes
|
@@ -98,6 +98,8 @@ module ZMQ
|
|
98
98
|
option_value_ptr.write_int option_value
|
99
99
|
|
100
100
|
when IDENTITY, SUBSCRIBE, UNSUBSCRIBE
|
101
|
+
option_len ||= option_value.size
|
102
|
+
|
101
103
|
# note: not checking errno for failed memory allocations :(
|
102
104
|
option_value_ptr = LibC.malloc option_len
|
103
105
|
option_value_ptr.write_string option_value
|
@@ -147,7 +149,7 @@ module ZMQ
|
|
147
149
|
option_length = FFI::MemoryPointer.new(:size_t) rescue FFI::MemoryPointer.new(:ulong)
|
148
150
|
|
149
151
|
unless [
|
150
|
-
RCVMORE, HWM, SWAP, AFFINITY, RATE, RECOVERY_IVL, MCAST_LOOP, IDENTITY,
|
152
|
+
TYPE, RCVMORE, HWM, SWAP, AFFINITY, RATE, RECOVERY_IVL, MCAST_LOOP, IDENTITY,
|
151
153
|
SNDBUF, RCVBUF, FD, EVENTS, LINGER, RECONNECT_IVL, BACKLOG, RECOVERY_IVL_MSEC
|
152
154
|
].include? option_name
|
153
155
|
# we didn't understand the passed option argument
|
@@ -167,7 +169,7 @@ module ZMQ
|
|
167
169
|
ret = option_value.read_long_long != 0
|
168
170
|
when HWM, SWAP, AFFINITY, RATE, RECOVERY_IVL, SNDBUF, RCVBUF, RECOVERY_IVL_MSEC
|
169
171
|
ret = option_value.read_long_long
|
170
|
-
when LINGER, RECONNECT_IVL, BACKLOG, FD, EVENTS
|
172
|
+
when TYPE, LINGER, RECONNECT_IVL, BACKLOG, FD, EVENTS
|
171
173
|
ret = option_value.read_int
|
172
174
|
when IDENTITY
|
173
175
|
ret = option_value.read_string(option_length.read_long_long)
|
@@ -257,7 +259,7 @@ module ZMQ
|
|
257
259
|
|
258
260
|
# when the flag isn't set, do a normal error check
|
259
261
|
# when set, check to see if the message was successfully queued
|
260
|
-
queued = flags
|
262
|
+
queued = noblock?(flags) ? error_check_nonblock(result_code) : error_check(ZMQ_SEND_STR, result_code)
|
261
263
|
end
|
262
264
|
|
263
265
|
# true if sent, false if failed/EAGAIN
|
@@ -280,7 +282,25 @@ module ZMQ
|
|
280
282
|
|
281
283
|
result_code
|
282
284
|
end
|
283
|
-
|
285
|
+
|
286
|
+
# Send a sequence of strings as a multipart message out of the +parts+
|
287
|
+
# passed in for transmission. Every element of +parts+ should be
|
288
|
+
# a String.
|
289
|
+
#
|
290
|
+
# +flags+ may be ZMQ::NOBLOCK.
|
291
|
+
#
|
292
|
+
# Raises the same exceptions as Socket#send.
|
293
|
+
#
|
294
|
+
def send_strings parts, flags = 0
|
295
|
+
return false if !parts || parts.empty?
|
296
|
+
|
297
|
+
parts[0...-1].each do |part|
|
298
|
+
return false unless send_string part, flags | ZMQ::SNDMORE
|
299
|
+
end
|
300
|
+
|
301
|
+
send_string parts[-1], flags
|
302
|
+
end
|
303
|
+
|
284
304
|
# Sends a message. This will automatically close the +message+ for both successful
|
285
305
|
# and failed sends.
|
286
306
|
#
|
@@ -355,6 +375,19 @@ module ZMQ
|
|
355
375
|
end
|
356
376
|
end
|
357
377
|
|
378
|
+
# Receive a multipart message as a list of strings.
|
379
|
+
#
|
380
|
+
# +flags+ may be ZMQ::NOBLOCK.
|
381
|
+
#
|
382
|
+
# Raises the same exceptions as Socket#recv.
|
383
|
+
#
|
384
|
+
def recv_strings flags = 0
|
385
|
+
parts = []
|
386
|
+
parts << recv_string(flags)
|
387
|
+
parts << recv_string(flags) while more_parts?
|
388
|
+
parts
|
389
|
+
end
|
390
|
+
|
358
391
|
private
|
359
392
|
|
360
393
|
def noblock? flag
|
@@ -385,7 +418,7 @@ module ZMQ
|
|
385
418
|
end
|
386
419
|
@sockopt_cache[:int64]
|
387
420
|
|
388
|
-
when LINGER, RECONNECT_IVL, BACKLOG, FD, EVENTS
|
421
|
+
when TYPE, LINGER, RECONNECT_IVL, BACKLOG, FD, EVENTS
|
389
422
|
# int, 0mq assumes int is 4-bytes
|
390
423
|
unless @sockopt_cache[:int32]
|
391
424
|
length = FFI::MemoryPointer.new :int32
|
data/lib/ffi-rzmq/wrapper.rb
CHANGED
@@ -21,11 +21,9 @@ end # module LibC
|
|
21
21
|
|
22
22
|
module LibZMQ
|
23
23
|
extend FFI::Library
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
ffi_lib(LINUX + OSX + WINDOWS)
|
28
|
-
|
24
|
+
ZMQ_LIB_PATHS = %w{/usr/local/lib /opt/local/lib /usr/local/homebrew/lib}.map{|path| "#{path}/libzmq.#{FFI::Platform::LIBSUFFIX}"}
|
25
|
+
ffi_lib(%w{libzmq} + ZMQ_LIB_PATHS)
|
26
|
+
|
29
27
|
# Size_t not working properly on Windows
|
30
28
|
find_type(:size_t) rescue typedef(:ulong, :size_t)
|
31
29
|
|
@@ -78,7 +76,7 @@ module LibZMQ
|
|
78
76
|
attach_function :zmq_recv, [:pointer, :pointer, :int], :int
|
79
77
|
attach_function :zmq_close, [:pointer], :int
|
80
78
|
|
81
|
-
|
79
|
+
@blocking = true
|
82
80
|
attach_function :zmq_device, [:int, :pointer, :pointer], :int
|
83
81
|
|
84
82
|
# Poll api
|
data/lib/ffi-rzmq/zmq.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
module ZMQ
|
3
2
|
|
4
3
|
# Socket types
|
@@ -7,8 +6,8 @@ module ZMQ
|
|
7
6
|
SUB = 2
|
8
7
|
REQ = 3
|
9
8
|
REP = 4
|
10
|
-
|
11
|
-
|
9
|
+
DEALER = XREQ = 5
|
10
|
+
ROUTER = XREP = 6
|
12
11
|
PULL = UPSTREAM = 7
|
13
12
|
PUSH = DOWNSTREAM = 8
|
14
13
|
|
@@ -176,7 +175,7 @@ module ZMQ
|
|
176
175
|
|
177
176
|
def raise_error source, result_code
|
178
177
|
case source
|
179
|
-
when ZMQ_SEND_STR, ZMQ_RECV_STR, ZMQ_SOCKET_STR, ZMQ_SETSOCKOPT_STR, ZMQ_GETSOCKOPT_STR, ZMQ_BIND_STR, ZMQ_CONNECT_STR
|
178
|
+
when ZMQ_SEND_STR, ZMQ_RECV_STR, ZMQ_SOCKET_STR, ZMQ_SETSOCKOPT_STR, ZMQ_GETSOCKOPT_STR, ZMQ_BIND_STR, ZMQ_CONNECT_STR, ZMQ_CLOSE_STR
|
180
179
|
raise SocketError.new source, result_code, errno, error_string
|
181
180
|
when ZMQ_INIT_STR, ZMQ_TERM_STR
|
182
181
|
raise ContextError.new source, result_code, errno, error_string
|
data/spec/device_spec.rb
CHANGED
data/spec/socket_spec.rb
CHANGED
@@ -391,6 +391,12 @@ module ZMQ
|
|
391
391
|
socket.getsockopt(ZMQ::EVENTS).should be_a(Fixnum)
|
392
392
|
end
|
393
393
|
end
|
394
|
+
|
395
|
+
context "using option ZMQ::TYPE" do
|
396
|
+
it "should return the socket type" do
|
397
|
+
socket.getsockopt(ZMQ::TYPE).should == socket_type
|
398
|
+
end
|
399
|
+
end
|
394
400
|
end # context #getsockopt
|
395
401
|
|
396
402
|
end # each socket_type
|
data/version.txt
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.8.
|
1
|
+
0.8.2
|
metadata
CHANGED
@@ -1,16 +1,11 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ffi-rzmq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 63
|
5
4
|
prerelease:
|
6
|
-
|
7
|
-
- 0
|
8
|
-
- 8
|
9
|
-
- 0
|
10
|
-
version: 0.8.0
|
5
|
+
version: 0.8.2
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
|
-
- Chuck Remes
|
8
|
+
- Chuck Remes
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
@@ -18,22 +13,17 @@ cert_chain: []
|
|
18
13
|
date: 2011-01-30 00:00:00 -06:00
|
19
14
|
default_executable:
|
20
15
|
dependencies:
|
21
|
-
- !ruby/object:Gem::Dependency
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
- 5
|
33
|
-
- 4
|
34
|
-
version: 3.5.4
|
35
|
-
type: :development
|
36
|
-
version_requirements: *id001
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: bones
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 3.5.4
|
25
|
+
type: :development
|
26
|
+
version_requirements: *id001
|
37
27
|
description: |-
|
38
28
|
This gem wraps the ZeroMQ networking library using the ruby FFI (foreign
|
39
29
|
function interface). It's a pure ruby wrapper so this gem can be loaded
|
@@ -45,77 +35,73 @@ executables: []
|
|
45
35
|
extensions: []
|
46
36
|
|
47
37
|
extra_rdoc_files:
|
48
|
-
-
|
49
|
-
-
|
50
|
-
-
|
51
|
-
-
|
38
|
+
- AUTHORS.txt
|
39
|
+
- History.txt
|
40
|
+
- README.rdoc
|
41
|
+
- examples/README.rdoc
|
42
|
+
- version.txt
|
52
43
|
files:
|
53
|
-
- .bnsignore
|
54
|
-
- History.txt
|
55
|
-
- README.rdoc
|
56
|
-
- Rakefile
|
57
|
-
- examples/README.rdoc
|
58
|
-
- examples/local_lat.rb
|
59
|
-
- examples/local_lat_poll.rb
|
60
|
-
- examples/local_lat_zerocopy.rb
|
61
|
-
- examples/local_throughput.rb
|
62
|
-
- examples/publish_subscribe.rb
|
63
|
-
- examples/remote_lat.rb
|
64
|
-
- examples/remote_lat_zerocopy.rb
|
65
|
-
- examples/remote_throughput.rb
|
66
|
-
- examples/reqrep_poll.rb
|
67
|
-
- examples/request_response.rb
|
68
|
-
- ffi-rzmq.gemspec
|
69
|
-
- lib/ffi-rzmq.rb
|
70
|
-
- lib/ffi-rzmq/context.rb
|
71
|
-
- lib/ffi-rzmq/device.rb
|
72
|
-
- lib/ffi-rzmq/exceptions.rb
|
73
|
-
- lib/ffi-rzmq/message.rb
|
74
|
-
- lib/ffi-rzmq/poll.rb
|
75
|
-
- lib/ffi-rzmq/poll_items.rb
|
76
|
-
- lib/ffi-rzmq/socket.rb
|
77
|
-
- lib/ffi-rzmq/wrapper.rb
|
78
|
-
- lib/ffi-rzmq/zmq.rb
|
79
|
-
- spec/context_spec.rb
|
80
|
-
- spec/device_spec.rb
|
81
|
-
- spec/message_spec.rb
|
82
|
-
- spec/pushpull_spec.rb
|
83
|
-
- spec/reqrep_spec.rb
|
84
|
-
- spec/socket_spec.rb
|
85
|
-
- spec/spec_helper.rb
|
86
|
-
- version.txt
|
44
|
+
- .bnsignore
|
45
|
+
- History.txt
|
46
|
+
- README.rdoc
|
47
|
+
- Rakefile
|
48
|
+
- examples/README.rdoc
|
49
|
+
- examples/local_lat.rb
|
50
|
+
- examples/local_lat_poll.rb
|
51
|
+
- examples/local_lat_zerocopy.rb
|
52
|
+
- examples/local_throughput.rb
|
53
|
+
- examples/publish_subscribe.rb
|
54
|
+
- examples/remote_lat.rb
|
55
|
+
- examples/remote_lat_zerocopy.rb
|
56
|
+
- examples/remote_throughput.rb
|
57
|
+
- examples/reqrep_poll.rb
|
58
|
+
- examples/request_response.rb
|
59
|
+
- ffi-rzmq.gemspec
|
60
|
+
- lib/ffi-rzmq.rb
|
61
|
+
- lib/ffi-rzmq/context.rb
|
62
|
+
- lib/ffi-rzmq/device.rb
|
63
|
+
- lib/ffi-rzmq/exceptions.rb
|
64
|
+
- lib/ffi-rzmq/message.rb
|
65
|
+
- lib/ffi-rzmq/poll.rb
|
66
|
+
- lib/ffi-rzmq/poll_items.rb
|
67
|
+
- lib/ffi-rzmq/socket.rb
|
68
|
+
- lib/ffi-rzmq/wrapper.rb
|
69
|
+
- lib/ffi-rzmq/zmq.rb
|
70
|
+
- spec/context_spec.rb
|
71
|
+
- spec/device_spec.rb
|
72
|
+
- spec/message_spec.rb
|
73
|
+
- spec/pushpull_spec.rb
|
74
|
+
- spec/reqrep_spec.rb
|
75
|
+
- spec/socket_spec.rb
|
76
|
+
- spec/spec_helper.rb
|
77
|
+
- version.txt
|
78
|
+
- AUTHORS.txt
|
87
79
|
has_rdoc: true
|
88
80
|
homepage: http://github.com/chuckremes/ffi-rzmq
|
89
81
|
licenses: []
|
90
82
|
|
91
83
|
post_install_message:
|
92
84
|
rdoc_options:
|
93
|
-
- --main
|
94
|
-
- README.rdoc
|
85
|
+
- --main
|
86
|
+
- README.rdoc
|
95
87
|
require_paths:
|
96
|
-
- lib
|
88
|
+
- lib
|
97
89
|
required_ruby_version: !ruby/object:Gem::Requirement
|
98
90
|
none: false
|
99
91
|
requirements:
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
segments:
|
104
|
-
- 0
|
105
|
-
version: "0"
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: "0"
|
106
95
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
96
|
none: false
|
108
97
|
requirements:
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
segments:
|
113
|
-
- 0
|
114
|
-
version: "0"
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: "0"
|
115
101
|
requirements: []
|
116
102
|
|
117
103
|
rubyforge_project: ffi-rzmq
|
118
|
-
rubygems_version: 1.5.
|
104
|
+
rubygems_version: 1.5.1
|
119
105
|
signing_key:
|
120
106
|
specification_version: 3
|
121
107
|
summary: This gem wraps the ZeroMQ networking library using the ruby FFI (foreign function interface).
|