earl 0.3.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.document +5 -0
  2. data/.gitignore +4 -15
  3. data/.rspec +1 -0
  4. data/.travis.yml +11 -0
  5. data/Gemfile +2 -2
  6. data/Gemfile.lock +60 -0
  7. data/Guardfile +10 -0
  8. data/LICENSE +2 -4
  9. data/README.rdoc +145 -0
  10. data/Rakefile +35 -2
  11. data/earl.gemspec +13 -7
  12. data/lib/earl.rb +7 -22
  13. data/lib/earl/earl.rb +158 -0
  14. data/lib/earl/scraper.rb +93 -0
  15. data/lib/earl/version.rb +2 -2
  16. data/script/console +10 -0
  17. data/spec/fixtures/bicycles.html +490 -0
  18. data/spec/fixtures/bicycles_without_description.html +489 -0
  19. data/spec/fixtures/bicycles_without_images.html +457 -0
  20. data/spec/fixtures/page_as_atom.html +161 -0
  21. data/spec/fixtures/page_as_rss.html +151 -0
  22. data/spec/fixtures/page_with_atom_feed.html +39 -0
  23. data/spec/fixtures/page_with_rss_and_atom_feeds.html +40 -0
  24. data/spec/fixtures/page_with_rss_feed.html +39 -0
  25. data/spec/fixtures/page_without_feeds.html +36 -0
  26. data/spec/fixtures/youtube.html +1839 -0
  27. data/spec/integration/feed_spec.rb +78 -0
  28. data/spec/integration/oembed_spec.rb +40 -0
  29. data/spec/spec_helper.rb +18 -28
  30. data/spec/support/fixtures.rb +10 -0
  31. data/spec/unit/earl/earl_spec.rb +16 -0
  32. data/spec/unit/earl/feed_spec.rb +59 -0
  33. data/spec/unit/earl/oembed_spec.rb +49 -0
  34. data/spec/unit/earl/scraper_spec.rb +48 -0
  35. data/spec/unit/earl_spec.rb +65 -0
  36. metadata +123 -46
  37. data/.rvmrc +0 -48
  38. data/README.md +0 -41
  39. data/lib/earl/email_assembler.rb +0 -11
  40. data/lib/earl/email_entity.rb +0 -27
  41. data/lib/earl/email_parser.tt +0 -58
  42. data/lib/earl/entity_base.rb +0 -37
  43. data/lib/earl/hash_inquirer.rb +0 -16
  44. data/lib/earl/string_inquirer.rb +0 -11
  45. data/lib/earl/url_assembler.rb +0 -15
  46. data/lib/earl/url_entity.rb +0 -23
  47. data/lib/earl/url_parser.tt +0 -163
  48. data/spec/earl/earl_spec.rb +0 -17
  49. data/spec/earl/email_entity_spec.rb +0 -31
  50. data/spec/earl/email_parser_spec.rb +0 -29
  51. data/spec/earl/entity_base_spec.rb +0 -39
  52. data/spec/earl/hash_inquirer_spec.rb +0 -24
  53. data/spec/earl/string_inquirer_spec.rb +0 -9
  54. data/spec/earl/url_entity_spec.rb +0 -45
  55. data/spec/earl/url_parser_spec.rb +0 -189
