ruby-readability 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7c4e7dd91c7e7dbd34238150565daacd14d19c4f
4
- data.tar.gz: fa8ef220bba559a5e3621de373bc3cb5295f9583
3
+ metadata.gz: 7452ade635ade3314c5eb992de803b2ed6d103e0
4
+ data.tar.gz: 90c7b2d34dd4d6070e06c589d5e01f5ebb5e76db
5
5
  SHA512:
6
- metadata.gz: 37f7e00448f2390cf87166899d967ad8521413b727e89a97f977310ceedf51e2f4a99201b046484bde645257ff9828ea3e1365056575776f107f50d0d1a8d15d
7
- data.tar.gz: 2e4bcfceac1c8be2b2cd9cc9ed725f459f57bebfc87beaf940e972a2ed8b37e73d5681955b71a8cebc9ffee246e92b3f33cc8c983ec2ee97b201268149555e73
6
+ metadata.gz: 09a7bfef009fdc001749a2695876d0c0adfcb12ca7cdce31ef494227cd9712133b6ba7a18ffd8340b7a2f233954f6e1cf83e1470b70052d9cb64ad66db24d0c8
7
+ data.tar.gz: cf7b9884f2339f8e2cc99c0a17fc4170a3a97e7f59c9c1e0a0b40417f45c059d2df31d54253b6535f942915096b11e0592d2f8cd2ff735c0bb9edd5ae465afe8
@@ -1,6 +1,6 @@
1
1
  language: ruby
2
2
  rvm:
3
+ - 2.1.1
3
4
  - 2.0.0
4
5
  - 1.9.3
5
- - 1.9.2
6
6
  script: "bundle exec rspec"
data/Gemfile CHANGED
@@ -2,6 +2,8 @@ source "http://rubygems.org"
2
2
 
3
3
  gem 'fastimage', '~> 1.2.13'
4
4
  gem 'rake'
5
+ gem 'guard'
6
+ gem 'guard-rspec'
5
7
 
6
8
  group :test do
7
9
  gem "fakeweb", "~> 1.3.0"
@@ -0,0 +1,9 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
9
+
data/README.md CHANGED
@@ -51,6 +51,7 @@ You may provide options to `Readability::Document.new`, including:
51
51
  `:ignore_image_format => ["gif", "png"]`;
52
52
  * `:min_image_height`: set a minimum image height for `#images`;
53
53
  * `:min_image_width`: set a minimum image width for `#images`.
54
+ * `:blacklist` and `:whitelist` allow you to explicitly scope to, or remove, CSS selectors.
54
55
 
55
56
 
56
57
  Command Line Tool
@@ -74,6 +75,10 @@ feature requires that the `fastimage` gem be installed.
74
75
  rbody = Readability::Document.new(body, :tags => %w[div p img a], :attributes => %w[src href], :remove_empty_nodes => false)
75
76
  rbody.images
76
77
 
78
+ Related Projects
79
+ ----------------
80
+
81
+ * [newspaper](https://github.com/codelucas/newspaper) is an advanced news extraction, article extraction, and content curation library for Python.
77
82
 
78
83
  Potential Issues
79
84
  ----------------
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby
1
+ #!/usr/bin/env ruby
2
2
  require 'rubygems'
3
3
  require 'open-uri'
4
4
  require 'optparse'
@@ -29,11 +29,13 @@ if ARGV.length != 1
29
29
  end
30
30
 
31
31
  text = open(ARGV.first).read
32
- if options[:images]
33
- puts Readability::Document.new(text, :tags => %w[div p img a],
34
- :attributes => %w[src href],
35
- :remove_empty_nodes => false,
36
- :debug => options[:debug]).content
32
+ params = if options[:images]
33
+ { :tags => %w[div p img a],
34
+ :attributes => %w[src href],
35
+ :remove_empty_nodes => false,
36
+ :debug => options[:debug] }
37
37
  else
38
- puts Readability::Document.new(text, :debug => options[:debug]).content
38
+ { :debug => options[:debug] }
39
39
  end
40
+
41
+ puts Readability::Document.new(text, params).content
@@ -15,7 +15,9 @@ module Readability
15
15
  :remove_empty_nodes => true,
16
16
  :min_image_width => 130,
17
17
  :min_image_height => 80,
18
- :ignore_image_format => []
18
+ :ignore_image_format => [],
19
+ :blacklist => nil,
20
+ :whitelist => nil
19
21
  }.freeze
20
22
 
21
23
  attr_accessor :options, :html, :best_candidate, :candidates, :best_candidate_has_image
@@ -35,18 +37,42 @@ module Readability
35
37
  @clean_conditionally = @options[:clean_conditionally]
36
38
  @best_candidate_has_image = true
37
39
  make_html
40
+ handle_exclusions!(@options[:whitelist], @options[:blacklist])
38
41
  end
39
42
 
40
43
  def prepare_candidates
41
44
  @html.css("script, style").each { |i| i.remove }
42
45
  remove_unlikely_candidates! if @remove_unlikely_candidates
43
46
  transform_misused_divs_into_paragraphs!
44
-
47
+
45
48
  @candidates = score_paragraphs(options[:min_text_length])
46
49
  @best_candidate = select_best_candidate(@candidates)
47
50
  end
48
51
 
49
- def make_html
52
+ def handle_exclusions!(whitelist, blacklist)
53
+ return unless whitelist || blacklist
54
+
55
+ if blacklist
56
+ elems = @html.css(blacklist)
57
+ if elems
58
+ elems.each do |e|
59
+ e.remove
60
+ end
61
+ end
62
+ end
63
+
64
+ if whitelist
65
+ elems = @html.css(whitelist).to_s
66
+
67
+ if body = @html.at_css('body')
68
+ body.inner_html = elems
69
+ end
70
+ end
71
+
72
+ @input = @html.to_s
73
+ end
74
+
75
+ def make_html(whitelist=nil, blacklist=nil)
50
76
  @html = Nokogiri::HTML(@input, nil, @options[:encoding])
51
77
  # In case document has no body, such as from empty string or redirect
52
78
  @html = Nokogiri::HTML('<body />', nil, @options[:encoding]) if @html.css('body').length == 0
@@ -78,16 +104,16 @@ module Readability
78
104
  url = element["src"].value
79
105
  height = element["height"].nil? ? 0 : element["height"].value.to_i
80
106
  width = element["width"].nil? ? 0 : element["width"].value.to_i
81
-
107
+
82
108
  if url =~ /\Ahttps?:\/\//i && (height.zero? || width.zero?)
83
- image = get_image_size(url)
109
+ image = get_image_size(url)
84
110
  next unless image
85
111
  else
86
112
  image = {:width => width, :height => height}
87
113
  end
88
-
114
+
89
115
  image[:format] = File.extname(url).gsub(".", "")
90
-
116
+
91
117
  if tested_images.include?(url)
92
118
  debug("Image was tested: #{url}")
93
119
  next
@@ -105,14 +131,12 @@ module Readability
105
131
  end
106
132
 
107
133
  def get_image_size(url)
108
- begin
109
- w, h = FastImage.size(url)
110
- raise "Couldn't get size." if w.nil? || h.nil?
111
- {:width => w, :height => h}
112
- rescue => e
113
- debug("Image error: #{e}")
114
- nil
115
- end
134
+ w, h = FastImage.size(url)
135
+ raise "Couldn't get size." if w.nil? || h.nil?
136
+ {:width => w, :height => h}
137
+ rescue => e
138
+ debug("Image error: #{e}")
139
+ nil
116
140
  end
117
141
 
118
142
  def image_meets_criteria?(image)
@@ -148,9 +172,7 @@ module Readability
148
172
  author_elements = @html.xpath('//meta[@name = "dc.creator"]')
149
173
  unless author_elements.empty?
150
174
  author_elements.each do |element|
151
- if element['content']
152
- return element['content'].strip
153
- end
175
+ return element['content'].strip if element['content']
154
176
  end
155
177
  end
156
178
 
@@ -160,9 +182,7 @@ module Readability
160
182
  author_elements = @html.xpath('//*[contains(@class, "vcard")]//*[contains(@class, "fn")]')
161
183
  unless author_elements.empty?
162
184
  author_elements.each do |element|
163
- if element.text
164
- return element.text.strip
165
- end
185
+ return element.text.strip if element.text
166
186
  end
167
187
  end
168
188
 
@@ -172,18 +192,14 @@ module Readability
172
192
  author_elements = @html.xpath('//a[@rel = "author"]')
173
193
  unless author_elements.empty?
