rainbows 0.90.0 → 0.90.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.
@@ -12,10 +12,9 @@ rainbows [-c CONFIG_FILE] [-E RACK_ENV] [-D] [RACKUP_FILE]
12
12
 
13
13
  # DESCRIPTION
14
14
 
15
- A rackup(1)-like command to launch Rack applications using
16
- Rainbows!. It is expected to be started in your application root
17
- (APP_ROOT), but "Dir.chdir" may also be executed in the CONFIG_FILE or
18
- RACKUP_FILE.
15
+ A rackup(1)-like command to launch Rack applications using Rainbows!.
16
+ It is expected to be started in your application root (APP_ROOT),
17
+ but the "working_directory" directive may be used in the CONFIG_FILE.
19
18
 
20
19
  While Rainbows! takes a myriad of command-line options for
21
20
  compatibility with ruby(1) and rackup(1), it is recommended to stick
@@ -34,10 +33,9 @@ with rackup(1) but strongly discouraged.
34
33
  # UNICORN OPTIONS
35
34
  -c, \--config-file CONFIG_FILE
36
35
  : Path to the Unicorn-specific config file. The config file is
37
- implemented as a Ruby DSL, so Ruby code may executed (e.g.
38
- "Dir.chdir", "Process::UID.change_privilege"). See the RDoc/ri
39
- for the *Unicorn::Configurator* class for the full list of
40
- directives available from the DSL.
36
+ implemented as a Ruby DSL, so Ruby code may executed.
37
+ See the RDoc/ri for the *Unicorn::Configurator* class for the full
38
+ list of directives available from the DSL.
41
39
 
42
40
  -D, \--daemonize
43
41
  : Run daemonized in the background. The process is detached from
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v0.90.0.GIT
4
+ DEF_VER=v0.90.1.GIT
5
5
 
6
6
  LF='
7
7
  '
data/TODO CHANGED
@@ -3,14 +3,15 @@
3
3
  We're lazy and pick the easy items to do first, then the ones people
4
4
  care about.
5
5
 
6
+ * Split out NeverBlock into NeverBlockEventMachine and NeverBlockReactor
7
+ NeverBlock will default to one of them (depending on NB upstream).
8
+
6
9
  * Improve test suite coverage. We won't waste cycles with puny
7
10
  unit tests, only integration tests that exercise externally
8
11
  visible parts.
9
12
 
10
13
  * EventMachine.spawn - should be like Revactor, maybe?
11
14
 
12
- * EventMachine deferrables
13
-
14
15
  * conditional app.deferred?(env) support
15
16
  Merb uses it, some other servers support it
16
17
 
data/lib/rainbows.rb CHANGED
@@ -60,6 +60,13 @@ module Rainbows
60
60
 
61
61
  # returns nil if accept fails
62
62
  if defined?(Fcntl::FD_CLOEXEC)
63
+ def sync_accept(sock)
64
+ rv = sock.accept
65
+ rv.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
66
+ rv
67
+ rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EINTR
68
+ end
69
+
63
70
  def accept(sock)
64
71
  rv = sock.accept_nonblock
65
72
  rv.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
@@ -67,6 +74,11 @@ module Rainbows
67
74
  rescue Errno::EAGAIN, Errno::ECONNABORTED
68
75
  end
69
76
  else
77
+ def sync_accept(sock)
78
+ sock.accept
79
+ rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EINTR
80
+ end
81
+
70
82
  def accept(sock)
71
83
  sock.accept_nonblock
72
84
  rescue Errno::EAGAIN, Errno::ECONNABORTED
@@ -3,7 +3,7 @@
3
3
  module Rainbows
4
4
 
5
5
  module Const
6
- RAINBOWS_VERSION = '0.90.0'
6
+ RAINBOWS_VERSION = '0.90.1'
7
7
 
8
8
  include Unicorn::Const
9
9
 
@@ -11,6 +11,8 @@ module Rainbows
11
11
  # Apps may return this Rack response: AsyncResponse = [ -1, {}, [] ]
12
12
  ASYNC_CALLBACK = "async.callback".freeze
13
13
 
