smess 1.0.4 → 1.0.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7bd97cb82c4e104f4878fd93026390b7f64e557d
4
- data.tar.gz: fb1c0c5c63933f965109182d2f6525359939b7e8
3
+ metadata.gz: bfda4dab3491c3d330309d126e50c9f57e39ba5c
4
+ data.tar.gz: c46314bbba0a491a7fa9b6b442cc3f5fc490cb0e
5
5
  SHA512:
6
- metadata.gz: a02d6af367b2b63838c692cb1e4bf9fc5d012d286de836e07d8c42b8f7d926f0aa8878f74204baaeef48a5149f5b5b586d289e01acfc269a57b69d548fc2f917
7
- data.tar.gz: 2a6bd99ef07c08ece8c04beea6ea65e0a820d422b6377e76f948ce22c76f9232fb34ef133eceead3ee62c11b5ac1286e0108fe75af9e8eb7fdd322830c5884b9
6
+ metadata.gz: 8812e709f447971d3e37395953749c6dbd4ed149426ef850f7a9b44d0a2262318fe835b6e26830890be578cb1c9ef1e9aec54711f762d8c759188c410fd5d802
7
+ data.tar.gz: 16336412133c3b916ef2de6bf3c92f76279e52d92674fc2c823a17060e11604bd523749c94c3ec066a1254510585a349965c023112bac9404673831e248bc443
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smess (1.0.3)
4
+ smess (1.0.4)
5
5
  activesupport (>= 3.0)
6
6
  clickatell
7
7
  httpi
@@ -21,7 +21,7 @@ GEM
21
21
  akami (1.2.0)
22
22
  gyoku (>= 0.4.0)
23
23
  nokogiri (>= 1.4.0)
24
- atomic (1.1.13)
24
+ atomic (1.1.14)
25
25
  builder (3.2.2)
26
26
  clickatell (0.8.2)
27
27
  diff-lcs (1.2.4)
@@ -63,12 +63,16 @@ GEM
63
63
  nokogiri (>= 1.4.0)
64
64
  nori (~> 1.1.0)
65
65
  wasabi (~> 2.5.0)
66
- thread_safe (0.1.2)
66
+ simplecov (0.7.1)
67
+ multi_json (~> 1.0)
68
+ simplecov-html (~> 0.7.1)
69
+ simplecov-html (0.7.1)
70
+ thread_safe (0.1.3)
67
71
  atomic
68
72
  treetop (1.4.15)
69
73
  polyglot
70
74
  polyglot (>= 0.3.1)
71
- twilio-ruby (3.10.1)
75
+ twilio-ruby (3.11.0)
72
76
  builder (>= 2.1.2)
73
77
  jwt (>= 0.1.2)
74
78
  multi_json (>= 1.3.0)
@@ -84,4 +88,5 @@ DEPENDENCIES
84
88
  dotenv
85
89
  jahtml_formatter
86
90
  rspec (>= 2.4.0)
91
+ simplecov
87
92
  smess!
@@ -15,6 +15,7 @@ require 'smess/outputs/http_base'
15
15
  require 'smess/outputs/auto'
16
16
  require 'smess/outputs/ipx'
17
17
  require 'smess/outputs/ipxus'
18
+ require 'smess/outputs/card_board_fish'
18
19
  require 'smess/outputs/clickatell'
19
20
  require 'smess/outputs/etisalatdemo'
20
21
  require 'smess/outputs/smsglobal'
@@ -29,8 +30,8 @@ require 'string'
29
30
  module Smess
30
31
 
31
32
  # Move to config?
32
- OUTPUTS = %w{auto clickatell etisalatdemo global_mouth iconectiv mblox ipxus smsglobal twilio}
33
- COUNTRY_CODES = [1, 20, 34, 46, 49, 966, 971]
33
+ OUTPUTS = %w{auto card_board_fish clickatell etisalatdemo global_mouth iconectiv mblox ipxus smsglobal twilio}
34
+ COUNTRY_CODES = [1, 20, 212, 34, 46, 49, 966, 971]
34
35
 