174
194
  author_elements.each do |element|
175
- if element.text
176
- return element.text.strip
177
- end
195
+ return element.text.strip if element.text
178
196
  end
179
197
  end
180
198
 
181
199
  author_elements = @html.xpath('//*[@id = "author"]')
182
200
  unless author_elements.empty?
183
201
  author_elements.each do |element|
184
- if element.text
185
- return element.text.strip
186
- end
202
+ return element.text.strip if element.text
187
203
  end
188
204
  end
189
205
  end
@@ -230,10 +246,10 @@ module Readability
230
246
  node_content = sibling.text
231
247
  node_length = node_content.length
232
248
 
233
- if node_length > 80 && link_density < 0.25
234
- append = true
249
+ append = if node_length > 80 && link_density < 0.25
250
+ true
235
251
  elsif node_length < 80 && link_density == 0 && node_content =~ /\.( |$)/
236
- append = true
252
+ true
237
253
  end
238
254
  end
239
255
 
@@ -302,40 +318,28 @@ module Readability
302
318
  return weight unless @weight_classes
303
319
 
304
320
  if e[:class] && e[:class] != ""
305
- if e[:class] =~ REGEXES[:negativeRe]
306
- weight -= 25
307
- end
308
-
309
- if e[:class] =~ REGEXES[:positiveRe]
310
- weight += 25
311
- end
321
+ weight -= 25 if e[:class] =~ REGEXES[:negativeRe]
322
+ weight += 25 if e[:class] =~ REGEXES[:positiveRe]
312
323
  end
313
324
 
314
325
  if e[:id] && e[:id] != ""
315
- if e[:id] =~ REGEXES[:negativeRe]
316
- weight -= 25
317
- end
318
-
319
- if e[:id] =~ REGEXES[:positiveRe]
320
- weight += 25
321
- end
326
+ weight -= 25 if e[:id] =~ REGEXES[:negativeRe]
327
+ weight += 25 if e[:id] =~ REGEXES[:positiveRe]
322
328
  end
323
329
 
324
330
  weight
325
331
  end
326
332
 
333
+ ELEMENT_SCORES = {
334
+ 'div' => 5,
335
+ 'blockquote' => 3,
336
+ 'form' => -3,
337
+ 'th' => -5
338
+ }.freeze
339
+
327
340
  def score_node(elem)
328
341
  content_score = class_weight(elem)
329
- case elem.name.downcase
330
- when "div"
331
- content_score += 5
332
- when "blockquote"
333
- content_score += 3
334
- when "form"
335
- content_score -= 3
336
- when "th"
337
- content_score -= 5
338
- end
342
+ content_score += ELEMENT_SCORES.fetch(elem.name.downcase, 0)
339
343
  { :content_score => content_score, :elem => elem }
340
344
  end
341
345
 
@@ -373,7 +377,7 @@ module Readability
373
377
  end
374
378
  end
375
379
 
376
- def sanitize(node, candidates, options = {})
380
+ def sanitize(node, candidates, options = {})
377
381
  node.css("h1, h2, h3, h4, h5, h6").each do |header|
378
382
  header.remove if class_weight(header) < 0 || get_link_density(header) > 0.33
379
383
  end
@@ -450,38 +454,35 @@ module Readability
450
454
 
451
455
  content_length = el.text.strip.length # Count the text length excluding any surrounding whitespace
452
456
  link_density = get_link_density(el)
453
- to_remove = false
454
- reason = ""
455
-
456
- if counts["img"] > counts["p"]
457
- reason = "too many images"
458
- to_remove = true
459
- elsif counts["li"] > counts["p"] && name != "ul" && name != "ol"
460
- reason = "more <li>s than <p>s"
461
- to_remove = true
462
- elsif counts["input"] > (counts["p"] / 3).to_i
463
- reason = "less than 3x <p>s than <input>s"
464
- to_remove = true
465
- elsif content_length < (options[:min_text_length] || TEXT_LENGTH_THRESHOLD) && (counts["img"] == 0 || counts["img"] > 2)
466
- reason = "too short a content length without a single image"
467
- to_remove = true
468
- elsif weight < 25 && link_density > 0.2
469
- reason = "too many links for its weight (#{weight})"
470
- to_remove = true
471
- elsif weight >= 25 && link_density > 0.5
472
- reason = "too many links for its weight (#{weight})"
473
- to_remove = true
474
- elsif (counts["embed"] == 1 && content_length < 75) || counts["embed"] > 1
475
- reason = "<embed>s with too short a content length, or too many <embed>s"
476
- to_remove = true
477
- end
478
457
 
479
- if to_remove
458
+ reason = clean_conditionally_reason?(counts, content_length, options, weight, link_density)
459
+ if reason
480
460
  debug("Conditionally cleaned #{name}##{el[:id]}.#{el[:class]} with weight #{weight} and content score #{content_score} because it has #{reason}.")
481
461
  el.remove
482
462
  end
483
463
  end
484
464
  end
485
465
  end
466
+
467
+ def clean_conditionally_reason?(counts, content_length, options, weight, link_density)
468
+ if counts["img"] > counts["p"]
469
+ "too many images"
470
+ elsif counts["li"] > counts["p"] && name != "ul" && name != "ol"
471
+ "more <li>s than <p>s"
472
+ elsif counts["input"] > (counts["p"] / 3).to_i
473
+ "less than 3x <p>s than <input>s"
474
+ elsif content_length < (options[:min_text_length] || TEXT_LENGTH_THRESHOLD) && (counts["img"] == 0 || counts["img"] > 2)
475
+ "too short a content length without a single image"
476
+ elsif weight < 25 && link_density > 0.2
477
+ "too many links for its weight (#{weight})"
478
+ elsif weight >= 25 && link_density > 0.5
479
+ "too many links for its weight (#{weight})"
480
+ elsif (counts["embed"] == 1 && content_length < 75) || counts["embed"] > 1
481
+ "<embed>s with too short a content length, or too many <embed>s"
482
+ else
483
+ nil
484
+ end
485
+ end
486
+
486
487
  end
487
488
  end
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "ruby-readability"
6
- s.version = '0.6.0'
6
+ s.version = '0.6.1'
7
7
  s.authors = ["Andrew Cantino", "starrhorne", "libc", "Kyle Maxwell"]
8
8
  s.email = ["andrew@iterationlabs.com"]
9
9
  s.homepage = "http://github.com/cantino/ruby-readability"
