facebook-messenger 0.11.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +56 -13
- data/lib/facebook/messenger/bot.rb +6 -35
- data/lib/facebook/messenger/bot/error_parser.rb +111 -0
- data/lib/facebook/messenger/bot/exceptions.rb +15 -0
- data/lib/facebook/messenger/error.rb +26 -0
- data/lib/facebook/messenger/incoming.rb +3 -1
- data/lib/facebook/messenger/incoming/common.rb +19 -1
- data/lib/facebook/messenger/incoming/postback.rb +7 -0
- data/lib/facebook/messenger/incoming/referral.rb +39 -0
- data/lib/facebook/messenger/subscriptions.rb +2 -2
- data/lib/facebook/messenger/thread.rb +2 -2
- data/lib/facebook/messenger/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e91c65dbe461f44e0516eab4311854cb1e346c67
|
4
|
+
data.tar.gz: 8986a3265e3c79aa89ee77476569d6a9a45aa652
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 03b239d5a2531fe9f11f483898a76b62c64cb24eb5ab3ae65230600c94485ac522e60526d8513be0718bfb85efc123b3e3c0a6bb0f479d7369783fc837822e7e
|
7
|
+
data.tar.gz: 4b22c9a53f9021b8725edb330fe48397b9bd51a571aa9bc85a5982eeef65902b064b171cbd6104848c32ff6d2c875aa823f4b4c51eda754e617d9c7e17e1b510
|
data/README.md
CHANGED
@@ -41,15 +41,14 @@ end
|
|
41
41
|
... or even send the human messages out of the blue:
|
42
42
|
|
43
43
|
```ruby
|
44
|
-
Bot.deliver(
|
44
|
+
Bot.deliver({
|
45
45
|
recipient: {
|
46
46
|
id: '45123'
|
47
47
|
},
|
48
48
|
message: {
|
49
49
|
text: 'Human?'
|
50
|
-
}
|
51
|
-
|
52
|
-
)
|
50
|
+
}
|
51
|
+
}, access_token: ENV['ACCESS_TOKEN'])
|
53
52
|
```
|
54
53
|
|
55
54
|
##### Messages with images
|
@@ -73,7 +72,7 @@ The human may appreciate hints:
|
|
73
72
|
|
74
73
|
```ruby
|
75
74
|
message.reply(
|
76
|
-
text: 'Human, who is your favorite bot?'
|
75
|
+
text: 'Human, who is your favorite bot?',
|
77
76
|
quick_replies: [
|
78
77
|
{
|
79
78
|
content_type: 'text',
|
@@ -126,7 +125,37 @@ end
|
|
126
125
|
Show the human you are preparing a message for them:
|
127
126
|
|
128
127
|
```ruby
|
129
|
-
message
|
128
|
+
Bot.on :message do |message|
|
129
|
+
message.typing_on
|
130
|
+
|
131
|
+
# Do something expensive
|
132
|
+
|
133
|
+
message.reply(text: 'Hello, human!')
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
Or that you changed your mind:
|
138
|
+
|
139
|
+
```ruby
|
140
|
+
Bot.on :message do |message|
|
141
|
+
message.typing_on
|
142
|
+
|
143
|
+
if # something
|
144
|
+
message.reply(text: 'Hello, human!')
|
145
|
+
else
|
146
|
+
message.typing_off
|
147
|
+
end
|
148
|
+
end
|
149
|
+
```
|
150
|
+
|
151
|
+
##### Mark as viewed
|
152
|
+
|
153
|
+
You can mark messages as seen to keep the human on their toes:
|
154
|
+
|
155
|
+
```ruby
|
156
|
+
Bot.on :message do |message|
|
157
|
+
message.mark_seen
|
158
|
+
end
|
130
159
|
```
|
131
160
|
|
132
161
|
#### Send to Facebook
|
@@ -161,24 +190,38 @@ Bot.on :delivery do |delivery|
|
|
161
190
|
end
|
162
191
|
```
|
163
192
|
|
193
|
+
#### Referral
|
194
|
+
|
195
|
+
When the human follows a m.me link with a ref parameter like http://m.me/mybot?ref=myparam,
|
196
|
+
you will receive a `referral` event.
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
Bot.on :referral do |referral|
|
200
|
+
referral.sender # => { 'id' => '1008372609250235' }
|
201
|
+
referral.recipient # => { 'id' => '2015573629214912' }
|
202
|
+
referral.sent_at # => 2016-04-22 21:30:36 +0200
|
203
|
+
referral.ref # => 'MYPARAM'
|
204
|
+
end
|
205
|
+
```
|
206
|
+
|
164
207
|
#### Change thread settings
|
165
208
|
|
166
209
|
You can greet new humans to entice them into talking to you:
|
167
210
|
|
168
211
|
```ruby
|
169
|
-
Facebook::Messenger::Thread.set(
|
212
|
+
Facebook::Messenger::Thread.set({
|
170
213
|
setting_type: 'greeting',
|
171
214
|
greeting: {
|
172
215
|
text: 'Welcome to your new bot overlord!'
|
173
|
-
}
|
174
|
-
)
|
216
|
+
},
|
217
|
+
}, access_token: ENV['ACCESS_TOKEN'])
|
175
218
|
```
|
176
219
|
|
177
220
|
You can define the action to trigger when new humans click on the Get
|
178
221
|
Started button. Before doing it you should check to select the messaging_postbacks field when setting up your webhook.
|
179
222
|
|
180
223
|
```ruby
|
181
|
-
Facebook::Messenger::Thread.set(
|
224
|
+
Facebook::Messenger::Thread.set({
|
182
225
|
setting_type: 'call_to_actions',
|
183
226
|
thread_state: 'new_thread',
|
184
227
|
call_to_actions: [
|
@@ -186,13 +229,13 @@ Facebook::Messenger::Thread.set(
|
|
186
229
|
payload: 'DEVELOPER_DEFINED_PAYLOAD_FOR_WELCOME'
|
187
230
|
}
|
188
231
|
]
|
189
|
-
)
|
232
|
+
}, access_token: ENV['ACCESS_TOKEN'])
|
190
233
|
```
|
191
234
|
|
192
235
|
You can show a persistent menu to humans.
|
193
236
|
|
194
237
|
```ruby
|
195
|
-
Facebook::Messenger::Thread.set(
|
238
|
+
Facebook::Messenger::Thread.set({
|
196
239
|
setting_type: 'call_to_actions',
|
197
240
|
thread_state: 'existing_thread',
|
198
241
|
call_to_actions: [
|
@@ -212,7 +255,7 @@ Facebook::Messenger::Thread.set(
|
|
212
255
|
url: 'http://example.com/'
|
213
256
|
}
|
214
257
|
]
|
215
|
-
)
|
258
|
+
}, access_token: ENV['ACCESS_TOKEN'])
|
216
259
|
```
|
217
260
|
|
218
261
|
## Configuration
|
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'facebook/messenger/bot/error_parser'
|
2
|
+
require 'facebook/messenger/bot/exceptions'
|
3
|
+
|
1
4
|
module Facebook
|
2
5
|
module Messenger
|
3
6
|
# The Bot module sends and receives messages.
|
@@ -7,7 +10,7 @@ module Facebook
|
|
7
10
|
base_uri 'https://graph.facebook.com/v2.6/me'
|
8
11
|
|
9
12
|
EVENTS = [:message, :delivery, :postback, :optin,
|
10
|
-
:read, :account_linking].freeze
|
13
|
+
:read, :account_linking, :referral].freeze
|
11
14
|
|
12
15
|
class << self
|
13
16
|
# Deliver a message with the given payload.
|
@@ -26,9 +29,9 @@ module Facebook
|
|
26
29
|
access_token: access_token
|
27
30
|
}
|
28
31
|
|
29
|
-
raise_errors_from(response)
|
32
|
+
Facebook::Messenger::Bot::ErrorParser.raise_errors_from(response)
|
30
33
|
|
31
|
-
response
|
34
|
+
response.body
|
32
35
|
end
|
33
36
|
|
34
37
|
# Register a hook for the given event.
|
@@ -66,34 +69,6 @@ module Facebook
|
|
66
69
|
$stderr.puts "Ignoring #{event} (no hook registered)"
|
67
70
|
end
|
68
71
|
|
69
|
-
# Raise any errors in the given response.
|
70
|
-
#
|
71
|
-
# response - A HTTParty::Response object.
|
72
|
-
#
|
73
|
-
# Returns nil if no errors were found, otherwises raises appropriately.
|
74
|
-
def raise_errors_from(response)
|
75
|
-
return unless response.key? 'error'
|
76
|
-
error = response['error']
|
77
|
-
|
78
|
-
raise(
|
79
|
-
error_class_from_error_code(error['code']),
|
80
|
-
(error['error_data'] || error['message'])
|
81
|
-
)
|
82
|
-
end
|
83
|
-
|
84
|
-
# Find the appropriate error class for the given error code.
|
85
|
-
#
|
86
|
-
# error_code - An Integer describing an error code.
|
87
|
-
#
|
88
|
-
# Returns an error class, or raises KeyError if none was found.
|
89
|
-
def error_class_from_error_code(error_code)
|
90
|
-
{
|
91
|
-
100 => RecipientNotFound,
|
92
|
-
10 => PermissionDenied,
|
93
|
-
2 => InternalError
|
94
|
-
}[error_code] || Facebook::Messenger::Error
|
95
|
-
end
|
96
|
-
|
97
72
|
# Return a Hash of hooks.
|
98
73
|
def hooks
|
99
74
|
@hooks ||= {}
|
@@ -113,10 +88,6 @@ module Facebook
|
|
113
88
|
)
|
114
89
|
end
|
115
90
|
end
|
116
|
-
|
117
|
-
class RecipientNotFound < Facebook::Messenger::Error; end
|
118
|
-
class PermissionDenied < Facebook::Messenger::Error; end
|
119
|
-
class InternalError < Facebook::Messenger::Error; end
|
120
91
|
end
|
121
92
|
end
|
122
93
|
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Facebook
|
2
|
+
module Messenger
|
3
|
+
module Bot
|
4
|
+
# Parses and raises Facebook response errors for the send API.
|
5
|
+
class ErrorParser
|
6
|
+
INTERNAL_ERROR_CODES = {
|
7
|
+
1200 => []
|
8
|
+
}.freeze
|
9
|
+
|
10
|
+
ACCESS_TOKEN_ERROR_CODES = {
|
11
|
+
190 => []
|
12
|
+
}.freeze
|
13
|
+
|
14
|
+
ACCOUNT_LINKING_ERROR_CODES = {
|
15
|
+
10_303 => []
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
LIMIT_ERROR_CODES = {
|
19
|
+
4 => [2_018_022],
|
20
|
+
100 => [2_018_109],
|
21
|
+
613 => [nil]
|
22
|
+
}.freeze
|
23
|
+
|
24
|
+
BAD_PARAMETER_ERROR_CODES = {
|
25
|
+
100 => [nil, 2_018_001]
|
26
|
+
}.freeze
|
27
|
+
|
28
|
+
PERMISSION_ERROR_CODES = {
|
29
|
+
10 => [2_018_065, 2_018_108],
|
30
|
+
200 => [1_545_041, 2_018_028, 2_018_027, 2_018_021],
|
31
|
+
230 => [nil]
|
32
|
+
}.freeze
|
33
|
+
|
34
|
+
class << self
|
35
|
+
# Raise any errors in the given response.
|
36
|
+
#
|
37
|
+
# response - A HTTParty::Response object.
|
38
|
+
#
|
39
|
+
# Returns nil if no errors were found, otherwises raises appropriately
|
40
|
+
def raise_errors_from(response)
|
41
|
+
return unless response.key? 'error'
|
42
|
+
|
43
|
+
error = response['error']
|
44
|
+
|
45
|
+
error_code = error['code']
|
46
|
+
error_subcode = error['error_subcode']
|
47
|
+
|
48
|
+
raise_code_only_error(error_code, error) if error_subcode.nil?
|
49
|
+
|
50
|
+
raise_code_subcode_error(error_code, error_subcode, error)
|
51
|
+
|
52
|
+
# Default to unidentified error
|
53
|
+
raise FacebookError, error
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def raise_code_only_error(error_code, args)
|
59
|
+
raise InternalError, args if internal_error?(error_code)
|
60
|
+
raise AccessTokenError, args if access_token_error?(error_code)
|
61
|
+
raise AccountLinkingError, args if account_linking_error?(
|
62
|
+
error_code
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def raise_code_subcode_error(error_code, error_subcode, args)
|
67
|
+
raise LimitError, args if limit_error?(error_code,
|
68
|
+
error_subcode)
|
69
|
+
raise BadParameterError, args if bad_parameter_error?(error_code,
|
70
|
+
error_subcode)
|
71
|
+
raise PermissionError, args if permission_error?(error_code,
|
72
|
+
error_subcode)
|
73
|
+
end
|
74
|
+
|
75
|
+
def internal_error?(error_code)
|
76
|
+
INTERNAL_ERROR_CODES.keys.include? error_code
|
77
|
+
end
|
78
|
+
|
79
|
+
def access_token_error?(error_code)
|
80
|
+
ACCESS_TOKEN_ERROR_CODES.keys.include? error_code
|
81
|
+
end
|
82
|
+
|
83
|
+
def account_linking_error?(error_code)
|
84
|
+
ACCOUNT_LINKING_ERROR_CODES.keys.include? error_code
|
85
|
+
end
|
86
|
+
|
87
|
+
def limit_error?(error_code, error_subcode)
|
88
|
+
limit_errors = LIMIT_ERROR_CODES[error_code]
|
89
|
+
return unless limit_errors
|
90
|
+
|
91
|
+
limit_errors.include? error_subcode
|
92
|
+
end
|
93
|
+
|
94
|
+
def bad_parameter_error?(error_code, error_subcode)
|
95
|
+
bad_parameter_errors = BAD_PARAMETER_ERROR_CODES[error_code]
|
96
|
+
return unless bad_parameter_errors
|
97
|
+
|
98
|
+
bad_parameter_errors.include? error_subcode
|
99
|
+
end
|
100
|
+
|
101
|
+
def permission_error?(error_code, error_subcode)
|
102
|
+
permission_errors = PERMISSION_ERROR_CODES[error_code]
|
103
|
+
return unless permission_errors
|
104
|
+
|
105
|
+
permission_errors.include? error_subcode
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Facebook
|
2
|
+
module Messenger
|
3
|
+
module Bot
|
4
|
+
# Base Facebook Messenger send API exception.
|
5
|
+
class SendError < Facebook::Messenger::FacebookError; end
|
6
|
+
|
7
|
+
class AccessTokenError < SendError; end
|
8
|
+
class AccountLinkingError < SendError; end
|
9
|
+
class BadParameterError < SendError; end
|
10
|
+
class InternalError < SendError; end
|
11
|
+
class LimitError < SendError; end
|
12
|
+
class PermissionError < SendError; end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,5 +1,31 @@
|
|
1
1
|
module Facebook
|
2
2
|
module Messenger
|
3
|
+
# Base Facebook Messenger exception.
|
3
4
|
class Error < StandardError; end
|
5
|
+
|
6
|
+
# Base error class for Facebook API errors.
|
7
|
+
class FacebookError < Error
|
8
|
+
attr_reader :message
|
9
|
+
attr_reader :type
|
10
|
+
attr_reader :code
|
11
|
+
attr_reader :subcode
|
12
|
+
attr_reader :user_title
|
13
|
+
attr_reader :user_msg
|
14
|
+
attr_reader :fbtrace_id
|
15
|
+
|
16
|
+
def initialize(error)
|
17
|
+
@message = error['message']
|
18
|
+
@type = error['type']
|
19
|
+
@code = error['code']
|
20
|
+
@subcode = error['error_subcode']
|
21
|
+
@user_title = error['error_user_title']
|
22
|
+
@user_msg = error['error_user_msg']
|
23
|
+
@fbtrace_id = error['fbtrace_id']
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
@message
|
28
|
+
end
|
29
|
+
end
|
4
30
|
end
|
5
31
|
end
|
@@ -5,6 +5,7 @@ require 'facebook/messenger/incoming/postback'
|
|
5
5
|
require 'facebook/messenger/incoming/optin'
|
6
6
|
require 'facebook/messenger/incoming/read'
|
7
7
|
require 'facebook/messenger/incoming/account_linking'
|
8
|
+
require 'facebook/messenger/incoming/referral'
|
8
9
|
|
9
10
|
module Facebook
|
10
11
|
module Messenger
|
@@ -17,7 +18,8 @@ module Facebook
|
|
17
18
|
'postback' => Postback,
|
18
19
|
'optin' => Optin,
|
19
20
|
'read' => Read,
|
20
|
-
'account_linking' => AccountLinking
|
21
|
+
'account_linking' => AccountLinking,
|
22
|
+
'referral' => Referral
|
21
23
|
}.freeze
|
22
24
|
|
23
25
|
# Parse the given payload.
|
@@ -21,7 +21,7 @@ module Facebook
|
|
21
21
|
Time.at(@messaging['timestamp'] / 1000)
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
24
|
+
def typing_on
|
25
25
|
payload = {
|
26
26
|
recipient: sender,
|
27
27
|
sender_action: 'typing_on'
|
@@ -30,6 +30,24 @@ module Facebook
|
|
30
30
|
Facebook::Messenger::Bot.deliver(payload, access_token: access_token)
|
31
31
|
end
|
32
32
|
|
33
|
+
def typing_off
|
34
|
+
payload = {
|
35
|
+
recipient: sender,
|
36
|
+
sender_action: 'typing_off'
|
37
|
+
}
|
38
|
+
|
39
|
+
Facebook::Messenger::Bot.deliver(payload, access_token: access_token)
|
40
|
+
end
|
41
|
+
|
42
|
+
def mark_seen
|
43
|
+
payload = {
|
44
|
+
recipient: sender,
|
45
|
+
sender_action: 'mark_seen'
|
46
|
+
}
|
47
|
+
|
48
|
+
Facebook::Messenger::Bot.deliver(payload, access_token: access_token)
|
49
|
+
end
|
50
|
+
|
33
51
|
def reply(message)
|
34
52
|
payload = {
|
35
53
|
recipient: sender,
|
@@ -8,6 +8,13 @@ module Facebook
|
|
8
8
|
def payload
|
9
9
|
@messaging['postback']['payload']
|
10
10
|
end
|
11
|
+
|
12
|
+
def referral
|
13
|
+
return if @messaging['postback']['referral'].nil?
|
14
|
+
@referral ||= Referral::Referral.new(
|
15
|
+
@messaging['postback']['referral']
|
16
|
+
)
|
17
|
+
end
|
11
18
|
end
|
12
19
|
end
|
13
20
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Facebook
|
2
|
+
module Messenger
|
3
|
+
module Incoming
|
4
|
+
# The Referral class represents an incoming Facebook Messenger referral.
|
5
|
+
#
|
6
|
+
# https://developers.facebook.com/docs/messenger-platform/referral-params
|
7
|
+
class Referral
|
8
|
+
include Facebook::Messenger::Incoming::Common
|
9
|
+
|
10
|
+
# The referral portion of the payload.
|
11
|
+
class Referral
|
12
|
+
def initialize(referral)
|
13
|
+
@referral = referral
|
14
|
+
end
|
15
|
+
|
16
|
+
def ref
|
17
|
+
@referral['ref']
|
18
|
+
end
|
19
|
+
|
20
|
+
def source
|
21
|
+
@referral['source']
|
22
|
+
end
|
23
|
+
|
24
|
+
def type
|
25
|
+
@referral['type']
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def referral
|
30
|
+
@referral ||= Referral.new(@messaging['referral'])
|
31
|
+
end
|
32
|
+
|
33
|
+
def ref
|
34
|
+
referral.ref
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -33,10 +33,10 @@ module Facebook
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def raise_errors(response)
|
36
|
-
raise Error, response['error']
|
36
|
+
raise Error, response['error'] if response.key? 'error'
|
37
37
|
end
|
38
38
|
|
39
|
-
class Error < Facebook::Messenger::
|
39
|
+
class Error < Facebook::Messenger::FacebookError; end
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
@@ -35,7 +35,7 @@ module Facebook
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def raise_errors(response)
|
38
|
-
raise Error, response['error']
|
38
|
+
raise Error, response['error'] if response.key? 'error'
|
39
39
|
end
|
40
40
|
|
41
41
|
def default_options
|
@@ -46,7 +46,7 @@ module Facebook
|
|
46
46
|
)
|
47
47
|
end
|
48
48
|
|
49
|
-
class Error < Facebook::Messenger::
|
49
|
+
class Error < Facebook::Messenger::FacebookError; end
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: facebook-messenger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Johannes Gorset
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -168,6 +168,8 @@ files:
|
|
168
168
|
- bin/setup
|
169
169
|
- lib/facebook/messenger.rb
|
170
170
|
- lib/facebook/messenger/bot.rb
|
171
|
+
- lib/facebook/messenger/bot/error_parser.rb
|
172
|
+
- lib/facebook/messenger/bot/exceptions.rb
|
171
173
|
- lib/facebook/messenger/configuration.rb
|
172
174
|
- lib/facebook/messenger/configuration/providers.rb
|
173
175
|
- lib/facebook/messenger/configuration/providers/base.rb
|
@@ -181,6 +183,7 @@ files:
|
|
181
183
|
- lib/facebook/messenger/incoming/optin.rb
|
182
184
|
- lib/facebook/messenger/incoming/postback.rb
|
183
185
|
- lib/facebook/messenger/incoming/read.rb
|
186
|
+
- lib/facebook/messenger/incoming/referral.rb
|
184
187
|
- lib/facebook/messenger/server.rb
|
185
188
|
- lib/facebook/messenger/subscriptions.rb
|
186
189
|
- lib/facebook/messenger/thread.rb
|
@@ -205,7 +208,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
205
208
|
version: '0'
|
206
209
|
requirements: []
|
207
210
|
rubyforge_project:
|
208
|
-
rubygems_version: 2.
|
211
|
+
rubygems_version: 2.6.8
|
209
212
|
signing_key:
|
210
213
|
specification_version: 4
|
211
214
|
summary: Facebook Messenger client
|