35
36
  def self.new(*args)
36
37
  Sms.new(*args)
@@ -60,4 +61,5 @@ HTTPI.adapter = :net_http
60
61
 
61
62
  # Setting config defaults
62
63
  # there is probably a better way and better place
64
+ # Unused and deprecated
63
65
  Smess.config.debug = Smess.booleanize(ENV["SMESS_DEBUG"])
@@ -24,6 +24,7 @@ module Smess
24
24
  "1869"=> :global_mouth,
25
25
  "1876"=> :global_mouth,
26
26
  "20" => :global_mouth,
27
+ "212" => :card_board_fish,
27
28
  "34" => :global_mouth,
28
29
  "46" => :global_mouth,
29
30
  "49" => :global_mouth,
@@ -14,7 +14,7 @@ module Smess
14
14
 
15
15
  def output_for(msisdn)
16
16
  out_class = get_output_name_for_msisdn msisdn
17
- ("Smess::#{out_class.to_s.camelize}").constantize.new(sms)
17
+ "Smess::#{out_class.to_s.camelize}".constantize.new(sms)
18
18
  end
19
19
 
20
20
  def deliver
@@ -0,0 +1,53 @@
1
+ module Smess
2
+ class CardBoardFish < HttpBase
3
+
4
+ def deliver
5
+ request.url = "#{url}?#{params.to_query}"
6
+ http_get request
7
+ end
8
+
9
+ private
10
+
11
+ def username
12
+ ENV["SMESS_CARD_BOARD_FISH_USER"]
13
+ end
14
+
15
+ def password
16
+ ENV["SMESS_CARD_BOARD_FISH_PASS"]
17
+ end
18
+
19
+ def sender_id
20
+ ENV["SMESS_SENDER_ID"]
21
+ end
22
+
23
+ def url
24
+ "https://sms2.cardboardfish.com:9444/HTTPSMS"
25
+ end
26
+
27
+ def params
28
+ @params ||= {
29
+ "S" => "H",
30
+ "UN" => username,
31
+ "P" => password,
32
+ "DA" => sms.to,
33
+ "M" => sms.message.strip_nongsm_chars.encode("ISO-8859-1"),
34
+ "SA" => from,
35
+ "ST" => 5
36
+ }
37
+ end
38
+
39
+ def normal_result(response)
40
+ response_code = response.code
41
+ response_code = "0" if response.code.to_s == "200"
42
+ # Successful response
43
+ {
44
+ message_id: message_id,
45
+ response_code: response_code.to_s,
46
+ response: {body: response.body},
47
+ destination_address: sms.to,
48
+ data: result_data
49
+ }
50
+ end
51
+
52
+ end
53
+ end
@@ -40,7 +40,7 @@ module Smess
40
40
  responses << rsp
41
41
  end
42
42
  result = normal_result(responses.first)
43
- rescue Exception => e
43
+ rescue => e
44
44
  # connection problem or some error
45
45
  result = result_for_error(e)
46
46
  end
@@ -31,7 +31,7 @@ module Smess
31
31
 
32
32
  begin
33
33
  mail.deliver
