eventmachine 0.12.6-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. data/.gitignore +13 -0
  2. data/Rakefile +262 -0
  3. data/docs/COPYING +60 -0
  4. data/docs/ChangeLog +211 -0
  5. data/docs/DEFERRABLES +138 -0
  6. data/docs/EPOLL +141 -0
  7. data/docs/GNU +281 -0
  8. data/docs/INSTALL +15 -0
  9. data/docs/KEYBOARD +38 -0
  10. data/docs/LEGAL +25 -0
  11. data/docs/LIGHTWEIGHT_CONCURRENCY +72 -0
  12. data/docs/PURE_RUBY +77 -0
  13. data/docs/README +74 -0
  14. data/docs/RELEASE_NOTES +96 -0
  15. data/docs/SMTP +9 -0
  16. data/docs/SPAWNED_PROCESSES +93 -0
  17. data/docs/TODO +10 -0
  18. data/eventmachine.gemspec +32 -0
  19. data/ext/binder.cpp +126 -0
  20. data/ext/binder.h +48 -0
  21. data/ext/cmain.cpp +586 -0
  22. data/ext/cplusplus.cpp +193 -0
  23. data/ext/ed.cpp +1522 -0
  24. data/ext/ed.h +380 -0
  25. data/ext/em.cpp +1937 -0
  26. data/ext/em.h +186 -0
  27. data/ext/emwin.cpp +300 -0
  28. data/ext/emwin.h +94 -0
  29. data/ext/epoll.cpp +26 -0
  30. data/ext/epoll.h +25 -0
  31. data/ext/eventmachine.h +98 -0
  32. data/ext/eventmachine_cpp.h +95 -0
  33. data/ext/extconf.rb +129 -0
  34. data/ext/fastfilereader/extconf.rb +77 -0
  35. data/ext/fastfilereader/mapper.cpp +214 -0
  36. data/ext/fastfilereader/mapper.h +59 -0
  37. data/ext/fastfilereader/rubymain.cpp +127 -0
  38. data/ext/files.cpp +94 -0
  39. data/ext/files.h +65 -0
  40. data/ext/kb.cpp +82 -0
  41. data/ext/page.cpp +107 -0
  42. data/ext/page.h +51 -0
  43. data/ext/pipe.cpp +351 -0
  44. data/ext/project.h +119 -0
  45. data/ext/rubymain.cpp +847 -0
  46. data/ext/sigs.cpp +89 -0
  47. data/ext/sigs.h +32 -0
  48. data/ext/ssl.cpp +423 -0
  49. data/ext/ssl.h +90 -0
  50. data/java/.classpath +8 -0
  51. data/java/.project +17 -0
  52. data/java/src/com/rubyeventmachine/Application.java +196 -0
  53. data/java/src/com/rubyeventmachine/Connection.java +74 -0
  54. data/java/src/com/rubyeventmachine/ConnectionFactory.java +37 -0
  55. data/java/src/com/rubyeventmachine/DefaultConnectionFactory.java +46 -0
  56. data/java/src/com/rubyeventmachine/EmReactor.java +408 -0
  57. data/java/src/com/rubyeventmachine/EmReactorException.java +40 -0
  58. data/java/src/com/rubyeventmachine/EventableChannel.java +57 -0
  59. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +171 -0
  60. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +244 -0
  61. data/java/src/com/rubyeventmachine/PeriodicTimer.java +38 -0
  62. data/java/src/com/rubyeventmachine/Timer.java +54 -0
  63. data/java/src/com/rubyeventmachine/tests/ApplicationTest.java +108 -0
  64. data/java/src/com/rubyeventmachine/tests/ConnectTest.java +124 -0
  65. data/java/src/com/rubyeventmachine/tests/EMTest.java +80 -0
  66. data/java/src/com/rubyeventmachine/tests/TestDatagrams.java +53 -0
  67. data/java/src/com/rubyeventmachine/tests/TestServers.java +74 -0
  68. data/java/src/com/rubyeventmachine/tests/TestTimers.java +89 -0
  69. data/lib/em/deferrable.rb +208 -0
  70. data/lib/em/eventable.rb +39 -0
  71. data/lib/em/future.rb +62 -0
  72. data/lib/em/messages.rb +66 -0
  73. data/lib/em/processes.rb +113 -0
  74. data/lib/em/spawnable.rb +88 -0
  75. data/lib/em/streamer.rb +112 -0
  76. data/lib/eventmachine.rb +1926 -0
  77. data/lib/eventmachine_version.rb +31 -0
  78. data/lib/evma.rb +32 -0
  79. data/lib/evma/callback.rb +32 -0
  80. data/lib/evma/container.rb +75 -0
  81. data/lib/evma/factory.rb +77 -0
  82. data/lib/evma/protocol.rb +87 -0
  83. data/lib/evma/reactor.rb +48 -0
  84. data/lib/jeventmachine.rb +137 -0
  85. data/lib/pr_eventmachine.rb +1011 -0
  86. data/lib/protocols/buftok.rb +127 -0
  87. data/lib/protocols/header_and_content.rb +129 -0
  88. data/lib/protocols/httpcli2.rb +803 -0
  89. data/lib/protocols/httpclient.rb +270 -0
  90. data/lib/protocols/line_and_text.rb +126 -0
  91. data/lib/protocols/linetext2.rb +161 -0
  92. data/lib/protocols/memcache.rb +293 -0
  93. data/lib/protocols/postgres.rb +261 -0
  94. data/lib/protocols/saslauth.rb +179 -0
  95. data/lib/protocols/smtpclient.rb +308 -0
  96. data/lib/protocols/smtpserver.rb +556 -0
  97. data/lib/protocols/stomp.rb +153 -0
  98. data/lib/protocols/tcptest.rb +57 -0
  99. data/setup.rb +1585 -0
  100. data/tasks/cpp.rake +77 -0
  101. data/tasks/project.rake +78 -0
  102. data/tasks/tests.rake +193 -0
  103. data/tests/test_attach.rb +83 -0
  104. data/tests/test_basic.rb +231 -0
  105. data/tests/test_connection_count.rb +45 -0
  106. data/tests/test_defer.rb +47 -0
  107. data/tests/test_epoll.rb +163 -0
  108. data/tests/test_error_handler.rb +35 -0
  109. data/tests/test_errors.rb +82 -0
  110. data/tests/test_eventables.rb +77 -0
  111. data/tests/test_exc.rb +58 -0
  112. data/tests/test_futures.rb +214 -0
  113. data/tests/test_handler_check.rb +37 -0
  114. data/tests/test_hc.rb +218 -0
  115. data/tests/test_httpclient.rb +215 -0
  116. data/tests/test_httpclient2.rb +155 -0
  117. data/tests/test_kb.rb +61 -0
  118. data/tests/test_ltp.rb +188 -0
  119. data/tests/test_ltp2.rb +320 -0
  120. data/tests/test_next_tick.rb +109 -0
  121. data/tests/test_processes.rb +95 -0
  122. data/tests/test_pure.rb +129 -0
  123. data/tests/test_running.rb +47 -0
  124. data/tests/test_sasl.rb +74 -0
  125. data/tests/test_send_file.rb +243 -0
  126. data/tests/test_servers.rb +80 -0
  127. data/tests/test_smtpclient.rb +83 -0
  128. data/tests/test_smtpserver.rb +93 -0
  129. data/tests/test_spawn.rb +329 -0
  130. data/tests/test_ssl_args.rb +68 -0
  131. data/tests/test_ssl_methods.rb +50 -0
  132. data/tests/test_timers.rb +148 -0
  133. data/tests/test_ud.rb +43 -0
  134. data/tests/testem.rb +31 -0
  135. data/web/whatis +7 -0
  136. metadata +214 -0
