matilda-maybe 0.3.0
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.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +27 -0
- data/LICENSE.md +7 -0
- data/README.md +95 -0
- data/Rakefile +9 -0
- data/lib/matilda-maybe.rb +3 -0
- data/lib/matilda-maybe/just.rb +46 -0
- data/lib/matilda-maybe/maybe.rb +9 -0
- data/lib/matilda-maybe/nothing.rb +37 -0
- data/matilda-maybe.gemspec +15 -0
- data/spec/integration_spec.rb +31 -0
- data/spec/just_spec.rb +57 -0
- data/spec/maybe_spec.rb +15 -0
- data/spec/nothing_spec.rb +56 -0
- data/spec/spec_helper.rb +4 -0
- metadata +61 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: dfedc2eb085cf84abaaf05050cee7cfc895ceaa0
|
|
4
|
+
data.tar.gz: 9ed28c975b9844f0075515bdb07f95fdbdea8bb5
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: d2e91c2a516f70cd7ab6b056aa8e32a69b75dd503f0bbefd8326b6d49a66e3453b006f6beba49a8e783978e3ff9007e1942d524ae5369b5e93d4217c717b8d10
|
|
7
|
+
data.tar.gz: 0a147b5b11ad2d7d7d7d15b7892418f9ea90c48c4e6b68947f72f5b043a3289f6448addece82cdfcb859c6d29a1573d8f9ad3e5d140fe400be08f6c81ea74f67
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
GEM
|
|
2
|
+
remote: https://rubygems.org/
|
|
3
|
+
specs:
|
|
4
|
+
colorize (0.5.8)
|
|
5
|
+
coveralls (0.6.7)
|
|
6
|
+
colorize
|
|
7
|
+
multi_json (~> 1.3)
|
|
8
|
+
rest-client
|
|
9
|
+
simplecov (>= 0.7)
|
|
10
|
+
thor
|
|
11
|
+
mime-types (1.23)
|
|
12
|
+
multi_json (1.7.3)
|
|
13
|
+
rake (10.0.3)
|
|
14
|
+
rest-client (1.6.7)
|
|
15
|
+
mime-types (>= 1.16)
|
|
16
|
+
simplecov (0.7.1)
|
|
17
|
+
multi_json (~> 1.0)
|
|
18
|
+
simplecov-html (~> 0.7.1)
|
|
19
|
+
simplecov-html (0.7.1)
|
|
20
|
+
thor (0.18.1)
|
|
21
|
+
|
|
22
|
+
PLATFORMS
|
|
23
|
+
ruby
|
|
24
|
+
|
|
25
|
+
DEPENDENCIES
|
|
26
|
+
coveralls
|
|
27
|
+
rake
|
data/LICENSE.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
The MIT License (MIT) Copyright (c) Callum Stott, http://www.seadowg.com
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# ruby-maybe
|
|
2
|
+
|
|
3
|
+
[](https://travis-ci.org/seadowg/ruby-maybe)
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Either include in your Gemfile:
|
|
10
|
+
|
|
11
|
+
gem 'ruby-maybe'
|
|
12
|
+
|
|
13
|
+
Or, install for your system:
|
|
14
|
+
|
|
15
|
+
> gem install ruby-maybe
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
### The Basics
|
|
20
|
+
|
|
21
|
+
'Maybe' not 'Maeby'. This is an implementation of the 'Maybe' or 'Option' monad similar to that used
|
|
22
|
+
[Haskell](http://www.haskell.org/haskellwiki/Maybe). Monads provide a
|
|
23
|
+
safe way to create non deterministic programs (for example, when not all
|
|
24
|
+
values are known at compile time). The Maybe monad allows programmers to
|
|
25
|
+
deal with values that may or may not be undefined.
|
|
26
|
+
|
|
27
|
+
Imagine we are access accessing an array via a method:
|
|
28
|
+
|
|
29
|
+
array = [1,2,3]
|
|
30
|
+
|
|
31
|
+
def access(n)
|
|
32
|
+
array[n]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
access(1) # => 2
|
|
36
|
+
access(5) # => nil
|
|
37
|
+
|
|
38
|
+
Now what if we want to take some index and add `5` to the array value
|
|
39
|
+
stored there?
|
|
40
|
+
|
|
41
|
+
access(5) + 5 # => NoMethodError: undefined method `+' for nil:NilClass
|
|
42
|
+
|
|
43
|
+
Hmmm, that fails pretty miserably. We can solve this with `Maybe`. Lets
|
|
44
|
+
rewrite `access`:
|
|
45
|
+
|
|
46
|
+
def access(n)
|
|
47
|
+
if array[n]
|
|
48
|
+
Just.new(array[n])
|
|
49
|
+
else
|
|
50
|
+
Nothing
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
`Nothing` and `Just` used here are both instances of `Maybe`. This means
|
|
55
|
+
that they will both respond to the `bind` method:
|
|
56
|
+
|
|
57
|
+
access(1).bind { |val| Just.new(val + 5) } # => Just.new(7)
|
|
58
|
+
access(5).bind { |val| Just.new(val + 5) } # => Nothing.new
|
|
59
|
+
|
|
60
|
+
For instances of `Just`, `bind` will execute the passed block with
|
|
61
|
+
respect to its contained value and for `Nothing` it will skip the block
|
|
62
|
+
and simply return another instance of `Nothing`. This allows a neat
|
|
63
|
+
mechanism for dealing with non determinitic methods such as `access`
|
|
64
|
+
without having them throw exceptions or simply return `nil`.
|
|
65
|
+
|
|
66
|
+
`Maybe` is a very basic monad and at first might not seem that powerful
|
|
67
|
+
but after using it instead of the more verbose control flow it replaces
|
|
68
|
+
you might just learn to love it.
|
|
69
|
+
|
|
70
|
+
### Method Lifting
|
|
71
|
+
|
|
72
|
+
Ok so using `bind` to operate on Maybe is all well and good, but what if
|
|
73
|
+
you want to add three Maybe's together:
|
|
74
|
+
|
|
75
|
+
x.bind { |x_val|
|
|
76
|
+
y.bind { |y_val|
|
|
77
|
+
z.bind { |z_val|
|
|
78
|
+
Just.new(x + y + z)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
Yeah... I don't think so. In languages like Haskell we can use [Applicative Functors](http://learnyouahaskell.com/functors-applicative-functors-and-monoids)
|
|
84
|
+
to deal with making expressions like the above less verbose. You can go read about them but that's not really important.
|
|
85
|
+
With ruby-maybe methods on the contained object in a Maybe can be lifted to operate on the Maybe:
|
|
86
|
+
|
|
87
|
+
Just.new(5) + Just.new(6) # => Just.new(11)
|
|
88
|
+
Just.new("OMG").downcase # => Just.new("omg")
|
|
89
|
+
Just.new([1,2]).inject(Just.new(0), :+) # => Just.new(3)
|
|
90
|
+
|
|
91
|
+
All operations can be lifted like this and you can mix and match actual values and Maybes in the arguments. This also
|
|
92
|
+
works for Nothing:
|
|
93
|
+
|
|
94
|
+
Nothing.new + Just.new(5) # => Nothing.new
|
|
95
|
+
Just.new(0) * Nothing.new / Just.new(1) # => Nothing.new
|
data/Rakefile
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
class Just < Maybe
|
|
2
|
+
def method_missing(method_name, *args, &block)
|
|
3
|
+
values = args.map { |arg|
|
|
4
|
+
return Nothing.new if arg == Nothing.new
|
|
5
|
+
arg.kind_of?(Just) ? arg.value : arg
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
Just.new(@value.public_send(method_name, *values, &block))
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize(value)
|
|
12
|
+
@value = value
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def bind(&block)
|
|
16
|
+
computed = block.call(@value)
|
|
17
|
+
warn("Not returning a Maybe from #bind is really bad form...") unless computed.kind_of?(Maybe)
|
|
18
|
+
computed
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def map(&block)
|
|
22
|
+
Just.new(block.call(@value))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def or(*args, &block)
|
|
26
|
+
self
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def get(*args, &block)
|
|
30
|
+
@value
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def ==(object)
|
|
34
|
+
if object.class == Just
|
|
35
|
+
object.value == self.value
|
|
36
|
+
else
|
|
37
|
+
false
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
protected
|
|
42
|
+
|
|
43
|
+
def value
|
|
44
|
+
@value
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
class Nothing < Maybe
|
|
2
|
+
def method_missing(method_name, *args, &block)
|
|
3
|
+
Nothing.new
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def bind
|
|
7
|
+
Nothing.new
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def map
|
|
11
|
+
Nothing.new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def or(*args, &block)
|
|
15
|
+
if args.empty?
|
|
16
|
+
block.call
|
|
17
|
+
else
|
|
18
|
+
args.first
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def get(*args, &block)
|
|
23
|
+
if args.empty?
|
|
24
|
+
block.call
|
|
25
|
+
else
|
|
26
|
+
args.first
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def ==(object)
|
|
31
|
+
if object.class == Nothing
|
|
32
|
+
true
|
|
33
|
+
else
|
|
34
|
+
false
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
lib = File.expand_path('../lib/', __FILE__)
|
|
2
|
+
$:.unshift lib unless $:.include?(lib)
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |s|
|
|
5
|
+
s.name = "matilda-maybe"
|
|
6
|
+
s.version = "0.3.0"
|
|
7
|
+
s.platform = Gem::Platform::RUBY
|
|
8
|
+
s.authors = ["Callum Stott"]
|
|
9
|
+
s.email = ["callum@seadowg"]
|
|
10
|
+
s.summary = "Maybe monad implementation for Ruby"
|
|
11
|
+
s.license = 'MIT'
|
|
12
|
+
|
|
13
|
+
s.require_paths = ['lib']
|
|
14
|
+
s.files = `git ls-files`.split("\n")
|
|
15
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'matilda-maybe'
|
|
3
|
+
|
|
4
|
+
describe "Integration Specs" do
|
|
5
|
+
it "works as expected" do
|
|
6
|
+
Just.new(5).bind { |val|
|
|
7
|
+
Just.new(val).map { |val|
|
|
8
|
+
val * 3
|
|
9
|
+
}
|
|
10
|
+
}.bind { |val|
|
|
11
|
+
if (val > 10)
|
|
12
|
+
Nothing.new
|
|
13
|
+
else
|
|
14
|
+
Just.new(val) + 1
|
|
15
|
+
end
|
|
16
|
+
}.must_equal(Nothing.new)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "has the correct interface" do
|
|
20
|
+
has_method(:bind)
|
|
21
|
+
has_method(:map)
|
|
22
|
+
has_method(:or)
|
|
23
|
+
has_method(:get)
|
|
24
|
+
has_method(:==)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def has_method(name)
|
|
29
|
+
assert(Just.method_defined?(name), "Just does not respond to #{name}")
|
|
30
|
+
assert(Nothing.method_defined?(name), "Nothing does not respond to #{name}")
|
|
31
|
+
end
|
data/spec/just_spec.rb
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'matilda-maybe'
|
|
3
|
+
|
|
4
|
+
describe "Just" do
|
|
5
|
+
describe "#bind" do
|
|
6
|
+
it "applys the passed block to its boxed value" do
|
|
7
|
+
Just.new(5).bind { |val| Just.new(val * 2) }.must_equal Just.new(10)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe "#or" do
|
|
12
|
+
it "ignores arg and returns self" do
|
|
13
|
+
(Just.new(5).or { 0 }).must_equal Just.new(5)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe "#get" do
|
|
18
|
+
it "ignores the arguments and returns the value" do
|
|
19
|
+
(Just.new(5).get { 0 }).must_equal 5
|
|
20
|
+
Just.new(5).get(0).must_equal 5
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe "#==" do
|
|
25
|
+
it "returns false if the passed object is not a Just" do
|
|
26
|
+
(Just.new(5) == 5).must_equal false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "returns true if the passed object is a Just with the same value" do
|
|
30
|
+
(Just.new(5) == Just.new(5)).must_equal true
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe "method lifting" do
|
|
35
|
+
it "allows using a method for the contained type" do
|
|
36
|
+
just = Just.new(5)
|
|
37
|
+
just.+(5).must_equal(Just.new(10))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "allows passed arguments to be Maybe instances" do
|
|
41
|
+
just = Just.new(5)
|
|
42
|
+
just.+(Just.new(5)).must_equal(Just.new(10))
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "returns Nothing if any argument is Nothing" do
|
|
46
|
+
just = Just.new("Hello")
|
|
47
|
+
just.slice(Just.new(0), Nothing.new).must_equal(Nothing.new)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "passes blocks correctly" do
|
|
51
|
+
count = 0
|
|
52
|
+
just = Just.new(5)
|
|
53
|
+
just.times { |i| count += i }
|
|
54
|
+
count.must_equal(10)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
data/spec/maybe_spec.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'matilda-maybe'
|
|
3
|
+
|
|
4
|
+
describe "Maybe" do
|
|
5
|
+
describe "#from" do
|
|
6
|
+
it "returns Nothing if passed nil" do
|
|
7
|
+
Maybe.from(nil).must_equal Nothing.new
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "returns Just if passed non-nil value" do
|
|
11
|
+
Maybe.from(false).must_equal Just.new(false)
|
|
12
|
+
Maybe.from(11).must_equal Just.new(11)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'matilda-maybe'
|
|
3
|
+
|
|
4
|
+
describe "Nothing" do
|
|
5
|
+
describe "#bind" do
|
|
6
|
+
it "does not execute the passed block" do
|
|
7
|
+
executed = false
|
|
8
|
+
Nothing.new.bind { |val| executed = true }
|
|
9
|
+
executed.must_equal false
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "returns a Nothing" do
|
|
13
|
+
Nothing.new.bind { |val| val }.kind_of?(Nothing).must_equal true
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe "#map" do
|
|
18
|
+
it "returns Nothing" do
|
|
19
|
+
Nothing.new.map { |val| val }.must_equal Nothing.new
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe "#or" do
|
|
24
|
+
it "evaluates arg, returning result" do
|
|
25
|
+
(Nothing.new.or { Just.new(5) }).must_equal Just.new(5)
|
|
26
|
+
Nothing.new.or(Just.new(5)).must_equal Just.new(5)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "chain or calls, returning last value" do
|
|
30
|
+
(Nothing.new.or { Nothing.new.or { Just.new(10) } }).must_equal Just.new(10)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe "#get" do
|
|
35
|
+
it "evaluates arg, returning result" do
|
|
36
|
+
(Nothing.new.get { 5 }).must_equal 5
|
|
37
|
+
Nothing.new.get(5).must_equal 5
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe "#==" do
|
|
42
|
+
it "returns false if the passed object is not a Nothing" do
|
|
43
|
+
(Nothing.new == 5).must_equal false
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "returns true if the passed object is a Nothing" do
|
|
47
|
+
(Nothing.new == Nothing.new).must_equal true
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
describe "method lifting" do
|
|
52
|
+
it "returns Nothing for any method call" do
|
|
53
|
+
Nothing.new.missing.must_equal(Nothing.new)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: matilda-maybe
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.3.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Callum Stott
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2013-08-07 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description:
|
|
14
|
+
email:
|
|
15
|
+
- callum@seadowg
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- .gitignore
|
|
21
|
+
- .travis.yml
|
|
22
|
+
- Gemfile
|
|
23
|
+
- Gemfile.lock
|
|
24
|
+
- LICENSE.md
|
|
25
|
+
- README.md
|
|
26
|
+
- Rakefile
|
|
27
|
+
- lib/matilda-maybe.rb
|
|
28
|
+
- lib/matilda-maybe/just.rb
|
|
29
|
+
- lib/matilda-maybe/maybe.rb
|
|
30
|
+
- lib/matilda-maybe/nothing.rb
|
|
31
|
+
- matilda-maybe.gemspec
|
|
32
|
+
- spec/integration_spec.rb
|
|
33
|
+
- spec/just_spec.rb
|
|
34
|
+
- spec/maybe_spec.rb
|
|
35
|
+
- spec/nothing_spec.rb
|
|
36
|
+
- spec/spec_helper.rb
|
|
37
|
+
homepage:
|
|
38
|
+
licenses:
|
|
39
|
+
- MIT
|
|
40
|
+
metadata: {}
|
|
41
|
+
post_install_message:
|
|
42
|
+
rdoc_options: []
|
|
43
|
+
require_paths:
|
|
44
|
+
- lib
|
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
46
|
+
requirements:
|
|
47
|
+
- - '>='
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: '0'
|
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - '>='
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
requirements: []
|
|
56
|
+
rubyforge_project:
|
|
57
|
+
rubygems_version: 2.0.0
|
|
58
|
+
signing_key:
|
|
59
|
+
specification_version: 4
|
|
60
|
+
summary: Maybe monad implementation for Ruby
|
|
61
|
+
test_files: []
|