thingfish 0.5.0.pre20160707192835 → 0.5.0.pre20161103181816
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/Manifest.txt +5 -0
- data/lib/thingfish/handler.rb +72 -3
- data/spec/thingfish/handler_spec.rb +46 -1
- metadata +34 -28
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74a092349d627e3de7578603e6cbba04c29f8045
|
4
|
+
data.tar.gz: eb4868b63ef6b8ad8b95c4ff5954f4482924bb3d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e3a206fa9f2ad2dd07543f407f85972a42b4f073ae8cc3eab66ead4ec5947b74c6f4228741a96efdb15a22101c4251cc49cee7a6e4b5720a1bf5acefda41967
|
7
|
+
data.tar.gz: a923141975987b85e96e84bd20c017d06609110abf10e319bd76a61ef51be1f0b6e59e2c66d8bc5d3d4d0275c862d8a3826b2e6c17f844daf456d6b7cfb21d91
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data.tar.gz.sig
ADDED
Binary file
|
data/Manifest.txt
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
.simplecov
|
2
|
+
ChangeLog
|
3
|
+
Gemfile
|
2
4
|
History.rdoc
|
3
5
|
LICENSE
|
4
6
|
Manifest.txt
|
@@ -7,6 +9,7 @@ README.rdoc
|
|
7
9
|
Rakefile
|
8
10
|
bin/tfprocessord
|
9
11
|
bin/thingfish
|
12
|
+
etc/mongrel2-config.rb
|
10
13
|
etc/thingfish.conf.example
|
11
14
|
lib/strelka/app/metadata.rb
|
12
15
|
lib/strelka/httprequest/metadata.rb
|
@@ -20,6 +23,7 @@ lib/thingfish/metastore/memory.rb
|
|
20
23
|
lib/thingfish/mixins.rb
|
21
24
|
lib/thingfish/processor.rb
|
22
25
|
lib/thingfish/processor/mp3.rb
|
26
|
+
lib/thingfish/processor/sha256.rb
|
23
27
|
lib/thingfish/processordaemon.rb
|
24
28
|
lib/thingfish/spechelpers.rb
|
25
29
|
spec/data/APIC-1-image.mp3
|
@@ -35,5 +39,6 @@ spec/thingfish/metastore/memory_spec.rb
|
|
35
39
|
spec/thingfish/metastore_spec.rb
|
36
40
|
spec/thingfish/mixins_spec.rb
|
37
41
|
spec/thingfish/processor/mp3_spec.rb
|
42
|
+
spec/thingfish/processor/sha256_spec.rb
|
38
43
|
spec/thingfish/processor_spec.rb
|
39
44
|
spec/thingfish_spec.rb
|
data/lib/thingfish/handler.rb
CHANGED
@@ -230,6 +230,7 @@ class Thingfish::Handler < Strelka::App
|
|
230
230
|
:datastore => self.datastore.class.name
|
231
231
|
}
|
232
232
|
|
233
|
+
self.check_resource_permissions( req )
|
233
234
|
res.for( :text, :json, :yaml ) { info }
|
234
235
|
return res
|
235
236
|
end
|
@@ -244,6 +245,8 @@ class Thingfish::Handler < Strelka::App
|
|
244
245
|
get do |req|
|
245
246
|
finish_with HTTP::BAD_REQUEST, req.params.error_messages.join(', ') unless req.params.okay?
|
246
247
|
|
248
|
+
self.check_resource_permissions( req )
|
249
|
+
|
247
250
|
uuids = self.metastore.search( req.params.valid )
|
248
251
|
self.log.debug "UUIDs are: %p" % [ uuids ]
|
249
252
|
|
@@ -340,13 +343,15 @@ class Thingfish::Handler < Strelka::App
|
|
340
343
|
metadata = self.metastore.fetch( uuid )
|
341
344
|
|
342
345
|
finish_with HTTP::NOT_FOUND, "No such object." unless object && metadata
|
346
|
+
self.check_resource_permissions( req, nil, metadata )
|
343
347
|
|
344
348
|
res = req.response
|
345
349
|
res.content_type = metadata['format']
|
346
350
|
|
351
|
+
self.add_etag_headers( req, metadata )
|
352
|
+
|
347
353
|
if object.respond_to?( :path )
|
348
354
|
path = Pathname( object.path )
|
349
|
-
self.log.debug "Server is chrooted to: %p" % [ req.server_chroot ]
|
350
355
|
chroot_path = path.relative_path_from( req.server_chroot )
|
351
356
|
res.extend_reply_with( :sendfile )
|
352
357
|
res.headers.content_length = object.size
|
@@ -387,6 +392,7 @@ class Thingfish::Handler < Strelka::App
|
|
387
392
|
self.datastore.include?( uuid ) or
|
388
393
|
finish_with HTTP::NOT_FOUND, "No such object."
|
389
394
|
|
395
|
+
self.check_resource_permissions( req, uuid )
|
390
396
|
self.remove_related_resources( uuid )
|
391
397
|
self.save_resource( req, uuid )
|
392
398
|
self.send_event( :replaced, :uuid => uuid )
|
@@ -403,6 +409,8 @@ class Thingfish::Handler < Strelka::App
|
|
403
409
|
delete ':uuid' do |req|
|
404
410
|
uuid = req.params[:uuid]
|
405
411
|
|
412
|
+
self.check_resource_permissions( req, uuid )
|
413
|
+
|
406
414
|
self.datastore.remove( uuid ) or finish_with( HTTP::NOT_FOUND, "No such object." )
|
407
415
|
metadata = self.metastore.remove( uuid )
|
408
416
|
self.remove_related_resources( uuid )
|
@@ -433,9 +441,13 @@ class Thingfish::Handler < Strelka::App
|
|
433
441
|
|
434
442
|
finish_with( HTTP::NOT_FOUND, "No such object." ) unless self.metastore.include?( uuid )
|
435
443
|
|
444
|
+
metadata = self.metastore.fetch( uuid )
|
445
|
+
metadata[ 'oid' ] = uuid
|
446
|
+
self.check_resource_permissions( req, uuid, metadata )
|
447
|
+
|
436
448
|
res = req.response
|
437
449
|
res.status = HTTP::OK
|
438
|
-
res.for( :json, :yaml ) {
|
450
|
+
res.for( :json, :yaml ) { metadata }
|
439
451
|
|
440
452
|
return res
|
441
453
|
end
|
@@ -449,9 +461,12 @@ class Thingfish::Handler < Strelka::App
|
|
449
461
|
|
450
462
|
finish_with( HTTP::NOT_FOUND, "No such object." ) unless self.metastore.include?( uuid )
|
451
463
|
|
464
|
+
metadata = self.metastore.fetch( uuid )
|
465
|
+
self.check_resource_permissions( req, uuid, metadata )
|
466
|
+
|
452
467
|
res = req.response
|
453
468
|
res.status = HTTP::OK
|
454
|
-
res.for( :json, :yaml ) {
|
469
|
+
res.for( :json, :yaml ) { metadata[key] }
|
455
470
|
|
456
471
|
return res
|
457
472
|
end
|
@@ -467,6 +482,9 @@ class Thingfish::Handler < Strelka::App
|
|
467
482
|
finish_with( HTTP::CONFLICT, "Key already exists." ) unless
|
468
483
|
self.metastore.fetch_value( uuid, key ).nil?
|
469
484
|
|
485
|
+
metadata = self.metastore.fetch( uuid )
|
486
|
+
self.check_resource_permissions( req, uuid, metadata )
|
487
|
+
|
470
488
|
self.metastore.merge( uuid, key => req.body.read )
|
471
489
|
self.send_event( :metadata_updated, :uuid => uuid, :key => key )
|
472
490
|
|
@@ -490,6 +508,9 @@ class Thingfish::Handler < Strelka::App
|
|
490
508
|
finish_with( HTTP::NOT_FOUND, "No such object." ) unless self.metastore.include?( uuid )
|
491
509
|
previous_value = self.metastore.fetch( uuid, key )
|
492
510
|
|
511
|
+
metadata = self.metastore.fetch( uuid )
|
512
|
+
self.check_resource_permissions( req, uuid, metadata )
|
513
|
+
|
493
514
|
self.metastore.merge( uuid, key => req.body.read )
|
494
515
|
self.send_event( :metadata_replaced, :uuid => uuid, :key => key )
|
495
516
|
|
@@ -514,6 +535,9 @@ class Thingfish::Handler < Strelka::App
|
|
514
535
|
|
515
536
|
finish_with( HTTP::NOT_FOUND, "No such object." ) unless self.metastore.include?( uuid )
|
516
537
|
|
538
|
+
metadata = self.metastore.fetch( uuid )
|
539
|
+
self.check_resource_permissions( req, uuid, metadata )
|
540
|
+
|
517
541
|
op_metadata = self.metastore.fetch( uuid, *OPERATIONAL_METADATA_KEYS )
|
518
542
|
new_metadata = self.extract_metadata( req )
|
519
543
|
self.metastore.save( uuid, new_metadata.merge(op_metadata) )
|
@@ -533,6 +557,9 @@ class Thingfish::Handler < Strelka::App
|
|
533
557
|
|
534
558
|
finish_with( HTTP::NOT_FOUND, "No such object." ) unless self.metastore.include?( uuid )
|
535
559
|
|
560
|
+
metadata = self.metastore.fetch( uuid )
|
561
|
+
self.check_resource_permissions( req, uuid, metadata )
|
562
|
+
|
536
563
|
new_metadata = self.extract_metadata( req )
|
537
564
|
self.metastore.merge( uuid, new_metadata )
|
538
565
|
self.send_event( :metadata_updated, :uuid => uuid )
|
@@ -551,6 +578,9 @@ class Thingfish::Handler < Strelka::App
|
|
551
578
|
|
552
579
|
finish_with( HTTP::NOT_FOUND, "No such object." ) unless self.metastore.include?( uuid )
|
553
580
|
|
581
|
+
metadata = self.metastore.fetch( uuid )
|
582
|
+
self.check_resource_permissions( req, uuid, metadata )
|
583
|
+
|
554
584
|
self.metastore.remove_except( uuid, *OPERATIONAL_METADATA_KEYS )
|
555
585
|
self.send_event( :metadata_deleted, :uuid => uuid )
|
556
586
|
|
@@ -571,6 +601,9 @@ class Thingfish::Handler < Strelka::App
|
|
571
601
|
finish_with( HTTP::FORBIDDEN, "Protected metadata." ) if
|
572
602
|
OPERATIONAL_METADATA_KEYS.include?( key )
|
573
603
|
|
604
|
+
metadata = self.metastore.fetch( uuid )
|
605
|
+
self.check_resource_permissions( req, uuid, metadata )
|
606
|
+
|
574
607
|
self.metastore.remove( uuid, key )
|
575
608
|
self.send_event( :metadata_deleted, :uuid => uuid, :key => key )
|
576
609
|
|
@@ -593,6 +626,9 @@ class Thingfish::Handler < Strelka::App
|
|
593
626
|
metadata.merge!( self.extract_header_metadata(request) )
|
594
627
|
metadata.merge!( self.extract_default_metadata(request) )
|
595
628
|
|
629
|
+
self.verify_operational_metadata( metadata )
|
630
|
+
self.check_resource_permissions( request, uuid, metadata )
|
631
|
+
|
596
632
|
if uuid
|
597
633
|
self.log.info "Replacing resource %s (encoding: %p)" %
|
598
634
|
[ uuid, request.headers.content_encoding ]
|
@@ -714,6 +750,15 @@ class Thingfish::Handler < Strelka::App
|
|
714
750
|
end
|
715
751
|
|
716
752
|
|
753
|
+
### Check that the metadata provided contains valid values for
|
754
|
+
### the operational keys, before saving a resource to disk.
|
755
|
+
def verify_operational_metadata( metadata )
|
756
|
+
if metadata.values_at( *OPERATIONAL_METADATA_KEYS ).any?( &:nil? )
|
757
|
+
finish_with( HTTP::BAD_REQUEST, "Missing operational attribute." )
|
758
|
+
end
|
759
|
+
end
|
760
|
+
|
761
|
+
|
717
762
|
### Send an event of +type+ with the given +msg+ over the zmq event socket.
|
718
763
|
def send_event( type, msg )
|
719
764
|
esock = self.event_socket or return
|
@@ -723,6 +768,30 @@ class Thingfish::Handler < Strelka::App
|
|
723
768
|
end
|
724
769
|
|
725
770
|
|
771
|
+
### Add browser cache headers for resources. This requires the sha256
|
772
|
+
### processor plugin to be enabled for stored resources.
|
773
|
+
def add_etag_headers( request, metadata )
|
774
|
+
response = request.response
|
775
|
+
checksum = metadata[ 'checksum' ]
|
776
|
+
return unless checksum
|
777
|
+
|
778
|
+
if (( match = request.headers[ :if_none_match ] ))
|
779
|
+
match = match.gsub( '"', '' ).split( /,\s*/ )
|
780
|
+
finish_with( HTTP::NOT_MODIFIED ) if match.include?( checksum )
|
781
|
+
end
|
782
|
+
|
783
|
+
response.headers[ :etag ] = checksum
|
784
|
+
return
|
785
|
+
end
|
786
|
+
|
787
|
+
|
788
|
+
### Supply a method that child handlers can override. The regular auth
|
789
|
+
### plugin runs too early (but can also be used), this hook allows
|
790
|
+
### child handlers to make access decisions based on the +request+
|
791
|
+
### object, +uuid+ of the resource, or +metadata+ of the fetched resource.
|
792
|
+
def check_resource_permissions( request, uuid=nil, metadata=nil ); end
|
793
|
+
|
794
|
+
|
726
795
|
end # class Thingfish::Handler
|
727
796
|
|
728
797
|
# vim: set nosta noet ts=4 sw=4:
|
@@ -70,7 +70,9 @@ describe Thingfish::Handler do
|
|
70
70
|
|
71
71
|
|
72
72
|
it 'accepts a POSTed upload' do
|
73
|
-
req = factory.post( '/', TEST_TEXT_DATA
|
73
|
+
req = factory.post( '/', TEST_TEXT_DATA )
|
74
|
+
req.content_type = 'text/plain'
|
75
|
+
req.headers.content_length = TEST_TEXT_DATA.bytesize
|
74
76
|
res = @handler.handle( req )
|
75
77
|
|
76
78
|
expect( res.status_line ).to match( /201 created/i )
|
@@ -145,6 +147,17 @@ describe Thingfish::Handler do
|
|
145
147
|
end
|
146
148
|
|
147
149
|
|
150
|
+
it 'returns a BAD_REQUEST if unable to extract operational metadata' do
|
151
|
+
req = factory.post( '/', TEST_TEXT_DATA )
|
152
|
+
req.content_type = 'text/plain'
|
153
|
+
|
154
|
+
res = @handler.handle( req )
|
155
|
+
res.body.rewind
|
156
|
+
expect( res.status ).to be( HTTP::BAD_REQUEST )
|
157
|
+
expect( res.body.read ).to match( /missing operational attribute/i )
|
158
|
+
end
|
159
|
+
|
160
|
+
|
148
161
|
it "allows additional metadata to be attached to uploads via X-Thingfish-* headers" do
|
149
162
|
headers = {
|
150
163
|
content_type: 'text/plain',
|
@@ -152,6 +165,7 @@ describe Thingfish::Handler do
|
|
152
165
|
x_thingfish_tags: 'rapper,ukraine,potap',
|
153
166
|
}
|
154
167
|
req = factory.post( '/', TEST_TEXT_DATA, headers )
|
168
|
+
req.headers.content_length = TEST_TEXT_DATA.bytesize
|
155
169
|
res = @handler.handle( req )
|
156
170
|
|
157
171
|
expect( res.status_line ).to match( /201 created/i )
|
@@ -169,6 +183,7 @@ describe Thingfish::Handler do
|
|
169
183
|
@handler.metastore.save( uuid, {'format' => 'text/plain'} )
|
170
184
|
|
171
185
|
req = factory.put( "/#{uuid}", @png_io, content_type: 'image/png' )
|
186
|
+
req.headers.content_length = @png_io.read.bytesize
|
172
187
|
res = @handler.handle( req )
|
173
188
|
|
174
189
|
expect( res.status ).to eq( HTTP::NO_CONTENT )
|
@@ -182,6 +197,7 @@ describe Thingfish::Handler do
|
|
182
197
|
@handler.metastore.save( uuid, {'format' => 'text/plain'} )
|
183
198
|
|
184
199
|
req = factory.put( "/#{uuid.upcase}", @png_io, content_type: 'image/png' )
|
200
|
+
req.headers.content_length = @png_io.read.bytesize
|
185
201
|
res = @handler.handle( req )
|
186
202
|
|
187
203
|
expect( res.status ).to eq( HTTP::NO_CONTENT )
|
@@ -339,6 +355,32 @@ describe Thingfish::Handler do
|
|
339
355
|
end
|
340
356
|
|
341
357
|
|
358
|
+
it "adds browser cache headers to resources with a checksum attribute" do
|
359
|
+
uuid = @handler.datastore.save( @png_io )
|
360
|
+
@handler.metastore.save( uuid, 'format' => 'image/png', 'checksum' => '123456' )
|
361
|
+
|
362
|
+
req = factory.get( "/#{uuid}" )
|
363
|
+
result = @handler.handle( req )
|
364
|
+
|
365
|
+
expect( result.status_line ).to match( /200 ok/i )
|
366
|
+
expect( result.headers.etag ).to eq( '123456' )
|
367
|
+
end
|
368
|
+
|
369
|
+
|
370
|
+
it "returns a 304 not modified for unchanged client cache requests" do
|
371
|
+
uuid = @handler.datastore.save( @png_io )
|
372
|
+
@handler.metastore.save( uuid, 'format' => 'image/png', 'checksum' => '123456' )
|
373
|
+
|
374
|
+
req = factory.get( "/#{uuid}" )
|
375
|
+
req.headers[ :if_none_match ] = '123456'
|
376
|
+
result = @handler.handle( req )
|
377
|
+
|
378
|
+
expect( result.status_line ).to match( /304 not modified/i )
|
379
|
+
expect( result.body.read ).to be_empty
|
380
|
+
end
|
381
|
+
|
382
|
+
|
383
|
+
|
342
384
|
it "can remove everything associated with an object id" do
|
343
385
|
uuid = @handler.datastore.save( @png_io )
|
344
386
|
@handler.metastore.save( uuid, {
|
@@ -391,6 +433,7 @@ describe Thingfish::Handler do
|
|
391
433
|
expect( result.status ).to eq( 200 )
|
392
434
|
expect( result.headers.content_type ).to eq( 'application/json' )
|
393
435
|
expect( content_hash ).to be_a( Hash )
|
436
|
+
expect( content_hash['oid'] ).to eq( uuid )
|
394
437
|
expect( content_hash['extent'] ).to eq( 288 )
|
395
438
|
expect( content_hash['created'] ).to eq( Time.at(1378313840).to_s )
|
396
439
|
end
|
@@ -733,6 +776,7 @@ describe Thingfish::Handler do
|
|
733
776
|
described_class.configure( :processors => %w[test] )
|
734
777
|
|
735
778
|
req = factory.post( '/', TEST_TEXT_DATA, content_type: 'text/plain' )
|
779
|
+
req.headers.content_length = TEST_TEXT_DATA.bytesize
|
736
780
|
res = @handler.handle( req )
|
737
781
|
uuid = res.headers.x_thingfish_uuid
|
738
782
|
|
@@ -816,6 +860,7 @@ describe Thingfish::Handler do
|
|
816
860
|
|
817
861
|
it "publishes notifications about uploaded assets to a PUBSUB socket" do
|
818
862
|
req = factory.post( '/', TEST_TEXT_DATA, content_type: 'text/plain' )
|
863
|
+
req.headers.content_length = TEST_TEXT_DATA.bytesize
|
819
864
|
res = @handler.handle( req )
|
820
865
|
|
821
866
|
handles = ZMQ.select( [@subsock], nil, nil, 0 )
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thingfish
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.0.
|
4
|
+
version: 0.5.0.pre20161103181816
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Granger
|
@@ -11,26 +11,32 @@ bindir: bin
|
|
11
11
|
cert_chain:
|
12
12
|
- |
|
13
13
|
-----BEGIN CERTIFICATE-----
|
14
|
-
|
14
|
+
MIIEbDCCAtSgAwIBAgIBATANBgkqhkiG9w0BAQsFADA+MQwwCgYDVQQDDANnZWQx
|
15
15
|
GTAXBgoJkiaJk/IsZAEZFglGYWVyaWVNVUQxEzARBgoJkiaJk/IsZAEZFgNvcmcw
|
16
|
-
|
16
|
+
HhcNMTYwODIwMTgxNzQyWhcNMTcwODIwMTgxNzQyWjA+MQwwCgYDVQQDDANnZWQx
|
17
17
|
GTAXBgoJkiaJk/IsZAEZFglGYWVyaWVNVUQxEzARBgoJkiaJk/IsZAEZFgNvcmcw
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
18
|
+
ggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC/JWGRHO+USzR97vXjkFgt
|
19
|
+
83qeNf2KHkcvrRTSnR64i6um/ziin0I0oX23H7VYrDJC9A/uoUa5nGRJS5Zw/+wW
|
20
|
+
ENcvWVZS4iUzi4dsYJGY6yEOsXh2CcF46+QevV8iE+UmbkU75V7Dy1JCaUOyizEt
|
21
|
+
TH5UHsOtUU7k9TYARt/TgYZKuaoAMZZd5qyVqhF1vV+7/Qzmp89NGflXf2xYP26a
|
22
|
+
4MAX2qqKX/FKXqmFO+AGsbwYTEds1mksBF3fGsFgsQWxftG8GfZQ9+Cyu2+l1eOw
|
23
|
+
cZ+lPcg834G9DrqW2zhqUoLr1MTly4pqxYGb7XoDhoR7dd1kFE2a067+DzWC/ADt
|
24
|
+
+QkcqWUm5oh1fN0eqr7NsZlVJDulFgdiiYPQiIN7UNsii4Wc9aZqBoGcYfBeQNPZ
|
25
|
+
soo/6za/bWajOKUmDhpqvaiRv9EDpVLzuj53uDoukMMwxCMfgb04+ckQ0t2G7wqc
|
26
|
+
/D+K9JW9DDs3Yjgv9k4h7YMhW5gftosd+NkNC/+Y2CkCAwEAAaN1MHMwCQYDVR0T
|
27
|
+
BAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFHKN/nkRusdqCJEuq3lgB3fJvyTg
|
28
|
+
MBwGA1UdEQQVMBOBEWdlZEBGYWVyaWVNVUQub3JnMBwGA1UdEgQVMBOBEWdlZEBG
|
29
|
+
YWVyaWVNVUQub3JnMA0GCSqGSIb3DQEBCwUAA4IBgQAPJzKiT0zBU7kpqe0aS2qb
|
30
|
+
FI0PJ4y5I8buU4IZGUD5NEt/N7pZNfOyBxkrZkXhS44Fp+xwBH5ebLbq/WY78Bqd
|
31
|
+
db0z6ZgW4LMYMpWFfbXsRbd9TU2f52L8oMAhxOvF7Of5qJMVWuFQ8FPagk2iHrdH
|
32
|
+
inYLQagqAF6goWTXgAJCdPd6SNeeSNqA6vlY7CV1Jh5kfNJJ6xu/CVij1GzCLu/5
|
33
|
+
DMOr26DBv+qLJRRC/2h34uX71q5QgeOyxvMg+7V3u/Q06DXyQ2VgeeqiwDFFpEH0
|
34
|
+
PFkdPO6ZqbTRcLfNH7mFgCBJjsfSjJrn0sPBlYyOXgCoByfZnZyrIMH/UY+lgQqS
|
35
|
+
6Von1VDsfQm0eJh5zYZD64ZF86phSR7mUX3mXItwH04HrZwkWpvgd871DZVR3i1n
|
36
|
+
w8aNA5re5+Rt/Vvjxj5AcEnZnZiz5x959NaddQocX32Z1unHw44pzRNUur1GInfW
|
37
|
+
p4vpx2kUSFSAGjtCbDGTNV2AH8w9OU4xEmNz8c5lyoA=
|
32
38
|
-----END CERTIFICATE-----
|
33
|
-
date: 2016-
|
39
|
+
date: 2016-11-04 00:00:00.000000000 Z
|
34
40
|
dependencies:
|
35
41
|
- !ruby/object:Gem::Dependency
|
36
42
|
name: strelka
|
@@ -103,47 +109,47 @@ dependencies:
|
|
103
109
|
- !ruby/object:Gem::Version
|
104
110
|
version: '0.2'
|
105
111
|
- !ruby/object:Gem::Dependency
|
106
|
-
name:
|
112
|
+
name: simplecov
|
107
113
|
requirement: !ruby/object:Gem::Requirement
|
108
114
|
requirements:
|
109
115
|
- - "~>"
|
110
116
|
- !ruby/object:Gem::Version
|
111
|
-
version: '
|
117
|
+
version: '0.7'
|
112
118
|
type: :development
|
113
119
|
prerelease: false
|
114
120
|
version_requirements: !ruby/object:Gem::Requirement
|
115
121
|
requirements:
|
116
122
|
- - "~>"
|
117
123
|
- !ruby/object:Gem::Version
|
118
|
-
version: '
|
124
|
+
version: '0.7'
|
119
125
|
- !ruby/object:Gem::Dependency
|
120
|
-
name:
|
126
|
+
name: ruby-mp3info
|
121
127
|
requirement: !ruby/object:Gem::Requirement
|
122
128
|
requirements:
|
123
129
|
- - "~>"
|
124
130
|
- !ruby/object:Gem::Version
|
125
|
-
version: '0.
|
131
|
+
version: '0.8'
|
126
132
|
type: :development
|
127
133
|
prerelease: false
|
128
134
|
version_requirements: !ruby/object:Gem::Requirement
|
129
135
|
requirements:
|
130
136
|
- - "~>"
|
131
137
|
- !ruby/object:Gem::Version
|
132
|
-
version: '0.
|
138
|
+
version: '0.8'
|
133
139
|
- !ruby/object:Gem::Dependency
|
134
|
-
name:
|
140
|
+
name: rdoc
|
135
141
|
requirement: !ruby/object:Gem::Requirement
|
136
142
|
requirements:
|
137
143
|
- - "~>"
|
138
144
|
- !ruby/object:Gem::Version
|
139
|
-
version: '0
|
145
|
+
version: '4.0'
|
140
146
|
type: :development
|
141
147
|
prerelease: false
|
142
148
|
version_requirements: !ruby/object:Gem::Requirement
|
143
149
|
requirements:
|
144
150
|
- - "~>"
|
145
151
|
- !ruby/object:Gem::Version
|
146
|
-
version: '0
|
152
|
+
version: '4.0'
|
147
153
|
- !ruby/object:Gem::Dependency
|
148
154
|
name: hoe
|
149
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -237,7 +243,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
237
243
|
version: 1.3.1
|
238
244
|
requirements: []
|
239
245
|
rubyforge_project:
|
240
|
-
rubygems_version: 2.
|
246
|
+
rubygems_version: 2.5.1
|
241
247
|
signing_key:
|
242
248
|
specification_version: 4
|
243
249
|
summary: Thingfish is a extensible, web-based digital asset manager
|
metadata.gz.sig
ADDED
Binary file
|