14
+ ASYNC_CLOSE = "async.close".freeze
15
+
14
16
  def post_init
15
17
  @remote_addr = ::TCPSocket === @_io ? @_io.peeraddr.last : LOCALHOST
16
18
  @env = {}
@@ -37,6 +37,7 @@ module Rainbows
37
37
 
38
38
  def initialize(io)
39
39
  @_io = io
40
+ @body = nil
40
41
  end
41
42
 
42
43
  alias write send_data
@@ -54,6 +55,9 @@ module Rainbows
54
55
  @env[REMOTE_ADDR] = @remote_addr
55
56
  @env[ASYNC_CALLBACK] = method(:response_write)
56
57
 
58
+ # we're not sure if anybody uses this, but Thin sets it, too
59
+ @env[ASYNC_CLOSE] = EM::DefaultDeferrable.new
60
+
57
61
  response = catch(:async) { APP.call(@env.update(RACK_DEFAULTS)) }
58
62
 
59
63
  # too tricky to support pipelining with :async since the
@@ -77,9 +81,14 @@ module Rainbows
77
81
  end while true
78
82
  end
79
83
 
80
- def response_write(response, out = [], alive = false)
81
- body = response.last
82
- unless body.respond_to?(:to_path)
84
+ def response_write(response, out = [ CONN_CLOSE ], alive = false)
85
+ @body = body = response.last
86
+ if body.respond_to?(:errback) && body.respond_to?(:callback)
87
+ body.callback { quit }
88
+ body.errback { quit }
89
+ HttpResponse.write(self, response, out)
90
+ return
91
+ elsif ! body.respond_to?(:to_path)
83
92
  HttpResponse.write(self, response, out)
84
93
  quit unless alive
85
94
  return
@@ -120,6 +129,8 @@ module Rainbows
120
129
  end
121
130
 
122
131
  def unbind
132
+ async_close = @env[ASYNC_CLOSE] and async_close.succeed
133
+ @body.respond_to?(:fail) and @body.fail
123
134
  @_io.close
124
135
  end
125
136
  end
@@ -44,8 +44,7 @@ module Rainbows
44
44
  def sync_worker
45
45
  s = LISTENERS.first
46
46
  begin
47
- process_client(s.accept)
48
- rescue Errno::EINTR, Errno::ECONNABORTED
47
+ c = Rainbows.sync_accept(s) and process_client(c)
49
48
  rescue => e
50
49
  Error.listen_loop(e)
51
50
  end while G.alive
@@ -34,8 +34,8 @@ module Rainbows
34
34
  # unlikely one. Since this case is (or should be) uncommon,
35
35
  # just busy wait when we have to.
36
36
  sleep(0.01)
37
- else
38
- klass.new(l.accept) do |c|
37
+ elsif c = Rainbows.sync_accept(l)
38
+ klass.new(c) do |c|
39
39
  begin
40
40
  lock.synchronize { G.cur += 1 }
41
41
  process_client(c)
@@ -44,7 +44,6 @@ module Rainbows
44
44
  end
45
45
  end
46
46
  end
47
- rescue Errno::EINTR, Errno::ECONNABORTED
48
47
  rescue => e
49
48
  Error.listen_loop(e)
50
49
  end while G.alive
data/rainbows.gemspec CHANGED
@@ -41,8 +41,7 @@ Gem::Specification.new do |s|
41
41
  s.test_files = test_files
42
42
 
43
43
  # we need Unicorn for the HTTP parser and process management
44
- # Unicorn 0.95.0 should be released on or around Nov 13/14/15, 2009
45
- s.add_dependency(%q<unicorn>, ["~> 0.95.0"])
44
+ s.add_dependency(%q<unicorn>, ["~> 0.95.0", "< 0.97.0"])
46
45
 
47
46
  # Unicorn already depends on Rack
48
47
  # s.add_dependency(%q<rack>)
