facegroups 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 92303bfc890617bfc360e4b089049596605649cb
4
+ data.tar.gz: f8bce6b8de9f77dc300239e56d1628adc2f04521
5
+ SHA512:
6
+ metadata.gz: 1088ff453e77ea1e3e444ae4bf545228ea6ed31bd4f0d98ed813d72aa2f651c3cf6e6beb0c30e3e727cfa905a94dad7e8dd5f10add803136f25c04743f48da82
7
+ data.tar.gz: a9f26a451f7761f5584721b769d5224730520e309d364da5a1d246a5b99ab3d1c6eccfc4719359c3a51c15306f2a8da488fffa03b61ed581ef612cf56c614668
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ config/credentials.yml
2
+ coverage/
3
+ Gemfile.lock
4
+ *.gem
data/.rubocop.yml ADDED
@@ -0,0 +1,3 @@
1
+ ---
2
+ AllCops:
3
+ TargetRubyVersion: 2.3
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.1
4
+ - 2.2
5
+ - 2.1
6
+ branches:
7
+ only:
8
+ - master
9
+ - develop
10
+ script: bundle exec rake spec
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+ source 'https://rubygems.org'
3
+
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,89 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ facegroups (0.1.0)
5
+ http (~> 2.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ addressable (2.4.0)
11
+ ast (2.3.0)
12
+ crack (0.4.3)
13
+ safe_yaml (~> 1.0.0)
14
+ docile (1.1.5)
15
+ domain_name (0.5.20160826)
16
+ unf (>= 0.0.5, < 1.0.0)
17
+ erubis (2.7.0)
18
+ flay (2.8.1)
19
+ erubis (~> 2.7.0)
20
+ path_expander (~> 1.0)
21
+ ruby_parser (~> 3.0)
22
+ sexp_processor (~> 4.0)
23
+ flog (4.4.0)
24
+ path_expander (~> 1.0)
25
+ ruby_parser (~> 3.1, > 3.1.0)
26
+ sexp_processor (~> 4.4)
27
+ hashdiff (0.3.0)
28
+ http (2.0.3)
29
+ addressable (~> 2.3)
30
+ http-cookie (~> 1.0)
31
+ http-form_data (~> 1.0.1)
32
+ http_parser.rb (~> 0.6.0)
33
+ http-cookie (1.0.3)
34
+ domain_name (~> 0.5)
35
+ http-form_data (1.0.1)
36
+ http_parser.rb (0.6.0)
37
+ json (2.0.2)
38
+ minitest (5.9.1)
39
+ minitest-rg (5.2.0)
40
+ minitest (~> 5.0)
41
+ parser (2.3.1.4)
42
+ ast (~> 2.2)
43
+ path_expander (1.0.0)
44
+ powerpack (0.1.1)
45
+ rainbow (2.1.0)
46
+ rake (11.3.0)
47
+ rubocop (0.44.1)
48
+ parser (>= 2.3.1.1, < 3.0)
49
+ powerpack (~> 0.1)
50
+ rainbow (>= 1.99.1, < 3.0)
51
+ ruby-progressbar (~> 1.7)
52
+ unicode-display_width (~> 1.0, >= 1.0.1)
53
+ ruby-progressbar (1.8.1)
54
+ ruby_parser (3.8.3)
55
+ sexp_processor (~> 4.1)
56
+ safe_yaml (1.0.4)
57
+ sexp_processor (4.7.0)
58
+ simplecov (0.12.0)
59
+ docile (~> 1.1.0)
60
+ json (>= 1.8, < 3)
61
+ simplecov-html (~> 0.10.0)
62
+ simplecov-html (0.10.0)
63
+ unf (0.1.4)
64
+ unf_ext
65
+ unf_ext (0.0.7.2)
66
+ unicode-display_width (1.1.1)
67
+ vcr (3.0.3)
68
+ webmock (2.1.0)
69
+ addressable (>= 2.3.6)
70
+ crack (>= 0.3.2)
71
+ hashdiff
72
+
73
+ PLATFORMS
74
+ ruby
75
+
76
+ DEPENDENCIES
77
+ facegroups!
78
+ flay (~> 2.8)
79
+ flog (~> 4.4)
80
+ minitest (~> 5.9)
81
+ minitest-rg (~> 5.2)
82
+ rake (~> 11.3)
83
+ rubocop (~> 0.42)
84
+ simplecov (~> 0.12)
85
+ vcr (~> 3.0)
86
+ webmock (~> 2.1)
87
+
88
+ BUNDLED WITH
89
+ 1.13.6
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016 Aditya Utama Wijaya
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,55 @@
1
+ # FaceGroups Gem
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/facegroups.svg)](https://badge.fury.io/rb/facegroup)
4
+ [![Build Status](https://travis-ci.org/aditya-utama-wijaya/facegroups.svg?branch=master)](https://travis-ci.org/aditya-utama-wijaya/facegroup)
5
+
6
+ FaceGroups is a gem that specializes in getting data from public Facebook Groups.
7
+
8
+ ## Installation
9
+
10
+ If you are working on a project, add this to your Gemfile: `gem 'facegroups'`
11
+
12
+ For ad hoc installation from command line:
13
+ ```$ gem install facegroups```
14
+
15
+ ## Setup Facebook Credentials
16
+
17
+ Please setup your Facebook developer credentials by creating an app profile on Facebook Developer: https://developers.facebook.com - you should get a "client ID" and "client secret".
18
+
19
+ ## Usage
20
+
21
+ Require FaceGroups gem in your code: `require 'facegroups'`
22
+
23
+ Supply your Facebook credentials to our library in one of two ways:
24
+ - Setup environment variables: `ENV[FB_CLIENT_ID]` and `ENV[FB_CLIENT_SECRET]`
25
+ - or, provide them directly to FaceGroups:
26
+
27
+ ```
28
+ FaceGroups::FbApi.config = {
29
+ client_id: ENV[FB_CLIENT_ID],
30
+ client_secret: ENV[FB_CLIENT_SECRET]
31
+ }
32
+ ```
33
+
34
+ See the following example code for more usage details:
35
+
36
+ ```ruby
37
+ # Access the group
38
+ group = FaceGroups::Group.find(id: ENV['FB_GROUP_ID'])
39
+
40
+ puts group.name
41
+
42
+ feed = group.feed
43
+
44
+ puts feed.count
45
+
46
+ group.feed.postings.each do |posting|
47
+ puts posting.id
48
+ puts posting.created_time
49
+ puts posting.message
50
+ if posting.attachment
51
+ puts posting.attachment.description
52
+ puts posting.attachment.url
53
+ end
54
+ end
55
+ ```
data/Rakefile ADDED
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+ require 'rake/testtask'
3
+
4
+ task default: :spec
5
+
6
+ namespace :credentials do
7
+ require 'yaml'
8
+ desc 'generate access_token to STDOUT'
9
+ task :get_access_token do
10
+ credentials = YAML.load(File.read('config/credentials.yml'))
11
+ require_relative 'lib/fb_api'
12
+ ENV['FBAPI_CLIENT_ID'] = credentials[:client_id]
13
+ ENV['FBAPI_CLIENT_SECRET'] = credentials[:client_secret]
14
+
15
+ puts "Access Token: #{FaceGroups::FbApi.access_token}"
16
+ end
17
+
18
+ desc 'Export sample credentials from file to bash'
19
+ task :export do
20
+ credentials = YAML.load(File.read('config/credentials.yml'))
21
+ puts 'Please run the following in bash:'
22
+ puts "export FBAPI_CLIENT_ID=#{credentials[:client_id]}"
23
+ puts "export FBAPI_CLIENT_SECRET=#{credentials[:client_secret]}"
24
+ end
25
+ end
26
+
27
+ desc 'run tests'
28
+ task :spec do
29
+ sh 'ruby spec/facegroups_spec.rb'
30
+ end
31
+
32
+ desc 'delete cassette fixtures'
33
+ task :wipe do
34
+ sh 'rm spec/fixtures/cassettes/*.yml' do |ok, _|
35
+ puts(ok ? 'Cassettes deleted' : 'No cassettes found')
36
+ end
37
+ end
38
+
39
+ namespace :quality do
40
+ desc 'run all quality checks'
41
+ task all: [:rubocop, :flog, :flay]
42
+
43
+ task :flog do
44
+ sh 'flog lib/'
45
+ end
46
+
47
+ task :flay do
48
+ sh 'flay lib/'
49
+ end
50
+
51
+ task :rubocop do
52
+ sh 'rubocop'
53
+ end
54
+ end
data/bin/facegroups ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w(.. lib))
4
+ require 'facegroups'
5
+
6
+ group_id = ARGV[0] || ENV['FB_GROUP_ID']
7
+ unless group_id
8
+ puts 'USAGE: facegroups [group_id]'
9
+ exit(1)
10
+ end
11
+
12
+ group = FaceGroups::Group.find(id: group_id)
13
+
14
+ puts group.name
15
+ puts Array.new(group.name.length) { '-' }.join
16
+ group.feed.postings.first(3).each.with_index do |post, index|
17
+ print "#{index + 1}"
18
+ puts post.message ? post.message : '(blank)'
19
+ puts "Attached: #{post.attachment.url}" if post.attachment
20
+ puts
21
+ end
@@ -0,0 +1,5 @@
1
+ ---
2
+ :client_id: ''
3
+ :client_secret: ''
4
+ :access_token: ''
5
+ :group_id: ''
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ $LOAD_PATH.push File.expand_path("../lib", __FILE__)
3
+ require 'facegroups/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'facegroups'
7
+ s.version = FaceGroups::VERSION
8
+
9
+ s.summary = 'Gets posted content from public Facebook groups'
10
+ s.description = 'Extracts feed, postings, and attachments from FB groups'
11
+ s.authors = ['Aditya Utama Wijaya']
12
+ s.email = ['adityautamawijaya@gmail.com']
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- spec/*`.split("\n")
16
+ s.executables << 'facegroups'
17
+
18
+ s.add_runtime_dependency 'http', '~> 2.0'
19
+
20
+ s.add_development_dependency 'minitest', '~> 5.9'
21
+ s.add_development_dependency 'minitest-rg', '~> 5.2'
22
+ s.add_development_dependency 'rake', '~> 11.3'
23
+ s.add_development_dependency 'vcr', '~> 3.0'
24
+ s.add_development_dependency 'webmock', '~> 2.1'
25
+ s.add_development_dependency 'simplecov', '~> 0.12'
26
+ s.add_development_dependency 'flog', '~> 4.4'
27
+ s.add_development_dependency 'flay', '~> 2.8'
28
+ s.add_development_dependency 'rubocop', '~> 0.42'
29
+
30
+ s.homepage = 'https://github.com/aditya-utama-wijaya/facegroups'
31
+ s.license = 'MIT'
32
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FaceGroups
4
+ # Attached URL to Posting
5
+ class Attachment
6
+ attr_reader :title, :description, :url
7
+
8
+ def initialize(data)
9
+ return unless data
10
+ attachment_data = data['data'].first
11
+ @title = attachment_data['title']
12
+ @description = attachment_data['description']
13
+ @url = attachment_data['url']
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+ require 'http'
3
+
4
+ module FaceGroups
5
+ # Service for all FB API calls
6
+ class FbApi
7
+ FB_URL = 'https://graph.facebook.com'
8
+ API_VER = 'v2.8'
9
+ FB_API_URL = [FB_URL, API_VER].join('/')
10
+ FB_TOKEN_URL = [FB_API_URL, 'oauth/access_token'].join('/')
11
+ TOKEN_KEY = 'fbapi_access_token'
12
+
13
+ GRAPH_QUERY = {
14
+ group:
15
+ 'id,name,feed{name,message,updated_time,created_time,'\
16
+ 'attachments{title,description,url,media}}',
17
+ posting:
18
+ 'name,message,updated_time,created_time,'\
19
+ 'attachments{title,description,url,media}'
20
+ }.freeze
21
+
22
+ def self.access_token
23
+ return @access_token if @access_token
24
+
25
+ access_token_response = HTTP.get(
26
+ FB_TOKEN_URL,
27
+ params: {
28
+ client_id: config[:client_id],
29
+ client_secret: config[:client_secret],
30
+ grant_type: 'client_credentials'
31
+ }
32
+ )
33
+ @access_token = access_token_response.parse['access_token']
34
+ end
35
+
36
+ def self.config=(credentials)
37
+ @config ? @config.update(credentials) : @config = credentials
38
+ end
39
+
40
+ def self.config
41
+ return @config if @config
42
+ @config = {
43
+ client_id: ENV['FB_CLIENT_ID'],
44
+ client_secret: ENV['FB_CLIENT_SECRET']
45
+ }
46
+ end
47
+
48
+ def self.group_data(group_id)
49
+ graphql_query(group_id, :group)
50
+ end
51
+
52
+ def self.posting_data(posting_id)
53
+ graphql_query(posting_id, :posting)
54
+ end
55
+
56
+ def self.graphql_query(resource_id, resource_key)
57
+ response = HTTP.get(
58
+ fb_resource_url(resource_id),
59
+ params: {
60
+ fields: GRAPH_QUERY[resource_key],
61
+ access_token: access_token
62
+ }
63
+ )
64
+ JSON.load(response.to_s)
65
+ end
66
+
67
+ private_class_method
68
+
69
+ def self.fb_resource_url(id)
70
+ URI.join(FB_API_URL, id.to_s).to_s
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'fb_api'
3
+ require_relative 'posting'
4
+
5
+ module FaceGroups
6
+ # Group feeds, with data and paging information
7
+ class Feed
8
+ attr_reader :postings
9
+
10
+ def initialize(feed_data:)
11
+ postings_data = feed_data['data']
12
+ @postings = postings_data.map do |post_data|
13
+ FaceGroups::Posting.new(data: post_data)
14
+ end
15
+
16
+ @pagination = feed_data['pagination']
17
+ end
18
+
19
+ def count
20
+ @postings.count
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'fb_api'
3
+ require_relative 'feed'
4
+
5
+ module FaceGroups
6
+ # Main class to setup a Facebook group
7
+ class Group
8
+ attr_reader :id, :name, :feed
9
+
10
+ def initialize(group_data:)
11
+ @name = group_data['name']
12
+ @id = group_data['id']
13
+ @feed = Feed.new(feed_data: group_data['feed'])
14
+ end
15
+
16
+ def self.find(id:)
17
+ group_data = FbApi.group_data(id)
18
+ new(group_data: group_data)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'fb_api'
3
+ require_relative 'attachment'
4
+
5
+ module FaceGroups
6
+ # Single posting on group's feed
7
+ class Posting
8
+ attr_reader :id, :created_time, :updated_time, :message, :name, :attachment
9
+
10
+ def initialize(data: nil)
11
+ load_data(data)
12
+ end
13
+
14
+ def self.find(id:)
15
+ posting_data = FaceGroups::FbApi.posting_data(id)
16
+ new(data: posting_data)
17
+ end
18
+
19
+ private
20
+
21
+ def load_data(posting_data)
22
+ @id = posting_data['id']
23
+ @updated_time = posting_data['updated_time']
24
+ @created_time = posting_data['created_time']
25
+ @name = posting_data['message']
26
+ @message = posting_data['message']
27
+ attached = posting_data['attachments']
28
+ @attachment = Attachment.new(attached) if attached
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FaceGroups
4
+ VERSION = '0.1.0'
5
+ end
data/lib/facegroups.rb ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ files = Dir.glob(File.join(File.dirname(__FILE__), 'facegroups/*.rb'))
4
+ files.each { |lib| require_relative lib }
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'spec_helper.rb'
3
+
4
+ describe 'FaceGroups specifications' do
5
+ VCR.configure do |c|
6
+ c.cassette_library_dir = CASSETTES_FOLDER
7
+ c.hook_into :webmock
8
+
9
+ c.filter_sensitive_data('<ACCESS_TOKEN>') do
10
+ URI.unescape(ENV['FB_ACCESS_TOKEN'])
11
+ end
12
+
13
+ c.filter_sensitive_data('<ACCESS_TOKEN_ESCAPED>') do
14
+ ENV['FB_ACCESS_TOKEN']
15
+ end
16
+
17
+ c.filter_sensitive_data('<CLIENT_ID>') { ENV['FB_CLIENT_ID'] }
18
+ c.filter_sensitive_data('<CLIENT_SECRET>') { ENV['FB_CLIENT_SECRET'] }
19
+ end
20
+
21
+ before do
22
+ VCR.insert_cassette CASSETTE_FILE, record: :new_episodes
23
+ end
24
+
25
+ after do
26
+ VCR.eject_cassette
27
+ end
28
+
29
+ describe 'FbApi Credentials' do
30
+ it 'should be able to get a new access token with ENV credentials' do
31
+ FaceGroups::FbApi.access_token.length.must_be :>, 0
32
+ end
33
+
34
+ it 'should be able to get a new access token with file credentials' do
35
+ FaceGroups::FbApi.config = {
36
+ client_id: ENV['FB_CLIENT_ID'],
37
+ client_secret: ENV['FB_CLIENT_SECRET']
38
+ }
39
+ FaceGroups::FbApi.access_token.length.must_be :>, 0
40
+ end
41
+ end
42
+
43
+ it 'should be able to open a Facebook Group' do
44
+ group = FaceGroups::Group.find(
45
+ id: ENV['FB_GROUP_ID']
46
+ )
47
+
48
+ group.name.length.must_be :>, 0
49
+ end
50
+
51
+ it 'should get the latest feed from a group' do
52
+ group = FaceGroups::Group.find(
53
+ id: ENV['FB_GROUP_ID']
54
+ )
55
+
56
+ feed = group.feed
57
+ feed.count.must_be :>, 1
58
+ end
59
+
60
+ it 'should get basic information about postings on the feed' do
61
+ group = FaceGroups::Group.find(
62
+ id: ENV['FB_GROUP_ID']
63
+ )
64
+
65
+ group.feed.postings.each do |posting|
66
+ posting.id.wont_be_nil
67
+ posting.updated_time.wont_be_nil
68
+ end
69
+ end
70
+
71
+ it 'should find all parts of a full posting' do
72
+ posting = FB_RESULT['posting']
73
+ attachment = posting['attachment'].first
74
+ retrieved = FaceGroups::Posting.find(id: posting['id'])
75
+
76
+ retrieved.id.must_equal posting['id']
77
+ retrieved.created_time.must_equal posting['created_time']
78
+ retrieved.message.must_equal posting['message']
79
+ retrieved.attachment.wont_be_nil
80
+ retrieved.attachment.description.must_equal attachment['description']
81
+ retrieved.attachment.url.must_match 'tutorialzine'
82
+ end
83
+ end
@@ -0,0 +1,297 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://graph.facebook.com/v2.8/oauth/access_token?client_id=<CLIENT_ID>&client_secret=<CLIENT_SECRET>&grant_type=client_credentials
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Connection:
11
+ - close
12
+ Host:
13
+ - graph.facebook.com
14
+ User-Agent:
15
+ - http.rb/2.0.3
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Access-Control-Allow-Origin:
22
+ - "*"
23
+ Pragma:
24
+ - no-cache
25
+ Cache-Control:
26
+ - private, no-cache, no-store, must-revalidate
27
+ Facebook-Api-Version:
28
+ - v2.8
29
+ Expires:
30
+ - Sat, 01 Jan 2000 00:00:00 GMT
31
+ Content-Type:
32
+ - application/json; charset=UTF-8
33
+ X-Fb-Trace-Id:
34
+ - C+G0/33ZH0o
35
+ X-Fb-Rev:
36
+ - '2654373'
37
+ X-Fb-Debug:
38
+ - 6W+8KMRw3wPdtxDUy9k0/LourAqASLcTLLXbyC4OzbE2+xlYzurPkMFOOEROugODHwdIsC0Bu4WDL6o1eIs3Wg==
39
+ Date:
40
+ - Mon, 31 Oct 2016 11:36:31 GMT
41
+ Connection:
42
+ - close
43
+ Content-Length:
44
+ - '85'
45
+ body:
46
+ encoding: UTF-8
47
+ string: '{"access_token":"<ACCESS_TOKEN>","token_type":"bearer"}'
48
+ http_version:
49
+ recorded_at: Mon, 31 Oct 2016 11:36:13 GMT
50
+ - request:
51
+ method: get
52
+ uri: https://graph.facebook.com/150352985174571_517105121832687?access_token=<CLIENT_ID>%7C0WiNEz4rbcf5Ki0Ge4vR7m4Wlts&fields=name,message,updated_time,created_time,attachments%7Btitle,description,url,media%7D
53
+ body:
54
+ encoding: US-ASCII
55
+ string: ''
56
+ headers:
57
+ Connection:
58
+ - close
59
+ Host:
60
+ - graph.facebook.com
61
+ User-Agent:
62
+ - http.rb/2.0.3
63
+ response:
64
+ status:
65
+ code: 200
66
+ message: OK
67
+ headers:
68
+ Access-Control-Allow-Origin:
69
+ - "*"
70
+ Etag:
71
+ - '"19ab4fac7a978265ff28a3f4c89a24f3a37265f4"'
72
+ Pragma:
73
+ - no-cache
74
+ Cache-Control:
75
+ - private, no-cache, no-store, must-revalidate
76
+ Facebook-Api-Version:
77
+ - v2.7
78
+ Expires:
79
+ - Sat, 01 Jan 2000 00:00:00 GMT
80
+ Content-Type:
81
+ - text/javascript; charset=UTF-8
82
+ X-Fb-Trace-Id:
83
+ - HUt5ZGrTYkm
84
+ X-Fb-Rev:
85
+ - '2654373'
86
+ Vary:
87
+ - Accept-Encoding
88
+ X-Fb-Debug:
89
+ - zvEa/+ZE+NkLMj6+4VJpKOuYmfhO3qHrj+qqxO990wx53Ttsv/b1/wg5C/LQ4Ci10m70DkDMwJLeIEsKvModtA==
90
+ Date:
91
+ - Mon, 31 Oct 2016 11:36:32 GMT
92
+ Connection:
93
+ - close
94
+ body:
95
+ encoding: UTF-8
96
+ string: '{"name":"Guess the Programming Language | Tutorialzine","message":"A
97
+ little quiz to keep you sharp on programming trends.","updated_time":"2016-10-06T06:51:44+0000","created_time":"2016-10-04T02:21:25+0000","attachments":{"data":[{"title":"Guess
98
+ the Programming Language | Tutorialzine","description":"Can you tell Java
99
+ from JavaScript? Awesome! So you are ready to take our ultimate programming
100
+ challenge.","url":"http:\/\/www.facebook.com\/l.php?u=http\u00253A\u00252F\u00252Ftutorialzine.com\u00252F2014\u00252F06\u00252Fguess-the-programming-language\u00252F&h=ZAQFN2caD&s=1&enc=AZOSnK148OZJedVdYW4wBMXBd3PXCWbCnSv00om_hEzZx_-VSjNESrSgpmRpy0iGYn_kc_x85BOz70FuPyrkJwRx","media":{"image":{"height":490,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQB9saA-D40lNQqm&w=720&h=720&url=http\u00253A\u00252F\u00252Fcdn.tutorialzine.com\u00252Fwp-content\u00252Fuploads\u00252F2014\u00252F06\u00252Fguess-the-programming-language.jpg&cfs=1","width":490}}}]},"id":"150352985174571_517105121832687"}'
101
+ http_version:
102
+ recorded_at: Mon, 31 Oct 2016 11:36:13 GMT
103
+ - request:
104
+ method: get
105
+ uri: https://graph.facebook.com/150352985174571?access_token=<CLIENT_ID>%7C0WiNEz4rbcf5Ki0Ge4vR7m4Wlts&fields=id,name,feed%7Bname,message,updated_time,created_time,attachments%7Btitle,description,url,media%7D%7D
106
+ body:
107
+ encoding: US-ASCII
108
+ string: ''
109
+ headers:
110
+ Connection:
111
+ - close
112
+ Host:
113
+ - graph.facebook.com
114
+ User-Agent:
115
+ - http.rb/2.0.3
116
+ response:
117
+ status:
118
+ code: 200
119
+ message: OK
120
+ headers:
121
+ Access-Control-Allow-Origin:
122
+ - "*"
123
+ Etag:
124
+ - '"1553fa0c64c395667251b3f53cd905ba13401d99"'
125
+ Pragma:
126
+ - no-cache
127
+ Cache-Control:
128
+ - private, no-cache, no-store, must-revalidate
129
+ Facebook-Api-Version:
130
+ - v2.7
131
+ Expires:
132
+ - Sat, 01 Jan 2000 00:00:00 GMT
133
+ Content-Type:
134
+ - text/javascript; charset=UTF-8
135
+ X-Fb-Trace-Id:
136
+ - CeJKdwfDcKG
137
+ X-Fb-Rev:
138
+ - '2654373'
139
+ Vary:
140
+ - Accept-Encoding
141
+ X-Fb-Debug:
142
+ - bND+vSntpGwMwBNkp4tYgQrDACRYLI8qI/IKmVX4iuC6SjaMtuFoyb6UsMLkI21NWYpd5GV0GjeUm1Qu1bB47g==
143
+ Date:
144
+ - Mon, 31 Oct 2016 11:36:33 GMT
145
+ Connection:
146
+ - close
147
+ body:
148
+ encoding: UTF-8
149
+ string: '{"id":"150352985174571","name":"Web Service Development \u0040 NTHU","feed":{"data":[{"name":"seriot.ch
150
+ - Parsing JSON is a Minefield \ud83d\udca3","message":"From the article: \"JSON
151
+ is not a data format you can rely on blindly [...] edge cases and maliciously
152
+ crafted payloads can cause bugs, crashes and denial of services, mainly because
153
+ JSON libraries rely on specifications that have evolved over time and that
154
+ left many details loosely specified or not specified at all.\" Long story
155
+ short: it seems XML will never die :D (actually, parsing XML is even worse...)","updated_time":"2016-10-28T02:09:39+0000","created_time":"2016-10-27T14:46:58+0000","id":"150352985174571_527664860776713","attachments":{"data":[{"title":"seriot.ch
156
+ - Parsing JSON is a Minefield \ud83d\udca3","description":"JSON is the de
157
+ facto standard when it comes to (un)serialising and exchanging data in web
158
+ and mobile programming. But how well do you really know JSON? We''ll read
159
+ the specifications and write test cases together. We''ll test common JSON
160
+ libraries against our test cases. I''ll show that JSON is not the...","url":"http:\/\/www.facebook.com\/l.php?u=http\u00253A\u00252F\u00252Fseriot.ch\u00252Fparsing_json.html&h=pAQGbdY1U&s=1&enc=AZOhZ_DoV8AZYnRVVBTklmcENxS7G53vn-lEU4ru_i3oXEgCxJnmbIOAWJvB-Gu3BWDU2GMBqx2nT6SzFh_zhGzU","media":{"image":{"height":720,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQBafep0D8nqgNS7&w=720&h=720&url=http\u00253A\u00252F\u00252Fseriot.ch\u00252Fjson\u00252Fpruned_results.png&cfs=1","width":720}}}]}},{"name":"GitHub
161
+ Dumps REST Calls for Facebook''s GraphQL - The New Stack","message":"Github''s
162
+ adoption of GraphQL for APIs, over RESTful services, might be the tipping
163
+ point that makes GraphQL ubiquitous. From what little exposure I have to it
164
+ (thanks to YenTing and Yen-Nan at Cardinal Blue), it seems we are taking the
165
+ complexity and burden of APIs away from API consumers, and putting it squarely
166
+ at the feet of API providers. That means using APIs is about to become significantly
167
+ easier (albeit more deeply nested) for everyone! But it also means that creating
168
+ APIs is about to become significantly harder. Read more about the big shift
169
+ at Github.","updated_time":"2016-10-20T08:29:06+0000","created_time":"2016-10-20T05:45:32+0000","id":"150352985174571_524070464469486","attachments":{"data":[{"title":"GitHub
170
+ Dumps REST Calls for Facebook''s GraphQL - The New Stack","description":"Hoping
171
+ to streamline the remote querying services of its site, GitHub is moving its
172
+ API (application programming interface) from REST calls to Facebook\u2019s
173
+ GraphQL API. In the company\u2019s recent user conference GitHub Universe,
174
+ Kyle Daigle, GitHub platform engineering manager, explained that the company...","url":"http:\/\/www.facebook.com\/l.php?u=http\u00253A\u00252F\u00252Fthenewstack.io\u00252Fgithub-dumps-rest-graphql-api\u00252F&h=5AQEXy6ZK&s=1&enc=AZP7SMCQUn4mPXq0u-5YrVbTOhpXUuU-7BEiY2T9VXvmMvx6DLVMgb7u7K0aQDR8WXQINoKi33_MKcXbrZe3T4tk","media":{"image":{"height":720,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQC5HLw3s46cLqn7&w=720&h=720&url=http\u00253A\u00252F\u00252Fthenewstack.io\u00252Fwp-content\u00252Fuploads\u00252F2016\u00252F09\u00252FGHU-GraphQL-Woah.jpg&cfs=1&sx=0&sy=0&sw=2448&sh=2448","width":720}}}]}},{"name":"Taking
175
+ PHP Seriously","message":"https:\/\/m.facebook.com\/story.php?story_fbid=1098448240203391&id=100001146751327","updated_time":"2016-10-13T18:17:23+0000","created_time":"2016-10-13T17:15:20+0000","id":"150352985174571_521137638096102","attachments":{"data":[{"title":"Taking
176
+ PHP Seriously","description":"by Keith Adams, Slack Engineering","url":"https:\/\/www.facebook.com\/l.php?u=https\u00253A\u00252F\u00252Fslack.engineering\u00252Ftaking-php-seriously-cf7a60065329\u002523.g3w9ecf66&h=5AQEXy6ZK&s=1&enc=AZOPuZs61zyxp-EAxBN3BJMYh36_YVKmxt02IWhV_f_uldh2ENrSMUA1imFjIGcuh_tDtSEmqzenhxGjzQYH1mK5","media":{"image":{"height":669,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQCmbxAdG46sLBUD&w=720&h=720&url=https\u00253A\u00252F\u00252Fd262ilb51hltx0.cloudfront.net\u00252Fmax\u00252F1200\u00252F1\u00252Ax5N8tfTVEmQro2ySxoZtvw.jpeg&cfs=1","width":669}}}]}},{"name":"How
177
+ To Save The Princess In 8 Programming Languages","updated_time":"2016-10-06T08:39:47+0000","created_time":"2016-10-06T08:28:40+0000","id":"150352985174571_518029841740215","attachments":{"data":[{"title":"How
178
+ To Save The Princess In 8 Programming Languages","description":"Programming
179
+ sucks. This fairytale comic shows the different ways in which programming
180
+ languages could fail you in the fantasy kingdom.","url":"https:\/\/www.facebook.com\/l.php?u=https\u00253A\u00252F\u00252Ftoggl.com\u00252Fprogramming-princess&h=yAQECYco_&s=1&enc=AZOrSP3Z5tmWrh10hw6WLxnqSBrUUe6GhApxOB6KFhM12_JwPOdXe6QzrPpUd_0q2zEV3OPa_u10ZWuF7whJrt8F","media":{"image":{"height":630,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQDEZQJwFjW82Fzm&w=720&h=720&url=https\u00253A\u00252F\u00252Ftoggl.com\u00252Fimages\u00252Fshare-img\u00252Ffb-share-git-princess.jpg&cfs=1","width":630}}}]}},{"name":"Guess
181
+ the Programming Language | Tutorialzine","message":"A little quiz to keep
182
+ you sharp on programming trends.","updated_time":"2016-10-06T06:51:44+0000","created_time":"2016-10-04T02:21:25+0000","id":"150352985174571_517105121832687","attachments":{"data":[{"title":"Guess
183
+ the Programming Language | Tutorialzine","description":"Can you tell Java
184
+ from JavaScript? Awesome! So you are ready to take our ultimate programming
185
+ challenge.","url":"http:\/\/www.facebook.com\/l.php?u=http\u00253A\u00252F\u00252Ftutorialzine.com\u00252F2014\u00252F06\u00252Fguess-the-programming-language\u00252F&h=NAQFG7_It&s=1&enc=AZP9HQ5mcmmfcwfFcEr5CoDl16o34wUhGiKl50GeDr7D2dSVFv3OG8Dkzab_o9qcSuL5JyhXYON4P1Oqmn-i21qP","media":{"image":{"height":490,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQB9saA-D40lNQqm&w=720&h=720&url=http\u00253A\u00252F\u00252Fcdn.tutorialzine.com\u00252Fwp-content\u00252Fuploads\u00252F2014\u00252F06\u00252Fguess-the-programming-language.jpg&cfs=1","width":490}}}]}},{"name":"How
186
+ it feels to learn JavaScript in 2016","updated_time":"2016-10-06T01:18:12+0000","created_time":"2016-10-05T13:47:43+0000","id":"150352985174571_517701838439682","attachments":{"data":[{"title":"How
187
+ it feels to learn JavaScript in 2016","description":"Edit: Thanks for pointing
188
+ typos and mistakes, I\u2019ll update the article as noted. Discussion in HackerNews
189
+ and Reddit.","url":"https:\/\/www.facebook.com\/l.php?u=https\u00253A\u00252F\u00252Fhackernoon.com\u00252Fhow-it-feels-to-learn-javascript-in-2016-d3a717dd577f\u002523.m0lkkfan1&h=-AQFaxps1&s=1&enc=AZOZpUPmyiTSwAY2laOzQuSKnTkTgsbfQ2qKwbavuXxu1Pc5zTci7eN9N617ApwnAFptH5HFAemnwYqyHOfwZkWD","media":{"image":{"height":720,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQBw5xIxnMhHtpnj&w=720&h=720&url=https\u00253A\u00252F\u00252Fcdn-images-2.medium.com\u00252Fmax\u00252F1200\u00252F1\u00252AraWO3dhM4jMjf9VY-kZzNg.png&cfs=1","width":720}}}]}},{"name":"5
190
+ emerging programming languages with a bright future","message":"Up and coming
191
+ languages worth keeping our eyes on. I''m already a huge fan of Crystal and
192
+ Rust, but the author has convinced me to pay more attention to Kotlin and
193
+ Elm.","updated_time":"2016-09-22T08:12:35+0000","created_time":"2016-09-21T10:13:58+0000","id":"150352985174571_511894255687107","attachments":{"data":[{"title":"5
194
+ emerging programming languages with a bright future","description":"Get the
195
+ elevator pitch for five of the most promising languages (some of them you
196
+ probably haven''t heard of before) that have the potential to grow...","url":"http:\/\/www.facebook.com\/l.php?u=http\u00253A\u00252F\u00252Ftechbeacon.com\u00252F5-emerging-programming-languages-bright-future\u00253Futm_content\u00253Dbuffer300a1\u002526utm_medium\u00253Dsocial\u002526utm_source\u00253Dtwitter.com\u002526utm_campaign\u00253Dbuffer&h=dAQFB3XXZ&s=1&enc=AZOBfNpM4UtkySbx0bWAnVmDzM9N1dQ9o2nIMMpjYKzTCmsK0PLlC9BIwtPPwb8KUsXwg9PZWArNndqUN2DQiX4g","media":{"image":{"height":480,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQAxbtCPHht3vWb6&w=720&h=720&url=http\u00253A\u00252F\u00252Ftechbeacon.com\u00252Fsites\u00252Fdefault\u00252Ffiles\u00252Fstyles\u00252Fsocial\u00252Fpublic\u00252Ffield\u00252Fimage\u00252F5_emerging_programming_languages_with_a_bright_future.jpg\u00253Fitok\u00253Dm0nlEinF&cfs=1","width":480}}}]}},{"name":"A
197
+ whole new Universe","message":"I can''t even wrap my head around all the new
198
+ features Github just released: code reviews, kanban boards, and much more.","updated_time":"2016-09-19T09:14:51+0000","created_time":"2016-09-15T03:42:48+0000","id":"150352985174571_509461352597064","attachments":{"data":[{"title":"A
199
+ whole new Universe","description":"Learn about the exciting features and announcements
200
+ revealed at this year\u2019s annual GitHub Universe conference at historic
201
+ Pier 70 in San Francisco.","url":"https:\/\/www.facebook.com\/l.php?u=https\u00253A\u00252F\u00252Fgithub.com\u00252Funiverse-2016&h=IAQHwFDmG&s=1&enc=AZNxDuwEVODTaUs6Do2WpBEGpRIOJymUaF5YfO69uS5q76v6eJWMVSylBnk9T5plhBflgibCmsV875OJuaDRtfW2","media":{"image":{"height":630,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQBsb70KV75vMJ8B&w=720&h=720&url=https\u00253A\u00252F\u00252Fassets-cdn.github.com\u00252Fimages\u00252Fmodules\u00252Funiverse-2016\u00252Funiverse-open-graph.png&cfs=1","width":630}}}]}},{"name":"Vert.x","message":"http:\/\/vertx.io\/","updated_time":"2016-09-13T20:34:39+0000","created_time":"2016-09-13T20:34:39+0000","id":"150352985174571_508953969314469","attachments":{"data":[{"title":"Vert.x","description":"Vert.x
202
+ is a tool-kit for building reactive applications on the JVM.","url":"http:\/\/www.facebook.com\/l.php?u=http\u00253A\u00252F\u00252Fvertx.io\u00252F&h=sAQFM4S68&s=1&enc=AZN4Iv2jN7Y0kZuKuQNprjSOv9OioIG94uFZSkhYcxPxqauoTOYZCxhuI6PzdbsNwMm1vH2MOhj13jMPAQn0bPib","media":{"image":{"height":360,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQC13D8UqDGMX5IF&w=720&h=720&url=http\u00253A\u00252F\u00252Fvertx.io\u00252Fassets\u00252Fuser_logos\u00252Fswisscom.png&cfs=1","width":360}}}]}},{"name":"Codecademy","updated_time":"2016-09-13T02:04:20+0000","created_time":"2016-09-13T02:04:20+0000","id":"150352985174571_508631766013356","attachments":{"data":[{"title":"Timeline
203
+ Photos","description":"Are you a Javascript guru? Then you should check out
204
+ our course in React.js!\n\nReact enables websites to display complex animations,
205
+ large volumes of data, or other memory-heavy tasks without slowing down. At
206
+ the end of the course, you\u2019ll know how to build sophisticated React applications.
207
+ Check it out!\n\nhttp:\/\/codecademy.io\/YRFS3047CDf","url":"https:\/\/www.facebook.com\/codecademy\/photos\/a.553205214692855.138303.272256069454439\/1387442691269099\/?type=3","media":{"image":{"height":377,"src":"https:\/\/scontent.xx.fbcdn.net\/v\/t1.0-9\/s720x720\/14264951_1387442691269099_7557697962736020966_n.png?oh=1c67604ccd5679d98c72100f943f3863&oe=5891713F","width":720}}}]}},{"name":"Scaling
208
+ Spinnaker at Netflix \u2014 The Basics","message":"https:\/\/medium.com\/\u0040ajordens\/scaling-spinnaker-at-netflix-part-1-8a5ae51ee6de#.fubo771g2","updated_time":"2016-09-11T09:14:53+0000","created_time":"2016-09-11T09:14:53+0000","id":"150352985174571_507894159420450","attachments":{"data":[{"title":"Scaling
209
+ Spinnaker at Netflix \u2014 The Basics","description":"The Backstory","url":"https:\/\/www.facebook.com\/l.php?u=https\u00253A\u00252F\u00252Fmedium.com\u00252F\u002540ajordens\u00252Fscaling-spinnaker-at-netflix-part-1-8a5ae51ee6de\u002523.fubo771g2&h=pAQGbdY1U&s=1&enc=AZMdr5SvBS9yxRKqZr-6VinF_uvE-TI3ci6lBT6EEUNGaKpwXEE5QJiVrWKcVWMNTCSS2GMMJkDyImxEw3Qryzc1","media":{"image":{"height":720,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQBS3PgL3uUEU1VC&w=720&h=720&url=https\u00253A\u00252F\u00252Fcdn-images-1.medium.com\u00252Fmax\u00252F1200\u00252F1\u00252AMrL6DHIxxY6CrL9Binpjjg.png&cfs=1","width":720}}}]}},{"name":"Design
210
+ Stamina Hypothesis","message":"Why (and when) we need architecture.","updated_time":"2016-09-08T03:33:06+0000","created_time":"2015-09-24T11:12:32+0000","id":"150352985174571_390601061149761","attachments":{"data":[{"title":"Design
211
+ Stamina Hypothesis","description":"The value of good software design is economic:
212
+ you can continue to add new functionality quickly even as the code-base grows
213
+ in size.","url":"http:\/\/www.facebook.com\/l.php?u=http\u00253A\u00252F\u00252Fmartinfowler.com\u00252Fbliki\u00252FDesignStaminaHypothesis.html&h=hAQEjWdH5&s=1&enc=AZPBRPGZ8n54geMOCiZlRvCnKbjF5yCxbP74wx8H18deII1uhZc_goBd-sPC9IR9WSJllfFUvdIh9FvE2ZpELnV6","media":{"image":{"height":329,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQB61p6nJsutcaQ4&w=720&h=720&url=http\u00253A\u00252F\u00252Fmartinfowler.com\u00252Fbliki\u00252Fimages\u00252FdesignStaminaGraph.gif&cfs=1","width":329}}}]}},{"name":"Git
214
+ 2.10 has been released","updated_time":"2016-09-03T06:33:51+0000","created_time":"2016-09-03T05:23:56+0000","id":"150352985174571_504539303089269","attachments":{"data":[{"title":"Git
215
+ 2.10 has been released","description":"The open source Git project has just
216
+ released Git 2.10.0, with features and bugfixes from over 70 contributors.
217
+ Here''s our look at some of the most interesting new features: Progress reporting
218
+ for...","url":"https:\/\/www.facebook.com\/l.php?u=https\u00253A\u00252F\u00252Fgithub.com\u00252Fblog\u00252F2242-git-2-10-has-been-released&h=dAQFB3XXZ&s=1&enc=AZOQouuSRO25XYW6K3kxpSaLQ0w1BYVGK6PXqm0MQAW5x-mcQ4knCPixp3POXCLCyGAtuk9a6_TonM9WQVEsI7-5","media":{"image":{"height":630,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQAMeAXoLqWgJ6YI&w=720&h=720&url=https\u00253A\u00252F\u00252Fcloud.githubusercontent.com\u00252Fassets\u00252F121322\u00252F16134794\u00252F284be2e6-33d4-11e6-9165-58068a872ec2.png&cfs=1","width":630}}}]}},{"name":"The
219
+ target=\"_blank\" vulnerability by example","message":"https:\/\/dev.to\/ben\/the-targetblank-vulnerability-by-example","updated_time":"2016-09-02T17:50:31+0000","created_time":"2016-09-01T12:49:45+0000","id":"150352985174571_503746883168511","attachments":{"data":[{"title":"The
220
+ target=\"_blank\" vulnerability by example","description":"Instagram leaves
221
+ its users open to a simple phishing attack","url":"https:\/\/www.facebook.com\/l.php?u=https\u00253A\u00252F\u00252Fdev.to\u00252Fben\u00252Fthe-targetblank-vulnerability-by-example&h=AAQFBgNq5&s=1&enc=AZOF9BILo6btwhKgaMMCeACe7TncZqjzLtl5rhxXLGg7HzhJW0YPsGbsWvuKlXrYXpONKkOOqNgHQ0wC-2woHECd","media":{"image":{"height":700,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQCuBI-PnC7cvAsc&w=720&h=720&url=https\u00253A\u00252F\u00252Fres.cloudinary.com\u00252Fpracticaldev\u00252Fimage\u00252Ffetch\u00252Fs--AGTf6Osi--\u00252Fc_imagga_scale\u00252Cf_auto\u00252Cfl_progressive\u00252Ch_700\u00252Cq_auto\u00252Cw_1480\u00252Fhttps\u00253A\u00252F\u00252Fi.vimeocdn.com\u00252Fvideo\u00252F570148251_1280x720.jpg&cfs=1","width":700}}}]}},{"name":"Katacoda
222
+ - Interactive Learning Platform for Software Engineers","message":"just discovered
223
+ this .... looks nice","updated_time":"2016-08-26T02:34:28+0000","created_time":"2016-08-26T02:34:28+0000","id":"150352985174571_500972406779292","attachments":{"data":[{"title":"Katacoda
224
+ - Interactive Learning Platform for Software Engineers","description":"Learn
225
+ the latest technologies with our hands-on labs","url":"https:\/\/www.facebook.com\/l.php?u=https\u00253A\u00252F\u00252Fwww.katacoda.com\u00252F&h=ZAQEZa7yF&s=1&enc=AZOjDRfERJ493aK44k3JuzYkj9f6Gw9ANO_K1Nxn4F2sozR4ahvy-mjFtbH5dsY5POdHNouHWhxB_jJKbBZme4BP","media":{"image":{"height":720,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQBt33FvO3-PQ4vI&w=720&h=720&url=https\u00253A\u00252F\u00252Fwww.katacoda.com\u00252Fimages\u00252Fbackgrounds\u00252Fpeople-working.jpg&cfs=1","width":720}}}]}},{"name":"Let''s
226
+ Encrypt - Wikipedia, the free encyclopedia","message":"No reason not to use
227
+ https for your web services: apart from the good old https:\/\/www.startssl.com,
228
+ now we have https:\/\/letsencrypt.org which makes getting, installing and
229
+ keeping a cert up to date easier. Plus its backed by many big guns and its
230
+ FREE! Here is the wikipedia article about it: https:\/\/en.m.wikipedia.org\/wiki\/Let\u002527s_Encrypt.
231
+ Just remember its pretty new and do read about how the certs are signed and
232
+ accepted by browser\/clients.","updated_time":"2016-08-22T00:55:29+0000","created_time":"2016-08-21T09:50:36+0000","id":"150352985174571_499005640309302","attachments":{"data":[{"title":"Let''s
233
+ Encrypt - Wikipedia, the free encyclopedia","description":"Let''s Encrypt
234
+ is a certificate authority that launched on April 12, 2016[1][2] that provides
235
+ free X.509 certificates for Transport Layer Security (TLS) encryption via
236
+ an automated process designed to eliminate the current complex process of
237
+ manual creation, validation, signing, installation, and ren...","url":"https:\/\/www.facebook.com\/l.php?u=https\u00253A\u00252F\u00252Fen.m.wikipedia.org\u00252Fwiki\u00252FLet\u00252527s_Encrypt&h=6AQH4hGaj&s=1&enc=AZNOOEWW4ZyzpwN2bxvv43OHUnLLLwDMK5OTlRaBWrQALmUwqVMLyTvKhpSI0H0-tPnX3Tx0e_NowHbRx1QeC_08","media":{"image":{"height":131,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQApCjwHGpTUJRSa&w=720&h=720&url=https\u00253A\u00252F\u00252Fupload.wikimedia.org\u00252Fwikipedia\u00252Fcommons\u00252Fthumb\u00252Fb\u00252Fbb\u00252FLetsencrypt_screenshot_2_domain_choice.png\u00252F220px-Letsencrypt_screenshot_2_domain_choice.png&cfs=1","width":131}}}]}},{"name":"Google''s
238
+ QUIC protocol: moving the web from TCP to UDP","message":"A speedier web?
239
+ Yes thank you!\n\n","updated_time":"2016-08-02T04:40:01+0000","created_time":"2016-08-01T13:53:37+0000","id":"150352985174571_491254161084450","attachments":{"data":[{"title":"Google''s
240
+ QUIC protocol: moving the web from TCP to UDP","description":"The QUIC protocol
241
+ (Quick UDP Internet Connections) is an entirely new protocol for the web developed
242
+ on top of UDP instead of TCP. Some are even (jokingly) calling it TCP\/2.
243
+ I only learned about QUIC a few weeks ago while doing the curl & libcurl episode
244
+ of the SysCast podcast. The really interestin...","url":"https:\/\/www.facebook.com\/l.php?u=https\u00253A\u00252F\u00252Fma.ttias.be\u00252Fgoogles-quic-protocol-moving-web-tcp-udp\u00252F&h=vAQGfGT4c&s=1&enc=AZPJrlg3YS3iKVvWZWUwT-YUh3CsfyPvg_YgQvTPa9T4qtHEm9j6PIXT6Nvwwgd7KHgamaKo1N_86KDHwYU4SMsb","media":{"image":{"height":720,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQAAP49rj-fnvioY&w=720&h=720&url=https\u00253A\u00252F\u00252Fma.ttias.be\u00252Fwp-content\u00252Fuploads\u00252F2016\u00252F07\u00252Fquic_parking_lot_problem.png&cfs=1","width":720}}}]}},{"name":"Introducing
245
+ GitKraken Pro\u2014launch fundraiser | Axosoft","message":"https:\/\/blog.axosoft.com\/2016\/07\/28\/introducing-gitkraken-pro\/","updated_time":"2016-07-30T17:51:41+0000","created_time":"2016-07-30T17:51:41+0000","id":"150352985174571_490544944488705","attachments":{"data":[{"title":"Introducing
246
+ GitKraken Pro\u2014launch fundraiser | Axosoft","description":"Learn about
247
+ the new edition of GitKraken, with even more features, and help raise money
248
+ and awareness for the Nightscout Foundation, an open source technology project
249
+ helping those affected by Type 1 diabetes!","url":"https:\/\/www.facebook.com\/l.php?u=https\u00253A\u00252F\u00252Fblog.axosoft.com\u00252F2016\u00252F07\u00252F28\u00252Fintroducing-gitkraken-pro\u00252F&h=dAQFB3XXZ&s=1&enc=AZOwunEYog8Fk1470qxi4Pj8ud_hJmUh_N7vZW_mjR0Wv-KIIy3iTHWG6eMlPsZpbBUKNt_hSjsTaOORu4K_k2qY","media":{"image":{"height":720,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQCiRe3ytesqyg6K&w=720&h=720&url=https\u00253A\u00252F\u00252Fblog.axosoft.com\u00252Fwp-content\u00252Fuploads\u00252F2016\u00252F07\u00252FTeaming-Up-v2-wide.png&cfs=1&l","width":720}}}]}},{"name":"Create
250
+ Apps with No Configuration | React","message":"For those using React, although
251
+ optional webpack loaders (such as sass) still need to be added!","updated_time":"2016-07-23T10:41:04+0000","created_time":"2016-07-23T09:55:25+0000","id":"150352985174571_487752758101257","attachments":{"data":[{"title":"Create
252
+ Apps with No Configuration | React","description":"A JavaScript library for
253
+ building user interfaces","url":"https:\/\/www.facebook.com\/l.php?u=https\u00253A\u00252F\u00252Ffacebook.github.io\u00252Freact\u00252Fblog\u00252F2016\u00252F07\u00252F22\u00252Fcreate-apps-with-no-configuration.html&h=zAQHHar3S&s=1&enc=AZMzd6n2Emq956imUxkM2P73QsA-jsr1j9-QrpxJYTjHYi1EXLTV7vtAXcGyiJQuUAwQBHhbvCz0RVSYuFvrg_M_","media":{"image":{"height":400,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQC26d6oRyFdqvxX&w=720&h=720&url=https\u00253A\u00252F\u00252Ffacebook.github.io\u00252Freact\u00252Fimg\u00252Flogo_og.png&cfs=1","width":400}}}]}},{"name":"introduction\u00b6
254
+ Lettuce is an extremely useful and charming tool for BDD (Behavior Driven...
255
+ -...","message":"Test scenarios that anyone can make sense of","updated_time":"2016-07-22T11:46:59+0000","created_time":"2016-07-22T06:28:02+0000","id":"150352985174571_487315358144997","attachments":{"data":[{"title":"introduction\u00b6
256
+ Lettuce is an extremely useful and charming tool for BDD (Behavior Driven...
257
+ -...","description":"Lettuce is an extremely useful and charming tool for
258
+ BDD (Behavior Driven Development). It can execute plain-text functional descriptions
259
+ as automated tests for Python projects, just as Cucumber does for Ruby.","url":"http:\/\/www.facebook.com\/l.php?u=http\u00253A\u00252F\u00252Flettuce.it\u00252Ftutorial\u00252Fsimple.html\u002523tutorial-simple&h=QAQHJzSDZ&s=1&enc=AZNXEe-FCkziOS4W3zMOMsPDlvRbqtWsZl8isTCHhydlF0iwFGSWk2gg2Iwl_YUO1vDYGIM2ddsT3W2q07mYD-Od","media":{"image":{"height":687,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQDL7gIjkOiwMbE7&w=720&h=720&url=http\u00253A\u00252F\u00252Flettuce.it\u00252F_images\u00252Fscreenshot5.png&cfs=1","width":687}}}]}},{"message":"Check
260
+ out: https:\/\/www.websequencediagrams.com \u2014 fun and friendly way to
261
+ create sequence diagrams for web and mobile activities. I usually end up drawing
262
+ these on paper or on the board. I think it will be quite engaging to play
263
+ with this live!","updated_time":"2016-07-21T02:25:49+0000","created_time":"2016-07-20T03:59:51+0000","id":"150352985174571_486566974886502","attachments":{"data":[{"description":"Check
264
+ out: https:\/\/www.websequencediagrams.com \u2014 fun and friendly way to
265
+ create sequence diagrams for web and mobile activities. I usually end up drawing
266
+ these on paper or on the board. I think it will be quite engaging to play
267
+ with this live!","url":"https:\/\/www.facebook.com\/photo.php?fbid=1058362510919499&set=gm.486566974886502&type=3","media":{"image":{"height":392,"src":"https:\/\/scontent.xx.fbcdn.net\/v\/t1.0-9\/s720x720\/13680904_1058362510919499_8542835077177246391_n.jpg?oh=e23aa643f32eb9665e3c8ba8a43c01ca&oe=58A0A9E7","width":720}}}]}},{"name":"Dropbox
268
+ open-sources Lepton, a compression algorithm that cuts JPEG file size by 22\u0025","message":"http:\/\/venturebeat.com\/2016\/07\/14\/dropbox-open-sources-lepton-a-compression-algorithm-that-cuts-jpeg-file-size-by-22\/","updated_time":"2016-07-15T05:52:51+0000","created_time":"2016-07-14T19:37:54+0000","id":"150352985174571_484513371758529","attachments":{"data":[{"title":"Dropbox
269
+ open-sources Lepton, a compression algorithm that cuts JPEG file size by 22\u0025","description":"Cloud
270
+ syncing and sharing software company Dropbox today announced that it has released
271
+ an image compression algorithm called Lepton under an Apache open-source license
272
+ on GitHub.","url":"http:\/\/www.facebook.com\/l.php?u=http\u00253A\u00252F\u00252Fventurebeat.com\u00252F2016\u00252F07\u00252F14\u00252Fdropbox-open-sources-lepton-a-compression-algorithm-that-cuts-jpeg-file-size-by-22\u00252F&h=JAQEPnFK0&s=1&enc=AZMjmVzr_G1gBKkY7nUuDz6AxY955tDBPQ4JEB35D2opKc0txgXlVfJngJYiHgqqtNQ7VimeUoNXbYHjNm8oXvBn","media":{"image":{"height":585,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQCBxul8ygkf06Je&w=720&h=720&url=https\u00253A\u00252F\u00252Fventurebeat.com\u00252Fwp-content\u00252Fuploads\u00252F2015\u00252F11\u00252FDropbox-Open-outside-Novet-780x585.jpg&cfs=1","width":585}}}]}},{"name":"Serverless
273
+ Architectures","message":"\"Serverless\" is the new sensation in service architecture,
274
+ and it integrates the recent trends of microservices and reactive (message-driven)
275
+ architectures. We will play with some of these concepts in our SOA class this
276
+ coming semester. Take a peek at what''s brewing.\nhttp:\/\/martinfowler.com\/articles\/serverless.html","updated_time":"2016-07-14T19:01:17+0000","created_time":"2016-07-14T12:16:33+0000","id":"150352985174571_484366188439914","attachments":{"data":[{"title":"Serverless
277
+ Architectures","description":"Serverless architectures replace a managed server
278
+ with a collection of third party services and FaaS","url":"http:\/\/www.facebook.com\/l.php?u=http\u00253A\u00252F\u00252Fmartinfowler.com\u00252Farticles\u00252Fserverless.html\u002523benefits&h=tAQFxOLUP&s=1&enc=AZOnodmObsKCua5Hgv0LB-cV9d94ECVdGjy7gm3yqARhHQqWT7Ojra2PH27QqIwjswS5aEk-CzEIvvUItmig30Mv","media":{"image":{"height":300,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQCGBUsGoj1TcRRD&w=720&h=720&url=http\u00253A\u00252F\u00252Fmartinfowler.com\u00252Farticles\u00252Fserverless\u00252Fsps.png&cfs=1","width":300}}}]}},{"name":"Pokemon
279
+ Go Is Driving Insane Amounts of Sales at Small Local Businesses. Here''s How
280
+ It Works","message":"I''m shocked at how Pok\u00e9mon Go is taking over our
281
+ streets (very soon in TW, right?). And now its having a major effect on local
282
+ businesses as well. Great example of how an online service can transform offline
283
+ ones.","updated_time":"2016-07-13T09:36:32+0000","created_time":"2016-07-13T02:42:08+0000","id":"150352985174571_483847351825131","attachments":{"data":[{"title":"Pokemon
284
+ Go Is Driving Insane Amounts of Sales at Small Local Businesses. Here''s How
285
+ It Works","description":"For $1.19 an hour, you can have more customers than
286
+ you''ve ever seen in your life","url":"http:\/\/www.facebook.com\/l.php?u=http\u00253A\u00252F\u00252Fwww.inc.com\u00252Fwalter-chen\u00252Fpok-mon-go-is-driving-insane-amounts-of-sales-at-small-local-businesses-here-s-h.html&h=0AQH76qxR&s=1&enc=AZPeGp9RV6xgmO8IJ7b6-l54PweT1SvXcMy-riyqyk7b8D_XJTeZB4ygHuSN3wvVARUuuAOegMhkKkup0KGeS94-","media":{"image":{"height":450,"src":"https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQCDr9LKzFIQfJFh&w=720&h=720&url=http\u00253A\u00252F\u00252Fwww.incimages.com\u00252Fuploaded_files\u00252Fimage\u00252F970x450\u00252FPokemon_Heroes_2003_03-cc_100058.jpg&cfs=1","width":450}}}]}},{"name":"SOA
287
+ Syllabus","message":"The syllabus for next semester''s \"Service Oriented
288
+ Architecture\" class is now online! Take a look and share it with your coder
289
+ friends who are dreaming of their first startup :)","updated_time":"2016-07-04T11:18:26+0000","created_time":"2016-07-04T06:48:44+0000","id":"150352985174571_480686308807902","attachments":{"data":[{"title":"SOA
290
+ Syllabus","description":"Institute of Service Science, National Tsing Hua
291
+ University\u000bService Oriented Architecture\u000bFall 2016 Course Duration:
292
+ Sep 2015 \u2013 Jan 2016\u000bClass Time: Mondays, 9:00am-12:00pm\u000b Instructor:
293
+ Soumya Ray (soumya.ray\u0040iss.nthu.edu.tw)\u000bAssistant: TBA (\u0040...
294
+ available on Slack) How do companies lik...","url":"http:\/\/www.facebook.com\/l.php?u=http\u00253A\u00252F\u00252Fbit.ly\u00252Fsoa-syllabus&h=BAQHN6LOh&s=1&enc=AZNGM5gYGMJrxsa388aIW6E8bK0oG-nn_SZUHKtOnATjOkd7hnXIZ_AAH7u4XMHeQP8FKRpOKGc6s1pUR8Tdypp3"}]}}],"paging":{"previous":"https:\/\/graph.facebook.com\/v2.7\/150352985174571\/feed?fields=name,message,updated_time,created_time,attachments\u00257Btitle,description,url,media\u00257D&since=1477620579&access_token=<ACCESS_TOKEN>&limit=25&__paging_token=enc_AdAchevYgL0m5xCIn76hqJ3aBASZBLnnBkHzYtokZBey5PDaQuxdVxZBDfJm2ifeekq5qoALQ6ZA4IMrAhmfWQ5dqvhVBMLvnbwrEWU90LoviZCxtZBgZDZD&__previous=1","next":"https:\/\/graph.facebook.com\/v2.7\/150352985174571\/feed?fields=name,message,updated_time,created_time,attachments\u00257Btitle,description,url,media\u00257D&access_token=<ACCESS_TOKEN>&limit=25&until=1467631106&__paging_token=enc_AdC4X4Wv1EBK4kEN9Y5TOPvPUz3HmgdUXTs7mZCGDzKM0JowQrOJOd0aQmt9j99Ih4aTyPdgZCtSjfotx3noc8yN9dZB40l6MStprBctRTbTZCOQzAZDZD"}}}'
295
+ http_version:
296
+ recorded_at: Mon, 31 Oct 2016 11:36:14 GMT
297
+ recorded_with: VCR 3.0.3
@@ -0,0 +1,22 @@
1
+ ---
2
+ group:
3
+ name: Web Service Development @ NTHU
4
+ privacy: OPEN
5
+ id: '150352985174571'
6
+ posting:
7
+ created_time: '2016-10-04T02:21:25+0000'
8
+ message: A little quiz to keep you sharp on programming trends.
9
+ id: '150352985174571_517105121832687'
10
+ attachment:
11
+ - description: Can you tell Java from JavaScript? Awesome! So you are ready to take
12
+ our ultimate programming challenge.
13
+ media:
14
+ image:
15
+ height: 490
16
+ src: https://external.xx.fbcdn.net/safe_image.php?d=AQB9saA-D40lNQqm&w=720&h=720&url=http%3A%2F%2Fcdn.tutorialzine.com%2Fwp-content%2Fuploads%2F2014%2F06%2Fguess-the-programming-language.jpg&cfs=1
17
+ width: 490
18
+ target:
19
+ url: http://www.facebook.com/l.php?u=http%3A%2F%2Ftutorialzine.com%2F2014%2F06%2Fguess-the-programming-language%2F&h=QAQFRGe1e&s=1&enc=AZN6y8VgJr9Ergk1McHtlVvCVfRfamxABJTgHWIsRMn-ol4YYMfoBf6AltqD5KJN4lP86EnrEGKSz-Ef6ROz3Lww
20
+ title: Guess the Programming Language | Tutorialzine
21
+ type: share
22
+ url: http://www.facebook.com/l.php?u=http%3A%2F%2Ftutorialzine.com%2F2014%2F06%2Fguess-the-programming-language%2F&h=QAQFRGe1e&s=1&enc=AZN6y8VgJr9Ergk1McHtlVvCVfRfamxABJTgHWIsRMn-ol4YYMfoBf6AltqD5KJN4lP86EnrEGKSz-Ef6ROz3Lww
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+
5
+ require 'yaml'
6
+ require 'minitest/autorun'
7
+ require 'minitest/rg'
8
+ require 'vcr'
9
+ require 'webmock'
10
+
11
+ require_relative '../lib/facegroups'
12
+
13
+ FIXTURES_FOLDER = 'spec/fixtures'
14
+ CASSETTES_FOLDER = "#{FIXTURES_FOLDER}/cassettes"
15
+ CASSETTE_FILE = 'facebook_api'
16
+
17
+ if File.file?('config/credentials.yml')
18
+ credentials = YAML.load(File.read('config/credentials.yml'))
19
+ ENV['FB_CLIENT_ID'] = credentials[:client_id]
20
+ ENV['FB_CLIENT_SECRET'] = credentials[:client_secret]
21
+ ENV['FB_ACCESS_TOKEN'] = credentials[:access_token]
22
+ ENV['FB_GROUP_ID'] = credentials[:group_id]
23
+ end
24
+
25
+ RESULT_FILE = "#{FIXTURES_FOLDER}/fb_api_results.yml"
26
+ FB_RESULT = YAML.load(File.read(RESULT_FILE))
metadata ADDED
@@ -0,0 +1,211 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: facegroups
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Aditya Utama Wijaya
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-10-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: http
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.9'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.9'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest-rg
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.2'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '11.3'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '11.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: vcr
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: webmock
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.1'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.1'
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.12'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.12'
111
+ - !ruby/object:Gem::Dependency
112
+ name: flog
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '4.4'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '4.4'
125
+ - !ruby/object:Gem::Dependency
126
+ name: flay
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '2.8'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '2.8'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubocop
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.42'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.42'
153
+ description: Extracts feed, postings, and attachments from FB groups
154
+ email:
155
+ - adityautamawijaya@gmail.com
156
+ executables:
157
+ - facegroups
158
+ extensions: []
159
+ extra_rdoc_files: []
160
+ files:
161
+ - ".gitignore"
162
+ - ".rubocop.yml"
163
+ - ".travis.yml"
164
+ - Gemfile
165
+ - Gemfile.lock
166
+ - LICENSE
167
+ - README.md
168
+ - Rakefile
169
+ - bin/facegroups
170
+ - config/credentials.yml.example
171
+ - facegroups.gemspec
172
+ - lib/facegroups.rb
173
+ - lib/facegroups/attachment.rb
174
+ - lib/facegroups/fb_api.rb
175
+ - lib/facegroups/feed.rb
176
+ - lib/facegroups/group.rb
177
+ - lib/facegroups/posting.rb
178
+ - lib/facegroups/version.rb
179
+ - spec/facegroups_spec.rb
180
+ - spec/fixtures/cassettes/facebook_api.yml
181
+ - spec/fixtures/fb_api_results.yml
182
+ - spec/spec_helper.rb
183
+ homepage: https://github.com/aditya-utama-wijaya/facegroups
184
+ licenses:
185
+ - MIT
186
+ metadata: {}
187
+ post_install_message:
188
+ rdoc_options: []
189
+ require_paths:
190
+ - lib
191
+ required_ruby_version: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
196
+ required_rubygems_version: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ version: '0'
201
+ requirements: []
202
+ rubyforge_project:
203
+ rubygems_version: 2.5.1
204
+ signing_key:
205
+ specification_version: 4
206
+ summary: Gets posted content from public Facebook groups
207
+ test_files:
208
+ - spec/facegroups_spec.rb
209
+ - spec/fixtures/cassettes/facebook_api.yml
210
+ - spec/fixtures/fb_api_results.yml
211
+ - spec/spec_helper.rb