slideshow 1.1.0.beta8 → 1.1.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/Rakefile +1 -1
- data/lib/slideshow/commands/gen.rb +35 -69
- data/lib/slideshow/config.rb +3 -0
- data/lib/slideshow/filters/slide_filter.rb +16 -0
- data/lib/slideshow/opts.rb +9 -0
- data/lib/slideshow/runner.rb +77 -18
- data/lib/slideshow/slide.rb +83 -25
- data/lib/slideshow/version.rb +1 -1
- metadata +11 -15
data/Rakefile
CHANGED
@@ -96,7 +96,11 @@ class Gen
|
|
96
96
|
if (@markup_type == :markdown && Markdown.lib == 'pandoc-ruby') || @markup_type == :rest
|
97
97
|
content = add_slide_directive_before_div_h1( content )
|
98
98
|
else
|
99
|
-
|
99
|
+
if config.header_level == 2
|
100
|
+
content = add_slide_directive_before_h2( content )
|
101
|
+
else # assume level 1
|
102
|
+
content = add_slide_directive_before_h1( content )
|
103
|
+
end
|
100
104
|
end
|
101
105
|
|
102
106
|
dump_content_to_file_debug_html( content )
|
@@ -126,65 +130,24 @@ class Gen
|
|
126
130
|
end
|
127
131
|
|
128
132
|
|
129
|
-
## split slide source into header (optional) and content/body
|
130
|
-
## plus check for (css style) classes and data attributes
|
131
|
-
|
132
133
|
slides2 = []
|
133
134
|
slides.each do |slide_source|
|
134
|
-
|
135
|
-
|
136
|
-
## check for css style classes
|
137
|
-
from = 0
|
138
|
-
while (pos = slide_source.index( /<!-- _S9(SLIDE|STYLE)_(.*?)-->/m, from ))
|
139
|
-
logger.debug " adding css classes from pi #{$1.downcase}: #{$2.strip}"
|
140
|
-
|
141
|
-
from = Regexp.last_match.end(0) # continue search later from here
|
142
|
-
|
143
|
-
values = $2.strip.dup
|
144
|
-
|
145
|
-
# remove data values (eg. x=-20 scale=4) and store in data hash
|
146
|
-
values.gsub!( /([-\w]+)[ \t]*=[ \t]*([-\w\.]+)/ ) do |_|
|
147
|
-
logger.debug " adding data pair: key=>#{$1.downcase}< value=>#{$2}<"
|
148
|
-
slide.data[ $1.downcase.dup ] = $2.dup
|
149
|
-
" " # replace w/ space
|
150
|
-
end
|
151
|
-
|
152
|
-
values.strip! # remove spaces # todo: use squish or similar and check for empty string
|
153
|
-
|
154
|
-
if slide.classes.nil?
|
155
|
-
slide.classes = values
|
156
|
-
else
|
157
|
-
slide.classes << " #{values}"
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
# try to cut off header using non-greedy .+? pattern; tip test regex online at rubular.com
|
162
|
-
# note/fix: needs to get improved to also handle case for h1 wrapped into div
|
163
|
-
# (e.g. extract h1 - do not assume it starts slide source)
|
164
|
-
if slide_source =~ /^\s*(<h1.*?>.*?<\/h\d>)\s*(.*)/m
|
165
|
-
slide.header = $1
|
166
|
-
slide.content = ($2 ? $2 : "")
|
167
|
-
logger.debug " adding slide with header:\n#{slide.header}"
|
168
|
-
else
|
169
|
-
slide.content = slide_source
|
170
|
-
logger.debug " adding slide with *no* header:\n#{slide.content}"
|
171
|
-
end
|
172
|
-
slides2 << slide
|
135
|
+
slides2 << Slide.new( slide_source, config )
|
173
136
|
end
|
174
137
|
|
175
138
|
# for convenience create a string w/ all in-one-html
|
176
139
|
# no need to wrap slides in divs etc.
|
177
140
|
|
178
141
|
content2 = ""
|
179
|
-
slides2.each do |slide|
|
142
|
+
slides2.each do |slide|
|
180
143
|
content2 << slide.to_classic_html
|
181
144
|
end
|
182
145
|
|
183
146
|
# make content2 and slide2 available to erb template
|
184
147
|
# -- todo: cleanup variable names and use attr_readers for content and slide
|
185
148
|
|
186
|
-
@slides = slides2 # strutured content
|
187
|
-
@content = content2 # content all-in-one
|
149
|
+
@slides = slides2 # strutured content
|
150
|
+
@content = content2 # content all-in-one
|
188
151
|
end
|
189
152
|
|
190
153
|
|
@@ -207,7 +170,7 @@ class Gen
|
|
207
170
|
matches = manifests.select { |m| m[0] == manifest_path_or_name }
|
208
171
|
|
209
172
|
if matches.empty?
|
210
|
-
puts "*** error: unknown template manifest '#{manifest_path_or_name}'"
|
173
|
+
puts "*** error: unknown template manifest '#{manifest_path_or_name}'"
|
211
174
|
# todo: list installed manifests
|
212
175
|
exit 2
|
213
176
|
end
|
@@ -215,6 +178,7 @@ class Gen
|
|
215
178
|
manifest = load_manifest( matches[0][1] )
|
216
179
|
end
|
217
180
|
|
181
|
+
|
218
182
|
# expand output path in current dir and make sure output path exists
|
219
183
|
outpath = File.expand_path( opts.output_path )
|
220
184
|
logger.debug "outpath=#{outpath}"
|
@@ -235,29 +199,16 @@ class Gen
|
|
235
199
|
logger.debug "oldcwd=#{oldcwd}"
|
236
200
|
logger.debug "newcwd=#{newcwd}"
|
237
201
|
Dir.chdir newcwd
|
238
|
-
end
|
202
|
+
end
|
239
203
|
|
240
204
|
puts "Preparing slideshow '#{basename}'..."
|
241
|
-
|
242
|
-
if
|
243
|
-
|
244
|
-
|
245
|
-
config.known_extnames.each do |e|
|
246
|
-
logger.debug "File.exists? #{dirname}/#{basename}#{e}"
|
247
|
-
if File.exists?( "#{dirname}/#{basename}#{e}" ) then
|
248
|
-
extname = e
|
249
|
-
logger.debug "extname=#{extname}"
|
250
|
-
break
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
if config.known_markdown_extnames.include?( extname )
|
256
|
-
@markup_type = :markdown
|
205
|
+
|
206
|
+
if config.known_textile_extnames.include?( extname )
|
207
|
+
@markup_type = :textile
|
257
208
|
elsif config.known_rest_extnames.include?( extname )
|
258
209
|
@markup_type = :rest
|
259
|
-
else
|
260
|
-
@markup_type = :
|
210
|
+
else # default/fallback use markdown
|
211
|
+
@markup_type = :markdown
|
261
212
|
end
|
262
213
|
|
263
214
|
# shared variables for templates (binding)
|
@@ -268,7 +219,7 @@ class Gen
|
|
268
219
|
|
269
220
|
@session = {} # reset session hash for plugins/helpers
|
270
221
|
|
271
|
-
inname = "#{
|
222
|
+
inname = "#{basename}#{extname}"
|
272
223
|
|
273
224
|
logger.debug "inname=#{inname}"
|
274
225
|
|
@@ -299,6 +250,10 @@ class Gen
|
|
299
250
|
end
|
300
251
|
|
301
252
|
|
253
|
+
#### fix/todo:
|
254
|
+
##
|
255
|
+
## check for .erb file extension for trigger for erb processing
|
256
|
+
|
302
257
|
manifest.each do |entry|
|
303
258
|
outname = entry[0]
|
304
259
|
if outname.include? '__file__' # process
|
@@ -320,11 +275,22 @@ class Gen
|
|
320
275
|
else # just copy verbatim if target/dest has no __file__ in name
|
321
276
|
dest = entry[0]
|
322
277
|
source = entry[1]
|
323
|
-
|
324
|
-
|
278
|
+
|
279
|
+
#### fix/todo:
|
280
|
+
##
|
281
|
+
## check for .erb file extension for trigger for erb processing
|
282
|
+
|
283
|
+
puts "Copying to #{dest} from #{source}..."
|
325
284
|
FileUtils.copy( source, with_output_path( dest, outpath ) )
|
326
285
|
end
|
327
286
|
end
|
287
|
+
|
288
|
+
|
289
|
+
## pop/restore working folder/dir
|
290
|
+
unless newcwd == oldcwd
|
291
|
+
logger.debug "oldcwd=>#{oldcwd}<, newcwd=>#{newcwd}<"
|
292
|
+
Dir.chdir( oldcwd )
|
293
|
+
end
|
328
294
|
|
329
295
|
puts "Done."
|
330
296
|
end
|
data/lib/slideshow/config.rb
CHANGED
@@ -28,6 +28,22 @@ def add_slide_directive_before_h1( content )
|
|
28
28
|
content
|
29
29
|
end
|
30
30
|
|
31
|
+
def add_slide_directive_before_h2( content )
|
32
|
+
|
33
|
+
slide_count = 0
|
34
|
+
|
35
|
+
content.gsub!( /<h2/ ) do |match|
|
36
|
+
slide_count += 1
|
37
|
+
"\n<!-- _S9SLIDE_ -->\n#{Regexp.last_match(0)}"
|
38
|
+
end
|
39
|
+
|
40
|
+
puts " Adding #{slide_count} slide breaks (using h2 rule)..."
|
41
|
+
|
42
|
+
content
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
|
31
47
|
# add slide directive before div h1 (for pandoc-generated html)
|
32
48
|
#
|
33
49
|
# e.g. changes:
|
data/lib/slideshow/opts.rb
CHANGED
data/lib/slideshow/runner.rb
CHANGED
@@ -35,44 +35,103 @@ def load_plugins
|
|
35
35
|
end
|
36
36
|
|
37
37
|
|
38
|
+
def find_file_with_known_extension( fn )
|
39
|
+
dirname = File.dirname( fn )
|
40
|
+
basename = File.basename( fn, '.*' )
|
41
|
+
extname = File.extname( fn )
|
42
|
+
logger.debug "dirname=#{dirname}, basename=#{basename}, extname=#{extname}"
|
43
|
+
|
44
|
+
config.known_extnames.each do |e|
|
45
|
+
newname = File.join( dirname, "#{basename}#{e}" )
|
46
|
+
logger.debug "File.exists? #{newname}"
|
47
|
+
return newname if File.exists?( newname )
|
48
|
+
end # each extension (e)
|
49
|
+
|
50
|
+
nil # not found; return nil
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def find_files( file_or_dir_or_pattern )
|
55
|
+
|
56
|
+
filtered_files = []
|
57
|
+
|
58
|
+
## for now process/assume only single file
|
59
|
+
|
60
|
+
## (check for missing extension)
|
61
|
+
if File.exists?( file_or_dir_or_pattern )
|
62
|
+
file = file_or_dir_or_pattern
|
63
|
+
logger.debug " adding file '#{file}'..."
|
64
|
+
filtered_files << file
|
65
|
+
else # check for existing file w/ missing extension
|
66
|
+
file = find_file_with_known_extension( file_or_dir_or_pattern )
|
67
|
+
if file.nil?
|
68
|
+
puts " skipping missing file '#{file_or_dir_or_pattern}{#{config.known_extnames.join(',')}}'..."
|
69
|
+
else
|
70
|
+
logger.debug " adding file '#{file}'..."
|
71
|
+
filtered_files << file
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
filtered_files
|
76
|
+
|
77
|
+
end # method find_files
|
78
|
+
|
79
|
+
|
80
|
+
|
38
81
|
def run( args )
|
39
82
|
|
40
83
|
opt=OptionParser.new do |cmd|
|
41
84
|
|
42
85
|
cmd.banner = "Usage: slideshow [options] name"
|
43
|
-
|
86
|
+
|
44
87
|
cmd.on( '-o', '--output PATH', 'Output Path' ) { |path| opts.output_path = path }
|
45
|
-
|
46
|
-
cmd.on( '-g', '--generate', 'Generate Slide Show Templates (Using Built-In S6 Pack)' ) { opts.generate = true }
|
47
88
|
|
48
|
-
cmd.on( "-t", "--template MANIFEST", "Template Manifest" ) do |t|
|
89
|
+
cmd.on( "-t", "--template MANIFEST", "Template Manifest (default is s6.txt)" ) do |t|
|
49
90
|
# todo: do some checks on passed in template argument
|
50
91
|
opts.manifest = t
|
51
92
|
end
|
52
93
|
|
94
|
+
|
95
|
+
# cmd.on( '--header NUM', 'Header Level (default is 1)' ) do |n|
|
96
|
+
# opts.header_level = n.to_i
|
97
|
+
# end
|
98
|
+
|
99
|
+
cmd.on( '--h1', 'Set Header Level to 1 (default)' ) { opts.header_level = 1 }
|
100
|
+
cmd.on( '--h2', 'Set Header Level to 2' ) { opts.header_level = 2 }
|
101
|
+
|
102
|
+
|
53
103
|
# ?? opts.on( "-s", "--style STYLE", "Select Stylesheet" ) { |s| $options[:style]=s }
|
54
|
-
# ?? opts.on( "--version", "Show version" ) {}
|
55
104
|
|
56
105
|
# ?? cmd.on( '-i', '--include PATH', 'Load Path' ) { |s| opts.put( 'include', s ) }
|
57
106
|
|
58
|
-
cmd.on( '-f', '--fetch URI', 'Fetch Templates' ) do |uri|
|
59
|
-
opts.fetch_uri = uri
|
60
|
-
end
|
61
|
-
|
62
107
|
cmd.on( '-c', '--config PATH', 'Configuration Path (default is ~/.slideshow)' ) do |path|
|
63
108
|
opts.config_path = path
|
64
109
|
end
|
110
|
+
|
111
|
+
cmd.on( '-f', '--fetch URI', 'Fetch Templates' ) do |uri|
|
112
|
+
opts.fetch_uri = uri
|
113
|
+
end
|
114
|
+
|
115
|
+
cmd.on( '-g', '--generate', 'Generate Slide Show Templates (Using Built-In S6 Pack)' ) { opts.generate = true }
|
65
116
|
|
66
117
|
cmd.on( '-l', '--list', 'List Installed Templates' ) { opts.list = true }
|
67
118
|
|
68
119
|
# todo: find different letter for debug trace switch (use v for version?)
|
69
120
|
cmd.on( "-v", "--verbose", "Show debug trace" ) do
|
70
121
|
logger.datetime_format = "%H:%H:%S"
|
71
|
-
logger.level = Logger::DEBUG
|
122
|
+
logger.level = Logger::DEBUG
|
72
123
|
end
|
73
|
-
|
74
|
-
|
124
|
+
|
125
|
+
## todo: add --version
|
75
126
|
|
127
|
+
cmd.on( '--version', "Show version" ) do
|
128
|
+
puts Slideshow.generator
|
129
|
+
exit
|
130
|
+
end
|
131
|
+
|
132
|
+
cmd.on_tail( "-h", "--help", "Show this message" ) do
|
133
|
+
puts <<EOS
|
134
|
+
|
76
135
|
Slide Show (S9) is a free web alternative to PowerPoint or KeyNote in Ruby
|
77
136
|
|
78
137
|
#{cmd.help}
|
@@ -95,10 +154,6 @@ Further information:
|
|
95
154
|
http://slideshow.rubyforge.org
|
96
155
|
|
97
156
|
EOS
|
98
|
-
|
99
|
-
|
100
|
-
cmd.on_tail( "-h", "--help", "Show this message" ) do
|
101
|
-
puts usage
|
102
157
|
exit
|
103
158
|
end
|
104
159
|
end
|
@@ -118,8 +173,12 @@ EOS
|
|
118
173
|
else
|
119
174
|
load_plugins # check for optional plugins/extension in ./lib folder
|
120
175
|
|
121
|
-
args.each do |
|
122
|
-
|
176
|
+
args.each do |arg|
|
177
|
+
files = find_files( arg )
|
178
|
+
files.each do |file|
|
179
|
+
### fix/todo: reset/clean headers
|
180
|
+
Gen.new( logger, opts, config, headers ).create_slideshow( file )
|
181
|
+
end
|
123
182
|
end
|
124
183
|
end
|
125
184
|
end
|
data/lib/slideshow/slide.rb
CHANGED
@@ -1,19 +1,84 @@
|
|
1
1
|
module Slideshow
|
2
2
|
|
3
3
|
class Slide
|
4
|
-
|
5
|
-
attr_accessor :
|
4
|
+
|
5
|
+
attr_accessor :logger
|
6
|
+
|
7
|
+
# NB: unparsed html source (use content_without_header
|
8
|
+
# for content without option header)
|
9
|
+
|
6
10
|
attr_accessor :content
|
11
|
+
attr_accessor :content_without_header
|
12
|
+
attr_accessor :header
|
7
13
|
attr_accessor :classes
|
8
|
-
attr_accessor :data
|
9
14
|
|
10
|
-
def initialize
|
11
|
-
@
|
12
|
-
@
|
13
|
-
|
15
|
+
def initialize( content, options )
|
16
|
+
@logger = options.logger
|
17
|
+
@header_level = options.header_level
|
18
|
+
|
19
|
+
@content = content
|
20
|
+
|
21
|
+
@header = nil
|
22
|
+
@content_without_header = nil
|
23
|
+
@classes = nil # NB: style classes as all in one string
|
14
24
|
@data = {}
|
25
|
+
|
26
|
+
parse()
|
15
27
|
end
|
16
28
|
|
29
|
+
def parse
|
30
|
+
## pass 1) check for (css style) classes and data attributes
|
31
|
+
## check for css style classes
|
32
|
+
from = 0
|
33
|
+
while( pos = @content.index( /<!-- _S9(SLIDE|STYLE)_(.*?)-->/m, from ))
|
34
|
+
logger.debug " adding css classes from pi >#{$1.downcase}<: >#{$2.strip}<"
|
35
|
+
|
36
|
+
from = Regexp.last_match.end(0) # continue search later from here
|
37
|
+
|
38
|
+
values = $2.strip.dup
|
39
|
+
|
40
|
+
# remove data values (eg. x=-20 scale=4) and store in data hash
|
41
|
+
values.gsub!( /([-\w]+)[ \t]*=[ \t]*([-\w\.]+)/ ) do |_|
|
42
|
+
logger.debug " adding data pair: key=>#{$1.downcase}< value=>#{$2}<"
|
43
|
+
@data[ $1.downcase.dup ] = $2.dup
|
44
|
+
" " # replace w/ space
|
45
|
+
end
|
46
|
+
|
47
|
+
values.strip! # remove spaces # todo: use squish or similar and check for empty string
|
48
|
+
|
49
|
+
if @classes.nil?
|
50
|
+
@classes = values
|
51
|
+
else
|
52
|
+
@classes << " #{values}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
## pass 2) split slide source into header (optional) and content/body
|
57
|
+
|
58
|
+
## todo: add option split on h1/h2 etc.
|
59
|
+
|
60
|
+
# try to extract first header using non-greedy .+? pattern;
|
61
|
+
# tip test regex online at rubular.com
|
62
|
+
# note/fix: needs to get improved to also handle case for h1 wrapped into div
|
63
|
+
|
64
|
+
if @header_level == 2
|
65
|
+
pattern = /^(.*?)(<h2.*?>.*?<\/h2>)(.*)/m
|
66
|
+
else # assume header level 1
|
67
|
+
pattern = /^(.*?)(<h1.*?>.*?<\/h1>)(.*)/m
|
68
|
+
end
|
69
|
+
|
70
|
+
if @content =~ pattern
|
71
|
+
@header = $2
|
72
|
+
@content_without_header = ($1 ? $1 : '') + ($3 ? $3 : '')
|
73
|
+
logger.debug " adding slide with header (h1):\n#{@header}"
|
74
|
+
else
|
75
|
+
@header = nil # todo: set to '' empty string? why not?
|
76
|
+
@content_without_header = @content
|
77
|
+
logger.debug " adding slide with *no* header:\n#{@content}"
|
78
|
+
end
|
79
|
+
end # method parse
|
80
|
+
|
81
|
+
|
17
82
|
def data_attributes
|
18
83
|
buf = ""
|
19
84
|
@data.each do | key,value |
|
@@ -21,40 +86,33 @@ module Slideshow
|
|
21
86
|
end
|
22
87
|
buf
|
23
88
|
end
|
89
|
+
|
90
|
+
################################
|
91
|
+
#### convenience helpers
|
24
92
|
|
25
93
|
def to_classic_html
|
26
|
-
|
27
94
|
buf = ""
|
28
95
|
buf << "<div class='slide "
|
29
96
|
buf << classes if classes
|
30
|
-
buf << "'>\n"
|
31
|
-
|
32
|
-
buf << header if header
|
33
|
-
buf << content if content
|
34
|
-
|
97
|
+
buf << "'>\n"
|
98
|
+
buf << content
|
35
99
|
buf << "</div>\n"
|
36
|
-
buf
|
100
|
+
buf
|
37
101
|
end
|
38
102
|
|
39
103
|
def to_google_html5
|
40
|
-
|
41
104
|
buf = ""
|
42
105
|
buf << "<div class='slide'>\n"
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
buf << "<section class='"
|
49
|
-
buf << classes if classes
|
106
|
+
buf << "<header>#{header}</header>\n" if header
|
107
|
+
buf << "<section "
|
108
|
+
buf << "class='#{classes}'" if classes
|
50
109
|
buf << "'>\n"
|
51
|
-
|
52
|
-
buf << content if content
|
110
|
+
buf << content_without_header if content_without_header
|
53
111
|
buf << "</section>\n"
|
54
112
|
buf << "</div>\n"
|
55
113
|
buf
|
56
114
|
end
|
57
115
|
|
58
|
-
end # class
|
116
|
+
end # class Slide
|
59
117
|
|
60
118
|
end # module Slideshow
|
data/lib/slideshow/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: slideshow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 19
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 1
|
9
9
|
- 0
|
10
|
-
|
11
|
-
- 8
|
12
|
-
version: 1.1.0.beta8
|
10
|
+
version: 1.1.0
|
13
11
|
platform: ruby
|
14
12
|
authors:
|
15
13
|
- Gerald Bauer
|
@@ -17,7 +15,7 @@ autorequire:
|
|
17
15
|
bindir: bin
|
18
16
|
cert_chain: []
|
19
17
|
|
20
|
-
date: 2012-06-
|
18
|
+
date: 2012-06-17 00:00:00 Z
|
21
19
|
dependencies:
|
22
20
|
- !ruby/object:Gem::Dependency
|
23
21
|
name: RedCloth
|
@@ -43,12 +41,12 @@ dependencies:
|
|
43
41
|
requirements:
|
44
42
|
- - ">="
|
45
43
|
- !ruby/object:Gem::Version
|
46
|
-
hash:
|
44
|
+
hash: 15
|
47
45
|
segments:
|
48
46
|
- 0
|
49
|
-
-
|
47
|
+
- 4
|
50
48
|
- 0
|
51
|
-
version: 0.
|
49
|
+
version: 0.4.0
|
52
50
|
type: :runtime
|
53
51
|
version_requirements: *id002
|
54
52
|
- !ruby/object:Gem::Dependency
|
@@ -222,14 +220,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
222
220
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
223
221
|
none: false
|
224
222
|
requirements:
|
225
|
-
- - "
|
223
|
+
- - ">="
|
226
224
|
- !ruby/object:Gem::Version
|
227
|
-
hash:
|
225
|
+
hash: 3
|
228
226
|
segments:
|
229
|
-
-
|
230
|
-
|
231
|
-
- 1
|
232
|
-
version: 1.3.1
|
227
|
+
- 0
|
228
|
+
version: "0"
|
233
229
|
requirements: []
|
234
230
|
|
235
231
|
rubyforge_project: slideshow
|