rnotifier 0.0.6 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/lib/rnotifier.rb CHANGED
@@ -1,15 +1,53 @@
1
+ require 'socket'
2
+ require 'yaml'
3
+ require 'digest/md5'
4
+ require 'multi_json'
5
+ require 'faraday'
6
+
1
7
  require 'rnotifier/version'
2
- require 'net/http'
3
- require 'json'
4
- require 'logger'
5
- require 'action_mailer'
8
+ require 'rnotifier/config'
9
+ require 'rnotifier/rlogger'
10
+ require 'rnotifier/notifier'
11
+ require 'rnotifier/exception_data'
12
+ require 'rnotifier/rack_middleware'
13
+ require 'rnotifier/parameter_filter'
14
+ require 'rnotifier/exception_code'
15
+ require 'rnotifier/railtie' if defined?(Rails)
6
16
 
7
17
  module Rnotifier
8
- autoload :Notifier, 'rnotifier/notifier'
9
- autoload :Configuration, 'rnotifier/configuration'
10
- autoload :RailsException, 'rnotifier/rails_exception'
11
- autoload :EmailNotifier, 'rnotifier/email_notifier'
12
- autoload :Util, 'rnotifier/util'
13
- autoload :Rlogger, 'rnotifier/rlogger'
14
- end
18
+ class << self
19
+ def config(&block)
20
+ yield(Rnotifier::Config)
21
+ Rnotifier::Config.init
22
+ end
23
+
24
+ def load_config(file)
25
+ config_yaml = YAML.load_file(file)
26
+
27
+ self.config do |c|
28
+ c.api_key = config_yaml['apikey']
29
+
30
+ ['environments', 'api_host', 'ignore_exceptions', 'capture_code'].each do |f|
31
+ c.send("#{f}=", config_yaml[f]) if config_yaml[f]
32
+ end
33
+ end
34
+ end
15
35
 
36
+ def context(attrs = {})
37
+ if Thread.current[:rnotifier_context]
38
+ Thread.current[:rnotifier_context].merge!(attrs)
39
+ else
40
+ Thread.current[:rnotifier_context] = attrs
41
+ end
42
+ end
43
+
44
+ def clear_context
45
+ Thread.current[:rnotifier_context] = nil
46
+ end
47
+
48
+ def send_exception(exception, opts = {})
49
+ Rnotifier::ExceptionData.new(exception, opts, {:type => :rescue}).notify
50
+ end
51
+
52
+ end
53
+ end
data/rnotifier.gemspec CHANGED
@@ -1,19 +1,28 @@
1
- # -*- encoding: utf-8 -*-
2
- require File.expand_path('../lib/rnotifier/version', __FILE__)
3
- #require "rnotifier/version"
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rnotifier/version'
4
5
 
5
- Gem::Specification.new do |gem|
6
- gem.authors = ["Jiren Patel"]
7
- gem.email = ["jiren@joshsoftware.com"]
8
- gem.description = %q{Rails 3 Exception catcher}
9
- gem.summary = %q{Rails 3 Exception catcher}
10
- gem.homepage = "https://github.com/jiren/rnotifier"
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'rnotifier'
8
+ spec.version = Rnotifier::VERSION
9
+ spec.authors = ['Jiren Patel']
10
+ spec.email = ['jirenpatel@gmail.com']
11
+ spec.description = %q{Exception catcher}
12
+ spec.summary = %q{Exception catcher for Rails and other Rack apps}
13
+ spec.homepage = 'https://github.com/jiren/rnotifier'
14
+ spec.license = 'MIT'
11
15
 
12
- gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
13
- gem.files = `git ls-files`.split("\n")
14
- gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
- gem.name = "rnotifier"
16
- gem.require_paths = ["lib"]
17
- gem.version = Rnotifier::VERSION
18
- gem.add_dependency('json', '>= 1.5.3')
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'faraday', '>= 0.8.7'
22
+ spec.add_dependency 'multi_json', '>= 1.7.2'
23
+ spec.add_development_dependency 'bundler', '~> 1.3'
24
+ spec.add_development_dependency 'rake'
25
+ spec.add_development_dependency 'sinatra'
26
+ spec.add_development_dependency 'rspec-rails'
27
+ spec.add_development_dependency 'rspec-expectations'
19
28
  end