@@ -0,0 +1,93 @@
1
+ class Earl::Scraper
2
+
3
+ class << self
4
+ @@registry = []
5
+ attr_reader :regexp
6
+ attr_reader :attributes
7
+
8
+ def match(regexp)
9
+ @regexp = regexp
10
+ register self
11
+ end
12
+
13
+ def define_attribute(name, &block)
14
+ @attributes ||= {}
15
+ @attributes[name] = block
16
+ end
17
+
18
+ def for(url, earl_source)
19
+ @@registry.each do |klass|
20
+ return klass.new(url,earl_source) if klass.regexp.match(url)
21
+ end
22
+ return Earl::Scraper.new(url,earl_source)
23
+ end
24
+
25
+ private
26
+
27
+ def register(scraper_klass)
28
+ @@registry << scraper_klass
29
+ end
30
+
31
+ end
32
+
33
+ attr_reader :earl_source
34
+
35
+ def initialize(url, earl_source = nil)
36
+ @url = url
37
+ @earl_source = earl_source
38
+ end
39
+
40
+ def response
41
+ @response ||= earl_source && Nokogiri::HTML(earl_source.uri_response)
42
+ end
43
+
44
+ def attribute(name)
45
+ return unless has_attribute?(name)
46
+ self.attributes[name].call(response)
47
+ end
48
+
49
+ def attributes
50
+ if self.class.superclass == Earl::Scraper
51
+ self.class.superclass.attributes.merge(self.class.attributes)
52
+ else
53
+ self.class.attributes
54
+ end
55
+ end
56
+
57
+ def has_attribute?(name)
58
+ return false unless self.class.attributes
59
+ self.attributes.has_key?(name)
60
+ end
61
+
62
+ define_attribute :title do |doc|
63
+ if title = doc.at('title')
64
+ title.content
65
+ end
66
+ end
67
+
68
+ define_attribute :image do |doc|
69
+ if first_image = doc.at('img')
70
+ first_image['src']
71
+ end
72
+ end
73
+
74
+ define_attribute :description do |doc|
75
+ if element = doc.at("meta[name='description']")
76
+ element['content']
77
+ end
78
+ end
79
+
80
+ define_attribute :rss_feed do |doc|
81
+ if element = doc.at("link[type='application/rss+xml']")
82
+ element['href']
83
+ end
84
+ end
85
+
86
+ define_attribute :atom_feed do |doc|
87
+ if element = doc.at("link[type='application/atom+xml']")
88
+ element['href']
89
+ end
90
+ end
91
+
92
+ end
93
+
@@ -1,3 +1,3 @@
1
- module Earl
2
- VERSION = '0.3.0'
1
+ class Earl
2
+ VERSION = "1.0.0"
3
3
  end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/earl.rb'}"
