harvester 0.8.0.pre.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.
Files changed (63) hide show
  1. data/CHANGELOG.rdoc +45 -0
  2. data/README.rdoc +74 -0
  3. data/Rakefile +28 -0
  4. data/bin/harvester +13 -0
  5. data/bin/harvester-chart +5 -0
  6. data/bin/harvester-clock +35 -0
  7. data/bin/harvester-db +15 -0
  8. data/bin/harvester-fetch +5 -0
  9. data/bin/harvester-generate +5 -0
  10. data/bin/harvester-jabber +6 -0
  11. data/bin/harvester-new +25 -0
  12. data/bin/harvester-post +5 -0
  13. data/bin/harvester-run +14 -0
  14. data/collections.yaml +15 -0
  15. data/config.yaml +13 -0
  16. data/data/ent/HTMLlat1.ent +194 -0
  17. data/data/ent/HTMLspecial.ent +77 -0
  18. data/data/ent/HTMLsymbol.ent +241 -0
  19. data/data/sql/dbd-mysql-isotime.diff +11 -0
  20. data/data/sql/harvester-0.6-mysql.diff +59 -0
  21. data/data/sql/harvester-0.7-mysql.diff +39 -0
  22. data/data/sql/mysql/chart.sql +1 -0
  23. data/data/sql/mysql/create.table.enclosures.sql +9 -0
  24. data/data/sql/mysql/create.table.items.sql +8 -0
  25. data/data/sql/mysql/create.table.jabbersettings.sql +5 -0
  26. data/data/sql/mysql/create.table.jabbersubscriptions.sql +5 -0
  27. data/data/sql/mysql/create.table.sources.sql +9 -0
  28. data/data/sql/mysql/create.view.last48hours.sql +1 -0
  29. data/data/sql/postgresql/chart.sql +1 -0
  30. data/data/sql/postgresql/create.table.enclosures.sql +9 -0
  31. data/data/sql/postgresql/create.table.items.sql +8 -0
  32. data/data/sql/postgresql/create.table.jabbersettings.sql +5 -0
  33. data/data/sql/postgresql/create.table.jabbersubscriptions.sql +5 -0
  34. data/data/sql/postgresql/create.table.sources.sql +9 -0
  35. data/data/sql/postgresql/create.view.last48hours.sql +1 -0
  36. data/data/sql/sqlite3/chart.sql +1 -0
  37. data/data/sql/sqlite3/create.table.enclosures.sql +9 -0
  38. data/data/sql/sqlite3/create.table.items.sql +8 -0
  39. data/data/sql/sqlite3/create.table.jabbersettings.sql +5 -0
  40. data/data/sql/sqlite3/create.table.jabbersubscriptions.sql +5 -0
  41. data/data/sql/sqlite3/create.table.sources.sql +9 -0
  42. data/data/sql/sqlite3/create.view.last48hours.sql +1 -0
  43. data/data/templates/atom-all.xml +88 -0
  44. data/data/templates/atom.xml +88 -0
  45. data/data/templates/index.html +412 -0
  46. data/data/templates/rss-all.rdf +86 -0
  47. data/data/templates/rss.rdf +85 -0
  48. data/data/templates/static/harvester.css +365 -0
  49. data/data/templates/static/harvester.gif +0 -0
  50. data/data/templates/static/harvester_ie7.css +15 -0
  51. data/data/templates/static/harvester_lte_ie6.css +27 -0
  52. data/harvester.gemspec +35 -0
  53. data/lib/harvester.rb +132 -0
  54. data/lib/harvester/chart.rb +72 -0
  55. data/lib/harvester/db.rb +123 -0
  56. data/lib/harvester/fetch.rb +96 -0
  57. data/lib/harvester/generate.rb +152 -0
  58. data/lib/harvester/generator/entity_translator.rb +46 -0
  59. data/lib/harvester/generator/link_absolutizer.rb +39 -0
  60. data/lib/harvester/jabber.rb +443 -0
  61. data/lib/harvester/mrss.rb +355 -0
  62. data/lib/harvester/post.rb +19 -0
  63. metadata +237 -0