@@ -0,0 +1,89 @@
1
+ /**
2
+ * $Id$
3
+ *
4
+ * Author:: Francis Cianfrocca (gmail: blackhedd)
5
+ * Homepage:: http://rubyeventmachine.com
6
+ * Date:: 15 Jul 2007
7
+ *
8
+ * See EventMachine and EventMachine::Connection for documentation and
9
+ * usage examples.
10
+ *
11
+ *
12
+ *----------------------------------------------------------------------------
13
+ *
14
+ * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
15
+ * Gmail: blackhedd
16
+ *
17
+ * This program is free software; you can redistribute it and/or modify
18
+ * it under the terms of either: 1) the GNU General Public License
19
+ * as published by the Free Software Foundation; either version 2 of the
20
+ * License, or (at your option) any later version; or 2) Ruby's License.
21
+ *
22
+ * See the file COPYING for complete licensing information.
23
+ *
24
+ *---------------------------------------------------------------------------
25
+ *
26
+ *
27
+ */
28
+
29
+
30
+ package com.rubyeventmachine.tests;
31
+
32
+ import com.rubyeventmachine.*;
33
+ import java.io.*;
34
+
35
+ import org.junit.Assert;
36
+ import org.junit.After;
37
+ import org.junit.AfterClass;
38
+ import org.junit.Before;
39
+ import org.junit.BeforeClass;
40
+ import org.junit.Test;
41
+
42
+
43
+ public class TestTimers {
44
+
45
+ @BeforeClass
46
+ public static void setUpBeforeClass() throws Exception {
47
+ }
48
+
49
+ @AfterClass
50
+ public static void tearDownAfterClass() throws Exception {
51
+ }
52
+
53
+ @Before
54
+ public void setUp() throws Exception {
55
+ }
56
+
57
+ @After
58
+ public void tearDown() throws Exception {
59
+ }
60
+
61
+
62
+
63
+ @Test
64
+ public final void test2() throws IOException {
65
+ Application a = new Application();
66
+ a.addTimer(0, new Timer() {
67
+ public void fire() {
68
+ application.stop();
69
+ }
70
+ });
71
+ a.run();
72
+ Assert.assertEquals (1, 1); // just to make sure the reactor halts.
73
+ }
74
+
75
+ @Test
76
+ public final void test3() throws IOException {
77
+ Application a = new Application();
78
+ a.addTimer (0.1, new PeriodicTimer() {
79
+ int n = 0;
80
+ public void fire() {
81
+ n++;
82
+ if (n == 5)
83
+ application.stop();
84
+ }
85
+ });
86
+ a.run();
87
+ Assert.assertEquals(1, 1);
88
+ }
89
+ }
@@ -0,0 +1,208 @@
1
+ # $Id$
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 16 Jul 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+
26
+ require 'forwardable'
27
+
28
+ module EventMachine
29
+
30
+ module Deferrable
31
+
32
+ # Specify a block to be executed if and when the Deferrable object receives
33
+ # a status of :succeeded. See #set_deferred_status for more information.
34
+ #
35
+ # Calling this method on a Deferrable object whose status is not yet known
36
+ # will cause the callback block to be stored on an internal list.
37
+ # If you call this method on a Deferrable whose status is :succeeded, the
38
+ # block will be executed immediately, receiving the parameters given to the
39
+ # prior #set_deferred_status call.
40
+ #
41
+ #--
42
+ # If there is no status, add a callback to an internal list.
43
+ # If status is succeeded, execute the callback immediately.
44
+ # If status is failed, do nothing.
45
+ #
46
+ def callback &block
47
+ return unless block
48
+ if @deferred_status == :succeeded
49
+ block.call(*@deferred_args)
50
+ elsif @deferred_status != :failed
51
+ @callbacks ||= []
52
+ @callbacks.unshift block # << block
53
+ end
54
+ end
55
+
56
+ # Specify a block to be executed if and when the Deferrable object receives
57
+ # a status of :failed. See #set_deferred_status for more information.
58
+ #--
59
+ # If there is no status, add an errback to an internal list.
60
+ # If status is failed, execute the errback immediately.
61
+ # If status is succeeded, do nothing.
62
+ #
63
+ def errback &block
64
+ return unless block
65
+ if @deferred_status == :failed
66
+ block.call(*@deferred_args)
67
+ elsif @deferred_status != :succeeded
68
+ @errbacks ||= []
69
+ @errbacks.unshift block # << block
70
+ end
71
+ end
72
+
73
+ # Sets the "disposition" (status) of the Deferrable object. See also the large set of
74
+ # sugarings for this method.
75
+ # Note that if you call this method without arguments,
76
+ # no arguments will be passed to the callback/errback.
77
+ # If the user has coded these with arguments, then the
78
+ # user code will throw an argument exception.
79
+ # Implementors of deferrable classes <b>must</b>
80
+ # document the arguments they will supply to user callbacks.
81
+ #
82
+ # OBSERVE SOMETHING VERY SPECIAL here: you may call this method even
83
+ # on the INSIDE of a callback. This is very useful when a previously-registered
84
+ # callback wants to change the parameters that will be passed to subsequently-registered
85
+ # ones.
86
+ #
87
+ # You may give either :succeeded or :failed as the status argument.
88
+ #
89
+ # If you pass :succeeded, then all of the blocks passed to the object using the #callback
90
+ # method (if any) will be executed BEFORE the #set_deferred_status method returns. All of the blocks
91
+ # passed to the object using #errback will be discarded.
92
+ #
93
+ # If you pass :failed, then all of the blocks passed to the object using the #errback
94
+ # method (if any) will be executed BEFORE the #set_deferred_status method returns. All of the blocks
95
+ # passed to the object using # callback will be discarded.
96
+ #
97
+ # If you pass any arguments to #set_deferred_status in addition to the status argument,
98
+ # they will be passed as arguments to any callbacks or errbacks that are executed.
99
+ # It's your responsibility to ensure that the argument lists specified in your callbacks and
100
+ # errbacks match the arguments given in calls to #set_deferred_status, otherwise Ruby will raise
101
+ # an ArgumentError.
102
+ #
103
+ # --
104
+ # We're shifting callbacks off and discarding them as we execute them.
105
+ # This is valid because by definition callbacks are executed no more than
106
+ # once. It also has the magic effect of permitting recursive calls, which
107
+ # means that a callback can call #set_deferred_status and change the parameters
108
+ # that will be sent to subsequent callbacks down the chain.
109
+ #
110
+ # Changed @callbacks and @errbacks from push/shift to unshift/pop, per suggestion
111
+ # by Kirk Haines, to work around the memory leak bug that still exists in many Ruby
112
+ # versions.
113
+ #
114
+ # Changed 15Sep07: after processing callbacks or errbacks, CLEAR the other set of
115
+ # handlers. This gets us a little closer to the behavior of Twisted's "deferred,"
116
+ # which only allows status to be set once. Prior to making this change, it was possible
117
+ # to "succeed" a Deferrable (triggering its callbacks), and then immediately "fail" it,
118
+ # triggering its errbacks! That is clearly undesirable, but it's just as undesirable
119
+ # to raise an exception is status is set more than once on a Deferrable. The latter
120
+ # behavior would invalidate the idiom of resetting arguments by setting status from
121
+ # within a callback or errback, but more seriously it would cause spurious errors
122
+ # if a Deferrable was timed out and then an attempt was made to succeed it. See the
123
+ # comments under the new method #timeout.
124
+ #
125
+ def set_deferred_status status, *args
126
+ cancel_timeout
127
+ @deferred_status = status
128
+ @deferred_args = args
129
+ case @deferred_status
130
+ when :succeeded
131
+ if @callbacks
132
+ while cb = @callbacks.pop
133
+ cb.call(*@deferred_args)
134
+ end
135
+ end
136
+ @errbacks.clear if @errbacks
137
+ when :failed
138
+ if @errbacks
139
+ while eb = @errbacks.pop
140
+ eb.call(*@deferred_args)
141
+ end
142
+ end
143
+ @callbacks.clear if @callbacks
144
+ end
145
+ end
146
+
147
+
148
+ # Setting a timeout on a Deferrable causes it to go into the failed state after
149
+ # the Timeout expires (passing no arguments to the object's errbacks).
150
+ # Setting the status at any time prior to a call to the expiration of the timeout
151
+ # will cause the timer to be cancelled.
152
+ #--
153
+ #
154
+ #
155
+ def timeout seconds
156
+ cancel_timeout
157
+ me = self
158
+ @deferred_timeout = EventMachine::Timer.new(seconds) {me.fail}
159
+ end
160
+
161
+
162
+ # Cancels an outstanding timeout if any. Undoes the action of #timeout.
163
+ #
164
+ #
165
+ def cancel_timeout
166
+ if @deferred_timeout
167
+ @deferred_timeout.cancel
168
+ @deferred_timeout = nil
169
+ end
170
+ end
171
+
172
+
173
+ # Equivalent to set_deferred_status(:succeeded, ...)
174
+ #
175
+ def set_deferred_success *args
176
+ set_deferred_status :succeeded, *args
177
+ end
178
+
179
+ # Equivalent to set_deferred_status(:failed, ...)
180
+ #
181
+ def set_deferred_failure *args
182
+ set_deferred_status :failed, *args
183
+ end
184
+
185
+ # And still more sugar
186
+ #
187
+ def succeed *args
188
+ set_deferred_success(*args)
189
+ end
190
+
191
+ # Can't get enough sugar
192
+ #
193
+ def fail *args
194
+ set_deferred_failure(*args)
195
+ end
196
+ end
197
+
198
+
199
+ # DefaultDeferrable is an otherwise empty class that includes Deferrable.
200
+ # This is very useful when you just need to return a Deferrable object
201
+ # as a way of communicating deferred status to some other part of a program.
202
+ #
203
+ class DefaultDeferrable
204
+ include Deferrable
205
+ end
206
+
207
+ end
208
+
@@ -0,0 +1,39 @@
1
+ # $Id$
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 16 Jul 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+
26
+
27
+ module EventMachine
28
+ module Eventable
29
+
30
+ def listen_event event_name
31
+ end
32
+
33
+ def post_event event_name, arg
34
+ end
35
+
36
+ end
37
+ end
38
+
39
+
@@ -0,0 +1,62 @@
1
+ # $Id$
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 16 Jul 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+
26
+ # This defines EventMachine::Deferrable#future, which requires
27
+ # that the rest of EventMachine::Deferrable has already been seen.
28
+ # (It's in deferrable.rb.)
29
+ #
30
+ # A future is a sugaring of a typical deferrable usage.
31
+
32
+ module EventMachine
33
+ module Deferrable
34
+
35
+ class << self
36
+ # Evaluate arg (which may be an expression or a block).
37
+ # What's the class of arg?
38
+ # If arg is an ordinary expression, then return it.
39
+ # If arg is deferrable (responds to :set_deferred_status),
40
+ # then look at the arguments. If either callback or errback
41
+ # are defined, then use them. If neither are defined, then
42
+ # use the supplied block (if any) as the callback.
43
+ # Then return arg.
44
+ def future arg, cb=nil, eb=nil, &blk
45
+ arg = arg.call if arg.respond_to?(:call)
46
+
47
+ if arg.respond_to?(:set_deferred_status)
48
+ if cb || eb
49
+ arg.callback(&cb) if cb
50
+ arg.errback(&eb) if eb
51
+ else
52
+ arg.callback(&blk) if blk
53
+ end
54
+ end
55
+
56
+ arg
57
+ end
58
+ end
59
+
60
+ end
61
+ end
62
+
@@ -0,0 +1,66 @@
1
+ # $Id$
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 16 Jul 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+
26
+ =begin
27
+
28
+ Message Routing in EventMachine.
29
+
30
+ The goal here is to enable "routing points," objects that can send and receive
31
+ "messages," which are delimited streams of bytes. The boundaries of a message
32
+ are preserved as it passes through the reactor system.
33
+
34
+ There will be several module methods defined in EventMachine to create route-point
35
+ objects (which will probably have a base class of EventMachine::MessageRouter
36
+ until someone suggests a better name).
37
+
38
+ As with I/O objects, routing objects will receive events by having the router
39
+ core call methods on them. And of course user code can and will define handlers
40
+ to deal with events of interest.
41
+
42
+ The message router base class only really needs a receive_message method. There will
43
+ be an EM module-method to send messages, in addition to the module methods to create
44
+ the various kinds of message receivers.
45
+
46
+ The simplest kind of message receiver object can receive messages by being named
47
+ explicitly in a parameter to EM#send_message. More sophisticated receivers can define
48
+ pub-sub selectors and message-queue names. And they can also define channels for
49
+ route-points in other processes or even on other machines.
50
+
51
+ A message is NOT a marshallable entity. Rather, it's a chunk of flat content more like
52
+ an Erlang message. Initially, all content submitted for transmission as a message will
53
+ have the to_s method called on it. Eventually, we'll be able to transmit certain structured
54
+ data types (XML and YAML documents, Structs within limits) and have them reconstructed
55
+ on the other end.
56
+
57
+ A fundamental goal of the message-routing capability is to interoperate seamlessly with
58
+ external systems, including non-Ruby systems like ActiveMQ. We will define various protocol
59
+ handlers for things like Stomp and possibly AMQP, but these will be wrapped up and hidden
60
+ from the users of the basic routing capability.
61
+
62
+ As with Erlang, a critical goal is for programs that are built to use message-passing to work
63
+ WITHOUT CHANGE when the code is re-based on a multi-process system.
64
+
65
+ =end
66
+