zuck 0.2.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MGYzNGI4MTQ0ZjJmNzgxZjQwY2JlNTg3YTgyMTc2NzlhYTE2NWNkZA==
5
+ data.tar.gz: !binary |-
6
+ ZjllZWZjNTgxYzdhYmRiNjQ1YmE2OTY5NTI5MmMyNmFjY2M2NDgyYQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NDU3YjViNWY4NWZiNGMzYTAwZTZmZmZmMWZmODVmNWQ2NjEyMzM3Nzc0OWFi
10
+ MWM5OWYwYTAyNmM1ODA4MTM1MmExYzI0MWM4YjM1N2MxNzc4NGFmMGYzMDc5
11
+ ODMwNzkwNTEzMThhYzgzYTE4ZWEyMWQ3NDM4NTdmMmZlMmY5Nzk=
12
+ data.tar.gz: !binary |-
13
+ NTZkMDQ0NzZlYzQyMGVmMmJiNjcwZmU2NmYzOTgwZTM1OWY2MGEwNjJhODQ3
14
+ YjcxMThmNzkxNDllOWYxMDhkMzhmMTBkNDk2ODg1ODFjY2RmYzBiODRjZDY2
15
+ MWMzZjkxNjhkNThmYjJkN2UxYTM3ZjM3ODE4Njg2ZGU1NDBlM2I=
data/.travis.yml CHANGED
@@ -3,5 +3,4 @@ rvm:
3
3
  - "1.9.2"
4
4
  - "1.9.3"
5
5
  - jruby-19mode
6
- - rbx-19mode
7
6
  script: bundle exec rspec spec
