artbase-cocos 0.0.1
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 +7 -0
- data/CHANGELOG.md +3 -0
- data/Manifest.txt +15 -0
- data/README.md +27 -0
- data/Rakefile +40 -0
- data/lib/artbase-cocos/attributes.rb +83 -0
- data/lib/artbase-cocos/collection/base.rb +332 -0
- data/lib/artbase-cocos/collection/image.rb +39 -0
- data/lib/artbase-cocos/collection/token.rb +347 -0
- data/lib/artbase-cocos/collection/token_meta.rb +77 -0
- data/lib/artbase-cocos/helper.rb +205 -0
- data/lib/artbase-cocos/image/sample.rb +31 -0
- data/lib/artbase-cocos/image.rb +30 -0
- data/lib/artbase-cocos/retry.rb +41 -0
- data/lib/artbase-cocos/version.rb +25 -0
- data/lib/artbase-cocos.rb +82 -0
- metadata +140 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 631db0140f623a59d67e52957f2b9f58020239dc02a3b5ac2aa9e15126a9df85
|
4
|
+
data.tar.gz: edbfda7a4d05e2827c7229def1d25e6b0146319bfbcf8cb8e81d77997c83829e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 480f00c1d0b1f303037373787293302997287323b4f2b41b5d7db8741430ad39c98cfec0edd516a842a718bafb0a476e5f93bcf7d48f64af07432025f0bf25e3
|
7
|
+
data.tar.gz: 6e1e364752bce64215a32f93b29eda79742698d6dc65c4ca9a7737c359a054bf20073cdd1181eadc6fa09c5c7f5c34f32223722d359b03c10d0c867db9d09164
|
data/CHANGELOG.md
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
CHANGELOG.md
|
2
|
+
Manifest.txt
|
3
|
+
README.md
|
4
|
+
Rakefile
|
5
|
+
lib/artbase-cocos.rb
|
6
|
+
lib/artbase-cocos/attributes.rb
|
7
|
+
lib/artbase-cocos/collection/base.rb
|
8
|
+
lib/artbase-cocos/collection/image.rb
|
9
|
+
lib/artbase-cocos/collection/token.rb
|
10
|
+
lib/artbase-cocos/collection/token_meta.rb
|
11
|
+
lib/artbase-cocos/helper.rb
|
12
|
+
lib/artbase-cocos/image.rb
|
13
|
+
lib/artbase-cocos/image/sample.rb
|
14
|
+
lib/artbase-cocos/retry.rb
|
15
|
+
lib/artbase-cocos/version.rb
|
data/README.md
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# artbase-cocos - artbase (shared) code commons (cocos); read artbase collection configs & metadata; download collection token metadata, images, and more
|
2
|
+
|
3
|
+
|
4
|
+
* home :: [github.com/pixelartexchange/artbase](https://github.com/pixelartexchange/artbase)
|
5
|
+
* bugs :: [github.com/pixelartexchange/artbase/issues](https://github.com/pixelartexchange/artbase/issues)
|
6
|
+
* gem :: [rubygems.org/gems/artbase-cocos](https://rubygems.org/gems/artbase-cocos)
|
7
|
+
* rdoc :: [rubydoc.info/gems/artbase-cocos](http://rubydoc.info/gems/artbase-cocos)
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
To be done
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
## License
|
20
|
+
|
21
|
+
The `artbase` scripts are dedicated to the public domain.
|
22
|
+
Use it as you please with no restrictions whatsoever.
|
23
|
+
|
24
|
+
|
25
|
+
## Questions? Comments?
|
26
|
+
|
27
|
+
Post them on the [D.I.Y. Punk (Pixel) Art reddit](https://old.reddit.com/r/DIYPunkArt). Thanks.
|
data/Rakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'hoe'
|
2
|
+
require './lib/artbase-cocos/version.rb'
|
3
|
+
|
4
|
+
|
5
|
+
###
|
6
|
+
# hack/ quick fix for broken intuit_values - overwrite with dummy
|
7
|
+
class Hoe
|
8
|
+
def intuit_values( input ); end
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
Hoe.spec 'artbase-cocos' do
|
13
|
+
|
14
|
+
self.version = Artbase::Module::Cocos::VERSION
|
15
|
+
|
16
|
+
self.summary = "artbase-cocos - artbase (shared) code commons (cocos); read artbase collection configs & metadata; download collection token metadata, images, and more"
|
17
|
+
self.description = summary
|
18
|
+
|
19
|
+
self.urls = { home: 'https://github.com/pixelartexchange/artbase'}
|
20
|
+
|
21
|
+
self.author = 'Gerald Bauer'
|
22
|
+
self.email = 'wwwmake@googlegroups.com'
|
23
|
+
|
24
|
+
# switch extension to .markdown for gihub formatting
|
25
|
+
self.readme_file = 'README.md'
|
26
|
+
self.history_file = 'CHANGELOG.md'
|
27
|
+
|
28
|
+
self.extra_deps = [
|
29
|
+
['cocos', '>= 0.1.2'],
|
30
|
+
['pixelart', '>= 1.3.6'],
|
31
|
+
['webclient', '>= 0.2.2'], ## weblclient part of cocos?
|
32
|
+
]
|
33
|
+
|
34
|
+
self.licenses = ['Public Domain']
|
35
|
+
|
36
|
+
self.spec_extras = {
|
37
|
+
required_ruby_version: '>= 2.2.2'
|
38
|
+
}
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
def counter_to_text( counter )
|
4
|
+
|
5
|
+
counter = counter.to_a
|
6
|
+
|
7
|
+
attribute_counter = counter[0]
|
8
|
+
more_counter = counter[1..-1]
|
9
|
+
|
10
|
+
|
11
|
+
puts "Attribute Counts\n"
|
12
|
+
trait_type, h = attribute_counter
|
13
|
+
|
14
|
+
total = h[:by_type].values.reduce(0) { |sum,count| sum+count }
|
15
|
+
|
16
|
+
|
17
|
+
types = h[:by_type]
|
18
|
+
types = types.sort { |l,r| l[0]<=>r[0] } ## sort by name
|
19
|
+
|
20
|
+
puts "\n"
|
21
|
+
puts "|Name|Total (%)|"
|
22
|
+
puts "|--------|----------:|"
|
23
|
+
|
24
|
+
types.each do |rec|
|
25
|
+
name = rec[0]
|
26
|
+
count = rec[1]
|
27
|
+
percent = Float(count*100)/Float(total)
|
28
|
+
|
29
|
+
puts "| **#{name} Attributes** | #{count} (#{'%.2f' % percent}) |"
|
30
|
+
end
|
31
|
+
puts "\n"
|
32
|
+
|
33
|
+
more_counter.each_with_index do |(trait_type, h),i|
|
34
|
+
print " · " if i > 0 ## add separator
|
35
|
+
print "#{trait_type } (#{h[:by_type].size})"
|
36
|
+
end
|
37
|
+
puts "\n\n"
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
more_counter.each do |trait_type, h|
|
42
|
+
print "### #{trait_type } (#{h[:by_type].size}) - "
|
43
|
+
print "∑Total #{h[:count]}/#{total}\n"
|
44
|
+
|
45
|
+
puts "\n"
|
46
|
+
puts "|Name|Total (%)|"
|
47
|
+
puts "|--------|----------:|"
|
48
|
+
|
49
|
+
types = h[:by_type]
|
50
|
+
types = types.sort do |l,r|
|
51
|
+
# sort by 1) by count
|
52
|
+
# 2) by name a-z
|
53
|
+
res = r[1] <=> l[1]
|
54
|
+
res = l[0] <=> r[0] if res == 0
|
55
|
+
res
|
56
|
+
end ## sort by count
|
57
|
+
types.each do |rec|
|
58
|
+
name = rec[0]
|
59
|
+
count = rec[1]
|
60
|
+
percent = Float(count*100)/Float(total)
|
61
|
+
|
62
|
+
puts "| **#{name}** | #{count} (#{'%.2f' % percent}) |"
|
63
|
+
end
|
64
|
+
puts "\n\n"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
def counter_to_csv( counter )
|
72
|
+
|
73
|
+
puts "type, name, count"
|
74
|
+
counter.each do |trait_type, h|
|
75
|
+
puts "#{trait_type}, ∑ Total, #{h[:count]}"
|
76
|
+
h[:by_type].each do |trait_value, count|
|
77
|
+
puts "#{trait_type}, #{trait_value}, #{count}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
|
@@ -0,0 +1,332 @@
|
|
1
|
+
|
2
|
+
module Artbase
|
3
|
+
class Base ## "abstract" Base collection - check -use a different name - why? why not?
|
4
|
+
|
5
|
+
|
6
|
+
def convert_images( overwrite: )
|
7
|
+
image_dir = "./#{@slug}/token-i"
|
8
|
+
Image.convert( image_dir, from: 'jpg', to: 'png', overwrite: overwrite )
|
9
|
+
Image.convert( image_dir, from: 'gif', to: 'png', overwrite: overwrite )
|
10
|
+
Image.convert( image_dir, from: 'svg', to: 'png', overwrite: overwrite )
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
def make_strip
|
16
|
+
composite_count = @count - @excludes.size
|
17
|
+
|
18
|
+
composite = ImageComposite.new( 9, 1,
|
19
|
+
width: @width,
|
20
|
+
height: @height )
|
21
|
+
|
22
|
+
i = 0
|
23
|
+
each_image do |img, id|
|
24
|
+
puts "==> [#{i+1}/9] #{id}"
|
25
|
+
composite << img
|
26
|
+
|
27
|
+
i += 1
|
28
|
+
break if i >= 9
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
composite.save( "./#{@slug}/tmp/#{@slug}-strip.png" )
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
def make_composite( limit: nil,
|
38
|
+
mirror: false )
|
39
|
+
### use well-known / pre-defined (default) grids
|
40
|
+
## (cols x rows) for now - why? why not?
|
41
|
+
|
42
|
+
composite_count = if limit
|
43
|
+
limit
|
44
|
+
else
|
45
|
+
@count - @excludes.size
|
46
|
+
end
|
47
|
+
|
48
|
+
cols, rows = case composite_count
|
49
|
+
when 99 then [10, 10]
|
50
|
+
when 100 then [10, 10]
|
51
|
+
when 150 then [15, 10]
|
52
|
+
when 314 then [15, 21]
|
53
|
+
when 500 then [25, 20]
|
54
|
+
when 946 then [25, 38]
|
55
|
+
when 1000 then [25, 40]
|
56
|
+
when 1300 then [25, 52]
|
57
|
+
when 2048 then [50, 41]
|
58
|
+
when 2077 then [50, 42]
|
59
|
+
when 2200 then [50, 44]
|
60
|
+
when 2222 then [50, 45]
|
61
|
+
when 2469 then [50, 50]
|
62
|
+
when 3000 then [100, 30] ## or use 50*60 - why? why not?
|
63
|
+
when 3500 then [100, 35] ## or use 50*x ??
|
64
|
+
when 3979 then [100, 40]
|
65
|
+
when 4000 then [100, 40] ## or use 50x80 - why? why not?
|
66
|
+
when 4444 then [100, 45] ## or use 50x??
|
67
|
+
when 5000 then [100, 50] ## or use 50x100 - why? why not?
|
68
|
+
when 5555 then [100, 56] # 5600 (45 left empty)
|
69
|
+
when 6666 then [100, 67] # 6700 (34 left empty)
|
70
|
+
when 6688 then [100, 67] # 6700 (12 left empty)
|
71
|
+
when 6969 then [100, 70] # 7000 (31 left empty)
|
72
|
+
when 7500 then [100, 75]
|
73
|
+
when 8888 then [100, 89]
|
74
|
+
when 9969 then [100,100]
|
75
|
+
when 10000 then [100,100]
|
76
|
+
else
|
77
|
+
raise ArgumentError, "sorry - unknown composite count #{composite_count}/#{@count} for now"
|
78
|
+
end
|
79
|
+
|
80
|
+
composite = ImageComposite.new( cols, rows,
|
81
|
+
width: @width,
|
82
|
+
height: @height )
|
83
|
+
|
84
|
+
|
85
|
+
count = 0
|
86
|
+
each_image do |img, id|
|
87
|
+
puts "==> #{id}"
|
88
|
+
composite << if mirror
|
89
|
+
img.mirror
|
90
|
+
else
|
91
|
+
img
|
92
|
+
end
|
93
|
+
|
94
|
+
count += 1
|
95
|
+
break if limit && count >= limit
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
slug = "#{@slug}"
|
100
|
+
slug += "#{limit}" if limit
|
101
|
+
slug += "_left" if mirror
|
102
|
+
|
103
|
+
path = "./#{@slug}/tmp/#{slug}-#{@width}x#{@height}.png"
|
104
|
+
puts " saving #{path}..."
|
105
|
+
composite.save( path )
|
106
|
+
|
107
|
+
if composite_count < 1000
|
108
|
+
path = "./#{@slug}/tmp/#{slug}-#{@width}x#{@height}@2x.png"
|
109
|
+
puts " saving 2x #{path}..."
|
110
|
+
composite.zoom(2).save( path )
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
def calc_attribute_counters ## todo/check: use a different name _counts/_stats etc - why? why not?
|
117
|
+
|
118
|
+
attributes_by_count = { count: 0,
|
119
|
+
by_count: Hash.new(0)
|
120
|
+
}
|
121
|
+
counter = {}
|
122
|
+
|
123
|
+
|
124
|
+
each_meta do |meta, id| ## todo/fix: change id to index
|
125
|
+
traits = meta.traits
|
126
|
+
# print "#{traits.size} - "
|
127
|
+
# pp traits
|
128
|
+
|
129
|
+
print "#{id}.." if id % 100 == 0 ## print progress report
|
130
|
+
|
131
|
+
attributes_by_count[ :count ] +=1
|
132
|
+
attributes_by_count[ :by_count ][ traits.size ] += 1
|
133
|
+
|
134
|
+
traits.each do |trait_type, trait_value|
|
135
|
+
trait_type = _normalize_trait_type( trait_type )
|
136
|
+
trait_value = _normalize_trait_value( trait_value )
|
137
|
+
|
138
|
+
|
139
|
+
rec = counter[ trait_type ] ||= { count: 0,
|
140
|
+
by_type: Hash.new(0)
|
141
|
+
}
|
142
|
+
rec[ :count ] +=1
|
143
|
+
rec[ :by_type ][ trait_value ] += 1
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
print "\n"
|
148
|
+
puts
|
149
|
+
|
150
|
+
## return all-in-one hash
|
151
|
+
{
|
152
|
+
total: attributes_by_count,
|
153
|
+
traits: counter,
|
154
|
+
}
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
def dump_attributes
|
159
|
+
stats = calc_attribute_counters
|
160
|
+
|
161
|
+
total = stats[:total]
|
162
|
+
counter = stats[:traits]
|
163
|
+
|
164
|
+
puts
|
165
|
+
puts "attribute usage / counts:"
|
166
|
+
pp total
|
167
|
+
puts
|
168
|
+
|
169
|
+
puts "#{counter.size} attribute(s):"
|
170
|
+
counter.each do |trait_name, trait_rec|
|
171
|
+
puts " #{trait_name} #{trait_rec[:count]} (#{trait_rec[:by_type].size} uniques)"
|
172
|
+
end
|
173
|
+
|
174
|
+
puts
|
175
|
+
pp counter
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
|
180
|
+
|
181
|
+
## order - allow "custom" attribute order export
|
182
|
+
## renames - allow renames of attributes
|
183
|
+
def export_attributes(
|
184
|
+
order: [],
|
185
|
+
renames: {}
|
186
|
+
)
|
187
|
+
|
188
|
+
## step 1: get counters
|
189
|
+
stats = calc_attribute_counters
|
190
|
+
|
191
|
+
total = stats[:total]
|
192
|
+
counter = stats[:traits]
|
193
|
+
|
194
|
+
puts
|
195
|
+
puts "attribute usage / counts:"
|
196
|
+
pp total
|
197
|
+
puts
|
198
|
+
|
199
|
+
puts "#{counter.size} attribute(s):"
|
200
|
+
counter.each do |trait_name, trait_rec|
|
201
|
+
puts " #{trait_name} #{trait_rec[:count]} (#{trait_rec[:by_type].size} uniques)"
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
trait_names = []
|
206
|
+
trait_names += order ## get attributes if any in pre-defined order
|
207
|
+
counter.each do |trait_name, _|
|
208
|
+
if trait_names.include?( trait_name )
|
209
|
+
next ## skip already included
|
210
|
+
else
|
211
|
+
trait_names << trait_name
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
|
216
|
+
recs = []
|
217
|
+
|
218
|
+
|
219
|
+
## step 2: get tabular data
|
220
|
+
each_meta do |meta, id| ## todo/fix: change id to index
|
221
|
+
|
222
|
+
traits = meta.traits
|
223
|
+
# print "#{traits.size} - "
|
224
|
+
# pp traits
|
225
|
+
|
226
|
+
print "#{id}.." if id % 100 == 0 ## print progress report
|
227
|
+
|
228
|
+
## setup empty hash table (with all attributes)
|
229
|
+
rec = {}
|
230
|
+
|
231
|
+
## note: use __Slug__& __Name__
|
232
|
+
## to avoid conflict with attribute names
|
233
|
+
## e.g. attribute with "Name" will overwrite built-in and so on
|
234
|
+
|
235
|
+
rec['__Slug__'] = if respond_to?( :_meta_slugify )
|
236
|
+
_meta_slugify( meta, id )
|
237
|
+
else
|
238
|
+
## default to id (six digits) as string with leading zeros
|
239
|
+
## for easy sorting using strings
|
240
|
+
## e.g. 1 => '000001'
|
241
|
+
## 2 => '000002'
|
242
|
+
'%06d' % id
|
243
|
+
end
|
244
|
+
|
245
|
+
rec['__Name__'] = meta.name
|
246
|
+
|
247
|
+
## add all attributes/traits names/keys
|
248
|
+
trait_names.reduce( rec ) { |h,value| h[value] = []; h }
|
249
|
+
## pp rec
|
250
|
+
|
251
|
+
## note: use an array (to allow multiple values for attributes)
|
252
|
+
traits.each do |trait_type, trait_value|
|
253
|
+
trait_type = _normalize_trait_type( trait_type )
|
254
|
+
trait_value = _normalize_trait_value( trait_value )
|
255
|
+
|
256
|
+
values = rec[ trait_type ]
|
257
|
+
values << trait_value
|
258
|
+
end
|
259
|
+
recs << rec
|
260
|
+
end
|
261
|
+
print "\n"
|
262
|
+
|
263
|
+
## pp recs
|
264
|
+
|
265
|
+
## flatten recs
|
266
|
+
data = []
|
267
|
+
recs.each do |rec|
|
268
|
+
row = rec.values.map do |value|
|
269
|
+
if value.is_a?( Array )
|
270
|
+
value.join( ' / ' )
|
271
|
+
else
|
272
|
+
value
|
273
|
+
end
|
274
|
+
end
|
275
|
+
data << row
|
276
|
+
end
|
277
|
+
|
278
|
+
|
279
|
+
## sort by slug
|
280
|
+
data = data.sort {|l,r| l[0] <=> r[0] }
|
281
|
+
pp data
|
282
|
+
|
283
|
+
### save dataset
|
284
|
+
## note: change first colum Slug to ID - only used for "internal" sort etc.
|
285
|
+
headers = ['ID', 'Name']
|
286
|
+
headers += trait_names.map do |trait_name| ## check for renames
|
287
|
+
renames[trait_name] || trait_name
|
288
|
+
end
|
289
|
+
|
290
|
+
|
291
|
+
path = "./#{@slug}/tmp/#{@slug}.csv"
|
292
|
+
dirname = File.dirname( path )
|
293
|
+
FileUtils.mkdir_p( dirname ) unless Dir.exist?( dirname )
|
294
|
+
|
295
|
+
File.open( path, 'w:utf-8' ) do |f|
|
296
|
+
f.write( headers.join( ', ' ))
|
297
|
+
f.write( "\n" )
|
298
|
+
## note: replace ID with our own internal running (zero-based) counter
|
299
|
+
data.each_with_index do |row,i|
|
300
|
+
f.write( ([i]+row[1..-1]).join( ', '))
|
301
|
+
f.write( "\n" )
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
|
307
|
+
|
308
|
+
|
309
|
+
#############
|
310
|
+
# "private" helpers
|
311
|
+
|
312
|
+
def _normalize_trait_type( trait_type )
|
313
|
+
if @patch && @patch[:trait_types]
|
314
|
+
@patch[:trait_types][ trait_type ] || trait_type
|
315
|
+
else
|
316
|
+
trait_type
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
def _normalize_trait_value( trait_value )
|
321
|
+
if @patch && @patch[:trait_values]
|
322
|
+
@patch[:trait_values][ trait_value ] || trait_value
|
323
|
+
else
|
324
|
+
trait_value
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
|
329
|
+
|
330
|
+
|
331
|
+
end # class Base
|
332
|
+
end # module Artbase
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
class ImageCollection
|
4
|
+
|
5
|
+
attr_reader :slug, :count
|
6
|
+
|
7
|
+
def initialize( slug, count,
|
8
|
+
image_base: ) # check: rename count to items or such - why? why not?
|
9
|
+
@slug = slug
|
10
|
+
@count = count
|
11
|
+
@image_base = image_base
|
12
|
+
end
|
13
|
+
|
14
|
+
def download_images( range=(0...@count) )
|
15
|
+
start = Time.now
|
16
|
+
delay_in_s = 0.3
|
17
|
+
|
18
|
+
range.each do |offset|
|
19
|
+
image_src = @image_base.sub( '{id}', offset.to_s )
|
20
|
+
|
21
|
+
puts "==> #{offset} - #{@slug}..."
|
22
|
+
|
23
|
+
## note: will auto-add format file extension (e.g. .png, .jpg)
|
24
|
+
## depending on http content type!!!!!
|
25
|
+
copy_image( image_src, "./#{@slug}/image-i/#{offset}" )
|
26
|
+
|
27
|
+
stop = Time.now
|
28
|
+
diff = stop - start
|
29
|
+
|
30
|
+
mins = diff / 60 ## todo - use floor or such?
|
31
|
+
secs = diff % 60
|
32
|
+
puts "up #{mins} mins #{secs} secs (total #{diff} secs)"
|
33
|
+
|
34
|
+
puts "sleeping #{delay_in_s}s..."
|
35
|
+
sleep( delay_in_s )
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end # class ImageCollection
|
39
|
+
|