data/spec/code.text ADDED
@@ -0,0 +1,18 @@
1
+ class User
2
+
3
+ attr_accessor :name, :address_1, :address_2
4
+
5
+ def initialize(name, address_1)
6
+ @name = name
7
+ @address_1 = address_1
8
+ end
9
+
10
+ def address
11
+ "#{@address_1} #{@address_2}"
12
+ end
13
+
14
+ def serach(q)
15
+ Tire.search(q)
16
+ end
17
+
18
+ end
@@ -0,0 +1,60 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+ require 'spec_helper'
3
+
4
+ describe Rnotifier::Config do
5
+ before(:all) do
6
+ @api_key = 'API-KEY'
7
+ @notification_path = '/' + [ Rnotifier::Config::DEFAULT[:api_version],
8
+ Rnotifier::Config::DEFAULT[:notify_path],
9
+ @api_key].join('/')
10
+ end
11
+
12
+ before(:each) do
13
+ ENV['RACK_ENV'] = @environments = 'production'
14
+
15
+ Rnotifier.config do |c|
16
+ c.api_key = @api_key
17
+ #c.environments = @environments
18
+ end
19
+ end
20
+
21
+ after(:each) do
22
+ ENV['RACK_ENV'] = 'test'
23
+ end
24
+
25
+ it 'has default config values' do
26
+ Rnotifier::Config.tap do |c|
27
+ expect(c.current_env).to eq @environments
28
+ expect(c.notification_path).to eq @notification_path
29
+ expect(c.api_key).to eq @api_key
30
+ end
31
+ end
32
+
33
+ it 'is invalid if config environments not include current env' do
34
+ ENV['RACK_ENV'] = 'staging'
35
+ Rnotifier.config{|c| c.environments = 'production'}
36
+ expect(Rnotifier::Config.valid?).to be_false
37
+ end
38
+
39
+ it 'is valid if config environments set to test or development' do
40
+ ['test', 'development'].each do |e|
41
+ ENV['RACK_ENV'] = e
42
+ Rnotifier.config{|c| c.environments = e}
43
+ expect(Rnotifier::Config.valid?).to be_true
44
+ end
45
+ end
46
+
47
+ it 'is invalid if api key blank' do
48
+ Rnotifier.config{|c| c.api_key = nil}
49
+ expect(Rnotifier::Config.valid?).to be_false
50
+ end
51
+
52
+ it 'is load config from the yaml file' do
53
+ Rnotifier.load_config("#{Dir.pwd}/spec/fixtures/rnotifier.yaml")
54
+
55
+ expect(Rnotifier::Config.api_key).to eq @api_key
56
+ expect(Rnotifier::Config.environments).to eq ['production', 'staging']
57
+ expect(Rnotifier::Config.valid?).to be_true
58
+ end
59
+
60
+ end
@@ -0,0 +1,48 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+ require 'spec_helper'
3
+
4
+ describe Rnotifier::ExceptionCode do
5
+
6
+ before(:all) do
7
+ @file = Dir.pwd + '/spec/code.text'
8
+ @lines = File.readlines(@file)
9
+ @total_lines = 18
10
+ end
11
+
12
+ it 'collect error line' do
13
+ code = Rnotifier::ExceptionCode.find(@file, 5, 0)
14
+
15
+ expect(code[0]).to eq (5 - 1)
16
+ expect(code[1]).to eq @lines[4]
17
+ end
18
+
19
+ it 'collect error line with range context' do
20
+ code = Rnotifier::ExceptionCode.find(@file, 5, 3)
21
+ expect(code[0]).to eq (5 - 3 - 1)
22
+
23
+ @lines[code[0]..(5 + 3 - 1)].each_with_index do |l, i|
24
+ expect(code[i+1]).to eq l
25
+ end
26
+
27
+ end
28
+
29
+ it 'collect error line from the file start' do
30
+ code = Rnotifier::ExceptionCode.find(@file, 1, 3)
31
+ expect(code[0]).to eq 0
32
+
33
+ @lines[code[0]..3].each_with_index do |l, i|
34
+ expect(code[i+1]).to eq l
35
+ end
36
+ end
37
+
38
+ it 'collect error line from the end of file' do
39
+ code = Rnotifier::ExceptionCode.find(@file, @lines.count, 3)
40
+ expect(code[0]).to eq (@lines.count - 3 - 1)
41
+
42
+ @lines[code[0]..-1].each_with_index do |l, i|
43
+ expect(code[i+1]).to eq l
44
+ end
45
+ end
46
+
47
+
48
+ end
@@ -0,0 +1,60 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+ require 'spec_helper'
3
+
4
+ describe Rnotifier::ExceptionData do
5
+
6
+ before(:all) do
7
+ rnotifier_init
8
+ @exception = mock_exception
9
+ @options = {:type => :rack}
10
+ @url = 'http://example.com/?foo=bar&quux=bla'
11
+ @vars = {
12
+ 'HTTP_REFERER' => 'http://localhost:3000/',
13
+ 'HTTP_COOKIE' => '_test_app_session=yYUhYSVc1U291M2I5TWpsN0E9BjsARg%3D%3D--6d69651b1cfb6a98387eb2fd01005955b2ca5406; _gauges_unique=1;'
14
+ }
15
+ @env = Rack::MockRequest.env_for(@url, @vars)
16
+ end
17
+
18
+ it 'is initialize exception_data object for rack' do
19
+ e_data = Rnotifier::ExceptionData.new(@exception, @env, @options)
20
+
21
+ expect(e_data.exception).to eq @exception
22
+ expect(e_data.options).to eq @options
23
+ expect(e_data.request).to be_an_instance_of(Rack::Request)
24
+ end
25
+
26
+ it 'is build rack exception data' do
27
+ e_data = Rnotifier::ExceptionData.new(@exception, @env, @options)
28
+ data = e_data.rack_exception_data
29
+ request_data = data[:request]
30
+
31
+ expect(request_data[:url]).to eq @url
32
+ expect(request_data[:http_method]).to eq 'GET'
33
+ expect(request_data[:referer_url]).to eq @vars['HTTP_REFERER']
34
+
35
+ headers = {'referer' => @vars['HTTP_REFERER'], 'cookie' => '_test_app_session=[FILTERED] _gauges_unique=1;'}
36
+ expect(request_data[:headers]).to eq headers
37
+ expect(request_data[:params]).to eq({'foo' => 'bar', 'quux' => 'bla'})
38
+
39
+ exception_data = data[:exception]
40
+ expect(exception_data[:class_name]).to eq @exception.class.to_s
41
+ expect(exception_data[:message]).to eq @exception.message
42
+ end
43
+
44
+ it 'is filter parameters' do
45
+
46
+ env = Rack::MockRequest.env_for(@url, {
47
+ 'action_dispatch.parameter_filter' =>[:password],
48
+ 'REQUEST_METHOD' => 'POST',
49
+ :input => 'password=foo&useranme=bar'
50
+ })
51
+
52
+ e_data = Rnotifier::ExceptionData.new(@exception, env, @options)
53
+ params = e_data.rack_exception_data[:request][:params]
54
+
55
+ expect(params).to include({'password' => '[FILTERED]'})
56
+ expect(params).to include({'useranme' => 'bar'})
57
+ end
58
+
59
+
60
+ end
@@ -0,0 +1,21 @@
1
+ require 'sinatra'
2
+ require 'sinatra/base'
3
+
4
+ module RnotifierTest
5
+
6
+ class FakeApp < Sinatra::Base
7
+ use Rnotifier::RackMiddleware, 'spec/fixtures/rnotifier_test.yaml'
8
+
9
+ get '/' do
10
+ [200, {}, 'OK']
11
+ end
12
+
13
+ get '/exception/1' do
14
+ 1 + '2'
15
+
16
+ [200, {}, 'OK']
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,2 @@
1
+ apikey: API-KEY
2
+ environments: production,staging
@@ -0,0 +1,2 @@
1
+ apikey: API-KEY
2
+ environments: test
@@ -0,0 +1,22 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+ require 'spec_helper'
3
+
4
+ describe Rnotifier::RackMiddleware do
5
+
6
+ before(:all) do
7
+ @type_error = "TypeError - String can't be coerced into Fixnum"
8
+ end
9
+
10
+ before(:each) do
11
+ @stubs = stub_faraday_request
12
+ end
13
+
14
+ it 'sends get request and catch exception' do
15
+ get "/exception/1"
16
+
17
+ expect(last_response.errors.split(/:\n/).first).to eq @type_error
18
+ expect(last_response.status).to eq 500
19
+ expect { @stubs.verify_stubbed_calls }.to_not raise_error
20
+ end
21
+
22
+ end
@@ -0,0 +1,59 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'open-uri'
4
+ require 'rack'
5
+ require 'rack/request'
6
+ require 'rack/mock'
7
+ require 'rack/test'
8
+ require 'rnotifier'
9
+
10
+ require File.dirname(__FILE__) + "/fixtures/fake_app"
11
+
12
+ RSpec.configure do |config|
13
+ config.color_enabled = true
14
+ #config.tty = true
15
+ #config.formatter = :documentation
16
+ config.include Rack::Test::Methods
17
+
18
+ def app
19
+ Rack::Lint.new(RnotifierTest::FakeApp.new)
20
+ end
21
+ end
22
+
23
+ $:.unshift(File.dirname(__FILE__) + '/../lib/')
24
+
25
+ ENV['RACK_ENV'] = 'test'
26
+
27
+ require 'rnotifier'
28
+
29
+ def rnotifier_init
30
+ ENV['RACK_ENV'] = 'test'
31
+ Rnotifier.load_config("#{Dir.pwd}/spec/fixtures/rnotifier.yaml")
32
+ end
33
+
34
+ def set_test_adapter
35
+ end
36
+
37
+ def stub_faraday_request(opts = {})
38
+ opts[:status] ||= 200
39
+ opts[:message] ||= 'ok'
40
+ opts[:path] = '/' + [ Rnotifier::Config::DEFAULT[:api_version], Rnotifier::Config::DEFAULT[:notify_path], 'API-KEY'].join('/')
41
+
42
+ stubs = Faraday::Adapter::Test::Stubs.new
43
+ conn = Faraday.new do |builder|
44
+ builder.adapter :test, stubs
45
+ end
46
+ stubs.post(opts[:path]) {|env| [opts[:status], {}, opts[:message]] }
47
+
48
+ Rnotifier::Notifier.instance_variable_set('@connection', conn)
49
+ stubs
50
+ end
51
+
52
+ def mock_exception
53
+ begin
54
+ 1 + '2'
55
+ rescue Exception => e
56
+ return e
57
+ end
58
+ end
59
+
metadata CHANGED
@@ -1,97 +1,180 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: rnotifier
3
- version: !ruby/object:Gem::Version
4
- hash: 19
5
- prerelease:
6
- segments:
7
- - 0
8
- - 0
9
- - 6
10
- version: 0.0.6
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.8
11
5
  platform: ruby
