murlsh 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -8,7 +8,7 @@ Site for sharing and archiving links.
8
8
  * embeds Flash mp3 player for mp3 urls
9
9
  * looks good on iPhone
10
10
  * PubSubHubbub notification
11
- * plug-in interface
11
+ * plugin interface
12
12
  * rack interface
13
13
  * Gravatar support
14
14
 
@@ -22,6 +22,8 @@ h1. Installation
22
22
 
23
23
  h2. Phusion Passenger
24
24
 
25
+ DESTINATION_DIRECTORY is the web directory to install the murlsh site to.
26
+
25
27
  <pre>
26
28
  <code>
27
29
  gem sources -a http://gemcutter.org/
@@ -33,6 +35,36 @@ rake init
33
35
  </code>
34
36
  </pre>
35
37
 
38
+ h1. Updating
39
+
40
+ If you are using the gem and it gets updated to a new version you should run
41
+ the murlsh command again from your web directory to update plugins, javascript
42
+ and css. It will prompt before overwriting anything in case you have made
43
+ modifications.
44
+
45
+ h1. Plugins
46
+
47
+ Classes in the plugins directory can be used to change behavior at certain
48
+ points. Each class that extends Murlsh::Plugin and sets an instance variable
49
+ called @hook will be called for that hook. Each plugin has a run() method that
50
+ accepts arguments and returns something. These methods will be called in the
51
+ order of their class names sorted lexically. Some hooks pass the output of their
52
+ run() method to the next plugin for that hook so that the data can be passed
53
+ through a chain of methods that each do something to it.
54
+
55
+ A lot of the standard behavior is implemented as plugins. See the plugins
56
+ directory for examples.
57
+
58
+ Plugin hooks
59
+
60
+ |Hook|Description|run() arguments|Returns|
61
+ |add_pre|called before a new url is saved|url, config hash|undefined|
62
+ |add_post|called after a new url is saved|config hash|undefined|
63
+ |hostrec|post process the domain that is shown after links|domain, url, title|text to display|
64
+ |html_parse|parse HTML using something like Hpricot or Nokogiri|parseable|parsed HTML, only first plugin is run (cannot be chained)|
65
+ |time|convert the time of a post into a string for display|time|time display text|
66
+ |via|convert a via url into a string for display|via url|via url display text|
67
+
36
68
  h1. PubSubHubbub
37
69
 
38
70
  Murlsh can notify "PubSubHubbub":http://code.google.com/p/pubsubhubbub/ hubs
@@ -52,11 +84,4 @@ subscribe_url is what gets put in the feed as link rel="hub"
52
84
 
53
85
  This will make updates to your feed show up in Google Reader instantly.
54
86
 
55
- h1. Updating
56
-
57
- If you are using the gem and it gets updated to a new version you should run
58
- the murlsh command again from your web directory to update plugins, javascript
59
- and css. It will prompt before overwriting anything in case you have made
60
- modifications.
61
-
62
87
  Questions and comments: "matthewm@boedicker.org":mailto:matthewm@boedicker.org
data/Rakefile CHANGED
@@ -154,23 +154,47 @@ namespace :user do
154
154
 
155
155
  end
156
156
 
157
- desc "Validate XHTML."
158
- task :validate do
159
- net_http = Net::HTTP.new('validator.w3.org', 80)
160
- #net_http.set_debug_output(STDOUT)
161
-
162
- check_url = config.fetch('root_url')
163
-
164
- print "validating #{check_url} : "
157
+ # Validate a document with the W3C validation service.
158
+ def validate(check_url, options={})
159
+ opts = {
160
+ :validator_host => 'validator.w3.org',
161
+ :validator_port => 80,
162
+ :validator_path =>
163
+ "/check?uri=#{CGI::escape(check_url)}&charset=(detect+automatically)&doctype=Inline&group=0",
164
+ }.merge(options)
165
+
166
+ net_http = Net::HTTP.new(opts[:validator_host], opts[:validator_port])
167
+ # net_http.set_debug_output(STDOUT)
165
168
 
166
169
  net_http.start do |http|
167
- resp = http.request_head(
168
- "/check?uri=#{CGI::escape(check_url)}&charset=(detect+automatically)&doctype=Inline&group=0")
169
- result = resp['X-W3C-Validator-Status']
170
- errors = resp['X-W3C-Validator-Errors']
171
- warnings = resp['X-W3C-Validator-Warnings']
170
+ resp = http.request_head(opts[:validator_path])
171
+ result = {
172
+ :response => resp
173
+ }
174
+ if Net::HTTPSuccess === resp
175
+ result.merge!(
176
+ :status => resp['X-W3C-Validator-Status'],
177
+ :errors => resp['X-W3C-Validator-Errors'],
178
+ :warnings => resp['X-W3C-Validator-Warnings']
179
+ )
180
+ end
181
+ result
182
+ end
172
183
 
173
- puts "#{result} (#{errors} errors, #{warnings} warnings)"
184
+ end
185
+
186
+ namespace :validate do
187
+
188
+ desc 'Validate XHTML.'
189
+ task :xhtml do
190
+ check_url = config['root_url']
191
+ print "validating #{check_url} : "
192
+ result = validate(check_url)
193
+ if Net::HTTPSuccess === result[:response]
194
+ puts "#{result[:status]} (#{result[:errors]} errors, #{result[:warnings]} warnings)"
195
+ else
196
+ puts result[:response]
197
+ end
174
198
  end
175
199
 
176
200
  end
@@ -294,6 +318,9 @@ begin
294
318
  gemspec.authors = ['Matthew M. Boedicker']
295
319
  gemspec.executables = %w{murlsh}
296
320
 
