sg_node_mapper 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sg_node_mapper.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Chris Mytton
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,39 @@
1
+ # SgNodeMapper
2
+
3
+ Lightweight ruby wrapper around the Social Graph Node Mapper [javascript
4
+ library](https://github.com/webjay/sgNodeMapper).
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'sg_node_mapper'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install sg_node_mapper
19
+
20
+ ## Usage
21
+
22
+ This library simply delegates to the javascript library, so you can call
23
+ any methods defined in there (see `vendor/sg_node_mapper/nodemapper.js` for more details.
24
+
25
+ ```ruby
26
+ SgNodeMapper.url_to_graph_node('http://twitter.com/hecticjeff')
27
+ # => "sgn://twitter.com/?ident=hecticjeff"
28
+
29
+ SgNodeMapper.parse_sgn_url('sgn://twitter.com/?ident=hecticjeff')
30
+ # => {"domain"=>"twitter.com", "keyName"=>"ident", "value"=>"hecticjeff"}
31
+ ```
32
+
33
+ ## Contributing
34
+
35
+ 1. Fork it
36
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
37
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
38
+ 4. Push to the branch (`git push origin my-new-feature`)
39
+ 5. Create new Pull Request
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,57 @@
1
+ # Core
2
+ require 'singleton'
3
+
4
+ # Gems
5
+ require 'execjs'
6
+ require 'active_support/core_ext'
7
+
8
+ # Internal
9
+ require 'sg_node_mapper/version'
10
+
11
+ # Simple wrapper for the sgNodeMapper javascript library. Uses
12
+ # [ExecJS](https://github.com/sstephenson/execjs) to dynamically select the best
13
+ # available javascript platform to execute the code on.
14
+ #
15
+ # This class will dynamically call methods in the sgNodeMapper javascript
16
+ # library. In the case that the the method doesn't exist, it will return nil,
17
+ # rather than raising a NoMethodError, this is a side effect of blindly
18
+ # delegating to javascript.
19
+ class SgNodeMapper
20
+ include Singleton
21
+
22
+ # When a method is called on this class, we intercept it and pass it through
23
+ # to the javascript context by converting the method name from underscore_case
24
+ # to camelCase, then calling that method on the javascript context with the
25
+ # given *args.
26
+ #
27
+ # method - The Symbol name of the method being called.
28
+ # args - The Array of arguments (optional).
29
+ #
30
+ # Returns the result from javascript.
31
+ def self.method_missing(method, *args)
32
+ instance.context.call("nodemapper.#{method.to_s.camelize(:lower)}", *args)
33
+ end
34
+
35
+ # Get a (potentially cached) version of the compiled source code for sgNodeMapper.
36
+ #
37
+ # Returns an ExecJS::ExternalRuntime::Context.
38
+ def context
39
+ @context ||= ExecJS.compile(source)
40
+ end
41
+
42
+ private
43
+
44
+ # Get a (potentially cached) string of the sgNodeMapper source code.
45
+ #
46
+ # Returns the String javascript source code.
47
+ def source
48
+ @source ||= File.read(source_path)
49
+ end
50
+
51
+ # Get the full path to the sgNodeMapper.js source code.
52
+ #
53
+ # Returns the String path to sgNodeMapper.
54
+ def source_path
55
+ File.join(File.expand_path('../../', __FILE__), 'vendor', 'sg_node_mapper', 'nodemapper.js')
56
+ end
57
+ end
@@ -0,0 +1,3 @@
1
+ class SgNodeMapper
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/sg_node_mapper/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Chris Mytton"]
6
+ gem.email = ["self@hecticjeff.net"]
7
+ gem.description = %q{Map social networking sites' URLs to and from a canonical form.}
8
+ gem.summary = %q{The Social Graph Node Mapper is a community project to build a portable library to map social networking sites' URLs to and from a canonical form (sgn:// URLs).}
9
+ gem.homepage = "https://github.com/hecticjeff/sg_node_mapper"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "sg_node_mapper"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = SgNodeMapper::VERSION
17
+
18
+ gem.add_dependency 'execjs', '>= 1.4'
19
+ gem.add_dependency 'activesupport', '>= 3.0'
20
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe SgNodeMapper do
4
+ describe ".url_to_graph_node('http://twitter.com/google')" do
5
+ subject { SgNodeMapper.url_to_graph_node('http://twitter.com/google') }
6
+ it { should == 'sgn://twitter.com/?ident=google' }
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper.rb"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ require 'sg_node_mapper'
8
+
9
+ RSpec.configure do |config|
10
+ config.treat_symbols_as_metadata_keys_with_true_values = true
11
+ config.run_all_when_everything_filtered = true
12
+ config.filter_run :focus
13
+ end
@@ -0,0 +1,12 @@
1
+ Licensed under the Apache License, Version 2.0 (the "License");
2
+ you may not use this file except in compliance with the License.
3
+ You may obtain a copy of the License at
4
+
5
+ http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software
8
+ distributed under the License is distributed on an "AS IS" BASIS,
9
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ See the License for the specific language governing permissions and
11
+ limitations under the License.
12
+
@@ -0,0 +1,1862 @@
1
+ //############################################################
2
+ // AUTO-GENERATED FILE; DO NOT EDIT. This is a concatenantion
3
+ // of nodemapper-base.js, and sites/*.js. Edit those.
4
+ //#############################################################
5
+ // -*-java-*-
6
+
7
+ /**
8
+ * Copyright 2007 Google Inc.
9
+ * Licensed under the Apache License, Version 2.0 (the "License");
10
+ * you may not use this file except in compliance with the License.
11
+ * You may obtain a copy of the License at
12
+ *
13
+ * http://www.apache.org/licenses/LICENSE-2.0
14
+ *
15
+ * Unless required by applicable law or agreed to in writing, software
16
+ * distributed under the License is distributed on an "AS IS" BASIS,
17
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ * See the License for the specific language governing permissions and
19
+ * limitations under the License.
20
+ */
21
+ nodemapper = {};
22
+ nodemapper.IDENT_REGEXP = /^\w*[a-zA-Z]+\w*$/;
23
+ nodemapper.PK_REGEXP = /^\d+$/;
24
+ nodemapper.pkRegexp = function(handler) {
25
+ return handler.pkRegexp ? handler.pkRegexp : nodemapper.PK_REGEXP;
26
+ };
27
+ nodemapper.identRegexp = function(handler) {
28
+ return handler.identRegexp ? handler.identRegexp : nodemapper.IDENT_REGEXP;
29
+ };
30
+ nodemapper.handlers = {};
31
+ nodemapper.registerDomain = function(domain, handler) {
32
+ if (!handler.identRegexp) {
33
+ handler.identRegexp = nodemapper.IDENT_REGEXP;
34
+ }
35
+ if (!handler.pkRegexp) {
36
+ handler.pkRegexp = nodemapper.PK_REGEXP;
37
+ }
38
+ if (domain instanceof Array) {
39
+ for (var i = 0; i < domain.length; i++) {
40
+ nodemapper.handlers[domain[i]] = handler;
41
+ }
42
+ } else {
43
+ nodemapper.handlers[domain] = handler;
44
+ }
45
+ };
46
+ nodemapper.addSimpleHandler = function(domain, handlerName,
47
+ prefix, suffix) {
48
+ var handlers = nodemapper.handlers[domain];
49
+ if (!handlers) {
50
+ handlers = nodemapper.handlers[domain] = {};
51
+ }
52
+ if (!suffix) { suffix = ""; }
53
+ var sgnType;
54
+ var m;
55
+ if (m = /^(ident|pk)_to_/.exec(handlerName)) {
56
+ sgnType = m[1];
57
+ }
58
+ if (!handlers.sgnToHttpPatterns) {
59
+ handlers.sgnToHttpPatterns = [];
60
+ }
61
+ handlers.sgnToHttpPatterns.push([prefix, suffix, sgnType]);
62
+ handlers[handlerName] = function (pk_or_ident) {
63
+ return prefix + pk_or_ident + suffix;
64
+ };
65
+ };
66
+ nodemapper.HTTP_REGEX = new RegExp("^(https?)://([^/]+)(.*)");
67
+ nodemapper.urlToGraphNode = function(url) {
68
+ var m = nodemapper.HTTP_REGEX.exec(url);
69
+ if (!m) {
70
+ return nodemapper.urlToGraphNodeNotHTTP(url);
71
+ }
72
+ var scheme = m[1];
73
+ var host = m[2].toLowerCase();
74
+ var path = m[3];
75
+ var hostparts = host.split(".");
76
+ var handler;
77
+ var matchedDomain; // the domain that matched tightest
78
+ for (var i = 0; i < hostparts.length; ++i) {
79
+ var subhost = hostparts.slice(i, hostparts.length);
80
+ matchedDomain = subhost.join(".");
81
+ handler = nodemapper.handlers[matchedDomain];
82
+ if (!handler) continue;
83
+ var graphNode;
84
+ if (scheme == "https" && !handler.httpsLikeHttp) {
85
+ graphNode = nodemapper.urlToGraphNodeNotHTTP(url);
86
+ }
87
+ if (handler.urlToGraphNode) {
88
+ graphNode = handler.urlToGraphNode(url, host, path);
89
+ }
90
+ if ((!graphNode || graphNode == url) && !handler.skipAutomaticHttpToSgn) {
91
+ graphNode = nodemapper.sgnFromHttpUsingToHttpRules(matchedDomain, url);
92
+ }
93
+ if (!graphNode || graphNode == url) {
94
+ continue;
95
+ }
96
+ return graphNode;
97
+ }
98
+ return url;
99
+ };
100
+ nodemapper.pairToGraphNode = function (host, account) {
101
+ if (!account) {
102
+ return;
103
+ }
104
+ if (account.substr(0, 4) == "http") {
105
+ var sgn = nodemapper.urlToGraphNode(account);
106
+ if (sgn && sgn.length >= 3 && sgn.substr(0, 3) == "sgn") {
107
+ return sgn;
108
+ }
109
+ return;
110
+ }
111
+ if (!host) {
112
+ return;
113
+ }
114
+ var domain = nodemapper.parseDomain(host);
115
+ if (!domain) {
116
+ return;
117
+ }
118
+ var accountToSgn = {};
119
+ var handler;
120
+ handler = nodemapper.lookupHandlerWithProperty(domain, "accountToSgn");
121
+ if (handler) {
122
+ accountToSgn = handler.accountToSgn;
123
+ } else {
124
+ handler = nodemapper.lookupHandlerWithProperty(domain, "pkRegexp");
125
+ if (handler) {
126
+ accountToSgn.pk = [handler._registeredOnDomain, handler.pkRegexp];
127
+ }
128
+ handler = nodemapper.lookupHandlerWithProperty(domain, "identRegexp");
129
+ if (handler) {
130
+ accountToSgn.ident = [handler._registeredOnDomain, handler.identRegexp];
131
+ }
132
+ }
133
+ if (accountToSgn.pk) {
134
+ var sgnDomain = accountToSgn.pk[0];
135
+ var sgnRegexp = accountToSgn.pk[1] || /^\d+$/;
136
+ var m;
137
+ if (m = sgnRegexp.exec(account)) {
138
+ if (m[1]) {
139
+ return "sgn://" + sgnDomain + "/?pk=" + m[1];
140
+ } else {
141
+ return "sgn://" + sgnDomain + "/?pk=" + account;
142
+ }
143
+ }
144
+ }
145
+ if (accountToSgn.ident) {
146
+ var sgnDomain = accountToSgn.ident[0];
147
+ var sgnRegexp = accountToSgn.ident[1] || /^\w+$/;
148
+ if (sgnRegexp.exec(account)) {
149
+ if (nodemapper.lookupHandlerWithProperty(host, "identCasePreserve")) {
150
+ } else {
151
+ account = account.toLowerCase();
152
+ }
153
+ return "sgn://" + sgnDomain + "/?ident=" + account;
154
+ }
155
+ }
156
+ return;
157
+ };
158
+ nodemapper.lookupHandlerWithProperty = function (host, property) {
159
+ return nodemapper.lookupHandler(host, function (h) {
160
+ if (h[property]) {
161
+ return h;
162
+ }
163
+ return;
164
+ });
165
+ };
166
+ nodemapper.lookupHandler_unittest = function (host, property) {
167
+ var handler = nodemapper.lookupHandlerWithProperty(host, property);
168
+ if (handler) {
169
+ return handler._name_for_testing;
170
+ }
171
+ return;
172
+ }
173
+ nodemapper.lookupHandler = function (host, filterFunc) {
174
+ var hostparts = host.split(".");
175
+ var handler;
176
+ var matchedDomain; // the domain that matched tightest
177
+ for (var i = 0; i < hostparts.length; ++i) {
178
+ var subhost = hostparts.slice(i, hostparts.length);
179
+ matchedDomain = subhost.join(".");
180
+ handler = nodemapper.handlers[matchedDomain];
181
+ if (!handler) continue;
182
+ if (filterFunc(handler)) {
183
+ handler._registeredOnDomain = matchedDomain;
184
+ return handler;
185
+ }
186
+ }
187
+ return;
188
+ };
189
+ nodemapper.DOMAIN_RE = /^(?:\w+:\/{0,2})?([^:\/]*?)(?:[:\/]|$)/;
190
+ nodemapper.parseDomain = function (arg) {
191
+ var m;
192
+ if ((m = nodemapper.DOMAIN_RE.exec(arg)) && m[1].length > 0) {
193
+ return m[1];
194
+ }
195
+ return;
196
+ };
197
+ nodemapper.sgnFromHttpUsingToHttpRules = function(domain, url) {
198
+ var handler = nodemapper.handlers[domain];
199
+ if (!handler || !handler.sgnToHttpPatterns) {
200
+ return;
201
+ }
202
+ var m;
203
+ var matches = [];
204
+ for (var i = 0; i < handler.sgnToHttpPatterns.length; i++) {
205
+ var pattern = handler.sgnToHttpPatterns[i];
206
+ var prefix = pattern[0];
207
+ var suffix = pattern[1];
208
+ var type = pattern[2];
209
+ if (url.substr(0, prefix.length) == prefix &&
210
+ url.substr(url.length - suffix.length, suffix.length) == suffix) {
211
+ var midLength = url.length - prefix.length - suffix.length;
212
+ if (midLength >= 1) {
213
+ var match = url.substr(prefix.length, midLength);
214
+ if (type == "pk" &&
215
+ (m = nodemapper.pkRegexp(handler).exec(match))) {
216
+ matches.push("sgn://" + domain + "/?pk=" + match);
217
+ } else if (type == "ident" &&
218
+ (m = nodemapper.identRegexp(handler).exec(match))) {
219
+ if (! handler.caseSensitiveIdent) {
220
+ match = match.toLowerCase();
221
+ }
222
+ if (!(match == "www" ||
223
+ (handler.notUsernames && handler.notUsernames[match]))) {
224
+ matches.push("sgn://" + domain + "/?ident=" + match);
225
+ }
226
+ }
227
+ }
228
+ }
229
+ }
230
+ if (matches.length == 1) {
231
+ return matches[0];
232
+ } else {
233
+ debug("More/less than 1 match for " + url + ". Potential matches: [" + matches + "]");
234
+ }
235
+ return;
236
+ };
237
+ nodemapper.SGN_REGEX = new RegExp("^sgn://([^/]+)/\\?(ident|pk)=(.*)");
238
+ nodemapper.parseSgnUrl = function(sgnUrl) {
239
+ var m = nodemapper.SGN_REGEX.exec(sgnUrl);
240
+ if (!m) return null;
241
+ return {
242
+ "domain": m[1],
243
+ "keyName": m[2],
244
+ "value": m[3]
245
+ };
246
+ }
247
+ nodemapper.urlFromGraphNode = function(sgnUrl, type) {
248
+ var node = nodemapper.parseSgnUrl(sgnUrl);
249
+ if (!node) {
250
+ return;
251
+ }
252
+ var handler = nodemapper.handlers[node.domain];
253
+ if (!handler) {
254
+ return;
255
+ }
256
+ var attrName = node.keyName + "_to_" + type;
257
+ var toFunc = handler[attrName];
258
+ if (!toFunc) {
259
+ return;
260
+ }
261
+ return toFunc(node.value);
262
+ };
263
+ nodemapper.nonHTTPHandlers = [];
264
+ nodemapper.registerNonHTTPHandler = function(handler) {
265
+ nodemapper.nonHTTPHandlers.push(handler);
266
+ };
267
+ nodemapper.urlToGraphNodeNotHTTP = function(url) {
268
+ for (var i=0; i < nodemapper.nonHTTPHandlers.length; ++i) {
269
+ var ident = nodemapper.nonHTTPHandlers[i](url);
270
+ if (ident) return ident;
271
+ }
272
+ return url;
273
+ };
274
+ nodemapper.createPathRegexpHandler = function(domain, re, opt_opts) {
275
+ if (!opt_opts) opt_opts = {};
276
+ return function(url, host, path) {
277
+ if (opt_opts.pathTransform) {
278
+ path = opt_opts.pathTransform(path);
279
+ }
280
+ var m = re.exec(path);
281
+ if (!m) {
282
+ return opt_opts.fallbackHandler ?
283
+ opt_opts.fallbackHandler(url, host, path) :
284
+ url;
285
+ }
286
+ var keyName = opt_opts.keyName || 'ident'; // ident= or pk=; TODO: enforce valid key names?
287
+ var value = (opt_opts.casePreserve ? m[1] : m[1].toLowerCase());
288
+ if (opt_opts.notUsernames && opt_opts.notUsernames[value]) {
289
+ return opt_opts.fallbackHandler ?
290
+ opt_opts.fallbackHandler(url, host, path) :
291
+ url;
292
+ }
293
+ return "sgn://" + domain + "/?" + keyName + "=" + value;
294
+ };
295
+ };
296
+ nodemapper.createHostRegexpHandler = function(domain, re, opt_opts) {
297
+ if (!opt_opts) opt_opts = {};
298
+ return function(url, host, path) {
299
+ var m = re.exec(host);
300
+ var ident = m ? m[1].toLowerCase() : "";
301
+ if (!m || ident == "www") {
302
+ return opt_opts.fallbackHandler ?
303
+ opt_opts.fallbackHandler(url, host, path) :
304
+ url;
305
+ }
306
+ return "sgn://" + domain + "/?ident=" + ident;
307
+ };
308
+ };
309
+ nodemapper.createSlashUsernameHandler = function(domain, opt_opts) {
310
+ var slashUsernameRE = /^\/(\w+)\/?$/;
311
+ if (opt_opts && opt_opts.slashAnything) {
312
+ slashUsernameRE = /^\/(\w+)(?:\/|$)/;
313
+ }
314
+ return nodemapper.createPathRegexpHandler(domain, slashUsernameRE, opt_opts);
315
+ };
316
+ nodemapper.createSomethingSlashUsernameHandler = function(prefix,
317
+ domain,
318
+ opt_opts) {
319
+ var slashSomethingUserRE = new RegExp("^/" + prefix + "/" +
320
+ "(\\w+)(?:/|$)");
321
+ return nodemapper.createPathRegexpHandler(domain,
322
+ slashSomethingUserRE,
323
+ opt_opts);
324
+ };
325
+ nodemapper.createUserIsSubdomainHandler = function(domain) {
326
+ var subdomainRE = new RegExp("([\\w\\-]+)\." + domain + "$", "i");
327
+ return nodemapper.createHostRegexpHandler(domain, subdomainRE);
328
+ };
329
+ nodemapper.createFirstMatchHandler = function(handlerList) {
330
+ return function (url, host, path) {
331
+ for (var i = 0; i < handlerList.length; i++) {
332
+ var out = handlerList[i](url, host, path);
333
+ if (out != url) {
334
+ return out;
335
+ }
336
+ }
337
+ return url; // unchanged
338
+ };
339
+ };
340
+ nodemapper.namedSites = function() {
341
+ if (nodemapper._memoizedNamedSites) {
342
+ return nodemapper._memoizedNamedSites;
343
+ }
344
+ var ret = [];
345
+ for (var domain in nodemapper.handlers) {
346
+ var handler = nodemapper.handlers[domain];
347
+ if (handler.name) {
348
+ if (handler.primaryDomain && handler.primaryDomain != domain) {
349
+ continue;
350
+ }
351
+ var canGenerateFeedUrl = false;
352
+ if (handler.ident_to_atom || handler.ident_to_rss
353
+ || handler.pk_to_atom || handler.pk_to_rss) {
354
+ canGenerateFeedUrl = true;
355
+ }
356
+ ret.push({
357
+ domain: domain,
358
+ name: handler.name,
359
+ notMassMarketSite: nodemapper.handlers[domain].notMassMarketSite,
360
+ canGenerateFeedUrl: canGenerateFeedUrl
361
+ });
362
+ }
363
+ }
364
+ ret.sort(function(a, b) {
365
+ if (a.name.toLowerCase() < b.name.toLowerCase()) return -1;
366
+ if (a.name.toLowerCase() > b.name.toLowerCase()) return 1;
367
+ return 0;
368
+ });
369
+ nodemapper._memoizedNamedSites = ret;
370
+ return ret;
371
+ }
372
+ nodemapper.namedSitesCount = function() {
373
+ return nodemapper.namedSites().length;
374
+ }
375
+ nodemapper.namedSiteProperty = function(n, property) {
376
+ return nodemapper.namedSites()[n][property];
377
+ }
378
+ /* install null debug handler, if host container hasn't */
379
+ try {
380
+ if (debug) { }
381
+ } catch (e) {
382
+ debug = function() {};
383
+ }
384
+ (function(){
385
+ var amazonPkHandler = nodemapper.createFirstMatchHandler([
386
+ nodemapper.createSomethingSlashUsernameHandler(
387
+ "gp/pdp/profile", "amazon.com",
388
+ {keyName: "pk", casePreserve: 1}),
389
+ nodemapper.createSomethingSlashUsernameHandler(
390
+ "rss/people", "amazon.com",
391
+ {keyName: "pk", casePreserve: 1})]);
392
+ nodemapper.registerDomain("amazon.com", {
393
+ accountToSgn: { pk: ["amazon.com", /^\w{14,14}$/] },
394
+ urlToGraphNode: amazonPkHandler,
395
+ name: "Amazon.com"
396
+ });
397
+ nodemapper.registerDomain("amazon.co.uk", {
398
+ urlToGraphNode: amazonPkHandler
399
+ });
400
+ nodemapper.addSimpleHandler("amazon.com", "pk_to_profile",
401
+ "http://www.amazon.com/gp/pdp/profile/");
402
+ nodemapper.addSimpleHandler("amazon.com", "pk_to_rss",
403
+ "http://www.amazon.com/rss/people/", "/reviews");
404
+ })();
405
+ (function(){
406
+ var AIM_REGEX = /^aim:(?:goim\?(?:message=[^&\s]+&)?screenname=)?([%\w \+]+)$/i;
407
+ nodemapper.registerNonHTTPHandler(function(url) {
408
+ var m = AIM_REGEX.exec(url);
409
+ if (m) {
410
+ var screenname = m[1].toLowerCase().replace(/(?:[\s\+]|%20)/g, "");
411
+ return "sgn://aol.com/?ident=" + screenname;
412
+ }
413
+ });
414
+ nodemapper.registerDomain(["openid.aol.com", "profiles.aim.com"], {
415
+ urlToGraphNode: nodemapper.createSlashUsernameHandler("aol.com")
416
+ });
417
+ var aimPagesHandler = function(url, host, path) {
418
+ var slashProfile = /^\/{1,2}([\w\+]+)(?:\/(?:profile\.html)?|$)/;
419
+ var m;
420
+ if (!(m = slashProfile.exec(path)))
421
+ return url;
422
+ return "sgn://aol.com/?ident=" + m[1].toLowerCase().replace(/[\s\+]/g, "");
423
+ };
424
+ nodemapper.registerDomain(
425
+ "aimpages.com",
426
+ {urlToGraphNode: aimPagesHandler});
427
+ nodemapper.registerDomain(
428
+ "aol.com",
429
+ {
430
+ name: "AIM/AOL",
431
+ identRegexp: /^\w+$/,
432
+ ident_to_openid: function (ident) { return "http://openid.aol.com/" + ident; },
433
+ ident_to_chat: function (ident) { return "aim:GoIM?screenname=" + ident; },
434
+ ident_to_profile: function (ident) {
435
+ return "http://profiles.aim.com/" + ident;
436
+ }
437
+ });
438
+ nodemapper.registerDomain("pictures.aol.com",
439
+ {name: "AOL Pictures",
440
+ urlToGraphNode: nodemapper.createSomethingSlashUsernameHandler("galleries",
441
+ "pictures.aol.com")});
442
+ nodemapper.addSimpleHandler("pictures.aol.com", "ident_to_profile",
443
+ "http://pictures.aol.com/galleries/");
444
+ nodemapper.addSimpleHandler("pictures.aol.com", "ident_to_atom",
445
+ "http://pictures.aol.com/galleries/", "/atom.xml");
446
+ })();
447
+ (function(){
448
+ var BLOGSPOT_REGEX = /^(?:www\.)?([\w\-]+)\.blogspot\.com$/;
449
+ nodemapper.registerDomain("blogspot.com", {
450
+ name: "Blogger (Blogspot)",
451
+ urlToGraphNode: nodemapper.createHostRegexpHandler("blogspot.com",
452
+ BLOGSPOT_REGEX)
453
+ });
454
+ nodemapper.addSimpleHandler("blogspot.com", "ident_to_blog",
455
+ "http://", ".blogspot.com/");
456
+ nodemapper.addSimpleHandler("blogspot.com", "ident_to_content",
457
+ "http://", ".blogspot.com/");
458
+ nodemapper.addSimpleHandler("blogspot.com", "ident_to_rss",
459
+ "http://", ".blogspot.com/feeds/posts/default?alt=rss");
460
+ nodemapper.addSimpleHandler("blogspot.com", "ident_to_atom",
461
+ "http://", ".blogspot.com/feeds/posts/default");
462
+ nodemapper.registerDomain("blogger.com", {
463
+ name: "Blogger (Profile)",
464
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
465
+ "blogger.com",
466
+ /^\/profile\/(\d+)/, { keyName: "pk" })
467
+ });
468
+ nodemapper.addSimpleHandler("blogger.com", "pk_to_profile",
469
+ "http://www.blogger.com/profile/");
470
+ })();
471
+ (function(){
472
+ var FACEBOOK_ALT_DOMAINS = [
473
+ "facebook.at",
474
+ "facebook.ca",
475
+ "facebook.co.nz",
476
+ "facebook.co.za",
477
+ "facebook.com.au",
478
+ "facebook.de",
479
+ "facebook.dk",
480
+ "facebook.es",
481
+ "facebook.ie",
482
+ "facebook.jp",
483
+ "facebook.net.nz",
484
+ "facebook.no",
485
+ "facebook.pl",
486
+ "facebook.se",
487
+ "facebook.vn"
488
+ ];
489
+ var PRIVATE_PROFILE_RE = /^(?:\/home\.php\#)?\/profile\.php\?id=(\d+)/;
490
+ var PUBLIC_PROFILE_RE = /^\/(?:p|people)\/([^\/]+\/(\d+))/;
491
+ var USERNAME_RE = /^\/(\w[\w\.\-]{2,30}\w)(?:$|[\/\?])/;
492
+ var NOT_USERNAME = {
493
+ people: 1,
494
+ pages: 1,
495
+ directory: 1,
496
+ video: 1,
497
+ apps: 1,
498
+ discography: 1,
499
+ networks: 1,
500
+ help: 1,
501
+ applications: 1,
502
+ reviews: 1,
503
+ ext: 1,
504
+ marketplace: 1
505
+ };
506
+ var facebookHandler = function(url, host, path) {
507
+ var m;
508
+ if (m = PRIVATE_PROFILE_RE.exec(path)) {
509
+ return "sgn://facebook.com/?pk=" + m[1];
510
+ }
511
+ if (m = PUBLIC_PROFILE_RE.exec(path)) {
512
+ return "sgn://facebook.com/?ident=" + m[1];
513
+ }
514
+ if (m = USERNAME_RE.exec(path)) {
515
+ if (m[1].lastIndexOf(".php") == m[1].length - 4 ||
516
+ NOT_USERNAME[m[1].toLowerCase()]) {
517
+ return url;
518
+ }
519
+ return "sgn://facebook.com/?ident=" + m[1].toLowerCase().replace(/[\-\.]/g, "");
520
+ }
521
+ return url;
522
+ };
523
+ nodemapper.registerDomain(
524
+ FACEBOOK_ALT_DOMAINS,
525
+ { urlToGraphNode: facebookHandler });
526
+ nodemapper.registerDomain(
527
+ "facebook.com",
528
+ {name: "Facebook",
529
+ urlToGraphNode: facebookHandler,
530
+ ident_to_profile: function (ident) {
531
+ if (/\//.exec(ident)) {
532
+ return "http://www.facebook.com/people/" + ident;
533
+ } else {
534
+ return "http://www.facebook.com/" + ident;
535
+ }
536
+ },
537
+ pk_to_profile: function (pk) { return "http://www.facebook.com/profile.php?id=" + pk; },
538
+ pkRegexp: /^\d+$/,
539
+ identRegexp: /^(?:.+\/\d+)|(?:\w[\w\.\-]{2,30}\w)$/,
540
+ identCasePreserve: 1
541
+ });
542
+ })();
543
+ (function(){
544
+ function urlToGraphNodeFlickrFallback(url, host, path) {
545
+ var flickerPathRE = /^\/(?:people|photos)\/(\d+@\w+)(?:\/|$)/;
546
+ var m = flickerPathRE.exec(path);
547
+ if (m) {
548
+ return "sgn://flickr.com/?pk=" + m[1];
549
+ }
550
+ return; // undef
551
+ };
552
+ var urlToGraphNodeFlickr =
553
+ nodemapper.createPathRegexpHandler(
554
+ "flickr.com",
555
+ /^(?:\/(?:people|photos))?\/([\w\-]+)(?:\/|$)/,
556
+ {fallbackHandler: urlToGraphNodeFlickrFallback,
557
+ notUsernames: {
558
+ photos: 1,
559
+ groups: 1,
560
+ people: 1,
561
+ search: 1,
562
+ places: 1,
563
+ help: 1,
564
+ services: 1,
565
+ explore: 1,
566
+ groups_topics: 1,
567
+ photo: 1,
568
+ creativecommons: 1,
569
+ commons: 1,
570
+ cameras: 1,
571
+ photo_zoom: 1,
572
+ signin: 1,
573
+ forums: 1,
574
+ apps: 1,
575
+ slideShow: 1,
576
+ map: 1,
577
+ account: 1,
578
+ groups_topic: 1
579
+ },
580
+ pathTransform: function(path) { return path.replace('%40', '@'); }
581
+ });
582
+ nodemapper.registerDomain(
583
+ "flickr.com", {
584
+ name: "Flickr",
585
+ urlToGraphNode: urlToGraphNodeFlickr,
586
+ pkRegexp: /^\d+@\w\d+$/,
587
+ accountToSgn: { pk: ["flickr.com", /^\d+@\w\d+$/],
588
+ ident: ["flickr.com", /^[\-\w]+$/] }
589
+ });
590
+ nodemapper.addSimpleHandler("flickr.com", "pk_to_rss",
591
+ "http://api.flickr.com/services/feeds/photos_public.gne?id=", "&lang=en-us&format=rss_200");
592
+ nodemapper.addSimpleHandler("flickr.com", "pk_to_atom",
593
+ "http://api.flickr.com/services/feeds/photos_public.gne?id=", "&lang=en-us&format=atom");
594
+ for (var i = 0; i < 2; i++) {
595
+ var type = ["pk", "ident"][i];
596
+ nodemapper.addSimpleHandler("flickr.com", type + "_to_profile",
597
+ "http://www.flickr.com/people/", "/");
598
+ nodemapper.addSimpleHandler("flickr.com", type + "_to_addfriend",
599
+ "http://www.flickr.com/people/", "/relationship/");
600
+ nodemapper.addSimpleHandler("flickr.com", type + "_to_content",
601
+ "http://www.flickr.com/photos/", "/");
602
+ }
603
+ })();
604
+ (function(){
605
+ nodemapper.registerDomain("friendfeed.com",
606
+ {
607
+ name: "FriendFeed",
608
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
609
+ "friendfeed.com", /^\/(\w+)/)
610
+ });
611
+ nodemapper.addSimpleHandler("friendfeed.com", "ident_to_profile",
612
+ "http://friendfeed.com/");
613
+ nodemapper.addSimpleHandler("friendfeed.com", "ident_to_atom",
614
+ "http://friendfeed.com/", "?format=atom");
615
+ })();
616
+ (function(){
617
+ var GOOGLE_TLDS = "ad ae am as at az ba be bg bi bs ca cd cg ch ci cl cn co.bw co.ck co.cr co.id co.il co.im co.in co.je co.jp co.ke co.kr co.ls co.ma co.mw co.nz co.pn co.th co.tt co.ug co.uk co.uz co.ve co.vi co.yu co.za co.zm co.zw com com.af com.ag com.ar com.au com.bd com.bh com.bn com.bo com.br com.bz com.cn com.co com.cu com.do com.ec com.eg com.et com.fj com.gi com.gr com.gt com.hk com.jm com.kh com.kz com.lv com.ly com.mt com.mw com.mx com.my com.na com.nf com.ng com.ni com.np com.om com.pa com.pe com.ph com.pk com.pl com.pr com.py com.qa com.ru com.sa com.sb com.sg com.sl com.sv com.tj com.tr com.tt com.tw com.ua com.uy com.vc com.ve com.vn cz de dj dk dm ee es fi fm fr ge gg gl gm gp gr gy hk hn hr ht hu ie is it je jo kg ki kz la li lk lt lu lv md me mn ms mu mv mw ne.jp nl no nr nu off.ai ph pl pn pt ro ru rw sc se sg sh si sk sl sm sn st tk tl tm to tp tt us vg vn vu ws".split(" ");
618
+ function googleDomains(prefix) {
619
+ var ret = [];
620
+ for (var idx in GOOGLE_TLDS) {
621
+ ret.push(prefix + GOOGLE_TLDS[idx]);
622
+ }
623
+ return ret;
624
+ }
625
+ var GOOGLE_DOMAINS = googleDomains("google.");
626
+ var READER_RE = /^\/reader\/(?:shared|public\/atom\/user)\/(\d{7,})(?:\/state\/com.google\/broadcast)?/;
627
+ var googleIdentProfileHandler = nodemapper.createPathRegexpHandler(
628
+ "profiles.google.com", // fake domain
629
+ /^(?:\/s2)?\/(?:profiles\/|sharing\/stuff\?user=)([\w+\.]+)/,
630
+ {keyName: "ident"});
631
+ var googleProfileHandler = nodemapper.createPathRegexpHandler(
632
+ "profiles.google.com", // fake domain
633
+ /^(?:\/s2)?\/(?:profiles\/|sharing\/stuff\?user=)(\d+)/,
634
+ {keyName: "pk", fallbackHandler: googleIdentProfileHandler });
635
+ var readerHandler = nodemapper.createPathRegexpHandler(
636
+ "reader.google.com", // fake domain
637
+ READER_RE,
638
+ {keyName: "pk"});
639
+ var profilesDomainIdentHandler = nodemapper.createPathRegexpHandler(
640
+ "profiles.google.com", // fake domain
641
+ /^\/([\w+\.]+)(?:\?|$)/,
642
+ {keyName: "ident"})
643
+ googleMasterHandler = function(url, host, path) {
644
+ var handler = null;
645
+ if (path.indexOf("/reader") == 0) {
646
+ handler = readerHandler;
647
+ } else if (path.indexOf("/s2/") == 0) {
648
+ handler = googleProfileHandler;
649
+ } else if (path.indexOf("/profiles/") == 0) {
650
+ handler = googleProfileHandler;
651
+ }
652
+ if (handler) return handler(url, host, path);
653
+ return url;
654
+ };
655
+ nodemapper.registerDomain(GOOGLE_DOMAINS, {urlToGraphNode: googleMasterHandler});
656
+ nodemapper.registerDomain("reader.google.com", {
657
+ name: "Google Reader",
658
+ pkRegexp: /^\d{7,}$/
659
+ });
660
+ nodemapper.addSimpleHandler("reader.google.com", "pk_to_content",
661
+ "http://www.google.com/reader/shared/", "");
662
+ nodemapper.addSimpleHandler("reader.google.com", "pk_to_profile",
663
+ "http://www.google.com/reader/shared/", "");
664
+ nodemapper.addSimpleHandler("reader.google.com", "pk_to_atom",
665
+ "http://www.google.com/reader/public/atom/user/",
666
+ "/state/com.google/broadcast");
667
+ var PROFILE_RE = /^\/profile\?user=(\w+)/;
668
+ var USER_RE = /^\/(?:(?:rss\/)?user\/)?(\w+)\b/;
669
+ var YOUTUBE_NOT_USERNAME = {
670
+ 'blog': true,
671
+ 'browse': true,
672
+ 'community': true,
673
+ 'dev': true,
674
+ 'feeds': true,
675
+ 'greetings': true,
676
+ 'inbox': true,
677
+ 'jobs': true,
678
+ 'members': true,
679
+ 'my_account': true,
680
+ 'my_favorites': true,
681
+ 'my_playlists': true,
682
+ 'my_subscriptions': true,
683
+ 'my_videos': true,
684
+ 'press_room': true,
685
+ 'support': true,
686
+ 't': true,
687
+ 'testtube': true,
688
+ 'watch': true,
689
+ 'watch_queue': true,
690
+ 'youtubeonyoursite': true
691
+ };
692
+ var youTubeToSgn = function(url, host, path) {
693
+ var m;
694
+ if ((m = PROFILE_RE.exec(path)) || (m = USER_RE.exec(path))) {
695
+ var username = m[1].toLowerCase();
696
+ if (YOUTUBE_NOT_USERNAME[username]) {
697
+ return url;
698
+ }
699
+ return "sgn://youtube.com/?ident=" + username;
700
+ }
701
+ return url;
702
+ };
703
+ nodemapper.registerDomain(
704
+ "youtube.com",
705
+ {name: "YouTube",
706
+ urlToGraphNode: youTubeToSgn});
707
+ nodemapper.registerDomain(
708
+ "gdata.youtube.com",
709
+ {urlToGraphNode: nodemapper.createSomethingSlashUsernameHandler(
710
+ "feeds/base/users",
711
+ "youtube.com")});
712
+ nodemapper.addSimpleHandler(
713
+ "youtube.com", "ident_to_profile",
714
+ "http://youtube.com/user/");
715
+ nodemapper.addSimpleHandler(
716
+ "youtube.com", "ident_to_rss",
717
+ "http://youtube.com/rss/user/", "/videos.rss");
718
+ nodemapper.registerDomain(
719
+ googleDomains("picasaweb.google."),
720
+ {name: "Picasa Web Albums",
721
+ primaryDomain: "picasaweb.google.com",
722
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
723
+ "picasaweb.google.com",
724
+ /^\/([\w\.]+)\/?$/
725
+ )});
726
+ nodemapper.addSimpleHandler("picasaweb.google.com", "ident_to_profile",
727
+ "http://picasaweb.google.com/");
728
+ nodemapper.addSimpleHandler("picasaweb.google.com", "ident_to_rss",
729
+ "http://picasaweb.google.com/data/feed/base/user/",
730
+ "?kind=album&alt=rss&hl=en_US&access=public");
731
+ nodemapper.registerDomain(
732
+ "dodgeball.com",
733
+ {name: "Dodgeball",
734
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
735
+ "dodgeball.com",
736
+ /^\/user\?uid=(\d+)/, { keyName: "pk" })
737
+ });
738
+ nodemapper.addSimpleHandler("dodgeball.com", "pk_to_profile",
739
+ "http://www.dodgeball.com/user?uid=", "");
740
+ nodemapper.registerDomain(
741
+ "orkut.com",
742
+ {name: "Orkut",
743
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
744
+ "orkut.com",
745
+ /^\/Profile.aspx\?uid=(\d+)/, { keyName: "pk" })
746
+ });
747
+ nodemapper.addSimpleHandler("orkut.com", "pk_to_profile",
748
+ "http://www.orkut.com/Profile.aspx?uid=");
749
+ nodemapper.registerDomain("profiles.google.com", {
750
+ urlToGraphNode: profilesDomainIdentHandler,
751
+ name: "Google Profile",
752
+ pkRegexp: /^\d{7,}$/,
753
+ identRegexp: /^[\w\.]{1,40}$/
754
+ });
755
+ nodemapper.addSimpleHandler("profiles.google.com", "pk_to_profile",
756
+ "http://www.google.com/profiles/");
757
+ nodemapper.addSimpleHandler("profiles.google.com", "ident_to_profile",
758
+ "http://www.google.com/profiles/");
759
+ })();
760
+ (function(){
761
+ var HAS_ID_REGEXP = /\b(?:ownerId=|userid=|friend\/|\/profile\/foaf\/)(\d+)/;
762
+ var FRIEND_ID_REGEXP = /^\/friend\/p(\d+)-/;
763
+ var DISPLAY_PROFILE = /^\/friend\/profile\/displayHi5URL\.do\?nickname=([\w\-]{6,})\b/;
764
+ var NUMERIC_DOMAIN = /^(\d+)\.hi5\.com$/;
765
+ function urlToGraphNodeHi5(url, host, path) {
766
+ var m;
767
+ if ((m = HAS_ID_REGEXP.exec(path)) ||
768
+ (m = FRIEND_ID_REGEXP.exec(path))) {
769
+ return "sgn://hi5.com/?pk=" + m[1];
770
+ }
771
+ if (path == "/" && (m = /^([\w\-]{6,})\.hi5\.com$/.exec(host))) {
772
+ var match = m[1];
773
+ if (/[^\d]/.exec(match)) {
774
+ return "sgn://hi5.com/?ident=" + m[1].toLowerCase();
775
+ } else {
776
+ return "sgn://hi5.com/?pk=" + m[1];
777
+ }
778
+ }
779
+ if (m = DISPLAY_PROFILE.exec(path)) {
780
+ return "sgn://hi5.com/?ident=" + m[1].toLowerCase();
781
+ }
782
+ if ((m = NUMERIC_DOMAIN.exec(host)) && !/\?/.exec(path)) {
783
+ return "sgn://hi5.com/?pk=" + m[1];
784
+ }
785
+ return url;
786
+ }
787
+ nodemapper.registerDomain(
788
+ "hi5.com", {
789
+ name: "hi5",
790
+ urlToGraphNode: urlToGraphNodeHi5
791
+ });
792
+ nodemapper.addSimpleHandler("hi5.com", "pk_to_foaf",
793
+ "http://api.hi5.com/rest/profile/foaf/", "");
794
+ nodemapper.addSimpleHandler("hi5.com", "pk_to_content",
795
+ "http://www.hi5.com/friend/profile/displayProfile.do?userid=", "");
796
+ nodemapper.addSimpleHandler("hi5.com", "pk_to_profile",
797
+ "http://www.hi5.com/friend/profile/displayProfile.do?userid=", "");
798
+ nodemapper.addSimpleHandler("hi5.com", "pk_to_atom",
799
+ "http://api.hi5.com/rest/feed/journal/", "");
800
+ nodemapper.addSimpleHandler("hi5.com", "pk_to_foaf",
801
+ "http://api.hi5.com/rest/profile/foaf/", "");
802
+ nodemapper.addSimpleHandler("hi5.com", "pk_to_blog",
803
+ "http://www.hi5.com/friend/profile/displayJournal.do?userid=", "");
804
+ nodemapper.addSimpleHandler("hi5.com", "ident_to_content",
805
+ "http://", ".hi5.com/");
806
+ nodemapper.addSimpleHandler("hi5.com", "ident_to_profile",
807
+ "http://", ".hi5.com/");
808
+ })();
809
+ (function(){
810
+ var LAST_FM_ALT_DOMAINS = [
811
+ "cn.last.fm",
812
+ "lastfm.excite.co.jp",
813
+ "lastfm.spiegel.de",
814
+ "www.last.fm",
815
+ "www.lastfm.com.br",
816
+ "www.lastfm.at",
817
+ "www.lastfm.ch",
818
+ "www.lastfm.co.kr",
819
+ "www.lastfm.com.br",
820
+ "www.lastfm.com.tr",
821
+ "www.lastfm.de",
822
+ "www.lastfm.es",
823
+ "www.lastfm.fr",
824
+ "www.lastfm.it",
825
+ "www.lastfm.jp",
826
+ "www.lastfm.pl",
827
+ "www.lastfm.pt",
828
+ "www.lastfm.ru",
829
+ "www.lastfm.se"
830
+ ];
831
+ var lastFmHttpToSgn = nodemapper.createPathRegexpHandler(
832
+ "last.fm", /^\/user\/([\w\-]+)(?:\/|$)/);
833
+ nodemapper.registerDomain(
834
+ "last.fm",
835
+ {name: "Last.fm",
836
+ urlToGraphNode: lastFmHttpToSgn});
837
+ nodemapper.registerDomain(
838
+ LAST_FM_ALT_DOMAINS,
839
+ {urlToGraphNode: lastFmHttpToSgn});
840
+ nodemapper.addSimpleHandler("last.fm", "ident_to_profile",
841
+ "http://www.last.fm/user/", "/");
842
+ })();
843
+ (function(){
844
+ var LJCOM_MAIN_DOMAIN_REGEX = /^\/(?:~|users\/|community\/)(\w+)(?:\/|$)/;
845
+ var LJCOM_USERINFO_BML_REGEX = /^\/userinfo\.bml\?(user|userid)=(\w+)/;
846
+ var LJCOM_MISC_BML_REGEX = /^\/(?:go|talkread)\.bml\?.*\bjournal=(\w+)/;
847
+ var LJCOM_MISC_FDATA_REGEX = /^\/misc\/fdata2?\.bml\?.*\buser=(\w+)/;
848
+ var urlToGraphNodeUsersCommunity = function(url, host, path) {
849
+ var slashUserMaybeProfile = /^\/(\w+)(?:\/|\/profile|$)/;
850
+ var m;
851
+ if (!(m = slashUserMaybeProfile.exec(path))) {
852
+ return url;
853
+ }
854
+ return "sgn://livejournal.com/?ident=" + m[1].toLowerCase();
855
+ };
856
+ nodemapper.registerDomain(["users.livejournal.com",
857
+ "community.livejournal.com"],
858
+ {urlToGraphNode:urlToGraphNodeUsersCommunity});
859
+ var urlToGraphNodeGeneral = function(url, host, path) {
860
+ var m;
861
+ if (host == "pics.livejournal.com") {
862
+ return url;
863
+ }
864
+ if (host == "www.livejournal.com" || host == "livejournal.com") {
865
+ if (m = LJCOM_MAIN_DOMAIN_REGEX.exec(path)) {
866
+ return "sgn://livejournal.com/?ident=" + m[1].toLowerCase();
867
+ }
868
+ if (m = LJCOM_USERINFO_BML_REGEX.exec(path)) {
869
+ if (m[1] == "user") {
870
+ return "sgn://livejournal.com/?ident=" + m[2].toLowerCase();
871
+ } else {
872
+ return "sgn://livejournal.com/?pk=" + m[2];
873
+ }
874
+ }
875
+ if (m = LJCOM_MISC_BML_REGEX.exec(path)) {
876
+ return "sgn://livejournal.com/?ident=" + m[1].toLowerCase();
877
+ }
878
+ if (m = LJCOM_MISC_FDATA_REGEX.exec(path)) {
879
+ return "sgn://livejournal.com/?ident=" + m[1].toLowerCase();
880
+ }
881
+ return url;
882
+ }
883
+ var hostparts = host.split(".");
884
+ var user = hostparts[0].replace(/-/g, "_");
885
+ return "sgn://livejournal.com/?ident=" + user;
886
+ };
887
+ var journalBase = function (ident) {
888
+ if (ident.indexOf("_") == 0) {
889
+ return "http://www.livejournal.com/~" + ident + "/";
890
+ }
891
+ return "http://" + ident.replace("_", "-") + ".livejournal.com/";
892
+ };
893
+ var appendToBase = function (suffix) {
894
+ return function(ident) { return journalBase(ident) + suffix; };
895
+ };
896
+ var identToContent = journalBase;
897
+ var identToRss = appendToBase("data/rss");
898
+ var identToAtom = appendToBase("data/atom");
899
+ var identToFoaf = appendToBase("data/foaf");
900
+ var identToProfile = appendToBase("profile");
901
+ var identToOpenid = journalBase;
902
+ nodemapper.registerDomain("livejournal.com",
903
+ {urlToGraphNode: urlToGraphNodeGeneral,
904
+ ident_to_content: identToContent,
905
+ ident_to_rss: identToRss,
906
+ ident_to_atom: identToAtom,
907
+ ident_to_foaf: identToFoaf,
908
+ ident_to_profile: identToProfile,
909
+ ident_to_openid: identToOpenid,
910
+ identRegexp: /^\w+$/,
911
+ name: "LiveJournal"
912
+ });
913
+ nodemapper.registerDomain(
914
+ "pics.livejournal.com",
915
+ {urlToGraphNode: nodemapper.createSlashUsernameHandler(
916
+ "livejournal.com",
917
+ { slashAnything: 1 })});
918
+ })();
919
+ (function(){
920
+ meetupHandler = function(url, host, path) {
921
+ var primaryKeyRegexp = /\/members\/(\d+)(?:\/|$)/;
922
+ var m;
923
+ if (!(m = primaryKeyRegexp.exec(path))) {
924
+ return url;
925
+ }
926
+ return "sgn://meetup.com/?pk=" + m[1];
927
+ };
928
+ nodemapper.registerDomain("meetup.com", {
929
+ name: "Meetup",
930
+ urlToGraphNode: meetupHandler
931
+ });
932
+ nodemapper.addSimpleHandler("meetup.com", "pk_to_profile",
933
+ "http://www.meetup.com/members/", "/");
934
+ })();
935
+ (function(){
936
+ var BUZZ_MEMBER_REGEXP = /^\/buzz\/members\/(?:mybloglog([0-9a-f]{20,20})|([\w\-]+))(?:\/|$)/;
937
+ var toSgn = function(url, host, path) {
938
+ var m;
939
+ if (!(m = BUZZ_MEMBER_REGEXP.exec(path))) {
940
+ return url;
941
+ }
942
+ if (m[1]) {
943
+ return "sgn://mybloglog.com/?pk=" + m[1].toLowerCase();
944
+ } else {
945
+ return "sgn://mybloglog.com/?ident=" + m[2].toLowerCase();
946
+ }
947
+ };
948
+ var PK_REGEXP = /^(?:mybloglog)?([0-9a-f]{20,20})$/;
949
+ nodemapper.registerDomain("mybloglog.com", {
950
+ urlToGraphNode: toSgn,
951
+ accountToSgn: { pk: ["mybloglog.com", PK_REGEXP],
952
+ ident: ["mybloglog.com", /^[\w-]+$/] },
953
+ pkRegexp: PK_REGEXP,
954
+ name: "MyBlogLog"
955
+ });
956
+ nodemapper.addSimpleHandler("mybloglog.com", "ident_to_foaf",
957
+ "http://www.mybloglog.com/buzz/members/", "/foaf");
958
+ nodemapper.addSimpleHandler("mybloglog.com", "ident_to_profile",
959
+ "http://www.mybloglog.com/buzz/members/", "/");
960
+ nodemapper.addSimpleHandler("mybloglog.com", "pk_to_foaf",
961
+ "http://www.mybloglog.com/buzz/members/mybloglog", "/foaf");
962
+ nodemapper.addSimpleHandler("mybloglog.com", "pk_to_profile",
963
+ "http://www.mybloglog.com/buzz/members/mybloglog", "/");
964
+ })();
965
+ (function(){
966
+ var ACTION_REGEX = /index\.cfm\?fuseaction=(.+)&friendID=(\d+)/i;
967
+ var SLASH_WHATEVER_REGEX = /^\/(\d+)|([a-z]\w*)(?:\?|$)/;
968
+ var MYSPACE_USER_ACTIONS = {
969
+ "user.viewprofile": 1,
970
+ "user.viewfriends": 1,
971
+ "blog.listall": 1,
972
+ "blog.confirmsubscribe": 1
973
+ };
974
+ function urlToGraphNodeMySpace(url, host, path) {
975
+ var m = ACTION_REGEX.exec(path);
976
+ if (m) {
977
+ var action = m[1].toLowerCase();
978
+ var userid = m[2];
979
+ if (MYSPACE_USER_ACTIONS[action]) {
980
+ return "sgn://myspace.com/?pk=" + userid;
981
+ }
982
+ }
983
+ if (host == "profile.myspace.com") {
984
+ m = SLASH_WHATEVER_REGEX.exec(path);
985
+ if (m) {
986
+ if (m[1]) {
987
+ return "sgn://myspace.com/?pk=" + m[1];
988
+ }
989
+ if (m[2]) {
990
+ return "sgn://myspace.com/?ident=" + m[2];
991
+ }
992
+ }
993
+ }
994
+ return url;
995
+ };
996
+ var urlToGraphNodeMySpaceUsername =
997
+ nodemapper.createSlashUsernameHandler(
998
+ "myspace.com",
999
+ {fallbackHandler: urlToGraphNodeMySpace});
1000
+ nodemapper.registerDomain(
1001
+ "myspace.com",
1002
+ {name: "MySpace",
1003
+ urlToGraphNode: urlToGraphNodeMySpaceUsername,
1004
+ accountToSgn: { pk: ["myspace.com"], ident: ["myspace.com"] }
1005
+ });
1006
+ nodemapper.addSimpleHandler(
1007
+ "myspace.com", "ident_to_profile",
1008
+ "http://www.myspace.com/");
1009
+ nodemapper.addSimpleHandler(
1010
+ "myspace.com", "ident_to_content",
1011
+ "http://www.myspace.com/");
1012
+ nodemapper.addSimpleHandler(
1013
+ "myspace.com", "pk_to_profile",
1014
+ "http://profile.myspace.com/index.cfm?fuseaction=user.viewprofile&friendid=");
1015
+ nodemapper.addSimpleHandler(
1016
+ "myspace.com", "pk_to_content",
1017
+ "http://profile.myspace.com/index.cfm?fuseaction=user.viewprofile&friendid=");
1018
+ nodemapper.addSimpleHandler(
1019
+ "myspace.com", "pk_to_rss",
1020
+ "http://blog.myspace.com/blog/rss.cfm?friendID=");
1021
+ nodemapper.addSimpleHandler(
1022
+ "myspace.com", "pk_to_blog",
1023
+ "http://blog.myspace.com/index.cfm?fuseaction=blog.ListAll&friendID=");
1024
+ nodemapper.registerDomain(
1025
+ ["profile.myspace.com", "blog.myspace.com"],
1026
+ {urlToGraphNode: urlToGraphNodeMySpace});
1027
+ })();
1028
+ (function(){
1029
+ var XMPP_REGEX = /^(?:xmpp|jabber):(.+)/i;
1030
+ var MAILTO_REGEX = /^mailto:(.+)/i;
1031
+ nodemapper.registerNonHTTPHandler(function(url) {
1032
+ var m;
1033
+ if (m = XMPP_REGEX.exec(url)) {
1034
+ return "xmpp:" + m[1].replace(/%40/, "@");
1035
+ }
1036
+ if (m = MAILTO_REGEX.exec(url)) {
1037
+ return "mailto:" + m[1].replace(/%40/, "@");
1038
+ }
1039
+ });
1040
+ })();
1041
+ (function(){
1042
+ var IDENT_REGEXP = /^[\w\-\%\.\:\*]+$/;
1043
+ var SLASH_WHATEVER = /^\/([^\/]+)(?:\/|$)/;
1044
+ var toSgn = function(url, host, path) {
1045
+ var m;
1046
+ if (!(m = SLASH_WHATEVER.exec(path))) {
1047
+ return;
1048
+ }
1049
+ var username = m[1];
1050
+ if (!(m = IDENT_REGEXP.exec(username))) {
1051
+ return url;
1052
+ }
1053
+ return "sgn://my.opera.com/?ident=" + username.toLowerCase();
1054
+ };
1055
+ nodemapper.registerDomain("my.opera.com", {
1056
+ name: "My Opera",
1057
+ identRegexp: IDENT_REGEXP,
1058
+ pkRegexp: /^ dontmatchme $/,
1059
+ urlToGraphNode: toSgn
1060
+ });
1061
+ nodemapper.addSimpleHandler("my.opera.com", "ident_to_profile",
1062
+ "http://my.opera.com/", "/about/");
1063
+ nodemapper.addSimpleHandler("my.opera.com", "ident_to_foaf",
1064
+ "http://my.opera.com/", "/xml/foaf/");
1065
+ })();
1066
+ (function(){
1067
+ nodemapper.registerDomain(
1068
+ "gallery.ru",
1069
+ {urlToGraphNode: nodemapper.createUserIsSubdomainHandler("gallery.ru"),
1070
+ name: "Gallery.ru"
1071
+ });
1072
+ nodemapper.addSimpleHandler("gallery.ru", "ident_to_foaf",
1073
+ "http://", ".gallery.ru/foaf/");
1074
+ nodemapper.addSimpleHandler("gallery.ru", "ident_to_profile",
1075
+ "http://", ".gallery.ru/");
1076
+ nodemapper.registerDomain(
1077
+ "blogonline.ru",
1078
+ {urlToGraphNode: nodemapper.createUserIsSubdomainHandler("blogonline.ru"),
1079
+ name: "blogonline.ru"
1080
+ });
1081
+ nodemapper.addSimpleHandler("blogonline.ru", "ident_to_foaf",
1082
+ "http://", ".blogonline.ru/data/foaf");
1083
+ nodemapper.addSimpleHandler("blogonline.ru", "ident_to_profile",
1084
+ "http://", ".blogonline.ru/profile");
1085
+ nodemapper.addSimpleHandler("blogonline.ru", "ident_to_blog",
1086
+ "http://", ".blogonline.ru/");
1087
+ nodemapper.registerDomain(
1088
+ "privet.ru",
1089
+ {urlToGraphNode: nodemapper.createSomethingSlashUsernameHandler("user", "privet.ru"),
1090
+ name: "privet.ru"
1091
+ });
1092
+ nodemapper.addSimpleHandler("privet.ru", "ident_to_foaf",
1093
+ "http://www.privet.ru/user/", "/foaf");
1094
+ nodemapper.addSimpleHandler("privet.ru", "ident_to_blog",
1095
+ "http://blogs.privet.ru/user/");
1096
+ nodemapper.addSimpleHandler("privet.ru", "ident_to_profile",
1097
+ "http://www.privet.ru/user/");
1098
+ })();
1099
+ (function(){
1100
+ nodemapper.registerDomain(
1101
+ "blogs.sapo.pt",
1102
+ {urlToGraphNode: nodemapper.createUserIsSubdomainHandler("blogs.sapo.pt"),
1103
+ name: "SAPO"
1104
+ });
1105
+ nodemapper.addSimpleHandler("blogs.sapo.pt", "ident_to_foaf",
1106
+ "http://", ".blogs.sapo.pt/data/foaf");
1107
+ nodemapper.addSimpleHandler("blogs.sapo.pt", "ident_to_blog",
1108
+ "http://", ".blogs.sapo.pt/");
1109
+ })();
1110
+ (function(){
1111
+ nodemapper.registerDomain(
1112
+ "digg.com",
1113
+ {name: "Digg",
1114
+ urlToGraphNode: nodemapper.createSomethingSlashUsernameHandler(
1115
+ "(?:users|rss)",
1116
+ "digg.com")});
1117
+ nodemapper.addSimpleHandler("digg.com", "ident_to_profile",
1118
+ "http://digg.com/users/", "/");
1119
+ nodemapper.addSimpleHandler("digg.com", "ident_to_rss",
1120
+ "http://digg.com/users/", "/history/diggs.rss");
1121
+ nodemapper.registerDomain(
1122
+ "pownce.com",
1123
+ {name: "Pownce",
1124
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
1125
+ "pownce.com", /^\/(?:feeds\/public\/)?(\w+)(?:[.\/]|$)/, {slashAnything: 1})});
1126
+ nodemapper.addSimpleHandler("pownce.com", "ident_to_profile",
1127
+ "http://pownce.com/");
1128
+ nodemapper.addSimpleHandler("pownce.com", "ident_to_rss",
1129
+ "http://pownce.com/feeds/public/", ".rss");
1130
+ nodemapper.addSimpleHandler("pownce.com", "ident_to_atom",
1131
+ "http://pownce.com/feeds/public/", ".atom");
1132
+ nodemapper.registerDomain(
1133
+ "jaiku.com",
1134
+ {name: "Jaiku",
1135
+ urlToGraphNode: nodemapper.createUserIsSubdomainHandler("jaiku.com")});
1136
+ nodemapper.addSimpleHandler("jaiku.com", "ident_to_profile",
1137
+ "http://", ".jaiku.com/");
1138
+ nodemapper.addSimpleHandler("jaiku.com", "ident_to_rss",
1139
+ "http://", ".jaiku.com/feed/rss");
1140
+ nodemapper.registerDomain(
1141
+ "mugshot.org",
1142
+ {name: "Mugshot",
1143
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
1144
+ "mugshot.org",
1145
+ /^\/person\?who=(\w+)/,
1146
+ {casePreserve: 1}),
1147
+ identCasePreserve: 1,
1148
+ accountToSgn: {ident: ["mugshot.org"]}
1149
+ });
1150
+ nodemapper.addSimpleHandler("mugshot.org", "ident_to_profile",
1151
+ "http://mugshot.org/person?who=", "");
1152
+ nodemapper.registerDomain(
1153
+ "linkedin.com",
1154
+ {name: "LinkedIn",
1155
+ urlToGraphNode: nodemapper.createSomethingSlashUsernameHandler(
1156
+ "in",
1157
+ "linkedin.com")});
1158
+ nodemapper.addSimpleHandler("linkedin.com", "ident_to_profile",
1159
+ "http://www.linkedin.com/in/", "");
1160
+ nodemapper.registerDomain(
1161
+ "ma.gnolia.com",
1162
+ {name: "Ma.gnolia",
1163
+ urlToGraphNode: nodemapper.createSomethingSlashUsernameHandler(
1164
+ "people",
1165
+ "ma.gnolia.com")});
1166
+ nodemapper.addSimpleHandler("ma.gnolia.com", "ident_to_profile",
1167
+ "http://ma.gnolia.com/people/");
1168
+ nodemapper.addSimpleHandler("ma.gnolia.com", "ident_to_rss",
1169
+ "http://ma.gnolia.com/rss/full/people/");
1170
+ nodemapper.registerDomain(
1171
+ "ziki.com",
1172
+ {name: "Ziki",
1173
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
1174
+ "ziki.com",
1175
+ /^\/\w\w\/people\/(\w+)\/?/)});
1176
+ nodemapper.addSimpleHandler("ziki.com", "ident_to_profile",
1177
+ "http://www.ziki.com/people/", "");
1178
+ nodemapper.registerDomain(
1179
+ ["del.icio.us", "delicious.com"],
1180
+ {name: "del.icio.us",
1181
+ primaryDomain: "del.icio.us",
1182
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
1183
+ "del.icio.us", /^\/(?:rss\/)?(\w+)/,
1184
+ { notUsernames: { "rss": 1 }, slashAnything: 1})});
1185
+ nodemapper.addSimpleHandler("del.icio.us", "ident_to_profile",
1186
+ "http://delicious.com/");
1187
+ nodemapper.addSimpleHandler("del.icio.us", "ident_to_rss",
1188
+ "http://feeds.delicious.com/rss/");
1189
+ nodemapper.registerDomain(
1190
+ ["tungle.me", "tgl.me"],
1191
+ {name: "Tungle.me",
1192
+ primaryDomain: "tungle.me",
1193
+ urlToGraphNode: nodemapper.createSlashUsernameHandler(
1194
+ "tungle.me")});
1195
+ nodemapper.addSimpleHandler("tungle.me", "ident_to_profile",
1196
+ "http://tungle.me/");
1197
+ nodemapper.registerDomain("webshots.com", {
1198
+ name: "Webshots",
1199
+ identRegexp: /^\w+$/
1200
+ });
1201
+ nodemapper.registerDomain("community.webshots.com",
1202
+ {urlToGraphNode: nodemapper.createSomethingSlashUsernameHandler("user",
1203
+ "webshots.com")});
1204
+ nodemapper.addSimpleHandler("webshots.com", "ident_to_profile",
1205
+ "http://community.webshots.com/user/");
1206
+ nodemapper.addSimpleHandler("webshots.com", "ident_to_rss",
1207
+ "http://community.webshots.com/rss?contentType=rss&type=user&value=");
1208
+ nodemapper.registerDomain(
1209
+ "smugmug.com",
1210
+ {name: "SmugMug",
1211
+ urlToGraphNode: nodemapper.createUserIsSubdomainHandler("smugmug.com")});
1212
+ nodemapper.addSimpleHandler("smugmug.com", "ident_to_profile",
1213
+ "http://", ".smugmug.com/");
1214
+ nodemapper.addSimpleHandler("smugmug.com", "ident_to_atom",
1215
+ "http://www.smugmug.com/hack/feed.mg?Type=nicknameRecentPhotos&Data=",
1216
+ "&format=atom03");
1217
+ nodemapper.registerDomain(
1218
+ "vox.com",
1219
+ {name: "Vox",
1220
+ urlToGraphNode: nodemapper.createUserIsSubdomainHandler("vox.com")});
1221
+ nodemapper.addSimpleHandler("vox.com", "ident_to_content",
1222
+ "http://", ".vox.com/");
1223
+ nodemapper.addSimpleHandler("vox.com", "ident_to_profile",
1224
+ "http://", ".vox.com/profile/");
1225
+ nodemapper.addSimpleHandler("vox.com", "ident_to_rss",
1226
+ "http://", ".vox.com/library/rss-full.xml");
1227
+ nodemapper.addSimpleHandler("vox.com", "ident_to_atom",
1228
+ "http://", ".vox.com/library/atom-full.xml");
1229
+ nodemapper.addSimpleHandler("vox.com", "ident_to_foaf",
1230
+ "http://", ".vox.com/profile/foaf.rdf");
1231
+ nodemapper.registerDomain(
1232
+ "tumblr.com",
1233
+ {name: "Tumblr",
1234
+ urlToGraphNode: nodemapper.createUserIsSubdomainHandler("tumblr.com")});
1235
+ nodemapper.addSimpleHandler("tumblr.com", "ident_to_profile",
1236
+ "http://", ".tumblr.com/");
1237
+ nodemapper.addSimpleHandler("tumblr.com", "ident_to_rss",
1238
+ "http://", ".tumblr.com/rss");
1239
+ nodemapper.registerDomain(
1240
+ "xanga.com",
1241
+ {name: "Xanga",
1242
+ urlToGraphNode: nodemapper.createSlashUsernameHandler(
1243
+ "xanga.com", { slashAnything: 1 })});
1244
+ nodemapper.addSimpleHandler("xanga.com", "ident_to_profile",
1245
+ "http://xanga.com/");
1246
+ nodemapper.addSimpleHandler("xanga.com", "ident_to_rss",
1247
+ "http://xanga.com/", "/rss");
1248
+ nodemapper.registerDomain(
1249
+ "360.yahoo.com",
1250
+ {name: "Yahoo! 360",
1251
+ urlToGraphNode: nodemapper.createSlashUsernameHandler(
1252
+ "360.yahoo.com", { slashAnything: 1 })});
1253
+ nodemapper.addSimpleHandler("360.yahoo.com", "ident_to_profile",
1254
+ "http://360.yahoo.com/");
1255
+ nodemapper.addSimpleHandler("360.yahoo.com", "ident_to_rss",
1256
+ "http://blog.360.yahoo.com/");
1257
+ nodemapper.registerDomain(
1258
+ "spaces.live.com",
1259
+ {name: "Windows Live Spaces",
1260
+ urlToGraphNode: nodemapper.createUserIsSubdomainHandler(
1261
+ "spaces.live.com")});
1262
+ nodemapper.addSimpleHandler("spaces.live.com", "ident_to_profile",
1263
+ "http://", ".spaces.live.com");
1264
+ nodemapper.addSimpleHandler("spaces.live.com", "ident_to_rss",
1265
+ "http://", ".spaces.live.com/feed.rss");
1266
+ nodemapper.registerDomain(
1267
+ "travelpod.com",
1268
+ {name: "TravelPod",
1269
+ urlToGraphNode: nodemapper.createSomethingSlashUsernameHandler(
1270
+ "members", "travelpod.com")});
1271
+ nodemapper.addSimpleHandler("travelpod.com", "ident_to_profile",
1272
+ "http://travelpod.com/members/");
1273
+ nodemapper.addSimpleHandler("travelpod.com", "ident_to_rss",
1274
+ "http://travelpod.com/syndication/rss/");
1275
+ nodemapper.registerDomain(
1276
+ "imageshack.us",
1277
+ {name: "ImageShack",
1278
+ urlToGraphNode: nodemapper.createSomethingSlashUsernameHandler(
1279
+ "user", "imageshack.us")});
1280
+ nodemapper.addSimpleHandler("imageshack.us", "ident_to_profile",
1281
+ "http://profile.imageshack.us/user/");
1282
+ nodemapper.addSimpleHandler("imageshack.us", "ident_to_rss",
1283
+ "http://rss.imageshack.us/user/", "/rss/");
1284
+ nodemapper.registerDomain("bloglines.com",
1285
+ {name: "Bloglines",
1286
+ urlToGraphNode: nodemapper.createSomethingSlashUsernameHandler(
1287
+ "(?:blog|public)", "bloglines.com", {slashAnything: 1})});
1288
+ nodemapper.addSimpleHandler("bloglines.com", "ident_to_profile",
1289
+ "http://www.bloglines.com/blog/");
1290
+ nodemapper.addSimpleHandler("bloglines.com", "ident_to_rss",
1291
+ "http://www.bloglines.com/blog/", "/rss");
1292
+ nodemapper.registerDomain("nytimes.com",
1293
+ {name: "TimesPeople",
1294
+ urlToGraphNode: nodemapper.createSomethingSlashUsernameHandler("view/user",
1295
+ "nytimes.com", {keyName: "pk", slashAnything: 1})});
1296
+ nodemapper.addSimpleHandler("nytimes.com", "pk_to_profile",
1297
+ "http://timespeople.nytimes.com/view/user/", "/activities.html");
1298
+ nodemapper.addSimpleHandler("nytimes.com", "pk_to_rss",
1299
+ "http://timespeople.nytimes.com/view/user/", "/rss.xml");
1300
+ upcomingHandler = nodemapper.createSomethingSlashUsernameHandler("user",
1301
+ "upcoming.yahoo.com", {keyName: "pk"});
1302
+ nodemapper.registerDomain("upcoming.yahoo.com",
1303
+ {name: "Upcoming",
1304
+ urlToGraphNode: upcomingHandler});
1305
+ nodemapper.registerDomain("upcoming.org",
1306
+ {urlToGraphNode: upcomingHandler});
1307
+ nodemapper.addSimpleHandler("upcoming.yahoo.com", "pk_to_profile",
1308
+ "http://upcoming.yahoo.com/user/", "/");
1309
+ nodemapper.addSimpleHandler("upcoming.yahoo.com", "pk_to_rss",
1310
+ "http://upcoming.yahoo.com/syndicate/v2/my_events/");
1311
+ nodemapper.registerDomain("socializr.com",
1312
+ {name: "Socializr",
1313
+ identRegexp: /^[A-Za-z]\w{2,}$/});
1314
+ nodemapper.addSimpleHandler("socializr.com", "ident_to_profile",
1315
+ "http://www.socializr.com/user/");
1316
+ nodemapper.addSimpleHandler("socializr.com", "ident_to_rss",
1317
+ "http://www.socializr.com/rss/user/", "/rss.xml");
1318
+ nodemapper.addSimpleHandler("socializr.com", "pk_to_profile",
1319
+ "http://www.socializr.com/user/");
1320
+ nodemapper.addSimpleHandler("socializr.com", "pk_to_rss",
1321
+ "http://www.socializr.com/rss/user/", "/rss.xml");
1322
+ nodemapper.registerDomain("furl.net",
1323
+ {name: "Furl",
1324
+ urlToGraphNode: nodemapper.createSomethingSlashUsernameHandler(
1325
+ "members", "furl.net", {slashAnything: 1})});
1326
+ nodemapper.addSimpleHandler("furl.net", "ident_to_profile",
1327
+ "http://www.furl.net/members/");
1328
+ nodemapper.addSimpleHandler("furl.net", "ident_to_rss",
1329
+ "http://www.furl.net/members/", "/rss.xml");
1330
+ nodemapper.registerDomain("dailymotion.com",
1331
+ {name: "DailyMotion",
1332
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
1333
+ "dailymotion.com", /^\/(?:rss\/)?(\w+)(?:\/|$|\?from=)/, {slashAnything: 1})});
1334
+ nodemapper.addSimpleHandler("dailymotion.com", "ident_to_profile",
1335
+ "http://www.dailymotion.com/");
1336
+ nodemapper.addSimpleHandler("dailymotion.com", "ident_to_rss",
1337
+ "http://www.dailymotion.com/rss/", "/1");
1338
+ nodemapper.registerDomain("vimeo.com",
1339
+ {name: "Vimeo",
1340
+ urlToGraphNode: nodemapper.createSlashUsernameHandler(
1341
+ "vimeo.com", {slashAnything: 1})});
1342
+ nodemapper.addSimpleHandler("vimeo.com", "ident_to_profile",
1343
+ "http://www.vimeo.com/");
1344
+ nodemapper.addSimpleHandler("vimeo.com", "ident_to_rss",
1345
+ "http://www.vimeo.com/", "/videos/rss");
1346
+ nodemapper.registerDomain("d.hatena.ne.jp",
1347
+ {name: "Hatena::Diary",
1348
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
1349
+ "d.hatena.ne.jp", /^\/([\w-]+)(?:\/|$)/, {casePreserve: 1})});
1350
+ nodemapper.addSimpleHandler("d.hatena.ne.jp", "ident_to_profile",
1351
+ "http://d.hatena.ne.jp/", "/");
1352
+ nodemapper.addSimpleHandler("d.hatena.ne.jp", "ident_to_rss",
1353
+ "http://d.hatena.ne.jp/", "/rss");
1354
+ nodemapper.addSimpleHandler("d.hatena.ne.jp", "ident_to_foaf",
1355
+ "http://d.hatena.ne.jp/", "/foaf");
1356
+ nodemapper.registerDomain("disqus.com",
1357
+ {name: "Disqus",
1358
+ urlToGraphNode: nodemapper.createSomethingSlashUsernameHandler(
1359
+ "people", "disqus.com", {slashAnything: 1})});
1360
+ nodemapper.addSimpleHandler("disqus.com", "ident_to_profile",
1361
+ "http://www.disqus.com/people/");
1362
+ nodemapper.addSimpleHandler("disqus.com", "ident_to_rss",
1363
+ "http://www.disqus.com/people/", "/comments.rss");
1364
+ var rateitallHandler = function(url, host, path) {
1365
+ var handler;
1366
+ if (path.match(/\/rss-u-[A-Za-z]/)) {
1367
+ handler = nodemapper.createPathRegexpHandler(
1368
+ "rateitall.com", /^\/rss-u-([A-Za-z][\w-]*).aspx$/);
1369
+ } else if (path.match(/\/rss-u-[0-9]/)) {
1370
+ handler = nodemapper.createPathRegexpHandler(
1371
+ "rateitall.com", /^\/rss-u-([0-9]+).aspx$/, {keyName: "pk"});
1372
+ } else if (path.match(/\/usercommentsrss.aspx\?RI=[A-Za-z]/)) {
1373
+ handler = nodemapper.createPathRegexpHandler(
1374
+ "rateitall.com", /^\/usercommentsrss.aspx\?RI=([A-Za-z][\w-]*)/);
1375
+ } else if (path.match(/\/usercommentsrss.aspx\?RI=[0-9]/)) {
1376
+ handler = nodemapper.createPathRegexpHandler(
1377
+ "rateitall.com", /^\/usercommentsrss.aspx\?RI=([0-9]+)/, {keyName: "pk"});
1378
+ } else {
1379
+ handler = nodemapper.createSlashUsernameHandler("rateitall.com");
1380
+ }
1381
+ return handler(url, host, path);
1382
+ };
1383
+ nodemapper.registerDomain("rateitall.com",
1384
+ {name: "RateItAll",
1385
+ identRegexp: /^(?!rss-)[A-Za-z][\w-]*$/,
1386
+ urlToGraphNode: rateitallHandler});
1387
+ nodemapper.addSimpleHandler("rateitall.com", "ident_to_profile",
1388
+ "http://www.rateitall.com/");
1389
+ nodemapper.addSimpleHandler("rateitall.com", "pk_to_profile",
1390
+ "http://www.rateitall.com/Profile.aspx?userID=");
1391
+ nodemapper.addSimpleHandler("rateitall.com", "ident_to_rss",
1392
+ "http://www.rateitall.com/rss-u-", ".aspx");
1393
+ nodemapper.addSimpleHandler("rateitall.com", "pk_to_rss",
1394
+ "http://www.rateitall.com/rss-u-", ".aspx");
1395
+ nodemapper.registerDomain("slideshare.net",
1396
+ {name: "SlideShare",
1397
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
1398
+ "slideshare.net", /^\/(?:rss\/user\/)?(\w+)(?:\/|$)/, {slashAnything: 1})});
1399
+ nodemapper.addSimpleHandler("slideshare.net", "ident_to_profile",
1400
+ "http://www.slideshare.net/");
1401
+ nodemapper.addSimpleHandler("slideshare.net", "ident_to_rss",
1402
+ "http://www.slideshare.net/rss/user/");
1403
+ nodemapper.registerDomain("blog.sina.com.cn",
1404
+ {name: "Sina Blog"});
1405
+ nodemapper.addSimpleHandler("blog.sina.com.cn", "ident_to_profile",
1406
+ "http://blog.sina.com.cn/");
1407
+ nodemapper.addSimpleHandler("blog.sina.com.cn", "ident_to_rss",
1408
+ "http://blog.sina.com.cn/rss/", ".xml");
1409
+ nodemapper.registerDomain("hi.baidu.com",
1410
+ {name: "Baidu Space"});
1411
+ nodemapper.addSimpleHandler("hi.baidu.com", "ident_to_profile",
1412
+ "http://hi.baidu.com/");
1413
+ nodemapper.addSimpleHandler("hi.baidu.com", "ident_to_rss",
1414
+ "http://hi.baidu.com/", "/rss");
1415
+ nodemapper.registerDomain(
1416
+ "blogbus.com",
1417
+ {name: "Blogbus",
1418
+ urlToGraphNode: nodemapper.createUserIsSubdomainHandler("blogbus.com")});
1419
+ nodemapper.addSimpleHandler("blogbus.com", "ident_to_profile",
1420
+ "http://", ".blogbus.com/");
1421
+ nodemapper.addSimpleHandler("blogbus.com", "ident_to_rss",
1422
+ "http://", ".blogbus.com/index.rdf");
1423
+ nodemapper.registerDomain("bebo.com",
1424
+ {name: "Bebo",
1425
+ identRegexp: /^[A-Za-z]\w{2,}$/});
1426
+ nodemapper.addSimpleHandler("bebo.com", "pk_to_profile",
1427
+ "http://bebo.com/Profile.jsp?MemberId=");
1428
+ nodemapper.addSimpleHandler("bebo.com", "ident_to_profile",
1429
+ "http://bebo.com/");
1430
+ nodemapper.addSimpleHandler("bebo.com", "pk_to_rss",
1431
+ "http://bebo.com/api/BlogRss.jsp?MemberId=");
1432
+ nodemapper.registerDomain("reddit.com",
1433
+ {name: "Reddit",
1434
+ urlToGraphNode: nodemapper.createSomethingSlashUsernameHandler(
1435
+ "user", "reddit.com", {slashAnything: 1})});
1436
+ nodemapper.addSimpleHandler("reddit.com", "ident_to_profile",
1437
+ "http://reddit.com/user/");
1438
+ nodemapper.addSimpleHandler("reddit.com", "ident_to_rss",
1439
+ "http://reddit.com/user/", "/submitted.rss");
1440
+ nodemapper.registerDomain("ilike.com",
1441
+ {name: "iLike",
1442
+ urlToGraphNode: nodemapper.createSomethingSlashUsernameHandler(
1443
+ "user", "ilike.com", {slashAnything: 1})});
1444
+ nodemapper.addSimpleHandler("ilike.com", "ident_to_profile",
1445
+ "http://www.ilike.com/user/");
1446
+ nodemapper.addSimpleHandler("ilike.com", "ident_to_rss",
1447
+ "http://www.ilike.com/user/", "/songs_ilike.rss");
1448
+ nodemapper.registerDomain(
1449
+ "multiply.com",
1450
+ {name: "Multiply",
1451
+ urlToGraphNode: nodemapper.createUserIsSubdomainHandler("multiply.com")});
1452
+ nodemapper.addSimpleHandler("multiply.com", "ident_to_profile",
1453
+ "http://", ".multiply.com/");
1454
+ nodemapper.addSimpleHandler("multiply.com", "ident_to_rss",
1455
+ "http://", ".multiply.com/feed.rss");
1456
+ nodemapper.registerDomain(
1457
+ "dopplr.com",
1458
+ {name: "Dopplr",
1459
+ urlToGraphNode: nodemapper.createSomethingSlashUsernameHandler(
1460
+ "traveller", "dopplr.com")});
1461
+ nodemapper.addSimpleHandler("dopplr.com", "ident_to_profile",
1462
+ "http://www.dopplr.com/traveller/", "");
1463
+ nodemapper.registerDomain(
1464
+ "c2.com",
1465
+ {name: "c2.com",
1466
+ notMassMarketSite: true,
1467
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
1468
+ "c2.com",
1469
+ /^\/cgi\/wiki\?(.*)/,
1470
+ {casePreserve: 1}),
1471
+ identCasePreserve: 1
1472
+ });
1473
+ nodemapper.addSimpleHandler("c2.com", "ident_to_profile",
1474
+ "http://c2.com/cgi/wiki?");
1475
+ nodemapper.registerDomain(
1476
+ "bookshelved.org",
1477
+ {name: "Bookshelved",
1478
+ notMassMarketSite: true,
1479
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
1480
+ "bookshelved.org",
1481
+ /^\/cgi\-bin\/wiki\.pl\?(.*)/,
1482
+ {casePreserve: 1}),
1483
+ identCasePreserve: 1
1484
+ });
1485
+ nodemapper.addSimpleHandler("bookshelved.org", "ident_to_profile",
1486
+ "http://bookshelved.org/cgi-bin/wiki.pl?");
1487
+ nodemapper.registerDomain(
1488
+ ["xpdeveloper.net", "xpdeveloper.org"],
1489
+ {name: "XP Developer",
1490
+ primaryDomain: "xpdeveloper.net", // is this?
1491
+ notMassMarketSite: true,
1492
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
1493
+ "xpdeveloper.net",
1494
+ /^\/xpdwiki\/Wiki\.jsp\?page=(.*)/,
1495
+ {casePreserve: 1}),
1496
+ identCasePreserve: 1
1497
+ });
1498
+ nodemapper.addSimpleHandler("xpdeveloper.net", "ident_to_profile",
1499
+ "http://xpdeveloper.net/xpdwiki/Wiki.jsp?page=");
1500
+ nodemapper.registerDomain(
1501
+ "usemod.com",
1502
+ {name: "UseModWiki",
1503
+ notMassMarketSite: true,
1504
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
1505
+ "usemod.com",
1506
+ /^\/cgi\-bin\/mb\.pl\?(.*)/,
1507
+ {casePreserve: 1}),
1508
+ identCasePreserve: 1
1509
+ });
1510
+ nodemapper.addSimpleHandler("usemod.com", "ident_to_profile",
1511
+ "http://usemod.com/cgi-bin/mb.pl?");
1512
+ nodemapper.registerDomain(
1513
+ "advogato.org",
1514
+ {name: "Advogato",
1515
+ notMassMarketSite: true,
1516
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
1517
+ "advogato.org",
1518
+ /^\/person\/(\w+)/)
1519
+ });
1520
+ nodemapper.addSimpleHandler("advogato.org", "ident_to_profile",
1521
+ "http://www.advogato.org/person/", "/");
1522
+ nodemapper.addSimpleHandler("advogato.org", "ident_to_foaf",
1523
+ "http://www.advogato.org/person/", "/foaf.rdf");
1524
+ nodemapper.registerDomain("weeloop.com",
1525
+ {name: "weeloop",
1526
+ urlToGraphNode: nodemapper.createUserIsSubdomainHandler("weeloop.com")
1527
+ });
1528
+ nodemapper.addSimpleHandler("weeloop.com", "ident_to_foaf",
1529
+ "http://", ".weeloop.com/foaf.rdf");
1530
+ nodemapper.addSimpleHandler("weeloop.com", "ident_to_profile",
1531
+ "http://", ".weeloop.com/profile");
1532
+ nodemapper.addSimpleHandler("weeloop.com", "ident_to_atom",
1533
+ "http://", ".weeloop.com/api/post?mimeType=application/atom+xml");
1534
+ nodemapper.registerDomain("planeta.rambler.ru",
1535
+ {name: "Rambler-Planeta",
1536
+ identRegexp: /^[\w\.]+$/,
1537
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
1538
+ "planeta.rambler.ru",
1539
+ /^\/users\/([\w\.]+)/)
1540
+ });
1541
+ nodemapper.addSimpleHandler("planeta.rambler.ru", "ident_to_foaf",
1542
+ "http://planeta.rambler.ru/users/", "/friends/foaf/");
1543
+ nodemapper.addSimpleHandler("planeta.rambler.ru", "ident_to_rss",
1544
+ "http://planeta.rambler.ru/users/", "/rss/");
1545
+ nodemapper.registerDomain("mojageneracja.pl",
1546
+ {name: "MojaGeneracja",
1547
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
1548
+ "mojageneracja.pl",
1549
+ /^\/(\d+)(?:\/|$)/, {keyName: "pk"})
1550
+ });
1551
+ nodemapper.addSimpleHandler("mojageneracja.pl", "pk_to_profile",
1552
+ "http://www.mojageneracja.pl/", "/");
1553
+ nodemapper.addSimpleHandler("mojageneracja.pl", "pk_to_rss",
1554
+ "http://www.mojageneracja.pl/", "/rss");
1555
+ nodemapper.registerDomain(
1556
+ "goodreads.com",
1557
+ {name: "goodreads",
1558
+ urlToGraphNode: nodemapper.createSomethingSlashUsernameHandler(
1559
+ "user/show", "goodreads.com", {keyName: "pk"})});
1560
+ nodemapper.addSimpleHandler("goodreads.com", "pk_to_profile",
1561
+ "http://www.goodreads.com/user/show/");
1562
+ nodemapper.addSimpleHandler("goodreads.com", "pk_to_rss",
1563
+ "http://www.goodreads.com/review/list_rss/");
1564
+ nodemapper.registerDomain("tripit.com", {
1565
+ name: "TripIt",
1566
+ identRegexp: /^[-\w\+\.]+$/,
1567
+ urlToGraphNode: nodemapper.createPathRegexpHandler(
1568
+ "tripit.com", /^\/people\/([-\w\+\.]+)/ )
1569
+ });
1570
+ nodemapper.addSimpleHandler("tripit.com", "ident_to_profile",
1571
+ "http://tripit.com/people/");
1572
+ })();
1573
+ (function(){
1574
+ spinPkHandler = function(url, host, path) {
1575
+ var primaryKeyRegexp = /^\/(?:hp|foaf)\/,([0-9a-fA-F]+)($|\/)/;
1576
+ var m;
1577
+ if (!(m = primaryKeyRegexp.exec(path))) {
1578
+ return url;
1579
+ }
1580
+ return "sgn://spin.de/?pk=" + m[1].toLowerCase();
1581
+ };
1582
+ spinIdentHandler = nodemapper.createPathRegexpHandler(
1583
+ "spin.de",
1584
+ /^\/(?:hp|foaf)\/([^\/,]+)/,
1585
+ { fallbackHandler: spinPkHandler,
1586
+ casePreserve: 0
1587
+ });
1588
+ nodemapper.registerDomain("spin.de", {
1589
+ name: "spin.de",
1590
+ urlToGraphNode: spinIdentHandler,
1591
+ pkRegexp: /^,[0-9a-fA-F]+$/,
1592
+ identRegexp: /^\w+$/
1593
+ });
1594
+ nodemapper.addSimpleHandler("spin.de", "ident_to_foaf",
1595
+ "http://www.spin.de/foaf/", "");
1596
+ nodemapper.addSimpleHandler("spin.de", "pk_to_foaf",
1597
+ "http://www.spin.de/foaf/,", "");
1598
+ nodemapper.addSimpleHandler("spin.de", "ident_to_profile",
1599
+ "http://www.spin.de/hp/", "/");
1600
+ nodemapper.addSimpleHandler("spin.de", "pk_to_profile",
1601
+ "http://www.spin.de/hp/,", "/");
1602
+ nodemapper.addSimpleHandler("spin.de", "ident_to_blog",
1603
+ "http://www.spin.de/hp/", "/blog");
1604
+ nodemapper.addSimpleHandler("spin.de", "pk_to_blog",
1605
+ "http://www.spin.de/hp/,", "/blog");
1606
+ })();
1607
+ (function(){
1608
+ var stumbleuponCompoundHandler = function(url, host, path) {
1609
+ var handler;
1610
+ if (host.indexOf('www.') == 0 || host.indexOf('rss.') == 0) {
1611
+ if (path.indexOf('syndicate.php') != -1) {
1612
+ handler = nodemapper.createPathRegexpHandler("stumbleupon.com",
1613
+ /^\/syndicate.php\?stumbler=([^&]+)/);
1614
+ } else {
1615
+ handler = nodemapper.createSomethingSlashUsernameHandler(
1616
+ "(?:user|stumbler)", "stumbleupon.com", {slashAnything:1});
1617
+ }
1618
+ } else handler = nodemapper.createUserIsSubdomainHandler("stumbleupon.com");
1619
+ return handler(url, host, path);
1620
+ };
1621
+ nodemapper.registerDomain(
1622
+ "stumbleupon.com",
1623
+ {name: "StumbleUpon",
1624
+ urlToGraphNode: stumbleuponCompoundHandler});
1625
+ nodemapper.addSimpleHandler("stumbleupon.com", "ident_to_profile",
1626
+ "http://", ".stumbleupon.com");
1627
+ nodemapper.addSimpleHandler("stumbleupon.com", "ident_to_rss",
1628
+ "http://rss.stumbleupon.com/user/", "/favorites");
1629
+ })();
1630
+ (function(){
1631
+ nodemapper.registerDomain(
1632
+ "x.foo.test", {
1633
+ blah: {},
1634
+ _name_for_testing: "x.foo.test (the specific one)"
1635
+ });
1636
+ nodemapper.registerDomain(
1637
+ "foo.test", {
1638
+ accountToSgn: {},
1639
+ _name_for_testing: "foo.test"
1640
+ });
1641
+ })();
1642
+ (function(){
1643
+ var pkMatcher = nodemapper.createPathRegexpHandler(
1644
+ "threadless.com",
1645
+ /\/(?:profile|rss\/blog)\/(\d+)\/?$/,
1646
+ {keyName:"pk"});
1647
+ var identMatcher = nodemapper.createPathRegexpHandler(
1648
+ "threadless.com",
1649
+ /\/(?:profile|rss\/blog)\/(\d+\/\w+)(?:\/.*)?$/,
1650
+ {fallbackHandler: pkMatcher});
1651
+ nodemapper.registerDomain(
1652
+ "threadless.com",
1653
+ {name: "Threadless",
1654
+ urlToGraphNode: identMatcher,
1655
+ identRegexp: /^\d+\/\w+$/});
1656
+ nodemapper.addSimpleHandler("threadless.com", "pk_to_rss",
1657
+ "http://www.threadless.com/rss/blog/", "");
1658
+ nodemapper.addSimpleHandler("threadless.com", "ident_to_rss",
1659
+ "http://www.threadless.com/rss/blog/", "");
1660
+ nodemapper.addSimpleHandler("threadless.com", "pk_to_profile",
1661
+ "http://www.threadless.com/profile/", "");
1662
+ nodemapper.addSimpleHandler("threadless.com", "ident_to_profile",
1663
+ "http://www.threadless.com/profile/", "");
1664
+ nodemapper.addSimpleHandler("threadless.com", "ident_to_blog",
1665
+ "http://www.threadless.com/profile/", "/blogs");
1666
+ })();
1667
+ (function(){
1668
+ tribePkHandler = function(url, host, path) {
1669
+ var primaryKeyRegexp = /^\/([\w\-]{36})(?:\/(?:foaf|blog)|\/$|$)/;
1670
+ var m;
1671
+ if (!(m = primaryKeyRegexp.exec(path))) {
1672
+ return url;
1673
+ }
1674
+ return "sgn://tribe.net/?pk=" + m[1].toLowerCase();
1675
+ };
1676
+ tribeIdentHandler = nodemapper.createPathRegexpHandler(
1677
+ "tribe.net",
1678
+ /^\/(\w+)(?:\/(?:foaf|blog)|\/$|$)/,
1679
+ { fallbackHandler: tribePkHandler }
1680
+ );
1681
+ nodemapper.registerDomain("tribe.net", {
1682
+ name: "Tribe.net",
1683
+ pkRegexp: /^[\w\-]{36}$/,
1684
+ identRegexp: /^\w+$/
1685
+ });
1686
+ nodemapper.registerDomain("people.tribe.net", {
1687
+ urlToGraphNode: tribeIdentHandler
1688
+ });
1689
+ nodemapper.addSimpleHandler("tribe.net", "ident_to_foaf",
1690
+ "http://people.tribe.net/", "/foaf");
1691
+ nodemapper.addSimpleHandler("tribe.net", "pk_to_foaf",
1692
+ "http://people.tribe.net/", "/foaf");
1693
+ nodemapper.addSimpleHandler("tribe.net", "ident_to_profile",
1694
+ "http://people.tribe.net/");
1695
+ nodemapper.addSimpleHandler("tribe.net", "pk_to_profile",
1696
+ "http://people.tribe.net/");
1697
+ })();
1698
+ (function(){
1699
+ var FRIENDS_API1_RE = /^\/friends\/ids\/(\w+)\.(?:xml|json)/;
1700
+ var FRIENDS_API2_RE = /^\/friends\/ids\.(?:xml|json)\?screen_name=(\w+)/;
1701
+ var HASH_BANG_RE = /^\/#!\/(\w+)/;
1702
+ var twitterFallbackHandler = function(url, host, path) {
1703
+ var m;
1704
+ if ((m = FRIENDS_API1_RE.exec(path)) ||
1705
+ (m = FRIENDS_API2_RE.exec(path)) ||
1706
+ (m = HASH_BANG_RE.exec(path))) {
1707
+ var username = m[1].toLowerCase();
1708
+ return "sgn://twitter.com/?ident=" + username;
1709
+ }
1710
+ return url;
1711
+ };
1712
+ var NOT_USERNAMES = {
1713
+ "statuses": 1,
1714
+ "friends": 1
1715
+ };
1716
+ nodemapper.registerDomain(
1717
+ "twitter.com",
1718
+ { httpsLikeHttp: 1,
1719
+ name: "Twitter",
1720
+ accountToSgn: { pk: ["twitter.com"], ident: ["twitter.com"] },
1721
+ notUsernames: NOT_USERNAMES,
1722
+ urlToGraphNode: nodemapper.createSlashUsernameHandler(
1723
+ "twitter.com",
1724
+ {slashAnything: 1,
1725
+ notUsernames: NOT_USERNAMES,
1726
+ fallbackHandler: twitterFallbackHandler
1727
+ })
1728
+ });
1729
+ nodemapper.addSimpleHandler("twitter.com", "ident_to_profile",
1730
+ "http://twitter.com/");
1731
+ nodemapper.addSimpleHandler("twitter.com", "ident_to_rss",
1732
+ "http://twitter.com/statuses/user_timeline/", ".rss");
1733
+ nodemapper.addSimpleHandler("twitter.com", "ident_to_atom",
1734
+ "http://twitter.com/statuses/user_timeline/", ".atom");
1735
+ nodemapper.addSimpleHandler("twitter.com", "pk_to_rss",
1736
+ "http://twitter.com/statuses/user_timeline/", ".rss");
1737
+ nodemapper.addSimpleHandler("twitter.com", "pk_to_atom",
1738
+ "http://twitter.com/statuses/user_timeline/", ".atom");
1739
+ })();
1740
+ (function(){
1741
+ var SOFTWARE_REGEXP = /^\/software\/([\w-]+)/;
1742
+ var USER_REGEXP = /^\/(\w+)(?:\/|$)/;
1743
+ var toSgn = function(url, host, path) {
1744
+ var m;
1745
+ if (m = SOFTWARE_REGEXP.exec(path)) {
1746
+ return "sgn://software.wakoopa.com/?ident=" + m[1].toLowerCase();
1747
+ }
1748
+ if (m = USER_REGEXP.exec(path)) {
1749
+ return "sgn://wakoopa.com/?ident=" + m[1].toLowerCase();
1750
+ }
1751
+ return url;
1752
+ };
1753
+ nodemapper.registerDomain("wakoopa.com", {
1754
+ name: "Wakoopa",
1755
+ urlToGraphNode: toSgn
1756
+ });
1757
+ nodemapper.registerDomain("software.wakoopa.com", {
1758
+ name: "Wakoopa Software",
1759
+ notMassMarketSite: true,
1760
+ identRegexp: /^[\w-]+$/
1761
+ });
1762
+ nodemapper.addSimpleHandler("wakoopa.com", "ident_to_profile",
1763
+ "http://wakoopa.com/");
1764
+ nodemapper.addSimpleHandler("software.wakoopa.com", "ident_to_profile",
1765
+ "http://wakoopa.com/software/");
1766
+ })();
1767
+ (function(){
1768
+ var DOMAIN_RE = /^(?:www\.)?([\w\-]+)\.wordpress\.com$/;
1769
+ function wordpressHandler(url, host, path) {
1770
+ var m = DOMAIN_RE.exec(host);
1771
+ var ident = m ? m[1].toLowerCase() : "";
1772
+ if (!m || ident == "www" || ident.length == 2 ||
1773
+ (ident.length == 5 && ident.substr(2, 1) == "-")) {
1774
+ return url;
1775
+ }
1776
+ return "sgn://wordpress.com/?ident=" + ident;
1777
+ }
1778
+ nodemapper.registerDomain(
1779
+ "wordpress.com",
1780
+ {name: "WordPress",
1781
+ skipAutomaticHttpToSgn: true,
1782
+ urlToGraphNode: wordpressHandler});
1783
+ nodemapper.addSimpleHandler("wordpress.com", "ident_to_blog",
1784
+ "http://", ".wordpress.com/");
1785
+ })();
1786
+ (function(){
1787
+ var yelpCompoundHandler = function(url, host, path) {
1788
+ var handler;
1789
+ if (host.indexOf("www.") == 0 || path.indexOf('user_details') != -1 || path.indexOf('syndicate/user') != -1) {
1790
+ handler = nodemapper.createPathRegexpHandler("yelp.com",
1791
+ /^(?:\/user_details\?userid=|\/syndicate\/user\/)([\w\-]+)/,
1792
+ {keyName: "pk", casePreserve: 1});
1793
+ } else handler = nodemapper.createUserIsSubdomainHandler("yelp.com");
1794
+ return handler(url, host, path);
1795
+ };
1796
+ nodemapper.registerDomain("yelp.com", {
1797
+ name: "Yelp",
1798
+ urlToGraphNode: yelpCompoundHandler,
1799
+ pkRegexp: /^(?=\w)[\w-]{22}$/,
1800
+ identRegexp: /^[\w\-]+$/
1801
+ });
1802
+ nodemapper.addSimpleHandler("yelp.com", "pk_to_rss",
1803
+ "http://www.yelp.com/syndicate/user/", "/rss.xml");
1804
+ nodemapper.addSimpleHandler("yelp.com", "pk_to_profile",
1805
+ "http://www.yelp.com/user_details?userid=");
1806
+ nodemapper.addSimpleHandler("yelp.com", "ident_to_profile",
1807
+ "http://", ".yelp.com");
1808
+ })();
1809
+ (function(){
1810
+ var SLASH_WORD_MAYBEWORD = /^\/(\w+)(?:\/(\w+))?(?:\/|$)/;
1811
+ var SLASH_PK_REGEXP = /\b(\d+\@Z\d\d)\b/;
1812
+ var userFirstPaths = {
1813
+ 'people': 1,
1814
+ 'photos': 1,
1815
+ 'zipline': 1
1816
+ };
1817
+ var userSecondPaths = {
1818
+ 'fans': 1,
1819
+ 'statuses': 1,
1820
+ 'favorites': 1,
1821
+ 'mutual': 1,
1822
+ 'with_friends': 1
1823
+ };
1824
+ var toSgn = function(url, host, path) {
1825
+ var m;
1826
+ if (m = SLASH_PK_REGEXP.exec(path)) {
1827
+ return "sgn://zooomr.com/?pk=" + m[1];
1828
+ }
1829
+ if (!(m = SLASH_WORD_MAYBEWORD.exec(path))) {
1830
+ return url;
1831
+ }
1832
+ if (userFirstPaths[m[1]]) {
1833
+ if (!m[2]) {
1834
+ return url;
1835
+ }
1836
+ return "sgn://zooomr.com/?ident=" + m[2].toLowerCase();
1837
+ }
1838
+ if (!m[2] || userSecondPaths[m[2]] || m[2].substr(0, 4) == "page") {
1839
+ return "sgn://zooomr.com/?ident=" + m[1].toLowerCase();
1840
+ }
1841
+ return url;
1842
+ };
1843
+ nodemapper.registerDomain("zooomr.com",
1844
+ {name: "Zooomr",
1845
+ urlToGraphNode: toSgn,
1846
+ pkRegexp: /^\d+\@Z\d\d$/
1847
+ });
1848
+ nodemapper.addSimpleHandler("zooomr.com", "ident_to_profile",
1849
+ "http://www.zooomr.com/people/", "/");
1850
+ nodemapper.addSimpleHandler("zooomr.com", "ident_to_content",
1851
+ "http://www.zooomr.com/photos/", "/");
1852
+ nodemapper.addSimpleHandler("zooomr.com", "ident_to_rss",
1853
+ "http://www.zooomr.com/services/feeds/public_photos/?id=",
1854
+ "&format=rss_200");
1855
+ nodemapper.addSimpleHandler("zooomr.com", "pk_to_profile",
1856
+ "http://www.zooomr.com/people/", "/");
1857
+ nodemapper.addSimpleHandler("zooomr.com", "pk_to_content",
1858
+ "http://www.zooomr.com/photos/", "/");
1859
+ nodemapper.addSimpleHandler("zooomr.com", "pk_to_rss",
1860
+ "http://www.zooomr.com/services/feeds/public_photos/?id=",
1861
+ "&format=rss_200");
1862
+ })();