thick 0.0.4-java → 0.0.5-java

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,4 +1,10 @@
1
- ## 0.4 (xy.xz.2012)
1
+ ## 0.5 (30.11.2012)
2
+
3
+ * update Netty to 3.5.11
4
+ * get rid of Loader experiment
5
+ * update Rake gem (development)
6
+
7
+ ## 0.4 (29.3.2012)
2
8
 
3
9
  * make gem Java specific
4
10
  * copy-less request body container
data/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Thick is very lightweight web server for JRuby based on excellent Netty library.
4
4
 
5
+ [![Build Status](https://secure.travis-ci.org/marekjelen/thick.png?branch=master)](http://travis-ci.org/marekjelen/thick)
6
+
5
7
  ## Status
6
8
 
7
9
  Works on several Sinatra and Rails applications. No real testing, yet.
data/ROADMAP.md CHANGED
@@ -3,8 +3,7 @@
3
3
  * SSL support
4
4
  * Tests
5
5
  * Code refactorings
6
- * Optimalizations
7
- * Replace StringIO
6
+ * Optimizations
8
7
 
9
8
  ## Nice to have
10
9
 
data/bin/thick CHANGED
@@ -2,7 +2,6 @@
2
2
  require 'optparse'
3
3
 
4
4
  require 'rubygems'
5
- require 'rack'
6
5
 
7
6
  $: << File.expand_path('../../lib', __FILE__)
8
7
  require 'thick'
@@ -27,20 +26,22 @@ OptionParser.new do |opts|
27
26
  options[:port] = Integer(port)
28
27
  end
29
28
 
30
- opts.on('-E', '--env ENVIRONMENT', 'use ENVIRONMENT for defaults (default: development)') do |e|
31
- options[:environment] = e
29
+ opts.on('-f', '--file FILE', 'use FILE to load the application (default: config.ru)') do |file|
30
+ options[:file] = file
32
31
  end
33
32
 
34
- end.parse!
33
+ opts.on('-d', '--directory DIR', 'use DIR as default directory (default: cwd)') do |directory|
34
+ options[:directory] = directory
35
+ end
35
36
 
36
- options[:address] ||= '0.0.0.0'
37
- options[:port] ||= 9292
38
- options[:environment] ||= 'development'
37
+ opts.on('-E', '--env ENVIRONMENT', 'use ENVIRONMENT for defaults (default: development)') do |e|
38
+ options[:environment] = e
39
+ end
39
40
 
40
- ENV['RACK_ENV'] ||= ENV['RAILS_ENV'] ||= options[:environment]
41
+ opts.on('-C', '--controller', 'starts controller for remote monitoring and management') do |e|
42
+ options[:controller] = e
43
+ end
41
44
 
42
- puts "Loading app #{options.inspect}"
43
- app = Rack::Builder.parse_file('config.ru')
45
+ end.parse!
44
46
 
45
- puts "Starting server"
46
- Thick.start(app[0], options)
47
+ Thick.start(options)
Binary file
@@ -8,15 +8,26 @@ module Thick
8
8
  @custom = false
9
9
  @async = false
10
10
  @block = nil
11
+ @chunked = false
12
+ @content_length = nil
13
+ @closed = false
11
14
  @params = []
12
15
  end
13
16
 
14
17
  def call(chunk)
15
- @context.channel.write(Thick::Java::ChannelBuffers.copiedBuffer(chunk.to_s, Thick::Java::CharsetUtil::UTF_8))
18
+ chunk = Thick::Java::ChannelBuffers.copiedBuffer(chunk.to_s, Thick::Java::CharsetUtil::UTF_8)
19
+ chunk = Thick::Java::DefaultHttpChunk.new(chunk) if @chunked
20
+ @context.channel.write(chunk) unless closed?
16
21
  end
17
22
 
18
23
  def close
19
- @context.channel.write(Thick::Java::ChannelBuffers::EMPTY_BUFFER).addListener(Thick::Java::ChannelFutureListener::CLOSE)
24
+ if @chunked
25
+ chunk = Thick::Java::ChannelBuffers.copiedBuffer("0\r\n\r\n", Thick::Java::CharsetUtil::UTF_8)
26
+ else
27
+ chunk = Thick::Java::ChannelBuffers::EMPTY_BUFFER
28
+ end
29
+ @context.channel.write(chunk).addListener(Thick::Java::ChannelFutureListener::CLOSE) unless closed?
30
+ closed!
20
31
  end
21
32
 
22
33
  def ready!
@@ -48,6 +59,30 @@ module Thick
48
59
  @async
49
60
  end
50
61
 
62
+ def chunked!
63
+ @chunked = true
64
+ end
65
+
66
+ def chunked?
67
+ @chunked
68
+ end
69
+
70
+ def content_length!(length)
71
+ @content_length = length
72
+ end
73
+
74
+ def content_length
75
+ @content_length
76
+ end
77
+
78
+ def closed!
79
+ @closed = true
80
+ end
81
+
82
+ def closed?
83
+ @closed
84
+ end
85
+
51
86
  end
52
87
 
53
88
  end
@@ -0,0 +1,88 @@
1
+ module Thick
2
+ class Controller
3
+
4
+ def initialize(options, server)
5
+ @options = options
6
+ @server = server
7
+ @factory = Thick::Java::NioServerSocketChannelFactory.new(Thick::Java::Executors.new_cached_thread_pool, Thick::Java::Executors.new_cached_thread_pool)
8
+ @bootstrap = Thick::Java::ServerBootstrap.new(@factory)
9
+ @bootstrap.pipeline_factory = Controller::PipelineFactory.new(@options)
10
+ end
11
+
12
+ def start
13
+ @channel = @bootstrap.bind(Thick::Java::InetSocketAddress.new('127.0.0.1', 9393))
14
+ puts "* Controller started on 127.0.0.1:9393"
15
+ self
16
+ end
17
+
18
+ def stop
19
+ @channel.close
20
+ self
21
+ end
22
+
23
+ class PipelineFactory
24
+
25
+ include Thick::Java::ChannelPipelineFactory
26
+
27
+ def initialize(options)
28
+ @options = options
29
+ end
30
+
31
+ def getPipeline
32
+ pipeline = Thick::Java::Channels.pipeline
33
+ pipeline.add_last('decoder', Thick::Java::HttpRequestDecoder.new)
34
+ pipeline.add_last('aggregator', Thick::Java::HttpChunkAggregator.new(65536))
35
+ pipeline.add_last('encoder', Thick::Java::HttpResponseEncoder.new)
36
+ pipeline.add_last('handler', Controller::Handler.new(@options))
37
+ pipeline
38
+ end
39
+
40
+ end
41
+
42
+ class Handler < Thick::Java::SimpleChannelUpstreamHandler
43
+
44
+ def messageReceived(context, event)
45
+ message = event.message
46
+ case message
47
+ when Thick::Java::HttpRequest
48
+ handle_request(context, message)
49
+ when Thick::Java::WebSocketFrame
50
+ handle_websocket_frame(context, message)
51
+ end
52
+ end
53
+
54
+ def handle_request(context, request)
55
+ url = "ws://" + request.get_header(Thick::Java::HttpHeaders::Names::HOST) + '/controller'
56
+ factory = Thick::Java::WebSocketServerHandshakerFactory.new(url, nil, false)
57
+ @handshaker = factory.new_handshaker(request)
58
+ if @handshaker
59
+ @handshaker.handshake(context, request)
60
+ else
61
+ factory.send_unsupported_webSocket_version_response(context)
62
+ end
63
+ end
64
+
65
+ def handle_websocket_frame(context, frame)
66
+ case frame
67
+ when Thick::Java::CloseWebSocketFrame
68
+ @handshaker.close(context, frame)
69
+ when Thick::Java::PingWebSocketFrame
70
+ context.channel.write(Thick::Java::PongWebSocketFrame.new(frame.binary_data))
71
+ when Thick::Java::TextWebSocketFrame
72
+ handle_websocket_message(context, frame.text)
73
+ end
74
+ end
75
+
76
+ def websocket_send(context, message)
77
+ context.channel.write(Thick::Java::TextWebSocketFrame.new(message.to_s))
78
+ end
79
+
80
+ def handle_websocket_message(context, message)
81
+
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+
88
+ end
data/lib/thick/java.rb CHANGED
@@ -8,16 +8,24 @@ module Thick
8
8
  java_import 'org.jboss.netty.buffer.ChannelBuffer'
9
9
  java_import 'org.jboss.netty.buffer.ChannelBufferInputStream'
10
10
  java_import 'org.jboss.netty.buffer.ChannelBuffers'
11
+ java_import 'org.jboss.netty.handler.codec.http.DefaultHttpChunk'
11
12
  java_import 'org.jboss.netty.handler.codec.http.DefaultHttpResponse'
12
13
  java_import 'org.jboss.netty.handler.codec.http.HttpContentDecompressor'
13
14
  java_import 'org.jboss.netty.handler.codec.http.HttpHeaders'
14
15
  java_import 'org.jboss.netty.handler.codec.http.HttpChunk'
16
+ java_import 'org.jboss.netty.handler.codec.http.HttpChunkAggregator'
15
17
  java_import 'org.jboss.netty.handler.codec.http.HttpRequest'
16
18
  java_import 'org.jboss.netty.handler.codec.http.HttpRequestDecoder'
17
19
  java_import 'org.jboss.netty.handler.codec.http.HttpResponseEncoder'
18
20
  java_import 'org.jboss.netty.handler.codec.http.HttpResponseStatus'
19
21
  java_import 'org.jboss.netty.handler.codec.http.HttpVersion'
20
22
  java_import 'org.jboss.netty.handler.codec.http.QueryStringDecoder'
23
+ java_import 'org.jboss.netty.handler.codec.http.websocketx.CloseWebSocketFrame'
24
+ java_import 'org.jboss.netty.handler.codec.http.websocketx.PingWebSocketFrame'
25
+ java_import 'org.jboss.netty.handler.codec.http.websocketx.PongWebSocketFrame'
26
+ java_import 'org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame'
27
+ java_import 'org.jboss.netty.handler.codec.http.websocketx.WebSocketFrame'
28
+ java_import 'org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory'
21
29
  java_import 'org.jboss.netty.handler.codec.spdy.SpdyFrameDecoder'
22
30
  java_import 'org.jboss.netty.handler.codec.spdy.SpdyFrameEncoder'
23
31
  java_import 'org.jboss.netty.handler.codec.spdy.SpdySessionHandler'
@@ -36,6 +44,10 @@ module Thick
36
44
  java_import 'org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory'
37
45
  java_import 'org.jboss.netty.logging.InternalLogLevel'
38
46
  java_import 'org.jboss.netty.util.CharsetUtil'
47
+ java_import 'org.jruby.CompatVersion'
48
+ java_import 'org.jruby.embed.AttributeName'
49
+ java_import 'org.jruby.embed.LocalContextScope'
50
+ java_import 'org.jruby.embed.ScriptingContainer'
39
51
 
40
52
  end
41
53
  end
@@ -0,0 +1,20 @@
1
+ module Thick
2
+
3
+ class Loader
4
+
5
+ def initialize(options)
6
+ @options = options
7
+ ENV['RACK_ENV'] ||= ENV['RAILS_ENV'] ||= @options[:environment]
8
+ @application = Rack::Builder.parse_file(@options[:file])[0]
9
+ end
10
+
11
+ def call(env)
12
+ @application.call(env)
13
+ rescue => e
14
+ puts e.message
15
+ puts e.backtrace
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -1,57 +1,16 @@
1
1
  module Thick
2
2
 
3
- class TimeProbe
4
-
5
- include Thick::Java::ChannelUpstreamHandler
6
- include Thick::Java::ChannelDownstreamHandler
7
-
8
- def self.setup
9
- @total = 0
10
- @count = 0
11
- end
12
-
13
- def initialize
14
- @time = Time.now.to_f
15
- end
16
-
17
- TimeProbe.setup
18
-
19
- def self.time(time)
20
- @total += time
21
- @count += 1
22
- if @count % 100 == 0
23
- puts "AVG: #{@total / @count}"
24
- setup
25
- end
26
- end
27
-
28
- def handleUpstream(context, event)
29
- context.send_upstream(event)
30
- end
31
-
32
- def handleDownstream(context, event)
33
- if event.respond_to?(:getState)
34
- stop = Time.now.to_f - @time
35
- self.class.time(stop)
36
- end
37
- context.send_downstream(event)
38
- end
39
-
40
- end
41
-
42
3
  class PipelineFactory
43
4
 
44
5
  include Thick::Java::ChannelPipelineFactory
45
6
 
46
- def initialize(application)
47
- @application = application
7
+ def initialize(options)
8
+ @options = options
48
9
  @executor = Thick::Java::ExecutionHandler.new(Thick::Java::OrderedMemoryAwareThreadPoolExecutor.new(20, 0, 0))
49
10
  end
50
11
 
51
12
  def getPipeline
52
13
  pipeline = Thick::Java::Channels.pipeline
53
-
54
- pipeline.add_last('time_probe', TimeProbe.new)
55
14
 
56
15
  pipeline.add_last('http_decoder', Thick::Java::HttpRequestDecoder.new)
57
16
  pipeline.add_last('http_encoder', Thick::Java::HttpResponseEncoder.new)
@@ -60,7 +19,7 @@ module Thick
60
19
 
61
20
  pipeline.add_last('executor', @executor)
62
21
 
63
- pipeline.add_last('handler', ServerHandler.new(@application))
22
+ pipeline.add_last('handler', ServerHandler.new(@options))
64
23
 
65
24
  pipeline
66
25
  end
data/lib/thick/server.rb CHANGED
@@ -1,29 +1,23 @@
1
1
  module Thick
2
2
 
3
- def self.start(application, options)
4
- @server = Server.new(application)
5
- @server.start(:address => options[:address], :port => options[:port])
6
- end
7
-
8
3
  class Server
9
4
 
10
- def initialize(application)
5
+ def initialize(options)
6
+ @options = options
11
7
  @factory = Thick::Java::NioServerSocketChannelFactory.new(Thick::Java::Executors.new_cached_thread_pool, Thick::Java::Executors.new_cached_thread_pool)
12
8
  @bootstrap = Thick::Java::ServerBootstrap.new(@factory)
13
- @bootstrap.pipeline_factory = PipelineFactory.new(application)
9
+ @bootstrap.pipeline_factory = PipelineFactory.new(@options)
14
10
  end
15
11
 
16
- def start(options = {})
17
- @channel = @bootstrap.bind(Thick::Java::InetSocketAddress.new(options[:address], options[:port]))
18
- puts 'Server started'
19
- loop do
20
- # ToDo: Is this hack needed?
21
- sleep(100)
22
- end
12
+ def start
13
+ @channel = @bootstrap.bind(Thick::Java::InetSocketAddress.new(@options[:address], @options[:port]))
14
+ puts "* Server started on #{@options[:address]}:#{@options[:port]}"
15
+ self
23
16
  end
24
17
 
25
18
  def stop
26
19
  @channel.close
20
+ self
27
21
  end
28
22
 
29
23
  end
@@ -1,12 +1,10 @@
1
- require 'stringio'
2
-
3
1
  module Thick
4
2
 
5
3
  class ServerHandler < Thick::Java::SimpleChannelUpstreamHandler
6
4
 
7
- def initialize(application)
5
+ def initialize(options)
8
6
  super()
9
- @application = application
7
+ @options = options
10
8
  end
11
9
 
12
10
  def channelConnected(context, event)
@@ -32,7 +30,7 @@ module Thick
32
30
  def on_request(context, request)
33
31
 
34
32
  # Serve file if exists in public directory
35
- file = File.join('public', request.uri)
33
+ file = File.join(@options[:directory], 'public', request.uri)
36
34
  return serve_file(context, file).addListener(Thick::Java::ChannelFutureListener::CLOSE) if !request.uri.index('..') && File.exists?(file) && !File.directory?(file)
37
35
 
38
36
  query_string = request.uri.split('?', 2)
@@ -53,7 +51,8 @@ module Thick
53
51
  'SERVER_NAME' => 'localhost', # ToDo: Be more precise!
54
52
  'SERVER_PORT' => '8080', # ToDo: Be more precise!
55
53
  # Thick specific
56
- 'thick.async' => AsyncResponse.new(context)
54
+ 'thick.async' => AsyncResponse.new(context),
55
+ 'thick.options' => @options
57
56
  }
58
57
 
59
58
  # Get content length if available
@@ -83,7 +82,7 @@ module Thick
83
82
  end
84
83
 
85
84
  def handle_request(context)
86
- response = @application.call(@env)
85
+ response = @options[:application].call(@env)
87
86
 
88
87
  # Let the application make the response as it wants
89
88
  if @env['thick.async'].custom?
@@ -102,6 +101,15 @@ module Thick
102
101
  Thick::Java::HttpHeaders.set_header(@response, name, value)
103
102
  end
104
103
 
104
+ if @env['thick.async'].async?
105
+ if length = @env['thick.async'].content_length
106
+ Thick::Java::HttpHeaders.set_content_length(@response, length)
107
+ else
108
+ @response.remove_header('Content-Length')
109
+ end
110
+ @response.chunked = true if @env['thick.async'].chunked?
111
+ end
112
+
105
113
  context.channel.write(@response)
106
114
 
107
115
  # Set content as requested by application
@@ -126,6 +134,7 @@ module Thick
126
134
  end
127
135
 
128
136
  def channelClosed(context, event)
137
+ @env['thick.async'].closed!
129
138
  end
130
139
 
131
140
  def exceptionCaught(context, e)
@@ -0,0 +1,29 @@
1
+ module Thick
2
+
3
+ def self.start(options)
4
+ @options = {
5
+ :address => '0.0.0.0',
6
+ :port => 9292,
7
+ :environment => 'development',
8
+ :reloader => false,
9
+ :controller => false,
10
+ :directory => Dir.getwd,
11
+ :file => 'config.ru'
12
+ }.merge(options)
13
+
14
+ puts "* Starting Thick: #{@options.inspect}"
15
+
16
+ @options[:application] = Loader.new(@options)
17
+ @server = Server.new(@options).start
18
+
19
+ if @options[:controller]
20
+ @controller = Controller.new(@options, @server)
21
+ @controller.start
22
+ end
23
+
24
+ loop do
25
+ sleep(100) # ToDo: Is this hack needed?
26
+ end
27
+ end
28
+
29
+ end
data/lib/thick/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Thick
2
- VERSION = '0.0.4' unless const_defined?(:VERSION)
2
+ VERSION = '0.0.5' unless const_defined?(:VERSION)
3
3
  end
data/lib/thick.rb CHANGED
@@ -2,12 +2,16 @@ require 'rack'
2
2
 
3
3
  require 'java'
4
4
 
5
- require File.expand_path('../jars/netty-3.4.0.Alpha2.jar', __FILE__)
5
+ require File.expand_path('../jars/netty-3.5.11.Final.jar', __FILE__)
6
6
 
7
7
  require 'thick/java'
8
+ require 'thick/thick'
8
9
  require 'thick/version'
9
10
  require 'thick/buffer'
10
11
  require 'thick/async_response'
12
+ require 'thick/loader'
11
13
  require 'thick/server_handler'
12
14
  require 'thick/pipeline_factory'
13
- require 'thick/server'
15
+ require 'thick/controller'
16
+ require 'thick/server'
17
+
metadata CHANGED
@@ -1,78 +1,113 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: thick
3
- version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.0.4
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.5
5
+ prerelease:
6
6
  platform: java
7
- authors:
8
- - Marek Jelen
9
- autorequire:
7
+ authors:
8
+ - Marek Jelen
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2012-03-29 00:00:00 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: rack
17
- prerelease: false
18
- requirement: &id001 !ruby/object:Gem::Requirement
19
- none: false
20
- requirements:
21
- - - "="
22
- - !ruby/object:Gem::Version
23
- version: 1.4.1
24
- type: :runtime
25
- version_requirements: *id001
12
+ date: 2012-11-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ version_requirements: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '='
19
+ - !ruby/object:Gem::Version
20
+ version: 1.4.1
21
+ none: false
22
+ requirement: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.4.1
27
+ none: false
28
+ prerelease: false
29
+ type: :runtime
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ version_requirements: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - '='
35
+ - !ruby/object:Gem::Version
36
+ version: 2.9.0
37
+ none: false
38
+ requirement: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - '='
41
+ - !ruby/object:Gem::Version
42
+ version: 2.9.0
43
+ none: false
44
+ prerelease: false
45
+ type: :development
26
46
  description: Very lightweight web server for JRuby based on Netty library.
27
- email:
28
- - marek@jelen.biz
29
- executables:
30
- - thick
47
+ email:
48
+ - marek@jelen.biz
49
+ executables:
50
+ - thick
31
51
  extensions: []
32
-
33
52
  extra_rdoc_files: []
34
-
35
- files:
36
- - bin/thick
37
- - lib/thick.rb
38
- - lib/jars/netty-3.4.0.Alpha2.jar
39
- - lib/thick/async_response.rb
40
- - lib/thick/buffer.rb
41
- - lib/thick/java.rb
42
- - lib/thick/pipeline_factory.rb
43
- - lib/thick/server.rb
44
- - lib/thick/server_handler.rb
45
- - lib/thick/version.rb
46
- - LICENSE
47
- - README.md
48
- - ROADMAP.md
49
- - CHANGELOG.md
53
+ files:
54
+ - !binary |-
55
+ YmluL3RoaWNr
56
+ - !binary |-
57
+ bGliL3RoaWNrLnJi
58
+ - !binary |-
59
+ bGliL3RoaWNrL3BpcGVsaW5lX2ZhY3RvcnkucmI=
60
+ - !binary |-
61
+ bGliL3RoaWNrL2phdmEucmI=
62
+ - !binary |-
63
+ bGliL3RoaWNrL3RoaWNrLnJi
64
+ - !binary |-
65
+ bGliL3RoaWNrL2xvYWRlci5yYg==
66
+ - !binary |-
67
+ bGliL3RoaWNrL3ZlcnNpb24ucmI=
68
+ - !binary |-
69
+ bGliL3RoaWNrL3NlcnZlcl9oYW5kbGVyLnJi
70
+ - !binary |-
71
+ bGliL3RoaWNrL2FzeW5jX3Jlc3BvbnNlLnJi
72
+ - !binary |-
73
+ bGliL3RoaWNrL2J1ZmZlci5yYg==
74
+ - !binary |-
75
+ bGliL3RoaWNrL2NvbnRyb2xsZXIucmI=
76
+ - !binary |-
77
+ bGliL3RoaWNrL3NlcnZlci5yYg==
78
+ - !binary |-
79
+ bGliL2phcnMvbmV0dHktMy41LjExLkZpbmFsLmphcg==
80
+ - LICENSE
81
+ - README.md
82
+ - ROADMAP.md
83
+ - CHANGELOG.md
50
84
  homepage: http://github.com/marekjelen/thick
51
85
  licenses: []
52
-
53
- post_install_message:
86
+ post_install_message:
54
87
  rdoc_options: []
55
-
56
- require_paths:
57
- - lib
58
- required_ruby_version: !ruby/object:Gem::Requirement
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ segments:
95
+ - 0
96
+ version: !binary |-
97
+ MA==
98
+ hash: 2
59
99
  none: false
60
- requirements:
61
- - - ">="
62
- - !ruby/object:Gem::Version
63
- version: "0"
64
- required_rubygems_version: !ruby/object:Gem::Requirement
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: !binary |-
105
+ MA==
65
106
  none: false
66
- requirements:
67
- - - ">="
68
- - !ruby/object:Gem::Version
69
- version: "0"
70
107
  requirements: []
71
-
72
- rubyforge_project:
73
- rubygems_version: 1.8.15
74
- signing_key:
108
+ rubyforge_project:
109
+ rubygems_version: 1.8.24
110
+ signing_key:
75
111
  specification_version: 3
76
112
  summary: Very lightweight web server for JRuby
77
113
  test_files: []
78
-
Binary file