jsl-myzofeedtosis 0.0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Justin S. Leitgeb
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,109 @@
1
+ = Description
2
+
3
+ Myzofeedtosis is a library that helps you to efficiently process syndicated web resources. It helps by automatically using
4
+ conditional HTTP GET requests, as well as by pointing out which entries are new in any given feed.
5
+
6
+ == Name
7
+
8
+ The name "myzofeedtosis" is based on the form of cellular digestion "myzocytosis". According to Wikipedia [1], myzocytosis
9
+ is described as the process where "one cell pierces another using a feeding tube, and sucks out cytoplasm". Myzofeedtosis is
10
+ kind of like that, except it works with RSS/Atom feeds instead of cytoplasm.
11
+
12
+ 1 - http://en.wikipedia.org/wiki/List_of_vores
13
+
14
+ == Philosophy
15
+
16
+ Myzofeedtosis is designed to help you with book-keeping about feed fetching details. This is usually something that is
17
+ mundane and not fundamentally related to the business logic of applications that deal with the consumption of syndicated
18
+ content on the web. Myzofeedtosis keeps track of these mundane details so you can just keep grabbing new content without
19
+ wasting bandwidth in making unnecessary requests and programmer time in implementing algorithms to figure out which feed
20
+ entries are new.
21
+
22
+ Myzofeedtosis fits into other frameworks to do the heavy lifting, including the Curb library which does HTTP requests through
23
+ curl, and FeedNormalizer which abstracts the differences between syndication formats. In the sense that it fits into these
24
+ existing, robust programs, Myzofeedtosis is a modular middleware piece that efficiently glues together disparate parts to create
25
+ a helpful feed reader with a minimal (< 200 LOC), test-covered codebase.
26
+
27
+ == Installation
28
+
29
+ Assuming that you've followed the directions on gems.github.com to allow your computer to install gems from GitHub, the
30
+ following command will install the Myzofeedtosis library:
31
+
32
+ sudo gem install jsl-myzofeedtosis
33
+
34
+ == Usage
35
+
36
+ Myzofeedtosis is easy to use. Just create a client object, and invoke the "fetch" method:
37
+
38
+ require 'myzofeedtosis'
39
+ client = Myzofeedtosis::Client.new('http://feeds.feedburner.com/wooster')
40
+ result = client.fetch
41
+
42
+ +result+ will be a FeedNormalizer::Feed object, which responds to the method +entries+. In this first case, Myzofeedtosis
43
+ isn't much more useful than just using FeedNormalizer by itself. On subsequent requests, though, it helps significantly.
44
+ Invoke client.fetch again. Instead of getting back an object that responds to +entries+, you'll probably get back a Curl::Easy
45
+ object with a response code of 304, indicating that the resource hasn't changed since the last retrieval. If you invoke
46
+ fetch again, assuming one entry was added, you would get back another FeedNormalizer::Feed object. You'll also notice that
47
+ all of the FeedNormalizer::Feed objects respond not only to +entries+, but +new_entries+, which is a selection of the entries
48
+ that haven't been seen before.
49
+
50
+ Myzofeedtosis is designed for these situations where you have one or maybe thousands of feeds that you have to update on a
51
+ regular basis. If the results that you receive respond to the method new_entries, iterate over the new entries, processing them
52
+ according to your business logic.
53
+
54
+ You will most likely want to allow Myzofeedtosis to remember details about the last retrieval of a feed after the client is
55
+ removed from memory. Myzofeedtosis uses Moneta, a unified interface to key-value storage systems to remember "summaries" of
56
+ feeds that it has seen in the past. See the document section on Customization for more details on how to configure this system.
57
+
58
+ == Customization
59
+
60
+ Myzofeedtosis stores summaries of feeds in a key-value storage system. If no options are included when creating a new
61
+ Myzofeedtosis::Client object, the default is to use a "memory" storage system. The memory system is just a basic ruby Hash, so it
62
+ won't keep track of feeds after a particular Client is removed from memory. To configure a different backend, pass an options hash
63
+ to the Myzofeedtosis client initialization:
64
+
65
+ url = "http://newsrss.bbc.co.uk/rss/newsonline_world_edition/south_asia/rss.xml"
66
+ mf = Myzofeedtosis::Client.new(url, :backend => {:moneta_klass => 'Moneta::Memcache', :server => 'localhost:1978'})
67
+ res = mf.fetch
68
+
69
+ This example sets up a Memcache backend, which in this case points to Tokyo Tyrant on port 1978. Note that Moneta::Memcache
70
+ can be given as a string, in which case you don't have to manually require Moneta::Memcache before initializing the client.
71
+
72
+ Generally, Myzofeedtosis supports all systems supported by Moneta, and any one of the supported systems can be given to the
73
+ +moneta_klass+ parameter. Other options following +backend+ are passed directly to Moneta for configuration.
74
+
75
+ == Implementation
76
+
77
+ Myzofeedtosis helps to identify new feed entries and to figure out when conditional GET can be used in retrieving resources. In
78
+ order to accomplish this without having to require that the user store information such as etags and dates of the last retrieved entry,
79
+ Myzofeedtosis stores a summary structure in the configured key-value store (backed by Moneta). In order to do conditional GET
80
+ requests, Myzofeedtosis stores the Last-Modified date, as well as the ETag of the last request in the summary structure, which is
81
+ put in a namespaced element consisting of the term 'Myzofeedtosis' (bet you won't have to worry about name collisions on that one!)
82
+ and the MD5 of the URL retrieved.
83
+
84
+ It can also be a bit tricky to decipher which feed entries are new since many feed sources don't include unique ids with their
85
+ feeds. Myzofeedtosis reliably keeps track of which entries in a feed are new by storing (in the summary hash mentioned above) an
86
+ MD5 signature of each entry in a feed. It takes elements such as the published-at date, title and content and generates the MD5
87
+ of these elements. This allows Myzofeedtosis to cheaply compute (both in terms of computation and storage) which feed entries
88
+ should be presented to the user as "new". Below is an example of a summary structure:
89
+
90
+ {
91
+ :etag=>"4c8f-46ac09fbbe940", :last_modified=>"Mon, 25 May 2009 18:17:33 GMT",
92
+ :digests=>["f2993783ded928637ce5f2dc2d837f10", "da64efa6dd9ce34e5699b9efe73a37a7"]
93
+ }
94
+
95
+ The data stored by Myzofeedtosis in the summary structure allows it to be helpful to the user without storing lots of
96
+ data that are unnecessary for efficient functioning.
97
+
98
+ == HTML cleaning/sanitizing
99
+
100
+ Myzofeedtosis doesn't do anything about feed sanitizing, as other libraries have been built for this purpose. FeedNormalizer
101
+ has methods for escaping entries, but to strip HTML I suggest that you look at the Ruby gem "sanitize".
102
+
103
+ == Feedback
104
+
105
+ Please let me know if you have any problems with or questions about Myzofeedtosis.
106
+
107
+ = Author
108
+
109
+ Justin S. Leitgeb, mailto:justin@phq.org
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ require 'rake'
5
+ require 'spec/rake/spectask'
6
+ require 'rake/rdoctask'
7
+
8
+ require 'lib/myzofeedtosis'
9
+
10
+ desc 'Test the plugin.'
11
+ Spec::Rake::SpecTask.new(:spec) do |t|
12
+ t.spec_opts = ["--format", "progress", "--colour"]
13
+ t.libs << 'lib'
14
+ t.verbose = true
15
+ end
16
+
17
+ desc "Run all the tests"
18
+ task :default => :spec
19
+
20
+ desc 'Generate documentation'
21
+ Rake::RDocTask.new(:rdoc) do |rdoc|
22
+ rdoc.rdoc_dir = 'rdoc'
23
+ rdoc.title = 'Myzofeedtosis'
24
+ rdoc.options << '--line-numbers' << '--inline-source'
25
+ rdoc.rdoc_files.include('README.rdoc')
26
+ rdoc.rdoc_files.include('lib/myzofeedtosis/**/*.rb')
27
+ end
28
+
@@ -0,0 +1,8 @@
1
+ class Array
2
+
3
+ # From Rails' ActiveSupport library
4
+ def extract_options!
5
+ last.is_a?(::Hash) ? pop : {}
6
+ end
7
+
8
+ end
@@ -0,0 +1,17 @@
1
+ class Hash
2
+ # Returns a Hash containing only input keys.
3
+ # Method from merb-core.
4
+ def except(*rejected)
5
+ reject { |k,v| rejected.include?(k) }
6
+ end
7
+
8
+ def reverse_merge(other_hash)
9
+ other_hash.merge(self)
10
+ end
11
+
12
+ # Returns a new hash containing only the input keys.
13
+ # Method from merb-core.
14
+ def only(*allowed)
15
+ reject { |k,v| !allowed.include?(k) }
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # Extends FeedNormalizer::Feed with method for detecting new_items (aliased as new_entries for
2
+ # convenience).
3
+ module Myzofeedtosis
4
+ module FeedInstanceMethods
5
+
6
+ # Returns only the feeds that are new.
7
+ def new_items
8
+ self.entries.select do |e|
9
+ e.instance_variable_get(:@_seen) == false
10
+ end
11
+ end
12
+
13
+ alias :new_entries :new_items
14
+ end
15
+ end
16
+
17
+ FeedNormalizer::Feed.__send__(:include, Myzofeedtosis::FeedInstanceMethods)
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'curb'
3
+ require 'hashback'
4
+ require 'http_headers'
5
+ require 'feed-normalizer'
6
+ require 'md5'
7
+
8
+ lib_dirs = [ 'extensions', 'myzofeedtosis' ].map do |d|
9
+ File.join(File.dirname(__FILE__), d)
10
+ end
11
+
12
+ lib_dirs.each do |d|
13
+ Dir[File.join(d, "**", "*.rb")].each {|file| require file }
14
+ end
@@ -0,0 +1,147 @@
1
+ module Myzofeedtosis
2
+
3
+ # Myzofeedtosis::Client is the primary interface to the feed reader. Call it with a url that was previously fetched while
4
+ # connected to the configured backend, and it will 1) only do a retrieval if deemed necessary based on the etag and modified-at
5
+ # of the last etag and 2) mark all entries retrieved as either new or not new. Entries retrieved are normalized using
6
+ # the feed-normalizer gem.
7
+ class Client
8
+ attr_reader :options, :url
9
+
10
+ DEFAULTS = {
11
+ :backend => {
12
+ :moneta_klass => 'Moneta::Memory'
13
+ }
14
+ } unless defined?(DEFAULTS)
15
+
16
+ def initialize(url, options = { })
17
+ @url = url
18
+ @options = DEFAULTS.merge(options)
19
+
20
+ @backend = HashBack::Backend.new( 'Myzofeedtosis',
21
+ @options[:backend][:moneta_klass],
22
+ @options[:backend].except(:moneta_klass) )
23
+ end
24
+
25
+ # Retrieves the latest entries from this feed. Returns a Feednormalizer::Feed object with
26
+ # method +new_entries+ if the response was successful, otherwise returns the Curl::Easy object
27
+ # that we used to retrieve this resource. Note that we also return this object if the request
28
+ # resulted in a 304 (Not Modified) response code since we don't have any new results. Depending
29
+ # on your business logic, you may want to do something in this case, such as putting this
30
+ # resource in a lower-priority queue if it is not frequently updated.
31
+ def fetch
32
+ curl = build_curl_easy
33
+ curl.perform
34
+ process_curl_response(curl)
35
+ end
36
+
37
+ private
38
+
39
+ # Marks entries as either seen or not seen based on the unique signature of the entry, which
40
+ # is calculated by taking the MD5 of common attributes.
41
+ def mark_new_entries(response)
42
+ digests = if summary_for_feed.nil? || summary_for_feed[:digests].nil?
43
+ [ ]
44
+ else
45
+ summary_for_feed[:digests]
46
+ end
47
+
48
+ # For each entry in the responses object, mark @_seen as false if the digest of this entry
49
+ # doesn't exist in the cached object.
50
+ response.entries.each do |e|
51
+ seen = digests.include?(digest_for(e))
52
+ e.instance_variable_set(:@_seen, seen)
53
+ end
54
+
55
+ response
56
+ end
57
+
58
+ # Processes the results by identifying which entries are new if the response
59
+ # is a 200. Otherwise, returns the Curl::Easy object for the user to inspect.
60
+ def process_curl_response(curl)
61
+ if curl.response_code == 200
62
+ response = parser_for_xml(curl.body_str)
63
+ response = mark_new_entries(response)
64
+ store_summary_to_backend(response, curl)
65
+ response
66
+ else
67
+ curl
68
+ end
69
+ end
70
+
71
+ # Sets options for the Curl::Easy object, including parameters for HTTP conditional GET.
72
+ def build_curl_easy
73
+ curl = new_curl_easy(url)
74
+
75
+ # Many feeds have a 302 redirect to another URL. For more recent versions of Curl,
76
+ # we need to specify this.
77
+ curl.follow_location = true
78
+
79
+ set_header_options(curl)
80
+ end
81
+
82
+ def new_curl_easy(url)
83
+ Curl::Easy.new(url)
84
+ end
85
+
86
+ # Returns the summary hash for this feed from the backend store.
87
+ def summary_for_feed
88
+ @backend[key_for_cached]
89
+ end
90
+
91
+ # Sets the headers from the backend, if available
92
+ def set_header_options(curl)
93
+ summary = summary_for_feed
94
+
95
+ unless summary.nil?
96
+ # We should only try to populate the headers for a conditional GET if we know both
97
+ # of these values.
98
+ if summary[:etag] && summary[:last_modified]
99
+ curl.headers['If-None-Match'] = summary[:etag]
100
+ curl.headers['If-Modified-Since'] = summary[:last_modified]
101
+ end
102
+ end
103
+
104
+ curl
105
+ end
106
+
107
+ def key_for_cached
108
+ MD5.hexdigest(@url)
109
+ end
110
+
111
+ # Stores information about the retrieval, including ETag, Last-Modified, and MD5 digests of all
112
+ # entries to the backend store. This enables conditional GET usage on subsequent requests and
113
+ # marking of entries as either new or seen.
114
+ def store_summary_to_backend(feed, curl)
115
+ headers = HttpHeaders.new(curl.header_str)
116
+
117
+ # Store info about HTTP retrieval
118
+ summary = { }
119
+
120
+ summary.merge!(:etag => headers.etag) unless headers.etag.nil?
121
+ summary.merge!(:last_modified => headers.last_modified) unless headers.last_modified.nil?
122
+
123
+ # Store digest for each feed entry so we can detect new feeds on the next retrieval
124
+ digests = feed.entries.map do |e|
125
+ digest_for(e)
126
+ end
127
+
128
+ summary.merge!(:digests => digests)
129
+ set_summary(summary)
130
+ end
131
+
132
+ def set_summary(summary)
133
+ @backend[key_for_cached] = summary
134
+ end
135
+
136
+ # Computes a unique signature for the FeedNormalizer::Entry object given. This signature
137
+ # will be the MD5 of enough fields to have a reasonable probability of determining if the
138
+ # entry is unique or not.
139
+ def digest_for(entry)
140
+ MD5.hexdigest([entry.date_published, entry.url, entry.title, entry.content].join)
141
+ end
142
+
143
+ def parser_for_xml(xml)
144
+ FeedNormalizer::FeedNormalizer.parse(xml)
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,42 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{myzofeedtosis}
3
+ s.version = "0.0.1.2"
4
+
5
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
+ s.authors = ["Justin Leitgeb"]
7
+ s.date = %q{2009-05-22}
8
+ s.description = %q{Myzofeedtosis finds new information in feeds quickly using smart fetching and matching of previously read entries}
9
+ s.email = %q{justin@phq.org}
10
+
11
+ s.files = ["lib/extensions/core/array.rb", "lib/extensions/core/hash.rb",
12
+ "lib/extensions/feed_normalizer/feed_instance_methods.rb", "lib/myzofeedtosis/client.rb", "lib/myzofeedtosis.rb",
13
+ "LICENSE", "myzofeedtosis.gemspec", "Rakefile", "README.rdoc", "spec/extensions/feed_normalizer/feed_instance_methods_spec.rb",
14
+ "spec/fixtures/http_headers/wooster.txt", "spec/fixtures/xml/older_wooster.xml", "spec/fixtures/xml/wooster.xml",
15
+ "spec/myzofeedtosis/client_spec.rb", "spec/myzofeedtosis_spec.rb", "spec/spec_helper.rb"]
16
+
17
+ s.has_rdoc = true
18
+ s.homepage = %q{http://github.com/jsl/myzofeedtosis}
19
+ s.rdoc_options = ["--charset=UTF-8"]
20
+ s.require_paths = ["lib"]
21
+ s.rubygems_version = %q{1.3.1}
22
+ s.summary = %q{Retrieves feeds using conditional GET and marks entries that you haven't seen before}
23
+ s.test_files = ["spec/myzofeedtosis_spec.rb", "spec/spec_helper.rb", "spec/myzofeedtosis/client_spec.rb"]
24
+
25
+ s.extra_rdoc_files = [ "README.rdoc" ]
26
+
27
+ s.rdoc_options += [
28
+ '--title', 'Myzofeedtosis',
29
+ '--main', 'README.rdoc',
30
+ '--line-numbers',
31
+ '--inline-source'
32
+ ]
33
+
34
+ %w[ taf2-curb wycats-moneta jsl-hashback jsl-http_headers feed-normalizer ].each do |dep|
35
+ s.add_dependency(dep)
36
+ end
37
+
38
+ if s.respond_to? :specification_version then
39
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
40
+ s.specification_version = 2
41
+ end
42
+ end
@@ -0,0 +1,12 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
2
+
3
+ describe Myzofeedtosis::FeedInstanceMethods do
4
+ before do
5
+ @fn = FeedNormalizer::FeedNormalizer.parse(xml_fixture('wooster'))
6
+ end
7
+
8
+ it "should respond to new_entries and new_items" do
9
+ @fn.should respond_to(:new_entries)
10
+ @fn.should respond_to(:new_items)
11
+ end
12
+ end
@@ -0,0 +1,19 @@
1
+ HTTP/1.1 302 Found
2
+ Date: Mon, 25 May 2009 17:36:02 GMT
3
+ Server: Apache/2.0.52 (Red Hat)
4
+ Location: http://feeds.feedburner.com/wooster
5
+ Content-Length: 311
6
+ Connection: close
7
+ Content-Type: text/html; charset=iso-8859-1
8
+
9
+ HTTP/1.1 200 OK
10
+ Last-Modified: Mon, 25 May 2009 16:38:49 GMT
11
+ ETag: /YJUYmsYIcQeFAGy7OZQoaCQeXw
12
+ Content-Type: text/xml; charset=utf-8
13
+ Date: Mon, 25 May 2009 17:36:03 GMT
14
+ Expires: Mon, 25 May 2009 17:36:03 GMT
15
+ Cache-Control: private, max-age=0
16
+ X-Content-Type-Options: nosniff
17
+ Server: GFE/2.0
18
+ Transfer-Encoding: chunked
19
+
@@ -0,0 +1,203 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?>
3
+ <?xml-stylesheet type="text/css" media="screen" href="http://feeds2.feedburner.com/~d/styles/itemcontent.css"?>
4
+ <rss xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
5
+ <channel>
6
+ <title>Wooster Collective</title>
7
+ <link>http://www.woostercollective.com/</link>
8
+ <description/>
9
+ <language>en</language>
10
+ <copyright>Copyright 2009</copyright>
11
+ <lastBuildDate>Mon, 25 May 2009 07:48:04 -0500</lastBuildDate>
12
+ <generator>http://www.sixapart.com/movabletype/?v=3.3</generator>
13
+ <docs>http://blogs.law.harvard.edu/tech/rss</docs>
14
+ <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="www.woostercollective.com/rss/index.xml" type="application/rss+xml"/>
15
+ <feedburner:emailServiceId>wooster</feedburner:emailServiceId>
16
+ <feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname>
17
+ <item>
18
+ <title>Seen In North London: Department of Urban Censorship</title>
19
+ <description><![CDATA[<p><a href="http://www.woostercollective.com/urbancensor.jpg"><img alt="urbancensor.jpg" src="http://www.woostercollective.com/urbancensor-thumb.jpg" width="500" height="444" /></a></p>
20
+
21
+ <p>(Thanks, <a href="http://www.tupajumi.com/jonathan/">Jonathan</a>)<br />
22
+ </p>]]></description>
23
+ <link>http://feedproxy.google.com/~r/wooster/~3/syiP17t0PKo/seen_in_north_london_department_of_urban.html</link>
24
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/seen_in_north_london_department_of_urban.html</guid>
25
+ <category>Wheatpastes</category>
26
+ <pubDate>Mon, 25 May 2009 07:39:16 -0500</pubDate>
27
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/seen_in_north_london_department_of_urban.html</feedburner:origLink>
28
+ </item>
29
+ <item>
30
+ <title>Seen On The Steets Of Stockholm</title>
31
+ <description><![CDATA[<p><a href="http://www.woostercollective.com/poststock.jpg"><img alt="poststock.jpg" src="http://www.woostercollective.com/poststock-thumb.jpg" width="500" height="748" /></a></p>
32
+
33
+ <p>Artist: <a href="http://vimeo.com/post">Post</a></p>]]></description>
34
+ <link>http://feedproxy.google.com/~r/wooster/~3/611KGRn-ZQE/seen_on_the_steets_of_stockholm.html</link>
35
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/seen_on_the_steets_of_stockholm.html</guid>
36
+ <category>Wheatpastes</category>
37
+ <pubDate>Mon, 25 May 2009 07:29:55 -0500</pubDate>
38
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/seen_on_the_steets_of_stockholm.html</feedburner:origLink>
39
+ </item>
40
+ <item>
41
+ <title>Zevs' Electric Rainbows (2007)</title>
42
+ <description><![CDATA[<p>Zevs has updated <a href="http://www.gzzglz.com/">his website</a> with photos of past and recent project. We love the Electric Rainbows that he exchanged for advertisements back 2007:</p>
43
+
44
+ <p><a href="http://www.woostercollective.com/electric-rainbow-02.jpg"><img alt="electric-rainbow-02.jpg" src="http://www.woostercollective.com/electric-rainbow-02-thumb.jpg" width="500" height="335" /></a></p>
45
+
46
+ <p><br />
47
+ </p>]]></description>
48
+ <link>http://feedproxy.google.com/~r/wooster/~3/TpmlTS7y0f0/zevs_electric_rainbows_2007.html</link>
49
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/zevs_electric_rainbows_2007.html</guid>
50
+ <category>Art</category>
51
+ <pubDate>Mon, 25 May 2009 07:19:27 -0500</pubDate>
52
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/zevs_electric_rainbows_2007.html</feedburner:origLink>
53
+ </item>
54
+ <item>
55
+ <title>Zephyr - An Introduction</title>
56
+ <description><![CDATA[<p><a href="http://www.woostercollective.com/zephydith.jpg"><img alt="zephydith.jpg" src="http://www.woostercollective.com/zephydith-thumb.jpg" width="500" height="347" /></a></p>
57
+
58
+ <p><object width="320" height="265"><param name="movie" value="http://www.youtube.com/v/kqXXZcy-2JU&hl=en&fs=1&rel=0&hd=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/kqXXZcy-2JU&hl=en&fs=1&rel=0&hd=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="320" height="265"></embed></object></p>
59
+
60
+ <p>One of the first graffiti artists to "accept" Sara and I back in 2000 when we started the Wooster Collective was Zephyr. This week <a href="http://www.upperplayground.com/">Upper Playground</a> posted a terrific interview with Zephyr filmed a few years ago for their Dithers DVD. </p>]]></description>
61
+ <link>http://feedproxy.google.com/~r/wooster/~3/32-ED1oPdYY/zephyr_in_introduction.html</link>
62
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/zephyr_in_introduction.html</guid>
63
+ <category>Graffiti</category>
64
+ <pubDate>Sat, 23 May 2009 12:44:36 -0500</pubDate>
65
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/zephyr_in_introduction.html</feedburner:origLink>
66
+ </item>
67
+ <item>
68
+ <title>The Yes Men - An Introduction</title>
69
+ <description><![CDATA[<div><object width="512" height="322"><param name="movie" value="http://d.yimg.com/static.video.yahoo.com/yep/YV_YEP.swf?ver=2.2.40" /><param name="allowFullScreen" value="true" /><param name="AllowScriptAccess" VALUE="always" /><param name="bgcolor" value="#000000" /><param name="flashVars" value="id=13527850&vid=13527850&lang=en-us&intl=us&thumbUrl=&embed=1" /><embed src="http://d.yimg.com/static.video.yahoo.com/yep/YV_YEP.swf?ver=2.2.40" type="application/x-shockwave-flash" width="512" height="322" allowFullScreen="true" AllowScriptAccess="always" bgcolor="#000000" flashVars="id=13527850&vid=13527850&lang=en-us&intl=us&thumbUrl=&embed=1" ></embed></object><br /><a href="http://video.yahoo.com/watch/13527850/13527850"></a> @ <a href="http://video.yahoo.com" >Yahoo! Video</a></div>
70
+
71
+ <p>If you're not familiar with <a href="http://theyesmen.org/">The Yes Men</a>, this video of their Poptech speech from 2006 is a fantastic introduction.</p>
72
+
73
+ <p>(Hat tip to <a href="http://www.brainpickings.org/">Brain Pickings</a>)</p>]]></description>
74
+ <link>http://feedproxy.google.com/~r/wooster/~3/0yXb4Ui8C3I/the_yes_men_an_introduction.html</link>
75
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/the_yes_men_an_introduction.html</guid>
76
+ <category>Activism</category>
77
+ <pubDate>Fri, 22 May 2009 11:24:26 -0500</pubDate>
78
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/the_yes_men_an_introduction.html</feedburner:origLink>
79
+ </item>
80
+ <item>
81
+ <title>A Great Example Of Site Specific Work: Carlsbad Sidewalk Surfer</title>
82
+ <description><![CDATA[<p><img alt="bryansurfer.jpg" src="http://www.woostercollective.com/bryansurfer.jpg" width="500" height="384" /></p>
83
+
84
+ <p><object width="400" height="307"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=4772503&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=4772503&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="307"></embed></object><p><a href="http://vimeo.com/4772503">Carlsbad Sidewalk Surfer by bryan snyder</a> from <a href="http://vimeo.com/bryansnyder">Bryan Snyder</a> on <a href="http://vimeo.com">Vimeo</a>.</p></p>
85
+
86
+ <p>From <a href="http://www.snyderartdesign.com">Bryan</a>:</p>
87
+
88
+ <p>Carlsbad Sidewalk Surfer interacts with its environment during mid day wind gusts. Like the waves that tumble upon our shore, the visibility of this art piece depends on the weather. Between the glassy conditions of the morning and the mellow winds at dusk, the Carlsbad Sidewalk Surfer sneaks into another ride. The goal of this project is to showcase the relationship between a piece of art and its environment when placed in the streets."</p>]]></description>
89
+ <link>http://feedproxy.google.com/~r/wooster/~3/oXfLFSd86cY/a_great_example_of_site_specific_work_ca.html</link>
90
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/a_great_example_of_site_specific_work_ca.html</guid>
91
+ <category>Environmental</category>
92
+ <pubDate>Fri, 22 May 2009 07:54:36 -0500</pubDate>
93
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/a_great_example_of_site_specific_work_ca.html</feedburner:origLink>
94
+ </item>
95
+ <item>
96
+ <title>Herakut Beautifies The Streets Of New York</title>
97
+ <description><![CDATA[<p><img alt="9501466.jpg" src="http://www.woostercollective.com/9501466.jpg" width="480" height="640" /></p>
98
+
99
+ <p>While they were in town this week for an opening at <a href="http://redflagg.com/">RedFlagg</a>, <a href="http://www.herakut.de/">Herakut</a> put up a wonderful piece outside <a href="http://eyebeam.org/">Eyebeam</a> If you haven't head about the show in New York, here's the info:</p>
100
+
101
+ <p>Herakut<br />
102
+ No Placebos<br />
103
+ May 21 – July 3, 2009</p>]]></description>
104
+ <link>http://feedproxy.google.com/~r/wooster/~3/rWAKvvkBDYY/herakut_beautifies_the_streets_of_new_yo.html</link>
105
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/herakut_beautifies_the_streets_of_new_yo.html</guid>
106
+ <category>Walls</category>
107
+ <pubDate>Fri, 22 May 2009 07:40:04 -0500</pubDate>
108
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/herakut_beautifies_the_streets_of_new_yo.html</feedburner:origLink>
109
+ </item>
110
+ <item>
111
+ <title>Fresh Stuff From Cena7</title>
112
+ <description><![CDATA[<p><a href="http://www.woostercollective.com/cenared.jpg"><img alt="cenared.jpg" src="http://www.woostercollective.com/cenared-thumb.jpg" width="500" height="409" /></a></p>
113
+
114
+ <p>More from Cena7 <a href="http://www.flickr.com/photos/cena7-mpc">here</a>. <br />
115
+ </p>]]></description>
116
+ <link>http://feedproxy.google.com/~r/wooster/~3/x4y4ZuKBadg/fresh_stuff_from_cena7_1.html</link>
117
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/fresh_stuff_from_cena7_1.html</guid>
118
+ <category>Walls</category>
119
+ <pubDate>Fri, 22 May 2009 07:37:33 -0500</pubDate>
120
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/fresh_stuff_from_cena7_1.html</feedburner:origLink>
121
+ </item>
122
+ <item>
123
+ <title>Wooster on Facebook</title>
124
+ <description><![CDATA[<p><img alt="woostfaceo.jpg" src="http://www.woostercollective.com/woostfaceo.jpg" width="500" height="376" /></p>
125
+
126
+ <p>Each and every day we get more excited about the discussions that are taking place on our <a href="http://www.facebook.com/pages/Wooster-Collective/24080260389?ref=ts#/pages/Wooster-Collective/24080260389?ref=mf">Wooster Collective Facebook page</a>. The responses to our recent questions:</p>
127
+
128
+ <p>For those who risk getting arrested while putting up street art or writing graffiti: What motivates you to do it?</p>
129
+
130
+ <p>What's currently inspiring you?</p>
131
+
132
+ <p>How would you describe the "role" that graffiti or street art plays in your life? What does it "add" or subtract?</p>
133
+
134
+ <p>If I gave you $50 today, with the condition that you had to spend it on "art", what would you do with it?</p>
135
+
136
+ <p>If you haven't yet checked it out we can't recommend it more highly. It's become an incredible companion to the Wooster blog. </p>
137
+
138
+ <p>Also, we are indeed on Twitter. Not as "Wooster Collective" but as <a href="http://www.twitter.com/MarcSchil">Marc</a> and <a href="http://www.twitter.com/saraschiller">Sara</a>. </p>]]></description>
139
+ <link>http://feedproxy.google.com/~r/wooster/~3/4uAvR5rZn80/wooster_on_facebook.html</link>
140
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/wooster_on_facebook.html</guid>
141
+ <category>Site Announcements</category>
142
+ <pubDate>Thu, 21 May 2009 08:05:18 -0500</pubDate>
143
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/wooster_on_facebook.html</feedburner:origLink>
144
+ </item>
145
+ <item>
146
+ <title>Wooster on Facebook</title>
147
+ <description><![CDATA[<p><img alt="woostfaceo.jpg" src="http://www.woostercollective.com/woostfaceo.jpg" width="500" height="376" /></p>
148
+
149
+ <p>Each and every day we get more excited about the discussions that are taking place on our <a href="http://www.facebook.com/pages/Wooster-Collective/24080260389?ref=ts#/pages/Wooster-Collective/24080260389?ref=mf">Wooster Collective Facebook page</a>. The responses to our recent questions:</p>
150
+
151
+ <p>For those who risk getting arrested while putting up street art or writing graffiti: What motivates you to do it?</p>
152
+
153
+ <p>What's currently inspiring you?</p>
154
+
155
+ <p>How would you describe the "role" that graffiti or street art plays in your life? What does it "add" or subtract?</p>
156
+
157
+ <p>If I gave you $50 today, with the condition that you had to spend it on "art", what would you do with it?</p>
158
+
159
+ <p>If you haven't yet checked it out we can't recommend it more highly. It's become an incredible companion to the Wooster blog. </p>
160
+
161
+ <p>Also, we are indeed on Twitter. Not as "Wooster Collective" but as <a href="http://www.twitter.com/MarcSchil">Marc</a> and <a href="http://www.twitter.com/saraschiller">Sara</a>. </p>]]></description>
162
+ <link>http://feedproxy.google.com/~r/wooster/~3/CV9qfY3WZqM/wooster_on_facebook_1.html</link>
163
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/wooster_on_facebook_1.html</guid>
164
+ <category>Site Announcements</category>
165
+ <pubDate>Thu, 21 May 2009 08:05:18 -0500</pubDate>
166
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/wooster_on_facebook_1.html</feedburner:origLink>
167
+ </item>
168
+ <item>
169
+ <title>Seen On The Steets Of Berlin</title>
170
+ <description><![CDATA[<p><a href="http://www.woostercollective.com/brownpaper1.jpg"><img alt="brownpaper1.jpg" src="http://www.woostercollective.com/brownpaper1-thumb.jpg" width="500" height="416" /></a><br />
171
+ </p>]]></description>
172
+ <link>http://feedproxy.google.com/~r/wooster/~3/O-9kaseEs8I/seen_on_the_steets_of_berlin_1.html</link>
173
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/seen_on_the_steets_of_berlin_1.html</guid>
174
+ <category>Wheatpastes</category>
175
+ <pubDate>Thu, 21 May 2009 07:57:05 -0500</pubDate>
176
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/seen_on_the_steets_of_berlin_1.html</feedburner:origLink>
177
+ </item>
178
+ <item>
179
+ <title>Checkin' In With... Lister</title>
180
+ <description><![CDATA[<p><a href="http://www.woostercollective.com/listcheck.jpg"><img alt="listcheck.jpg" src="http://www.woostercollective.com/listcheck-thumb.jpg" width="500" height="342" /></a></p>
181
+
182
+ <p>"out onto this roof the other night. i wasnt even sure that i had finished this piece but when i returned the next day i was surprised that it looked like this. the wall was so big and high that i couldn't step back at all. i am still surprised the proportions were correct."... <a href="http://www.anthonylister.com">Lister</a></p>]]></description>
183
+ <link>http://feedproxy.google.com/~r/wooster/~3/xKfEO6qRHLY/checkin_in_with_lister.html</link>
184
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/checkin_in_with_lister.html</guid>
185
+ <category>Walls</category>
186
+ <pubDate>Thu, 21 May 2009 07:45:54 -0500</pubDate>
187
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/checkin_in_with_lister.html</feedburner:origLink>
188
+ </item>
189
+ <item>
190
+ <title>Another Great Electronic Billboard Takeover From Poster Child</title>
191
+ <description><![CDATA[<p><a href="http://www.woostercollective.com/pixeljes.jpg"><img alt="pixeljes.jpg" src="http://www.woostercollective.com/pixeljes-thumb.jpg" width="500" height="375" /></a></p>
192
+
193
+ <div><object width="480" height="381"><param name="movie" value="http://www.dailymotion.com/swf/x99ave_stained-glass-postpixelators_creation&related=1"></param><param name="allowFullScreen" value="true"></param><param name="allowScriptAccess" value="always"></param><embed src="http://www.dailymotion.com/swf/x99ave_stained-glass-postpixelators_creation&related=1" type="application/x-shockwave-flash" width="480" height="381" allowFullScreen="true" allowScriptAccess="always"></embed></object><br /><b><a href="http://www.dailymotion.com/video/x99ave_stained-glass-postpixelators_creation">Stained Glass Post-Pixelators</a></b><br /><i>Uploaded by <a href="http://www.dailymotion.com/posterchild">posterchild</a>. - <a href="http://www.dailymotion.com/channel/creation">Independent web videos.</a></i></div>
194
+
195
+ <p>More from Poster Child <a href="http://www.bladediary.com/">here</a>. </p>]]></description>
196
+ <link>http://feedproxy.google.com/~r/wooster/~3/Rz_yYr1lijQ/another_great_electronic_billboard_takeo.html</link>
197
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/another_great_electronic_billboard_takeo.html</guid>
198
+ <category>Billboard Liberations</category>
199
+ <pubDate>Wed, 20 May 2009 07:59:04 -0500</pubDate>
200
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/another_great_electronic_billboard_takeo.html</feedburner:origLink>
201
+ </item>
202
+ </channel>
203
+ </rss>
@@ -0,0 +1,215 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds2.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
3
+ <channel>
4
+ <title>Wooster Collective</title>
5
+ <link>http://www.woostercollective.com/</link>
6
+ <description />
7
+ <language>en</language>
8
+ <copyright>Copyright 2009</copyright>
9
+ <lastBuildDate>Mon, 25 May 2009 07:48:04 -0500</lastBuildDate>
10
+ <generator>http://www.sixapart.com/movabletype/?v=3.3</generator>
11
+ <docs>http://blogs.law.harvard.edu/tech/rss</docs>
12
+
13
+ <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="www.woostercollective.com/rss/index.xml" type="application/rss+xml" /><feedburner:emailServiceId>wooster</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item>
14
+ <title>Fresh Stuff From Davide Zucco (aka Rekal)</title>
15
+ <description><![CDATA[<p><a href="http://www.woostercollective.com/rekalmonkey.jpg"><img alt="rekalmonkey.jpg" src="http://www.woostercollective.com/rekalmonkey-thumb.jpg" width="500" height="589" /></a></p>
16
+
17
+ <p>From from Rekal<a href="http://www.rekal.org"> here</a>. </p>
18
+
19
+ <p></p>
20
+
21
+ <p></p>
22
+
23
+ <p><br />
24
+ </p>]]></description>
25
+ <link>http://feedproxy.google.com/~r/wooster/~3/rlRoUehLOSM/fresh_stuff_from_davide_zucco_aka_rekal_1.html</link>
26
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/fresh_stuff_from_davide_zucco_aka_rekal_1.html</guid>
27
+ <category>Art</category>
28
+ <pubDate>Mon, 25 May 2009 07:48:04 -0500</pubDate>
29
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/fresh_stuff_from_davide_zucco_aka_rekal_1.html</feedburner:origLink></item>
30
+ <item>
31
+ <title>Fresh Stuff From Sten and Lex</title>
32
+ <description><![CDATA[<p><a href="http://www.woostercollective.com/stenlexpope.jpg"><img alt="stenlexpope.jpg" src="http://www.woostercollective.com/stenlexpope-thumb.jpg" width="500" height="364" /></a></p>
33
+
34
+ <p>Location: Palermo in Piazza Magione.<br />
35
+ Image: Pope Sergius, the first Pope born in Palermo</p>]]></description>
36
+ <link>http://feedproxy.google.com/~r/wooster/~3/RAHYCux58bs/fresh_stuff_from_sten_and_lex.html</link>
37
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/fresh_stuff_from_sten_and_lex.html</guid>
38
+ <category>Walls</category>
39
+ <pubDate>Mon, 25 May 2009 07:44:48 -0500</pubDate>
40
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/fresh_stuff_from_sten_and_lex.html</feedburner:origLink></item>
41
+ <item>
42
+ <title>Seen In North London: Department of Urban Censorship</title>
43
+ <description><![CDATA[<p><a href="http://www.woostercollective.com/urbancensor.jpg"><img alt="urbancensor.jpg" src="http://www.woostercollective.com/urbancensor-thumb.jpg" width="500" height="444" /></a></p>
44
+
45
+ <p>(Thanks, <a href="http://www.tupajumi.com/jonathan/">Jonathan</a>)<br />
46
+ </p>]]></description>
47
+ <link>http://feedproxy.google.com/~r/wooster/~3/syiP17t0PKo/seen_in_north_london_department_of_urban.html</link>
48
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/seen_in_north_london_department_of_urban.html</guid>
49
+ <category>Wheatpastes</category>
50
+ <pubDate>Mon, 25 May 2009 07:39:16 -0500</pubDate>
51
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/seen_in_north_london_department_of_urban.html</feedburner:origLink></item>
52
+ <item>
53
+ <title>Seen On The Steets Of Stockholm</title>
54
+ <description><![CDATA[<p><a href="http://www.woostercollective.com/poststock.jpg"><img alt="poststock.jpg" src="http://www.woostercollective.com/poststock-thumb.jpg" width="500" height="748" /></a></p>
55
+
56
+ <p>Artist: <a href="http://vimeo.com/post">Post</a></p>]]></description>
57
+ <link>http://feedproxy.google.com/~r/wooster/~3/611KGRn-ZQE/seen_on_the_steets_of_stockholm.html</link>
58
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/seen_on_the_steets_of_stockholm.html</guid>
59
+ <category>Wheatpastes</category>
60
+ <pubDate>Mon, 25 May 2009 07:29:55 -0500</pubDate>
61
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/seen_on_the_steets_of_stockholm.html</feedburner:origLink></item>
62
+ <item>
63
+ <title>Zevs' Electric Rainbows (2007)</title>
64
+ <description><![CDATA[<p>Zevs has updated <a href="http://www.gzzglz.com/">his website</a> with photos of past and recent project. We love the Electric Rainbows that he exchanged for advertisements back 2007:</p>
65
+
66
+ <p><a href="http://www.woostercollective.com/electric-rainbow-02.jpg"><img alt="electric-rainbow-02.jpg" src="http://www.woostercollective.com/electric-rainbow-02-thumb.jpg" width="500" height="335" /></a></p>
67
+
68
+ <p><br />
69
+ </p>]]></description>
70
+ <link>http://feedproxy.google.com/~r/wooster/~3/TpmlTS7y0f0/zevs_electric_rainbows_2007.html</link>
71
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/zevs_electric_rainbows_2007.html</guid>
72
+ <category>Art</category>
73
+ <pubDate>Mon, 25 May 2009 07:19:27 -0500</pubDate>
74
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/zevs_electric_rainbows_2007.html</feedburner:origLink></item>
75
+ <item>
76
+ <title>Zephyr - An Introduction</title>
77
+ <description><![CDATA[<p><a href="http://www.woostercollective.com/zephydith.jpg"><img alt="zephydith.jpg" src="http://www.woostercollective.com/zephydith-thumb.jpg" width="500" height="347" /></a></p>
78
+
79
+ <p><object width="320" height="265"><param name="movie" value="http://www.youtube.com/v/kqXXZcy-2JU&hl=en&fs=1&rel=0&hd=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/kqXXZcy-2JU&hl=en&fs=1&rel=0&hd=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="320" height="265"></embed></object></p>
80
+
81
+ <p>One of the first graffiti artists to "accept" Sara and I back in 2000 when we started the Wooster Collective was Zephyr. This week <a href="http://www.upperplayground.com/">Upper Playground</a> posted a terrific interview with Zephyr filmed a few years ago for their Dithers DVD. </p>]]></description>
82
+ <link>http://feedproxy.google.com/~r/wooster/~3/32-ED1oPdYY/zephyr_in_introduction.html</link>
83
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/zephyr_in_introduction.html</guid>
84
+ <category>Graffiti</category>
85
+ <pubDate>Sat, 23 May 2009 12:44:36 -0500</pubDate>
86
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/zephyr_in_introduction.html</feedburner:origLink></item>
87
+ <item>
88
+ <title>The Yes Men - An Introduction</title>
89
+ <description><![CDATA[<div><object width="512" height="322"><param name="movie" value="http://d.yimg.com/static.video.yahoo.com/yep/YV_YEP.swf?ver=2.2.40" /><param name="allowFullScreen" value="true" /><param name="AllowScriptAccess" VALUE="always" /><param name="bgcolor" value="#000000" /><param name="flashVars" value="id=13527850&vid=13527850&lang=en-us&intl=us&thumbUrl=&embed=1" /><embed src="http://d.yimg.com/static.video.yahoo.com/yep/YV_YEP.swf?ver=2.2.40" type="application/x-shockwave-flash" width="512" height="322" allowFullScreen="true" AllowScriptAccess="always" bgcolor="#000000" flashVars="id=13527850&vid=13527850&lang=en-us&intl=us&thumbUrl=&embed=1" ></embed></object><br /><a href="http://video.yahoo.com/watch/13527850/13527850"></a> @ <a href="http://video.yahoo.com" >Yahoo! Video</a></div>
90
+
91
+ <p>If you're not familiar with <a href="http://theyesmen.org/">The Yes Men</a>, this video of their Poptech speech from 2006 is a fantastic introduction.</p>
92
+
93
+ <p>(Hat tip to <a href="http://www.brainpickings.org/">Brain Pickings</a>)</p>]]></description>
94
+ <link>http://feedproxy.google.com/~r/wooster/~3/0yXb4Ui8C3I/the_yes_men_an_introduction.html</link>
95
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/the_yes_men_an_introduction.html</guid>
96
+ <category>Activism</category>
97
+ <pubDate>Fri, 22 May 2009 11:24:26 -0500</pubDate>
98
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/the_yes_men_an_introduction.html</feedburner:origLink></item>
99
+ <item>
100
+ <title>A Great Example Of Site Specific Work: Carlsbad Sidewalk Surfer</title>
101
+ <description><![CDATA[<p><img alt="bryansurfer.jpg" src="http://www.woostercollective.com/bryansurfer.jpg" width="500" height="384" /></p>
102
+
103
+ <p><object width="400" height="307"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=4772503&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=4772503&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="307"></embed></object><p><a href="http://vimeo.com/4772503">Carlsbad Sidewalk Surfer by bryan snyder</a> from <a href="http://vimeo.com/bryansnyder">Bryan Snyder</a> on <a href="http://vimeo.com">Vimeo</a>.</p></p>
104
+
105
+ <p>From <a href="http://www.snyderartdesign.com">Bryan</a>:</p>
106
+
107
+ <p>Carlsbad Sidewalk Surfer interacts with its environment during mid day wind gusts. Like the waves that tumble upon our shore, the visibility of this art piece depends on the weather. Between the glassy conditions of the morning and the mellow winds at dusk, the Carlsbad Sidewalk Surfer sneaks into another ride. The goal of this project is to showcase the relationship between a piece of art and its environment when placed in the streets."</p>]]></description>
108
+ <link>http://feedproxy.google.com/~r/wooster/~3/oXfLFSd86cY/a_great_example_of_site_specific_work_ca.html</link>
109
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/a_great_example_of_site_specific_work_ca.html</guid>
110
+ <category>Environmental</category>
111
+ <pubDate>Fri, 22 May 2009 07:54:36 -0500</pubDate>
112
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/a_great_example_of_site_specific_work_ca.html</feedburner:origLink></item>
113
+ <item>
114
+ <title>Herakut Beautifies The Streets Of New York</title>
115
+ <description><![CDATA[<p><img alt="9501466.jpg" src="http://www.woostercollective.com/9501466.jpg" width="480" height="640" /></p>
116
+
117
+ <p>While they were in town this week for an opening at <a href="http://redflagg.com/">RedFlagg</a>, <a href="http://www.herakut.de/">Herakut</a> put up a wonderful piece outside <a href="http://eyebeam.org/">Eyebeam</a> If you haven't head about the show in New York, here's the info:</p>
118
+
119
+ <p>Herakut<br />
120
+ No Placebos<br />
121
+ May 21 – July 3, 2009</p>]]></description>
122
+ <link>http://feedproxy.google.com/~r/wooster/~3/rWAKvvkBDYY/herakut_beautifies_the_streets_of_new_yo.html</link>
123
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/herakut_beautifies_the_streets_of_new_yo.html</guid>
124
+ <category>Walls</category>
125
+ <pubDate>Fri, 22 May 2009 07:40:04 -0500</pubDate>
126
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/herakut_beautifies_the_streets_of_new_yo.html</feedburner:origLink></item>
127
+ <item>
128
+ <title>Fresh Stuff From Cena7</title>
129
+ <description><![CDATA[<p><a href="http://www.woostercollective.com/cenared.jpg"><img alt="cenared.jpg" src="http://www.woostercollective.com/cenared-thumb.jpg" width="500" height="409" /></a></p>
130
+
131
+ <p>More from Cena7 <a href="http://www.flickr.com/photos/cena7-mpc">here</a>. <br />
132
+ </p>]]></description>
133
+ <link>http://feedproxy.google.com/~r/wooster/~3/x4y4ZuKBadg/fresh_stuff_from_cena7_1.html</link>
134
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/fresh_stuff_from_cena7_1.html</guid>
135
+ <category>Walls</category>
136
+ <pubDate>Fri, 22 May 2009 07:37:33 -0500</pubDate>
137
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/fresh_stuff_from_cena7_1.html</feedburner:origLink></item>
138
+ <item>
139
+ <title>Wooster on Facebook</title>
140
+ <description><![CDATA[<p><img alt="woostfaceo.jpg" src="http://www.woostercollective.com/woostfaceo.jpg" width="500" height="376" /></p>
141
+
142
+ <p>Each and every day we get more excited about the discussions that are taking place on our <a href="http://www.facebook.com/pages/Wooster-Collective/24080260389?ref=ts#/pages/Wooster-Collective/24080260389?ref=mf">Wooster Collective Facebook page</a>. The responses to our recent questions:</p>
143
+
144
+ <p>For those who risk getting arrested while putting up street art or writing graffiti: What motivates you to do it?</p>
145
+
146
+ <p>What's currently inspiring you?</p>
147
+
148
+ <p>How would you describe the "role" that graffiti or street art plays in your life? What does it "add" or subtract?</p>
149
+
150
+ <p>If I gave you $50 today, with the condition that you had to spend it on "art", what would you do with it?</p>
151
+
152
+ <p>If you haven't yet checked it out we can't recommend it more highly. It's become an incredible companion to the Wooster blog. </p>
153
+
154
+ <p>Also, we are indeed on Twitter. Not as "Wooster Collective" but as <a href="http://www.twitter.com/MarcSchil">Marc</a> and <a href="http://www.twitter.com/saraschiller">Sara</a>. </p>]]></description>
155
+ <link>http://feedproxy.google.com/~r/wooster/~3/4uAvR5rZn80/wooster_on_facebook.html</link>
156
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/wooster_on_facebook.html</guid>
157
+ <category>Site Announcements</category>
158
+ <pubDate>Thu, 21 May 2009 08:05:18 -0500</pubDate>
159
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/wooster_on_facebook.html</feedburner:origLink></item>
160
+ <item>
161
+ <title>Wooster on Facebook</title>
162
+ <description><![CDATA[<p><img alt="woostfaceo.jpg" src="http://www.woostercollective.com/woostfaceo.jpg" width="500" height="376" /></p>
163
+
164
+ <p>Each and every day we get more excited about the discussions that are taking place on our <a href="http://www.facebook.com/pages/Wooster-Collective/24080260389?ref=ts#/pages/Wooster-Collective/24080260389?ref=mf">Wooster Collective Facebook page</a>. The responses to our recent questions:</p>
165
+
166
+ <p>For those who risk getting arrested while putting up street art or writing graffiti: What motivates you to do it?</p>
167
+
168
+ <p>What's currently inspiring you?</p>
169
+
170
+ <p>How would you describe the "role" that graffiti or street art plays in your life? What does it "add" or subtract?</p>
171
+
172
+ <p>If I gave you $50 today, with the condition that you had to spend it on "art", what would you do with it?</p>
173
+
174
+ <p>If you haven't yet checked it out we can't recommend it more highly. It's become an incredible companion to the Wooster blog. </p>
175
+
176
+ <p>Also, we are indeed on Twitter. Not as "Wooster Collective" but as <a href="http://www.twitter.com/MarcSchil">Marc</a> and <a href="http://www.twitter.com/saraschiller">Sara</a>. </p>]]></description>
177
+ <link>http://feedproxy.google.com/~r/wooster/~3/CV9qfY3WZqM/wooster_on_facebook_1.html</link>
178
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/wooster_on_facebook_1.html</guid>
179
+ <category>Site Announcements</category>
180
+ <pubDate>Thu, 21 May 2009 08:05:18 -0500</pubDate>
181
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/wooster_on_facebook_1.html</feedburner:origLink></item>
182
+ <item>
183
+ <title>Seen On The Steets Of Berlin</title>
184
+ <description><![CDATA[<p><a href="http://www.woostercollective.com/brownpaper1.jpg"><img alt="brownpaper1.jpg" src="http://www.woostercollective.com/brownpaper1-thumb.jpg" width="500" height="416" /></a><br />
185
+ </p>]]></description>
186
+ <link>http://feedproxy.google.com/~r/wooster/~3/O-9kaseEs8I/seen_on_the_steets_of_berlin_1.html</link>
187
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/seen_on_the_steets_of_berlin_1.html</guid>
188
+ <category>Wheatpastes</category>
189
+ <pubDate>Thu, 21 May 2009 07:57:05 -0500</pubDate>
190
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/seen_on_the_steets_of_berlin_1.html</feedburner:origLink></item>
191
+ <item>
192
+ <title>Checkin' In With... Lister</title>
193
+ <description><![CDATA[<p><a href="http://www.woostercollective.com/listcheck.jpg"><img alt="listcheck.jpg" src="http://www.woostercollective.com/listcheck-thumb.jpg" width="500" height="342" /></a></p>
194
+
195
+ <p>"out onto this roof the other night. i wasnt even sure that i had finished this piece but when i returned the next day i was surprised that it looked like this. the wall was so big and high that i couldn't step back at all. i am still surprised the proportions were correct."... <a href="http://www.anthonylister.com">Lister</a></p>]]></description>
196
+ <link>http://feedproxy.google.com/~r/wooster/~3/xKfEO6qRHLY/checkin_in_with_lister.html</link>
197
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/checkin_in_with_lister.html</guid>
198
+ <category>Walls</category>
199
+ <pubDate>Thu, 21 May 2009 07:45:54 -0500</pubDate>
200
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/checkin_in_with_lister.html</feedburner:origLink></item>
201
+ <item>
202
+ <title>Another Great Electronic Billboard Takeover From Poster Child</title>
203
+ <description><![CDATA[<p><a href="http://www.woostercollective.com/pixeljes.jpg"><img alt="pixeljes.jpg" src="http://www.woostercollective.com/pixeljes-thumb.jpg" width="500" height="375" /></a></p>
204
+
205
+ <div><object width="480" height="381"><param name="movie" value="http://www.dailymotion.com/swf/x99ave_stained-glass-postpixelators_creation&related=1"></param><param name="allowFullScreen" value="true"></param><param name="allowScriptAccess" value="always"></param><embed src="http://www.dailymotion.com/swf/x99ave_stained-glass-postpixelators_creation&related=1" type="application/x-shockwave-flash" width="480" height="381" allowFullScreen="true" allowScriptAccess="always"></embed></object><br /><b><a href="http://www.dailymotion.com/video/x99ave_stained-glass-postpixelators_creation">Stained Glass Post-Pixelators</a></b><br /><i>Uploaded by <a href="http://www.dailymotion.com/posterchild">posterchild</a>. - <a href="http://www.dailymotion.com/channel/creation">Independent web videos.</a></i></div>
206
+
207
+ <p>More from Poster Child <a href="http://www.bladediary.com/">here</a>. </p>]]></description>
208
+ <link>http://feedproxy.google.com/~r/wooster/~3/Rz_yYr1lijQ/another_great_electronic_billboard_takeo.html</link>
209
+ <guid isPermaLink="false">http://www.woostercollective.com/2009/05/another_great_electronic_billboard_takeo.html</guid>
210
+ <category>Billboard Liberations</category>
211
+ <pubDate>Wed, 20 May 2009 07:59:04 -0500</pubDate>
212
+ <feedburner:origLink>http://www.woostercollective.com/2009/05/another_great_electronic_billboard_takeo.html</feedburner:origLink></item>
213
+
214
+ </channel>
215
+ </rss>
@@ -0,0 +1,90 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. spec_helper])
2
+
3
+ describe Myzofeedtosis::Client do
4
+ before do
5
+ @url = "http://www.example.com/feed.rss"
6
+ @opts = { :user_agent => "My Cool Application" }
7
+ @fr = Myzofeedtosis::Client.new(@url, @opts)
8
+ end
9
+
10
+ describe "initialization" do
11
+ it "should set #url to an Array when an Array is given" do
12
+ @fr.url.should == @url
13
+ end
14
+
15
+ it "should set #options to the options hash given at end of list" do
16
+ @fr.options.should == Myzofeedtosis::Client::DEFAULTS.merge(@opts)
17
+ end
18
+
19
+ it "should set the If-None-Match and If-Modified-Since headers to the value of the summary hash" do
20
+ curl_headers = mock('headers')
21
+ curl_headers.expects(:[]=).with('If-None-Match', '42ab')
22
+ curl_headers.expects(:[]=).with('If-Modified-Since', 'Mon, 25 May 2009 16:38:49 GMT')
23
+
24
+ summary = { :etag => '42ab', :last_modified => 'Mon, 25 May 2009 16:38:49 GMT' }
25
+
26
+ @fr.__send__(:set_summary, summary)
27
+
28
+ curl_easy = mock('curl', :perform => true, :follow_location= => true,
29
+ :response_code => 200, :body_str => xml_fixture('wooster'),
30
+ :header_str => http_header('wooster')
31
+ )
32
+
33
+ curl_easy.expects(:headers).returns(curl_headers).times(2)
34
+
35
+ @fr.expects(:new_curl_easy).returns(curl_easy)
36
+ @fr.fetch
37
+ end
38
+ end
39
+
40
+ describe "#fetch" do
41
+ it "should call Curl::Easy.perform with the url, and #process_curl_response" do
42
+ curl_easy = mock('curl', :perform => true)
43
+ @fr.expects(:build_curl_easy).returns(curl_easy)
44
+ @fr.expects(:process_curl_response)
45
+ @fr.fetch
46
+ end
47
+
48
+ describe "when the response code is not 200" do
49
+ it "should return the Curl::Easy object" do
50
+ curl = mock('curl', :perform => true, :response_code => 304)
51
+ @fr.expects(:build_curl_easy).returns(curl)
52
+ @fr.fetch.should == curl
53
+ end
54
+ end
55
+
56
+ describe "when the response code is 200" do
57
+ describe "when an identical resource has been retrieved previously" do
58
+ before do
59
+ curl = mock('curl', :perform => true, :response_code => 200,
60
+ :body_str => xml_fixture('wooster'), :header_str => http_header('wooster'))
61
+ @fr.expects(:build_curl_easy).returns(curl)
62
+ @fr.fetch
63
+ end
64
+
65
+ it "should have an empty array for new_entries" do
66
+ curl = mock('curl', :perform => true, :response_code => 200,
67
+ :body_str => xml_fixture('wooster'), :header_str => http_header('wooster'))
68
+ @fr.expects(:build_curl_easy).returns(curl)
69
+ @fr.fetch.new_entries.should == []
70
+ end
71
+ end
72
+
73
+ describe "when the resource has been previously retrieved minus two entries" do
74
+ before do
75
+ curl = mock('curl', :perform => true, :response_code => 200,
76
+ :body_str => xml_fixture('older_wooster'), :header_str => http_header('wooster'))
77
+ @fr.expects(:build_curl_easy).returns(curl)
78
+ @fr.fetch
79
+ end
80
+
81
+ it "should have two elements in new_entries" do
82
+ curl = mock('curl', :perform => true, :response_code => 200,
83
+ :body_str => xml_fixture('wooster'), :header_str => http_header('wooster'))
84
+ @fr.expects(:build_curl_easy).returns(curl)
85
+ @fr.fetch.new_entries.size.should == 2
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,5 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Myzofeedtosis do
4
+
5
+ end
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'mocha'
3
+ require 'spec'
4
+
5
+ require File.join(File.dirname(__FILE__), %w[.. lib myzofeedtosis])
6
+
7
+ Spec::Runner.configure do |config|
8
+ config.mock_with(:mocha)
9
+ end
10
+
11
+ # Returns the xml fixture identified by +name+.
12
+ def xml_fixture(name)
13
+ File.read(File.join(File.dirname(__FILE__), 'fixtures', 'xml', "#{name}.xml"))
14
+ end
15
+
16
+ def http_header(name)
17
+ File.read(File.join(File.dirname(__FILE__), 'fixtures', 'http_headers', "#{name}.txt"))
18
+ end
19
+
20
+ shared_examples_for "all backends" do
21
+ it "should respond to #get" do
22
+ @backend.should respond_to(:get)
23
+ end
24
+
25
+ it "should respond to #set" do
26
+ @backend.should respond_to(:set)
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jsl-myzofeedtosis
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Justin Leitgeb
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-22 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: taf2-curb
17
+ type: :runtime
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: wycats-moneta
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: jsl-hashback
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: jsl-http_headers
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: feed-normalizer
57
+ type: :runtime
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ description: Myzofeedtosis finds new information in feeds quickly using smart fetching and matching of previously read entries
66
+ email: justin@phq.org
67
+ executables: []
68
+
69
+ extensions: []
70
+
71
+ extra_rdoc_files:
72
+ - README.rdoc
73
+ files:
74
+ - lib/extensions/core/array.rb
75
+ - lib/extensions/core/hash.rb
76
+ - lib/extensions/feed_normalizer/feed_instance_methods.rb
77
+ - lib/myzofeedtosis/client.rb
78
+ - lib/myzofeedtosis.rb
79
+ - LICENSE
80
+ - myzofeedtosis.gemspec
81
+ - Rakefile
82
+ - README.rdoc
83
+ - spec/extensions/feed_normalizer/feed_instance_methods_spec.rb
84
+ - spec/fixtures/http_headers/wooster.txt
85
+ - spec/fixtures/xml/older_wooster.xml
86
+ - spec/fixtures/xml/wooster.xml
87
+ - spec/myzofeedtosis/client_spec.rb
88
+ - spec/myzofeedtosis_spec.rb
89
+ - spec/spec_helper.rb
90
+ has_rdoc: true
91
+ homepage: http://github.com/jsl/myzofeedtosis
92
+ post_install_message:
93
+ rdoc_options:
94
+ - --charset=UTF-8
95
+ - --title
96
+ - Myzofeedtosis
97
+ - --main
98
+ - README.rdoc
99
+ - --line-numbers
100
+ - --inline-source
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: "0"
108
+ version:
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: "0"
114
+ version:
115
+ requirements: []
116
+
117
+ rubyforge_project:
118
+ rubygems_version: 1.2.0
119
+ signing_key:
120
+ specification_version: 2
121
+ summary: Retrieves feeds using conditional GET and marks entries that you haven't seen before
122
+ test_files:
123
+ - spec/myzofeedtosis_spec.rb
124
+ - spec/spec_helper.rb
125
+ - spec/myzofeedtosis/client_spec.rb