jls-tweetstream 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +6 -0
- data/CHANGELOG.md +76 -0
- data/CONTRIBUTING.md +9 -0
- data/LICENSE.md +20 -0
- data/README.md +392 -0
- data/Rakefile +11 -0
- data/lib/tweetstream.rb +36 -0
- data/lib/tweetstream/client.rb +582 -0
- data/lib/tweetstream/configuration.rb +92 -0
- data/lib/tweetstream/daemon.rb +52 -0
- data/lib/tweetstream/site_stream_client.rb +122 -0
- data/lib/tweetstream/version.rb +3 -0
- data/spec/fixtures/delete.json +8 -0
- data/spec/fixtures/direct_messages.json +1 -0
- data/spec/fixtures/favorite.json +150 -0
- data/spec/fixtures/ids.json +30 -0
- data/spec/fixtures/info.json +18 -0
- data/spec/fixtures/limit.json +5 -0
- data/spec/fixtures/scrub_geo.json +8 -0
- data/spec/fixtures/stall_warning.json +7 -0
- data/spec/fixtures/status_withheld.json +7 -0
- data/spec/fixtures/statuses.json +1 -0
- data/spec/fixtures/user_withheld.json +6 -0
- data/spec/helper.rb +58 -0
- data/spec/tweetstream/client_authentication_spec.rb +83 -0
- data/spec/tweetstream/client_site_stream_spec.rb +145 -0
- data/spec/tweetstream/client_spec.rb +391 -0
- data/spec/tweetstream/client_userstream_spec.rb +74 -0
- data/spec/tweetstream/daemon_spec.rb +29 -0
- data/spec/tweetstream/site_stream_client_spec.rb +233 -0
- data/spec/tweetstream_spec.rb +129 -0
- data/tweetstream.gemspec +29 -0
- metadata +179 -0
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'tweetstream/version'
|
2
|
+
|
3
|
+
module TweetStream
|
4
|
+
# Defines constants and methods related to configuration
|
5
|
+
module Configuration
|
6
|
+
# An array of valid keys in the options hash when configuring TweetStream.
|
7
|
+
VALID_OPTIONS_KEYS = [
|
8
|
+
:parser,
|
9
|
+
:username,
|
10
|
+
:password,
|
11
|
+
:user_agent,
|
12
|
+
:auth_method,
|
13
|
+
:proxy,
|
14
|
+
:consumer_key,
|
15
|
+
:consumer_secret,
|
16
|
+
:oauth_token,
|
17
|
+
:oauth_token_secret].freeze
|
18
|
+
|
19
|
+
OAUTH_OPTIONS_KEYS = [
|
20
|
+
:consumer_key,
|
21
|
+
:consumer_secret,
|
22
|
+
:oauth_token,
|
23
|
+
:oauth_token_secret].freeze
|
24
|
+
|
25
|
+
# By default, don't set a username
|
26
|
+
DEFAULT_USERNAME = nil
|
27
|
+
|
28
|
+
# By default, don't set a password
|
29
|
+
DEFAULT_PASSWORD = nil
|
30
|
+
|
31
|
+
# The user agent that will be sent to the API endpoint if none is set
|
32
|
+
DEFAULT_USER_AGENT = "TweetStream Ruby Gem #{TweetStream::VERSION}".freeze
|
33
|
+
|
34
|
+
# The default authentication method
|
35
|
+
DEFAULT_AUTH_METHOD = :oauth
|
36
|
+
|
37
|
+
DEFAULT_PROXY = nil
|
38
|
+
|
39
|
+
VALID_FORMATS = [
|
40
|
+
:basic,
|
41
|
+
:oauth].freeze
|
42
|
+
|
43
|
+
# By default, don't set an application key
|
44
|
+
DEFAULT_CONSUMER_KEY = nil
|
45
|
+
|
46
|
+
# By default, don't set an application secret
|
47
|
+
DEFAULT_CONSUMER_SECRET = nil
|
48
|
+
|
49
|
+
# By default, don't set a user oauth token
|
50
|
+
DEFAULT_OAUTH_TOKEN = nil
|
51
|
+
|
52
|
+
# By default, don't set a user oauth secret
|
53
|
+
DEFAULT_OAUTH_TOKEN_SECRET = nil
|
54
|
+
|
55
|
+
# @private
|
56
|
+
attr_accessor *VALID_OPTIONS_KEYS
|
57
|
+
|
58
|
+
# When this module is extended, set all configuration options to their default values
|
59
|
+
def self.extended(base)
|
60
|
+
base.reset
|
61
|
+
end
|
62
|
+
|
63
|
+
# Convenience method to allow configuration options to be set in a block
|
64
|
+
def configure
|
65
|
+
yield self
|
66
|
+
end
|
67
|
+
|
68
|
+
# Create a hash of options and their values
|
69
|
+
def options
|
70
|
+
Hash[*VALID_OPTIONS_KEYS.map {|key| [key, send(key)] }.flatten]
|
71
|
+
end
|
72
|
+
|
73
|
+
# Create a hash of options and their values
|
74
|
+
def oauth_options
|
75
|
+
Hash[*OAUTH_OPTIONS_KEYS.map {|key| [key, send(key)] }.flatten]
|
76
|
+
end
|
77
|
+
|
78
|
+
# Reset all configuration options to defaults
|
79
|
+
def reset
|
80
|
+
self.username = DEFAULT_USERNAME
|
81
|
+
self.password = DEFAULT_PASSWORD
|
82
|
+
self.user_agent = DEFAULT_USER_AGENT
|
83
|
+
self.auth_method = DEFAULT_AUTH_METHOD
|
84
|
+
self.proxy = DEFAULT_PROXY
|
85
|
+
self.consumer_key = DEFAULT_CONSUMER_KEY
|
86
|
+
self.consumer_secret = DEFAULT_CONSUMER_SECRET
|
87
|
+
self.oauth_token = DEFAULT_OAUTH_TOKEN
|
88
|
+
self.oauth_token_secret = DEFAULT_OAUTH_TOKEN_SECRET
|
89
|
+
self
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'daemons'
|
2
|
+
|
3
|
+
# A daemonized TweetStream client that will allow you to
|
4
|
+
# create backgroundable scripts for application specific
|
5
|
+
# processes. For instance, if you create a script called
|
6
|
+
# <tt>tracker.rb</tt> and fill it with this:
|
7
|
+
#
|
8
|
+
# require 'rubygems'
|
9
|
+
# require 'tweetstream'
|
10
|
+
#
|
11
|
+
# TweetStream.configure do |config|
|
12
|
+
# config.consumer_key = 'abcdefghijklmnopqrstuvwxyz'
|
13
|
+
# config.consumer_secret = '0123456789'
|
14
|
+
# config.oauth_token = 'abcdefghijklmnopqrstuvwxyz'
|
15
|
+
# config.oauth_token_secret = '0123456789'
|
16
|
+
# config.auth_method = :oauth
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# TweetStream::Daemon.new('tracker').track('intridea') do |status|
|
20
|
+
# # do something here
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# And then you call this from the shell:
|
24
|
+
#
|
25
|
+
# ruby tracker.rb start
|
26
|
+
#
|
27
|
+
# A daemon process will spawn that will automatically
|
28
|
+
# run the code in the passed block whenever a new tweet
|
29
|
+
# matching your search term ('intridea' in this case)
|
30
|
+
# is posted.
|
31
|
+
#
|
32
|
+
class TweetStream::Daemon < TweetStream::Client
|
33
|
+
|
34
|
+
DEFAULT_NAME = 'tweetstream'.freeze
|
35
|
+
DEFAULT_OPTIONS = { :multiple => true }
|
36
|
+
|
37
|
+
attr_accessor :app_name, :daemon_options
|
38
|
+
|
39
|
+
# The daemon has an optional process name for use when querying
|
40
|
+
# running processes. You can also pass daemon options.
|
41
|
+
def initialize(name = DEFAULT_NAME, options = DEFAULT_OPTIONS)
|
42
|
+
@app_name = name
|
43
|
+
@daemon_options = options
|
44
|
+
super({})
|
45
|
+
end
|
46
|
+
|
47
|
+
def start(path, query_parameters = {}, &block) #:nodoc:
|
48
|
+
Daemons.run_proc(@app_name, @daemon_options) do
|
49
|
+
super(path, query_parameters, &block)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'em-http'
|
2
|
+
require 'em-http/middleware/oauth'
|
3
|
+
require 'em-http/middleware/json_response'
|
4
|
+
|
5
|
+
module TweetStream
|
6
|
+
class SiteStreamClient
|
7
|
+
|
8
|
+
attr_accessor *Configuration::OAUTH_OPTIONS_KEYS
|
9
|
+
|
10
|
+
def initialize(config_uri, oauth = {})
|
11
|
+
@config_uri = config_uri
|
12
|
+
|
13
|
+
options = TweetStream.oauth_options.merge(oauth)
|
14
|
+
Configuration::OAUTH_OPTIONS_KEYS.each do |key|
|
15
|
+
send("#{key}=", options[key])
|
16
|
+
end
|
17
|
+
|
18
|
+
EventMachine::HttpRequest.use EventMachine::Middleware::JSONResponse
|
19
|
+
end
|
20
|
+
|
21
|
+
def on_error(&block)
|
22
|
+
if block_given?
|
23
|
+
@on_error = block
|
24
|
+
self
|
25
|
+
else
|
26
|
+
@on_error
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def info(&block)
|
31
|
+
options = { :error_msg => 'Failed to retrieve SiteStream info.' }
|
32
|
+
request(:get, info_path, options, &block)
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_user(user_id, &block)
|
36
|
+
options = {
|
37
|
+
:error_msg => 'Failed to add user to SiteStream',
|
38
|
+
:body => { 'user_id' => normalized_user_ids(user_id) }
|
39
|
+
}
|
40
|
+
|
41
|
+
request(:post, add_user_path, options, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
def remove_user(user_id, &block)
|
45
|
+
options = {
|
46
|
+
:error_msg => 'Failed to remove user from SiteStream.',
|
47
|
+
:body => { 'user_id' => normalized_user_ids(user_id) }
|
48
|
+
}
|
49
|
+
|
50
|
+
request(:post, remove_user_path, options, &block)
|
51
|
+
end
|
52
|
+
|
53
|
+
def friends_ids(user_id, &block)
|
54
|
+
options = { :error_msg => 'Failed to retrieve SiteStream friends ids.',
|
55
|
+
:body => { 'user_id' => user_id }
|
56
|
+
}
|
57
|
+
request(:post, friends_ids_path, options, &block)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def connection
|
63
|
+
return @conn if defined?(@conn)
|
64
|
+
|
65
|
+
@conn = EventMachine::HttpRequest.new('https://sitestream.twitter.com/')
|
66
|
+
@conn.use EventMachine::Middleware::OAuth, oauth_configuration
|
67
|
+
@conn
|
68
|
+
end
|
69
|
+
|
70
|
+
def oauth_configuration
|
71
|
+
{
|
72
|
+
:consumer_key => consumer_key,
|
73
|
+
:consumer_secret => consumer_secret,
|
74
|
+
:access_token => oauth_token,
|
75
|
+
:access_token_secret => oauth_token_secret
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def info_path
|
80
|
+
@config_uri + '/info.json'
|
81
|
+
end
|
82
|
+
|
83
|
+
def add_user_path
|
84
|
+
@config_uri + '/add_user.json'
|
85
|
+
end
|
86
|
+
|
87
|
+
def remove_user_path
|
88
|
+
@config_uri + '/remove_user.json'
|
89
|
+
end
|
90
|
+
|
91
|
+
def friends_ids_path
|
92
|
+
@config_uri + '/friends/ids.json'
|
93
|
+
end
|
94
|
+
|
95
|
+
def request(method, path, options, &block)
|
96
|
+
error_msg = options.delete(:error_msg)
|
97
|
+
|
98
|
+
http = connection.send(method, options.merge(:path => path))
|
99
|
+
http.callback do
|
100
|
+
if http.response_header.status == 200
|
101
|
+
if block && block.kind_of?(Proc)
|
102
|
+
if block.arity == 1
|
103
|
+
block.call http.response
|
104
|
+
else
|
105
|
+
block.call
|
106
|
+
end
|
107
|
+
end
|
108
|
+
else
|
109
|
+
@on_error.call(error_msg) if @on_error && @on_error.kind_of?(Proc)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
http.errback do
|
113
|
+
@on_error.call(error_msg) if @on_error && @on_error.kind_of?(Proc)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def normalized_user_ids(user_id)
|
118
|
+
user_id.join(',') if user_id.kind_of?(Array)
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
{"direct_message":{"created_at":"Sat Sep 24 18:59:38 +0000 2011", "id_str":"4227325281", "sender_screen_name":"coreyhaines", "sender":{"name":"Corey Haines", "profile_sidebar_fill_color":"DAECF4", "profile_sidebar_border_color":"C6E2EE", "profile_background_tile":false, "profile_image_url":"http://a0.twimg.com/profile_images/1508969901/Photo_on_2011-08-22_at_19.15__3_normal.jpg", "created_at":"Sun Dec 23 18:11:29 +0000 2007", "location":"Chicago, IL", "follow_request_sent":false, "id_str":"11458102", "is_translator":false, "profile_link_color":"1F98C7", "default_profile":false, "favourites_count":122, "contributors_enabled":false, "url":"http://www.coreyhaines.com", "id":11458102, "profile_image_url_https":"https://si0.twimg.com/profile_images/1508969901/Photo_on_2011-08-22_at_19.15__3_normal.jpg", "utc_offset":-21600, "profile_use_background_image":true, "listed_count":593, "lang":"en", "followers_count":5764, "protected":false, "profile_text_color":"663B12", "notifications":false, "description":"Software Journeyman, Coderetreat Facilitator, Cofounder of MercuryApp.com, Awesome....\r\nI make magic!", "verified":false, "profile_background_color":"C6E2EE", "geo_enabled":false, "profile_background_image_url_https":"https://si0.twimg.com/images/themes/theme2/bg.gif", "time_zone":"Central Time (US & Canada)", "profile_background_image_url":"http://a1.twimg.com/images/themes/theme2/bg.gif", "default_profile_image":false, "friends_count":423, "statuses_count":35950, "following":false, "screen_name":"coreyhaines", "show_all_inline_media":false}, "recipient_screen_name":"coreyhainestest", "text":"waddup gain", "id":4227325281, "recipient":{"name":"Corey's Test Account", "profile_sidebar_fill_color":"DDEEF6", "profile_sidebar_border_color":"C0DEED", "profile_background_tile":false, "profile_image_url":"http://a2.twimg.com/sticky/default_profile_images/default_profile_3_normal.png", "created_at":"Sat Sep 24 13:04:56 +0000 2011", "location":null, "follow_request_sent":false, "id_str":"379145826", "is_translator":false, "profile_link_color":"0084B4", "default_profile":true, "favourites_count":0, "contributors_enabled":false, "url":null, "id":379145826, "profile_image_url_https":"https://si0.twimg.com/sticky/default_profile_images/default_profile_3_normal.png", "utc_offset":null, "profile_use_background_image":true, "listed_count":0, "lang":"en", "followers_count":1, "protected":false, "profile_text_color":"333333", "notifications":false, "description":null, "verified":false, "profile_background_color":"C0DEED", "geo_enabled":false, "profile_background_image_url_https":"https://si0.twimg.com/images/themes/theme1/bg.png", "time_zone":null, "profile_background_image_url":"http://a0.twimg.com/images/themes/theme1/bg.png", "default_profile_image":true, "friends_count":1, "statuses_count":21, "following":true, "screen_name":"coreyhainestest", "show_all_inline_media":false}, "recipient_id":379145826, "sender_id":11458102}}
|
@@ -0,0 +1,150 @@
|
|
1
|
+
{"target":
|
2
|
+
{"id": 598914668,
|
3
|
+
"verified": false,
|
4
|
+
"id_str": "598914668",
|
5
|
+
"profile_background_tile": false,
|
6
|
+
"location": "",
|
7
|
+
"profile_sidebar_fill_color": "DDEEF6",
|
8
|
+
"contributors_enabled": false,
|
9
|
+
"notifications": false,
|
10
|
+
"geo_enabled": false,
|
11
|
+
"profile_image_url_https": "https://si0.twimg.com/profile_images/2276724218/raf46pju0mijc6ixm6ke_normal.jpeg",
|
12
|
+
"utc_offset": null,
|
13
|
+
"default_profile": true,
|
14
|
+
"statuses_count": 151,
|
15
|
+
"name": "dev4sns",
|
16
|
+
"profile_background_color": "C0DEED",
|
17
|
+
"friends_count": 15,
|
18
|
+
"show_all_inline_media": false,
|
19
|
+
"protected": false,
|
20
|
+
"follow_request_sent": false,
|
21
|
+
"screen_name": "dev4sns",
|
22
|
+
"listed_count": 0,
|
23
|
+
"profile_background_image_url": "http://a0.twimg.com/images/themes/theme1/bg.png",
|
24
|
+
"lang": "ko",
|
25
|
+
"profile_link_color": "0084B4",
|
26
|
+
"time_zone": null,
|
27
|
+
"description": "Dev 계정입니다.",
|
28
|
+
"is_translator": false,
|
29
|
+
"profile_use_background_image": true,
|
30
|
+
"url": null,
|
31
|
+
"profile_text_color": "333333",
|
32
|
+
"created_at": "Mon Jun 04 04:07:27 +0000 2012",
|
33
|
+
"default_profile_image": false,
|
34
|
+
"profile_background_image_url_https":
|
35
|
+
"https://si0.twimg.com/images/themes/theme1/bg.png",
|
36
|
+
"favourites_count": 0,
|
37
|
+
"profile_sidebar_border_color": "C0DEED",
|
38
|
+
"profile_image_url":
|
39
|
+
"http://a0.twimg.com/profile_images/2276724218/raf46pju0mijc6ixm6ke_normal.jpeg",
|
40
|
+
"following": true,
|
41
|
+
"followers_count": 5},
|
42
|
+
"target_object":
|
43
|
+
{"id_str": "228029422597443584",
|
44
|
+
"in_reply_to_user_id": null,
|
45
|
+
"truncated": false,
|
46
|
+
"contributors": null,
|
47
|
+
"retweet_count": 0,
|
48
|
+
"possibly_sensitive_editable": true,
|
49
|
+
"favorited": false,
|
50
|
+
"coordinates": null,
|
51
|
+
"geo": null,
|
52
|
+
"possibly_sensitive": false,
|
53
|
+
"user":
|
54
|
+
{"id": 598914668,
|
55
|
+
"verified": false,
|
56
|
+
"id_str": "598914668",
|
57
|
+
"profile_background_tile": false,
|
58
|
+
"location": "",
|
59
|
+
"profile_sidebar_fill_color": "DDEEF6",
|
60
|
+
"contributors_enabled": false,
|
61
|
+
"notifications": false,
|
62
|
+
"geo_enabled": false,
|
63
|
+
"profile_image_url_https":
|
64
|
+
"https://si0.twimg.com/profile_images/2276724218/raf46pju0mijc6ixm6ke_normal.jpeg",
|
65
|
+
"utc_offset": null,
|
66
|
+
"default_profile": true,
|
67
|
+
"statuses_count": 151,
|
68
|
+
"name": "dev4sns",
|
69
|
+
"profile_background_color": "C0DEED",
|
70
|
+
"friends_count": 15,
|
71
|
+
"show_all_inline_media": false,
|
72
|
+
"protected": false,
|
73
|
+
"follow_request_sent": false,
|
74
|
+
"screen_name": "dev4sns",
|
75
|
+
"listed_count": 0,
|
76
|
+
"profile_background_image_url":
|
77
|
+
"http://a0.twimg.com/images/themes/theme1/bg.png",
|
78
|
+
"lang": "ko",
|
79
|
+
"profile_link_color": "0084B4",
|
80
|
+
"time_zone": null,
|
81
|
+
"description": "Dev 계정입니다.",
|
82
|
+
"is_translator": false,
|
83
|
+
"profile_use_background_image": true,
|
84
|
+
"url": null,
|
85
|
+
"profile_text_color": "333333",
|
86
|
+
"created_at": "Mon Jun 04 04:07:27 +0000 2012",
|
87
|
+
"default_profile_image": false,
|
88
|
+
"profile_background_image_url_https":
|
89
|
+
"https://si0.twimg.com/images/themes/theme1/bg.png",
|
90
|
+
"favourites_count": 0,
|
91
|
+
"profile_sidebar_border_color": "C0DEED",
|
92
|
+
"profile_image_url":
|
93
|
+
"http://a0.twimg.com/profile_images/2276724218/raf46pju0mijc6ixm6ke_normal.jpeg",
|
94
|
+
"following": true,
|
95
|
+
"followers_count": 5},
|
96
|
+
"in_reply_to_status_id_str": null,
|
97
|
+
"in_reply_to_screen_name": null,
|
98
|
+
"source": "<a href=\"http://www.a2m.co.kr\" rel=\"nofollow\">Dev Acct</a>",
|
99
|
+
"in_reply_to_user_id_str": null,
|
100
|
+
"retweeted": false,
|
101
|
+
"in_reply_to_status_id": null,
|
102
|
+
"id": 228029422597443584,
|
103
|
+
"place": null,
|
104
|
+
"text": "asdf http://t.co/CRX3fCRa",
|
105
|
+
"created_at": "Wed Jul 25 07:30:25 +0000 2012"},
|
106
|
+
"source":
|
107
|
+
{"id": 459909498,
|
108
|
+
"verified": false,
|
109
|
+
"id_str": "459909498",
|
110
|
+
"profile_background_tile": false,
|
111
|
+
"location": "",
|
112
|
+
"profile_sidebar_fill_color": "DDEEF6",
|
113
|
+
"contributors_enabled": false,
|
114
|
+
"notifications": false,
|
115
|
+
"geo_enabled": false,
|
116
|
+
"profile_image_url_https":
|
117
|
+
"https://si0.twimg.com/sticky/default_profile_images/default_profile_6_normal.png",
|
118
|
+
"utc_offset": null,
|
119
|
+
"default_profile": true,
|
120
|
+
"statuses_count": 124,
|
121
|
+
"name": "Brian Park",
|
122
|
+
"profile_background_color": "C0DEED",
|
123
|
+
"friends_count": 3,
|
124
|
+
"show_all_inline_media": false,
|
125
|
+
"protected": false,
|
126
|
+
"follow_request_sent": false,
|
127
|
+
"screen_name": "bdares",
|
128
|
+
"listed_count": 0,
|
129
|
+
"profile_background_image_url":
|
130
|
+
"http://a0.twimg.com/images/themes/theme1/bg.png",
|
131
|
+
"lang": "en",
|
132
|
+
"profile_link_color": "0084B4",
|
133
|
+
"time_zone": null,
|
134
|
+
"description": "",
|
135
|
+
"is_translator": false,
|
136
|
+
"profile_use_background_image": true,
|
137
|
+
"url": null,
|
138
|
+
"profile_text_color": "333333",
|
139
|
+
"created_at": "Tue Jan 10 05:33:52 +0000 2012",
|
140
|
+
"default_profile_image": true,
|
141
|
+
"profile_background_image_url_https":
|
142
|
+
"https://si0.twimg.com/images/themes/theme1/bg.png",
|
143
|
+
"favourites_count": 14,
|
144
|
+
"profile_sidebar_border_color": "C0DEED",
|
145
|
+
"profile_image_url":
|
146
|
+
"http://a0.twimg.com/sticky/default_profile_images/default_profile_6_normal.png",
|
147
|
+
"following": false,
|
148
|
+
"followers_count": 1},
|
149
|
+
"event": "favorite",
|
150
|
+
"created_at": "Mon Aug 06 02:24:16 +0000 2012"}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
{
|
2
|
+
"follow":
|
3
|
+
{
|
4
|
+
"user":
|
5
|
+
{
|
6
|
+
"id":119476949,
|
7
|
+
"name":"oauth_dancer",
|
8
|
+
"dm":false
|
9
|
+
},
|
10
|
+
"friends":
|
11
|
+
[
|
12
|
+
795649,
|
13
|
+
819797,
|
14
|
+
1401881,
|
15
|
+
3191321,
|
16
|
+
6253282,
|
17
|
+
8285392,
|
18
|
+
9160152,
|
19
|
+
13058772,
|
20
|
+
15147442,
|
21
|
+
15266205,
|
22
|
+
15822993,
|
23
|
+
27831060,
|
24
|
+
101058399,
|
25
|
+
289788076
|
26
|
+
],
|
27
|
+
"previous_cursor":0,
|
28
|
+
"next_cursor":0
|
29
|
+
}
|
30
|
+
}
|