thin 1.2.11 → 1.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.
- data/CHANGELOG +16 -0
- data/lib/thin.rb +1 -8
- data/lib/thin/connection.rb +0 -34
- data/lib/thin/controllers/service.rb +1 -1
- data/lib/thin/logging.rb +2 -2
- data/lib/thin/runner.rb +1 -1
- data/lib/thin/server.rb +4 -3
- data/lib/thin/version.rb +3 -3
- data/spec/backends/swiftiply_client_spec.rb +1 -1
- data/spec/backends/tcp_server_spec.rb +1 -1
- data/spec/backends/unix_server_spec.rb +1 -1
- data/spec/command_spec.rb +1 -1
- data/spec/connection_spec.rb +1 -1
- data/spec/controllers/cluster_spec.rb +1 -1
- data/spec/controllers/controller_spec.rb +1 -1
- data/spec/controllers/service_spec.rb +2 -2
- data/spec/daemonizing_spec.rb +10 -6
- data/spec/headers_spec.rb +1 -1
- data/spec/logging_spec.rb +8 -2
- data/spec/perf/request_perf_spec.rb +1 -1
- data/spec/perf/response_perf_spec.rb +1 -1
- data/spec/perf/server_perf_spec.rb +1 -1
- data/spec/rack/loader_spec.rb +1 -1
- data/spec/rack/rails_adapter_spec.rb +1 -1
- data/spec/request/mongrel_spec.rb +1 -1
- data/spec/request/parser_spec.rb +1 -1
- data/spec/request/persistent_spec.rb +1 -1
- data/spec/request/processing_spec.rb +1 -1
- data/spec/response_spec.rb +1 -1
- data/spec/runner_spec.rb +1 -1
- data/spec/server/builder_spec.rb +1 -1
- data/spec/server/pipelining_spec.rb +3 -3
- data/spec/server/robustness_spec.rb +1 -1
- data/spec/server/stopping_spec.rb +1 -1
- data/spec/server/swiftiply_spec.rb +1 -1
- data/spec/server/tcp_spec.rb +1 -11
- data/spec/server/threaded_spec.rb +2 -2
- data/spec/server/unix_socket_spec.rb +1 -1
- data/spec/server_spec.rb +1 -1
- data/spec/spec_helper.rb +16 -2
- data/tasks/gem.rake +1 -2
- data/tasks/spec.rake +1 -2
- metadata +4 -33
- data/COPYING +0 -18
data/CHANGELOG
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
== 1.3.0 Double Espresso
|
2
|
+
* BREAKING CHANGE: Thin no longer ships with fat Windows binaries.
|
3
|
+
From now on, to install on Windows, install https://github.com/oneclick/rubyinstaller/wiki/Development-Kit.
|
4
|
+
* BREAKING CHANGE: Remove automatic Content-Length setting.
|
5
|
+
It is now the responsibility of the app (or a middleware) to set the Content-Length.
|
6
|
+
* Log errors to STDERR [textgoeshere]
|
7
|
+
* Shut down gracefully when receiving SIGTERM [ddollar]
|
8
|
+
|
9
|
+
Processes are allowed a chance to shut down gracefully when receiving
|
10
|
+
SIGTERM (http://en.wikipedia.org/wiki/SIGTERM).
|
11
|
+
|
12
|
+
On Heroku, when shutting down a process, we send a SIGTERM followed 10
|
13
|
+
seconds later with a SIGKILL, similar to the behavior of the init daemon
|
14
|
+
on most Unix systems. This patch will allow Heroku apps to shut down
|
15
|
+
gracefully when they need to be terminated / moved.
|
16
|
+
|
1
17
|
== 1.2.11 Bat-Shit Crazy
|
2
18
|
* Fix pure Ruby gem to not include binary.
|
3
19
|
|
data/lib/thin.rb
CHANGED
@@ -38,14 +38,7 @@ end
|
|
38
38
|
require "#{Thin::ROOT}/thin/version"
|
39
39
|
require "#{Thin::ROOT}/thin/statuses"
|
40
40
|
require "#{Thin::ROOT}/rack/adapter/loader"
|
41
|
-
|
42
|
-
if Thin.win?
|
43
|
-
# Select proper binary under Windows
|
44
|
-
major_ruby_version = RUBY_VERSION[/^(\d+\.\d+)/]
|
45
|
-
require "#{Thin::ROOT}/#{major_ruby_version}/thin_parser"
|
46
|
-
else
|
47
|
-
require "#{Thin::ROOT}/thin_parser"
|
48
|
-
end
|
41
|
+
require "#{Thin::ROOT}/thin_parser"
|
49
42
|
|
50
43
|
module Rack
|
51
44
|
module Adapter
|
data/lib/thin/connection.rb
CHANGED
@@ -5,10 +5,6 @@ module Thin
|
|
5
5
|
# This class is instanciated by EventMachine on each new connection
|
6
6
|
# that is opened.
|
7
7
|
class Connection < EventMachine::Connection
|
8
|
-
CONTENT_LENGTH = 'Content-Length'.freeze
|
9
|
-
TRANSFER_ENCODING = 'Transfer-Encoding'.freeze
|
10
|
-
CHUNKED_REGEXP = /\bchunked\b/i.freeze
|
11
|
-
|
12
8
|
include Logging
|
13
9
|
|
14
10
|
# This is a template async response. N.B. Can't use string for body on 1.9
|
@@ -97,9 +93,6 @@ module Thin
|
|
97
93
|
# Status code -1 indicates that we're going to respond later (async).
|
98
94
|
return if result.first == AsyncResponse.first
|
99
95
|
|
100
|
-
# Set the Content-Length header if possible
|
101
|
-
set_content_length(result) if need_content_length?(result)
|
102
|
-
|
103
96
|
@response.status, @response.headers, @response.body = *result
|
104
97
|
|
105
98
|
log "!! Rack application returned nil body. Probably you wanted it to be an empty string?" if @response.body.nil?
|
@@ -195,36 +188,9 @@ module Thin
|
|
195
188
|
end
|
196
189
|
|
197
190
|
protected
|
198
|
-
|
199
191
|
# Returns IP address of peer as a string.
|
200
192
|
def socket_address
|
201
193
|
Socket.unpack_sockaddr_in(get_peername)[1]
|
202
194
|
end
|
203
|
-
|
204
|
-
private
|
205
|
-
def need_content_length?(result)
|
206
|
-
status, headers, body = result
|
207
|
-
return false if status == -1
|
208
|
-
return false if headers.has_key?(CONTENT_LENGTH)
|
209
|
-
return false if (100..199).include?(status) || status == 204 || status == 304
|
210
|
-
return false if headers.has_key?(TRANSFER_ENCODING) && headers[TRANSFER_ENCODING] =~ CHUNKED_REGEXP
|
211
|
-
return false unless body.kind_of?(String) || body.kind_of?(Array)
|
212
|
-
true
|
213
|
-
end
|
214
|
-
|
215
|
-
def set_content_length(result)
|
216
|
-
headers, body = result[1..2]
|
217
|
-
case body
|
218
|
-
when String
|
219
|
-
# See http://redmine.ruby-lang.org/issues/show/203
|
220
|
-
headers[CONTENT_LENGTH] = (body.respond_to?(:bytesize) ? body.bytesize : body.size).to_s
|
221
|
-
when Array
|
222
|
-
bytes = 0
|
223
|
-
body.each do |p|
|
224
|
-
bytes += p.respond_to?(:bytesize) ? p.bytesize : p.size
|
225
|
-
end
|
226
|
-
headers[CONTENT_LENGTH] = bytes.to_s
|
227
|
-
end
|
228
|
-
end
|
229
195
|
end
|
230
196
|
end
|
@@ -5,7 +5,7 @@ module Thin
|
|
5
5
|
# System service controller to launch all servers which
|
6
6
|
# config files are in a directory.
|
7
7
|
class Service < Controller
|
8
|
-
INITD_PATH = '/etc/init.d/thin'
|
8
|
+
INITD_PATH = Dir.exist?('/etc/rc.d') ? '/etc/rc.d/thin' : '/etc/init.d/thin'
|
9
9
|
DEFAULT_CONFIG_PATH = '/etc/thin'
|
10
10
|
TEMPLATE = File.dirname(__FILE__) + '/service.sh.erb'
|
11
11
|
|
data/lib/thin/logging.rb
CHANGED
@@ -46,9 +46,9 @@ module Thin
|
|
46
46
|
|
47
47
|
# Log an error backtrace if debugging is activated
|
48
48
|
def log_error(e=$!)
|
49
|
-
|
49
|
+
STDERR.print("#{e}\n\t" + e.backtrace.join("\n\t")) if Logging.debug?
|
50
50
|
end
|
51
51
|
module_function :log_error
|
52
52
|
public :log_error
|
53
53
|
end
|
54
|
-
end
|
54
|
+
end
|
data/lib/thin/runner.rb
CHANGED
@@ -118,7 +118,7 @@ module Thin
|
|
118
118
|
opts.on("-f", "--force", "Force the execution of the command") { @options[:force] = true }
|
119
119
|
opts.on( "--max-conns NUM", "Maximum number of open file descriptors " +
|
120
120
|
"(default: #{@options[:max_conns]})",
|
121
|
-
"Might require sudo to set higher
|
121
|
+
"Might require sudo to set higher than 1024") { |num| @options[:max_conns] = num.to_i } unless Thin.win?
|
122
122
|
opts.on( "--max-persistent-conns NUM",
|
123
123
|
"Maximum number of persistent connections",
|
124
124
|
"(default: #{@options[:max_persistent_conns]})") { |num| @options[:max_persistent_conns] = num.to_i }
|
data/lib/thin/server.rb
CHANGED
@@ -210,11 +210,12 @@ module Thin
|
|
210
210
|
|
211
211
|
protected
|
212
212
|
# Register signals:
|
213
|
-
# *
|
214
|
-
# *
|
213
|
+
# * TERM & QUIT calls +stop+ to shutdown gracefully.
|
214
|
+
# * INT calls <tt>stop!</tt> to force shutdown.
|
215
|
+
# * HUP calls <tt>restart</tt> to ... surprise, restart!
|
215
216
|
def setup_signals
|
216
217
|
trap('INT') { stop! }
|
217
|
-
trap('TERM') { stop
|
218
|
+
trap('TERM') { stop }
|
218
219
|
unless Thin.win?
|
219
220
|
trap('QUIT') { stop }
|
220
221
|
trap('HUP') { restart }
|
data/lib/thin/version.rb
CHANGED
@@ -5,12 +5,12 @@ module Thin
|
|
5
5
|
|
6
6
|
module VERSION #:nodoc:
|
7
7
|
MAJOR = 1
|
8
|
-
MINOR =
|
9
|
-
TINY =
|
8
|
+
MINOR = 3
|
9
|
+
TINY = 0
|
10
10
|
|
11
11
|
STRING = [MAJOR, MINOR, TINY].join('.')
|
12
12
|
|
13
|
-
CODENAME = "
|
13
|
+
CODENAME = "Double Espresso".freeze
|
14
14
|
|
15
15
|
RACK = [1, 0].freeze # Rack protocol version
|
16
16
|
end
|
data/spec/command_spec.rb
CHANGED
data/spec/connection_spec.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
include Controllers
|
3
3
|
|
4
4
|
describe Service do
|
5
5
|
before(:all) do
|
6
|
-
|
6
|
+
silence_warnings do
|
7
7
|
Service::INITD_PATH = 'tmp/sandbox' + Service::INITD_PATH
|
8
8
|
Service::DEFAULT_CONFIG_PATH = 'tmp/sandbox' + Service::DEFAULT_CONFIG_PATH
|
9
9
|
end
|
data/spec/daemonizing_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
class TestServer
|
4
4
|
include Logging # Daemonizable should include this?
|
@@ -87,8 +87,10 @@ describe 'Daemonizing' do
|
|
87
87
|
|
88
88
|
@pid = @server.pid
|
89
89
|
|
90
|
-
|
91
|
-
|
90
|
+
timeout(10) do
|
91
|
+
silence_stream STDOUT do
|
92
|
+
TestServer.kill(@server.pid_file, 1)
|
93
|
+
end
|
92
94
|
end
|
93
95
|
|
94
96
|
File.exist?(@server.pid_file).should be_false
|
@@ -104,8 +106,10 @@ describe 'Daemonizing' do
|
|
104
106
|
|
105
107
|
@pid = @server.pid
|
106
108
|
|
107
|
-
|
108
|
-
|
109
|
+
timeout(10) do
|
110
|
+
silence_stream STDOUT do
|
111
|
+
TestServer.kill(@server.pid_file, 0)
|
112
|
+
end
|
109
113
|
end
|
110
114
|
|
111
115
|
File.exist?(@server.pid_file).should be_false
|
@@ -193,4 +197,4 @@ describe 'Daemonizing' do
|
|
193
197
|
def server_should_start_in_less_then(sec=10)
|
194
198
|
proc { sleep 0.1 until File.exist?(@server.pid_file) }.should take_less_then(10)
|
195
199
|
end
|
196
|
-
end
|
200
|
+
end
|
data/spec/headers_spec.rb
CHANGED
data/spec/logging_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
class TestLogging
|
4
4
|
include Logging
|
@@ -39,8 +39,14 @@ describe Logging do
|
|
39
39
|
Logging.silent = true
|
40
40
|
Logging.log "hi"
|
41
41
|
end
|
42
|
+
|
43
|
+
it "should print errors to STDERR" do
|
44
|
+
error = mock(:error, :backtrace => Array("PC LOAD LETTER"))
|
45
|
+
STDERR.should_receive(:print).with(/PC LOAD LETTER/)
|
46
|
+
@object.log_error(error)
|
47
|
+
end
|
42
48
|
|
43
49
|
after do
|
44
50
|
Logging.silent = true
|
45
51
|
end
|
46
|
-
end
|
52
|
+
end
|
data/spec/rack/loader_spec.rb
CHANGED
data/spec/request/parser_spec.rb
CHANGED
data/spec/response_spec.rb
CHANGED
data/spec/runner_spec.rb
CHANGED
data/spec/server/builder_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Server, "HTTP pipelining" do
|
4
4
|
before do
|
@@ -35,7 +35,7 @@ describe Server, "HTTP pipelining" do
|
|
35
35
|
socket.close
|
36
36
|
|
37
37
|
wait_for_requests_to_complete!
|
38
|
-
|
38
|
+
|
39
39
|
response.should include('/first-1', '/second-2')
|
40
40
|
end
|
41
41
|
|
@@ -107,4 +107,4 @@ describe Server, "HTTP pipelining" do
|
|
107
107
|
def wait_for_requests_to_complete!
|
108
108
|
sleep 0.1 until @server.backend.size == 0
|
109
109
|
end
|
110
|
-
end
|
110
|
+
end
|
data/spec/server/tcp_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Server, 'on TCP socket' do
|
4
4
|
before do
|
@@ -20,16 +20,6 @@ describe Server, 'on TCP socket' do
|
|
20
20
|
body.should include('this')
|
21
21
|
end
|
22
22
|
|
23
|
-
it "should add the Content-Length to the response when not present" do
|
24
|
-
status, headers, body = parse_response(send_data("GET / HTTP/1.0\r\nConnection: close\r\n\r\n"))
|
25
|
-
headers.should have_key('Content-Length')
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'should set the Content-Length to equal the body size in bytes' do
|
29
|
-
status, headers, body = parse_response(send_data("GET / HTTP/1.0\r\nConnection: close\r\n\r\n"))
|
30
|
-
headers['Content-Length'].should == (body.respond_to?(:bytesize) ? body.bytesize : body.size).to_s
|
31
|
-
end
|
32
|
-
|
33
23
|
it 'should return empty string on incomplete headers' do
|
34
24
|
send_data("GET /?this HTTP/1.1\r\nHost:").should be_empty
|
35
25
|
end
|
data/spec/server_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'thin'
|
3
|
+
gem "rspec", "~> 1.2.9"
|
3
4
|
require 'spec'
|
4
5
|
require 'benchmark'
|
5
6
|
require 'timeout'
|
@@ -134,6 +135,13 @@ module Helpers
|
|
134
135
|
stream.reopen(old_stream)
|
135
136
|
end
|
136
137
|
|
138
|
+
def silence_warnings
|
139
|
+
old_verbose, $VERBOSE = $VERBOSE, nil
|
140
|
+
yield
|
141
|
+
ensure
|
142
|
+
$VERBOSE = old_verbose
|
143
|
+
end
|
144
|
+
|
137
145
|
# Create and parse a request
|
138
146
|
def R(raw, convert_line_feed=false)
|
139
147
|
raw.gsub!("\n", "\r\n") if convert_line_feed
|
@@ -153,13 +161,19 @@ module Helpers
|
|
153
161
|
wait_for_socket(address, port)
|
154
162
|
else
|
155
163
|
# If we can't ping the address fallback to just wait for the server to run
|
156
|
-
sleep
|
164
|
+
sleep 0.01 until @server.running?
|
157
165
|
end
|
158
166
|
end
|
159
167
|
|
160
168
|
def stop_server
|
161
169
|
@server.stop!
|
162
170
|
@thread.kill
|
171
|
+
|
172
|
+
100.times do
|
173
|
+
break unless EM.reactor_running?
|
174
|
+
sleep 0.01
|
175
|
+
end
|
176
|
+
|
163
177
|
raise "Reactor still running, wtf?" if EventMachine.reactor_running?
|
164
178
|
end
|
165
179
|
|
@@ -217,4 +231,4 @@ end
|
|
217
231
|
Spec::Runner.configure do |config|
|
218
232
|
config.include Matchers
|
219
233
|
config.include Helpers
|
220
|
-
end
|
234
|
+
end
|
data/tasks/gem.rake
CHANGED
@@ -13,7 +13,6 @@ Thin::GemSpec = Gem::Specification.new do |s|
|
|
13
13
|
s.email = 'macournoyer@gmail.com'
|
14
14
|
s.homepage = 'http://code.macournoyer.com/thin/'
|
15
15
|
s.rubyforge_project = 'thin'
|
16
|
-
s.has_rdoc = true
|
17
16
|
s.executables = %w(thin)
|
18
17
|
|
19
18
|
s.required_ruby_version = '>= 1.8.5'
|
@@ -24,7 +23,7 @@ Thin::GemSpec = Gem::Specification.new do |s|
|
|
24
23
|
s.add_dependency 'daemons', '>= 1.0.9'
|
25
24
|
end
|
26
25
|
|
27
|
-
s.files = %w(
|
26
|
+
s.files = %w(CHANGELOG README Rakefile) +
|
28
27
|
Dir.glob("{benchmark,bin,doc,example,lib,spec,tasks}/**/*") - Dir.glob("lib/thin_parser.*") +
|
29
28
|
Dir.glob("ext/**/*.{h,c,rb,rl}")
|
30
29
|
|
data/tasks/spec.rake
CHANGED
@@ -19,7 +19,6 @@ SPECS = FileList['spec/**/*_spec.rb'] - PERF_SPECS - SPECS2
|
|
19
19
|
|
20
20
|
def spec_task(name, specs)
|
21
21
|
Spec::Rake::SpecTask.new(name) do |t|
|
22
|
-
t.libs << 'lib'
|
23
22
|
t.spec_opts = %w(-fs -c)
|
24
23
|
t.spec_files = specs
|
25
24
|
end
|
@@ -41,4 +40,4 @@ task :check_benchmark_unit_gem do
|
|
41
40
|
end
|
42
41
|
end
|
43
42
|
|
44
|
-
task 'spec:perf' => :check_benchmark_unit_gem
|
43
|
+
task 'spec:perf' => :check_benchmark_unit_gem
|
metadata
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 2
|
9
|
-
- 11
|
10
|
-
version: 1.2.11
|
4
|
+
prerelease:
|
5
|
+
version: 1.3.0
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
8
|
- Marc-Andre Cournoyer
|
@@ -15,7 +10,7 @@ autorequire:
|
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
12
|
|
18
|
-
date: 2011-
|
13
|
+
date: 2011-11-11 00:00:00 -05:00
|
19
14
|
default_executable:
|
20
15
|
dependencies:
|
21
16
|
- !ruby/object:Gem::Dependency
|
@@ -26,11 +21,6 @@ dependencies:
|
|
26
21
|
requirements:
|
27
22
|
- - ">="
|
28
23
|
- !ruby/object:Gem::Version
|
29
|
-
hash: 23
|
30
|
-
segments:
|
31
|
-
- 1
|
32
|
-
- 0
|
33
|
-
- 0
|
34
24
|
version: 1.0.0
|
35
25
|
type: :runtime
|
36
26
|
version_requirements: *id001
|
@@ -42,11 +32,6 @@ dependencies:
|
|
42
32
|
requirements:
|
43
33
|
- - ">="
|
44
34
|
- !ruby/object:Gem::Version
|
45
|
-
hash: 35
|
46
|
-
segments:
|
47
|
-
- 0
|
48
|
-
- 12
|
49
|
-
- 6
|
50
35
|
version: 0.12.6
|
51
36
|
type: :runtime
|
52
37
|
version_requirements: *id002
|
@@ -58,11 +43,6 @@ dependencies:
|
|
58
43
|
requirements:
|
59
44
|
- - ">="
|
60
45
|
- !ruby/object:Gem::Version
|
61
|
-
hash: 5
|
62
|
-
segments:
|
63
|
-
- 1
|
64
|
-
- 0
|
65
|
-
- 9
|
66
46
|
version: 1.0.9
|
67
47
|
type: :runtime
|
68
48
|
version_requirements: *id003
|
@@ -75,7 +55,6 @@ extensions:
|
|
75
55
|
extra_rdoc_files: []
|
76
56
|
|
77
57
|
files:
|
78
|
-
- COPYING
|
79
58
|
- CHANGELOG
|
80
59
|
- README
|
81
60
|
- Rakefile
|
@@ -224,25 +203,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
224
203
|
requirements:
|
225
204
|
- - ">="
|
226
205
|
- !ruby/object:Gem::Version
|
227
|
-
hash: 61
|
228
|
-
segments:
|
229
|
-
- 1
|
230
|
-
- 8
|
231
|
-
- 5
|
232
206
|
version: 1.8.5
|
233
207
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
234
208
|
none: false
|
235
209
|
requirements:
|
236
210
|
- - ">="
|
237
211
|
- !ruby/object:Gem::Version
|
238
|
-
hash: 3
|
239
|
-
segments:
|
240
|
-
- 0
|
241
212
|
version: "0"
|
242
213
|
requirements: []
|
243
214
|
|
244
215
|
rubyforge_project: thin
|
245
|
-
rubygems_version: 1.
|
216
|
+
rubygems_version: 1.6.2
|
246
217
|
signing_key:
|
247
218
|
specification_version: 3
|
248
219
|
summary: A thin and fast web server
|
data/COPYING
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
Copyright (c) 2008 Marc-Andre Cournoyer
|
2
|
-
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
of this software and associated documentation files (the "Software"), to
|
5
|
-
deal in the Software without restriction, including without limitation the
|
6
|
-
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
7
|
-
sell copies of the Software, and to permit persons to whom the Software is
|
8
|
-
furnished to do so, subject to the following conditions:
|
9
|
-
|
10
|
-
The above copyright notice and this permission notice shall be included in
|
11
|
-
all copies or substantial portions of the Software.
|
12
|
-
|
13
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
16
|
-
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
-
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
-
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|