34
- rescue Exception => e
34
+ rescue => e
35
35
  result = {
36
36
  response_code: "-1",
37
37
  response: {text: "Email2sms: Delivery Error: #{e.inspect}"},
@@ -7,16 +7,7 @@ module Smess
7
7
  def deliver
8
8
  generate_mac_hash
9
9
  request.url = "#{url}?#{params.to_query}"
10
-
11
- begin
12
- response = HTTPI.get request
13
- result = normal_result(response)
14
- rescue Exception => e
15
- logger.warn response
16
- # connection problem or some error
17
- result = result_for_error(e)
18
- end
19
- result
10
+ http_get request
20
11
  end
21
12
 
22
13
  private
@@ -30,6 +30,22 @@ module Smess
30
30
  @request ||= HTTPI::Request.new
31
31
  end
32
32
 
33
+ def http_get(request)
34
+ http_request(:get, request)
35
+ end
36
+
37
+ def http_post(request)
38
+ http_request(:post, request)
39
+ end
40
+
41
+ def http_request(method, request)
42
+ response = HTTPI.send(method, request)
43
+ normal_result(response)
44
+ rescue => e
45
+ logger.warn response
46
+ result_for_error(e)
47
+ end
48
+
33
49
  def result_for_error(e)
34
50
  {
35
51
  response_code: '-1',
@@ -1,17 +1,10 @@
1
1
  module Smess
2
2
  class Iconectiv < Ipxus
3
3
 
4
- def account
5
- @account ||= {
6
- sms_url: 'http://66.70.32.42:32005/api/services2/SmsApi52?wsdl',
7
- shortcode: ENV["SMESS_ICONECTIV_SHORTCODE"],
8
- username: ENV["SMESS_ICONECTIV_USER"],
9
- password: ENV["SMESS_ICONECTIV_PASS"],
10
- account_name: ENV["SMESS_ICONECTIV_ACCOUNT_NAME"],
11
- service_name: ENV["SMESS_SERVICE_NAME"],
12
- service_meta_data_t_mobile_us: ENV["SMESS_ICONECTIV_SERVICE_META_DATA_T_MOBILE_US"],
13
- service_meta_data_verizon: ENV["SMESS_ICONECTIV_SERVICE_META_DATA_VERIZON"]
14
- }
4
+ private
5
+
6
+ def account_key_prefix
7
+ "ICONECTIV"
15
8
  end
16
9
 
17
10
  end
@@ -5,21 +5,10 @@ module Smess
5
5
  def initialize(sms)
6
6
  @sms = sms
7
7
  @results = []
8
- @endpoint = account[:sms_url]
8
+ @endpoint = sms_url
9
9
  @credentials = {
10
- name: account[:username],
11
- pass: account[:password]
12
- }
13
- end
14
-
15
- def account
16
- @account ||= {
17
- sms_url: 'http://europe.ipx.com/api/services2/SmsApi52?wsdl',
18
- shortcode: ENV["SMESS_IPX_SHORTCODE"],
19
- username: ENV["SMESS_IPX_USER"],
20
- password: ENV["SMESS_IPX_PASS"],
21
- account_name: ENV["SMESS_IPX_ACCOUNT_NAME"],
22
- service_name: ENV["SMESS_SERVICE_NAME"]
10
+ name: username,
11
+ pass: password
23
12
  }
24
13
  end
25
14
 
@@ -47,10 +36,50 @@ module Smess
47
36
  attr_reader :sms
48
37
  attr_accessor :results
49
38
 
39
+ def account_key_prefix
40
+ "IPX"
41
+ end
42
+
43
+ def account_key_for(key_part)
44
+ "SMESS_#{account_key_prefix}_#{key_part}"
45
+ end
46
+
47
+ def sms_url
48
+ ENV[ account_key_for("URL") ]
49
+ end
50
+
51
+ def shortcode
52
+ ENV[ account_key_for("SHORTCODE") ]
53
+ end
54
+
55
+ def username
56
+ ENV[ account_key_for("USER") ]
57
+ end
58
+
59
+ def password
60
+ ENV[ account_key_for("PASS") ]
61
+ end
62
+
63
+ def account_name
64
+ ENV[ account_key_for("ACCOUNT_NAME") ]
65
+ end
66
+
67
+ def service_name
68
+ ENV["SMESS_SERVICE_NAME"]
69
+ end
70
+
71
+ def service_meta_data_t_mobile_us
72
+ ENV[ account_key_for("SERVICE_META_DATA_T_MOBILE_US") ]
73
+ end
74
+
75
+ def service_meta_data_verizon
76
+ ENV[ account_key_for("SERVICE_META_DATA_VERIZON") ]
77
+ end
78
+
50
79
  def soap_body
51
80
  @soap_body ||= {
52
81
  "correlationId" => Time.now.strftime('%Y%m%d%H%M%S') + sms.to,
53
- "originatingAddress" => account[:shortcode],
82
+ "originatingAddress" => shortcode,
54
83
  "originatorTON" => "0",
55
84
  "destinationAddress" => sms.to,
56
85
  "userData" => "",
@@ -60,16 +89,16 @@ module Smess
60
89
  "relativeValidityTime" => "-1",
61
90
  "deliveryTime" => "#NULL#",
62
91
  "statusReportFlags" => "1", # 1
63
- "accountName" => account[:account_name],
92
+ "accountName" => account_name,
64
93
  "tariffClass" => "USD0", # needs to be extracted and variable per country
65
94
  "VAT" => "-1",
66
95
  "referenceId" => "#NULL#",
67
- "serviceName" => account[:service_name],
96
+ "serviceName" => service_name,
68
97
  "serviceCategory" => "#NULL#",
69
98
  "serviceMetaData" => "#NULL#",
70
99
  "campaignName" => "#NULL#",
71
- "username" => account[:username],
72
- "password" => account[:password]
100
+ "username" => username,
101
+ "password" => password
73
102
  }
74
103
  end
75
104
 
@@ -156,7 +185,7 @@ module Smess
156
185
  soap.body = soap_body_var
157
186
  end
158
187
  result = parse_sms_response(response)
159
- rescue Exception => e
188
+ rescue => e
160
189
  result = result_for_error(e)
161
190
  # LOG error here?
162
191
  end
@@ -1,19 +1,6 @@
1
1
  module Smess
2
2
  class Ipxus < Ipx
3
3
 
4
- def account
5
- @account ||= {
6
- sms_url: 'http://europe.ipx.com/api/services2/SmsApi52?wsdl',
7
- shortcode: ENV["SMESS_IPX_SHORTCODE"],
8
- username: ENV["SMESS_IPX_USER"],
9
- password: ENV["SMESS_IPX_PASS"],
10
- account_name: ENV["SMESS_IPX_ACCOUNT_NAME"],
11
- service_name: ENV["SMESS_SERVICE_NAME"],
12
- service_meta_data_t_mobile_us: ENV["SMESS_IPX_SERVICE_META_DATA_T_MOBILE_US"],
13
- service_meta_data_verizon: ENV["SMESS_IPX_SERVICE_META_DATA_VERIZON"]
14
- }
15
- end
16
-
17
4
  private
18
5
 
19
6
  def set_originator(originator)
@@ -25,7 +12,7 @@ module Smess
25
12
  def perform_operator_adaptation(msisdn)
26
13
  operator_data = lookup_operator msisdn
27
14
  unless operator_data[:operator].nil?
28
- method_name = "adapt_for_#{operator_data[:operator].to_underscore.gsub(" ","_")}"
15
+ method_name = "adapt_for_#{operator_data[:operator].smess_to_underscore.gsub(" ","_")}"
29
16
  send(method_name, msisdn) if respond_to?(:"#{method_name}", true)
30
17
  end
31
18
  end
@@ -41,8 +28,8 @@ module Smess
41
28
  "correlationId" => Time.now.strftime('%Y%m%d%H%M%S') + msisdn,
42
29
  "consumerId" => msisdn,
43
30
  "campaignName" => "#NULL#",
44
- "username" => account[:username],
45
- "password" => account[:password]
31
+ "username" => username,
32
+ "password" => password
46
33
  }
47
34
 
48
35
  begin
@@ -50,7 +37,7 @@ module Smess
50
37
  soap.body = body
51
38
  end
52
39
  result = parse_operator_response(response)
53
- rescue Exception => e
40
+ rescue => e
54
41
  result = result_for_error(e)
55
42
  ensure
56
43
  @endpoint = orig_endpoint
@@ -71,11 +58,11 @@ module Smess
71
58
 
72
59
 
73
60
  def adapt_for_verizon(msisdn)
74
- soap_body["serviceMetaData"] = account[:service_meta_data_verizon]
61
+ soap_body["serviceMetaData"] = service_meta_data_verizon
75
62
  end
76
63
 
77
64
  def adapt_for_t_mobile_us(msisdn)
78
- soap_body["serviceMetaData"] = account[:service_meta_data_t_mobile_us]
65
+ soap_body["serviceMetaData"] = service_meta_data_t_mobile_us
79
66
  end
80
67
 
81
68
  end
@@ -90,7 +90,7 @@ module Smess
90
90
  HTTPI.log_level = :debug
91
91
  response = HTTPI.post request
92
92
  result = normal_result(response)
93
- rescue Exception => e
93
+ rescue => e
94
94
  logger.warn response
95
95
  # connection problem or some error
96
96
  result = result_for_error(e)
@@ -8,15 +8,7 @@ module Smess
8
8
  request.url = url
9
9
  request.body = params
10
10
 
11
- begin
12
- response = HTTPI.post request
13
- result = normal_result(response)
14
- rescue Exception => e
15
- logger.warn response
16
- # connection problem or some error
17
- result = result_for_error(e)
18
- end
19
- result
11
+ http_post request
20
12
  end
21
13
 
22
14
  private
@@ -32,7 +32,7 @@ module Smess
32
32
  end
33
33
 
34
34
  def split_parts
35
- Smess.split_sms(sms.message.strip_nongsm_chars).reject {|s| s.empty? }
35
+ Smess.separate_sms(sms.message.strip_nongsm_chars).reject {|s| s.empty? }
36
36
  end
37
37
 
38
38
  def client
@@ -48,7 +48,7 @@ module Smess
48
48
  status_callback: ENV["SMESS_TWILIO_CALLBACK_URL"]
49
49
  })