321
+ # gemspec.signing_key = '/home/mmb/src/keys/gem-private_key.pem'
322
+ # gemspec.cert_chain = %w{/home/mmb/src/keys/gem-public_cert.pem}
323
+
297
324
  %w{
298
325
  activerecord 2.3.4
299
326
  bcrypt-ruby 2.1.2
@@ -301,6 +328,7 @@ begin
301
328
  hpricot 0.8.1
302
329
  htmlentities 4.2.0
303
330
  json 1.2.3
331
+ push-notify 0.1.0
304
332
  rack 1.0.0
305
333
  rack-cache 0.5.2
306
334
  rack-throttle 0.3.0
@@ -310,5 +338,5 @@ begin
310
338
 
311
339
  end
312
340
  rescue LoadError
313
- puts 'Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com'
341
+ puts "Jeweler not available. Install it with: gem install jeweler"
314
342
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.0
1
+ 0.10.0
data/config.yaml CHANGED
@@ -1,7 +1,11 @@
1
1
  ---
2
+ apple_icon_hosts: []
3
+
2
4
  auth_file: murlsh_users
3
5
  cache_entitystore: file:tmp/cache/rack/body
4
6
  cache_metastore: file:tmp/cache/rack/meta
7
+ config_js:
8
+ - apple_icon_hosts
5
9
  css_files:
6
10
  - css/jquery.jgrowl.css
7
11
  - css/screen.css
@@ -0,0 +1,32 @@
1
+ %w{
2
+ digest/sha1
3
+
4
+ json
5
+ rack
6
+ }.each { |m| require m }
7
+
8
+ module Murlsh
9
+
10
+ # Serve a JSON subset of the configuration.
11
+ #
12
+ # Will include all config keys contained in the config key named config_js.
13
+ class ConfigServer
14
+
15
+ def initialize(config)
16
+ @config_json =
17
+ config.reject { |k,v| !config.fetch('config_js', []).
18
+ include?(k) }.to_json
19
+
20
+ @headers = {
21
+ 'Content-Type' => 'application/json',
22
+ 'ETag' => "\"#{Digest::SHA1.hexdigest(@config_json)}\"",
23
+ 'Last-Modified' => Time.now.httpdate
24
+ }
25
+ end
26
+
27
+ # Serve a JSON subset of the configuration.
28
+ def get(req); Rack::Response.new(@config_json, 200, @headers); end
29
+
30
+ end
31
+
32
+ end
@@ -20,6 +20,7 @@ module Murlsh
20
20
  db = ActiveRecord::Base.connection.instance_variable_get(:@connection)
21
21
 
22
22
  url_server = Murlsh::UrlServer.new(@config, db)
23
+ config_server = Murlsh::ConfigServer.new(@config)
23
24
  flickr_server = Murlsh::FlickrServer.new(@config)
24
25
  twitter_server = Murlsh::TwitterServer.new
25
26
 
@@ -28,8 +29,9 @@ module Murlsh
28
29
  @dispatch = [
29
30
  [%r{^GET #{root_path}(url)?$}, url_server.method(:get)],
30
31
  [%r{^POST #{root_path}(url)?$}, url_server.method(:post)],
31
- [%r{^GET /flickr$}, flickr_server.method(:get)],
32
- [%r{^GET /twitter/.+$}, twitter_server.method(:get)],
32
+ [%r{^GET #{root_path}config$}, config_server.method(:get)],
33
+ [%r{^GET #{root_path}flickr$}, flickr_server.method(:get)],
34
+ [%r{^GET #{root_path}twitter/.+$}, twitter_server.method(:get)],
33
35
  ]
34
36
  end
35
37
 
data/murlsh.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{murlsh}
8
- s.version = "0.9.0"
8
+ s.version = "0.10.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Matthew M. Boedicker"]
12
- s.date = %q{2010-06-03}
12
+ s.date = %q{2010-08-05}
13
13
  s.default_executable = %q{murlsh}
14
14
  s.description = %q{url sharing site framework with easy adding, title lookup, atom feed, thumbnails and embedding}
15
15
  s.email = %q{matthewm@boedicker.org}
@@ -29,6 +29,7 @@ Gem::Specification.new do |s|
29
29
  "config.yaml",
30
30
  "lib/murlsh.rb",
31
31
  "lib/murlsh/auth.rb",
32
+ "lib/murlsh/config_server.rb",
32
33
  "lib/murlsh/dispatch.rb",
33
34
  "lib/murlsh/doc.rb",
34
35
  "lib/murlsh/etag_add_encoding.rb",
@@ -63,6 +64,7 @@ Gem::Specification.new do |s|
63
64
  "plugins/via_50_domain.rb",
64
65
  "public/css/jquery.jgrowl.css",
65
66
  "public/css/screen.css",
67
+ "public/js/comments.json",
66
68
  "public/js/jquery-1.4.2.min.js",
67
69
  "public/js/jquery.jgrowl_compressed.js",
68
70
  "public/js/js.js",
@@ -107,6 +109,7 @@ Gem::Specification.new do |s|
107
109
  s.add_runtime_dependency(%q<hpricot>, [">= 0.8.1"])
108
110
  s.add_runtime_dependency(%q<htmlentities>, [">= 4.2.0"])
109
111
  s.add_runtime_dependency(%q<json>, [">= 1.2.3"])
112
+ s.add_runtime_dependency(%q<push-notify>, [">= 0.1.0"])
110
113
  s.add_runtime_dependency(%q<rack>, [">= 1.0.0"])
111
114
  s.add_runtime_dependency(%q<rack-cache>, [">= 0.5.2"])
112
115
  s.add_runtime_dependency(%q<rack-throttle>, [">= 0.3.0"])
@@ -119,6 +122,7 @@ Gem::Specification.new do |s|
119
122
  s.add_dependency(%q<hpricot>, [">= 0.8.1"])
120
123
  s.add_dependency(%q<htmlentities>, [">= 4.2.0"])
121
124
  s.add_dependency(%q<json>, [">= 1.2.3"])
125
+ s.add_dependency(%q<push-notify>, [">= 0.1.0"])
122
126
  s.add_dependency(%q<rack>, [">= 1.0.0"])
123
127
  s.add_dependency(%q<rack-cache>, [">= 0.5.2"])
124
128
  s.add_dependency(%q<rack-throttle>, [">= 0.3.0"])
@@ -132,6 +136,7 @@ Gem::Specification.new do |s|
132
136
  s.add_dependency(%q<hpricot>, [">= 0.8.1"])
133
137
  s.add_dependency(%q<htmlentities>, [">= 4.2.0"])
134
138
  s.add_dependency(%q<json>, [">= 1.2.3"])
139
+ s.add_dependency(%q<push-notify>, [">= 0.1.0"])
135
140
  s.add_dependency(%q<rack>, [">= 1.0.0"])
136
141
  s.add_dependency(%q<rack-cache>, [">= 0.5.2"])
137
142
  s.add_dependency(%q<rack-throttle>, [">= 0.3.0"])
@@ -13,23 +13,14 @@ module Murlsh
13
13
  hubs = config.fetch('pubsubhubbub_hubs', [])
14
14
 
15
15
  unless hubs.empty?
16
- require 'eventmachine'
17
- require 'pubsubhubbub'
16
+ require 'push-notify'
18
17
 
19
18
  feed_url = URI.join(config['root_url'], config['feed_file'])
20
-
21
- hubs.each do |hub|
22
- EventMachine.run {
23
- pub = EventMachine::PubSubHubbub.new(hub['publish_url']).publish(
24
- feed_url)
25
-
26
- pub.callback { EventMachine.stop }
27
- pub.errback { EventMachine.stop }
28
- }
19
+ begin
20
+ PushNotify::Content.new(feed_url).tell(*hubs.map { |h| h['publish_url'] })
21
+ rescue Exception
29
22
  end
30
-
31
23
  end
32
-
33
24
  end
34
25
 
35
26
  end
@@ -12,6 +12,10 @@ img {
12
12
  width : 600px;
13
13
  }
14
14
 
15
+ ul.comments {
16
+ list-style-type : none;
17
+ }
18
+
15
19
  li {
16
20
  clear : both;
17
21
  float : left;
@@ -49,9 +53,6 @@ div.name {
49
53
  img.thumb, li object {
50
54
  float : left;
51
55
  margin-right : 10px;
52
- border : 1px solid #808080;
53
- -moz-border-radius : 5px;
54
- -webkit-border-radius : 5px;
55
56
  }
56
57
 
57
58
  img.thumb.twitter {
@@ -59,6 +60,11 @@ img.thumb.twitter {
59
60
  width : 48px;
60
61
  }
61
62
 
63
+ img.thumb.apple {
64
+ height : 48px;
65
+ width : 48px;
66
+ }
67
+
62
68
  span.host {
63
69
  color : #808080;
64
70
  font-family : monospace;
@@ -88,7 +94,7 @@ fieldset#add label {
88
94
  }
89
95
 
90
96
  a.feed {
91
- background-color : #fb9e3a;
97
+ background : #fb9e3a;
92
98
  border-top : 1px solid #fba141;
93
99
  border-right : 1px solid #bc4d04;
94
100
  border-bottom : 1px solid #bc4d04;
@@ -129,7 +135,7 @@ div.jGrowl div.jGrowl-closer {
129
135
  width : 290px;
130
136
  }
131
137
 
132
- #urls li {
138
+ #urls>li {
133
139
  overflow : hidden;
134
140
  border-bottom : 1px solid #ccc;
135
141
  }
@@ -0,0 +1,12 @@
1
+ {
2
+ "http://url/being/commented/on": [
3
+ {
4
+ "authorAvatar": "http://url/of/your/avatar/image",
5
+ "authorName": "yourname",
6
+ "authorUrl": "http://url/of/your/site",
7
+ "comment": "your comment",
8
+ "createdTime": 1275005075,
9
+ "updatedTime": 1275005075
10
+ },
11
+ ],
12
+ }
data/public/js/js.js CHANGED
@@ -1,347 +1,434 @@
1
- /*global $, window*/
1
+ /*global $, document, navigator, window*/
2
2
 
3
3
  "use strict";
4
4
 
5
- var Murlsh = {};
6
-
7
- Murlsh.img = function(src, text) {
8
- text = text || '';
9
- return $('<img />', {
10
- src : src,
11
- alt : text,
12
- title : text
13
- });
14
- };
5
+ var Murlsh = function (config, $, navigator, window) {
6
+ var my = {},
7
+ hrefRes = {
8
+ flickr :
9
+ /^http:\/\/(?:www\.)?flickr\.com\/photos\/[@\w\-]+?\/([\d]+)/i,
10
+ imageshack :
11
+ /^(http:\/\/img\d+\.imageshack\.us\/img\d+\/\d+\/\w+\.)(jpe?g|gif|png)$/i,
12
+ imgur :
13
+ /^(http:\/\/(?:i\.)?imgur\.com\/[a-z\d]+)(\.(?:jpe?g|gif|png))$/i,
14
+ mp3 :
15
+ /\.mp3$/i,
16
+ s3 :
17
+ /^(http:\/\/static\.mmb\.s3\.amazonaws\.com\/[\w\-]+\.)(jpe?g|gif|pdf|png)$/i,
18
+ twitter :
19
+ /^https?:\/\/twitter\.com\/\w+\/status(?:es)?\/(\d+)$/i,
20
+ vimeo :
21
+ /^http:\/\/(?:www\.)?vimeo\.com\/(\d+)$/i,
22
+ youtube :
23
+ /^http:\/\/(?:(?:www|uk)\.)?youtube\.com\/watch\?v=([\w\-]+)(?:&|$)/i
24
+ },
25
+ hostRe = /^http:\/\/([a-z\d\.\-]+(?::\d+)?)\//i;
26
+
27
+ function autoLink(s) {
28
+ // turn urls into links
29
+ var result = s.replace(
30
+ /https?:\/\/(?:[0-9a-z](?:[0-9a-z\-]{0,61}[0-9a-z])?\.)+[a-z]+\/[0-9a-z$_.+!*'(),\/?#\-]*/gi,
31
+ '<a href="$&">$&</a>');
32
+
33
+ return result;
34
+ }
15
35
 
16
- Murlsh.makeFit = function(e, maxWidth, maxHeight) {
17
- var height = e.height();
18
- var scale;
19
- var width = e.width();
36
+ function escapeXml(s) {
37
+ return s.replace(/&/g, '&amp;');
38
+ }
20
39
 
21
- if (width > maxWidth || height > maxHeight) {
22
- scale = Math.min(maxWidth / width, maxHeight / height);
23
- e.width(Math.round(width * scale));
24
- e.height(Math.round(height * scale));
40
+ function img(src, text) {
41
+ text = text || '';
42
+ return $('<img />', {
43
+ src : src,
44
+ alt : text,
45
+ title : text
46
+ });
25
47
  }
26
- };
27
48
 
28
- Murlsh.closerAdd = function(x, header) {
29
- var html = (typeof x === 'object') ? $('<div />').append(x).html() : x;
30
-
31
- $.jGrowl(html, {
32
- closeTemplate : 'X',
33
- glue : 'before',
34
- header : header,
35
- sticky : true,
36
- beforeOpen : function(e) {
37
- e.find('.message img').load(function() {
38
- Murlsh.makeFit($(this),
39
- Math.round($(window).width() / 2),
40
- Math.round($(window).height() - 100));
41
- });
49
+ function makeFit(e, maxWidth, maxHeight) {
50
+ var height = e.height(),
51
+ scale,
52
+ width = e.width();
53
+
54
+ if (width > maxWidth || height > maxHeight) {
55
+ scale = Math.min(maxWidth / width, maxHeight / height);
56
+ e.width(Math.round(width * scale));
57
+ e.height(Math.round(height * scale));
42
58
  }
43
- });
44
- };
59
+ }
45
60
 
46
- Murlsh.escapeXml = function(s) {
47
- return s.replace(/&/g, '&amp;');
48
- };
61
+ function objectTag(data, height, width, params) {
62
+ // this does not use jQuery to build tags because building object
63
+ // tags is broken in IE
64
+ var result = '<object data="' + escapeXml(data) +
65
+ '" height="' + height +
66
+ '" type="application/x-shockwave-flash" width="' + width + '">';
49
67
 
50
- Murlsh.objectTag = function(data, height, width, params) {
51
- // this does not use jQuery to build tags because building object
52
- // tags is broken in IE
53
- var result = '<object data="' + Murlsh.escapeXml(data) +
54
- '" height="' + height +
55
- '" type="application/x-shockwave-flash" width="' + width + '">';
68
+ $.each(params, function (i, v) {
69
+ result += '<param name="' + v.name + '" value="' +
70
+ escapeXml(v.value) + '" />';
71
+ });
56
72
 
57
- $.each(params, function(i, v) {
58
- result += '<param name="' + v.name + '" value="' +
59
- Murlsh.escapeXml(v.value) + '" />';
60
- });
73
+ result += '</object>';
61
74
 
62
- result += '</object>';
75
+ return result;
76
+ }
63
77
 
64
- return result;
65
- };
78
+ function appleThumb(host) {
79
+ return img('http://' + host + '/apple-touch-icon.png', '').addClass(
80
+ 'thumb apple');
81
+ }
66
82
 
67
- Murlsh.flickrThumb = function(d) {
68
- var base;
69
- var owner;
70
- var photo = d.photo;
71
- var zoom;
83
+ function closerAdd(x, header) {
84
+ var html = (typeof x === 'object') ? $('<div />').append(x).html() : x;
85
+
86
+ $.jGrowl(html, {
87
+ closeTemplate : 'X',
88
+ glue : 'before',
89
+ header : header,
90
+ sticky : true,
91
+ beforeOpen : function (e) {
92
+ e.find('.message img').load(function () {
93
+ makeFit($(this), Math.round($(window).width() / 2),
94
+ Math.round($(window).height() - 100));
95
+ });
96
+ }
97
+ });
98
+ }
99
+
100
+ function flickrClick() {
101
+ closerAdd(img($(this).data('zoom')));
102
+ }
72
103
 
73
- if (d.stat === 'ok') {
74
- base = 'http://farm' + photo.farm + '.static.flickr.com/' +
75
- photo.server + '/' + photo.id + '_';
76
- zoom = base + photo.secret + '_m.jpg';
104
+ function flickrThumb(d) {
105
+ var base,
106
+ owner,
107
+ photo = d.photo,
108
+ zoom;
77
109
 
78
- if (photo.originalsecret) {
79
- zoom = base + photo.originalsecret + '_o.' + photo.originalformat;
110
+ if (d.stat === 'ok') {
111
+ base = 'http://farm' + photo.farm + '.static.flickr.com/' +
112
+ photo.server + '/' + photo.id + '_';
113
+ zoom = base + photo.secret + '_m.jpg';
114
+
115
+ if (photo.originalsecret) {
116
+ zoom = base + photo.originalsecret + '_o.' +
117
+ photo.originalformat;
118
+ }
119
+
120
+ owner = photo.owner;
121
+ return img(base + photo.secret + '_s.jpg', photo.title._content +
122
+ (owner && owner.username ? ' by ' + owner.username : '')
123
+ ).addClass('thumb flickr').data('zoom', zoom);
80
124
  }
125
+ }
81
126
 
82
- owner = photo.owner;
83
- return Murlsh.img(base + photo.secret + '_s.jpg',
84
- photo.title._content +
85
- (owner && owner.username ? ' by ' + owner.username : '')
86
- ).addClass('thumb flickr').data('zoom', zoom);
127
+ function imgClick() {
128
+ closerAdd(img($(this).data('href')));
87
129
  }
88
- };
89
130
 
90
- Murlsh.flickrClick = function() {
91
- Murlsh.closerAdd(Murlsh.img($(this).data('zoom')));
92
- };
131
+ function imgThumb() {
132
+ var i,
133
+ lastIndex,
134
+ urlParts = [];
93
135
 
94
- Murlsh.imgThumb = function() {
95
- var lastIndex;
96
- var urlParts = [];
136
+ for (i = 0; i < arguments.length; i += 1) {
137
+ urlParts.push(arguments[i]);
138
+ }
97
139
 
98
- for (var i = 0; i < arguments.length; i += 1) {
99
- urlParts.push(arguments[i]);
100
- }
140
+ lastIndex = urlParts.length - 1;
101
141
 
102
- lastIndex = urlParts.length - 1;
142
+ // if pdf the thumbnail will be .png
143
+ if (urlParts[lastIndex].match(/^pdf$/i)) {
144
+ urlParts.splice(lastIndex, 1, 'png');
145
+ }
103
146
 
104
- // if pdf the thumbnail will be .png
105
- if (urlParts[lastIndex].match(/^pdf$/i)) {
106
- urlParts.splice(lastIndex, 1, 'png');
147
+ return img(urlParts.join('')).addClass('thumb');
107
148
  }
108
149
 
109
- return Murlsh.img(urlParts.join('')).addClass('thumb');
110
- };
150
+ function thumbInsert(img, clickFunction, a) {
151
+ if (img) {
152
+ if (my.isIphone()) {
153
+ a.prepend(img);
154
+ } else {
155
+ if (clickFunction) {
156
+ img.click(clickFunction);
157
+ }
158
+ a.before(img);
159
+ }
160
+ }
161
+ }
111
162
 
112
- Murlsh.imgClick = function() {
113
- Murlsh.closerAdd(Murlsh.img($(this).data('href')));
114
- };
163
+ function twitterAddLinks(s) {
164
+ // turn urls into links and Twitter usernames into links to Twitter
165
+ var result = autoLink(s);
115
166
 
116
- Murlsh.twitterThumb = function(d) {
117
- return Murlsh.img(d.user.profile_image_url).addClass('thumb twitter');
118
- }
167
+ result = result.replace(
168
+ /(^|[\s,(])@([0-9a-z_]+)($|[\s,.)])/gi,
169
+ '$1<a href="http://twitter.com/$2">@$2</a>$3');
119
170
 
120
- Murlsh.vimeoThumb = function(d) {
121
- return Murlsh.img(d.thumbnail_medium, d.title).addClass('thumb vimeo');
122
- };
171
+ return result;
172
+ }
123
173
 
124
- Murlsh.vimeoClick = function() {
125
- Murlsh.closerAdd($(this).data('embedHtml'));
126
- };
174
+ function twitterThumb(d) {
175
+ return img(d.user.profile_image_url).addClass('thumb twitter');
176
+ }
127
177
 
128
- Murlsh.youtubeThumb = function(id) {
129
- return Murlsh.img('http://img.youtube.com/vi/' + id + '/default.jpg',
130
- 'click to watch').addClass('thumb youtube').data('id', id);
131
- };
178
+ function vimeoClick() {
179
+ closerAdd($(this).data('embedHtml'));
180
+ }
132
181
 
133
- Murlsh.youtubeClick = function() {
134
- var movie = 'http://www.youtube.com/v/' + $(this).data('id') + '?' +
135
- $.param({
136
- fs : 1,
137
- hd : 1,
138
- hl : 'en',
139
- iv_load_policy : 3,
140
- showinfo : 0,
141
- showsearch : 0
142
- });
182
+ function vimeoThumb(d) {
183
+ return img(d.thumbnail_medium, d.title).addClass('thumb vimeo');
184
+ }
143
185
 
144
- Murlsh.closerAdd(Murlsh.objectTag(movie, 505, 640,
145
- [{ name : 'movie', value : movie }]));
146
- };
186
+ function youtubeClick() {
187
+ var movie = 'http://www.youtube.com/v/' + $(this).data('id') + '?' +
188
+ $.param({
189
+ fs : 1,
190
+ hd : 1,
191
+ hl : 'en',
192
+ iv_load_policy : 3,
193
+ showinfo : 0,
194
+ showsearch : 0
195
+ });
147
196
 
148
- Murlsh.thumbInsert = function(img, clickFunction, a) {
149
- if (img) {
150
- if (Murlsh.isIphone()) {
151
- a.prepend(img);
152
- } else {
153
- if (clickFunction) {
154
- img.click(clickFunction);
155
- }
156
- a.before(img);
157
- }
197
+ closerAdd(objectTag(movie, 505, 640, [{
198
+ name : 'movie',
199
+ value : movie
200
+ }]));
158
201
  }
159
- };
160
202
 
161
- Murlsh.isIphone = function() {
162
- return navigator.userAgent.match(/i(phone|pod)/i);
163
- };
164
-
165
- Murlsh.hrefRes = {
166
- flickr :
167
- /^http:\/\/(?:www\.)?flickr\.com\/photos\/[@\w\-]+?\/([\d]+)/i,
168
- imageshack :
169
- /^(http:\/\/img\d+\.imageshack\.us\/img\d+\/\d+\/\w+\.)(jpe?g|gif|png)$/i,
170
- imgur :
171
- /^(http:\/\/(?:i\.)?imgur\.com\/[a-z\d]+)(\.(?:jpe?g|gif|png))$/i,
172
- mp3 :
173
- /\.mp3$/i,
174
- s3 :
175
- /^(http:\/\/static\.mmb\.s3\.amazonaws\.com\/[\w\-]+\.)(jpe?g|gif|pdf|png)$/i,
176
- twitter :
177
- /^https?:\/\/twitter\.com\/\w+\/status(?:es)?\/(\d+)$/i,
178
- vimeo :
179
- /^http:\/\/(?:www\.)?vimeo\.com\/(\d+)$/i,
180
- youtube :
181
- /^http:\/\/(?:(?:www|uk)\.)?youtube\.com\/watch\?v=([\w\-]+)(?:&|$)/i
182
- };
203
+ function youtubeThumb(id) {
204
+ return img('http://img.youtube.com/vi/' + id + '/default.jpg',
205
+ 'click to watch').addClass('thumb youtube').data('id', id);
206
+ }
183
207
 
184
- Murlsh.addExtra = function() {
185
- var href = $(this).attr('href');
186
- var match = {};
187
- var swf = 'swf/player_mp3_mini.swf';
188
- var thumb;
208
+ my.addComments = function (link, comments) {
209
+ var avatar,
210
+ comment,
211
+ commentElement,
212
+ i,
213
+ ul = $('<ul />').addClass('comments').appendTo(link.parent());
214
+
215
+ for (i = 0; i < comments.length; i += 1) {
216
+ comment = comments[i];
217
+ commentElement = $('<li />');
218
+ if (comment.authorAvatar.length > 0) {
219
+ avatar = img(comment.authorAvatar).appendTo(commentElement);
220
+ if (comment.authorUrl.length > 0) {
221
+ avatar.wrapAll($('<a />').attr('href', comment.authorUrl));
222
+ }
223
+ commentElement.append(' ');
224
+ }
225
+ commentElement
226
+ .append($('<span />').append(comment.authorName).addClass(
227
+ 'comment-name'))
228
+ .append(' : ')
229
+ .append($('<span />').append(autoLink(comment.comment)).
230
+ addClass('comment-comment'))
231
+ .appendTo(ul);
232
+ }
233
+ };
189
234
 
190
- $.each(Murlsh.hrefRes, function(x, re) {
191
- return !(match[x] = re.exec(href));
192
- });
235
+ my.addExtra = function () {
236
+ var host,
237
+ hostMatch,
238
+ href = $(this).attr('href'),
239
+ match = {},
240
+ swf = 'swf/player_mp3_mini.swf',
241
+ thumb;
193
242
 
194
- if (match.flickr) {
195
- $.ajax({
196
- // url : 'http://api.flickr.com/services/rest/',
197
- url : 'flickr',
198
- data : {
199
- format : 'json',
200
- method : 'flickr.photos.getinfo',
201
- photo_id : match.flickr[1]
202
- },
203
- dataType : 'jsonp',
204
- jsonp : 'jsoncallback',
205
- success : function(d) {
206
- Murlsh.thumbInsert(Murlsh.flickrThumb(d),
207
- Murlsh.flickrClick, $(this));
208
- },
209
- context : $(this),
210
- jsonpCallback : 'flickrCallback' + match.flickr[1]
243
+ $.each(hrefRes, function (x, re) {
244
+ return !(match[x] = re.exec(href));
211
245
  });
212
- } else if (match.imageshack) {
213
- Murlsh.thumbInsert(
214
- Murlsh.imgThumb(match.imageshack[1], 'th.', match.imageshack[2]).data(
215
- 'href', match.imageshack[0]),
216
- Murlsh.imgClick, $(this).html('imageshack.us'));
217
- } else if (match.imgur) {
218
- Murlsh.thumbInsert(
219
- Murlsh.imgThumb(match.imgur[1], 's', match.imgur[2]).data('href', match.imgur[0]),
220
- Murlsh.imgClick, $(this).html('imgur.com'));
221
- } else if (match.mp3) {
222
- $(this).before(Murlsh.objectTag(swf, 20, 200, [
223
- { name : 'bgcolor', value : '#000000' },
224
- { name : 'FlashVars', value : 'mp3=' + href },
225
- { name : 'movie', value : swf }
226
- ]));
227
- } else if (match.s3) {
228
- thumb = Murlsh.imgThumb(match.s3[1], 'th.', match.s3[2]);
229
-
230
- if (match.s3[2].match(/^pdf$/i)) {
231
- $(this).before(thumb).html('pdf');
232
- } else {
233
- if (Murlsh.isIphone()) {
234
- $(this).html(thumb);
246
+
247
+ if (match.flickr) {
248
+ $.ajax({
249
+ // url : 'http://api.flickr.com/services/rest/',
250
+ url : 'flickr',
251
+ data : {
252
+ format : 'json',
253
+ method : 'flickr.photos.getinfo',
254
+ photo_id : match.flickr[1]
255
+ },
256
+ dataType : 'jsonp',
257
+ jsonp : 'jsoncallback',
258
+ success : function (d) {
259
+ thumbInsert(flickrThumb(d), flickrClick, $(this));
260
+ },
261
+ context : $(this),
262
+ jsonpCallback : 'flickrCallback' + match.flickr[1]
263
+ });
264
+ } else if (match.imageshack) {
265
+ thumbInsert(imgThumb(match.imageshack[1], 'th.',
266
+ match.imageshack[2]).data('href', match.imageshack[0]),
267
+ imgClick, $(this).html('imageshack.us'));
268
+ } else if (match.imgur) {
269
+ thumbInsert(imgThumb(match.imgur[1], 's', match.imgur[2]).data(
270
+ 'href', match.imgur[0]), imgClick, $(this).html('imgur.com'));
271
+ } else if (match.mp3) {
272
+ $(this).before(objectTag(swf, 20, 200, [
273
+ { name : 'bgcolor', value : '#000000' },
274
+ { name : 'FlashVars', value : 'mp3=' + href },
275
+ { name : 'movie', value : swf }
276
+ ]));
277
+ } else if (match.s3) {
278
+ thumb = imgThumb(match.s3[1], 'th.', match.s3[2]);
279
+
280
+ if (match.s3[2].match(/^pdf$/i)) {
281
+ $(this).before(thumb).html('pdf');
235
282
  } else {
236
- $(this).html('link');
237
- $(this).before(thumb.data('href', match.s3[0]).click(
238
- Murlsh.imgClick));
283
+ if (my.isIphone()) {
284
+ $(this).html(thumb);
285
+ } else {
286
+ $(this).html('link');
287
+ $(this).before(thumb.data('href', match.s3[0]).click(
288
+ imgClick));
289
+ }
290
+ }
291
+ } else if (match.twitter) {
292
+ $.ajax({
293
+ // url : 'http://api.twitter.com/1/statuses/show/' +
294
+ url : '/twitter/1/statuses/show/' +
295
+ match.twitter[1] + '.json',
296
+ dataType : 'jsonp',
297
+ success : function (d) {
298
+ var nameLink = $('<a />', {
299
+ href: 'http://twitter.com/' + d.user.screen_name +
300
+ '/status/' + d.id,
301
+ text: '@' + d.user.screen_name
302
+ }),
303
+ tweet = $('<span />').addClass('tweet').append(
304
+ nameLink).append(': ').append(twitterAddLinks(
305
+ d.text));
306
+
307
+ thumbInsert(twitterThumb(d), null, nameLink);
308
+
309
+ $(this).replaceWith(tweet);
310
+ },
311
+ context : $(this),
312
+ jsonpCallback : 'twitterCallback' + match.twitter[1]
313
+ });
314
+ } else if (match.vimeo) {
315
+ $.ajax({
316
+ url : 'http://vimeo.com/api/v2/video/' + match.vimeo[1] +
317
+ '.json',
318
+ dataType : 'jsonp',
319
+ success : function (d) {
320
+ var video = d[0],
321
+ movie = 'http://vimeo.com/moogaloop.swf?clip_id=' +
322
+ video.id;
323
+
324
+ thumbInsert(vimeoThumb(video).data('embedHtml',
325
+ objectTag(movie, video.height, video.width, [
326
+ { name : 'movie', value : movie }
327
+ ])), vimeoClick, $(this));
328
+ },
329
+ context : $(this),
330
+ jsonpCallback : 'vimeoCallback' + match.vimeo[1]
331
+ });
332
+ } else if (match.youtube) {
333
+ thumbInsert(youtubeThumb(match.youtube[1]), youtubeClick, $(this));
334
+ } else {
335
+ // Apple touch icon if available
336
+ hostMatch = hostRe.exec(href);
337
+ if (hostMatch) {
338
+ host = hostMatch[1];
339
+ if ($.inArray(host, config.apple_icon_hosts) > -1) {
340
+ thumbInsert(appleThumb(host), null, $(this));
341
+ }
239
342
  }
240
343
  }
241
- } else if (match.twitter) {
242
- $.ajax({
243
- // url : 'http://api.twitter.com/1/statuses/show/' +
244
- url : '/twitter/1/statuses/show/' +
245
- match.twitter[1] + '.json',
246
- dataType : 'jsonp',
247
- success : function(d) {
248
- var nameLink = $('<a />', {
249
- href: 'http://twitter.com/' + d.user.screen_name,
250
- text: d.user.screen_name
251
- });
344
+ };
252
345
 
253
- $(this).html(d.text).before(nameLink).before(
254
- document.createTextNode(': '));
346
+ my.formatLi = function (d) {
347
+ var iconSize = 32,
348
+ li = $('<li />').append($('<a />', {
349
+ href : d.url,
350
+ text : d.title
351
+ }));
255
352
 
256
- Murlsh.thumbInsert(Murlsh.twitterThumb(d), null, nameLink);
257
- },
258
- context : $(this),
259
- jsonpCallback : 'twitterCallback' + match.twitter[1]
260
- });
261
- } else if (match.vimeo) {
262
- $.ajax({
263
- url : 'http://vimeo.com/api/v2/video/' + match.vimeo[1] + '.json',
264
- dataType : 'jsonp',
265
- success : function(d) {
266
- var video = d[0];
267
- var movie = 'http://vimeo.com/moogaloop.swf?clip_id=' + video.id;
268
-
269
- Murlsh.thumbInsert(Murlsh.vimeoThumb(video).data(
270
- 'embedHtml',
271
- Murlsh.objectTag(movie, video.height, video.width, [
272
- { name : 'movie', value : movie }
273
- ])), Murlsh.vimeoClick, $(this));
274
- },
275
- context : $(this),
276
- jsonpCallback : 'vimeoCallback' + match.vimeo[1]
277
- });
278
- } else if (match.youtube) {
279
- Murlsh.thumbInsert(Murlsh.youtubeThumb(match.youtube[1]),
280
- Murlsh.youtubeClick, $(this));
281
- }
282
- };
353
+ if (d.name) {
354
+ li.prepend($('<div />', { text : d.name }).addClass('name'));
355
+ }
283
356
 
284
- Murlsh.formatLi = function(d) {
285
- var iconSize = 32;
286
- var li = $('<li />').append($('<a />', {
287
- href : d.url,
288
- text : d.title
289
- }));
357
+ if (d.email) {
358
+ li.prepend($('<div />').addClass('icon').append(
359
+ img('http://www.gravatar.com/avatar/' + d.email + '?s=' +
360
+ iconSize, d.name).attr({
361
+ width : iconSize,
362
+ height : iconSize
363
+ })));
364
+ }
290
365
 
291
- if (d.name) {
292
- li.prepend($('<div />', { text : d.name }).addClass('name'));
293
- }
366
+ return li;
367
+ };
294
368
 
295
- if (d.email) {
296
- li.prepend($('<div />').addClass('icon').append(
297
- Murlsh.img(
298
- 'http://www.gravatar.com/avatar/' + d.email + '?s=' + iconSize,
299
- d.name).attr({
300
- width : iconSize,
301
- height : iconSize
302
- })));
303
- }
369
+ my.iphoneInit = function () {
370
+ window.onorientationchange = function () {
371
+ var width = 450;
372
+ if (window.orientation === 0 || window.orientation === 180) {
373
+ width = 290;
374
+ }
375
+ $('#urls').width(width);
376
+ };
304
377
 
305
- return li;
306
- };
378
+ window.onorientationchange();
307
379
 
308
- Murlsh.iphoneInit = function() {
309
- window.onorientationchange = function() {
310
- var width = 450;
311
- if (window.orientation === 0 || window.orientation === 180) {
312
- width = 290;
313
- }
314
- $('#urls').width(width);
380
+ $('a.feed').replaceWith($('<a />', {
381
+ href : '#bottom',
382
+ text : 'bottom'
383
+ }));
315
384
  };
316
385
 
317
- window.onorientationchange();
386
+ my.isIphone = function () {
387
+ return navigator.userAgent.match(/i(phone|pod)/i);
388
+ };
318
389
 
319
- $('a.feed').replaceWith($('<a />', {
320
- href : '#bottom',
321
- text : 'bottom'
322
- }));
390
+ return my;
323
391
  };
324
392
 
325
- $(document).ready(function() {
326
- if (Murlsh.isIphone()) {
327
- Murlsh.iphoneInit();
328
- }
329
- $('a.m').map(Murlsh.addExtra);
330
-
331
- $('#submit').click(function() {
332
- $.post('url', {
333
- url : $('#url').val(),
334
- via : $('#via').val(),
335
- auth : $('#auth').val()
336
- }, function (d) {
337
- $.each(d, function(i, v) {
338
- var li = Murlsh.formatLi(v);
339
- $('#urls > li:first').after(li);
340
- $(li).children('a:first').map(Murlsh.addExtra);
393
+ $(document).ready(function () {
394
+ $.getJSON('config', function (config) {
395
+ var murlsh = new Murlsh(config, $, navigator, window),
396
+ urls;
397
+
398
+ if (murlsh.isIphone()) {
399
+ murlsh.iphoneInit();
400
+ }
401
+
402
+ $('#submit').click(function () {
403
+ $.post('url', {
404
+ url : $('#url').val(),
405
+ via : $('#via').val(),
406
+ auth : $('#auth').val()
407
+ }, function (d) {
408
+ $.each(d, function (i, v) {
409
+ var li = murlsh.formatLi(v);
410
+ $('#urls > li:first').after(li);
411
+ $(li).children('a:first').each(murlsh.addExtra);
412
+ });
413
+ $('#url').val('');
414
+ $('#via').val('');
415
+ }, 'json');
416
+ });
417
+
418
+ urls = $('a.m');
419
+
420
+ urls.each(murlsh.addExtra);
421
+
422
+ /*
423
+ // experimental comment support, to enable uncomment and edit comments.json
424
+ $.getJSON('/js/comments.json', function (data) {
425
+ urls.each(function () {
426
+ var href = $(this).attr('href');
427
+ if (href in data) {
428
+ murlsh.addComments($(this), data[href]);
429
+ }
341
430
  });
342
- $('#url').val('');
343
- $('#via').val('');
344
- }, 'json');
431
+ });
432
+ */
345
433
  });
346
-
347
434
  });
data/spec/auth_spec.rb CHANGED
@@ -1,5 +1,3 @@
1
- $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
-
3
1
  %w{
4
2
  tempfile
5
3
 
@@ -1,5 +1,3 @@
1
- $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
-
3
1
  %w{
4
2
  rack/test
5
3
 
data/spec/doc_spec.rb CHANGED
@@ -1,5 +1,3 @@
1
- $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
-
3
1
  %w{
4
2
  hpricot
5
3
 
data/spec/markup_spec.rb CHANGED
@@ -1,5 +1,3 @@
1
- $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
-
3
1
  %w{
4
2
  murlsh
5
3
  }.each { |m| require m }
@@ -1,5 +1,3 @@
1
- $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
-
3
1
  %w{
4
2
  murlsh
5
3
  }.each { |m| require m }
data/spec/uri_ask_spec.rb CHANGED
@@ -1,5 +1,3 @@
1
- $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
-
3
1
  %w{
4
2
  uri
5
3
 
data/spec/uri_spec.rb CHANGED
@@ -1,5 +1,3 @@
1
- $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
-
3
1
  %w{
4
2
  murlsh
5
3
  }.each { |m| require m }
@@ -1,5 +1,3 @@
1
- $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
-
3
1
  %w{
4
2
  murlsh
5
3
  }.each { |m| require m }
@@ -1,5 +1,3 @@
1
- $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
-
3
1
  %w{
4
2
  murlsh
5
3
  }.each { |m| require m }
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: murlsh
3
3
  version: !ruby/object:Gem::Version
4
- hash: 59
4
+ hash: 55
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 9
8
+ - 10
9
9
  - 0
10
- version: 0.9.0
10
+ version: 0.10.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Matthew M. Boedicker
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-06-03 00:00:00 -04:00
18
+ date: 2010-08-05 00:00:00 -04:00
19
19
  default_executable: murlsh
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -115,9 +115,25 @@ dependencies:
115
115
  type: :runtime
116
116
  version_requirements: *id006
117
117
  - !ruby/object:Gem::Dependency
118
- name: rack
118
+ name: push-notify
119
119
  prerelease: false
120
120
  requirement: &id007 !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ hash: 27
126
+ segments:
127
+ - 0
128
+ - 1
129
+ - 0
130
+ version: 0.1.0
131
+ type: :runtime
132
+ version_requirements: *id007
133
+ - !ruby/object:Gem::Dependency
134
+ name: rack
135
+ prerelease: false
136
+ requirement: &id008 !ruby/object:Gem::Requirement
121
137
  none: false
122
138
  requirements:
123
139
  - - ">="
@@ -129,11 +145,11 @@ dependencies:
129
145
  - 0
130
146
  version: 1.0.0
131
147
  type: :runtime
132
- version_requirements: *id007
148
+ version_requirements: *id008
133
149
  - !ruby/object:Gem::Dependency
134
150
  name: rack-cache
135
151
  prerelease: false
136
- requirement: &id008 !ruby/object:Gem::Requirement
152
+ requirement: &id009 !ruby/object:Gem::Requirement
137
153
  none: false
138
154
  requirements:
139
155
  - - ">="
@@ -145,11 +161,11 @@ dependencies:
145
161
  - 2
146
162
  version: 0.5.2
147
163
  type: :runtime
148
- version_requirements: *id008
164
+ version_requirements: *id009
149
165
  - !ruby/object:Gem::Dependency
150
166
  name: rack-throttle
151
167
  prerelease: false
152
- requirement: &id009 !ruby/object:Gem::Requirement
168
+ requirement: &id010 !ruby/object:Gem::Requirement
153
169
  none: false
154
170
  requirements:
155
171
  - - ">="
@@ -161,11 +177,11 @@ dependencies:
161
177
  - 0
162
178
  version: 0.3.0
163
179
  type: :runtime
164
- version_requirements: *id009
180
+ version_requirements: *id010
165
181
  - !ruby/object:Gem::Dependency
166
182
  name: sqlite3-ruby
167
183
  prerelease: false
168
- requirement: &id010 !ruby/object:Gem::Requirement
184
+ requirement: &id011 !ruby/object:Gem::Requirement
169
185
  none: false
170
186
  requirements:
171
187
  - - ">="
@@ -177,11 +193,11 @@ dependencies:
177
193
  - 1
178
194
  version: 1.2.1
179
195
  type: :runtime
180
- version_requirements: *id010
196
+ version_requirements: *id011
181
197
  - !ruby/object:Gem::Dependency
182
198
  name: tinyatom
183
199
  prerelease: false
184
- requirement: &id011 !ruby/object:Gem::Requirement
200
+ requirement: &id012 !ruby/object:Gem::Requirement
185
201
  none: false
186
202
  requirements:
187
203
  - - ">="
@@ -193,7 +209,7 @@ dependencies:
193
209
  - 1
194
210
  version: 0.1.1
195
211
  type: :runtime
196
- version_requirements: *id011
212
+ version_requirements: *id012
197
213
  description: url sharing site framework with easy adding, title lookup, atom feed, thumbnails and embedding
198
214
  email: matthewm@boedicker.org
199
215
  executables:
@@ -214,6 +230,7 @@ files:
214
230
  - config.yaml
215
231
  - lib/murlsh.rb
216
232
  - lib/murlsh/auth.rb
233
+ - lib/murlsh/config_server.rb
217
234
  - lib/murlsh/dispatch.rb
218
235
  - lib/murlsh/doc.rb
219
236
  - lib/murlsh/etag_add_encoding.rb
@@ -248,6 +265,7 @@ files:
248
265
  - plugins/via_50_domain.rb
249
266
  - public/css/jquery.jgrowl.css
250
267
  - public/css/screen.css
268
+ - public/js/comments.json
251
269
  - public/js/jquery-1.4.2.min.js
252
270
  - public/js/jquery.jgrowl_compressed.js
253
271
  - public/js/js.js