aws-sdk-s3 1.48.0 → 1.51.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.
- checksums.yaml +4 -4
- data/lib/aws-sdk-s3/client.rb +1 -1
- data/lib/aws-sdk-s3/customizations/object.rb +65 -43
- data/lib/aws-sdk-s3/encryption/client.rb +4 -0
- data/lib/aws-sdk-s3/file_part.rb +9 -6
- data/lib/aws-sdk-s3/file_uploader.rb +13 -12
- data/lib/aws-sdk-s3/multipart_file_uploader.rb +14 -11
- data/lib/aws-sdk-s3/plugins/md5s.rb +3 -4
- data/lib/aws-sdk-s3.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '039fad1e173a3cfb90b575982a4b13cd4c39d648'
|
|
4
|
+
data.tar.gz: 3245e49e28ff8886d2c0ed0061a5a73443b14644
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ffc16878216117fcfa119d68e71f25e2b9e40503429bfbe79318a8b87d698b48b0b97050ca405fdee86d74eb62299739f26cc0d007204a69002f161529b81cd7
|
|
7
|
+
data.tar.gz: 59899b906bb1ab3b84d205799e038ab9347002f9956bd25b331ed173590a64356512d6b1cb6585fcc58f37303ce5399a7f1d426af0db915f6c4906ee4487ff9f
|
data/lib/aws-sdk-s3/client.rb
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
module Aws
|
|
2
2
|
module S3
|
|
3
3
|
class Object
|
|
4
|
-
|
|
5
4
|
alias size content_length
|
|
6
5
|
|
|
7
6
|
# Copies another object to this object. Use `multipart_copy: true`
|
|
8
7
|
# for large objects. This is required for objects that exceed 5GB.
|
|
9
8
|
#
|
|
10
|
-
# @param [S3::Object, S3::ObjectVersion, S3::ObjectSummary, String, Hash]
|
|
11
|
-
# Where to copy object data from. `source` must be one of the
|
|
9
|
+
# @param [S3::Object, S3::ObjectVersion, S3::ObjectSummary, String, Hash]
|
|
10
|
+
# source Where to copy object data from. `source` must be one of the
|
|
11
|
+
# following:
|
|
12
12
|
#
|
|
13
13
|
# * {Aws::S3::Object}
|
|
14
14
|
# * {Aws::S3::ObjectSummary}
|
|
@@ -103,8 +103,9 @@ module Aws
|
|
|
103
103
|
ObjectCopier.new(self, options).copy_to(target, options)
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
-
# Copies and deletes the current object. The object will only be
|
|
107
|
-
#
|
|
106
|
+
# Copies and deletes the current object. The object will only be deleted
|
|
107
|
+
# if the copy operation succeeds.
|
|
108
|
+
#
|
|
108
109
|
# @param (see Object#copy_to)
|
|
109
110
|
# @option (see Object#copy_to)
|
|
110
111
|
# @return [void]
|
|
@@ -129,10 +130,7 @@ module Aws
|
|
|
129
130
|
client.config.credentials,
|
|
130
131
|
client.config.region,
|
|
131
132
|
bucket_name,
|
|
132
|
-
{
|
|
133
|
-
key: key,
|
|
134
|
-
url: bucket.url,
|
|
135
|
-
}.merge(options)
|
|
133
|
+
{ key: key, url: bucket.url }.merge(options)
|
|
136
134
|
)
|
|
137
135
|
end
|
|
138
136
|
|
|
@@ -186,10 +184,10 @@ module Aws
|
|
|
186
184
|
#
|
|
187
185
|
def presigned_url(http_method, params = {})
|
|
188
186
|
presigner = Presigner.new(client: client)
|
|
189
|
-
presigner.presigned_url(
|
|
190
|
-
|
|
191
|
-
key: key
|
|
192
|
-
)
|
|
187
|
+
presigner.presigned_url(
|
|
188
|
+
"#{http_method.downcase}_object",
|
|
189
|
+
params.merge(bucket: bucket_name, key: key)
|
|
190
|
+
)
|
|
193
191
|
end
|
|
194
192
|
|
|
195
193
|
# Returns the public (un-signed) URL for this object.
|
|
@@ -199,7 +197,8 @@ module Aws
|
|
|
199
197
|
#
|
|
200
198
|
# To use virtual hosted bucket url (disables https):
|
|
201
199
|
#
|
|
202
|
-
# s3.bucket('my.bucket.com').object('key')
|
|
200
|
+
# s3.bucket('my.bucket.com').object('key')
|
|
201
|
+
# .public_url(virtual_host: true)
|
|
203
202
|
# #=> "http://my.bucket.com/key"
|
|
204
203
|
#
|
|
205
204
|
# @option options [Boolean] :virtual_host (false) When `true`, the bucket
|
|
@@ -216,11 +215,12 @@ module Aws
|
|
|
216
215
|
|
|
217
216
|
# Uploads a stream in a streaming fashion to the current object in S3.
|
|
218
217
|
#
|
|
219
|
-
#
|
|
220
|
-
#
|
|
221
|
-
#
|
|
218
|
+
# Passed chunks automatically split into multipart upload parts and the
|
|
219
|
+
# parts are uploaded in parallel. This allows for streaming uploads that
|
|
220
|
+
# never touch the disk.
|
|
222
221
|
#
|
|
223
|
-
#
|
|
222
|
+
# Note that this is known to have issues in JRuby until jruby-9.1.15.0,
|
|
223
|
+
# so avoid using this with older versions of JRuby.
|
|
224
224
|
#
|
|
225
225
|
# @example Streaming chunks of data
|
|
226
226
|
# obj.upload_stream do |write_stream|
|
|
@@ -235,17 +235,15 @@ module Aws
|
|
|
235
235
|
# IO.copy_stream(STDIN, write_stream)
|
|
236
236
|
# end
|
|
237
237
|
#
|
|
238
|
-
# @option options [Integer] :thread_count
|
|
239
|
-
#
|
|
240
|
-
# Default `:thread_count` is `10`.
|
|
238
|
+
# @option options [Integer] :thread_count (10) The number of parallel
|
|
239
|
+
# multipart uploads
|
|
241
240
|
#
|
|
242
|
-
# @option options [Boolean] :tempfile
|
|
243
|
-
#
|
|
244
|
-
#
|
|
241
|
+
# @option options [Boolean] :tempfile (false) Normally read data is stored
|
|
242
|
+
# in memory when building the parts in order to complete the underlying
|
|
243
|
+
# multipart upload. By passing `:tempfile => true` data read will be
|
|
245
244
|
# temporarily stored on disk reducing the memory footprint vastly.
|
|
246
|
-
# Default `:tempfile` is `false`.
|
|
247
245
|
#
|
|
248
|
-
# @option options [Integer] :part_size
|
|
246
|
+
# @option options [Integer] :part_size (5242880)
|
|
249
247
|
# Define how big each part size but the last should be.
|
|
250
248
|
# Default `:part_size` is `5 * 1024 * 1024`.
|
|
251
249
|
#
|
|
@@ -264,9 +262,12 @@ module Aws
|
|
|
264
262
|
client: client,
|
|
265
263
|
thread_count: uploading_options.delete(:thread_count),
|
|
266
264
|
tempfile: uploading_options.delete(:tempfile),
|
|
267
|
-
part_size: uploading_options.delete(:part_size)
|
|
265
|
+
part_size: uploading_options.delete(:part_size)
|
|
266
|
+
)
|
|
267
|
+
uploader.upload(
|
|
268
|
+
uploading_options.merge(bucket: bucket_name, key: key),
|
|
269
|
+
&block
|
|
268
270
|
)
|
|
269
|
-
uploader.upload(uploading_options.merge(bucket: bucket_name, key: key), &block)
|
|
270
271
|
true
|
|
271
272
|
end
|
|
272
273
|
|
|
@@ -282,15 +283,29 @@ module Aws
|
|
|
282
283
|
# # and the parts are uploaded in parallel
|
|
283
284
|
# obj.upload_file('/path/to/very_large_file')
|
|
284
285
|
#
|
|
285
|
-
#
|
|
286
|
-
#
|
|
287
|
-
#
|
|
288
|
-
#
|
|
286
|
+
# The response of the S3 upload API is yielded if a block given.
|
|
287
|
+
#
|
|
288
|
+
# # API response will have etag value of the file
|
|
289
|
+
# obj.upload_file('/path/to/file') do |response|
|
|
290
|
+
# etag = response.etag
|
|
291
|
+
# end
|
|
292
|
+
#
|
|
293
|
+
# @param [String, Pathname, File, Tempfile] source A file on the local
|
|
294
|
+
# file system that will be uploaded as this object. This can either be
|
|
295
|
+
# a String or Pathname to the file, an open File object, or an open
|
|
296
|
+
# Tempfile object. If you pass an open File or Tempfile object, then
|
|
297
|
+
# you are responsible for closing it after the upload completes. When
|
|
298
|
+
# using an open Tempfile, rewind it before uploading or else the object
|
|
299
|
+
# will be empty.
|
|
289
300
|
#
|
|
290
301
|
# @option options [Integer] :multipart_threshold (15728640) Files larger
|
|
291
302
|
# than `:multipart_threshold` are uploaded using the S3 multipart APIs.
|
|
292
303
|
# Default threshold is 15MB.
|
|
293
304
|
#
|
|
305
|
+
# @option options [Integer] :thread_count (10) The number of parallel
|
|
306
|
+
# multipart uploads. This option is not used if the file is smaller than
|
|
307
|
+
# `:multipart_threshold`.
|
|
308
|
+
#
|
|
294
309
|
# @raise [MultipartUploadError] If an object is being uploaded in
|
|
295
310
|
# parts, and the upload can not be completed, then the upload is
|
|
296
311
|
# aborted and this error is raised. The raised error has a `#errors`
|
|
@@ -304,8 +319,13 @@ module Aws
|
|
|
304
319
|
uploading_options = options.dup
|
|
305
320
|
uploader = FileUploader.new(
|
|
306
321
|
multipart_threshold: uploading_options.delete(:multipart_threshold),
|
|
307
|
-
client: client
|
|
308
|
-
|
|
322
|
+
client: client
|
|
323
|
+
)
|
|
324
|
+
response = uploader.upload(
|
|
325
|
+
source,
|
|
326
|
+
uploading_options.merge(bucket: bucket_name, key: key)
|
|
327
|
+
)
|
|
328
|
+
yield response if block_given?
|
|
309
329
|
true
|
|
310
330
|
end
|
|
311
331
|
|
|
@@ -320,7 +340,7 @@ module Aws
|
|
|
320
340
|
# # and the parts are downloaded in parallel
|
|
321
341
|
# obj.download_file('/path/to/very_large_file')
|
|
322
342
|
#
|
|
323
|
-
# @param [String] destination Where to download the file to
|
|
343
|
+
# @param [String] destination Where to download the file to.
|
|
324
344
|
#
|
|
325
345
|
# @option options [String] mode `auto`, `single_request`, `get_range`
|
|
326
346
|
# `single_request` mode forces only 1 GET request is made in download,
|
|
@@ -328,21 +348,23 @@ module Aws
|
|
|
328
348
|
# customizing each range size in multipart_download,
|
|
329
349
|
# By default, `auto` mode is enabled, which performs multipart_download
|
|
330
350
|
#
|
|
331
|
-
# @option options [String] chunk_size required in get_range mode
|
|
351
|
+
# @option options [String] chunk_size required in get_range mode.
|
|
332
352
|
#
|
|
333
|
-
# @option options [
|
|
334
|
-
#
|
|
353
|
+
# @option options [Integer] thread_count (10) Customize threads used in
|
|
354
|
+
# the multipart download.
|
|
335
355
|
#
|
|
336
|
-
# @option options [String] version_id The object version id used to
|
|
337
|
-
# the object
|
|
356
|
+
# @option options [String] version_id The object version id used to
|
|
357
|
+
# retrieve the object. For more about object versioning, see:
|
|
338
358
|
# https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectVersioning.html
|
|
339
359
|
#
|
|
340
|
-
# @return [Boolean] Returns `true` when the file is downloaded
|
|
341
|
-
#
|
|
360
|
+
# @return [Boolean] Returns `true` when the file is downloaded without
|
|
361
|
+
# any errors.
|
|
342
362
|
def download_file(destination, options = {})
|
|
343
363
|
downloader = FileDownloader.new(client: client)
|
|
344
364
|
downloader.download(
|
|
345
|
-
destination,
|
|
365
|
+
destination,
|
|
366
|
+
options.merge(bucket: bucket_name, key: key)
|
|
367
|
+
)
|
|
346
368
|
true
|
|
347
369
|
end
|
|
348
370
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'forwardable'
|
|
2
|
+
|
|
1
3
|
module Aws
|
|
2
4
|
module S3
|
|
3
5
|
|
|
@@ -178,6 +180,8 @@ module Aws
|
|
|
178
180
|
class Client
|
|
179
181
|
|
|
180
182
|
extend Deprecations
|
|
183
|
+
extend Forwardable
|
|
184
|
+
def_delegators :@client, :delete_object, :head_object
|
|
181
185
|
|
|
182
186
|
# Creates a new encryption client. You must provide one of the following
|
|
183
187
|
# options:
|
data/lib/aws-sdk-s3/file_part.rb
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
module Aws
|
|
2
2
|
module S3
|
|
3
3
|
|
|
4
|
-
# A utility class that provides an IO-like interface to a portion of
|
|
5
|
-
#
|
|
4
|
+
# A utility class that provides an IO-like interface to a portion of a file
|
|
5
|
+
# on disk.
|
|
6
6
|
# @api private
|
|
7
7
|
class FilePart
|
|
8
8
|
|
|
9
|
-
# @option options [required,String,Pathname,File,Tempfile] :source
|
|
10
|
-
#
|
|
9
|
+
# @option options [required, String, Pathname, File, Tempfile] :source
|
|
10
|
+
# The file to upload.
|
|
11
|
+
#
|
|
12
|
+
# @option options [required, Integer] :offset The file part will read
|
|
11
13
|
# starting at this byte offset.
|
|
12
|
-
#
|
|
14
|
+
#
|
|
15
|
+
# @option options [required, Integer] :size The maximum number of bytes to
|
|
13
16
|
# read from the `:offset`.
|
|
14
17
|
def initialize(options = {})
|
|
15
18
|
@source = options[:source]
|
|
@@ -19,7 +22,7 @@ module Aws
|
|
|
19
22
|
@file = nil
|
|
20
23
|
end
|
|
21
24
|
|
|
22
|
-
# @return [String,Pathname,File,Tempfile]
|
|
25
|
+
# @return [String, Pathname, File, Tempfile]
|
|
23
26
|
attr_reader :source
|
|
24
27
|
|
|
25
28
|
# @return [Integer]
|
|
@@ -7,13 +7,14 @@ module Aws
|
|
|
7
7
|
|
|
8
8
|
FIFTEEN_MEGABYTES = 15 * 1024 * 1024
|
|
9
9
|
|
|
10
|
+
# @param [Hash] options
|
|
10
11
|
# @option options [Client] :client
|
|
11
|
-
# @option options [Integer] :multipart_threshold
|
|
12
|
-
# `:multipart_threshold` bytes are uploaded using S3 multipart APIs.
|
|
12
|
+
# @option options [Integer] :multipart_threshold (15728640)
|
|
13
13
|
def initialize(options = {})
|
|
14
14
|
@options = options
|
|
15
15
|
@client = options[:client] || Client.new
|
|
16
|
-
@multipart_threshold = options[:multipart_threshold] ||
|
|
16
|
+
@multipart_threshold = options[:multipart_threshold] ||
|
|
17
|
+
FIFTEEN_MEGABYTES
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
# @return [Client]
|
|
@@ -23,9 +24,9 @@ module Aws
|
|
|
23
24
|
# using a {MultipartFileUploader}.
|
|
24
25
|
attr_reader :multipart_threshold
|
|
25
26
|
|
|
26
|
-
# @param [String,Pathname,File,Tempfile] source
|
|
27
|
-
# @option options [required,String] :bucket
|
|
28
|
-
# @option options [required,String] :key
|
|
27
|
+
# @param [String, Pathname, File, Tempfile] source The file to upload.
|
|
28
|
+
# @option options [required, String] :bucket The bucket to upload to.
|
|
29
|
+
# @option options [required, String] :key The key for the object.
|
|
29
30
|
# @return [void]
|
|
30
31
|
def upload(source, options = {})
|
|
31
32
|
if File.size(source) >= multipart_threshold
|
|
@@ -37,12 +38,6 @@ module Aws
|
|
|
37
38
|
|
|
38
39
|
private
|
|
39
40
|
|
|
40
|
-
def put_object(source, options)
|
|
41
|
-
open_file(source) do |file|
|
|
42
|
-
@client.put_object(options.merge(body: file))
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
41
|
def open_file(source)
|
|
47
42
|
if String === source || Pathname === source
|
|
48
43
|
File.open(source, 'rb') { |file| yield(file) }
|
|
@@ -51,6 +46,12 @@ module Aws
|
|
|
51
46
|
end
|
|
52
47
|
end
|
|
53
48
|
|
|
49
|
+
def put_object(source, options)
|
|
50
|
+
open_file(source) do |file|
|
|
51
|
+
@client.put_object(options.merge(body: file))
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
54
55
|
end
|
|
55
56
|
end
|
|
56
57
|
end
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
require 'pathname'
|
|
2
|
-
require 'thread'
|
|
3
2
|
require 'set'
|
|
4
3
|
|
|
5
4
|
module Aws
|
|
@@ -16,14 +15,17 @@ module Aws
|
|
|
16
15
|
THREAD_COUNT = 10
|
|
17
16
|
|
|
18
17
|
# @api private
|
|
19
|
-
CREATE_OPTIONS =
|
|
20
|
-
|
|
18
|
+
CREATE_OPTIONS = Set.new(
|
|
19
|
+
Client.api.operation(:create_multipart_upload).input.shape.member_names
|
|
20
|
+
)
|
|
21
21
|
|
|
22
22
|
# @api private
|
|
23
|
-
UPLOAD_PART_OPTIONS =
|
|
24
|
-
|
|
23
|
+
UPLOAD_PART_OPTIONS = Set.new(
|
|
24
|
+
Client.api.operation(:upload_part).input.shape.member_names
|
|
25
|
+
)
|
|
25
26
|
|
|
26
27
|
# @option options [Client] :client
|
|
28
|
+
# @option options [Integer] :thread_count (THREAD_COUNT)
|
|
27
29
|
def initialize(options = {})
|
|
28
30
|
@client = options[:client] || Client.new
|
|
29
31
|
@thread_count = options[:thread_count] || THREAD_COUNT
|
|
@@ -32,9 +34,9 @@ module Aws
|
|
|
32
34
|
# @return [Client]
|
|
33
35
|
attr_reader :client
|
|
34
36
|
|
|
35
|
-
# @param [String,Pathname,File,Tempfile] source
|
|
36
|
-
# @option options [required,String] :bucket
|
|
37
|
-
# @option options [required,String] :key
|
|
37
|
+
# @param [String, Pathname, File, Tempfile] source The file to upload.
|
|
38
|
+
# @option options [required, String] :bucket The bucket to upload to.
|
|
39
|
+
# @option options [required, String] :key The key for the object.
|
|
38
40
|
# @return [void]
|
|
39
41
|
def upload(source, options = {})
|
|
40
42
|
if File.size(source) < MIN_PART_SIZE
|
|
@@ -57,7 +59,8 @@ module Aws
|
|
|
57
59
|
bucket: options[:bucket],
|
|
58
60
|
key: options[:key],
|
|
59
61
|
upload_id: upload_id,
|
|
60
|
-
multipart_upload: { parts: parts }
|
|
62
|
+
multipart_upload: { parts: parts }
|
|
63
|
+
)
|
|
61
64
|
end
|
|
62
65
|
|
|
63
66
|
def upload_parts(upload_id, source, options)
|
|
@@ -93,7 +96,7 @@ module Aws
|
|
|
93
96
|
part_number = 1
|
|
94
97
|
parts = []
|
|
95
98
|
while offset < size
|
|
96
|
-
parts << upload_part_opts(options).merge(
|
|
99
|
+
parts << upload_part_opts(options).merge(
|
|
97
100
|
upload_id: upload_id,
|
|
98
101
|
part_number: part_number,
|
|
99
102
|
body: FilePart.new(
|
|
@@ -101,7 +104,7 @@ module Aws
|
|
|
101
104
|
offset: offset,
|
|
102
105
|
size: part_size(size, default_part_size, offset)
|
|
103
106
|
)
|
|
104
|
-
|
|
107
|
+
)
|
|
105
108
|
part_number += 1
|
|
106
109
|
offset += default_part_size
|
|
107
110
|
end
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
require 'openssl'
|
|
2
|
-
require 'base64'
|
|
3
2
|
|
|
4
3
|
module Aws
|
|
5
4
|
module S3
|
|
@@ -37,13 +36,13 @@ module Aws
|
|
|
37
36
|
# @return [String<MD5>]
|
|
38
37
|
def md5(value)
|
|
39
38
|
if (File === value || Tempfile === value) && !value.path.nil? && File.exist?(value.path)
|
|
40
|
-
|
|
39
|
+
OpenSSL::Digest::MD5.file(value).base64digest
|
|
41
40
|
elsif value.respond_to?(:read)
|
|
42
41
|
md5 = OpenSSL::Digest::MD5.new
|
|
43
42
|
update_in_chunks(md5, value)
|
|
44
|
-
|
|
43
|
+
md5.base64digest
|
|
45
44
|
else
|
|
46
|
-
|
|
45
|
+
OpenSSL::Digest::MD5.digest(value).base64digest
|
|
47
46
|
end
|
|
48
47
|
end
|
|
49
48
|
|
data/lib/aws-sdk-s3.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: aws-sdk-s3
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.51.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Amazon Web Services
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2019-
|
|
11
|
+
date: 2019-10-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: aws-sdk-kms
|
|
@@ -47,7 +47,7 @@ dependencies:
|
|
|
47
47
|
version: '3'
|
|
48
48
|
- - ">="
|
|
49
49
|
- !ruby/object:Gem::Version
|
|
50
|
-
version: 3.
|
|
50
|
+
version: 3.71.0
|
|
51
51
|
type: :runtime
|
|
52
52
|
prerelease: false
|
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -57,7 +57,7 @@ dependencies:
|
|
|
57
57
|
version: '3'
|
|
58
58
|
- - ">="
|
|
59
59
|
- !ruby/object:Gem::Version
|
|
60
|
-
version: 3.
|
|
60
|
+
version: 3.71.0
|
|
61
61
|
description: Official AWS Ruby gem for Amazon Simple Storage Service (Amazon S3).
|
|
62
62
|
This gem is part of the AWS SDK for Ruby.
|
|
63
63
|
email:
|