50
50
  result = normal_result(response)
51
- rescue Exception => e
51
+ rescue => e
52
52
  result = result_for_error(e)
53
53
  end
54
54
  result
@@ -13,12 +13,12 @@ module Smess
13
13
 
14
14
  def deliver
15
15
  out_class = output
16
- out = ("Smess::#{out_class.to_s.camelize}").constantize.new(self)
16
+ out = "Smess::#{out_class.to_s.camelize}".constantize.new(self)
17
17
  results = out.deliver
18
18
  end
19
19
 
20
20
  def delivered?
21
- @results[:response_code] == "0" rescue false
21
+ results[:response_code] == "0"
22
22
  end
23
23
 
24
24
  end
@@ -3,51 +3,71 @@
3
3
  module Smess
4
4
  class << self
5
5
 
6
+ def booleanize(value)
7
+ value.to_s.downcase == "true"
8
+ end
9
+
6
10
  # returns an array of strings of gsm-compatible lengths
7
- # performance issue: utf8_safe_split also loops over the split point
8
11
  # this should be used when sending via concatenating providers
9
12
  def split_sms(text)
10
13
  return [text] unless text.sms_length > 160
11
-
12
14
  result = []
15
+
13
16
  while text.sms_length > 0
14
- end_char = 151
15
- part = ""
16
- while part.sms_length < 152 && part != text
17
- end_char = end_char + 1
18
- part = text.utf8_safe_split(end_char)[0] || ""
19
- end
17
+ part, text = text.split_at( split_point(text) )
20
18
  result << part