data/CHANGELOG.markdown CHANGED
@@ -1,6 +1,17 @@
1
+ 1.0.0
2
+ -----
3
+ - Implement Facebook's April 9 breaking changes, which also change this
4
+ gem
5
+ - AdKeyword/keywords are gone, welcome AdInterest/interests
6
+ (see [the
7
+ docs](https://developers.facebook.com/docs/reference/ads-api/interest-targeting))
8
+ - locations became geo_locations, and you can now also target cities
9
+ (see [the
10
+ docs](https://developers.facebook.com/docs/reference/ads-api/targeting-specs))
11
+
1
12
  0.2.0
2
13
  -----
3
- - implement Facbook's [Oct 2013 breaking changes](https://developers.facebook.com/roadmap/#q4_2013)
14
+ - implement Facebook's [Oct 2013 breaking changes](https://developers.facebook.com/roadmap/#q4_2013)
4
15
 
5
16
  0.0.9
6
17
  -----
data/Gemfile CHANGED
@@ -2,14 +2,14 @@ source 'http://rubygems.org'
2
2
 
3
3
  gem 'rvm'
4
4
  gem 'bundler'
5
- gem 'koala', '>=1.6'
5
+ gem 'koala', '~>1.6.0'
6
6
  gem 'activesupport'
7
7
 
8
8
  group :development do
9
- gem "shoulda", ">= 0"
9
+ gem "shoulda", "~> 3.3.2"
10
10
  gem "rdoc", "~> 3.12"
11
- gem "jeweler", "~> 1.8.4"
12
- gem "simplecov", ">= 0", :require => false
11
+ gem "jeweler", "~> 2.0.1"
12
+ gem "simplecov", "~> 0.7.1", :require => false
13
13
  end
14
14
 
15
15
  group :development, :test do
data/Gemfile.lock CHANGED
@@ -7,12 +7,20 @@ GEM
7
7
  addressable (2.3.3)
8
8
  bourne (1.1.2)
9
9
  mocha (= 0.10.5)
10
+ builder (3.2.2)
10
11
  coderay (1.0.8)
11
12
  crack (0.3.1)
12
13
  diff-lcs (1.1.3)
13
14
  faraday (0.8.7)
14
15
  multipart-post (~> 1.1)
15
- git (1.2.5)
16
+ git (1.2.6)
17
+ github_api (0.10.2)
18
+ addressable
19
+ faraday (~> 0.8.7)
20
+ hashie (>= 1.2)
21
+ multi_json (~> 1.4)
22
+ nokogiri (~> 1.6.0)
23
+ oauth2
16
24
  growl (1.0.3)
17
25
  guard (1.6.1)
18
26
  listen (>= 0.6.0)
@@ -28,14 +36,22 @@ GEM
28
36
  guard-yard (2.0.1)
29
37
  guard (>= 1.1.0)
30
38
  yard (>= 0.7.0)
39
+ hashie (2.1.1)
40
+ highline (1.6.21)
31
41
  i18n (0.6.1)
32
- jeweler (1.8.4)
33
- bundler (~> 1.0)
42
+ jeweler (2.0.1)
43
+ builder
44
+ bundler (>= 1.0)
34
45
  git (>= 1.2.5)
46
+ github_api
47
+ highline (>= 1.6.15)
48
+ nokogiri (>= 1.5.10)
35
49
  rake
36
50
  rdoc
37
- json (1.7.5)
38
- json (1.7.5-java)
51
+ json (1.8.1)
52
+ json (1.8.1-java)
53
+ jwt (0.1.11)
54
+ multi_json (>= 1.5)
39
55
  koala (1.6.0)
40
56
  addressable (~> 2.2)
41
57
  faraday (~> 0.8)
@@ -44,17 +60,30 @@ GEM
44
60
  lumberjack (1.0.2)
45
61
  metaclass (0.0.1)
46
62
  method_source (0.8.1)
63
+ mini_portile (0.5.3)
47
64
  mocha (0.10.5)
48
65
  metaclass (~> 0.0.1)
49
66
  multi_json (1.7.2)
67
+ multi_xml (0.5.5)
50
68
  multipart-post (1.2.0)
69
+ nokogiri (1.6.1)
70
+ mini_portile (~> 0.5.0)
71
+ nokogiri (1.6.1-java)
72
+ mini_portile (~> 0.5.0)
73
+ oauth2 (0.9.3)
74
+ faraday (>= 0.8, < 0.10)
75
+ jwt (~> 0.1.8)
76
+ multi_json (~> 1.3)
77
+ multi_xml (~> 0.5)
78
+ rack (~> 1.2)
51
79
  pry (0.9.10)
52
80
  coderay (~> 1.0.5)
53
81
  method_source (~> 0.8)
54
82
  slop (~> 3.3.1)
55
- rake (10.0.3)
83
+ rack (1.5.2)
84
+ rake (10.3.1)
56
85
  rb-fsevent (0.9.1)
57
- rdoc (3.12)
86
+ rdoc (3.12.2)
58
87
  json (~> 1.4)
59
88
  redcarpet (2.2.2)
60
89
  rspec (2.12.0)
@@ -97,14 +126,14 @@ DEPENDENCIES
97
126
  guard-bundler
98
127
  guard-rspec
99
128
  guard-yard
100
- jeweler (~> 1.8.4)
101
- koala (>= 1.6)
129
+ jeweler (~> 2.0.1)
130
+ koala (~> 1.6.0)
102
131
  rb-fsevent
103
132
  rdoc (~> 3.12)
104
133
  redcarpet
105
134
  rspec
106
135
  rvm
107
- shoulda
108
- simplecov
136
+ shoulda (~> 3.3.2)
137
+ simplecov (~> 0.7.1)
109
138
  vcr
110
139
  webmock (~> 1.8.0)
data/README.markdown CHANGED
@@ -88,14 +88,14 @@ group.ad_status
88
88
  => 3
89
89
  ```
90
90
 
91
- AdKeyword convenience methods
91
+ AdInterest convenience methods
92
92
  --------
93
93
 
94
94
  ```ruby
95
95
  graph = Zuck.graph
96
96
 
97
97
  # Search for keywords (to auto complete, for example) (yes, facebook sometimes returns ids as string and sometimes as numbers)
98
- Zuck::AdKeyword.search(graph, "Auto")
98
+ Zuck::AdInterest.search(graph, "Auto")
99
99
  => [
100
100
  {:keyword=>"Auto", :id=>"6003156165433", :audience=>nil},
101
101
  {:keyword=>"#Automobile", :id=>6003176678152, :audience=>97900000},
@@ -104,20 +104,20 @@ Zuck::AdKeyword.search(graph, "Auto")
104
104
  ]
105
105
 
106
106
  # Quickly check if a keyword is valid
107
- Zuck::AdKeyword.validate(graph, '#Eminem')
107
+ Zuck::AdInterest.validate(graph, '#Eminem')
108
108
  => {"#Eminem" => true}
109
109
 
110
110
  # Quickly check a couple of keywords
111
- Zuck::AdKeyword.validate(graph, ['#Eminem', 'Wil Ferel', 'Bronson'])
111
+ Zuck::AdInterest.validate(graph, ['#Eminem', 'Wil Ferel', 'Bronson'])
112
112
  => {"#Eminem"=>true, "Bronson"=>true, "Wil Ferel"=>false}
113
113
 
114
114
  # Make a best guess on how a keyword is called on Facebook
115
- Zuck::AdKeyword.best_guess(graph, 'Disney')
115
+ Zuck::AdInterest.best_guess(graph, 'Disney')
116
116
  => {:keyword=>"#The Walt Disney Company", :id=>6003270522085, :audience=>72500000}
117
117
 
118
118
  # Sometimes a best guess does not return a keyword with a # prefix, and that
119
119
  # means that we don't know the audience of that keyword:
120
- Zuck::AdKeyword.best_guess(graph, 'Moviepilot')
120
+ Zuck::AdInterest.best_guess(graph, 'Moviepilot')
121
121
  => {:keyword=>"Moviepilot", :id=>6003327847780, :audience=>nil}
122
122
 
123
123
  ```
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 1.0.0
@@ -0,0 +1,44 @@
1
+ module Zuck
2
+ module AdInterest
3
+ extend Zuck::Helpers
4
+ extend self
5
+
6
+ # Given an interest, make a guess on what the closest interest
7
+ # on the facebook ads api is. It tends to use a # prefixed
8
+ # interest if available, and also a more popular one over a less
9
+ # popular one
10
+ def best_guess(graph, interest)
11
+ search(graph, interest).sort do |a,b|
12
+ if a[:audience].to_i > 0 || b[:audience].to_i > 0
13
+ a[:audience].to_i <=> b[:audience].to_i
14
+ else
15
+ b[:interest].length <=> a[:interest].length
16
+ end
17
+ end.last
18
+ end
19
+
20
+ # Checks the ad api to see if the given interests are valid
21
+ # @return [Hash] The keys are the (lowercased) interests and the values their validity
22
+ def validate(graph, interests)
23
+ interests = normalize_array(interests).map{|k| k.gsub(',', '%2C')}
24
+ search = graph.search(nil, type: 'adinterestvalid', interest_list: [interests].flatten)
25
+ results = {}
26
+ search.each do |r|
27
+ results[r['name']] = r['valid']
28
+ end
29
+ results
30
+ end
31
+
32
+ # Ad interest search
33
+ def search(graph, interest)
34
+ results = graph.search(interest, type: :adinterest).map do |r|
35
+ {
36
+ interest: r['name'],
37
+ id: r['id'],
38
+ audience: r['audience_size']
39
+ }
40
+ end
41
+ end
42
+ end
43
+
44
+ end
@@ -35,13 +35,13 @@ module Zuck
35
35
  # Some helpers around https://developers.facebook.com/docs/reference/ads-api/targeting-specs/
36
36
  # Use like this:
37
37
  #
38
- # > ts = Facebook::TargetingSpec.new(graph, ad_account, keyword: 'foo', countries: ['US'])
38
+ # > ts = Facebook::TargetingSpec.new(graph, ad_account, interest: 'foo', geo_locations: {countries: ['US']})
39
39
  # > ts.spec
40
40
  # => {
41
41
  # :countries => [
42
42
  # [0] "US"
43
43
  # ],
44
- # :keywords => [
44
+ # :interests => [
45
45
  # [0] "foo"
46
46
  # ]
47
47
  # }
@@ -65,10 +65,10 @@ module Zuck
65
65
  # - `:age_class` (optional): Set it to `young` or `old` to autoconfigure `age_min` and `age_max`
66
66
  # for people older or younger than 25
67
67
  # - `:locales` (optional): [disabled] Array of integers, valid keys are here https://graph.facebook.com/search?type=adlocale&q=en
68
- # - `:keywords`: Array of strings with keywords
68
+ # - `:interests`: Array of strings with interests
69
69
  #
70
70
  def initialize(graph, ad_account, spec = nil)
71
- @validated_keywords = {}
71
+ @validated_interests = {}
72
72
  @graph = graph
73
73
  @ad_account = "act_#{ad_account}".gsub('act_act_', 'act_')
74
74
  self.spec = spec
@@ -91,23 +91,23 @@ module Zuck
91
91
  result.with_indifferent_access
92
92
  end
93
93
 
94
- def validate_keywords
95
- @spec[:keywords].each do |w|
96
- raise(InvalidKeywordError, w) unless validate_keyword(w)
94
+ def validate_interests
95
+ @spec[:interests].each do |w|
96
+ raise(InvalidKeywordError, w) unless validate_interest(w)
97
97
  end
98
98
  end
99
99
 
100
- # Validates a single keyword from the cache or calls
101
- # {TargetingSpec.validate_keywords}.to validate the keywords via
100
+ # Validates a single interest from the cache or calls
101
+ # {TargetingSpec.validate_interests}.to validate the interests via
102
102
  # facebook's api.
103
- # @param keyword [String] A single keyword
103
+ # @param interest [String] A single interest
104
104
  # @return boolean
105
- def validate_keyword(keyword)
106
- if @validated_keywords[keyword] == nil
107
- keywords = normalize_array([@spec[:keywords]] + [keyword])
108
- @validated_keywords = Zuck::AdKeyword.validate(@graph, keywords)
105
+ def validate_interest(interest)
106
+ if @validated_interests[interest] == nil
107
+ interests = normalize_array([@spec[:interests]] + [interest])
108
+ @validated_interests = Zuck::AdInterest.validate(@graph, interests)
109
109
  end
110
- @validated_keywords[keyword] == true
110
+ @validated_interests[interest] == true
111
111
  end
112
112
 
113
113
  # Fetches a bunch of reach estimates from facebook at once.
@@ -153,17 +153,18 @@ module Zuck
153
153
  private
154
154
 
155
155
  def validate_spec
156
- @spec[:countries] = normalize_countries(@spec[:countries])
157
- @spec[:keywords] = normalize_array(@spec[:keywords])
156
+ @spec[:interests] = normalize_array(@spec[:interests])
158
157
  @spec[:broad_age] ||= false
159
158
  validate_countries
160
- unless @spec[:keywords].present? or @spec[:connections].present?
161
- raise(ParamsMissingError, "Need to set :keywords or :connections")
159
+ unless @spec[:interests].present? or @spec[:connections].present?
160
+ raise(ParamsMissingError, "Need to set :interests or :connections")
162
161
  end
163
162
  end
164
163
 
165
164
  def validate_countries
166
- self.class.valid_countries?(@spec[:countries])
165
+ return unless @spec[:geo_locations] and @spec[:geo_locations][:countries]
166
+ @spec[:geo_locations][:countries] = normalize_countries(@spec[:geo_locations][:countries])
167
+ self.class.valid_countries?(@spec[:geo_locations][:countries])
167
168
  end
168
169
 
169
170
  def self.valid_countries?(countries)
@@ -193,8 +194,8 @@ module Zuck
193
194
  @spec[:genders] = [1] if gender.to_s == 'male'
194
195
  @spec[:genders] = [2] if gender.to_s == 'female'
195
196
 
196
- keyword = spec.delete(:keyword)
197
- @spec[:keywords] = normalize_array([keyword, @spec[:keywords]])
197
+ interest = spec.delete(:interest)
198
+ @spec[:interests] = normalize_array([interest, @spec[:interests]])
198
199
 
199
200
  country = spec.delete(:country)
200
201
  @spec[:countries] = normalize_countries([country, @spec[:countries]])
@@ -0,0 +1,54 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://graph.facebook.com/search?access_token=CAAEvJ5vzhl8BAPGZCZCPL4FxryEHXGxPCuCGeqe3PEWIjhIvJ00HB8PPpokFmUkemvmEUHirqdNMc7zIDLSTVnX6jTQjAgSlzcYrAYJRQ32fr6RM5ZAnKPdgFEwN5tgvswatXZAI4vu7ZBAQexRl9MU0CpwW7JDDBZAGo5XDrCKrBxkUUWJUvh&q=disney&type=adinterest
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - Faraday v0.8.7
12
+ Accept-Encoding:
13
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
+ Accept:
15
+ - ! '*/*'
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Etag:
22
+ - ! '"8b5fcea570986b5e25aff7226b80215ebf71cf56"'
23
+ Content-Type:
24
+ - application/json; charset=UTF-8
25
+ Pragma:
26
+ - no-cache
27
+ Access-Control-Allow-Origin:
28
+ - ! '*'
29
+ X-Fb-Rev:
30
+ - '1216101'
31
+ Cache-Control:
32
+ - private, no-cache, no-store, must-revalidate
33
+ Expires:
34
+ - Sat, 01 Jan 2000 00:00:00 GMT
35
+ X-Fb-Debug:
36
+ - oBEMRG6MgL42DEtthxp3LNt+Gzgr2GbJckt8uA8N/q8=
37
+ Date:
38
+ - Tue, 22 Apr 2014 16:22:30 GMT
39
+ Connection:
40
+ - keep-alive
41
+ Content-Length:
42
+ - '854'
43
+ body:
44
+ encoding: US-ASCII
45
+ string: ! '{"data":[{"name":"The Walt Disney Company","id":6003270522085,"audience_size":129354141,"path":[],"description":null},{"name":"Disney
46
+ Channel","id":6003327130854,"audience_size":45965936,"path":[],"description":null},{"name":"Walt
47
+ Disney","id":6003284678611,"audience_size":38133064,"path":[],"description":null},{"name":"Disneyland","id":6003274193708,"audience_size":31257896,"path":[],"description":null},{"name":"Walt
48
+ Disney Parks and Resorts","id":6003318701218,"audience_size":26448385,"path":[],"description":null},{"name":"List
49
+ of Disney Channel Original Movies","id":6003220883649,"audience_size":38392980,"path":[],"description":null},{"name":"Disney
50
+ XD","id":6003540152503,"audience_size":16841504,"path":[],"description":null},{"name":"Walt
51
+ Disney Animation Studios","id":6003375444677,"audience_size":17506594,"path":[],"description":null}]}'
52
+ http_version:
53
+ recorded_at: Tue, 22 Apr 2014 16:22:31 GMT
54
+ recorded_with: VCR 2.3.0
@@ -0,0 +1,138 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://graph.facebook.com/search?access_token=CAAEvJ5vzhl8BAPGZCZCPL4FxryEHXGxPCuCGeqe3PEWIjhIvJ00HB8PPpokFmUkemvmEUHirqdNMc7zIDLSTVnX6jTQjAgSlzcYrAYJRQ32fr6RM5ZAnKPdgFEwN5tgvswatXZAI4vu7ZBAQexRl9MU0CpwW7JDDBZAGo5XDrCKrBxkUUWJUvh&q=moviepilotcom&type=adinterest
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - Faraday v0.8.7
12
+ Accept-Encoding:
13
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
+ Accept:
15
+ - ! '*/*'
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Etag:
22
+ - ! '"f4708ef59d4457b905f54670ff7a3ab8fb53d758"'
23
+ Content-Type:
24
+ - application/json; charset=UTF-8
25
+ Pragma:
26
+ - no-cache
27
+ Access-Control-Allow-Origin:
28
+ - ! '*'
29
+ X-Fb-Rev:
30
+ - '1216101'
31
+ Cache-Control:
32
+ - private, no-cache, no-store, must-revalidate
33
+ Expires:
34
+ - Sat, 01 Jan 2000 00:00:00 GMT
35
+ X-Fb-Debug:
36
+ - 9Ihh9aS8WUH+aH6uc7MUk/Kxu6CV8yMAw6N0dClTJaM=
37
+ Date:
38
+ - Tue, 22 Apr 2014 16:22:30 GMT
39
+ Connection:
40
+ - keep-alive
41
+ Content-Length:
42
+ - '107'
43
+ body:
44
+ encoding: US-ASCII
45
+ string: ! '{"data":[{"name":"moviepilotcom","id":6003495809986,"audience_size":4992196,"path":[],"description":null}]}'
46
+ http_version:
47
+ recorded_at: Tue, 22 Apr 2014 16:22:32 GMT
48
+ - request:
49
+ method: get
50
+ uri: https://graph.facebook.com/search?access_token=CAAEvJ5vzhl8BAPGZCZCPL4FxryEHXGxPCuCGeqe3PEWIjhIvJ00HB8PPpokFmUkemvmEUHirqdNMc7zIDLSTVnX6jTQjAgSlzcYrAYJRQ32fr6RM5ZAnKPdgFEwN5tgvswatXZAI4vu7ZBAQexRl9MU0CpwW7JDDBZAGo5XDrCKrBxkUUWJUvh&q=moviepilotcocomm&type=adinterest
51
+ body:
52
+ encoding: US-ASCII
53
+ string: ''
54
+ headers:
55
+ User-Agent:
56
+ - Faraday v0.8.7
57
+ Accept-Encoding:
58
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
59
+ Accept:
60
+ - ! '*/*'
61
+ response:
62
+ status:
63
+ code: 200
64
+ message: OK
65
+ headers:
66
+ Etag:
67
+ - ! '"1050253aec7b29caff644806927dabfa81406eee"'
68
+ Content-Type:
69
+ - application/json; charset=UTF-8
70
+ Pragma:
71
+ - no-cache
72
+ Access-Control-Allow-Origin:
73
+ - ! '*'
74
+ X-Fb-Rev:
75
+ - '1216101'
76
+ Cache-Control:
77
+ - private, no-cache, no-store, must-revalidate
78
+ Expires:
79
+ - Sat, 01 Jan 2000 00:00:00 GMT
80
+ X-Fb-Debug:
81
+ - bBOfyA7fkYvP457S15CzkxmNavxH4F+Zx+Sys3Ux4v0=
82
+ Date:
83
+ - Tue, 22 Apr 2014 16:23:50 GMT
84
+ Connection:
85
+ - keep-alive
86
+ Content-Length:
87
+ - '11'
88
+ body:
89
+ encoding: US-ASCII
90
+ string: ! '{"data":[]}'
91
+ http_version:
92
+ recorded_at: Tue, 22 Apr 2014 16:23:52 GMT
93
+ - request:
94
+ method: get
95
+ uri: https://graph.facebook.com/search?access_token=CAAEvJ5vzhl8BAPGZCZCPL4FxryEHXGxPCuCGeqe3PEWIjhIvJ00HB8PPpokFmUkemvmEUHirqdNMc7zIDLSTVnX6jTQjAgSlzcYrAYJRQ32fr6RM5ZAnKPdgFEwN5tgvswatXZAI4vu7ZBAQexRl9MU0CpwW7JDDBZAGo5XDrCKrBxkUUWJUvh&q=moviepilot&type=adinterest
96
+ body:
97
+ encoding: US-ASCII
98
+ string: ''
99
+ headers:
100
+ User-Agent:
101
+ - Faraday v0.8.7
102
+ Accept-Encoding:
103
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
104
+ Accept:
105
+ - ! '*/*'
106
+ response:
107
+ status:
108
+ code: 200
109
+ message: OK
110
+ headers:
111
+ Etag:
112
+ - ! '"60861a1401b05970d9b7f19b2f1a6cbf470fe17b"'
113
+ Content-Type:
114
+ - application/json; charset=UTF-8
115
+ Pragma:
116
+ - no-cache
117
+ Access-Control-Allow-Origin:
118
+ - ! '*'
119
+ X-Fb-Rev:
120
+ - '1216101'
121
+ Cache-Control:
122
+ - private, no-cache, no-store, must-revalidate
123
+ Expires:
124
+ - Sat, 01 Jan 2000 00:00:00 GMT
125
+ X-Fb-Debug:
126
+ - uo6B1d8Kd0luLkuJlq53BjWBVCcZl93SjpuywRl/Aro=
127
+ Date:
128
+ - Tue, 22 Apr 2014 16:24:12 GMT
129
+ Connection:
130
+ - keep-alive
131
+ Content-Length:
132
+ - '201'
133
+ body:
134
+ encoding: US-ASCII
135
+ string: ! '{"data":[{"name":"moviepilotcom","id":6003495809986,"audience_size":4992196,"path":[],"description":null},{"name":"moviepilot","id":6003327847780,"audience_size":2036083,"path":[],"description":null}]}'
136
+ http_version:
137
+ recorded_at: Tue, 22 Apr 2014 16:24:13 GMT
138
+ recorded_with: VCR 2.3.0