sequencer 1.0.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.
- data/.autotest +23 -0
- data/History.txt +6 -0
- data/Manifest.txt +8 -0
- data/README.txt +49 -0
- data/Rakefile +12 -0
- data/bin/seqls +8 -0
- data/lib/sequencer.rb +208 -0
- data/test/test_sequencer.rb +156 -0
- metadata +85 -0
data/.autotest
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'autotest/restart'
|
4
|
+
|
5
|
+
# Autotest.add_hook :initialize do |at|
|
6
|
+
# at.extra_files << "../some/external/dependency.rb"
|
7
|
+
#
|
8
|
+
# at.libs << ":../some/external"
|
9
|
+
#
|
10
|
+
# at.add_exception 'vendor'
|
11
|
+
#
|
12
|
+
# at.add_mapping(/dependency.rb/) do |f, _|
|
13
|
+
# at.files_matching(/test_.*rb$/)
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# %w(TestA TestB).each do |klass|
|
17
|
+
# at.extra_class_map[klass] = "test/test_misc.rb"
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
|
21
|
+
# Autotest.add_hook :run_command do |at|
|
22
|
+
# system "rake build"
|
23
|
+
# end
|
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
= sequencer
|
2
|
+
|
3
|
+
* http://guerilla-di.org/sequencer
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Simplifies working with image sequences
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* List all sequences in a directory interspersed with other file entries
|
12
|
+
* Detect sequence from single file
|
13
|
+
|
14
|
+
== SYNOPSIS:
|
15
|
+
|
16
|
+
require "sequencer"
|
17
|
+
s = Sequencer.from_single_file("/RAID/Film/CONFORM.092183.dpx")
|
18
|
+
s.file_count #=> 3201
|
19
|
+
s.gaps? #=> true
|
20
|
+
s.missing_frames #=> 15, somebody was careless
|
21
|
+
|
22
|
+
== INSTALL:
|
23
|
+
|
24
|
+
* sudo gem install sequencer
|
25
|
+
|
26
|
+
== LICENSE:
|
27
|
+
|
28
|
+
(The MIT License)
|
29
|
+
|
30
|
+
Copyright (c) 2010 Julik Tarkhanov (me@julik.nl)
|
31
|
+
|
32
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
33
|
+
a copy of this software and associated documentation files (the
|
34
|
+
'Software'), to deal in the Software without restriction, including
|
35
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
36
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
37
|
+
permit persons to whom the Software is furnished to do so, subject to
|
38
|
+
the following conditions:
|
39
|
+
|
40
|
+
The above copyright notice and this permission notice shall be
|
41
|
+
included in all copies or substantial portions of the Software.
|
42
|
+
|
43
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
44
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
45
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
46
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
47
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
48
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
49
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
require 'rubygems'
|
3
|
+
require 'hoe'
|
4
|
+
require File.dirname(__FILE__) + "/lib/sequencer"
|
5
|
+
|
6
|
+
Hoe.spec 'sequencer' do | s |
|
7
|
+
s.version = Sequencer::VERSION
|
8
|
+
s.developer('Julik Tarkhanov', 'me@julik.nl')
|
9
|
+
s.extra_dev_deps = {"test-spec" => ">=0"}
|
10
|
+
end
|
11
|
+
|
12
|
+
# vim: syntax=ruby
|
data/bin/seqls
ADDED
data/lib/sequencer.rb
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
module Sequencer
|
2
|
+
VERSION = '1.0.0'
|
3
|
+
NUMBERS_AT_END = /(\d+)([^\d]+)?$/
|
4
|
+
|
5
|
+
extend self
|
6
|
+
|
7
|
+
# Detects sequences in the passed directory (same as Dir.entries but returns Sequence objects).
|
8
|
+
# Single files will be upgraded to single-frame Sequences
|
9
|
+
def entries(of_dir)
|
10
|
+
actual_files = Dir.entries(of_dir)[2..-1]
|
11
|
+
groups = {}
|
12
|
+
|
13
|
+
actual_files.each do | e |
|
14
|
+
if e =~ NUMBERS_AT_END
|
15
|
+
base = e[0...-([$1, $2].join.length)]
|
16
|
+
key = [base, $2]
|
17
|
+
groups[key] ||= []
|
18
|
+
groups[key] << e
|
19
|
+
else
|
20
|
+
groups[e] = [e]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
groups.map do | key, filenames |
|
25
|
+
Sequence.new(of_dir, filenames)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Detect a Sequence from a single file and return a handle to it
|
30
|
+
def from_single_file(path_to_single_file)
|
31
|
+
File.stat(path_to_single_file)
|
32
|
+
frame_number = path_to_single_file.scan(NUMBERS_AT_END).flatten.shift
|
33
|
+
if frame_number =~ /^0/ # Assume that the input is padded and take the glob path
|
34
|
+
sequence_via_glob(path_to_single_file)
|
35
|
+
else # Take the slower path by pattern-matching on entries
|
36
|
+
sequence_via_patterns(path_to_single_file)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Get a glob pattern and padding offset for a file in a sequence
|
41
|
+
def glob_and_padding_for(path)
|
42
|
+
plen = 0
|
43
|
+
glob_pattern = path.gsub(NUMBERS_AT_END) do
|
44
|
+
plen = $1.length
|
45
|
+
('[0-9]' * plen) + $2.to_s
|
46
|
+
end
|
47
|
+
return nil if glob_pattern == path
|
48
|
+
|
49
|
+
[glob_pattern, plen]
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def sequence_via_glob(path_to_single_file)
|
55
|
+
glob, padding = glob_and_padding_for(path_to_single_file)
|
56
|
+
seq_glob = File.join(File.dirname(path_to_single_file), File.basename(glob))
|
57
|
+
files = Dir.glob(seq_glob).map {|f| File.basename(f) }
|
58
|
+
|
59
|
+
Sequence.new(File.expand_path(File.dirname(path_to_single_file)), files)
|
60
|
+
end
|
61
|
+
|
62
|
+
def sequence_via_patterns(path_to_single_file)
|
63
|
+
base_glob_pattern = path_to_single_file.gsub(NUMBERS_AT_END, '*')
|
64
|
+
closing_element = $2
|
65
|
+
matching_paths = Dir.glob(base_glob_pattern).select do | p |
|
66
|
+
number, closer = p.scan(NUMBERS_AT_END).flatten
|
67
|
+
closer == closing_element
|
68
|
+
end
|
69
|
+
files = matching_paths.map {|f| File.basename(f) }
|
70
|
+
Sequence.new(File.expand_path(File.dirname(path_to_single_file)), files)
|
71
|
+
end
|
72
|
+
|
73
|
+
public
|
74
|
+
|
75
|
+
class Sequence
|
76
|
+
include Enumerable
|
77
|
+
attr_reader :pattern
|
78
|
+
|
79
|
+
def initialize(directory, filenames)
|
80
|
+
raise "Can't sequence nothingness" if filenames.empty?
|
81
|
+
@directory, @filenames = directory, natural_sort(filenames)
|
82
|
+
@directory.freeze
|
83
|
+
@filenames.freeze
|
84
|
+
detect_gaps!
|
85
|
+
detect_pattern!
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns true if the files in the sequence can have numbers
|
89
|
+
def numbered?
|
90
|
+
@numbered ||= !!(@filenames[0] =~ NUMBERS_AT_END)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Returns true if this sequence has gaps
|
94
|
+
def gaps?
|
95
|
+
@ranges.length > 1
|
96
|
+
end
|
97
|
+
|
98
|
+
# Tells whether this is a single frame sequence
|
99
|
+
def single_file?
|
100
|
+
@filenames.length == 1
|
101
|
+
end
|
102
|
+
|
103
|
+
def inspect
|
104
|
+
'#<%s>' % to_s
|
105
|
+
end
|
106
|
+
|
107
|
+
def to_s
|
108
|
+
return @filenames[0] if (!numbered? || single_file?)
|
109
|
+
|
110
|
+
printable = unless single_file?
|
111
|
+
@ranges.map do | r |
|
112
|
+
"%d..%d" % [r.begin, r.end]
|
113
|
+
end.join(', ')
|
114
|
+
else
|
115
|
+
@ranges[0].begin
|
116
|
+
end
|
117
|
+
@inspect_pattern % "[#{printable}]"
|
118
|
+
end
|
119
|
+
|
120
|
+
def expected_frames
|
121
|
+
@expected_frames ||= ((@ranges[-1].end - @ranges[0].begin) + 1)
|
122
|
+
end
|
123
|
+
|
124
|
+
def gap_count
|
125
|
+
@ranges.length - 1
|
126
|
+
end
|
127
|
+
|
128
|
+
# Returns the number of frames that the sequence should contain to be continuous
|
129
|
+
def missing_frames
|
130
|
+
expected_frames - file_count
|
131
|
+
end
|
132
|
+
|
133
|
+
# Returns the actual file count in the sequence
|
134
|
+
def file_count
|
135
|
+
@file_count ||= @filenames.length
|
136
|
+
end
|
137
|
+
|
138
|
+
# Check if this sequencer includes a file
|
139
|
+
def include?(base_filename)
|
140
|
+
@filenames.include?(base_filename)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Yield each filename in the sequence to the block
|
144
|
+
def each
|
145
|
+
@filenames.each {|f| yield(f) }
|
146
|
+
end
|
147
|
+
|
148
|
+
# Yield each absolute path to a file in the sequence to the block
|
149
|
+
def each_path
|
150
|
+
@filenames.each{|f| yield(File.join(@directory, f))}
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
def natural_sort(ar)
|
156
|
+
ar.sort_by {|e| e.scan(NUMBERS_AT_END).flatten.shift.to_i }
|
157
|
+
end
|
158
|
+
|
159
|
+
def detect_pattern!
|
160
|
+
|
161
|
+
unless numbered?
|
162
|
+
@inspect_pattern = "%s"
|
163
|
+
@pattern = @filenames[0]
|
164
|
+
else
|
165
|
+
@inspect_pattern = @filenames[0].gsub(NUMBERS_AT_END) do
|
166
|
+
["%s", $2].join
|
167
|
+
end
|
168
|
+
|
169
|
+
highest_padding = nil
|
170
|
+
@pattern = @filenames[-1].gsub(NUMBERS_AT_END) do
|
171
|
+
highest_padding = $1.length
|
172
|
+
["%0#{$1.length}d", $2].join
|
173
|
+
end
|
174
|
+
|
175
|
+
# Look at the first file in the sequence. If it has a lesser number of
|
176
|
+
lowest_padding = @filenames[0].scan(NUMBERS_AT_END).flatten.shift.length
|
177
|
+
if lowest_padding < highest_padding # Natural numbering
|
178
|
+
@pattern = @filenames[0].gsub(NUMBERS_AT_END) do
|
179
|
+
["%d", $2].join
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
@inspect_pattern.freeze
|
185
|
+
@pattern.freeze
|
186
|
+
end
|
187
|
+
|
188
|
+
def detect_gaps!
|
189
|
+
only_numbers = @filenames.map do | f |
|
190
|
+
f.scan(NUMBERS_AT_END).flatten.shift.to_i
|
191
|
+
end
|
192
|
+
@ranges = to_ranges(only_numbers)
|
193
|
+
end
|
194
|
+
|
195
|
+
def to_ranges(array)
|
196
|
+
array.compact.sort.uniq.inject([]) do | result, elem |
|
197
|
+
result = [elem..elem] if result.length.zero?
|
198
|
+
if [result[-1].end, result[-1].end.succ].include?(elem)
|
199
|
+
result[-1] = result[-1].begin..elem
|
200
|
+
else
|
201
|
+
result.push(elem..elem)
|
202
|
+
end
|
203
|
+
result
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'test/spec'
|
4
|
+
require 'fileutils'
|
5
|
+
require File.dirname(__FILE__) + '/../lib/sequencer'
|
6
|
+
|
7
|
+
TEST_DIR = File.dirname(__FILE__) + "/tmp"
|
8
|
+
|
9
|
+
def emit_test_dirs
|
10
|
+
start_f = 123
|
11
|
+
end_f = 568
|
12
|
+
|
13
|
+
FileUtils.mkdir_p(TEST_DIR + "/sequence_and_sole_file")
|
14
|
+
main_seq = TEST_DIR + "/sequence_and_sole_file/seq1.%06d.tif"
|
15
|
+
sole_file = TEST_DIR + "/sequence_and_sole_file/somefile.tif"
|
16
|
+
(start_f..end_f).each do | i |
|
17
|
+
FileUtils.touch(main_seq % i)
|
18
|
+
end
|
19
|
+
FileUtils.touch(sole_file)
|
20
|
+
|
21
|
+
broken_seq = TEST_DIR + "/sequence_and_sole_file/broken_seq.%06d.tif"
|
22
|
+
|
23
|
+
(start_f..end_f).each do | i |
|
24
|
+
FileUtils.touch(broken_seq % i)
|
25
|
+
end
|
26
|
+
|
27
|
+
((end_f + 10)..(end_f + 134)).each do | i |
|
28
|
+
FileUtils.touch(broken_seq % i)
|
29
|
+
end
|
30
|
+
|
31
|
+
single_file_seq = TEST_DIR + "/sequence_and_sole_file/single_file.002123154.tif"
|
32
|
+
FileUtils.touch(single_file_seq)
|
33
|
+
|
34
|
+
FileUtils.mkdir_p(TEST_DIR + "/natural_numbering")
|
35
|
+
nat_seq = TEST_DIR + "/natural_numbering/somefiles %d.png"
|
36
|
+
|
37
|
+
(5545142...5545172).each do | i |
|
38
|
+
FileUtils.touch(nat_seq % i)
|
39
|
+
end
|
40
|
+
|
41
|
+
FileUtils.mkdir_p(TEST_DIR + "/many_seqs")
|
42
|
+
(458..512).each do | i |
|
43
|
+
FileUtils.touch(TEST_DIR + "/many_seqs/seq1.%d.tif" % i)
|
44
|
+
end
|
45
|
+
|
46
|
+
(228..312).each do | i |
|
47
|
+
FileUtils.touch(TEST_DIR + "/many_seqs/anotherS %d.tif" % i)
|
48
|
+
end
|
49
|
+
FileUtils.touch(TEST_DIR + "/many_seqs/single.tif")
|
50
|
+
$emitted = true
|
51
|
+
end
|
52
|
+
|
53
|
+
def teardown_test_dirs
|
54
|
+
FileUtils.rm_rf(TEST_DIR)
|
55
|
+
end
|
56
|
+
|
57
|
+
context "Sequencer.glob_and_padding_for should" do
|
58
|
+
|
59
|
+
specify "return proper glob pattern and padding for a path with extension" do
|
60
|
+
glob, pad = Sequencer.glob_and_padding_for("file.00001.gif")
|
61
|
+
glob.should.equal "file.[0-9][0-9][0-9][0-9][0-9].gif"
|
62
|
+
pad.should.equal 5
|
63
|
+
end
|
64
|
+
|
65
|
+
specify "return proper glob pattern and padding for a path without extension" do
|
66
|
+
glob, pad = Sequencer.glob_and_padding_for("file.00001")
|
67
|
+
glob.should.equal "file.[0-9][0-9][0-9][0-9][0-9]"
|
68
|
+
pad.should.equal 5
|
69
|
+
end
|
70
|
+
|
71
|
+
specify "return nil for a file that is not a sequence" do
|
72
|
+
glob, pad = Sequencer.glob_and_padding_for("file")
|
73
|
+
glob.should.be.nil
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "Sequencer.entries should" do
|
78
|
+
before { emit_test_dirs }
|
79
|
+
after { teardown_test_dirs }
|
80
|
+
specify "return entries for every sequence in a directory" do
|
81
|
+
entries = Sequencer.entries(TEST_DIR + "/many_seqs")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context "A Sequence created from unpadded files should" do
|
86
|
+
before { emit_test_dirs }
|
87
|
+
after { teardown_test_dirs }
|
88
|
+
|
89
|
+
specify "be properly created" do
|
90
|
+
s = Sequencer.from_single_file(TEST_DIR + "/natural_numbering/somefiles 5545168.png")
|
91
|
+
s.should.not.be.nil
|
92
|
+
s.expected_frames.should.equal 30
|
93
|
+
s.file_count.should.equal 30
|
94
|
+
s.pattern.should.equal "somefiles %07d.png"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "A Sequence created from a file that has no numbering slot should" do
|
99
|
+
before { @single = Sequencer::Sequence.new("/tmp", ["foo.tif"]) }
|
100
|
+
|
101
|
+
specify "report a pattern that is the same as filename" do
|
102
|
+
@single.pattern.should.equal "foo.tif"
|
103
|
+
@single.should.be.single_file?
|
104
|
+
@single.expected_frames.should.equal 1
|
105
|
+
@single.inspect.should.equal "#<foo.tif>"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "A Sequence created from pad-numbered files should" do
|
110
|
+
before do
|
111
|
+
emit_test_dirs
|
112
|
+
@gapless = Sequencer.from_single_file(TEST_DIR + "/sequence_and_sole_file/seq1.000245.tif")
|
113
|
+
@with_gaps = Sequencer.from_single_file(TEST_DIR + "/sequence_and_sole_file/broken_seq.000245.tif")
|
114
|
+
@single = Sequencer.from_single_file(TEST_DIR + "/sequence_and_sole_file/single_file.002123154.tif")
|
115
|
+
end
|
116
|
+
|
117
|
+
after { teardown_test_dirs }
|
118
|
+
|
119
|
+
specify "initialize itself from one path to a file in the sequence without gaps" do
|
120
|
+
@gapless.should.not.be.nil
|
121
|
+
@gapless.should.be.kind_of(Sequencer::Sequence)
|
122
|
+
@gapless.should.respond_to(:gaps?)
|
123
|
+
@gapless.should.not.be.single_file?
|
124
|
+
|
125
|
+
@gapless.should.blaming("this is a gapless sequence").not.be.gaps?
|
126
|
+
@gapless.file_count.should.blaming("actual file count in sequence").equal(446)
|
127
|
+
@gapless.expected_frames.should.blaming("expected frame count in sequence").equal(446)
|
128
|
+
@gapless.inspect.should.blaming("inspect itself").equal('#<seq1.[123..568].tif>')
|
129
|
+
@gapless.pattern.should.equal 'seq1.%06d.tif'
|
130
|
+
files = @gapless.map {|f| f }
|
131
|
+
files.length.should.equal 446
|
132
|
+
files[0].should.equal 'seq1.000123.tif'
|
133
|
+
end
|
134
|
+
|
135
|
+
specify "initialize itself from one path to a file in the sequence with gaps" do
|
136
|
+
@with_gaps.should.not.be.nil
|
137
|
+
@with_gaps.should.be.kind_of(Sequencer::Sequence)
|
138
|
+
@with_gaps.should.not.be.single_file?
|
139
|
+
|
140
|
+
@with_gaps.should.be.gaps?
|
141
|
+
@with_gaps.gap_count.should.equal 1
|
142
|
+
@with_gaps.missing_frames.should.equal(9)
|
143
|
+
@with_gaps.inspect.should.blaming("inspect itself").equal('#<broken_seq.[123..568, 578..702].tif>')
|
144
|
+
@with_gaps.should.include("broken_seq.000123.tif")
|
145
|
+
@with_gaps.should.not.include("bogus.123.tif")
|
146
|
+
end
|
147
|
+
|
148
|
+
specify "initialize itself from a single file" do
|
149
|
+
@single.should.be.single_file?
|
150
|
+
@single.inspect.should.equal '#<single_file.002123154.tif>'
|
151
|
+
@single.should.not.be.gaps?
|
152
|
+
@single.expected_frames.should.equal 1
|
153
|
+
@single.file_count.should.equal 1
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sequencer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Julik Tarkhanov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-13 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: test-spec
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: hoe
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.3.3
|
34
|
+
version:
|
35
|
+
description: Simplifies working with image sequences
|
36
|
+
email:
|
37
|
+
- me@julik.nl
|
38
|
+
executables:
|
39
|
+
- seqls
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files:
|
43
|
+
- History.txt
|
44
|
+
- Manifest.txt
|
45
|
+
- README.txt
|
46
|
+
files:
|
47
|
+
- .autotest
|
48
|
+
- History.txt
|
49
|
+
- Manifest.txt
|
50
|
+
- README.txt
|
51
|
+
- Rakefile
|
52
|
+
- bin/seqls
|
53
|
+
- lib/sequencer.rb
|
54
|
+
- test/test_sequencer.rb
|
55
|
+
has_rdoc: true
|
56
|
+
homepage: http://guerilla-di.org/sequencer
|
57
|
+
licenses: []
|
58
|
+
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options:
|
61
|
+
- --main
|
62
|
+
- README.txt
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: "0"
|
70
|
+
version:
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: "0"
|
76
|
+
version:
|
77
|
+
requirements: []
|
78
|
+
|
79
|
+
rubyforge_project: sequencer
|
80
|
+
rubygems_version: 1.3.5
|
81
|
+
signing_key:
|
82
|
+
specification_version: 3
|
83
|
+
summary: Simplifies working with image sequences
|
84
|
+
test_files:
|
85
|
+
- test/test_sequencer.rb
|