concurrent-ruby 0.1.0 → 0.1.1.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/LICENSE +21 -21
  2. data/README.md +279 -224
  3. data/lib/concurrent.rb +27 -20
  4. data/lib/concurrent/agent.rb +106 -130
  5. data/lib/concurrent/cached_thread_pool.rb +130 -122
  6. data/lib/concurrent/defer.rb +67 -69
  7. data/lib/concurrent/drb_async_demux.rb +72 -0
  8. data/lib/concurrent/event.rb +60 -60
  9. data/lib/concurrent/event_machine_defer_proxy.rb +23 -23
  10. data/lib/concurrent/executor.rb +87 -0
  11. data/lib/concurrent/fixed_thread_pool.rb +89 -89
  12. data/lib/concurrent/functions.rb +120 -0
  13. data/lib/concurrent/future.rb +52 -42
  14. data/lib/concurrent/global_thread_pool.rb +3 -3
  15. data/lib/concurrent/goroutine.rb +29 -25
  16. data/lib/concurrent/obligation.rb +67 -121
  17. data/lib/concurrent/promise.rb +172 -194
  18. data/lib/concurrent/reactor.rb +162 -0
  19. data/lib/concurrent/smart_mutex.rb +66 -0
  20. data/lib/concurrent/tcp_sync_demux.rb +96 -0
  21. data/lib/concurrent/thread_pool.rb +65 -61
  22. data/lib/concurrent/utilities.rb +34 -0
  23. data/lib/concurrent/version.rb +3 -3
  24. data/lib/concurrent_ruby.rb +1 -1
  25. data/md/agent.md +123 -123
  26. data/md/defer.md +174 -174
  27. data/md/event.md +32 -32
  28. data/md/executor.md +176 -0
  29. data/md/future.md +83 -83
  30. data/md/goroutine.md +52 -52
  31. data/md/obligation.md +32 -32
  32. data/md/promise.md +225 -225
  33. data/md/thread_pool.md +197 -197
  34. data/spec/concurrent/agent_spec.rb +376 -405
  35. data/spec/concurrent/cached_thread_pool_spec.rb +112 -112
  36. data/spec/concurrent/defer_spec.rb +209 -199
  37. data/spec/concurrent/event_machine_defer_proxy_spec.rb +250 -246
  38. data/spec/concurrent/event_spec.rb +134 -134
  39. data/spec/concurrent/executor_spec.rb +146 -0
  40. data/spec/concurrent/fixed_thread_pool_spec.rb +84 -84
  41. data/spec/concurrent/functions_spec.rb +57 -0
  42. data/spec/concurrent/future_spec.rb +125 -115
  43. data/spec/concurrent/goroutine_spec.rb +67 -52
  44. data/spec/concurrent/obligation_shared.rb +121 -121
  45. data/spec/concurrent/promise_spec.rb +299 -310
  46. data/spec/concurrent/smart_mutex_spec.rb +234 -0
  47. data/spec/concurrent/thread_pool_shared.rb +209 -209
  48. data/spec/concurrent/utilities_spec.rb +74 -0
  49. data/spec/spec_helper.rb +21 -19
  50. metadata +38 -14
  51. checksums.yaml +0 -7