12
- authors:
6
+ authors:
13
7
  - Jiren Patel
14
8
  autorequire:
15
9
  bindir: bin
16
10
  cert_chain: []
17
-
18
- date: 2011-11-28 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- version_requirements: &id001 !ruby/object:Gem::Requirement
22
- none: false
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- hash: 5
27
- segments:
28
- - 1
29
- - 5
30
- - 3
31
- version: 1.5.3
11
+ date: 2013-07-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.8.7
20
+ type: :runtime
32
21
  prerelease: false
33
- requirement: *id001
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.8.7
27
+ - !ruby/object:Gem::Dependency
28
+ name: multi_json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 1.7.2
34
34
  type: :runtime
35
- name: json
36
- description: Rails 3 Exception catcher
37
- email:
38
- - jiren@joshsoftware.com
39
- executables: []
40
-
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 1.7.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sinatra
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec-rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec-expectations
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Exception catcher
112
+ email:
113
+ - jirenpatel@gmail.com
114
+ executables:
115
+ - rnotifier
41
116
  extensions: []
42
-
43
117
  extra_rdoc_files: []
44
-
45
- files:
118
+ files:
46
119
  - .gitignore
47
120
  - Gemfile
48
- - LICENSE
121
+ - LICENSE.txt
49
122
  - README.md