@@ -0,0 +1,3 @@
1
+ These examples in this directory are stolen from Thin 1.2.5 with only
2
+ trivial changes. All examples in this directory retain their original
3
+ license (MIT) and copyrights.
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env rackup -s thin
2
+ #
3
+ # async_app.ru
4
+ # raggi/thin
5
+ #
6
+ # A second demo app for async rack + thin app processing!
7
+ # Now using http status code 100 instead.
8
+ #
9
+ # Created by James Tucker on 2008-06-17.
10
+ # Copyright 2008 James Tucker <raggi@rubyforge.org>.
11
+ #
12
+ #--
13
+ # Benchmark Results:
14
+ #
15
+ # raggi@mbk:~$ ab -c 100 -n 500 http://127.0.0.1:3000/
16
+ # This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
17
+ # Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
18
+ # Copyright 2006 The Apache Software Foundation, http://www.apache.org/
19
+ #
20
+ # Benchmarking 127.0.0.1 (be patient)
21
+ # Completed 100 requests
22
+ # Completed 200 requests
23
+ # Completed 300 requests
24
+ # Completed 400 requests
25
+ # Finished 500 requests
26
+ #
27
+ #
28
+ # Server Software: thin
29
+ # Server Hostname: 127.0.0.1
30
+ # Server Port: 3000
31
+ #
32
+ # Document Path: /
33
+ # Document Length: 12 bytes
34
+ #
35
+ # Concurrency Level: 100
36
+ # Time taken for tests: 5.263089 seconds
37
+ # Complete requests: 500
38
+ # Failed requests: 0
39
+ # Write errors: 0
40
+ # Total transferred: 47000 bytes
41
+ # HTML transferred: 6000 bytes
42
+ # Requests per second: 95.00 [#/sec] (mean)
43
+ # Time per request: 1052.618 [ms] (mean)
44
+ # Time per request: 10.526 [ms] (mean, across all concurrent requests)
45
+ # Transfer rate: 8.55 [Kbytes/sec] received
46
+ #
47
+ # Connection Times (ms)
48
+ # min mean[+/-sd] median max
49
+ # Connect: 0 3 2.2 3 8
50
+ # Processing: 1042 1046 3.1 1046 1053
51
+ # Waiting: 1037 1042 3.6 1041 1050
52
+ # Total: 1045 1049 3.1 1049 1057
53
+ #
54
+ # Percentage of the requests served within a certain time (ms)
55
+ # 50% 1049
56
+ # 66% 1051
57
+ # 75% 1053
58
+ # 80% 1053
59
+ # 90% 1054
60
+ # 95% 1054
61
+ # 98% 1056
62
+ # 99% 1057
63
+ # 100% 1057 (longest request)
64
+
65
+ class DeferrableBody
66
+ include EventMachine::Deferrable
67
+
68
+ def call(body)
69
+ body.each do |chunk|
70
+ @body_callback.call(chunk)
71
+ end
72
+ end
73
+
74
+ def each &blk
75
+ @body_callback = blk
76
+ end
77
+
78
+ end
79
+
80
+ class AsyncApp
81
+
82
+ # This is a template async response. N.B. Can't use string for body on 1.9
83
+ AsyncResponse = [-1, {}, []].freeze
84
+
85
+ def call(env)
86
+
87
+ body = DeferrableBody.new
88
+
89
+ # Get the headers out there asap, let the client know we're alive...
90
+ EventMachine::next_tick { env['async.callback'].call [200, {'Content-Type' => 'text/plain'}, body] }
91
+
92
+ # Semi-emulate a long db request, instead of a timer, in reality we'd be
93
+ # waiting for the response data. Whilst this happens, other connections
94
+ # can be serviced.
95
+ # This could be any callback based thing though, a deferrable waiting on
96
+ # IO data, a db request, an http request, an smtp send, whatever.
97
+ EventMachine::add_timer(1) {
98
+ body.call ["Woah, async!\n"]
99
+
100
+ EventMachine::next_tick {
101
+ # This could actually happen any time, you could spawn off to new
102
+ # threads, pause as a good looking lady walks by, whatever.
103
+ # Just shows off how we can defer chunks of data in the body, you can
104
+ # even call this many times.
105
+ body.call ["Cheers then!"]
106
+ body.succeed
107
+ }
108
+ }
109
+
110
+ # throw :async # Still works for supporting non-async frameworks...
111
+
112
+ AsyncResponse # May end up in Rack :-)
113
+ end
114
+
115
+ end
116
+
117
+ # The additions to env for async.connection and async.callback absolutely
118
+ # destroy the speed of the request if Lint is doing it's checks on env.
119
+ # It is also important to note that an async response will not pass through
120
+ # any further middleware, as the async response notification has been passed
121
+ # right up to the webserver, and the callback goes directly there too.
122
+ # Middleware could possibly catch :async, and also provide a different
123
+ # async.connection and async.callback.
124
+
125
+ # use Rack::Lint
126
+ run AsyncApp.new
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env rackup -s thin
2
+ #
3
+ # async_tailer.ru
4
+ # raggi/thin
5
+ #
6
+ # Tested with 150 spawned tails on OS X
7
+ #
8
+ # Created by James Tucker on 2008-06-18.
9
+ # Copyright 2008 James Tucker <raggi@rubyforge.org>.
10
+
11
+ # Uncomment if appropriate for you..
12
+ # EM.epoll
13
+ # EM.kqueue
14
+
15
+ tail_log_file = ENV["TAIL_LOG_FILE"] or abort "TAIL_LOG_FILE= env must be set"
16
+ unless ::File.file?(tail_log_file) && ::File.readable?(tail_log_file)
17
+ abort "#{tail_log_file} must be a readable regular file"
18
+ end
19
+
20
+ class DeferrableBody
21
+ include EventMachine::Deferrable
22
+
23
+ def initialize
24
+ @queue = []
25
+ # make sure to flush out the queue before closing the connection
26
+ callback{
27
+ until @queue.empty?
28
+ @queue.shift.each{|chunk| @body_callback.call(chunk) }
29
+ end
30
+ }
31
+ end
32
+
33
+ def schedule_dequeue
34
+ return unless @body_callback
35
+ EventMachine::next_tick do
36
+ next unless body = @queue.shift
37
+ body.each do |chunk|
38
+ @body_callback.call(chunk)
39
+ end
40
+ schedule_dequeue unless @queue.empty?
41
+ end
42
+ end
43
+
44
+ def call(body)
45
+ @queue << body
46
+ schedule_dequeue
47
+ end
48
+
49
+ def each &blk
50
+ @body_callback = blk
51
+ schedule_dequeue
52
+ end
53
+
54
+ end
55
+
56
+ module TailRenderer
57
+ attr_accessor :callback
58
+
59
+ def receive_data(data)
60
+ @callback.call([data])
61
+ end
62
+
63
+ def unbind
64
+ @callback.succeed
65
+ end
66
+ end
67
+
68
+ class AsyncTailer
69
+
70
+ AsyncResponse = [-1, {}, []].freeze
71
+
72
+ def call(env)
73
+
74
+ body = DeferrableBody.new
75
+
76
+ EventMachine::next_tick do
77
+
78
+ env['async.callback'].call [200, {'Content-Type' => 'text/html'}, body]
79
+
80
+ body.call ["<h1>Async Tailer</h1><pre>"]
81
+
82
+ end
83
+
84
+ EventMachine::popen("tail -f #{ENV["TAIL_LOG_FILE"]}", TailRenderer) do |t|
85
+
86
+ t.callback = body
87
+
88
+ # If for some reason we 'complete' body, close the tail.
89
+ body.callback do
90
+ t.close_connection
91
+ end
92
+
93
+ # If for some reason the client disconnects, close the tail.
94
+ body.errback do
95
+ t.close_connection
96
+ end
97
+
98
+ end
99
+
100
+ AsyncResponse
101
+ end
102
+
103
+ end
104
+
105
+ run AsyncTailer.new
@@ -0,0 +1,41 @@
1
+ #!/bin/sh
2
+ nr=${nr-4}
3
+ . ./test-lib.sh
4
+
5
+ # ApacheBench (ab) is commonly installed in the sbin paths in Debian-based
6
+ # systems...
7
+ AB="$(which ab 2>/dev/null || :)"
8
+ if test -z "$AB"
9
+ then
10
+ AB=$(PATH=/usr/local/sbin:/usr/sbin:$PATH which ab 2>/dev/null || :)
11
+ fi
12
+
13
+ if test -z "$AB"
14
+ then
15
+ t_info "skipping $T since 'ab' could not be found"
16
+ exit 0
17
+ fi
18
+
19
+ t_plan 4 "quiet spurious wakeups for $model"
20
+
21
+ t_begin "setup and start" && {
22
+ rainbows_setup $model
23
+ echo "preload_app true" >> $unicorn_config
24
+ echo "worker_processes $nr" >> $unicorn_config
25
+ rainbows -D env.ru -c $unicorn_config -E none
26
+ rainbows_wait_start
27
+ }
28
+
29
+ t_begin "spam the server with requests" && {
30
+ $AB -c1 -n100 http://$listen/
31
+ }
32
+
33
+ t_begin "killing succeeds" && {
34
+ kill -QUIT $rainbows_pid
35
+ }
36
+
37
+ t_begin "check stderr" && {
38
+ check_stderr
39
+ }
40
+
41
+ t_done
@@ -0,0 +1,57 @@
1
+ #!/bin/sh
2
+ nr=${nr-5}
3
+ . ./test-lib.sh
4
+ case $model in
5
+ NeverBlock|EventMachine) ;;
6
+ *)
7
+ t_info "skipping $T since it's not compatible with $model"
8
+ exit 0
9
+ ;;
10
+ esac
11
+
12
+ t_plan 7 "async_app test for test for EM"
13
+
14
+ CONFIG_RU=async_examples/async_app.ru
15
+
16
+ t_begin "setup and start" && {
17
+ rainbows_setup
18
+ rtmpfiles a b c curl_err expect
19
+
20
+ # this does not does not support Rack::Lint
21
+ rainbows -E deployment -D $CONFIG_RU -c $unicorn_config
22
+ rainbows_wait_start
23
+ }
24
+
25
+ t_begin "send async requests off in parallel" && {
26
+ t0=$(date +%s)
27
+ curl --no-buffer -sSf http://$listen/ > $a 2>> $curl_err &
28
+ curl --no-buffer -sSf http://$listen/ > $b 2>> $curl_err &
29
+ curl --no-buffer -sSf http://$listen/ > $c 2>> $curl_err &
30
+ }
31
+
32
+ t_begin "wait for curl terminations" && {
33
+ wait
34
+ t1=$(date +%s)
35
+ elapsed=$(( $t1 - $t0 ))
36
+ t_info "elapsed=$elapsed"
37
+ }
38
+
39
+ t_begin "termination signal sent" && {
40
+ kill $rainbows_pid
41
+ }
42
+
43
+ t_begin "no errors from curl" && {
44
+ test ! -s $curl_err
45
+ }
46
+
47
+ t_begin "no errors in stderr" && check_stderr
48
+
49
+ t_begin "responses match expected" && {
50
+ echo 'Woah, async!' > $expect
51
+ printf 'Cheers then!' >> $expect
52
+ cmp $expect $a
53
+ cmp $expect $b
54
+ cmp $expect $c
55
+ }
56
+
57
+ t_done
@@ -0,0 +1,74 @@
1
+ #!/bin/sh
2
+ nr=${nr-5}
3
+ . ./test-lib.sh
4
+ case $model in
5
+ NeverBlock|EventMachine) ;;
6
+ *)
7
+ t_info "skipping $T since it's not compatible with $model"
8
+ exit 0
9
+ ;;
10
+ esac
11
+
12
+ t_plan 8 "async_tailer test for test for EM"
13
+
14
+ CONFIG_RU=async_examples/async_tailer.ru
15
+
16
+ t_begin "setup and start" && {
17
+ rainbows_setup
18
+ rtmpfiles a b c curl_err TAIL_LOG_FILE expect
19
+
20
+ printf '<h1>Async Tailer</h1><pre>' >> $expect
21
+
22
+ export TAIL_LOG_FILE
23
+
24
+ # this does not does not support Rack::Lint
25
+ rainbows -E deployment -D $CONFIG_RU -c $unicorn_config
26
+ rainbows_wait_start
27
+ }
28
+
29
+ t_begin "send async requests off in parallel" && {
30
+ t0=$(date +%s)
31
+ curl --no-buffer -sSf http://$listen/ > $a 2>> $curl_err &
32
+ curl_a=$!
33
+ curl --no-buffer -sSf http://$listen/ > $b 2>> $curl_err &
34
+ curl_b=$!
35
+ curl --no-buffer -sSf http://$listen/ > $c 2>> $curl_err &
36
+ curl_c=$!
37
+ }
38
+
39
+ t_begin "generate log output" && {
40
+ for i in $(awk "BEGIN {for(i=0;i<$nr;i++) print i}" < /dev/null)
41
+ do
42
+ date >> $TAIL_LOG_FILE
43
+ sleep 1
44
+ done
45
+ # sometimes tail(1) can be slow
46
+ sleep 2
47
+ }
48
+
49
+ t_begin "kill curls and wait for termination" && {
50
+ kill $curl_a $curl_b $curl_c
51
+ wait
52
+ t1=$(date +%s)
53
+ elapsed=$(( $t1 - $t0 ))
54
+ t_info "elapsed=$elapsed"
55
+ }
56
+
57
+ t_begin "termination signal sent" && {
58
+ kill $rainbows_pid
59
+ }
60
+
61
+ t_begin "no errors from curl" && {
62
+ test ! -s $curl_err
63
+ }
64
+
65
+ t_begin "no errors in stderr" && check_stderr
66
+
67
+ t_begin "responses match expected" && {
68
+ cat $TAIL_LOG_FILE >> $expect
69
+ cmp $expect $a
70
+ cmp $expect $b
71
+ cmp $expect $c
72
+ }
73
+
74
+ t_done
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rainbows
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.90.0
4
+ version: 0.90.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rainbows! hackers
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-22 00:00:00 +00:00
12
+ date: 2009-12-30 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -21,6 +21,9 @@ dependencies:
21
21
  - - ~>
