concurrent-ruby 0.1.0 → 0.1.1.pre.1

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.
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.