50
123
  - Rakefile
124
+ - bin/rnotifier
51
125
  - lib/generators/rnotifier/rnotifier_generator.rb
52
126
  - lib/generators/rnotifier/templates/initializer.rb
53
127
  - lib/rnotifier.rb
54
- - lib/rnotifier/configuration.rb
55
- - lib/rnotifier/email_notifier.rb
128
+ - lib/rnotifier/config.rb
129
+ - lib/rnotifier/exception_code.rb
130
+ - lib/rnotifier/exception_data.rb
56
131
  - lib/rnotifier/notifier.rb
57
- - lib/rnotifier/rails_exception.rb
132
+ - lib/rnotifier/parameter_filter.rb
133
+ - lib/rnotifier/rack_middleware.rb
134
+ - lib/rnotifier/railtie.rb
58
135
  - lib/rnotifier/rlogger.rb
59
- - lib/rnotifier/util.rb
60
136
  - lib/rnotifier/version.rb
61
- - lib/rnotifier/views/email_notifier/exception_notify.html.erb
62
137
  - rnotifier.gemspec
138
+ - spec/code.text
139
+ - spec/config_spec.rb
140
+ - spec/exception_code_spec.rb
141
+ - spec/exception_data_spec.rb
142
+ - spec/fixtures/fake_app.rb
143
+ - spec/fixtures/rnotifier.yaml
144
+ - spec/fixtures/rnotifier_test.yaml
145
+ - spec/rack_middleware_spec.rb
146
+ - spec/spec_helper.rb
63
147
  homepage: https://github.com/jiren/rnotifier