@@ -0,0 +1,355 @@
1
+ # encoding: utf-8
2
+ # Magic RSS
3
+ # Helps getting around with RSS while ignoring standards and tolerating much
4
+
5
+ require 'rexml/document'
6
+ require 'cgi'
7
+ require 'iconv'
8
+
9
+ # Search macros
10
+ class REXML::Element
11
+ def s(expr)
12
+ each_element(expr) { |e| return e }
13
+ nil
14
+ end
15
+
16
+ def s_text(expr)
17
+ if (e = s(expr))
18
+ (e.cdatas.size > 0) ? e.cdatas.to_s : e.text
19
+ else
20
+ nil
21
+ end
22
+ end
23
+
24
+ def s_attr(expr, attr)
25
+ (e = s(expr)) ? e.attributes[attr] : nil
26
+ end
27
+
28
+ def rss_content(expr) # TODO: understand & refactor
29
+ if e = s(expr)
30
+ CGI::unescapeHTML(e.children.join)
31
+ end
32
+ end
33
+
34
+ def atom_content(expr)
35
+ e = s(expr)
36
+ if e
37
+ type = e.attributes['type']
38
+ mode = e.attributes['mode']
39
+
40
+ if type == 'xhtml' or mode == 'xml'
41
+ e.children.join
42
+ elsif type == 'html' or mode == 'escaped'
43
+ if e.cdatas.size > 0
44
+ e.cdatas.to_s
45
+ else
46
+ e.text
47
+ end
48
+ else # 'text'
49
+ if e.cdatas.size > 0
50
+ CGI::escapeHTML(e.cdatas.to_s)
51
+ else
52
+ CGI::escapeHTML(e.text.to_s)
53
+ end
54
+ end
55
+ else
56
+ nil
57
+ end
58
+ end
59
+
60
+ def atom_content_text(expr)
61
+ c = atom_content(expr)
62
+ if c
63
+ c.gsub!(/<.+?>/, '')
64
+ CGI::unescapeHTML(c)
65
+ else
66
+ nil
67
+ end
68
+ end
69
+
70
+ def atom_link
71
+ link, rank = 0, 0
72
+
73
+ each_element('link') do |e|
74
+ rel = e.attributes['rel']
75
+ type = e.attributes['type']
76
+
77
+ e_rank = (rel == 'alternate' ? 2 : 1) *
78
+ (rel == 'enclosure' ? 0 : 1) *
79
+ ((type == 'text/html' ? 2 : 0) +
80
+ (type == 'application/xhtml+xml' ? 1 : 0) +
81
+ 1)
82
+
83
+ if e_rank > rank
84
+ link = e.attributes['href']
85
+ rank = e_rank
86
+ end
87
+ end
88
+
89
+ link
90
+ end
91
+ end
92
+
93
+
94
+ class MRSS
95
+ class AbstractMethod < RuntimeError; end
96
+
97
+ def initialize(root)
98
+ @root = root
99
+ end
100
+
101
+ # Common properties
102
+ def items
103
+ res = []
104
+
105
+ @root.each_element(items_expr) do |i|
106
+ item = self.class::Item.new(i)
107
+
108
+ res << item unless item.title.to_s == '' and item.link.to_s == ''
109
+ end
110
+
111
+ res
112
+ end
113
+
114
+ # Abstract stuff
115
+ def title
116
+ raise AbstractMethod.new
117
+ end
118
+
119
+ def type
120
+ raise AbstractMethod.new
121
+ end
122
+
123
+ def link
124
+ raise AbstractMethod.new
125
+ end
126
+
127
+ def description
128
+ raise AbstractMethod.new
129
+ end
130
+
131
+ def feed_expr
132
+ raise AbstractMethod.new
133
+ end
134
+
135
+ def items_expr
136
+ raise AbstractMethod.new
137
+ end
138
+
139
+ # Item
140
+
141
+ class Item
142
+ def initialize(e)
143
+ @e = e
144
+ end
145
+ def title
146
+ raise AbstractMethod.new
147
+ end
148
+ def link
149
+ raise AbstractMethod.new
150
+ end
151
+ def description
152
+ raise AbstractMethod.new
153
+ end
154
+ def date
155
+ raise AbstractMethod.new
156
+ end
157
+ def enclosures
158
+ raise AbstractMethod.new
159
+ end
160
+ end
161
+
162
+ # Flavours
163
+
164
+ # RSS 0.9 & 2.0
165
+ class RSS < MRSS
166
+ def title
167
+ @root.s_text "#{feed_expr}/title"
168
+ end
169
+ def feed_expr
170
+ "/rss/channel"
171
+ end
172
+ def items_expr
173
+ "/rss/channel/item"
174
+ end
175
+ def link
176
+ @root.s_text "#{feed_expr}/link"
177
+ end
178
+ def description
179
+ @root.s_text "#{feed_expr}/description"
180
+ end
181
+
182
+ class Item < ::MRSS::Item
183
+ def title
184
+ @e.s_text "title"
185
+ end
186
+ def link
187
+ @e.s_text "link"
188
+ end
189
+ def description
190
+ @e.rss_content("content:encoded") ||
191
+ @e.rss_content("encoded") ||
192
+ @e.rss_content("description")
193
+ end
194
+ def date
195
+ d = @e.s_text('date') || @e.s_text('pubDate') || @e.s_text('dc:date')
196
+ MRSS::Util.detect_time(d).localtime
197
+ end
198
+ def enclosures
199
+ r = []
200
+ @e.each_element('enclosure') do |e|
201
+ h = {
202
+ 'href' => e.attributes['url'],
203
+ 'type' => e.attributes['type'],
204
+ 'title' => e.attributes['title'],
205
+ 'length' => e.attributes['length']
206
+ }
207
+ r << h
208
+ end
209
+ r
210
+ end
211
+ end
212
+ end
213
+
214
+ # RSS 1.0
215
+ class RDF < RSS
216
+ def feed_expr
217
+ "/*/channel"
218
+ end
219
+ def items_expr
220
+ "/*/item"
221
+ end
222
+ end
223
+
224
+ # ATOM 0.3 & 1.0
225
+ class ATOM < MRSS
226
+ def feed_expr
227
+ "/feed"
228
+ end
229
+ def items_expr
230
+ "/feed/entry"
231
+ end
232
+ def title
233
+ @root.atom_content_text "title"
234
+ end
235
+ def link
236
+ @root.atom_link
237
+ end
238
+ def description
239
+ @root.atom_content_text('tagline') ||
240
+ @root.atom_content_text('subtitle')
241
+ end
242
+
243
+ class Item < ::MRSS::Item
244
+ def title
245
+ @e.atom_content_text "title"
246
+ end
247
+ def link
248
+ @e.atom_link
249
+ end
250
+ def description
251
+ @e.atom_content("content") ||
252
+ @e.atom_content("summary")
253
+ end
254
+ def date
255
+ d = @e.s_text('published') || @e.s_text('issued') || @e.s_text('updated')
256
+ MRSS::Util.detect_time(d).localtime
257
+ end
258
+ def enclosures
259
+ r = []
260
+ @e.each_element("link") do |e|
261
+ if e.attributes['rel'] == 'enclosure'
262
+ h = {
263
+ 'href' => e.attributes['href'],
264
+ 'type' => e.attributes['type'],
265
+ 'title' => e.attributes['title'],
266
+ 'length' => e.attributes['length']
267
+ }
268
+ r << h
269
+ end
270
+ end
271
+ r
272
+ end
273
+ end
274
+ end
275
+
276
+
277
+ def self.parse(body)
278
+ begin
279
+ xml = REXML::Document.new(body).root
280
+ rescue REXML::ParseException
281
+ xml = REXML::Document.new(Iconv::iconv('UTF-8', 'ISO-8859-15', body).to_s).root
282
+ end
283
+
284
+ begin
285
+ # Try to validate UTF-8
286
+ Iconv::iconv('UTF-8', 'UTF-8', xml.to_s).to_s
287
+ rescue Iconv::IllegalSequence, Iconv::InvalidCharacter
288
+ xml = REXML::Document.new(Iconv::iconv('UTF-8', 'ISO-8859-15', body).to_s).root
289
+ end
290
+
291
+ k = case xml.name
292
+ when 'rss'
293
+ RSS
294
+ when 'rdf'
295
+ RDF
296
+ when 'RDF'
297
+ RDF
298
+ when 'feed'
299
+ ATOM
300
+ else
301
+ raise "Unknwon feed format: #{xml.name} (#{xml.namespace})"
302
+ end
303
+ k.new(xml)
304
+ end
305
+
306
+ module Util
307
+ def self.detect_time(s)
308
+ tz_offset = 0
309
+
310
+ # Fix it up
311
+ s.strip!
312
+
313
+ s.scan(/([\+\-])(\d\d):?(\d\d)$/).each do |plus_minus,hours,minutes|
314
+ tz_offset = ((hours.to_i * 60) + minutes.to_i) * 60
315
+ tz_offset *= (plus_minus == '+') ? -1 : 1
316
+ end
317
+
318
+ # 2004-04-01T21:23+00:00
319
+ # 2004-09-05T21:23Z
320
+ s.scan(/^(\d+)-(\d+)-(\d+)T(\d+):(\d+)/).each do |y,mo,d,h,m|
321
+ return Time.gm(y.to_i, mo.to_i, d.to_i, h.to_i, m.to_i) + tz_offset
322
+ end
323
+
324
+ # 2004-04-01T21:23:23+00:00
325
+ s.scan(/^(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+)\+(\d+):(\d+)$/).each do |y,mo,d,h,m,s,tz_h,tz_m|
326
+ return Time.gm(y.to_i, mo.to_i, d.to_i, h.to_i, m.to_i, s.to_i) + tz_offset
327
+ end
328
+
329
+ # Wed, 20 Apr 2005 19:38:15 +0200
330
+ # Fri, 22 Apr 2005 10:31:12 GMT
331
+ months = {"Jan" => 1, "Feb" => 2, "Mar" => 3, "Mär" => 3, "Apr" => 4, "May" => 5, "Mai" => 5, "Jun" => 6, "Jul" => 7, "Aug" => 8, "Sep" => 9, "Oct" => 10, "Okt" => 10, "Nov" => 11, "Dec" => 12, "Dez" => 12 }
332
+ s.scan(/^(.+?), +(\d+) (.+?) (\d+) (\d+):(\d+):(\d+) /).each do |wday,d,mo,y,h,m,s|
333
+ return Time.gm(y.to_i, months[mo], d.to_i, h.to_i, m.to_i, s.to_i) + tz_offset
334
+ end
335
+
336
+ # 06 May 2007 02:20:00
337
+ s.scan(/^(\d+) (.+?) (\d{4}) (\d\d):(\d\d):(\d\d)/).each do |d,mo,y,h,m,s|
338
+ return Time.gm(y.to_i, months[mo], d.to_i, h.to_i, m.to_i, s.to_i) + tz_offset
339
+ end
340
+
341
+ # Mon Apr 25 00:00:00 +0000 2011
342
+ s.scan(/^(.+?) (.+?) (\d+) (\d+):(\d+):(\d+) .* (\d{4})/).each do |wday,mo,d,h,m,s,y|
343
+ return Time.gm(y.to_i, months[mo], d.to_i, h.to_i, m.to_i, s.to_i) + tz_offset
344
+ end
345
+
346
+ # 2011-05-27
347
+ s.scan(/^(\d{4})-(\d\d)-(\d\d)/).each do |y,mo,d|
348
+ return Time.gm(y.to_i, months[mo], d.to_i) + tz_offset
349
+ end
350
+
351
+ # ugly <now> fallback
352
+ Time.new
353
+ end
354
+ end
355
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative '../harvester'
4
+
5
+ class Harvester
6
+ module POST; end
7
+
8
+ # runs the configured post processing scripts
9
+ def post!(path = nil)
10
+ task "post process" do
11
+ if post_script = path || @config['settings']['post_script']
12
+ error "Cannot find an executable script at #{ post_script }" unless test('x', post_script)
13
+ exec post_script, @config['settings']['output']
14
+ else
15
+ warn 'No post processing script configured or passed as argument!'
16
+ end
17
+ end#task
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,237 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: harvester
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: 6
5
+ version: 0.8.0.pre.1
6
+ platform: ruby
7
+ authors:
8
+ - astro
9
+ - Neingeist
10
+ - Tigion
11
+ - Josef Spillner
12
+ - Jan Lelis
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-05-27 00:00:00 Z
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: rdbi
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: "0"
28
+ type: :runtime
29
+ version_requirements: *id001
30
+ - !ruby/object:Gem::Dependency
31
+ name: rdbi-driver-sqlite3
32
+ prerelease: false
33
+ requirement: &id002 !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: "0"
39
+ type: :runtime
40
+ version_requirements: *id002
41
+ - !ruby/object:Gem::Dependency
42
+ name: logger-colors
43
+ prerelease: false
44
+ requirement: &id003 !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ type: :runtime
51
+ version_requirements: *id003
52
+ - !ruby/object:Gem::Dependency
53
+ name: eventmachine
54
+ prerelease: false
55
+ requirement: &id004 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ type: :runtime
62
+ version_requirements: *id004
63
+ - !ruby/object:Gem::Dependency
64
+ name: em-http-request
65
+ prerelease: false
66
+ requirement: &id005 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ type: :runtime
73
+ version_requirements: *id005
74
+ - !ruby/object:Gem::Dependency
75
+ name: ruby-xslt
76
+ prerelease: false
77
+ requirement: &id006 !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: "0"
83
+ type: :runtime
84
+ version_requirements: *id006
85
+ - !ruby/object:Gem::Dependency
86
+ name: hpricot
87
+ prerelease: false
88
+ requirement: &id007 !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: "0"
94
+ type: :runtime
95
+ version_requirements: *id007
96
+ - !ruby/object:Gem::Dependency
97
+ name: rmagick
98
+ prerelease: false
99
+ requirement: &id008 !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: "0"
105
+ type: :runtime
106
+ version_requirements: *id008
107
+ - !ruby/object:Gem::Dependency
108
+ name: gruff
109
+ prerelease: false
110
+ requirement: &id009 !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: "0"
116
+ type: :runtime
117
+ version_requirements: *id009
118
+ - !ruby/object:Gem::Dependency
119
+ name: clockwork
120
+ prerelease: false
121
+ requirement: &id010 !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: "0"
127
+ type: :runtime
128
+ version_requirements: *id010
129
+ description: The harvester collects your favourite feeds and generates static html/feed pages
130
+ email: mail@janlelis.de
131
+ executables:
132
+ - harvester-new
133
+ - harvester
134
+ - harvester-clock
135
+ - harvester-db
136
+ - harvester-chart
137
+ - harvester-run
138
+ - harvester-generate
139
+ - harvester-fetch
140
+ - harvester-jabber
141
+ - harvester-post
142
+ extensions: []
143
+
144
+ extra_rdoc_files: []
145
+
146
+ files:
147
+ - lib/harvester/generate.rb
148
+ - lib/harvester/generator/entity_translator.rb
149
+ - lib/harvester/generator/link_absolutizer.rb
150
+ - lib/harvester/db.rb
151
+ - lib/harvester/chart.rb
152
+ - lib/harvester/post.rb
153
+ - lib/harvester/jabber.rb
154
+ - lib/harvester/fetch.rb
155
+ - lib/harvester/mrss.rb
156
+ - lib/harvester.rb
157
+ - bin/harvester-new
158
+ - bin/harvester
159
+ - bin/harvester-clock
160
+ - bin/harvester-db
161
+ - bin/harvester-chart
162
+ - bin/harvester-run
163
+ - bin/harvester-generate
164
+ - bin/harvester-fetch
165
+ - bin/harvester-jabber
166
+ - bin/harvester-post
167
+ - README.rdoc
168
+ - CHANGELOG.rdoc
169
+ - data/ent/HTMLsymbol.ent
170
+ - data/ent/HTMLspecial.ent
171
+ - data/ent/HTMLlat1.ent
172
+ - data/templates/rss.rdf
173
+ - data/templates/atom.xml
174
+ - data/templates/index.html
175
+ - data/templates/static/harvester_lte_ie6.css
176
+ - data/templates/static/harvester_ie7.css
177
+ - data/templates/static/harvester.css
178
+ - data/templates/static/harvester.gif
179
+ - data/templates/rss-all.rdf
180
+ - data/templates/atom-all.xml
181
+ - data/sql/sqlite3/create.table.jabbersettings.sql
182
+ - data/sql/sqlite3/create.table.items.sql
183
+ - data/sql/sqlite3/create.table.jabbersubscriptions.sql
184
+ - data/sql/sqlite3/create.table.sources.sql
185
+ - data/sql/sqlite3/create.view.last48hours.sql
186
+ - data/sql/sqlite3/chart.sql
187
+ - data/sql/sqlite3/create.table.enclosures.sql
188
+ - data/sql/harvester-0.6-mysql.diff
189
+ - data/sql/dbd-mysql-isotime.diff
190
+ - data/sql/harvester-0.7-mysql.diff
191
+ - data/sql/postgresql/create.table.jabbersettings.sql
192
+ - data/sql/postgresql/create.table.items.sql
193
+ - data/sql/postgresql/create.table.jabbersubscriptions.sql
194
+ - data/sql/postgresql/create.table.sources.sql
195
+ - data/sql/postgresql/create.view.last48hours.sql
196
+ - data/sql/postgresql/chart.sql
197
+ - data/sql/postgresql/create.table.enclosures.sql
198
+ - data/sql/mysql/create.table.jabbersettings.sql
199
+ - data/sql/mysql/create.table.items.sql
200
+ - data/sql/mysql/create.table.jabbersubscriptions.sql
201
+ - data/sql/mysql/create.table.sources.sql
202
+ - data/sql/mysql/create.view.last48hours.sql
203
+ - data/sql/mysql/chart.sql
204
+ - data/sql/mysql/create.table.enclosures.sql
205
+ - collections.yaml
206
+ - config.yaml
207
+ - Rakefile
208
+ - harvester.gemspec
209
+ homepage: https://github.com/janlelis/harvester
210
+ licenses:
211
+ - AGPL
212
+ post_install_message:
213
+ rdoc_options: []
214
+
215
+ require_paths:
216
+ - lib
217
+ required_ruby_version: !ruby/object:Gem::Requirement
218
+ none: false
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: 1.9.2
223
+ required_rubygems_version: !ruby/object:Gem::Requirement
224
+ none: false
225
+ requirements:
226
+ - - ">="
227
+ - !ruby/object:Gem::Version
228
+ version: 1.3.6
229
+ requirements: []
230
+
231
+ rubyforge_project:
232
+ rubygems_version: 1.8.1
233
+ signing_key:
234
+ specification_version: 3
235
+ summary: Web-based feed aggregator
236
+ test_files: []
237
+