@@ -0,0 +1,876 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <title>Tick, tick, tick - Boing Boing</title><meta charset="utf-8">
5
+ <meta property="twitter:account_id" content="5971922" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=1" />
7
+ <link rel="stylesheet" href="http://media.boingboing.net/wp-content/themes/2012/style.css?v=33" type="text/css" charset="utf-8" />
8
+ <!--[if lt IE 9]> <link rel="stylesheet" href="http://media.boingboing.net/wp-content/themes/2012/style_IE.css?v=3" type="text/css" charset="utf-8" /><![endif]-->
9
+ <script type="text/javascript" src="//use.typekit.net/its8tor.js"></script>
10
+ <script type="text/javascript">try{Typekit.load();}catch(e){}</script>
11
+
12
+ <meta property="fb:admins" content="1219680052" />
13
+ <meta property="og:site_name" content="Boing Boing" />
14
+ <link rel="apple-touch-icon" href="/wp-content/themes/2012/sundries/apple-touch-icon.png"/>
15
+ <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
16
+ <script type="text/javascript" charset="utf-8">
17
+ document.domain = 'boingboing.net';
18
+ </script>
19
+
20
+
21
+ <!-- Begin DoubleClick For Publishers code -->
22
+ <script type='text/javascript'>
23
+ var googletag = googletag || {};
24
+ googletag.cmd = googletag.cmd || [];
25
+ (function() {
26
+ var gads = document.createElement('script');
27
+ gads.async = true;
28
+ gads.type = 'text/javascript';
29
+ var useSSL = 'https:' == document.location.protocol;
30
+ gads.src = (useSSL ? 'https:' : 'http:') +
31
+ '//www.googletagservices.com/tag/js/gpt.js';
32
+ var node = document.getElementsByTagName('script')[0];
33
+ node.parentNode.insertBefore(gads, node);
34
+ })();
35
+ </script>
36
+
37
+ <script type='text/javascript'>
38
+ googletag.cmd.push(function() {
39
+ googletag.defineSlot('/6203160/400x300_home_footer', [[400, 267], [300, 250]], 'div-gpt-ad-1348031780431-0').addService(googletag.pubads());
40
+ googletag.defineSlot('/6203160/300x250_temp_top_sidebar', [300, 250], 'div-gpt-ad-1388426870729-0').addService(googletag.pubads());
41
+ googletag.pubads().collapseEmptyDivs();
42
+ googletag.enableServices();
43
+ });
44
+ </script>
45
+
46
+ <script type='text/javascript'>
47
+ (function() {
48
+ var useSSL = 'https:' == document.location.protocol;
49
+ var src = (useSSL ? 'https:' : 'http:') +
50
+ '//www.googletagservices.com/tag/js/gpt_mobile.js';
51
+ document.write('<scr' + 'ipt src="' + src + '"></scr' + 'ipt>');
52
+ })();
53
+ </script>
54
+ <script type='text/javascript'>
55
+ googletag.cmd.push(function() {
56
+ googletag.defineSlot('/6203160/320x50', [320, 50], 'div-gpt-ad-1356214036289-0').addService(googletag.pubads());
57
+ googletag.enableServices();
58
+ });
59
+ </script>
60
+ <!-- End DoubleClick For Publishers Code -->
61
+
62
+
63
+
64
+ <link rel="stylesheet" href="http://media.boingboing.net/wp-content/themes/2012/style_single.css?v=21" type="text/css" charset="utf-8" />
65
+ <!--[if lt IE 9]> <link rel="stylesheet" href="http://media.boingboing.net/wp-content/themes/2012/style_IE_single.css?v=18" type="text/css" charset="utf-8" /><![endif]-->
66
+
67
+
68
+ <meta property="og:type" content="article" />
69
+ <meta property="og:title" content="Tick, tick, tick" />
70
+ <meta property="og:description" content="No idea who made this, but it&#039;s wonderful. If you know, post in the comments, please.
71
+
72
+
73
+ Update: It&#039;s from Bees and Bombs, to which I have just subscribed." />
74
+ <meta property="og:url" content="http://boingboing.net/2014/04/13/tick-tick-tick.html" />
75
+ <meta property="og:image" content="http://media.boingboing.net/wp-content/uploads/2014/04/tumblr_n3wstblgoN1socbkko1_5001.gif" />
76
+
77
+
78
+ <meta itemprop="name" content="Tick, tick, tick" />
79
+ <meta itemprop="headline" content="Tick, tick, tick" />
80
+ <meta itemprop="author" content="Cory Doctorow" />
81
+ <meta itemprop="description" content="No idea who made this, but it&#039;s wonderful. If you know, post in the comments, please.
82
+
83
+
84
+ Update: It&#039;s from Bees and Bombs, to which I have just subscribed." />
85
+ <link itemprop="url" href="http://boingboing.net/2014/04/13/tick-tick-tick.html" />
86
+ <link itemprop="thumbnailUrl" href="http://media.boingboing.net/wp-content/uploads/2014/04/tumblr_n3wstblgoN1socbkko1_5001.gif" />
87
+
88
+
89
+ <meta name="twitter:card" content="summary_large_image">
90
+ <meta name="twitter:site" content="@BoingBoing">
91
+ <meta name="twitter:creator" content="@doctorow">
92
+ <meta name="twitter:title" content="Tick, tick, tick">
93
+ <meta name="twitter:description" content="No idea who made this, but it&#039;s wonderful. If you know, post in the comments, please.
94
+
95
+
96
+ Update: It&#039;s from Bees and Bombs, to which I have just subscribed.">
97
+ <meta name="twitter:image:src" content="http://media.boingboing.net/wp-content/uploads/2014/04/tumblr_n3wstblgoN1socbkko1_5001.gif">
98
+
99
+
100
+ <link rel='stylesheet' id='discourse_comments-css' href='http://media.boingboing.net/wp-content/plugins/wp-discourse/css/style.css?ver=3.4.1' type='text/css' media='all' />
101
+ <link rel='stylesheet' id='kindle-style-css' href='http://media.boingboing.net/wp-content/plugins/sendtokindle/media/kindle.css?ver=3.4.1' type='text/css' media='all' />
102
+ <script type='text/javascript'>
103
+ /* <![CDATA[ */
104
+ (function k(){window.$SendToKindle&&window.$SendToKindle.Widget?$SendToKindle.Widget.init({"title":".entry-title","published":".entry-date","content":".post","exclude":".sharedaddy"}):setTimeout(k,500);})();
105
+ /* ]]> */
106
+ </script>
107
+ <script type='text/javascript' src='http://d1xnn692s7u6t6.cloudfront.net/widget.js'></script>
108
+ <link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://boingboing.net/xmlrpc.php?rsd" />
109
+ <link rel="wlwmanifest" type="application/wlwmanifest+xml" href="http://media.boingboing.net/wp-includes/wlwmanifest.xml" />
110
+ <link rel='prev' title='This Day in Blogging History: Google&#039;s adds dead-man&#039;s switch; Hyperbolic Bronnerianism; Amex can&#039;t take a&nbsp;joke' href='http://boingboing.net/2014/04/13/this-day-in-blogging-history-195.html' />
111
+ <link rel='next' title='TV recap: Game Of Thrones &#039;The Lion And The Rose&#039; [season 4, episode&nbsp;2]' href='http://boingboing.net/2014/04/13/tv-recap-game-of-thrones-th.html' />
112
+ <meta name="generator" content="WordPress 3.4.1" />
113
+ <link rel='canonical' href='http://boingboing.net/2014/04/13/tick-tick-tick.html' />
114
+ <link rel='shortlink' href='http://boingboing.net/?p=297258' />
115
+ <link rel='stylesheet' type='text/css' href='http://media.boingboing.net/wp-content/plugins/embedly/css/embedly.css' />
116
+ <script type="text/javascript" src="http://media.boingboing.net/wp-content/plugins/oembed-manager/oembed-html-style-scripts.js?v=1"> </script><link rel="stylesheet" type="text/css" href="http://media.boingboing.net/wp-content/plugins/oembed-manager/oembed-html-style.css?v=1" /> </head>
117
+
118
+ <body class="single single-post postid-297258 single-format-standard" itemscope='' itemtype='http://schema.org/Blog'
119
+ >
120
+
121
+ <div id="adskin"></div>
122
+
123
+ <div id="dickbar2" style="">
124
+
125
+ <div id="dickbar2-inner">
126
+ <span style="float:left">
127
+ <a href="http://boingboing.net/suggest.html">Submit <span style="mobile-hide">a link</span></a>
128
+ </span>
129
+
130
+
131
+
132
+ <!-- Google search box. -->
133
+
134
+
135
+ <div id="cse-search-box" class="tablet-hide">
136
+ <form action="http://www.google.com/cse">
137
+ <input name="cx" value="partner-pub-2170174688585464:d58nno-rqp8" type="hidden">
138
+ <input name="ie" value="ISO-8859-1" type="hidden">
139
+ <input name="q" id="searchInputField" size="18" class="" value="" type="text" style="background-image:url('http://media.boingboing.net/wp-content/uploads/2013/07/searchback.png')!important;background-position:right center!important;background-repeat:no-repeat!important">
140
+ <input value="" name="siteurl" type="hidden">
141
+ </form>
142
+ </div>
143
+ <script type="text/javascript" src="http://www.google.com/coop/cse/brand?form=cse-search-box&amp;lang=en"></script>
144
+
145
+
146
+ <script>
147
+ function navdrop()
148
+ {
149
+ if (document.getElementById('drop').style.display=='none') { document.getElementById('drop').style.display='block'; }
150
+ else {document.getElementById('drop').style.display='none'}
151
+ }
152
+ </script>
153
+
154
+ <span style="float:right;margin-right:1em">
155
+ <a href="http://boingboing.net/category/feature/" style="color:#ff638c">Features</a>
156
+ <a href="http://boingboing.net/category/review/" style="color:#e761fd">Reviews</a>
157
+ <a href="http://boingboing.net/category/podcasts" style="color:#6b70ff">Podcasts</a>
158
+ <a href="http://boingboing.net/category/video/" style="color:#61f1fc">Video</a>
159
+ <a class="mobile-hide" href="http://bbs.boingboing.net/" style="color:#61fe99">Forums</a>
160
+ <a class="mobile-hide" href="javascript:void(0)" onClick="navdrop()" style="color:#80eb59">More &#9662;</a>
161
+ </span>
162
+
163
+
164
+ <div id="drop" style="border-left:15px solid white;border-right:15px solid white;border-bottom:15px solid white;position:absolute;top:54px;padding:0px 15px 15px 15px;right:87px;background-color:black;opacity:1;z-index:999;display:none;">
165
+ <a class="mobile-hide" href="http://shop.boingboing.net/" style="color:#fff">Shop</a>
166
+ <br><a class="mobile-hide" href="http://boingboing.net/about" style="color:#fff">About Us</a>
167
+ <br><a class="mobile-hide" href="http://boingboing.net/contact" style="color:#fff">Contact</a>
168
+ <br><a class="mobile-hide" href="mailto:inquiries@boingboing.net" style="color:#fff">Advertise</a>
169
+ <br><a class="mobile-hide" href="http://boingboing.net/privacy" style="color:#fff">Privacy</a>
170
+ <br><a class="mobile-hide" href="http://boingboing.net/tos" style="color:#fff">TOS</a>
171
+ <br><br><span style="font-size:13px;color:gray;">Follow Us</span>
172
+ <br><a href="http://facebook.com/boingboing" style="color:#fff">Facebook</a>
173
+ <br><a href="http://twitter.com/boingboing" style="color:#fff">Twitter</a>
174
+ <br><a href="http://feeds.boingboing.net/boingboing/iBag" style="color:#fff">RSS</a>
175
+ <br><a href="http://boingboing.us2.list-manage.com/subscribe?u=0e91f8e7df61da4bff2bd9b1f&id=fa324756a4" style="color:#fff">Email</a>
176
+ </div>
177
+ </div>
178
+ </div>
179
+
180
+
181
+ <h2 id="JKAnchor"><img src="http://media.boingboing.net/wp-content/themes/2012/sundries/boingboing.jpg"></h2> <!-- top anchor for j/k navigation -->
182
+
183
+ <div id="container">
184
+
185
+
186
+ <div id="mobile_includes">
187
+ <noscript id="mobile_includes_noscript">
188
+ <style type="text/css">
189
+ @media screen and (max-width:400px){
190
+ body{
191
+ overflow-x:hidden;
192
+ background:#ffffff !important;
193
+ }
194
+ #posts-loop *{
195
+ max-width:100% !important;
196
+ }
197
+ *{
198
+ max-width:320px;
199
+ }
200
+ #mobile_includes{
201
+ width:320px;
202
+ margin-left:-16px;
203
+ }
204
+ #container{
205
+ padding-top:0px;
206
+ }
207
+ #cse-search-box {
208
+ margin-right: 5px !important;
209
+ }
210
+ #dickbar {
211
+ width:310px;
212
+ }
213
+ #mobile-logo {
214
+ padding:20px 0px 10px 0px;
215
+ }
216
+ #metadataBox {
217
+ overflow-x:hidden;
218
+ }
219
+ #ad_500 {
220
+ max-height:400px;
221
+ overflow:hidden;
222
+ }
223
+ }
224
+ </style>
225
+
226
+ <!-- 320x50-Mobile-Leaderboard -->
227
+ <div id='div-gpt-ad-1356214036289-0'>
228
+ <script type='text/javascript'>
229
+ googletag.cmd.push(function() { googletag.display('div-gpt-ad-1356214036289-0')});
230
+ </script>
231
+ </div>
232
+ <!-- end 320x50-Mobile-Leaderboard -->
233
+ </noscript>
234
+
235
+ <script type="text/javascript">
236
+ function isMobile(){
237
+ return (function(a){
238
+ if(/android.+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))){
239
+ return true;
240
+ }
241
+ else {
242
+ return false;
243
+ }
244
+ })(navigator.userAgent||navigator.vendor||window.opera);
245
+ }
246
+
247
+ if(isMobile()){
248
+ console.log('Mobile or tablet detected for mobile ad');
249
+ if($('#mobile_includes') && $('#mobile_includes_noscript')) {
250
+ console.log('Populating mobile-specific styles');
251
+ document.write($('#mobile_includes_noscript').text());
252
+ }
253
+ }
254
+ </script>
255
+ </div>
256
+
257
+
258
+ <div id="mobile-logo"><a href="http://boingboing.net"><img src="http://media.boingboing.net/wp-content/themes/2012/sundries/logo1.png"></a></div>
259
+
260
+
261
+
262
+
263
+
264
+ <!-- The main content area of the site -->
265
+
266
+ <div id="mainbar" style="">
267
+
268
+ <!-- Masthead and Leaderboard ad -->
269
+ <div id="masthead">
270
+ <div id="logobox" style="">
271
+ <a href="http://boingboing.net">
272
+ <img id="logo" src="http://media.boingboing.net/wp-content/themes/2012/sundries/logo_bounce2012_static.gif" name="MyImage" alt="Jill" onmouseover="document.MyImage.src='http://media.boingboing.net/wp-content/themes/2012/sundries/logo_bounce2012.gif';" onmouseout="document.MyImage.src='http://media.boingboing.net/wp-content/themes/2012/sundries/logo_bounce2012_static.gif';">
273
+ </a>
274
+ </div>
275
+
276
+ <div id="ad_leaderboard">
277
+ <!--[if !IE]> -->
278
+ <noscript id="ad_leaderboard_noscript">
279
+ <!-- <![endif]-->
280
+ <center>
281
+ <iframe src="http://boingboing.net/wp-content/themes/2012/ads/ad_leaderboard.html?v=1&fm_url=http://boingboing.net/2014/04/13/tick-tick-tick.html&fm_custom_kvs=category%3Dpost" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" topmargin="0" leftmargin="0" allowtransparency="true" width="100%" onload="console.log('ad_leaderboard iframe loaded');"></iframe>
282
+ </center>
283
+ <!--[if !IE]> -->
284
+ </noscript>
285
+ <!-- <![endif]-->
286
+ </div>
287
+
288
+ </div>
289
+
290
+
291
+ <!-- IF IT'S AN AD, DISCLOSE IT-->
292
+
293
+
294
+ <!-- A LARGE HEADLINE AND THE BYLINE -->
295
+
296
+ <div id="headline-297258" class="headlineBox">
297
+
298
+
299
+
300
+ <h1 class="bigHeadline" id="theHeadline">Tick, tick,&nbsp;tick</h1>
301
+
302
+
303
+ <div id="share_post_small">
304
+
305
+ <span class="emailDiv">
306
+ <a href="mailto:type%20email%20address%20here?subject=Shared%20from%20Boing Boing&body=Tick, tick,&nbsp;tick - http://boingboing.net/2014/04/13/tick-tick-tick.html" title="Email to a friend/colleague" target="_blank">
307
+ <img src="http://media.boingboing.net/wp-content/themes/2012/sundries/share.png" style="margin-left:-60px;">
308
+ </a>
309
+ </span>
310
+
311
+ <span class="fbDiv">
312
+ <a href="http://www.facebook.com/sharer.php?u=http://boingboing.net/2014/04/13/tick-tick-tick.html" target='_blank'>
313
+ <img src="http://media.boingboing.net/wp-content/themes/2012/sundries/share.png" style="margin-left:-42px;">
314
+ </a>
315
+ </span>
316
+
317
+ <span class="twitterDiv">
318
+ <a href="http://twitter.com/home?status=Tick%2C+tick%2C%26nbsp%3Btick: http://boingboing.net/2014/04/13/tick-tick-tick.html" target='_blank' title='Click to Tweet this page'>
319
+ <img src="http://media.boingboing.net/wp-content/themes/2012/sundries/share.png" style="margin-left:-27px;">
320
+ </a>
321
+ </span>
322
+
323
+ </div>
324
+ <p class="byline permalink"><a href="http://boingboing.net/author/cory_doctorow_1" title="Posts by Cory Doctorow" rel="author">Cory Doctorow</a> at 8:00 pm Sun, Apr 13, 2014 </p>
325
+
326
+
327
+ </div>
328
+
329
+ <!-- RIGHT HAND ADS -->
330
+
331
+ <div id="sidebar">
332
+ <div class="sidebar_item">
333
+ <!-- 300x250_temp_top_sidebar -->
334
+ <div id='div-gpt-ad-1388426870729-0' style='width:300px; height:250px;'>
335
+ <script type='text/javascript'>
336
+ googletag.cmd.push(function() { googletag.display('div-gpt-ad-1388426870729-0'); });
337
+ </script>
338
+ </div>
339
+ </div>
340
+
341
+ <div id="wrap300">
342
+ <p id="featuretitle">&mdash; FEATURED &mdash;
343
+
344
+ <div id="features" >
345
+
346
+
347
+ <div class="features-item">
348
+
349
+ <a href="http://boingboing.net/2014/04/14/a-vindication-for-the-public.html"><img class="sidebarThumb" style="margin-top:2px;" src="http://media.boingboing.net/wp-content/uploads/2014/04/snow1.jpg"></a>
350
+
351
+ <p style="margin:0px 0px 3px 0px;text-transform:uppercase;font-size:12px;font-weight:bold;"><a href="http://boingboing.net/2014/04/14/a-vindication-for-the-public.html" style="color:#C00">THE LATEST</a></p>
352
+ <p style="margin: 0px;font-size:13px;line-height:1"><a href="http://boingboing.net/2014/04/14/a-vindication-for-the-public.html">A Vindication for the Public: Guardian and Washington Post Win Pulitzer Prize (A statement from Edward&nbsp;Snowden)</a>
353
+
354
+
355
+ </div>
356
+
357
+
358
+
359
+
360
+
361
+ <div class="features-item">
362
+
363
+ <a href="http://boingboing.net/2014/04/14/77-fun-ways-to-play-fast-movin.html"><img class="sidebarThumb" style="margin-top:2px;" src="http://media.boingboing.net/wp-content/uploads/2014/04/tenzi-pattern.jpg"></a>
364
+
365
+ <p style="margin:0px 0px 3px 0px;text-transform:uppercase;font-size:12px;font-weight:bold;"><a href="http://boingboing.net/2014/04/14/77-fun-ways-to-play-fast-movin.html" style="color:#C00">Family</a></p>
366
+ <p style="margin: 0px;font-size:13px;line-height:1"><a href="http://boingboing.net/2014/04/14/77-fun-ways-to-play-fast-movin.html">77 fun ways to play fast-moving Tenzi dice&nbsp;game</a>
367
+
368
+
369
+ </div>
370
+
371
+ <div class="features-item">
372
+
373
+ <a href="http://boingboing.net/2014/04/14/diableries-stereoscopic-adven.html"><img class="sidebarThumb" style="margin-top:2px;" src="http://media.boingboing.net/wp-content/uploads/2014/04/Screen-Shot-2014-04-13-at-7.41.53-PM.jpg"></a>
374
+
375
+ <p style="margin:0px 0px 3px 0px;text-transform:uppercase;font-size:12px;font-weight:bold;"><a href="http://boingboing.net/2014/04/14/diableries-stereoscopic-adven.html" style="color:#C00">Book Review</a></p>
376
+ <p style="margin: 0px;font-size:13px;line-height:1"><a href="http://boingboing.net/2014/04/14/diableries-stereoscopic-adven.html">Diableries: Stereoscopic Adventures in Hell (book&nbsp;review)</a>
377
+
378
+
379
+ </div>
380
+
381
+ <div class="features-item">
382
+
383
+ <a href="http://boingboing.net/2014/04/13/tv-recap-game-of-thrones-th.html"><img class="sidebarThumb" style="margin-top:2px;" src="http://media.boingboing.net/wp-content/uploads/2014/04/gotth1.jpg"></a>
384
+
385
+ <p style="margin:0px 0px 3px 0px;text-transform:uppercase;font-size:12px;font-weight:bold;"><a href="http://boingboing.net/2014/04/13/tv-recap-game-of-thrones-th.html" style="color:#C00">Recap</a></p>
386
+ <p style="margin: 0px;font-size:13px;line-height:1"><a href="http://boingboing.net/2014/04/13/tv-recap-game-of-thrones-th.html">TV recap: Game Of Thrones 'The Lion And The Rose' [season 4, episode&nbsp;2]</a>
387
+
388
+
389
+ </div>
390
+
391
+
392
+ </div>
393
+
394
+ <div id="sidebar_adblock">
395
+
396
+ <!--[if !IE]> -->
397
+ <noscript id="adblock_noscript">
398
+ <p style="text-align:center;margin-top:0px"><small><a href="mailto:inquiries@boingboing.net">ADVERTISE AT BOING BOING!</a></small>
399
+ <!-- <![endif]-->
400
+
401
+ <div class="sidebar_item">
402
+ <iframe id="ad_squares_frame" class="ad" src="http://boingboing.net/wp-content/themes/2012/ads/ad_squares.html?v=11&fm_url=http://boingboing.net/2014/04/13/tick-tick-tick.html" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" topmargin="0" leftmargin="0" allowtransparency="true" width="300px" height="300px"> </iframe>
403
+ </div>
404
+
405
+ <div class="sidebar_item">
406
+
407
+ <iframe id="ad_300_frame" src="http://boingboing.net/wp-content/themes/2012/ads/ad_300.html?fm_url=http://boingboing.net/2014/04/13/tick-tick-tick.html&fm_custom_kvs=category%3Dpost&v=0" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" topmargin="0" leftmargin="0" allowtransparency="true" width="300px"> </iframe>
408
+
409
+ </div>
410
+
411
+
412
+
413
+
414
+
415
+ <p id="featuretitle">&mdash; COMICS &mdash;
416
+ <div id="features" >
417
+
418
+ <div class="features-item">
419
+
420
+ <a href="http://boingboing.net/2014/04/09/tom-the-dancing-bug-learning.html"><img class="sidebarThumb" src="http://media.boingboing.net/wp-content/uploads/2014/04/1183cbTHUMB-twitter-events.jpg"></a>
421
+
422
+ <p style="margin:0px 0px 3px 0px;text-transform:uppercase;font-size:12px;font-weight:bold;"><a href="http://boingboing.net/2014/04/09/tom-the-dancing-bug-learning.html" style="color:#C00">Tom the Dancing Bug</a></p>
423
+ <p style="margin: 0px;font-size:13px;line-height:1"><a href="http://boingboing.net/2014/04/09/tom-the-dancing-bug-learning.html">TOM THE DANCING BUG: Learning Big News on Twitter, Through the&nbsp;Ages</a>
424
+
425
+ </div>
426
+
427
+ <div class="features-item">
428
+
429
+ <a href="http://boingboing.net/2014/04/08/brain-rot-hip-hop-family-tree-97.html"><img class="sidebarThumb" src="http://media.boingboing.net/wp-content/uploads/2014/04/hip-hop-strip-99-thumb.jpg"></a>
430
+
431
+ <p style="margin:0px 0px 3px 0px;text-transform:uppercase;font-size:12px;font-weight:bold;"><a href="http://boingboing.net/2014/04/08/brain-rot-hip-hop-family-tree-97.html" style="color:#C00">Brain Rot</a></p>
432
+ <p style="margin: 0px;font-size:13px;line-height:1"><a href="http://boingboing.net/2014/04/08/brain-rot-hip-hop-family-tree-97.html">Brain Rot: Hip Hop Family Tree, The Infamous Style Wars Film&nbsp;Screening</a>
433
+
434
+ </div>
435
+
436
+ <div class="features-item">
437
+
438
+ <a href="http://boingboing.net/2014/04/02/tom-the-dancing-bug-hobby-lob.html"><img class="sidebarThumb" src="http://media.boingboing.net/wp-content/uploads/2014/04/1182cbTHUMB-news-hobby-lobby.jpg"></a>
439
+
440
+ <p style="margin:0px 0px 3px 0px;text-transform:uppercase;font-size:12px;font-weight:bold;"><a href="http://boingboing.net/2014/04/02/tom-the-dancing-bug-hobby-lob.html" style="color:#C00">Tom the Dancing Bug</a></p>
441
+ <p style="margin: 0px;font-size:13px;line-height:1"><a href="http://boingboing.net/2014/04/02/tom-the-dancing-bug-hobby-lob.html">TOM THE DANCING BUG: Hobby Lobby, Inc., Changes Its&nbsp;Religion</a>
442
+
443
+ </div>
444
+
445
+ </div>
446
+
447
+
448
+ <p id="featuretitle">&mdash; RECENTLY &mdash;
449
+
450
+ <div id="features" >
451
+ <div class="features-item">
452
+
453
+ <a href="http://boingboing.net/2014/04/10/a-canticle-for-leibowitz-vene.html"><img class="sidebarThumb" style="margin-top:2px;" src="http://media.boingboing.net/wp-content/uploads/2014/04/Screen-Shot-2014-04-10-at-8.49.13-AM.png"></a>
454
+
455
+ <p style="margin:0px 0px 3px 0px;text-transform:uppercase;font-size:12px;font-weight:bold;"><a href="http://boingboing.net/2014/04/10/a-canticle-for-leibowitz-vene.html" style="color:#C00">Book Review</a></p>
456
+ <p style="margin: 0px;font-size:13px;line-height:1"><a href="http://boingboing.net/2014/04/10/a-canticle-for-leibowitz-vene.html">A Canticle for Leibowitz, venerated science fiction&nbsp;masterpiece</a>
457
+
458
+
459
+ </div>
460
+
461
+ <div class="features-item">
462
+
463
+ <a href="http://boingboing.net/2014/04/08/the-adjacent-by-christopher-p.html"><img class="sidebarThumb" style="margin-top:2px;" src="http://media.boingboing.net/wp-content/uploads/2014/04/christpherpreist.jpg"></a>
464
+
465
+ <p style="margin:0px 0px 3px 0px;text-transform:uppercase;font-size:12px;font-weight:bold;"><a href="http://boingboing.net/2014/04/08/the-adjacent-by-christopher-p.html" style="color:#C00">Review</a></p>
466
+ <p style="margin: 0px;font-size:13px;line-height:1"><a href="http://boingboing.net/2014/04/08/the-adjacent-by-christopher-p.html">The Adjacent, by Christopher Priest [exclusive&nbsp;excerpt]</a>
467
+
468
+
469
+ </div>
470
+
471
+ <div class="features-item">
472
+
473
+ <a href="http://boingboing.net/2014/04/08/the-unthinkable-blooms-on-hann.html"><img class="sidebarThumb" style="margin-top:2px;" src="http://media.boingboing.net/wp-content/uploads/2014/04/hanth.jpg"></a>
474
+
475
+ <p style="margin:0px 0px 3px 0px;text-transform:uppercase;font-size:12px;font-weight:bold;"><a href="http://boingboing.net/2014/04/08/the-unthinkable-blooms-on-hann.html" style="color:#C00">Recap</a></p>
476
+ <p style="margin: 0px;font-size:13px;line-height:1"><a href="http://boingboing.net/2014/04/08/the-unthinkable-blooms-on-hann.html">The unthinkable blooms on Hannibal "Futomono"&nbsp;[s2,e6]</a>
477
+
478
+
479
+ </div>
480
+
481
+ <div class="features-item">
482
+
483
+ <a href="http://boingboing.net/2014/04/08/doubleclicks-celebrate-the-pap.html"><img class="sidebarThumb" style="margin-top:2px;" src="http://media.boingboing.net/wp-content/uploads/2014/04/mqdefault6.jpg"></a>
484
+
485
+ <p style="margin:0px 0px 3px 0px;text-transform:uppercase;font-size:12px;font-weight:bold;"><a href="http://boingboing.net/2014/04/08/doubleclicks-celebrate-the-pap.html" style="color:#C00">Science</a></p>
486
+ <p style="margin: 0px;font-size:13px;line-height:1"><a href="http://boingboing.net/2014/04/08/doubleclicks-celebrate-the-pap.html">Doubleclicks celebrate the paperback of Scatter, Adapt, and Remember with a new&nbsp;song</a>
487
+
488
+
489
+ </div>
490
+
491
+ <div class="features-item">
492
+
493
+ <a href="http://boingboing.net/2014/04/07/restoring-cc-attribution-to-fl.html"><img class="sidebarThumb" style="margin-top:2px;" src="http://media.boingboing.net/wp-content/uploads/2014/04/nohotlinking63.jpg"></a>
494
+
495
+ <p style="margin:0px 0px 3px 0px;text-transform:uppercase;font-size:12px;font-weight:bold;"><a href="http://boingboing.net/2014/04/07/restoring-cc-attribution-to-fl.html" style="color:#C00">Feature</a></p>
496
+ <p style="margin: 0px;font-size:13px;line-height:1"><a href="http://boingboing.net/2014/04/07/restoring-cc-attribution-to-fl.html">Restoring CC attribution to Flickr, because Yahoo broke&nbsp;it</a>
497
+
498
+
499
+ </div>
500
+
501
+
502
+ </div>
503
+
504
+ <div class="sidebar_item">
505
+
506
+ <iframe id="ad_t-shirts_frame" src="http://media.boingboing.net/wp-content/themes/2012/ads/ad_t-shirts.html?v=1" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" topmargin="0" leftmargin="0" allowtransparency="true" width="300px" height="300px"> </iframe>
507
+
508
+ </div>
509
+
510
+
511
+
512
+
513
+
514
+
515
+ <div id="ad_skyscraper" style="">
516
+ <div class="sidebar_item">
517
+ <!-- FM Wide Skyscraper 1 Zone -->
518
+ <iframe src="http://boingboing.net/wp-content/themes/2012/ads/ad_skyscraper.html?fm_url=http://boingboing.net/2014/04/13/tick-tick-tick.html&fm_custom_kvs=category%3Dpost" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" topmargin="0" leftmargin="0" allowtransparency="true" width="160px" height="600px"> </iframe>
519
+ <!-- FM Wide Skyscraper 1 Zone -->
520
+ </div>
521
+ </div>
522
+ </div>
523
+
524
+ <p id="featuretitle">&mdash; FOLLOW US &mdash;
525
+ <p style="text-align:center;"><small>Find us on <a href="http://twitter.com/boingboing">Twitter</a>, <a href="https://plus.google.com/+BoingBoing" rel="publisher">Google+</a>, <a href="irc://irc.freenode.net/boingboing">IRC</a>, and <a href="http://facebook.com/boingboing">Facebook</a>. Subscribe to our <a href="http://feeds.boingboing.net/boingboing/iBag">RSS feed</a> or <a href="http://boingboing.us2.list-manage.com/subscribe?u=0e91f8e7df61da4bff2bd9b1f&id=fa324756a4">daily email</a>.</small>
526
+ <p>&nbsp;
527
+
528
+ <p id="featuretitle">&mdash; POLICIES &mdash;
529
+ <p style="text-align:center;"><small>Please read our <a href="http://boingboing.net/tos">Terms of Service</a>, <a href="http://boingboing.net/privacy">Privacy Policy</a>, and <a href="http://boingboing.net/community">Community Guidelines</a>. Except where indicated, Boing Boing is licensed under a Creative&nbsp;Commons License permitting <a href="http://creativecommons.org/licenses/by-nc/2.5/">non-commercial sharing with attribution</a></small>
530
+
531
+ <p>&nbsp;
532
+ <p id="featuretitle">&mdash; FONTS &mdash;
533
+ <p style="text-align:center;"><a href="https://typekit.com"><img src="http://media.boingboing.net/wp-content/uploads/2013/04/typekit-logo.jpg"></a>
534
+
535
+ <!--[if !IE]> -->
536
+ </noscript>
537
+ <!-- <![endif]-->
538
+ </div>
539
+ </div>
540
+
541
+
542
+ </div>
543
+
544
+
545
+ <!-- MAIN POST -->
546
+
547
+ <div id="posts-loop">
548
+
549
+ <div id="post-297258" class="post">
550
+
551
+
552
+
553
+
554
+
555
+ <!-- SHARING BUTTONS -->
556
+ <div id="sidebarPinPoint" style="height:0px;">
557
+ </div>
558
+ <div id="sidebarsticky">
559
+ <div style="" id="newShareBox">
560
+ <div class="sharebutton">
561
+ <div id="fb-root"></div>
562
+ <script>(function(d, s, id) {
563
+ var js, fjs = d.getElementsByTagName(s)[0];
564
+ if (d.getElementById(id)) return;
565
+ js = d.createElement(s); js.id = id;
566
+ js.src = "//connect.facebook.net/en_US/all.js#xfbml=1&appId=403820626333734";
567
+ fjs.parentNode.insertBefore(js, fjs);
568
+ }(document, 'script', 'facebook-jssdk'));</script>
569
+ <div class="fb-like" data-href="http://boingboing.net/2014/04/13/tick-tick-tick.html" data-send="false" data-layout="box_count" data-width="90" data-show-faces="false"></div>
570
+ </div>
571
+
572
+ <div class="sharebutton">
573
+ <a href="https://twitter.com/share" class="twitter-share-button" data-via="BoingBoing" data-count="vertical">Tweet</a>
574
+ <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
575
+ </div>
576
+
577
+ <div class="sharebutton">
578
+ <!-- Place this tag where you want the su badge to render -->
579
+ <su:badge layout="5"></su:badge>
580
+
581
+ <!-- Place this snippet wherever appropriate -->
582
+ <script type="text/javascript">
583
+ (function() {
584
+ var li = document.createElement('script'); li.type = 'text/javascript'; li.async = true;
585
+ li.src = ('https:' == document.location.protocol ? 'https:' : 'http:') + '//platform.stumbleupon.com/1/widgets.js';
586
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(li, s);
587
+ })();
588
+ </script>
589
+ </div>
590
+
591
+ <div class="sharebutton">
592
+ <!-- Place this tag where you want the +1 button to render. -->
593
+ <div class="g-plusone" data-size="tall"></div>
594
+
595
+ <!-- Place this tag after the last +1 button tag. -->
596
+ <script type="text/javascript">
597
+ (function() {
598
+ var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
599
+ po.src = 'https://apis.google.com/js/plusone.js';
600
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
601
+ })();
602
+ </script>
603
+ </div>
604
+
605
+ <div class="sharebutton">
606
+ <div class='kindleWidget kindleLight' style='font-family: sans-serif;'><img src="http://media.boingboing.net/wp-content/plugins/sendtokindle/media/white-15.png" /><span>Kindle</span></div> </div>
607
+ </div>
608
+ </div>
609
+ <div class="post-content sharebuttons">
610
+
611
+ <!-- CONTENT OF THE POST -->
612
+
613
+ <p>
614
+ <img src="http://media.boingboing.net/wp-content/uploads/2014/04/tumblr_n3wstblgoN1socbkko1_5001-300x300.gif" original="http://media.boingboing.net/wp-content/uploads/2014/04/tumblr_n3wstblgoN1socbkko1_5001.gif" mobile="http://media.boingboing.net/wp-content/uploads/2014/04/tumblr_n3wstblgoN1socbkko1_5001-300x300.gif" class="bordered"><br />
615
+ No idea who made this, but it's wonderful. If you know, post in the comments, please.
616
+
617
+ <p>
618
+ <b>Update:</b> It's from <a href="http://beesandbombs.tumblr.com/post/82429759407/this-is-a-bees-bombs-original-accept-no">Bees and Bombs</a>, to which I have just subscribed.
619
+
620
+ <!-- METADATA AND COMMENTS -->
621
+ <div id="metadataBox">
622
+
623
+ <!-- PODCAST EMBEDS/LINKS, IF APPLICABLE -->
624
+
625
+
626
+
627
+
628
+
629
+
630
+ <!-- AUTHOR INFORMATION -->
631
+
632
+ <div id="authorbox">
633
+ <p><a href="http://craphound.com/homeland/buy"> <img src="http://craphound.com/images/homelandbio.jpg" class="bordered" align="left"></a>I write books. My latest is a YA science fiction novel called <a href="http://craphound.com/homeland">Homeland</a> (it's the sequel to <a href="http://craphound.com/littlebrother">Little Brother</a>). More books: <a href="http://craphound.com/rotn">Rapture of the Nerds</a> (a novel, with Charlie Stross); <a href="http://craphound.com/walh">With a Little Help</a> (short stories); and <a href="http://craphound.com/gbbt">The Great Big Beautiful Tomorrow</a> (novella and nonfic). I <a href="https://craphound.com/?page_id=4667">speak all over the place</a> and I <a href="https://twitter.com/doctorow">tweet</a> and <a href="http://mostlysignssomeportents.tumblr.com/">tumble</a>, too. </div>
634
+
635
+ <!-- TAGS -->
636
+
637
+ <div id="tagbox">
638
+ <p>MORE:&nbsp; <a href="http://boingboing.net/tag/animation" rel="tag">animation</a></p>
639
+ </div>
640
+
641
+
642
+
643
+
644
+ <!-- MORE AT BOING BOING from FEATURES -->
645
+
646
+ <div id="moreatboingboing">
647
+
648
+ <h3>More at Boing Boing</h3>
649
+
650
+
651
+
652
+ <div class="moreitem">
653
+ <p><a href="http://boingboing.net/2014/04/13/tv-recap-game-of-thrones-th.html?utm_campaign=moreatbbmetadata&utm_medium=referral&utm_source=boingboing.net" rel="bookmark"><img class="bordered" src="http://media.boingboing.net/wp-content/uploads/2014/04/gotth1.jpg"></a>
654
+
655
+ <p><a href="http://boingboing.net/2014/04/13/tv-recap-game-of-thrones-th.html?utm_campaign=moreatbbmetadata&utm_medium=referral&utm_source=boingboing.net" rel="bookmark">TV recap: Game Of Thrones 'The Lion And The Rose' [season 4, episode&nbsp;2]</a></p>
656
+ </div>
657
+
658
+
659
+
660
+ <div class="moreitem">
661
+ <p><a href="http://boingboing.net/2014/04/08/the-unthinkable-blooms-on-hann.html?utm_campaign=moreatbbmetadata&utm_medium=referral&utm_source=boingboing.net" rel="bookmark"><img class="bordered" src="http://media.boingboing.net/wp-content/uploads/2014/04/hanth.jpg"></a>
662
+
663
+ <p><a href="http://boingboing.net/2014/04/08/the-unthinkable-blooms-on-hann.html?utm_campaign=moreatbbmetadata&utm_medium=referral&utm_source=boingboing.net" rel="bookmark">The unthinkable blooms on Hannibal "Futomono"&nbsp;[s2,e6]</a></p>
664
+ </div>
665
+
666
+
667
+ </div>
668
+
669
+ <div id="ad_500">
670
+ <noscript id="ad_500_noscript">
671
+ <script type="text/javascript">
672
+ function convosuiteLabeling(){
673
+ console.log('convosuiteLabeling');
674
+ google_ad_500_code = "<center><iframe src='http://media.boingboing.net/wp-content/themes/2012/ads/ad_google_rect.html' width='410' height='290' scrolling='no' frameborder='no' style='margin:0;'></iframe><center>";
675
+
676
+ $('#ad_500').css('border-top', '1px solid #CCC');
677
+ $('#ad_500').css('border-bottom', '1px solid #CCC');
678
+ $('#ad_500').css('margin-bottom', '20px');
679
+ $('#ad_500').css('margin-top', '40px');
680
+ $('#ad_500_label').show();
681
+
682
+ if($('#ad_500').height() < 50){
683
+ $('#convosuite_ad').hide();
684
+ $('#google_ad_500').append(google_ad_500_code);
685
+ console.log('Appending google ad code: '+google_ad_500_code);
686
+ }
687
+ }
688
+ $(document).ready(function(){
689
+ // convosuiteLabeling();
690
+ setTimeout('convosuiteLabeling();', 3000);
691
+ });
692
+ </script>
693
+ <style type="text/css">
694
+ .fm-cs-ad {
695
+ margin:18px 0px 18px 0px !important;
696
+ max-width:514px;
697
+ }
698
+ </style>
699
+ <div id="ad_500_label" style="display:none;margin-top:-22px;text-align:center;font-family: 'proxima-nova-condensed', 'Helvetica Neue', Arial, sans-serif;color: #666;">ADVERTISEMENT</div>
700
+ <div id="convosuite_ad">
701
+ <!-- FM Convosuite 650x300 Zone -->
702
+ <script type='text/javascript' src='http://static.fmpub.net/zone/7234'></script>
703
+ <!-- FM Convosuite 650x300 Zone -->
704
+ </div>
705
+ <div id="google_ad_500"></div>
706
+ </noscript>
707
+ <script type="text/javascript">
708
+ if($('#ad_500').is(':visible')) {
709
+ console.debug('Populating desktop 500 spot with document.write');
710
+ document.write($('#ad_500_noscript').text());
711
+ }
712
+ </script>
713
+ </div>
714
+
715
+
716
+
717
+ </div>
718
+
719
+ <div id="comments-container">
720
+
721
+ <div id="comments">
722
+
723
+ <div class="respond">
724
+ <h3 class="reply-title"><a href="http://bbs.boingboing.net/t/tick-tick-tick/28470">Continue the discussion</a> at bbs.boingboing.net</h3>
725
+ <p class='more-replies'>22 replies</p>
726
+ <p>
727
+ <img alt="" src="//www.gravatar.com/avatar/bdd2b71f7e0f6b5e4e2fdf809cd8e3dc.png?s=25&r=pg&d=identicon" class="avatar avatar-25 photo avatar-default" height="25" width="25">
728
+ <img alt="" src="//scdn-discourse.r.worldssl.net/uploads/boingboing/avatars/ce6/573/7c77555a28/25.JPG" class="avatar avatar-25 photo avatar-default" height="25" width="25">
729
+ <img alt="" src="//scdn-discourse.r.worldssl.net/uploads/boingboing/avatars/d13/c17/ebaa887f16/25.jpg" class="avatar avatar-25 photo avatar-default" height="25" width="25">
730
+ <img alt="" src="//www.gravatar.com/avatar/dd477586d6b8bb0b5e25838985ed24cb.png?s=25&r=pg&d=identicon" class="avatar avatar-25 photo avatar-default" height="25" width="25">
731
+ <img alt="" src="//scdn-discourse.r.worldssl.net/uploads/boingboing/avatars/bfe/e7a/10ea6f18f4/25.jpg" class="avatar avatar-25 photo avatar-default" height="25" width="25">
732
+ <img alt="" src="//scdn-discourse.r.worldssl.net/uploads/boingboing/avatars/859/95b/fef8e18140/25.jpg" class="avatar avatar-25 photo avatar-default" height="25" width="25">
733
+ <img alt="" src="//scdn-discourse.r.worldssl.net/uploads/boingboing/avatars/9c9/c8d/983343ab8b/25.jpg" class="avatar avatar-25 photo avatar-default" height="25" width="25">
734
+ <img alt="" src="//scdn-discourse.r.worldssl.net/uploads/boingboing/avatars/dbd/003/583512792e/25.jpg" class="avatar avatar-25 photo avatar-default" height="25" width="25">
735
+ <img alt="" src="//www.gravatar.com/avatar/54052b273cc682b884d2f6151faf8207.png?s=25&r=pg&d=identicon" class="avatar avatar-25 photo avatar-default" height="25" width="25">
736
+ <img alt="" src="//www.gravatar.com/avatar/297418cf750e0c88035cf26cb430111a.png?s=25&r=pg&d=identicon" class="avatar avatar-25 photo avatar-default" height="25" width="25">
737
+ <img alt="" src="//www.gravatar.com/avatar/c1c83f628971c4bd7fc0be6e92ebdc42.png?s=25&r=pg&d=identicon" class="avatar avatar-25 photo avatar-default" height="25" width="25">
738
+ <img alt="" src="//www.gravatar.com/avatar/90ab94a6731be923785e4229028c1a86.png?s=25&r=pg&d=identicon" class="avatar avatar-25 photo avatar-default" height="25" width="25">
739
+ <img alt="" src="//www.gravatar.com/avatar/98bbaa880662d351e021d2f5fb5e40fe.png?s=25&r=pg&d=identicon" class="avatar avatar-25 photo avatar-default" height="25" width="25">
740
+ <img alt="" src="//www.gravatar.com/avatar/b82895a8423e72e133b679d4911045a7.png?s=25&r=pg&d=identicon" class="avatar avatar-25 photo avatar-default" height="25" width="25">
741
+ <img alt="" src="//www.gravatar.com/avatar/899a8a98c0788669af2ca0faba0d12d1.png?s=25&r=pg&d=identicon" class="avatar avatar-25 photo avatar-default" height="25" width="25">
742
+ <img alt="" src="//www.gravatar.com/avatar/f56c317566802c0d69809e2147507d38.png?s=25&r=pg&d=identicon" class="avatar avatar-25 photo avatar-default" height="25" width="25">
743
+ <img alt="" src="//scdn-discourse.r.worldssl.net/uploads/boingboing/avatars/88a/a82/211f2d102d/25.jpg" class="avatar avatar-25 photo avatar-default" height="25" width="25">
744
+ <img alt="" src="//www.gravatar.com/avatar/78d185ccd8b98d3b38f1e4a2ca88796c.png?s=25&r=pg&d=identicon" class="avatar avatar-25 photo avatar-default" height="25" width="25">
745
+ <img alt="" src="//www.gravatar.com/avatar/749e54555e08d2831cdfc817bbcd99dd.png?s=25&r=pg&d=identicon" class="avatar avatar-25 photo avatar-default" height="25" width="25">
746
+ </p>
747
+ </div><!-- #respond -->
748
+
749
+ </div>
750
+ </div>
751
+ </div>
752
+
753
+ </div>
754
+ </div>
755
+
756
+
757
+ <div style="text-align:center;margin-top:25px;">
758
+
759
+ </div>
760
+ <div style="clear:both;"></div>
761
+ </div>
762
+
763
+
764
+
765
+ <p style="clear:both;">
766
+ </div>
767
+
768
+
769
+
770
+ <div id="debugger"></div>
771
+
772
+ <!-- Sitewide javascript -->
773
+ <script type="text/javascript" src="http://media.boingboing.net/wp-content/themes/2012/boingboing.js?v=7"></script>
774
+ <!-- JK Nav by Yu-Jie Lin -->
775
+ <script src="http://media.boingboing.net/wp-content/themes/2012/jquery.jknav.min.js?v=1"></script>
776
+ <!-- Infinite Scroll -->
777
+ <script type="text/javascript" src="http://media.boingboing.net/wp-content/themes/2012/infinitescroll.init.js?v=9"> </script>
778
+
779
+ <!-- Google Plus -->
780
+ <script type="text/javascript">
781
+ (function() {
782
+ var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
783
+ po.src = 'https://apis.google.com/js/plusone.js';
784
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
785
+ })();
786
+ </script>
787
+
788
+
789
+ <!-- Disqus javascript -->
790
+ <script type="text/javascript">
791
+ var disqus_shortname = 'boingboing'; // required: replace example with your forum shortname
792
+ /* * * DON'T EDIT BELOW THIS LINE * * */
793
+ (function () {
794
+ var s = document.createElement('script'); s.async = true;
795
+ s.type = 'text/javascript';
796
+ s.src = 'http://' + disqus_shortname + '.disqus.com/count.js';
797
+ (document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
798
+ }());
799
+ </script>
800
+
801
+ <!-- Day We Fight Back campaign -->
802
+ <!--[if !(lte IE 8)]><!-->
803
+ <script type="text/javascript">
804
+ (function(){var e=document.createElement("script");e.type="text/javascript";e.async=true;e.src=document.location.protocol+"//d1agz031tafz8n.cloudfront.net/thedaywefightback.js/widget.min.js";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t)})()
805
+ </script>
806
+ <!--<![endif]-->
807
+
808
+ <!-- Analytics-->
809
+ <!-- FM Tracking Pixel -->
810
+ <script type='text/javascript' src='http://static-cf.fmpub.net/site/boingboing'></script>
811
+ <!-- FM Tracking Pixel -->
812
+
813
+ <!-- Mint internal analytics include -->
814
+ <script src="http://mint.boingboing.net/?js" type="text/javascript"></script>
815
+
816
+ <!-- Google Analytics include -->
817
+ <script type="text/javascript">
818
+
819
+ var _gaq = _gaq || [];
820
+ _gaq.push(['_setAccount', 'UA-3839311-1']);
821
+ <!-- Categories -->
822
+ _gaq.push(['_trackEvent', 'Permalink View', 'Category', 'Post']);
823
+
824
+ <!-- Tags -->
825
+ _gaq.push(['_trackEvent', 'Permalink View', 'Tag', 'animation']);
826
+
827
+ _gaq.push(['_setCustomVar', 1, 'MTAuthor', 'Cory Doctorow', 3]);
828
+ _gaq.push(['_trackEvent', 'Permalink View', 'Author', 'Cory Doctorow']);
829
+ _gaq.push(['_trackPageview']);
830
+
831
+ (function() {
832
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
833
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
834
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
835
+ })();
836
+
837
+ </script>
838
+ <!-- end Google Analytics include -->
839
+
840
+ <!-- Blockmetrics include -->
841
+ <script type="text/javascript">
842
+ (function() {
843
+ function async_load(){
844
+ var protocol = ('https:' == document.location.protocol ? 'https://' : 'http://');
845
+ var s = document.createElement('script');
846
+ s.src = protocol + 'blockmetrics.com/static/adblock_detection/js/d.min.js';
847
+ var x = document.getElementsByTagName('script')[0]; x.parentNode.insertBefore(s, x);
848
+ }
849
+ bm_website_code = 'D3D06F828B4511E2';
850
+ jQuery(document).ready(async_load);
851
+ })();
852
+ </script>
853
+ <!-- end Blockmetrics include -->
854
+ <!-- Ads -->
855
+ <div id="ads">
856
+
857
+ <!-- FM AD SKIN Zone -->
858
+ <script type='text/javascript' src='http://static-cf.fmpub.net/zone/3992'></script>
859
+ <!-- FM AD SKIN Zone -->
860
+
861
+ </div>
862
+
863
+
864
+
865
+ </body>
866
+ </html>
867
+
868
+ <div style="clear:both;"></div>
869
+
870
+ </div> <!-- Ends container DIV -->
871
+
872
+
873
+
874
+ <!-- Dynamic page generated in 0.281 seconds. -->
875
+ <!-- Cached page generated by WP-Super-Cache on 2014-04-14 16:47:33 -->
876
+ <!-- super cache -->