@@ -1,32 +1,32 @@
1
- # Obligation
2
-
3
- TBD...
4
-
5
- ## Copyright
6
-
7
- *Concurrent Ruby* is Copyright © 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
8
- It is free software and may be redistributed under the terms specified in the LICENSE file.
9
-
10
- ## License
11
-
12
- Released under the MIT license.
13
-
14
- http://www.opensource.org/licenses/mit-license.php
15
-
16
- > Permission is hereby granted, free of charge, to any person obtaining a copy
17
- > of this software and associated documentation files (the "Software"), to deal
18
- > in the Software without restriction, including without limitation the rights
19
- > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20
- > copies of the Software, and to permit persons to whom the Software is
21
- > furnished to do so, subject to the following conditions:
22
- >
23
- > The above copyright notice and this permission notice shall be included in
24
- > all copies or substantial portions of the Software.
25
- >
26
- > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
- > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
- > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
- > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
- > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
- > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32
- > THE SOFTWARE.
1
+ # Obligation
2
+
3
+ TBD...
4
+
5
+ ## Copyright
6
+
7
+ *Concurrent Ruby* is Copyright © 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
8
+ It is free software and may be redistributed under the terms specified in the LICENSE file.
9
+
10
+ ## License
11
+
12
+ Released under the MIT license.
13
+
14
+ http://www.opensource.org/licenses/mit-license.php
15
+
16
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
17
+ > of this software and associated documentation files (the "Software"), to deal
18
+ > in the Software without restriction, including without limitation the rights
19
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20
+ > copies of the Software, and to permit persons to whom the Software is
21
+ > furnished to do so, subject to the following conditions:
22
+ >
23
+ > The above copyright notice and this permission notice shall be included in
24
+ > all copies or substantial portions of the Software.
25
+ >
26
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32
+ > THE SOFTWARE.
@@ -1,225 +1,225 @@
1
- # Promises, Promises...
2
-
3
- A promise is the most powerful and versatile of the concurrency objects in this library.
4
- Promises are inspired by the JavaScript [Promises/A](http://wiki.commonjs.org/wiki/Promises/A)
5
- and [Promises/A+](http://promises-aplus.github.io/promises-spec/) specifications.
6
-
7
- > A promise represents the eventual value returned from the single completion of an operation.
8
-
9
- Promises are similar to futures and share many of the same behaviours. Promises are far more robust,
10
- however. Promises can be chained in a tree structure where each promise may have zero or more children.
11
- Promises are chained using the `then` method. The result of a call to `then` is always another promise.
12
- Promises are resolved asynchronously in the order they are added to the tree. Parents are guaranteed
13
- to be resolved before their children. The result of each promise is passed to each of its children
14
- upon resolution. When a promise is rejected all its children will be summarily rejected.
15
-
16
- Promises have three possible states: *pending*, *rejected*, and *fulfilled*. When a promise is created it is set
17
- to *pending* and will remain in that state until processing is complete. A completed promise is either *rejected*,
18
- indicating that an exception was thrown during processing, or *fulfilled*, indicating succedd. If a promise is
19
- *fulfilled* its `value` will be updated to reflect the result of the operation. If *rejected* the `reason` will
20
- be updated with a reference to the thrown exception. The predicate methods `pending?`, `rejected`, and `fulfilled?`
21
- can be called at any time to obtain the state of the promise, as can the `state` method, which returns a symbol.
22
-
23
- Retrieving the value of a promise is done through the `value` (alias: `deref`) method. Obtaining the value of
24
- a promise is a potentially blocking operation. When a promise is *rejected* a call to `value` will return `nil`
25
- immediately. When a promise is *fulfilled* a call to `value` will immediately return the current value.
26
- When a promise is *pending* a call to `value` will block until the promise is either *rejected* or *fulfilled*.
27
- A *timeout* value can be passed to `value` to limit how long the call will block. If `nil` the call will
28
- block indefinitely. If `0` the call will not block. Any other integer or float value will indicate the
29
- maximum number of seconds to block.
30
-
31
- ## Examples
32
-
33
- Start by requiring promises
34
-
35
- ```ruby
36
- require 'concurrent'
37
- ```
38
-
39
- Then create one
40
-
41
- ```ruby
42
- p = Promise.new("Jerry", "D'Antonio") do |first, last|
43
- "#{last}, #{first}"
44
- end
45
-
46
- # -or-
47
-
48
- p = promise(10){|x| x * x * x }
49
- ```
50
-
51
- Promises can be chained using the `then` method. The `then` method
52
- accepts a block but no arguments. The result of the each promise is
53
- passed as the block argument to chained promises
54
-
55
- ```ruby
56
- p = promise(10){|x| x * 2}.then{|result| result - 10 }
57
- ```
58
-
59
- And so on, and so on, and so on...
60
-
61
- ```ruby
62
- p = promise(10){|x| x * 2}.
63
- then{|result| result - 10 }.
64
- then{|result| result * 3 }.
65
- then{|result| result % 5 }
66
- ```
67
-
68
- Promises are executed asynchronously so a newly-created promise *should* always be in the pending state
69
-
70
-
71
- ```ruby
72
- p = promise{ "Hello, world!" }
73
- p.state #=> :pending
74
- p.pending? #=> true
75
- ```
76
-
77
- Wait a little bit, and the promise will resolve and provide a value
78
-
79
- ```ruby
80
- p = promise{ "Hello, world!" }
81
- sleep(0.1)
82
-
83
- p.state #=> :fulfilled
84
- p.fulfilled? #=> true
85
-
86
- p.value #=> "Hello, world!"
87
-
88
- ```
89
-
90
- If an exception occurs, the promise will be rejected and will provide
91
- a reason for the rejection
92
-
93
- ```ruby
94
- p = promise{ raise StandardError.new("Here comes the Boom!") }
95
- sleep(0.1)
96
-
97
- p.state #=> :rejected
98
- p.rejected? #=> true
99
-
100
- p.reason=> #=> "#<StandardError: Here comes the Boom!>"
101
- ```
102
-
103
- ### Rejection
104
-
105
- Much like the economy, rejection exhibits a trickle-down effect. When
106
- a promise is rejected all its children will be rejected
107
-
108
- ```ruby
109
- p = [ promise{ Thread.pass; raise StandardError } ]
110
-
111
- 10.times{|i| p << p.first.then{ i } }
112
- sleep(0.1)
113
-
114
- p.length #=> 11
115
- p.first.state #=> :rejected
116
- p.last.state #=> :rejected
117
- ```
118
-
119
- Once a promise is rejected it will not accept any children. Calls
120
- to `then` will continually return `self`
121
-
122
- ```ruby
123
- p = promise{ raise StandardError }
124
- sleep(0.1)
125
-
126
- p.object_id #=> 32960556
127
- p.then{}.object_id #=> 32960556
128
- p.then{}.object_id #=> 32960556
129
- ```
130
-
131
- ### Error Handling
132
-
133
- Promises support error handling callbacks is a style mimicing Ruby's
134
- own exception handling mechanism, namely `rescue`
135
-
136
-
137
- ```ruby
138
- promise{ "dangerous operation..." }.rescue{|ex| puts "Bam!" }
139
-
140
- # -or- (for the Java/C# crowd)
141
- promise{ "dangerous operation..." }.catch{|ex| puts "Boom!" }
142
-
143
- # -or- (for the hipsters)
144
- promise{ "dangerous operation..." }.on_error{|ex| puts "Pow!" }
145
- ```
146
-
147
- As with Ruby's `rescue` mechanism, a promise's `rescue` method can
148
- accept an optional Exception class argument (defaults to `Exception`
149
- when not specified)
150
-
151
-
152
- ```ruby
153
- promise{ "dangerous operation..." }.rescue(ArgumentError){|ex| puts "Bam!" }
154
- ```
155
-
156
- Calls to `rescue` can also be chained
157
-
158
- ```ruby
159
- promise{ "dangerous operation..." }.
160
- rescue(ArgumentError){|ex| puts "Bam!" }.
161
- rescue(NoMethodError){|ex| puts "Boom!" }.
162
- rescue(StandardError){|ex| puts "Pow!" }
163
- ```
164
-
165
- When there are multiple `rescue` handlers the first one to match the thrown
166
- exception will be triggered
167
-
168
- ```ruby
169
- promise{ raise NoMethodError }.
170
- rescue(ArgumentError){|ex| puts "Bam!" }.
171
- rescue(NoMethodError){|ex| puts "Boom!" }.
172
- rescue(StandardError){|ex| puts "Pow!" }
173
-
174
- sleep(0.1)
175
-
176
- #=> Boom!
177
- ```
178
-
179
- Trickle-down rejection also applies to rescue handlers. When a promise is rejected,
180
- for any reason, its rescue handlers will be triggered. Rejection of the parent counts.
181
-
182
- ```ruby
183
- promise{ Thread.pass; raise StandardError }.
184
- then{ true }.rescue{ puts 'Boom!' }.
185
- then{ true }.rescue{ puts 'Boom!' }.
186
- then{ true }.rescue{ puts 'Boom!' }.
187
- then{ true }.rescue{ puts 'Boom!' }.
188
- then{ true }.rescue{ puts 'Boom!' }
189
- sleep(0.1)
190
-
191
- #=> Boom!
192
- #=> Boom!
193
- #=> Boom!
194
- #=> Boom!
195
- #=> Boom!
196
- ```
197
-
198
- ## Copyright
199
-
200
- *Concurrent Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
201
- It is free software and may be redistributed under the terms specified in the LICENSE file.
202
-
203
- ## License
204
-
205
- Released under the MIT license.
206
-
207
- http://www.opensource.org/licenses/mit-license.php
208
-
209
- > Permission is hereby granted, free of charge, to any person obtaining a copy
210
- > of this software and associated documentation files (the "Software"), to deal
211
- > in the Software without restriction, including without limitation the rights
212
- > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
213
- > copies of the Software, and to permit persons to whom the Software is
214
- > furnished to do so, subject to the following conditions:
215
- >
216
- > The above copyright notice and this permission notice shall be included in
217
- > all copies or substantial portions of the Software.
218
- >
219
- > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
220
- > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
221
- > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
222
- > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
223
- > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
224
- > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
225
- > THE SOFTWARE.
1
+ # Promises, Promises...
2
+
3
+ A promise is the most powerful and versatile of the concurrency objects in this library.
4
+ Promises are inspired by the JavaScript [Promises/A](http://wiki.commonjs.org/wiki/Promises/A)
5
+ and [Promises/A+](http://promises-aplus.github.io/promises-spec/) specifications.
6
+
7
+ > A promise represents the eventual value returned from the single completion of an operation.
8
+
9
+ Promises are similar to futures and share many of the same behaviours. Promises are far more robust,
10
+ however. Promises can be chained in a tree structure where each promise may have zero or more children.
11
+ Promises are chained using the `then` method. The result of a call to `then` is always another promise.
12
+ Promises are resolved asynchronously in the order they are added to the tree. Parents are guaranteed
13
+ to be resolved before their children. The result of each promise is passed to each of its children
14
+ upon resolution. When a promise is rejected all its children will be summarily rejected.
15
+
16
+ Promises have three possible states: *pending*, *rejected*, and *fulfilled*. When a promise is created it is set
17
+ to *pending* and will remain in that state until processing is complete. A completed promise is either *rejected*,
18
+ indicating that an exception was thrown during processing, or *fulfilled*, indicating succedd. If a promise is
19
+ *fulfilled* its `value` will be updated to reflect the result of the operation. If *rejected* the `reason` will
20
+ be updated with a reference to the thrown exception. The predicate methods `pending?`, `rejected`, and `fulfilled?`
21
+ can be called at any time to obtain the state of the promise, as can the `state` method, which returns a symbol.
22
+
23
+ Retrieving the value of a promise is done through the `value` (alias: `deref`) method. Obtaining the value of
24
+ a promise is a potentially blocking operation. When a promise is *rejected* a call to `value` will return `nil`
25
+ immediately. When a promise is *fulfilled* a call to `value` will immediately return the current value.
26
+ When a promise is *pending* a call to `value` will block until the promise is either *rejected* or *fulfilled*.
27
+ A *timeout* value can be passed to `value` to limit how long the call will block. If `nil` the call will
28
+ block indefinitely. If `0` the call will not block. Any other integer or float value will indicate the
29
+ maximum number of seconds to block.
30
+
31
+ ## Examples
32
+
33
+ Start by requiring promises
34
+
35
+ ```ruby
36
+ require 'concurrent'
37
+ ```
38
+
39
+ Then create one
40
+
41
+ ```ruby
42
+ p = Promise.new("Jerry", "D'Antonio") do |first, last|
43
+ "#{last}, #{first}"
44
+ end
45
+
46
+ # -or-
47
+
48
+ p = promise(10){|x| x * x * x }
49
+ ```
50
+
51
+ Promises can be chained using the `then` method. The `then` method
52
+ accepts a block but no arguments. The result of the each promise is
53
+ passed as the block argument to chained promises
54
+
55
+ ```ruby
56
+ p = promise(10){|x| x * 2}.then{|result| result - 10 }
57
+ ```
58
+
59
+ And so on, and so on, and so on...
60
+
61
+ ```ruby
62
+ p = promise(10){|x| x * 2}.
63
+ then{|result| result - 10 }.
64
+ then{|result| result * 3 }.
65
+ then{|result| result % 5 }
66
+ ```
67
+
68
+ Promises are executed asynchronously so a newly-created promise *should* always be in the pending state
69
+
70
+
71
+ ```ruby
72
+ p = promise{ "Hello, world!" }
73
+ p.state #=> :pending
74
+ p.pending? #=> true
75
+ ```
76
+
77
+ Wait a little bit, and the promise will resolve and provide a value
78
+
79
+ ```ruby
80
+ p = promise{ "Hello, world!" }
81
+ sleep(0.1)
82
+
83
+ p.state #=> :fulfilled
84
+ p.fulfilled? #=> true
85
+
86
+ p.value #=> "Hello, world!"
87
+
88
+ ```
89
+
90
+ If an exception occurs, the promise will be rejected and will provide
91
+ a reason for the rejection
92
+
93
+ ```ruby
94
+ p = promise{ raise StandardError.new("Here comes the Boom!") }
95
+ sleep(0.1)
96
+
97
+ p.state #=> :rejected
98
+ p.rejected? #=> true
99
+
100
+ p.reason=> #=> "#<StandardError: Here comes the Boom!>"
101
+ ```
102
+
103
+ ### Rejection
104
+
105
+ Much like the economy, rejection exhibits a trickle-down effect. When
106
+ a promise is rejected all its children will be rejected
107
+
108
+ ```ruby
109
+ p = [ promise{ Thread.pass; raise StandardError } ]
110
+
111
+ 10.times{|i| p << p.first.then{ i } }
112
+ sleep(0.1)
113
+
114
+ p.length #=> 11
115
+ p.first.state #=> :rejected
116
+ p.last.state #=> :rejected
117
+ ```
118
+
119
+ Once a promise is rejected it will not accept any children. Calls
120
+ to `then` will continually return `self`
121
+
122
+ ```ruby
123
+ p = promise{ raise StandardError }
124
+ sleep(0.1)
125
+
126
+ p.object_id #=> 32960556
127
+ p.then{}.object_id #=> 32960556
128
+ p.then{}.object_id #=> 32960556
129
+ ```
130
+
131
+ ### Error Handling
132
+
133
+ Promises support error handling callbacks is a style mimicing Ruby's
134
+ own exception handling mechanism, namely `rescue`
135
+
136
+
137
+ ```ruby
138
+ promise{ "dangerous operation..." }.rescue{|ex| puts "Bam!" }
139
+
140
+ # -or- (for the Java/C# crowd)
141
+ promise{ "dangerous operation..." }.catch{|ex| puts "Boom!" }
142
+
143
+ # -or- (for the hipsters)
144
+ promise{ "dangerous operation..." }.on_error{|ex| puts "Pow!" }
145
+ ```
146
+
147
+ As with Ruby's `rescue` mechanism, a promise's `rescue` method can
148
+ accept an optional Exception class argument (defaults to `Exception`
149
+ when not specified)
150
+
151
+
152
+ ```ruby
153
+ promise{ "dangerous operation..." }.rescue(ArgumentError){|ex| puts "Bam!" }
154
+ ```
155
+
156
+ Calls to `rescue` can also be chained
157
+
158
+ ```ruby
159
+ promise{ "dangerous operation..." }.
160
+ rescue(ArgumentError){|ex| puts "Bam!" }.
161
+ rescue(NoMethodError){|ex| puts "Boom!" }.
162
+ rescue(StandardError){|ex| puts "Pow!" }
163
+ ```
164
+
165
+ When there are multiple `rescue` handlers the first one to match the thrown
166
+ exception will be triggered
167
+
168
+ ```ruby
169
+ promise{ raise NoMethodError }.
170
+ rescue(ArgumentError){|ex| puts "Bam!" }.
171
+ rescue(NoMethodError){|ex| puts "Boom!" }.
172
+ rescue(StandardError){|ex| puts "Pow!" }
173
+
174
+ sleep(0.1)
175
+
176
+ #=> Boom!
177
+ ```
178
+
179
+ Trickle-down rejection also applies to rescue handlers. When a promise is rejected,
180
+ for any reason, its rescue handlers will be triggered. Rejection of the parent counts.
181
+
182
+ ```ruby
183
+ promise{ Thread.pass; raise StandardError }.
184
+ then{ true }.rescue{ puts 'Boom!' }.
185
+ then{ true }.rescue{ puts 'Boom!' }.
186
+ then{ true }.rescue{ puts 'Boom!' }.
187
+ then{ true }.rescue{ puts 'Boom!' }.
188
+ then{ true }.rescue{ puts 'Boom!' }
189
+ sleep(0.1)
190
+
191
+ #=> Boom!
192
+ #=> Boom!
193
+ #=> Boom!
194
+ #=> Boom!
195
+ #=> Boom!
196
+ ```
197
+
198
+ ## Copyright
199
+
200
+ *Concurrent Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
201
+ It is free software and may be redistributed under the terms specified in the LICENSE file.
202
+
203
+ ## License
204
+
205
+ Released under the MIT license.
206
+
207
+ http://www.opensource.org/licenses/mit-license.php
208
+
209
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
210
+ > of this software and associated documentation files (the "Software"), to deal
211
+ > in the Software without restriction, including without limitation the rights
212
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
213
+ > copies of the Software, and to permit persons to whom the Software is
214
+ > furnished to do so, subject to the following conditions:
215
+ >
216
+ > The above copyright notice and this permission notice shall be included in
217
+ > all copies or substantial portions of the Software.
218
+ >
219
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
220
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
221
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
222
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
223
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
224
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
225
+ > THE SOFTWARE.