22
22
  - !ruby/object:Gem::Version
23
23
  version: 0.95.0
24
+ - - <
25
+ - !ruby/object:Gem::Version
26
+ version: 0.97.0
24
27
  version:
25
28
  description: |-
26
29
  Rainbows! is an HTTP server for sleepy Rack applications. It is based on
@@ -74,7 +77,6 @@ extra_rdoc_files:
74
77
  - lib/rainbows/thread_spawn.rb
75
78
  - LICENSE
76
79
  - NEWS
77
- - rainbows.1
78
80
  - README
79
81
  - SIGNALS
80
82
  - TODO
@@ -150,6 +152,9 @@ files:
150
152
  - t/README
151
153
  - t/async-response-no-autochunk.ru
152
154
  - t/async-response.ru
155
+ - t/async_examples/README
156
+ - t/async_examples/async_app.ru
157
+ - t/async_examples/async_tailer.ru
153
158
  - t/async_sinatra.ru
154
159
  - t/bin/content-md5-put
155
160
  - t/bin/sha1sum.rb
@@ -193,18 +198,20 @@ files:
193
198
  - t/t0009.ru
194
199
  - t/t0010-keepalive-timeout-effective.sh
195
200
  - t/t0011-close-on-exec-set.sh
201
+ - t/t0012-spurious-wakeups-quiet.sh
196
202
  - t/t0100-rack-input-hammer.sh
197
203
  - t/t0101-rack-input-trailer.sh
198
204
  - t/t0102-rack-input-short.sh
199
205
  - t/t0200-async-response.sh
200
206
  - t/t0201-async-response-no-autochunk.sh
201
207
  - t/t0300-async_sinatra.sh
208
+ - t/t0400-em-async-app.sh
209
+ - t/t0401-em-async-tailer.sh
202
210
  - t/t9000-rack-app-pool.sh
203
211
  - t/t9000.ru
204
212
  - t/test-lib.sh
205
213
  - t/worker-follows-master-to-death.ru
206
214
  - vs_Unicorn
207
- - rainbows.1
208
215
  has_rdoc: true
209
216
  homepage: http://rainbows.rubyforge.org/
210
217
  licenses: []
data/rainbows.1 DELETED
File without changes