9
+ puts "Loading earl gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1,490 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+
5
+ <head>
6
+ <script type="text/javascript">
7
+ //<![CDATA[
8
+ var page={};var onCondition=function(D,C,A,B){D=D;A=A?Math.min(A,5):5;B=B||100;if(D()){C()}else{if(A>1){setTimeout(function(){onCondition(D,C,A-1,B)},B)}}};
9
+ //]]>
10
+ </script>
11
+ <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
12
+ <meta content="en-us" http-equiv="Content-Language" />
13
+ <meta content="I write business plans for a living and fiction to stay sane. I also try my hand at all sorts of creative side projects: painting, game dev, whiskey drinking.." name="description" />
14
+ <meta content="no" http-equiv="imagetoolbar" />
15
+ <meta content="width = 780" name="viewport" />
16
+ <meta content="4FTTxY4uvo0RZTMQqIyhh18HsepyJOctQ+XTOu1zsfE=" name="verify-v1" />
17
+ <meta content="1" name="page" />
18
+ <meta content="IE=7" http-equiv="X-UA-Compatible" />
19
+ <meta content="n" name="session-loggedin" />
20
+ <meta content="bicycles" name="page-user-screen_name" />
21
+ <title>bicycles (bicycles) on Twitter</title>
22
+ <link href="http://assets1.twitter.com/images/favicon.ico" rel="shortcut icon" type="image/x-icon" />
23
+ <link href="http://assets1.twitter.com/images/twitter_57.png" rel="apple-touch-icon" />
24
+ <link rel="alternate" href="/statuses/user_timeline/user_id.rss" title="bicycles's Updates" type="application/rss+xml" />
25
+ <link rel="alternate" href="/favorites/user_id.rss" title="bicycles's Favorites" type="application/rss+xml" />
26
+
27
+
28
+ <link href="http://assets3.twitter.com/stylesheets/timeline.css?1241136264" media="screen, projection" rel="stylesheet" type="text/css" />
29
+ <link href="http://assets1.twitter.com/stylesheets/master.css?1241136271" media="screen, projection" rel="stylesheet" type="text/css" />
30
+ <style type="text/css">
31
+ /* begin custom css */
32
+ .top-navigation > li > a,
33
+ a { color: #0000FF; }
34
+ body {
35
+ color: #000000;
36
+ background-color: #9AE4E8;
37
+ background: #9AE4E8 url(http://s3.amazonaws.com/twitter_production/profile_background_images/2837167/untitled.PNG) fixed no-repeat top left;}
38
+ #side_base {
39
+ border-left:1px solid #87BC44;
40
+ background-color: #E0FF92;
41
+ }
42
+ #side div.last { border-top: 1px solid #87BC44; }
43
+ ul#tabMenu li {
44
+ display: block; width: 100%;
45
+ border-top: 1px solid #87BC44;
46
+ }
47
+ ul#tabMenu li a, #side .section h1 { color:#000000; }
48
+ #content tr.hentry:hover a { color:#0000FF; }
49
+ body#profile #content div.hentry:hover a { color:#0000FF;}
50
+ #side .actions { border: 1px solid #87BC44; }
51
+
52
+ #side .promo {
53
+ border: 1px solid #87BC44;
54
+ }
55
+
56
+ #side .stat a {
57
+ color: #000000;
58
+ }
59
+
60
+ #side .stats a span.stats_count {
61
+ color: #000000;
62
+ }
63
+
64
+ #side .stats a:hover span.stats_count {
65
+ color: #0000FF;
66
+ }
67
+
68
+ #side div.section-header h1 { color: #000000; }
69
+ #side div.section-header h3.faq-header {
70
+ border-bottom: 1px solid #87BC44;
71
+ color: #000000;
72
+ }
73
+ #side .stat a {color: #000000; }
74
+
75
+
76
+ #side div.user_icon a, #side div.user_icon a:hover {
77
+ color: #000000;
78
+ }
79
+
80
+ #side div.user_icon a:hover {
81
+ color: #0000FF;
82
+ }
83
+
84
+ #side hr {
85
+ background: #87BC44;
86
+ color: #87BC44;
87
+ }
88
+ #side .notice {
89
+ border: 1px solid #87BC44;
90
+ }
91
+
92
+ #side .promotion .definition strong {
93
+ color: #0000FF;
94
+ }
95
+
96
+
97
+
98
+ ul.sidebar-menu li.loading a {
99
+ background: #F4FFA6 url('http://static.twitter.com/images/spinner.gif') no-repeat 171px 0.5em !important;
100
+ }
101
+
102
+ #side .collapsible h2.sidebar-title {
103
+ background: transparent url('http://static.twitter.com/images/toggle_up_dark.png') no-repeat center right !important;
104
+ }
105
+
106
+ #side .collapsible.collapsed h2.sidebar-title {
107
+ background: transparent url('http://static.twitter.com/images/toggle_down_dark.png') no-repeat center right !important;
108
+ }
109
+
110
+ ul.sidebar-menu li.active a {
111
+ font-weight: bold;
112
+ color: #000000;
113
+ background-color: #F4FFA6;
114
+ }
115
+
116
+ #side .promotion {
117
+ background-color: #F4FFA6;
118
+ }
119
+
120
+ #side .promotion a {
121
+ color: #000000;
122
+ }
123
+
124
+ #side .promotion .definition strong {
125
+ color: #0000FF;
126
+ }
127
+
128
+ #side div#custom_search.active {
129
+ background-color: #F4FFA6;
130
+ }
131
+
132
+ ul.sidebar-menu li:hover a {
133
+ text-decoration: none;
134
+ background-color: #F4FFA6;
135
+ }
136
+
137
+ #search div#custom_search.active {
138
+ background-color: #F4FFA6;
139
+ }
140
+
141
+
142
+ /* end custom css */
143
+
144
+
145
+ .content-bubble-arrow { background-image: url(http://static.twitter.com/images/arr2.gif); }
146
+ .status-btn input.round-btn { background-image: url('http://static.twitter.com/images/round-btn.gif'); }
147
+ .status-btn input.round-btn:hover { background-image: url('http://static.twitter.com/images/round-btn-hover.gif'); }
148
+ .status-btn input.disabled, .status-btn input.disabled:hover { background-image: url('http://static.twitter.com/images/round-btn.gif'); }
149
+ .hentry .actions .fav { background-image: url('http://static.twitter.com/images/icon_star_full.gif'); }
150
+ .hentry .actions .non-fav { background-image: url('http://static.twitter.com/images/icon_star_empty.gif'); }
151
+ .hentry .actions .fav-throb, .hentry .actions a.del-throb { background-image: url('http://static.twitter.com/images/icon_throbber.gif'); }
152
+ .hentry .actions .del { background-image: url('http://static.twitter.com/images/icon_trash.gif'); }
153
+ body#show .reply, .hentry .actions .reply { background-image: url('http://static.twitter.com/images/icon_reply.gif'); }
154
+ .direct_message .actions .reply { background-image: url('http://static.twitter.com/images/icon_direct_reply.gif'); }
155
+ .direct_message .actions .del { background-image: url('http://static.twitter.com/images/icon_trash.gif'); }
156
+ .notify { background-image: url('http://static.twitter.com/images/girl.gif'); }
157
+ ul#tabMenu a#keyword_search_tab.hover, ul#tabMenu a:hover { background-image: url('http://static.twitter.com/images/pale.png'); background-color: transparent; }
158
+ div#follow-toggle.closed { background-image: url('http://static.twitter.com/images/toggle_closed.gif'); }
159
+ div#follow-toggle.opened { background-image: url('http://static.twitter.com/images/toggle_opened.gif'); }
160
+ .follow-actions .following { background-image: url('http://static.twitter.com/images/checkmark.gif'); }
161
+ .more { background-image: url('http://static.twitter.com/images/more.gif'); }
162
+ .more.loading { background-image: url('http://static.twitter.com/images/ajax.gif'); }
163
+ body#show .protected { background-image: url('http://static.twitter.com/images/icon_lock.gif'); }
164
+ .rss { background-image: url('http://static.twitter.com/images/rss.gif'); }
165
+ .bulletin a.close { background: transparent url('http://static.twitter.com/images/close_small.png') no-repeat; }
166
+ #sidebar_search_submit { background: url('http://static.twitter.com/images/nav_search_submit.png') -2px 0px !important ; }
167
+ #sidebar_search_submit:hover { background: url('http://static.twitter.com/images/nav_search_submit.png') -2px -25px !important; }
168
+ #sidebar_search_submit:active { background: url('http://static.twitter.com/images/nav_search_submit.png') -2px -50px !important; }
169
+ #sidebar_search_submit.loading, #sidebar_search_submit.loading:hover, #sidebar_search_submit.loading:active { background: #eee url('http://static.twitter.com/images/spinner.gif') no-repeat 5px 5px !important; }
170
+
171
+ ul.sidebar-menu li.loading a {
172
+ background: #edffe5 url('http://static.twitter.com/images/spinner.gif') no-repeat 171px 0.5em;
173
+ }
174
+
175
+ #side .collapsible.loading h2.sidebar-title { background: transparent url('http://static.twitter.com/images/spinner.gif') no-repeat center right !important; }
176
+ #side .collapsible h2.sidebar-title {
177
+ background: transparent url('http://static.twitter.com/images/toggle_up_dark.png') no-repeat right center;
178
+ width: 157px;
179
+ }
180
+
181
+ #side .collapsible.collapsed h2.sidebar-title {
182
+ background: transparent url('http://static.twitter.com/images/toggle_down_dark.png') no-repeat right center;
183
+ }
184
+
185
+ .save-search-link {
186
+ background: transparent url('http://static.twitter.com/images/icon_add.png') no-repeat left bottom;
187
+ }
188
+
189
+ .delete-search-link {
190
+ background: transparent url('http://static.twitter.com/images/icon_remove.png') no-repeat left bottom;
191
+ }
192
+
193
+ #timeline_heading h1 span.loading {
194
+ background: transparent url('http://static.twitter.com/images/spinner.gif') no-repeat left bottom;
195
+ }
196
+
197
+
198
+ </style>
199
+
200
+ </head>
201
+
202
+ <body class="account" id="profile">
203
+ <div id="dim-screen"></div>
204
+ <ul id="accessibility" class="offscreen">
205
+ <li><a href="#content" accesskey="0">Skip past navigation</a></li>
206
+ <li>On a mobile phone? Check out <a href="http://m.twitter.com/">m.twitter.com</a>!</li>
207
+ <li><a href="#footer" accesskey="2">Skip to navigation</a></li>
208
+ <li><a href="#signin">Skip to sign in form</a></li>
209
+ </ul>
210
+
211
+
212
+
213
+ <div id="container" class="subpage">
214
+ <span id="loader" style="display:none"><img alt="Loader" src="http://assets0.twitter.com/images/loader.gif" /></span>
215
+ <div id="header">
216
+ <a href="/" title="Twitter: home" accesskey="1" id="logo">
217
+ <img alt="Twitter.com" height="36" src="http://assets0.twitter.com/images/twitter_logo_header.png" width="155" />
218
+ </a>
219
+ <form method="post" id="sign_out_form" action="/sessions/destroy" style="display:none;">
220
+ <input name="authenticity_token" value="05fa1ba4ad2b0b060a72fff262aba2b3aacf80c6" type="hidden" />
221
+ </form>
222
+ <ul class="top-navigation round">
223
+ <li><a href="/login" accesskey="l">Login</a></li>
224
+ <li class="signup-link"><a href="/signup">Join Twitter!</a></li>
225
+ </ul>
226
+ </div>
227
+
228
+
229
+
230
+ <div id="profilebox_outer">
231
+ <div id="profilebird"><img alt="Profile_bird" height="48" id="profilebirdimg" src="http://assets0.twitter.com/images/profile_bird.png" width="48" /></div>
232
+ <div id="profilebox" class="clearfix">
233
+ <div id="profiletext">
234
+ <h1>Hey there! <strong>bicycles</strong> is using Twitter.</h1>
235
+ <h2>Twitter is a free service that lets you keep in touch with people through the exchange of quick, frequent answers to one simple question: What are you doing? <strong>Join today</strong> to start receiving <strong>bicycles's </strong> updates.</h2>
236
+ </div>
237
+ <div id="profilebutton">
238
+ <form name="account_signup_form" id="account_signup_form" action="/signup">
239
+ <input id="follow" name="follow" type="hidden" value="bicycles" />
240
+ <input class="profilesubmit" id="join" name="commit" type="submit" value="Join today!" />
241
+ </form>
242
+ <p><small>Already using Twitter<br /> from your phone? <a href="/account/complete">Click here</a>.</small></p>
243
+ </div>
244
+ </div>
245
+ </div>
246
+
247
+
248
+
249
+ <div class="content-bubble-arrow"></div>
250
+
251
+ <table cellspacing="0" class="columns">
252
+ <tbody>
253
+ <tr>
254
+ <td id="content" class="round-left column">
255
+ <div class="wrapper">
256
+
257
+
258
+
259
+
260
+
261
+
262
+
263
+
264
+ <div class="profile-head">
265
+
266
+ <h2 class="thumb clearfix">
267
+ <a href="/account/profile_image/bicycles"><img alt="" border="0" height="73" id="profile-image" src="http://s3.amazonaws.com/twitter_production/profile_images/57623431/kitty_bigger.png" valign="middle" width="73" /></a>
268
+
269
+ bicycles
270
+ </h2>
271
+ <div class="clear"></div>
272
+ <div id="follow_actions_11240082" class="follow-actions bicycles">
273
+
274
+ </div>
275
+
276
+ <div class="hentry">
277
+
278
+
279
+ </div>
280
+ </div>
281
+
282
+ <div class="section">
283
+
284
+ <div id="timeline_heading" style="display: none;">
285
+ <h1></h1>
286
+ </div>
287
+
288
+ <ol class="statuses" id="timeline"><li class="hentry status u-bicycles latest-status" id="status_1021338503"><span class="status-body"><span class="entry-content">I sat on a balloon, and it didn't pop.</span><span class="meta entry-meta"><a href="http://twitter.com/bicycles/status/1021338503" class="entry-date" rel="bookmark"><span class="published">11:14 AM Nov 24th, 2008</span></a> <span>from web</span> </span></span></li><li class="hentry status u-bicycles" id="status_935287253"><span class="status-body"><span class="entry-content">What am I doing? Tweeting?</span><span class="meta entry-meta"><a href="http://twitter.com/bicycles/status/935287253" class="entry-date" rel="bookmark"><span class="published">9:07 PM Sep 25th, 2008</span></a> <span>from web</span> </span></span></li><li class="hentry status u-bicycles" id="status_914315082"><span class="status-body"><span class="entry-content">Tweet</span><span class="meta entry-meta"><a href="http://twitter.com/bicycles/status/914315082" class="entry-date" rel="bookmark"><span class="published">2:19 PM Sep 8th, 2008</span></a> <span>from <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a></span> </span></span></li><li class="hentry status u-bicycles" id="status_885502724"><span class="status-body"><span class="entry-content">I just realized why it's called "pen pals." Amazing.</span><span class="meta entry-meta"><a href="http://twitter.com/bicycles/status/885502724" class="entry-date" rel="bookmark"><span class="published">11:55 AM Aug 12th, 2008</span></a> <span>from <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a></span> </span></span></li><li class="hentry status u-bicycles" id="status_882028714"><span class="status-body"><span class="entry-content">Today I learned about the U.S. market for wine.</span><span class="meta entry-meta"><a href="http://twitter.com/bicycles/status/882028714" class="entry-date" rel="bookmark"><span class="published">4:18 PM Aug 8th, 2008</span></a> <span>from <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a></span> </span></span></li><li class="hentry status u-bicycles" id="status_875111099"><span class="status-body"><span class="entry-content">Today I learned about sports contracts.</span><span class="meta entry-meta"><a href="http://twitter.com/bicycles/status/875111099" class="entry-date" rel="bookmark"><span class="published">2:34 PM Aug 1st, 2008</span></a> <span>from web</span> </span></span></li><li class="hentry status u-bicycles" id="status_821106491"><span class="status-body"><span class="entry-content">Ms. Pac-Man 134050</span><span class="meta entry-meta"><a href="http://twitter.com/bicycles/status/821106491" class="entry-date" rel="bookmark"><span class="published">11:22 AM May 27th, 2008</span></a> <span>from <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a></span> </span></span></li><li class="hentry status u-bicycles" id="status_794096159"><span class="status-body"><span class="entry-content">At the pixel lounge!</span><span class="meta entry-meta"><a href="http://twitter.com/bicycles/status/794096159" class="entry-date" rel="bookmark"><span class="published">10:55 PM Apr 21st, 2008</span></a> <span>from <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a></span> </span></span></li><li class="hentry status u-bicycles" id="status_794095970"><span class="status-body"><span class="entry-content">Ms. Pacman 128000</span><span class="meta entry-meta"><a href="http://twitter.com/bicycles/status/794095970" class="entry-date" rel="bookmark"><span class="published">10:55 PM Apr 21st, 2008</span></a> <span>from <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a></span> </span></span></li><li class="hentry status u-bicycles" id="status_611417982"><span class="status-body"><span class="entry-content">I pack a chainsaw.</span><span class="meta entry-meta"><a href="http://twitter.com/bicycles/status/611417982" class="entry-date" rel="bookmark"><span class="published">4:01 PM Jan 17th, 2008</span></a> <span>from <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a></span> </span></span></li><li class="hentry status u-bicycles" id="status_563603172"><span class="status-body"><span class="entry-content">Cattleeyes is now following me on twitter.</span><span class="meta entry-meta"><a href="http://twitter.com/bicycles/status/563603172" class="entry-date" rel="bookmark"><span class="published">3:38 PM Jan 4th, 2008</span></a> <span>from <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a></span> </span></span></li><li class="hentry status u-bicycles" id="status_543528112"><span class="status-body"><span class="entry-content">Dude, Christof</span><span class="meta entry-meta"><a href="http://twitter.com/bicycles/status/543528112" class="entry-date" rel="bookmark"><span class="published">3:38 AM Dec 29th, 2007</span></a> <span>from <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a></span> </span></span></li><li class="hentry status u-bicycles" id="status_508844042"><span class="status-body"><span class="entry-content">All of my Christmas gifts are going to be late.</span><span class="meta entry-meta"><a href="http://twitter.com/bicycles/status/508844042" class="entry-date" rel="bookmark"><span class="published">1:36 PM Dec 17th, 2007</span></a> <span>from <a href="http://help.twitter.com/index.php?pg=kb.page&id=75">txt</a></span> </span></span></li><li class="hentry status u-bicycles" id="status_507249672"><span class="status-body"><span class="entry-content">I just lost $1.25 in the laundry machine and had to walk all the way across the street to make my dimes and nickels into two more quarters.</span><span class="meta entry-meta"><a href="http://twitter.com/bicycles/status/507249672" class="entry-date" rel="bookmark"><span class="published">5:23 PM Dec 16th, 2007</span></a> <span>from web</span> </span></span></li></ol>
289
+
290
+ <div id="pagination">
291
+
292
+ </div>
293
+
294
+ </div>
295
+
296
+
297
+
298
+ </div>
299
+ </td>
300
+
301
+ <td id="side_base" class="column round-right">
302
+
303
+ <div id="side">
304
+
305
+ <div id="profile" class="section profile-side">
306
+ <span class="section-links">
307
+ </span>
308
+
309
+ <address>
310
+ <ul class="about vcard entry-author">
311
+ <li><span class="label">Name</span> <span class="fn">bicycles</span></li>
312
+ <li><span class="label">Location</span> <span class="adr">Portland, Oregon</span></li>
313
+ <li><span class="label">Web</span> <a href="http://www.antehero.com/blog" class="url" rel="me nofollow">http://www.antehe...</a></li>
314
+
315
+ <li id="bio"><span class="label">Bio</span> <span class="bio">I write business plans for a living and fiction to stay sane. I also try my hand at all sorts of creative side projects: painting, game dev, whiskey drinking..</span></li>
316
+ </ul>
317
+ </address>
318
+
319
+
320
+ <div class="stats">
321
+ <table>
322
+ <tr>
323
+ <td>
324
+
325
+ <a href="/bicycles/friends" id="following_count_link" class="link-following_page" rel="me" title="See who you’re following">
326
+ <span id="following_count" class="stats_count numeric">7 </span>
327
+ <span class="label">Following</span>
328
+ </a>
329
+
330
+ </td>
331
+ <td>
332
+
333
+ <a href="/bicycles/followers" id="follower_count_link" class="link-followers_page" rel="me" title="See who’s following you">
334
+ <span id="follower_count" class="stats_count numeric">32 </span>
335
+ <span class="label">Followers</span>
336
+ </a>
337
+
338
+ </td>
339
+
340
+ </tr>
341
+ </table>
342
+ </div>
343
+
344
+ </div>
345
+
346
+ <ul id="primary_nav" class="sidebar-menu">
347
+ <li id="profile_tab"><a href="/bicycles" accesskey="u" class="in-page-link"><span id="update_count" class="stat_count">14</span><span>Updates</span></a></li>
348
+ <li id="profile_favorites_tab"><a href="/favourings?user=bicycles" accesskey="f" class="in-page-link"><span>Favorites</span></a></li>
349
+ </ul>
350
+
351
+ <hr/>
352
+
353
+
354
+ <div id="following">
355
+ <h2 class="sidebar-title" id="fm_menu"><span>Following</span></h2>
356
+
357
+ <div class="sidebar-menu">
358
+ <div id="following_list">
359
+
360
+ <span class="vcard">
361
+ <a href="/edwario" class="url" rel="contact" title="Scott Carver"><img alt="Scott Carver" class="photo fn" height="24" src="http://s3.amazonaws.com/twitter_production/profile_images/59122441/scott_mini.jpg" width="24" /></a> </span>
362
+
363
+
364
+ <span class="vcard">
365
+ <a href="/bryanwoods" class="url" rel="contact" title="Bryan Woods"><img alt="Bryan Woods" class="photo fn" height="24" src="http://s3.amazonaws.com/twitter_production/profile_images/72755964/bryanwoods_mini.jpg" width="24" /></a> </span>
366
+
367
+
368
+ <span class="vcard">
369
+ <a href="/robertjwhitney" class="url" rel="contact" title="robertjwhitney"><img alt="robertjwhitney" class="photo fn" height="24" src="http://s3.amazonaws.com/twitter_production/profile_images/188783823/IMG_0003_mini.PNG" width="24" /></a> </span>
370
+
371
+
372
+ <span class="vcard">
373
+ <a href="/meandmybicycle" class="url" rel="contact" title="meandmybicycle"><img alt="meandmybicycle" class="photo fn" height="24" src="http://s3.amazonaws.com/twitter_production/profile_images/48230722/bikelogomedium_mini.jpg" width="24" /></a> </span>
374
+
375
+
376
+ <span class="vcard">
377
+ <a href="/bikefeed" class="url" rel="contact" title="bikefeed"><img alt="bikefeed" class="photo fn" height="24" src="http://s3.amazonaws.com/twitter_production/profile_images/51746801/Picture_4_mini.png" width="24" /></a> </span>
378
+
379
+
380
+ <span class="vcard">
381
+ <a href="/bandorelli" class="url" rel="contact" title="danborelli"><img alt="danborelli" class="photo fn" height="24" src="http://static.twitter.com/images/default_profile_mini.png" width="24" /></a> </span>
382
+
383
+
384
+ <span class="vcard">
385
+ <a href="/BrassTacks" class="url" rel="contact" title="BrassTacks"><img alt="BrassTacks" class="photo fn" height="24" src="http://s3.amazonaws.com/twitter_production/profile_images/57484985/BT2_mini.jpg" width="24" /></a> </span>
386
+
387
+
388
+ </div>
389
+
390
+ </div>
391
+
392
+ </div>
393
+
394
+
395
+
396
+
397
+ <div id="rssfeed">
398
+ <hr/>
399
+ <a href="/statuses/user_timeline/11240082.rss" class="xref rss profile-rss" rel="alternate" type="application/rss+xml">RSS feed of bicycles's updates</a>
400
+ </div>
401
+
402
+
403
+
404
+ </div>
405
+ </td>
406
+
407
+ </tr>
408
+ </tbody>
409
+ </table>
410
+
411
+
412
+
413
+ <div id="footer" class="round">
414
+ <h3 class="offscreen">Footer</h3>
415
+
416
+ <ul>
417
+ <li class="first">&copy; 2009 Twitter</li>
418
+ <li><a href="/about#about">About Us</a></li>
419
+ <li><a href="/about#contact">Contact</a></li>
420
+ <li><a href="http://blog.twitter.com">Blog</a></li>
421
+ <li><a href="http://status.twitter.com">Status</a></li>
422
+ <li><a href="/downloads">Apps</a></li>
423
+ <li><a href="http://apiwiki.twitter.com/">API</a></li>
424
+ <li><a href="http://search.twitter.com">Search</a></li>
425
+ <li><a href="http://help.twitter.com">Help</a></li>
426
+ <li><a href="/jobs">Jobs</a></li>
427
+ <li><a href="/tos">Terms</a></li>
428
+ <li><a href="/privacy">Privacy</a></li>
429
+ </ul>
430
+ </div>
431
+
432
+
433
+
434
+ <hr />
435
+
436
+ </div>
437
+
438
+
439
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.0/jquery.min.js" type="text/javascript"></script><script src="http://assets2.twitter.com/javascripts/application.js?1241136213" type="text/javascript"></script><script src="http://assets1.twitter.com/javascripts/jquery.watermarkinput.js?1241136231" type="text/javascript"></script><script src="http://assets3.twitter.com/javascripts/notifications.js?1241136232" type="text/javascript"></script><script src="http://assets0.twitter.com/javascripts/search.js?1241136233" type="text/javascript"></script>
440
+ <script src="http://assets2.twitter.com/javascripts/jquery.cookie.js?1241136222" type="text/javascript"></script><script src="http://assets1.twitter.com/javascripts/jquery.color.js?1241136221" type="text/javascript"></script>
441
+ <script src="http://assets2.twitter.com/javascripts/jquery.livequery.js?1241136226" type="text/javascript"></script>
442
+ <script src="http://assets1.twitter.com/javascripts/timeline.js?1241136238" type="text/javascript"></script><script type="text/javascript">
443
+ //<![CDATA[
444
+ page.user_screenname = 'bicycles';
445
+ page.user_fullname = 'bicycles';
446
+ twttr.form_authenticity_token = '05fa1ba4ad2b0b060a72fff262aba2b3aacf80c6';
447
+ if (window.top !== window.self) { setTimeout(function(){document.body.innerHTML='';},1);window.self.onload=function(evt){document.body.innerHTML='';};}
448
+ //]]>
449
+ </script><script type="text/javascript">
450
+ //<![CDATA[
451
+
452
+ $( function () {
453
+ initializePage();
454
+
455
+ });
456
+
457
+ //]]>
458
+ </script>
459
+
460
+
461
+
462
+ <!-- BEGIN google analytics -->
463
+
464
+ <script type="text/javascript">
465
+ var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
466
+ document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
467
+ </script>
468
+
469
+ <script type="text/javascript">
470
+ try {
471
+ var pageTracker = _gat._getTracker("UA-30775-6");
472
+ pageTracker._setDomainName("twitter.com");
473
+ pageTracker._setVar('Not Logged In');
474
+ pageTracker._setVar('lang: en');
475
+ pageTracker._initData();
476
+ pageTracker._trackPageview('/profile/not_logged_in/bicycles');
477
+ } catch(err) { }
478
+ </script>
479
+
480
+ <!-- END google analytics -->
481
+
482
+
483
+
484
+
485
+
486
+ <div id="notifications"></div>
487
+
488
+ </body>
489
+
490
+ </html>