21
- text = text.utf8_safe_split(end_char)[1] || ""
22
19
  end
23
20
  result
24
21
  end
25
22
 
26
- # returns an array of strings of <160 char lengths
27
- # splits on whitespace and will mangle non-space whitespace
23
+ # it is not as simple as
24
+ #def split_sms(text)
25
+ # text = text.scan(/.{1,154}/m) if text.sms_length > SMS_MAX_LENGTH
26
+ # Array(text)
27
+ #end
28
+ # (which i forgot trying to please Code Climate)
29
+
30
+
31
+
32
+ # returns an array of strings of <160 char lengths, split on whitespace
28
33
  # this should be used when sending via non-concatenating providers
29
34
  def separate_sms(text)
30
- return [text] unless text.sms_length > 160
31
-
32
- end_char = 160
35
+ return [text] unless text.sms_length > SMS_MAX_LENGTH
33
36
  result = []
34
- while text.sms_length > end_char
35
- part = ""
36
- parts = text.utf8_safe_split(end_char)
37
- text = parts[1]
38
- splitpoint = end_char-parts[0].reverse.index(/[^\w-]+/)
39
- split = parts[0].utf8_safe_split(splitpoint)
40
- result << split[0].strip
41
- text = (split[1]+text).strip rescue text
37
+ while text.sms_length > SMS_MAX_LENGTH
38
+ part, text = text.split_at( separation_point(text) )
39
+ result << part.strip
42
40
  end
