s3_multipart 0.0.8 → 0.0.9
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/README.md +9 -2
- data/app/controllers/s3_multipart/uploads_controller.rb +3 -1
- data/app/models/s3_multipart/upload.rb +14 -7
- data/javascripts/s3mp.js +1 -0
- data/lib/generators/s3_multipart/templates/uploader.rb +3 -0
- data/lib/generators/s3_multipart/templates/uploads_table_migration.rb +2 -1
- data/lib/s3_multipart/railtie.rb +1 -1
- data/lib/s3_multipart/uploader/validations.rb +5 -1
- data/lib/s3_multipart/uploader.rb +0 -1
- data/lib/s3_multipart/version.rb +1 -1
- data/lib/s3_multipart.rb +4 -1
- data/spec/internal/app/uploaders/multipart/video_uploader.rb +3 -0
- data/spec/internal/db/schema.rb +1 -0
- data/vendor/assets/javascripts/s3_multipart/lib.js +1 -0
- data/vendor/assets/javascripts/s3_multipart/lib.min.js +1 -1
- metadata +3 -3
data/README.md
CHANGED
@@ -109,6 +109,9 @@ class VideoUploader < ApplicationController
|
|
109
109
|
# Only accept certain file types. Expects an array of valid extensions.
|
110
110
|
accept %w(wmv avi mp4 mkv mov mpeg)
|
111
111
|
|
112
|
+
# Define the minimum and maximum allowed file sizes (in bytes)
|
113
|
+
limit min: 5*1000*1000, max: 2*1000*1000*1000
|
114
|
+
|
112
115
|
# Takes in a block that will be evaluated when the upload has been
|
113
116
|
# successfully initiated. The block will be passed an instance of
|
114
117
|
# the upload object as well as the session hash when the callback is made.
|
@@ -141,7 +144,7 @@ To add the multipart uploader to a view, insert the following:
|
|
141
144
|
|
142
145
|
```ruby
|
143
146
|
<%= multipart_uploader_form(input_name: 'uploader',
|
144
|
-
uploader: 'VideoUploader'
|
147
|
+
uploader: 'VideoUploader',
|
145
148
|
button_class: 'submit-button',
|
146
149
|
button_text: 'Upload selected videos',
|
147
150
|
html: %Q{<button class="upload-button">Select videos</button>}) %>
|
@@ -210,12 +213,16 @@ S3_Multipart is very much a work in progress. If you squash a bug, make enhancem
|
|
210
213
|
|
211
214
|
The library is working on the latest version of IE, Firefox, Safari, and Chrome. Tests for over 100 browsers are currently being conducted.
|
212
215
|
|
216
|
+
## What's New
|
217
|
+
|
218
|
+
**0.0.9** - File type and size validations are now specified in the upload controller. Untested support for browsers that lack the FileBlob API
|
219
|
+
|
213
220
|
## To Do
|
214
221
|
|
215
222
|
* ~~If the FileBlob API is not supported on page load, the uploader should just send one giant chunk~~ (DONE)
|
216
223
|
* Handle network errors in the javascript client library
|
217
224
|
* ~~File type validations~~ (DONE)
|
218
|
-
* File size validations
|
225
|
+
* ~~File size validations~~ (DONE)
|
219
226
|
* More and better tests
|
220
227
|
* More browser testing
|
221
228
|
* Roll file signing and initiation into one request
|
@@ -6,7 +6,9 @@ module S3Multipart
|
|
6
6
|
upload = Upload.create(params)
|
7
7
|
upload.execute_callback(:begin, session)
|
8
8
|
response = upload.to_json
|
9
|
-
rescue
|
9
|
+
rescue FileTypeError, FileSizeError => e
|
10
|
+
response = {error: e.message}
|
11
|
+
rescue
|
10
12
|
response = {error: 'There was an error initiating the upload'}
|
11
13
|
ensure
|
12
14
|
render :json => response
|
@@ -2,12 +2,12 @@ module S3Multipart
|
|
2
2
|
class Upload < ::ActiveRecord::Base
|
3
3
|
extend S3Multipart::TransferHelpers
|
4
4
|
|
5
|
-
attr_accessible :key, :upload_id, :name, :location, :uploader
|
6
|
-
|
5
|
+
attr_accessible :key, :upload_id, :name, :location, :uploader, :size
|
6
|
+
before_create :validate_file_type, :validate_file_size
|
7
7
|
|
8
8
|
def self.create(params)
|
9
9
|
response = initiate(params)
|
10
|
-
super(key: response["key"], upload_id: response["upload_id"], name: response["name"], uploader: params["uploader"])
|
10
|
+
super(key: response["key"], upload_id: response["upload_id"], name: response["name"], uploader: params["uploader"], size: params["content_size"])
|
11
11
|
end
|
12
12
|
|
13
13
|
def execute_callback(stage, session)
|
@@ -23,12 +23,19 @@ module S3Multipart
|
|
23
23
|
|
24
24
|
private
|
25
25
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
26
|
+
def validate_file_size
|
27
|
+
size = self.size
|
28
|
+
limits = deserialize(self.uploader).size_limits
|
29
|
+
raise FileSizeError, "File size is too small" if limits[:min] > size
|
30
|
+
raise FileSizeError, "File size is too large" if limits[:max] < size
|
31
|
+
end
|
32
|
+
|
33
|
+
def validate_file_type
|
34
|
+
ext = self.name.match(/\.([a-zA-Z0-9]+)$/)[1]
|
35
|
+
controller = deserialize(self.uploader)
|
29
36
|
|
30
37
|
if !controller.file_types.include?(ext)
|
31
|
-
|
38
|
+
raise FileTypeError, "File type not supported"
|
32
39
|
end
|
33
40
|
end
|
34
41
|
|
data/javascripts/s3mp.js
CHANGED
@@ -160,6 +160,7 @@ S3MP.prototype.initiateMultipart = function(upload, cb) {
|
|
160
160
|
url = '/s3_multipart/uploads';
|
161
161
|
body = JSON.stringify({ object_name : upload.name,
|
162
162
|
content_type : upload.type,
|
163
|
+
content_size : upload.size,
|
163
164
|
uploader : $(this.fileInputElement).data("uploader")
|
164
165
|
});
|
165
166
|
|
@@ -8,6 +8,9 @@ class <%= model_constant %>Uploader < ApplicationController
|
|
8
8
|
# Only accept certain file types. Expects an array of valid extensions.
|
9
9
|
accept %w(wmv avi mp4 mkv mov mpeg)
|
10
10
|
|
11
|
+
# Define the minimum and maximum allowed file sizes (in bytes)
|
12
|
+
limit min: 5*1000*1000, max: 2*1000*1000*1000
|
13
|
+
|
11
14
|
# Takes in a block that will be evaluated when the upload has been
|
12
15
|
# successfully initiated. The block will be passed an instance of
|
13
16
|
# the upload object as well as the session hashwhen the callback is made.
|
data/lib/s3_multipart/railtie.rb
CHANGED
@@ -15,7 +15,7 @@ if defined?(Rails)
|
|
15
15
|
# Load all of the upload controllers in app/uploaders/multipart
|
16
16
|
initializer "s3_multipart.load_upload_controllers" do
|
17
17
|
begin
|
18
|
-
uploaders = Dir.entries(Rails.root.join('app', 'uploaders', 'multipart').to_s).keep_if {|n| n =~ /
|
18
|
+
uploaders = Dir.entries(Rails.root.join('app', 'uploaders', 'multipart').to_s).keep_if {|n| n =~ /uploader\.rb$/}
|
19
19
|
uploaders.each do |uploader|
|
20
20
|
require "#{Rails.root.join('app', 'uploaders', 'multipart')}/#{uploader}"
|
21
21
|
end
|
@@ -2,12 +2,16 @@ module S3Multipart
|
|
2
2
|
module Uploader
|
3
3
|
module Validations
|
4
4
|
|
5
|
-
attr_accessor :file_types
|
5
|
+
attr_accessor :file_types, :size_limits
|
6
6
|
|
7
7
|
def accept(types)
|
8
8
|
self.file_types = types
|
9
9
|
end
|
10
10
|
|
11
|
+
def limit(sizes)
|
12
|
+
self.size_limits = sizes
|
13
|
+
end
|
14
|
+
|
11
15
|
end
|
12
16
|
end
|
13
17
|
end
|
data/lib/s3_multipart/version.rb
CHANGED
data/lib/s3_multipart.rb
CHANGED
@@ -18,6 +18,9 @@ module S3Multipart
|
|
18
18
|
|
19
19
|
end
|
20
20
|
|
21
|
+
class FileTypeError < StandardError; end
|
22
|
+
class FileSizeError < StandardError; end
|
23
|
+
|
21
24
|
end
|
22
25
|
|
23
26
|
require 's3_multipart/config'
|
@@ -25,4 +28,4 @@ require 's3_multipart/railtie'
|
|
25
28
|
require 's3_multipart/engine'
|
26
29
|
require 's3_multipart/http/net_http'
|
27
30
|
require 's3_multipart/uploader'
|
28
|
-
require 's3_multipart/transfer_helpers'
|
31
|
+
require 's3_multipart/transfer_helpers'
|
@@ -8,6 +8,9 @@ class VideoUploader < ApplicationController
|
|
8
8
|
# Only accept certain file types. Expects an array of valid extensions.
|
9
9
|
accept %w(wmv avi mp4 mkv mov mpeg)
|
10
10
|
|
11
|
+
# Define the minimum and maximum allowed file sizes (in bytes)
|
12
|
+
limit min: 5*1000*1000, max: 2*1000*1000*1000
|
13
|
+
|
11
14
|
# Takes in a block that will be evaluated when the upload has been
|
12
15
|
# successfully initiated. The block will be passed an instance of
|
13
16
|
# the upload object when the callback is made.
|
data/spec/internal/db/schema.rb
CHANGED
@@ -174,6 +174,7 @@ S3MP.prototype.initiateMultipart = function(upload, cb) {
|
|
174
174
|
url = '/s3_multipart/uploads';
|
175
175
|
body = JSON.stringify({ object_name : upload.name,
|
176
176
|
content_type : upload.type,
|
177
|
+
content_size : upload.size,
|
177
178
|
uploader : $(this.fileInputElement).data("uploader")
|
178
179
|
});
|
179
180
|
|
@@ -1 +1 @@
|
|
1
|
-
(function(e){e.S3MP=function(){function t(t){var r,i=[],s=this;_.extend(this,t),this.uploadList=[],this.handler={beginUpload:function(){function t(t,n){var r=n.key,i=n.parts.length;typeof e[r]=="undefined"&&(e[r]=0),e[r]++;if(e[r]===i){for(var o=0;o<t;o++)n.parts[o].activate();s.handler.startProgressTimer(r),s.onStart(n)}}var e=[];return t}(),onError:function(e,t){},onPartSuccess:function(e,t){var n,r,i;n=e.parts,i=t.xhr.getResponseHeader("ETag"),e.Etags.push({ETag:i.replace(/\"/g,""),partNum:t.num}),e.uploaded+=t.size,e.inprogress[t.num]=0,r=_.indexOf(n,t),n.splice(r,1),n.length&&(r=_.findIndex(n,function(e,t,n){if(e.status!=="active")return!0}),r!==-1&&n[r].activate()),n.length||this.onComplete(e)},onComplete:function(e){var t=_.indexOf(s.uploadList,e);this.clearProgressTimer(t),s.completeMultipart(e,function(t){t.location&&s.onComplete(e)})},onProgress:function(e,t,n,r,i){s.onProgress(e,t,n,r,i)},startProgressTimer:function(){var t=[],n=function(n){i[n]=e.setInterval(function(){var e,r,i,o,u;typeof t[n]=="undefined"&&(t[n]=0),e=s.uploadList[n],r=e.size,i=e.uploaded,_.each(e.inprogress,function(e){i+=e}),o=i/r*100,u=i-t[n],t[n]=i,e.handler.onProgress(n,r,i,o,u)},1e3)};return n}(),clearProgressTimer:function(t){e.clearInterval(i[t])}},this.fileSelector?r=$(this.fileSelector).get(0).files:r=this.fileList,_.each(r,function(e,t){if(e.size<5e6)return s.onError({name:"FileSizeError",message:"File size is too small"});var r=new n(e,s,t);s.uploadList.push(r),r.init()})}function n(e,t,n){function i(){var t,i,s,o,u,a,f,l,c;t=this,this.key=n,this.file=e,this.name=e.name,this.size=e.size,this.type=e.type,this.Etags=[],this.inprogress=[],this.uploaded=0,this.status="",this.size>1e9?(num_segs=100,l=10):this.size>5e8?(num_segs=50,l=5):this.size>1e8?(num_segs=20,l=5):(num_segs=2,l=2),a=_.range(num_segs+1),f=_.map(a,function(t){return Math.round(t*(e.size/num_segs))}),t.sliceBlob=="Unsupported"?this.parts=[new r(e,0,t)]:(this.parts=_.map(f,function(n,i){return c=t.sliceBlob(e,n,f[i+1]),new r(c,i+1,t)}),this.parts.pop()),this.init=function(){t.initiateMultipart(t,function(e){var n=t.id=e.id,r=t.upload_id=e.upload_id,i=t.object_name=e.key,s=t.parts;t.signPartRequests(n,i,r,s,function(e){_.each(s,function(n,s){var o=n.xhr;o.open("PUT","http://"+t.bucket+".s3.amazonaws.com/"+i+"?partNumber="+n.num+"&uploadId="+r,!0),o.setRequestHeader("x-amz-date",e[s].date),o.setRequestHeader("Authorization",e[s].authorization),t.handler.beginUpload(l,t)})})})}}return i.prototype=t,new i}function r(e,t,n){var r,i;r=this,this.size=e.size,this.blob=e,this.num=t,this.xhr=i=n.createXhrRequest(),i.onload=function(){n.handler.onPartSuccess(n,r)},i.onerror=function(){n.handler.onError(n,r)},i.upload.onprogress=_.throttle(function(e){n.inprogress[t]=e.loaded},1e3)}return _.mixin({findIndex:function(e,t){for(var n=0;n<e.length;n++)if(t(e[n],n,e))return n;return-1}}),t.prototype.initiateMultipart=function(e,t){var n,r,i;n="/s3_multipart/uploads",r=JSON.stringify({object_name:e.name,content_type:e.type,uploader:$(this.fileInputElement).data("uploader")}),i=this.createXhrRequest("POST",n),this.deliverRequest(i,r,t)},t.prototype.signPartRequests=function(e,t,n,r,i){var s,o,u,a;s=_.reduce(_.rest(r),function(e,t){return e+"-"+t.size},r[0].size),o="s3_multipart/uploads/"+e,u=JSON.stringify({object_name:t,upload_id:n,content_lengths:s}),a=this.createXhrRequest("PUT",o),this.deliverRequest(a,u,i)},t.prototype.completeMultipart=function(e,t){var n,r,i;n="s3_multipart/uploads/"+e.id,r=JSON.stringify({object_name:e.object_name,upload_id:e.upload_id,content_length:e.size,parts:e.Etags}),i=this.createXhrRequest("PUT",n),this.deliverRequest(i,r,t)},t.prototype.deliverRequest=function(e,t,n){var r=this;e.onload=function(){response=JSON.parse(this.responseText);if(response.error)return r.onError({name:"ServerResponse",message:"The server responded with an error"});n(response)},e.onerror=function(){},e.setRequestHeader("Content-Type","application/json"),e.setRequestHeader("X-CSRF-Token",$('meta[name="csrf-token"]').attr("content")),e.send(t)},t.prototype.createXhrRequest=function(){var e;return typeof XMLHttpRequest.constructor=="function"?e=XMLHttpRequest:typeof XDomainRequest!="undefined"?e=XDomainRequest:e=null,function(t,n,r,i){var s,o,i=!0;return s=Array.prototype.slice.call(arguments),typeof s[0]=="undefined"&&(r=null,i=!1),o=new e,i&&o.open(t,n,!0),o.onreadystatechange=r,o}}(),t.prototype.sliceBlob=function(){try{var e=new Blob}catch(t){return"Unsupported"}return e.slice?function(e,t,n){return e.slice(t,n)}:e.mozSlice?function(e,t,n){return e.mozSlice(t,n)}:e.webkitSlice?function(e,t,n){return e.webkitSlice(t,n)}:"Unsupported"}(),t.prototype._returnUploadObj=function(e){var t=_.find(this.uploadList,function(t){return t.key===e});return t},t.prototype.cancel=function(e){var t,n;t=this._returnUploadObj(e),n=_.indexOf(this.uploadList,t),this.uploadList.splice(n,n+1),this.onCancel()},t.prototype.pause=function(e){var t=this._returnUploadObj(e);_.each(t.parts,function(e,t,n){e.status=="active"&&e.pause()}),this.onPause()},t.prototype.resume=function(e){var t=this._returnUploadObj(e);_.each(t.parts,function(e,t,n){e.status=="paused"&&e.activate()}),this.onResume()},r.prototype.activate=function(){this.xhr.send(this.blob),this.status="active"},r.prototype.pause=function(){this.xhr.abort(),this.status="paused"},t}()})(this);
|
1
|
+
(function(e){e.S3MP=function(){function t(t){var r,i=[],s=this;_.extend(this,t),this.uploadList=[],this.handler={beginUpload:function(){function t(t,n){var r=n.key,i=n.parts.length;typeof e[r]=="undefined"&&(e[r]=0),e[r]++;if(e[r]===i){for(var o=0;o<t;o++)n.parts[o].activate();s.handler.startProgressTimer(r),s.onStart(n)}}var e=[];return t}(),onError:function(e,t){},onPartSuccess:function(e,t){var n,r,i;n=e.parts,i=t.xhr.getResponseHeader("ETag"),e.Etags.push({ETag:i.replace(/\"/g,""),partNum:t.num}),e.uploaded+=t.size,e.inprogress[t.num]=0,r=_.indexOf(n,t),n.splice(r,1),n.length&&(r=_.findIndex(n,function(e,t,n){if(e.status!=="active")return!0}),r!==-1&&n[r].activate()),n.length||this.onComplete(e)},onComplete:function(e){var t=_.indexOf(s.uploadList,e);this.clearProgressTimer(t),s.completeMultipart(e,function(t){t.location&&s.onComplete(e)})},onProgress:function(e,t,n,r,i){s.onProgress(e,t,n,r,i)},startProgressTimer:function(){var t=[],n=function(n){i[n]=e.setInterval(function(){var e,r,i,o,u;typeof t[n]=="undefined"&&(t[n]=0),e=s.uploadList[n],r=e.size,i=e.uploaded,_.each(e.inprogress,function(e){i+=e}),o=i/r*100,u=i-t[n],t[n]=i,e.handler.onProgress(n,r,i,o,u)},1e3)};return n}(),clearProgressTimer:function(t){e.clearInterval(i[t])}},this.fileSelector?r=$(this.fileSelector).get(0).files:r=this.fileList,_.each(r,function(e,t){if(e.size<5e6)return s.onError({name:"FileSizeError",message:"File size is too small"});var r=new n(e,s,t);s.uploadList.push(r),r.init()})}function n(e,t,n){function i(){var t,i,s,o,u,a,f,l,c;t=this,this.key=n,this.file=e,this.name=e.name,this.size=e.size,this.type=e.type,this.Etags=[],this.inprogress=[],this.uploaded=0,this.status="",this.size>1e9?(num_segs=100,l=10):this.size>5e8?(num_segs=50,l=5):this.size>1e8?(num_segs=20,l=5):(num_segs=2,l=2),a=_.range(num_segs+1),f=_.map(a,function(t){return Math.round(t*(e.size/num_segs))}),t.sliceBlob=="Unsupported"?this.parts=[new r(e,0,t)]:(this.parts=_.map(f,function(n,i){return c=t.sliceBlob(e,n,f[i+1]),new r(c,i+1,t)}),this.parts.pop()),this.init=function(){t.initiateMultipart(t,function(e){var n=t.id=e.id,r=t.upload_id=e.upload_id,i=t.object_name=e.key,s=t.parts;t.signPartRequests(n,i,r,s,function(e){_.each(s,function(n,s){var o=n.xhr;o.open("PUT","http://"+t.bucket+".s3.amazonaws.com/"+i+"?partNumber="+n.num+"&uploadId="+r,!0),o.setRequestHeader("x-amz-date",e[s].date),o.setRequestHeader("Authorization",e[s].authorization),t.handler.beginUpload(l,t)})})})}}return i.prototype=t,new i}function r(e,t,n){var r,i;r=this,this.size=e.size,this.blob=e,this.num=t,this.xhr=i=n.createXhrRequest(),i.onload=function(){n.handler.onPartSuccess(n,r)},i.onerror=function(){n.handler.onError(n,r)},i.upload.onprogress=_.throttle(function(e){n.inprogress[t]=e.loaded},1e3)}return _.mixin({findIndex:function(e,t){for(var n=0;n<e.length;n++)if(t(e[n],n,e))return n;return-1}}),t.prototype.initiateMultipart=function(e,t){var n,r,i;n="/s3_multipart/uploads",r=JSON.stringify({object_name:e.name,content_type:e.type,content_size:e.size,uploader:$(this.fileInputElement).data("uploader")}),i=this.createXhrRequest("POST",n),this.deliverRequest(i,r,t)},t.prototype.signPartRequests=function(e,t,n,r,i){var s,o,u,a;s=_.reduce(_.rest(r),function(e,t){return e+"-"+t.size},r[0].size),o="s3_multipart/uploads/"+e,u=JSON.stringify({object_name:t,upload_id:n,content_lengths:s}),a=this.createXhrRequest("PUT",o),this.deliverRequest(a,u,i)},t.prototype.completeMultipart=function(e,t){var n,r,i;n="s3_multipart/uploads/"+e.id,r=JSON.stringify({object_name:e.object_name,upload_id:e.upload_id,content_length:e.size,parts:e.Etags}),i=this.createXhrRequest("PUT",n),this.deliverRequest(i,r,t)},t.prototype.deliverRequest=function(e,t,n){var r=this;e.onload=function(){response=JSON.parse(this.responseText);if(response.error)return r.onError({name:"ServerResponse",message:"The server responded with an error"});n(response)},e.onerror=function(){},e.setRequestHeader("Content-Type","application/json"),e.setRequestHeader("X-CSRF-Token",$('meta[name="csrf-token"]').attr("content")),e.send(t)},t.prototype.createXhrRequest=function(){var e;return typeof XMLHttpRequest.constructor=="function"?e=XMLHttpRequest:typeof XDomainRequest!="undefined"?e=XDomainRequest:e=null,function(t,n,r,i){var s,o,i=!0;return s=Array.prototype.slice.call(arguments),typeof s[0]=="undefined"&&(r=null,i=!1),o=new e,i&&o.open(t,n,!0),o.onreadystatechange=r,o}}(),t.prototype.sliceBlob=function(){try{var e=new Blob}catch(t){return"Unsupported"}return e.slice?function(e,t,n){return e.slice(t,n)}:e.mozSlice?function(e,t,n){return e.mozSlice(t,n)}:e.webkitSlice?function(e,t,n){return e.webkitSlice(t,n)}:"Unsupported"}(),t.prototype._returnUploadObj=function(e){var t=_.find(this.uploadList,function(t){return t.key===e});return t},t.prototype.cancel=function(e){var t,n;t=this._returnUploadObj(e),n=_.indexOf(this.uploadList,t),this.uploadList.splice(n,n+1),this.onCancel()},t.prototype.pause=function(e){var t=this._returnUploadObj(e);_.each(t.parts,function(e,t,n){e.status=="active"&&e.pause()}),this.onPause()},t.prototype.resume=function(e){var t=this._returnUploadObj(e);_.each(t.parts,function(e,t,n){e.status=="paused"&&e.activate()}),this.onResume()},r.prototype.activate=function(){this.xhr.send(this.blob),this.status="active"},r.prototype.pause=function(){this.xhr.abort(),this.status="paused"},t}()})(this);
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: s3_multipart
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-03-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: uuid
|
@@ -297,7 +297,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
297
297
|
version: '0'
|
298
298
|
requirements: []
|
299
299
|
rubyforge_project:
|
300
|
-
rubygems_version: 1.8.
|
300
|
+
rubygems_version: 1.8.25
|
301
301
|
signing_key:
|
302
302
|
specification_version: 3
|
303
303
|
summary: Upload directly to S3 using multipart uploading
|