dentaku 0.2.12 → 0.2.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/README.md +41 -8
- data/dentaku.gemspec +0 -1
- data/lib/dentaku/binary_operation.rb +2 -0
- data/lib/dentaku/calculator.rb +11 -0
- data/lib/dentaku/evaluator.rb +11 -1
- data/lib/dentaku/rules.rb +33 -3
- data/lib/dentaku/token_matcher.rb +12 -0
- data/lib/dentaku/token_scanner.rb +3 -3
- data/lib/dentaku/version.rb +1 -1
- data/spec/binary_operation_spec.rb +4 -0
- data/spec/calculator_spec.rb +15 -0
- data/spec/evaluator_spec.rb +6 -0
- data/spec/external_function_spec.rb +44 -0
- data/spec/spec_helper.rb +1 -1
- metadata +16 -23
- data/MIT-LICENSE.txt +0 -21
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bc04ff45c34b77ede3ebb41f6ed34a94413925ac
|
4
|
+
data.tar.gz: 19906fc893a540448be14ed1374cc1cb89b7c999
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b8ef9498e64f6050bc7fd587b5c3cae3c0489bc050810601c70820d233a03bd586ed37567b186a423a397c1571e0cb02828ed17126627b1764e7c089abe36dfd
|
7
|
+
data.tar.gz: a5d0ee82db757582c697bfb721b27a9670cf46b790b17839967fd40fc52bdaf0e91a9839be73504da6bd026fbcb750edd7235c53d23f7930aec89da77b4f839a
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -48,22 +48,23 @@ to ensure proper evaluation:
|
|
48
48
|
calculator.evaluate('(5 + 3) * 2')
|
49
49
|
=> 16
|
50
50
|
|
51
|
-
A number of functions are also supported. Okay, the number is currently
|
52
|
-
but more will be added soon. The current functions are
|
53
|
-
they work like their counterparts in Excel:
|
51
|
+
A number of functions are also supported. Okay, the number is currently five,
|
52
|
+
but more will be added soon. The current functions are
|
53
|
+
`if`, `not`, `round`, `rounddown`, and `roundup`, and they work like their counterparts in Excel:
|
54
54
|
|
55
55
|
calculator.evaluate('if (pears < 10, 10, 20)', :pears => 5)
|
56
56
|
=> 10
|
57
57
|
calculator.evaluate('if (pears < 10, 10, 20)', :pears => 15)
|
58
58
|
=> 20
|
59
59
|
|
60
|
-
`
|
60
|
+
`round`, `rounddown`, and `roundup` can be called with or without the number of decimal places:
|
61
61
|
|
62
62
|
calculator.evaluate('round(8.2)')
|
63
63
|
=> 8
|
64
64
|
calculator.evaluate('round(8.2759, 2)')
|
65
65
|
=> 8.28
|
66
66
|
|
67
|
+
`round` and `rounddown` round down, while `roundup` rounds up.
|
67
68
|
|
68
69
|
If you're too lazy to be building calculator objects, there's a shortcut just
|
69
70
|
for you:
|
@@ -72,12 +73,44 @@ for you:
|
|
72
73
|
=> 3.0
|
73
74
|
|
74
75
|
|
75
|
-
|
76
|
+
BUILT-IN OPERATORS AND FUNCTIONS
|
76
77
|
---------------------------------
|
77
78
|
|
78
|
-
Math: `+ - *
|
79
|
-
Logic: `< > <= >= <> != = AND OR
|
80
|
-
Functions: `IF ROUND`
|
79
|
+
Math: `+ - * / %`
|
80
|
+
Logic: `< > <= >= <> != = AND OR`
|
81
|
+
Functions: `IF NOT ROUND ROUNDDOWN ROUNDUP`
|
82
|
+
|
83
|
+
|
84
|
+
EXTERNAL FUNCTIONS
|
85
|
+
------------------
|
86
|
+
|
87
|
+
See `spec/external_function_spec.rb` for examples of how to add your own functions.
|
88
|
+
|
89
|
+
The short, dense version:
|
90
|
+
|
91
|
+
Each rule for an external function consists of three parts: the function's name,
|
92
|
+
a list of tokens describing its signature (parameters), and a lambda representing the
|
93
|
+
function's body.
|
94
|
+
|
95
|
+
The function name should be passed as a symbol (for example, `:func`).
|
96
|
+
|
97
|
+
The token list should consist of `:numeric` or `:string` if a single value of the named
|
98
|
+
type should be passed; `:non_group` or `:non_group_star` for grouped expressions.
|
99
|
+
|
100
|
+
> (what's the difference? when would you use one instead of the other?)
|
101
|
+
|
102
|
+
The function body should accept a list of parameters. Each function body will be passed
|
103
|
+
a sequence of tokens, in order:
|
104
|
+
|
105
|
+
1. The function's name
|
106
|
+
2. A token representing the opening parenthesis
|
107
|
+
3. Tokens representing the parameter values, separated by tokens representing the commas between parameters
|
108
|
+
4. A token representing the closing parenthesis
|
109
|
+
|
110
|
+
It should return a token (either `:numeric` or `:string`) representing the return value.
|
111
|
+
|
112
|
+
Rules can be set individually using Calculator#add_rule, or en masse using Calculator#add_rules.
|
113
|
+
|
81
114
|
|
82
115
|
THANKS
|
83
116
|
------
|
data/dentaku.gemspec
CHANGED
data/lib/dentaku/calculator.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'dentaku/evaluator'
|
2
|
+
require 'dentaku/rules'
|
2
3
|
require 'dentaku/token'
|
3
4
|
require 'dentaku/tokenizer'
|
4
5
|
|
@@ -10,6 +11,16 @@ module Dentaku
|
|
10
11
|
clear
|
11
12
|
end
|
12
13
|
|
14
|
+
def add_rule(new_rule)
|
15
|
+
Rules.add_rule new_rule
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_rules(new_rules)
|
20
|
+
new_rules.each { | r | Rules.add_rule r }
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
13
24
|
def evaluate(expression, data={})
|
14
25
|
@tokenizer ||= Tokenizer.new
|
15
26
|
@tokens = @tokenizer.tokenize(expression)
|
data/lib/dentaku/evaluator.rb
CHANGED
@@ -55,7 +55,13 @@ module Dentaku
|
|
55
55
|
|
56
56
|
def evaluate_step(token_stream, start, length, evaluator)
|
57
57
|
expr = token_stream.slice!(start, length)
|
58
|
-
|
58
|
+
if self.respond_to?(evaluator)
|
59
|
+
token_stream.insert start, *self.send(evaluator, *expr)
|
60
|
+
else
|
61
|
+
func = Rules.func(evaluator)
|
62
|
+
raise "unknown evaluator '#{evaluator.to_s}'" if func.nil?
|
63
|
+
token_stream.insert start, *(func.call(*expr))
|
64
|
+
end
|
59
65
|
end
|
60
66
|
|
61
67
|
def evaluate_group(*args)
|
@@ -68,6 +74,10 @@ module Dentaku
|
|
68
74
|
Token.new(*operation.send(operator.value))
|
69
75
|
end
|
70
76
|
|
77
|
+
def negate(_, token)
|
78
|
+
Token.new(token.category,token.value * -1)
|
79
|
+
end
|
80
|
+
|
71
81
|
def expand_range(left, oper1, middle, oper2, right)
|
72
82
|
[left, oper1, middle, Token.new(:combinator, :and), middle, oper2, right]
|
73
83
|
end
|
data/lib/dentaku/rules.rb
CHANGED
@@ -3,8 +3,8 @@ require 'dentaku/token_matcher'
|
|
3
3
|
|
4
4
|
module Dentaku
|
5
5
|
class Rules
|
6
|
-
def self.
|
7
|
-
|
6
|
+
def self.core_rules
|
7
|
+
[
|
8
8
|
[ p(:if), :if ],
|
9
9
|
[ p(:round_one), :round ],
|
10
10
|
[ p(:round_two), :round ],
|
@@ -14,21 +14,49 @@ module Dentaku
|
|
14
14
|
|
15
15
|
[ p(:group), :evaluate_group ],
|
16
16
|
[ p(:math_pow), :apply ],
|
17
|
+
[ p(:math_mod), :apply ],
|
17
18
|
[ p(:math_mul), :apply ],
|
18
19
|
[ p(:math_add), :apply ],
|
20
|
+
[ p(:negation), :negate ],
|
19
21
|
[ p(:range_asc), :expand_range ],
|
20
22
|
[ p(:range_desc), :expand_range ],
|
21
23
|
[ p(:num_comp), :apply ],
|
22
24
|
[ p(:str_comp), :apply ],
|
23
25
|
[ p(:combine), :apply ]
|
24
26
|
]
|
27
|
+
end
|
25
28
|
|
29
|
+
def self.each
|
30
|
+
@rules ||= core_rules
|
26
31
|
@rules.each { |r| yield r }
|
27
32
|
end
|
28
33
|
|
34
|
+
def self.add_rule(new_rule)
|
35
|
+
@rules ||= core_rules
|
36
|
+
@funcs ||= {}
|
37
|
+
name = new_rule[:name].to_sym
|
38
|
+
|
39
|
+
## rules need to be added to the beginning of @rules; for precedence?
|
40
|
+
@rules.unshift [
|
41
|
+
[
|
42
|
+
TokenMatcher.send(name),
|
43
|
+
t(:open),
|
44
|
+
*pattern(*new_rule[:tokens]),
|
45
|
+
t(:close),
|
46
|
+
],
|
47
|
+
name
|
48
|
+
]
|
49
|
+
@funcs[name] = new_rule[:body]
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.func(name)
|
53
|
+
@funcs ||= {}
|
54
|
+
@funcs[name]
|
55
|
+
end
|
56
|
+
|
29
57
|
def self.t(name)
|
30
58
|
@matchers ||= [
|
31
|
-
:numeric, :string, :addsub, :muldiv, :pow,
|
59
|
+
:numeric, :string, :addsub, :subtract, :muldiv, :pow, :mod,
|
32
60
|
:comparator, :comp_gt, :comp_lt,
|
33
61
|
:open, :close, :comma,
|
34
62
|
:non_group, :non_group_star,
|
@@ -47,6 +75,8 @@ module Dentaku
|
|
47
75
|
math_add: pattern(:numeric, :addsub, :numeric),
|
48
76
|
math_mul: pattern(:numeric, :muldiv, :numeric),
|
49
77
|
math_pow: pattern(:numeric, :pow, :numeric),
|
78
|
+
math_mod: pattern(:numeric, :mod, :numeric),
|
79
|
+
negation: pattern(:subtract, :numeric),
|
50
80
|
range_asc: pattern(:numeric, :comp_lt, :numeric, :comp_lt, :numeric),
|
51
81
|
range_desc: pattern(:numeric, :comp_gt, :numeric, :comp_gt, :numeric),
|
52
82
|
num_comp: pattern(:numeric, :comparator, :numeric),
|
@@ -61,8 +61,10 @@ module Dentaku
|
|
61
61
|
def self.numeric; new(:numeric); end
|
62
62
|
def self.string; new(:string); end
|
63
63
|
def self.addsub; new(:operator, [:add, :subtract]); end
|
64
|
+
def self.subtract; new(:operator, :subtract); end
|
64
65
|
def self.muldiv; new(:operator, [:multiply, :divide]); end
|
65
66
|
def self.pow; new(:operator, :pow); end
|
67
|
+
def self.mod; new(:operator, :mod); end
|
66
68
|
def self.comparator; new(:comparator); end
|
67
69
|
def self.comp_gt; new(:comparator, [:gt, :ge]); end
|
68
70
|
def self.comp_lt; new(:comparator, [:lt, :le]); end
|
@@ -78,6 +80,16 @@ module Dentaku
|
|
78
80
|
def self.not; new(:function, :not); end
|
79
81
|
def self.non_group; new(:grouping).invert; end
|
80
82
|
def self.non_group_star; new(:grouping).invert.star; end
|
83
|
+
|
84
|
+
|
85
|
+
def self.method_missing(name, *args, &block)
|
86
|
+
new(:function, name)
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.respond_to_missing?(name, include_priv)
|
90
|
+
true
|
91
|
+
end
|
92
|
+
|
81
93
|
end
|
82
94
|
end
|
83
95
|
|
@@ -52,8 +52,8 @@ module Dentaku
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def operator
|
55
|
-
names = { pow: '^', add: '+', subtract: '-', multiply: '*', divide: '/' }.invert
|
56
|
-
new(:operator, '
|
55
|
+
names = { pow: '^', add: '+', subtract: '-', multiply: '*', divide: '/', mod: '%' }.invert
|
56
|
+
new(:operator, '\^|\+|-|\*|\/|%', lambda { |raw| names[raw] })
|
57
57
|
end
|
58
58
|
|
59
59
|
def grouping
|
@@ -72,7 +72,7 @@ module Dentaku
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def function
|
75
|
-
new(:function, '(
|
75
|
+
new(:function, '(\w+\s*(?=\())', lambda {|raw| raw.strip.downcase.to_sym })
|
76
76
|
end
|
77
77
|
|
78
78
|
def identifier
|
data/lib/dentaku/version.rb
CHANGED
data/spec/calculator_spec.rb
CHANGED
@@ -72,10 +72,17 @@ describe Dentaku::Calculator do
|
|
72
72
|
calculator.evaluate('some_boolean AND 7 > 5', :some_boolean => true).should be_true
|
73
73
|
calculator.evaluate('some_boolean AND 7 < 5', :some_boolean => true).should be_false
|
74
74
|
calculator.evaluate('some_boolean AND 7 > 5', :some_boolean => false).should be_false
|
75
|
+
|
76
|
+
calculator.evaluate('some_boolean OR 7 > 5', :some_boolean => true).should be_true
|
77
|
+
calculator.evaluate('some_boolean OR 7 < 5', :some_boolean => true).should be_true
|
78
|
+
calculator.evaluate('some_boolean OR 7 < 5', :some_boolean => false).should be_false
|
79
|
+
|
75
80
|
end
|
76
81
|
|
77
82
|
describe 'functions' do
|
78
83
|
it 'should include IF' do
|
84
|
+
calculator.evaluate('if(foo < 8, 10, 20)', :foo => 2).should eq(10)
|
85
|
+
calculator.evaluate('if(foo < 8, 10, 20)', :foo => 9).should eq(20)
|
79
86
|
calculator.evaluate('if (foo < 8, 10, 20)', :foo => 2).should eq(10)
|
80
87
|
calculator.evaluate('if (foo < 8, 10, 20)', :foo => 9).should eq(20)
|
81
88
|
end
|
@@ -87,5 +94,13 @@ describe Dentaku::Calculator do
|
|
87
94
|
|
88
95
|
calculator.evaluate('ROUND(apples * 0.93)', { :apples => 10 }).should eq(9)
|
89
96
|
end
|
97
|
+
|
98
|
+
it 'should include NOT' do
|
99
|
+
calculator.evaluate('NOT(some_boolean)', :some_boolean => true).should be_false
|
100
|
+
calculator.evaluate('NOT(some_boolean)', :some_boolean => false).should be_true
|
101
|
+
|
102
|
+
calculator.evaluate('NOT(some_boolean) AND 7 > 5', :some_boolean => true).should be_false
|
103
|
+
calculator.evaluate('NOT(some_boolean) OR 7 < 5', :some_boolean => false).should be_true
|
104
|
+
end
|
90
105
|
end
|
91
106
|
end
|
data/spec/evaluator_spec.rb
CHANGED
@@ -41,6 +41,11 @@ describe Dentaku::Evaluator do
|
|
41
41
|
evaluator.evaluate_step(stream, 0, 5, :evaluate_group).should eq(expected)
|
42
42
|
end
|
43
43
|
|
44
|
+
it 'supports unary minus' do
|
45
|
+
evaluator.evaluate(token_stream(:subtract, 1)).should eq(-1)
|
46
|
+
evaluator.evaluate(token_stream(1, :subtract, :subtract, 1)).should eq(2)
|
47
|
+
end
|
48
|
+
|
44
49
|
describe 'maths' do
|
45
50
|
it 'should perform addition' do
|
46
51
|
evaluator.evaluate(token_stream(1, :add, 1)).should eq(2)
|
@@ -48,6 +53,7 @@ describe Dentaku::Evaluator do
|
|
48
53
|
|
49
54
|
it 'should respect order of precedence' do
|
50
55
|
evaluator.evaluate(token_stream(1, :add, 1, :multiply, 5)).should eq(6)
|
56
|
+
evaluator.evaluate(token_stream(2, :add, 10, :mod, 2)).should eq(2)
|
51
57
|
end
|
52
58
|
|
53
59
|
it 'should respect explicit grouping' do
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'dentaku/calculator'
|
2
|
+
|
3
|
+
describe Dentaku::Calculator do
|
4
|
+
describe 'functions' do
|
5
|
+
describe 'external functions' do
|
6
|
+
|
7
|
+
let(:with_external_funcs) do
|
8
|
+
c = described_class.new
|
9
|
+
|
10
|
+
rule = { :name => :now, :tokens => [], :body => ->(*args) { Dentaku::Token.new(:string, Time.now.to_s) } }
|
11
|
+
c.add_rule rule
|
12
|
+
|
13
|
+
new_rules = [
|
14
|
+
{
|
15
|
+
:name => :exp,
|
16
|
+
:tokens => [ :non_group_star, :comma, :non_group_star ],
|
17
|
+
:body => ->(*args) do
|
18
|
+
## first one is function name
|
19
|
+
## second one is open parenthesis
|
20
|
+
## last one is close parenthesis
|
21
|
+
## all others are commas
|
22
|
+
_, _, mantissa, _, exponent, _ = args
|
23
|
+
Dentaku::Token.new(:numeric, (mantissa.value ** exponent.value))
|
24
|
+
end
|
25
|
+
},
|
26
|
+
]
|
27
|
+
|
28
|
+
c.add_rules new_rules
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should include NOW' do
|
32
|
+
now = with_external_funcs.evaluate('NOW()')
|
33
|
+
now.should_not be_nil
|
34
|
+
now.should_not be_empty
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should include EXP' do
|
38
|
+
with_external_funcs.evaluate('EXP(2,3)').should eq(8)
|
39
|
+
with_external_funcs.evaluate('EXP(3,2)').should eq(9)
|
40
|
+
with_external_funcs.evaluate('EXP(mantissa,exponent)', :mantissa => 2, :exponent => 4).should eq(16)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,51 +1,45 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dentaku
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
5
|
-
prerelease:
|
4
|
+
version: 0.2.13
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Solomon White
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-01-17 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rake
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rspec
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - '>='
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - '>='
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
|
-
description:
|
47
|
-
|
48
|
-
'
|
41
|
+
description: |2
|
42
|
+
Dentaku is a parser and evaluator for mathematical formulas
|
49
43
|
email:
|
50
44
|
- rubysolo@gmail.com
|
51
45
|
executables: []
|
@@ -55,7 +49,6 @@ files:
|
|
55
49
|
- .gitignore
|
56
50
|
- .travis.yml
|
57
51
|
- Gemfile
|
58
|
-
- MIT-LICENSE.txt
|
59
52
|
- README.md
|
60
53
|
- Rakefile
|
61
54
|
- dentaku.gemspec
|
@@ -73,41 +66,41 @@ files:
|
|
73
66
|
- spec/calculator_spec.rb
|
74
67
|
- spec/dentaku_spec.rb
|
75
68
|
- spec/evaluator_spec.rb
|
69
|
+
- spec/external_function_spec.rb
|
76
70
|
- spec/spec_helper.rb
|
77
71
|
- spec/token_matcher_spec.rb
|
78
72
|
- spec/token_scanner_spec.rb
|
79
73
|
- spec/token_spec.rb
|
80
74
|
- spec/tokenizer_spec.rb
|
81
75
|
homepage: http://github.com/rubysolo/dentaku
|
82
|
-
licenses:
|
83
|
-
|
76
|
+
licenses: []
|
77
|
+
metadata: {}
|
84
78
|
post_install_message:
|
85
79
|
rdoc_options: []
|
86
80
|
require_paths:
|
87
81
|
- lib
|
88
82
|
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
83
|
requirements:
|
91
|
-
- -
|
84
|
+
- - '>='
|
92
85
|
- !ruby/object:Gem::Version
|
93
86
|
version: '0'
|
94
87
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
-
none: false
|
96
88
|
requirements:
|
97
|
-
- -
|
89
|
+
- - '>='
|
98
90
|
- !ruby/object:Gem::Version
|
99
91
|
version: '0'
|
100
92
|
requirements: []
|
101
93
|
rubyforge_project: dentaku
|
102
|
-
rubygems_version:
|
94
|
+
rubygems_version: 2.0.3
|
103
95
|
signing_key:
|
104
|
-
specification_version:
|
96
|
+
specification_version: 4
|
105
97
|
summary: A formula language parser and evaluator
|
106
98
|
test_files:
|
107
99
|
- spec/binary_operation_spec.rb
|
108
100
|
- spec/calculator_spec.rb
|
109
101
|
- spec/dentaku_spec.rb
|
110
102
|
- spec/evaluator_spec.rb
|
103
|
+
- spec/external_function_spec.rb
|
111
104
|
- spec/spec_helper.rb
|
112
105
|
- spec/token_matcher_spec.rb
|
113
106
|
- spec/token_scanner_spec.rb
|
data/MIT-LICENSE.txt
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
The MIT License (MIT)
|
2
|
-
|
3
|
-
Copyright (c) 2012 Solomon White
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
7
|
-
in the Software without restriction, including without limitation the rights
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
10
|
-
furnished to do so, subject to the following conditions:
|
11
|
-
|
12
|
-
The above copyright notice and this permission notice shall be included in
|
13
|
-
all copies or substantial portions of the Software.
|
14
|
-
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
THE SOFTWARE.
|