43
- result << text
41
+ result << text.strip
44
42
  end
45
43
 
44
+ private
46
45
 
47
- def booleanize(value)
48
- value.to_s.downcase == "true"
46
+ SMS_MAX_LENGTH = 160
47
+
48
+ # for finding the GSM alphabet split point for concatenated message strings
49
+ # The reason this is a bit qirky is that a subset of characters are "extended".
50
+ # These and take 2 bytes and the number of these in the message body alter the
51
+ # "byte" splitpoint.
52
+ def split_point(text)
53
+ end_char = 155
54
+ while text.sms_length > 154
55
+ end_char -= 1
56
+ text = text.split_at(end_char).first
57
+ # puts "split_point #{end_char}"
58
+ end
59
+ end_char
49
60
  end
50
61
 
62
+ # This is used when there is no concatenation and you want the string split on whitespace.
63
+ def separation_point(text)
64
+ end_char = SMS_MAX_LENGTH + 1
65
+ while text.sms_length > SMS_MAX_LENGTH || !(text[-1] =~ /\s/)
66
+ end_char -= 1
67
+ text = text.split_at(end_char).first
68
+ end
69
+ end_char
70
+ end
51
71
 
52
72
  end
53
73
  end
@@ -1,3 +1,3 @@
1
1
  module Smess
2
- VERSION = '1.0.4'
2
+ VERSION = '1.0.5'
3
3
  end
@@ -1,6 +1,6 @@
1
1
  # coding: UTF-8
2
2
  class String
3
- def to_underscore
3
+ def smess_to_underscore
4
4
  self.gsub(/::/, '/').
5
5
  gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
6
6
  gsub(/([a-z\d])([A-Z])/,'\1_\2').
@@ -9,23 +9,8 @@ class String
9
9
  end
10
10
 
11
11
 
12
- def valid_utf8?
13
- !!unpack("U") rescue false
14
- end
15
-
16
- def utf8_safe_split(n)
17
- if length <= n
18
- [self, nil]
19
- else
20
- before = self[0, n]
21
- after = self[n..-1]
22
- until after.valid_utf8?
23
- n = n - 1
24
- before = self[0, n]
25
- after = self[n..-1]
26
- end
27
- [before, after.empty? ? nil : after]
28
- end
12
+ def split_at(index)
13
+ [ self[0, index], self[index..-1] || "" ]
29
14
  end
30
15
 
31
16
  # like strlen but with SMS alphabet calculations
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smess
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Westin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-09-19 00:00:00.000000000 Z
11
+ date: 2013-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: 2.4.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: simplecov
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: jahtml_formatter
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -145,6 +159,7 @@ files:
145
159
  - lib/smess/country_code_registry.rb
146
160
  - lib/smess/logging.rb
147
161
  - lib/smess/outputs/auto.rb
162
+ - lib/smess/outputs/card_board_fish.rb
148
163
  - lib/smess/outputs/clickatell.rb
149
164
  - lib/smess/outputs/etisalatdemo.rb
150
165
  - lib/smess/outputs/global_mouth.rb
@@ -185,7 +200,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
185
200
  version: 1.3.7
186
201
  requirements: []
187
202
  rubyforge_project:
188
- rubygems_version: 2.0.2
203
+ rubygems_version: 2.1.9
189
204
  signing_key:
190
205
  specification_version: 4
191
206
  summary: A messy SMS messenger supporting every aggregator I have gotten my hands