64
- licenses: []
65
-
148
+ licenses:
149
+ - MIT
150
+ metadata: {}
66
151
  post_install_message:
67
152
  rdoc_options: []
68
-
69
- require_paths:
153
+ require_paths:
70
154
  - lib
71
- required_ruby_version: !ruby/object:Gem::Requirement
72
- none: false
73
- requirements:
74
- - - ">="
75
- - !ruby/object:Gem::Version
76
- hash: 3
77
- segments:
78
- - 0
79
- version: "0"
80
- required_rubygems_version: !ruby/object:Gem::Requirement
81
- none: false
82
- requirements:
83
- - - ">="
84
- - !ruby/object:Gem::Version
85
- hash: 3
86
- segments:
87
- - 0
88
- version: "0"
155
+ required_ruby_version: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ required_rubygems_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - '>='
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
89
165
  requirements: []
90
-
91
166
  rubyforge_project:
92
- rubygems_version: 1.8.11
167
+ rubygems_version: 2.0.3
93
168
  signing_key:
94
- specification_version: 3
95
- summary: Rails 3 Exception catcher
96
- test_files: []
97
-
169
+ specification_version: 4
170
+ summary: Exception catcher for Rails and other Rack apps
171
+ test_files:
172
+ - spec/code.text
173
+ - spec/config_spec.rb
174
+ - spec/exception_code_spec.rb
175
+ - spec/exception_data_spec.rb
176
+ - spec/fixtures/fake_app.rb
177
+ - spec/fixtures/rnotifier.yaml
178
+ - spec/fixtures/rnotifier_test.yaml
179
+ - spec/rack_middleware_spec.rb
180
+ - spec/spec_helper.rb
data/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- The MIT License
2
-
3
- Copyright (c) 2011 Jiren Patel[joshsoftware.com]
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.