yoomee-rwebthumb 0.2.13

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,47 @@
1
+ == rwebthumb
2
+
3
+ = what is it
4
+ A Ruby wrapper for the webthumb API from http://webthumb.bluga.net and a generator
5
+ for the easythumb API
6
+
7
+ = Installation
8
+ sudo gem update --system (in case you are not yet on version 1.2.0 or higher)
9
+ sudo gem sources -a http://gems.github.com (only once)
10
+ sudo gem install simplificator-rwebthumb
11
+
12
+
13
+ = Usage
14
+ # require the libs
15
+ require 'rubygems'
16
+ require 'rwebthumb'
17
+ include Simplificator::Webthumb
18
+
19
+ # Creating a Webthumb Object. This is used as your main access point.
20
+ wt = Webthumb.new('YOUR API KEY')
21
+
22
+ # Create a new thumbnail job
23
+ job = wt.thumbnail(:url => 'http://simplificator.com')
24
+
25
+ # fetch the thumbnail. this might throw an exception from server side
26
+ # if thumb is not ready yet
27
+ job.fetch(:large)
28
+
29
+ # you can check the status of a job
30
+ job.check_status()
31
+
32
+ # or fetch the thumbnail when it is complete
33
+ job.fetch_when_complete(:large)
34
+
35
+ # once thumbnails are fetched they are cached within the job. so a new fetch will not go to the server again
36
+
37
+ # there is a helper method to write the images to disk
38
+ job.write_file(job.fetch(:custom), '/tmp/test.jpg')
39
+
40
+ # if you have a job ID then you can use this to get a Job object and then use the fetch_xyz methods
41
+ wt.job_status(JOB_ID)
42
+
43
+ # generate a Easythumb URL
44
+ et = Easythumb.new('YOUR_API_KEY', 'YOUR_USER_ID')
45
+ # This returns an URL which you can directly use in your webpage
46
+ et.build_url(:url => 'http://simplificator.com', :size => :large, :cache => 1)
47
+
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'rwebthumb'
@@ -0,0 +1,5 @@
1
+ require 'time'
2
+ require 'rwebthumb/base'
3
+ require 'rwebthumb/job'
4
+ require 'rwebthumb/webthumb'
5
+ require 'rwebthumb/easythumb'
@@ -0,0 +1,82 @@
1
+ module Simplificator
2
+ module Webthumb
3
+ #
4
+ #
5
+ #
6
+ #
7
+ class Base
8
+ # Valid output_types for thumbnail requests
9
+ VALID_OUTPUT_TYPES = [:jpg, :png]
10
+ # Valid values for size element in fetch requests
11
+ VALID_SIZES = [:small, :medium, :medium2, :large, :full, :excerpt, :effect, :custom, :zip]
12
+
13
+ attr_reader :api_key
14
+ # Constructor
15
+ # api_key: the Webthumb api key, not nil and not blank
16
+ #
17
+ def initialize(api_key, api_endpoint = 'http://webthumb.bluga.net/api.php')
18
+ raise WebthumbException.new('Need an not nil and not blank api_key') if api_key == nil || api_key == ''
19
+ @api_key = api_key
20
+ @api_endpoint = api_endpoint
21
+ @api_uri = URI.parse(@api_endpoint)
22
+ end
23
+
24
+ # Parse the datetime string and returns a DateTime object in UTC time
25
+ # Webthumb returns the time in MST (Mountain Standard Time) which is some 7 hours
26
+ # behind UTC
27
+ def self.parse_webthumb_datetime(s)
28
+ Time.parse("#{s} MST").getutc
29
+ end
30
+
31
+ def do_request(xml)
32
+ request = Net::HTTP::Post.new(@api_uri.path)
33
+ request.body = xml.to_s
34
+ response = Net::HTTP.new(@api_uri.host, @api_uri.port).start {|p| p.request(request) }
35
+ case response
36
+ when Net::HTTPOK
37
+ case response.content_type.downcase
38
+ when 'text/xml'
39
+ REXML::Document.new(response.body)
40
+ when 'text/plain'
41
+ raise WebthumbException.new("Unsupported content type #{response.content_type}: Body was: #{response.body}")
42
+ when 'image/jpg', 'image/jpeg', 'image/png', 'archive/zip'
43
+ raise WebthumbException.new("No data returned though content type is #{response.content_type}") if response.body.length == 0
44
+ response.body
45
+ else
46
+ raise WebthumbException.new("Unsupported content type #{response.content_type}")
47
+ end
48
+ else
49
+ raise CommunicationException('Response code was not HTTP OK')
50
+ end
51
+ end
52
+
53
+
54
+ # builds the root node for webthumb requtes
55
+ def build_root_node()
56
+ root = REXML::Element.new('webthumb')
57
+ api = root.add_element('apikey')
58
+ api.text = @api_key
59
+ root
60
+ end
61
+
62
+ protected
63
+ #
64
+ # add a XML element if value is present.
65
+ # can be used to create XML for webthumb requests from ruby options hash.
66
+ #
67
+ # root: the root XML element where element is added to
68
+ # options: the hash where value is taken from
69
+ # key: the key to lookup the value in options
70
+ # name: the name of the XML element. defaults to key
71
+ #
72
+ def add_element(root, options, key, name = key.to_s)
73
+ root.add_element(name).add_text(options[key].to_s) if options.has_key?(key)
74
+ end
75
+
76
+ end
77
+ class WebthumbException < RuntimeError
78
+ end
79
+ class CommunicationException < RuntimeError
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,27 @@
1
+ require 'cgi'
2
+ require 'digest/md5'
3
+ module Simplificator
4
+ module Webthumb
5
+ class Easythumb
6
+ VALID_SIZES = [:small, :medium, :medium2, :large]
7
+ def initialize(api_key, user_id, api_endpoint = 'http://webthumb.bluga.net/easythumb.php')
8
+ @api_key = api_key
9
+ @user_id = user_id
10
+ @api_endpoint = api_endpoint
11
+ end
12
+
13
+ # Build an Easythumb URL
14
+ # options are
15
+ # url: the url to take a snapshot from. required.
16
+ # size: the size of the thumbnail to take (VALID_SIZES). Defaults to :medium
17
+ # cache: the maximum allowed age in the cache (1-30). Defaults to 15
18
+ def build_url(options = {})
19
+ raise WebthumbException.new(':url is required') if (options[:url] == nil || options[:url] == '')
20
+ options[:size] ||= :medium
21
+ options[:cache] ||= 15
22
+ hash_out = Digest::MD5.hexdigest("#{Time.now.strftime('%Y%m%d')}#{options[:url]}#{@api_key}")
23
+ "#{@api_endpoint}?user=#{@user_id}&cache=#{options[:cache]}&size=#{options[:size]}&url=#{CGI.escape(options[:url])}&hash=#{hash_out}"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,123 @@
1
+ module Simplificator
2
+ module Webthumb
3
+ class Job < Base
4
+
5
+ attr_reader :duration_estimate, :submission_datetime, :cost, :job_id, :url
6
+
7
+ # Constant for the status attribute when job is beeing processed
8
+ STATUS_PROCESSING = 100
9
+ # Constant for the status attribute when job is done
10
+ STATUS_PICKUP = 200
11
+
12
+ # Factory method to build a Job object from a REXML xml element
13
+ def self.from_thumbnail_xml(api_key, xml)
14
+ job_element = REXML::XPath.first(xml, '/webthumb/jobs/job')
15
+ return nil if job_element.nil?
16
+
17
+ submission_datetime = self.parse_webthumb_datetime(job_element.attributes['time'])
18
+ Job.new(api_key, job_element.text, job_element.attributes['url'], submission_datetime, job_element.attributes['estimate'].to_i, job_element.attributes['cost'].to_i)
19
+ end
20
+ # Factory method to create a Job object from a status XML.
21
+ # this does not set all attributes of the Job (url, duration_estimate, cost) since the API of webthumb does not
22
+ # return the same information on job creation and status requests.
23
+ def self.from_status_xml(api_key, xml)
24
+ status_element = REXML::XPath.first(xml, '/webthumb/jobStatus/status')
25
+ submission_datetime = self.parse_webthumb_datetime(status_element.attributes['submissionTime'])
26
+ job = Job.new(api_key, status_element.attributes['id'], nil, submission_datetime, 5, nil,
27
+ status_element.text == 'Complete' ? STATUS_PICKUP : STATUS_PROCESSING)
28
+ end
29
+ # Constructor.
30
+ # *api_key: webthumb API key. Required by all the operations which query the server
31
+ # *job_id: id of the job. Required.
32
+ # *url: the url of the site to snapshot. Optional
33
+ # *submission_datetime: UTC Datetime of job submission
34
+ # *duration_estimate: integer value indicating estimated job duration in seconds
35
+ # *cost: integer value indicating how many credit this request costet. Optional
36
+ # *status: one of the STATUS_XXX constants defined in Base. Defaults to STATUS_PROCESSING
37
+ def initialize(api_key, job_id, url, submission_datetime, duration_estimate, cost, status = STATUS_PROCESSING)
38
+ super(api_key)
39
+ @job_id = job_id
40
+ @url = url
41
+ @submission_datetime = submission_datetime
42
+ @duration_estimate = duration_estimate
43
+ @cost = cost
44
+ @status = status
45
+ @cache = {}
46
+ end
47
+
48
+ # Checks the status of the job on webthumb server.
49
+ # Returns one of the STATUS_XXX constants from Base.
50
+ # A call to this method updates the @status attribute.
51
+ def check_status
52
+ response = do_request(build_status_xml())
53
+ @status = REXML::XPath.first(response, '/webthumb/jobStatus/status').text == 'Complete' ? STATUS_PICKUP : STATUS_PROCESSING
54
+ if pickup?
55
+ @completion_time = response.attributes['completionTime']
56
+ end
57
+ @status
58
+ end
59
+
60
+ def fetch_when_complete(size = :small)
61
+ while not pickup?
62
+ sleep @duration_estimate
63
+ check_status
64
+ end
65
+ fetch(size)
66
+ end
67
+
68
+ # Fetch an image from the webthumb server.
69
+ # If the job has not yet finished then the server will return an error so check status first or use fetch_when_complete()
70
+ # Images are cached in the context of this Job so consequent calls are not requested from server again.
71
+ # Cache is experimental, dont know if it is a good idea.
72
+ def fetch(size = :small)
73
+ unless @cache.has_key?(size)
74
+ response = do_request(build_fetch_xml(size))
75
+ @cache[size] = response
76
+ end
77
+ @cache[size]
78
+ end
79
+
80
+ # Write the data to disk.
81
+ # *data: the bytes of the image as returned by fetch/fetch_when_complete
82
+ # *name: a filename
83
+ # Will return a File object
84
+ def write_file(data, name)
85
+ raise WebthumbException.new('No data given') if data == nil || data.size == 0
86
+ File.open(name, 'wb+') do |file|
87
+ file.write(data)
88
+ file.close
89
+ file
90
+ end
91
+ end
92
+
93
+ # Is the status attribute set to STATUS_PICKUP ?
94
+ def pickup?
95
+ @status == STATUS_PICKUP
96
+ end
97
+ # Is the status attribute set to STATUS_PROCESSING ?
98
+ def processing?
99
+ @status == STATUS_PROCESSING
100
+ end
101
+
102
+ private
103
+ def build_fetch_xml(size = :small)
104
+ raise WebthumbException.new("size parameter must be one of #{VALID_SIZES.join(', ')} but was #{size}") unless Base::VALID_SIZES.include?(size)
105
+ root = build_root_node()
106
+ fetch = root.add_element('fetch')
107
+ fetch.add_element('job').add_text(@job_id)
108
+ fetch.add_element('size').add_text(size.to_s)
109
+ root
110
+ end
111
+ def build_status_xml()
112
+ root = build_root_node()
113
+ status = root.add_element('status')
114
+ status.add_element('job').add_text(@job_id)
115
+ root
116
+ end
117
+
118
+ def to_s
119
+ "Job: #{@job_id} / Status: #{@status} / Submission Time #{@submission_time} / Duration Estimate #{@duration_estimate}"
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,111 @@
1
+ require 'net/http'
2
+ require 'rexml/document'
3
+ require 'date'
4
+ module Simplificator
5
+ module Webthumb
6
+
7
+ #
8
+ # Main access point for the webthumb API.
9
+ # All methods calling the Server need the api key beeing set.
10
+ #
11
+ class Webthumb < Base
12
+ # Request thumbnail creation from webthumb server. A Job object holding
13
+ # request information is returned (most important the job_id)
14
+ # Some keys have been ruby-ized (i.e. outputType -> :output_type). All keys are
15
+ # Symbols. Check out the webthumb API description for detailed explanation of the options
16
+ # http://webthumb.bluga.net/apidoc
17
+ # Options:
18
+ # * url: the url to take the snapshot from
19
+ # * output_type: chose output format (jpg or png)
20
+ # * width: width of the browser
21
+ # * height: height of the browser
22
+ # * fullthumb: full sized snapshot (true or false)
23
+ # * custom_thumbnail: create a custom sized thumbnail. A hash with width and height entries
24
+ # * effect: specify a visual effect (mirror, dropshadow or border)
25
+ # * delay: wait until the snapshot is taken
26
+ # * notify: callback url which is called after snapshot is taken
27
+ # * excerpt: taking an excerpt snapshot. A hash with for entries. width, height, x, y
28
+ # * videothumb: experimental option, check Joshs blog (http://blog.joshuaeichorn.com/archives/2008/07/08/videothumb-addon-to-webthumb-is-alpha/)
29
+ # (true or false)
30
+ # Only the url option is required. Check webthumb API for default values. Check also the different constants
31
+ # defined in Base.rb for valid values
32
+ #
33
+ def thumbnail(options = {})
34
+ Job.from_thumbnail_xml(@api_key, do_request(build_thumbnail_xml(options)))
35
+ end
36
+
37
+ # Request the job status from server.
38
+ # This can be used to look up job status from server when you just have the job ID, e.g. when you want to retrieve
39
+ # the thumbs later or when you use callbacks.
40
+ # The Job object returned from this method does not have all attributes set since. Webthumbs API does not return
41
+ # the requested URL, the duration estimation and the cost values when checking the status. I hope this will change someday.
42
+ def job_status(job_id)
43
+ raise WebthumbException.new('Job id is required') if job_id == nil || job_id == ''
44
+ Job.from_status_xml(@api_key, do_request(build_job_status_xml(job_id)))
45
+ end
46
+
47
+ # Check your credit status on the webthumbs server
48
+ # Returns a hash with two keys. See webthumb API for detailed information.
49
+ # * reserve: an integer
50
+ # * subscription: an integer
51
+ def credits()
52
+ response = do_request(build_credits_xml())
53
+ credit_elements = REXML::XPath.first(response, '/webthumb/credits').elements
54
+ {:reserve => credit_elements['reserve'].text.to_i, :subscription => credit_elements['subscription'].text.to_i}
55
+ end
56
+
57
+ private
58
+ def build_thumbnail_xml(options)
59
+ validate_thumbnail_options(options)
60
+
61
+
62
+ root = build_root_node()
63
+ request = root.add_element('request')
64
+ request.add_element('url').add_text(options[:url])
65
+ add_element(request, options, :output_type, 'outputType')
66
+ # these elements have the same name as the key in options hash
67
+ [:width, :height, :effect, :delay, :notify].each {|item| add_element(request, options, item)}
68
+ # these options need conversion from true/false to 0/1
69
+ if options[:fullthumb] == true
70
+ request.add_element('fullthumb').add_text('1')
71
+ end
72
+ if options[:videothumb] == true
73
+ request.add_element('videothumb').add_text('1')
74
+ end
75
+ if options.has_key?(:custom_thumbnail)
76
+ request.add_element('customThumbnail',
77
+ 'width' => options[:custom_thumbnail][:width].to_s,
78
+ 'height' => options[:custom_thumbnail][:height].to_s)
79
+
80
+ end
81
+ if options.has_key?(:excerpt)
82
+ excerpt = request.add_element('excerpt')
83
+ [:x, :y, :width, :height].each {|item| add_element(excerpt, options[:excerpt], item)}
84
+ end
85
+ root
86
+ end
87
+
88
+ def build_job_status_xml(job_id)
89
+ root = build_root_node()
90
+ root.add_element('status').add_element('job').add_text(job_id)
91
+ root
92
+ end
93
+
94
+ def build_credits_xml()
95
+ root = build_root_node()
96
+ root.add_element('credits')
97
+ root
98
+ end
99
+
100
+ def validate_thumbnail_options(options)
101
+ raise WebthumbException.new('Need an URL') if options[:url] == nil || options[:url] == ''
102
+ #raise WebthumbException.new("output_type is invalid: #{options[:output_type]}") if options.has_key?(:output_type) and (not Base::VALID_OUTPUT_TYPES.include?(options[:output_type]))
103
+ end
104
+ end
105
+
106
+ end
107
+ end
108
+
109
+
110
+
111
+
@@ -0,0 +1,23 @@
1
+ require File.join(File.dirname(__FILE__), 'helper')
2
+ class BaseTest < Test::Unit::TestCase
3
+ def test_api_key_required
4
+ assert_raises(WebthumbException) { Base.new('') }
5
+ assert_raises(WebthumbException) { Base.new(nil) }
6
+ end
7
+
8
+ def test_parse_webthumb_date
9
+ [['2000-1-1 14:00:00', '2000-1-1 07:00:00'], ['2000-1-1 07:00:00', '2000-1-1 00:00:00'], ['2000-8-1 07:44:2', '2000-8-1 00:44:02']].each do |item|
10
+ utc = Time.parse("#{item[0]} UTC")
11
+ mst = Base.parse_webthumb_datetime(item[1])
12
+ assert_equal(utc, mst)
13
+ end
14
+ end
15
+
16
+ def test_build_root_node()
17
+ root = Base.new('1234').build_root_node()
18
+ assert_not_nil(root)
19
+ assert_not_nil(REXML::XPath.first(root, '/'))
20
+ assert_not_nil(REXML::XPath.first(root, '/apikey'))
21
+ assert_equal('1234', REXML::XPath.first(root, '/apikey').text)
22
+ end
23
+ end
@@ -0,0 +1,4 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'rwebthumb'
4
+ include Simplificator::Webthumb
@@ -0,0 +1,48 @@
1
+ require File.join(File.dirname(__FILE__), 'helper')
2
+ class JobTest < Test::Unit::TestCase
3
+ JOB_XML = <<-EOF
4
+ <webthumb>
5
+ <jobs>
6
+ <job estimate='20' time='2008-02-27 12:49:48' url='http://blog.joshuaeichorn.com' cost='1'>wt47c5f71c37c3a</job>
7
+ </jobs>
8
+ </webthumb>
9
+ EOF
10
+
11
+ JOBLESS_XML = <<-EOF
12
+ <webthumb>
13
+ </webthumb>
14
+ EOF
15
+
16
+ def setup_job_from_xml(xml)
17
+ job_xml = REXML::Document.new(xml)
18
+ @job = Job.from_thumbnail_xml('1234', job_xml)
19
+ end
20
+
21
+ def test_from_thumbnail_xml
22
+ setup_job_from_xml(JOB_XML)
23
+ assert_equal('1234', @job.api_key)
24
+ assert_equal(20, @job.duration_estimate)
25
+ assert_equal(Time.parse('2008-02-27 19:49:48 UTC'), @job.submission_datetime)
26
+ assert_equal('http://blog.joshuaeichorn.com', @job.url)
27
+ assert_equal(1, @job.cost)
28
+ assert_equal('wt47c5f71c37c3a', @job.job_id)
29
+ end
30
+
31
+ def test_build_fetch()
32
+ setup_job_from_xml(JOB_XML)
33
+ xml = @job.send(:build_fetch_xml)
34
+ assert_equal('small', REXML::XPath.first(xml, 'fetch/size').text)
35
+ assert_equal('wt47c5f71c37c3a', REXML::XPath.first(xml, 'fetch/job').text)
36
+ end
37
+
38
+ def test_build_status_xml()
39
+ setup_job_from_xml(JOB_XML)
40
+ xml = @job.send(:build_status_xml)
41
+ assert_equal('wt47c5f71c37c3a', REXML::XPath.first(xml, 'status/job').text)
42
+ end
43
+
44
+ def test_from_thumbnail_xml_without_any_jobs()
45
+ setup_job_from_xml(JOBLESS_XML)
46
+ assert_nil @job
47
+ end
48
+ end
@@ -0,0 +1,35 @@
1
+ require File.join(File.dirname(__FILE__), 'helper')
2
+ class WebthumbTest < Test::Unit::TestCase
3
+
4
+
5
+
6
+ def test_build_fetch()
7
+ xml = Webthumb.new('1234').send(:build_thumbnail_xml,
8
+ :url => 'http://simplificator.com',
9
+ :videothumb => true, :fullthumb => true, :effect => 'dropshadow', :output_type => :jpg,
10
+ :width => 1024, :height => 2048, :custom_thumbnail => {:width => 300, :height => 400},
11
+ :excerpt => {:x => 30, :y => 40, :width => 600, :height => 345}, :delay => 20, :notify => 'http://foo.bar.com')
12
+ assert_equal('http://simplificator.com', REXML::XPath.first(xml, 'request/url').text)
13
+ assert_equal('1', REXML::XPath.first(xml, 'request/videothumb').text)
14
+ assert_equal('1', REXML::XPath.first(xml, 'request/fullthumb').text)
15
+ assert_equal('dropshadow', REXML::XPath.first(xml, 'request/effect').text)
16
+ assert_equal('jpg', REXML::XPath.first(xml, 'request/outputType').text)
17
+ assert_equal('1024', REXML::XPath.first(xml, 'request/width').text)
18
+ assert_equal('2048', REXML::XPath.first(xml, 'request/height').text)
19
+ assert_equal('300', REXML::XPath.first(xml, 'request/customThumbnail').attributes['width'])
20
+ assert_equal('400', REXML::XPath.first(xml, 'request/customThumbnail').attributes['height'])
21
+ assert_equal('30', REXML::XPath.first(xml, 'request/excerpt/x').text)
22
+ assert_equal('40', REXML::XPath.first(xml, 'request/excerpt/y').text)
23
+ assert_equal('600', REXML::XPath.first(xml, 'request/excerpt/width').text)
24
+ assert_equal('345', REXML::XPath.first(xml, 'request/excerpt/height').text)
25
+ assert_equal('20', REXML::XPath.first(xml, 'request/delay').text)
26
+ assert_equal('http://foo.bar.com', REXML::XPath.first(xml, 'request/notify').text)
27
+
28
+
29
+ end
30
+
31
+ def test_build_job_status_xml()
32
+ xml = Webthumb.new('1234').send(:build_job_status_xml, 'abcd')
33
+ assert_equal('abcd', REXML::XPath.first(xml, 'status/job').text)
34
+ end
35
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yoomee-rwebthumb
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 13
9
+ version: 0.2.13
10
+ platform: ruby
11
+ authors:
12
+ - Simplificator GmbH
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-03-16 00:00:00 +00:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: "rwebthumb provides a ruby interface for the webthumb.bluga.net. "
22
+ email: info@simplificator.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - lib/rwebthumb.rb
31
+ - lib/rwebthumb/base.rb
32
+ - lib/rwebthumb/job.rb
33
+ - lib/rwebthumb/webthumb.rb
34
+ - test/base_test.rb
35
+ - test/helper.rb
36
+ - test/job_test.rb
37
+ - test/webthumb_test.rb
38
+ - lib/rwebthumb/easythumb.rb
39
+ - README
40
+ - init.rb
41
+ has_rdoc: true
42
+ homepage: http://simplificator.com/
43
+ licenses: []
44
+
45
+ post_install_message:
46
+ rdoc_options: []
47
+
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ requirements: []
67
+
68
+ rubyforge_project:
69
+ rubygems_version: 1.3.7
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: rwebthumb provides a ruby interface for the webthumb.bluga.net
73
+ test_files: []
74
+