contacts_txt 0.2.11 → 0.4.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
- checksums.yaml.gz.sig +0 -0
- data/lib/contacts_txt.rb +190 -56
- data.tar.gz.sig +0 -0
- metadata +32 -27
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bf478e02d22813b059b002369a94120ffa7db0c98e7ee02f7eb5a7604f000e36
|
|
4
|
+
data.tar.gz: 0e220217e01429b1b35c059df1e8459100ee4003a618c8634dcafd09ca30baeb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 71e031cd9bef37e5d93c634832d2ba450a17605cbbf5c088898a73b1678cb0c477bfce0eddfa60604c784805b3126bd8e1305ebc494e78927aea4024339e0752
|
|
7
|
+
data.tar.gz: 1d0686e575cd7242676541d2ad093a113c5ffd95666f56450d1139376d4d399ecd6c67e7b547f9118e02cc4f7e42620e93dd2752b550f445c43cab008d216a0c
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/lib/contacts_txt.rb
CHANGED
|
@@ -3,26 +3,27 @@
|
|
|
3
3
|
# file: contacts_txt.rb
|
|
4
4
|
|
|
5
5
|
require 'dynarex'
|
|
6
|
+
require 'rxfreadwrite'
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class ContactsTxt
|
|
9
|
-
include
|
|
10
|
+
include RXFReadWriteModule
|
|
10
11
|
|
|
11
12
|
attr_reader :to_s
|
|
12
|
-
|
|
13
|
-
def initialize(src=nil, fields: %w(role organisation mobile
|
|
14
|
-
sms email dob tags address notes note mobile2 ),
|
|
13
|
+
|
|
14
|
+
def initialize(src=nil, fields: %w(role organisation mobile
|
|
15
|
+
sms email dob tags address notes note mobile2 ),
|
|
15
16
|
username: nil, password: nil, debug: false)
|
|
16
|
-
|
|
17
|
+
|
|
17
18
|
@debug = debug
|
|
18
19
|
@fields = %w(fullname firstname lastname tel) | fields
|
|
19
20
|
|
|
20
21
|
txt, type = if src then
|
|
21
|
-
|
|
22
|
+
RXFReader.read(src, username: username, password: password)
|
|
22
23
|
else
|
|
23
24
|
['', :unknown]
|
|
24
25
|
end
|
|
25
|
-
|
|
26
|
+
|
|
26
27
|
case type
|
|
27
28
|
when :file
|
|
28
29
|
@path, @filename = File.dirname(src), File.basename(src)
|
|
@@ -33,94 +34,165 @@ class ContactsTxt
|
|
|
33
34
|
when :unknown
|
|
34
35
|
@path, @filename = '.', 'contacts.txt'
|
|
35
36
|
end
|
|
36
|
-
|
|
37
|
+
|
|
37
38
|
@dx = txt.lines.length > 1 ? import_to_dx(txt) : new_dx()
|
|
38
39
|
|
|
39
40
|
end
|
|
40
|
-
|
|
41
|
+
|
|
42
|
+
def all()
|
|
43
|
+
@dx.all
|
|
44
|
+
end
|
|
45
|
+
|
|
41
46
|
def dx()
|
|
42
47
|
@dx
|
|
43
48
|
end
|
|
44
|
-
|
|
49
|
+
|
|
45
50
|
def find_by_id(id)
|
|
46
|
-
|
|
51
|
+
|
|
47
52
|
@dx.find_by_id id
|
|
48
|
-
|
|
53
|
+
|
|
49
54
|
end
|
|
50
|
-
|
|
55
|
+
|
|
51
56
|
def find_by_mobile(raw_number, countrycode='44')
|
|
52
57
|
|
|
53
58
|
number = Regexp.new raw_number.sub(/^(?:0|#{countrycode})/,'').gsub(/[ -]*/,'')
|
|
54
|
-
|
|
55
|
-
@dx.all.find {|x| x.mobile.gsub(/[ -]*/,'') =~ number }
|
|
56
59
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
@dx.all.find {|x| x.mobile.gsub(/[ -]*/,'') =~ number }
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def find_by_name(s)
|
|
65
|
+
|
|
66
|
+
# Appending a hashtag to the name can help with finding the specific record
|
|
67
|
+
# e.g. 'Peter#plumber' or 'Peter #plumber'
|
|
68
|
+
|
|
69
|
+
raw_name, tag = s.split('#',2).map(&:strip)
|
|
60
70
|
|
|
61
71
|
name = Regexp.new "\b#{raw_name}\b|#{raw_name}", Regexp::IGNORECASE
|
|
62
72
|
puts 'name: ' + name.inspect if @debug
|
|
63
|
-
|
|
64
|
-
@dx.all.select do |x|
|
|
73
|
+
|
|
74
|
+
a = @dx.all.select do |x|
|
|
65
75
|
x.fullname =~ name or x.firstname =~ name or x.lastname =~ name
|
|
66
76
|
end
|
|
67
77
|
|
|
68
|
-
|
|
69
|
-
|
|
78
|
+
if tag then
|
|
79
|
+
a.find {|x| x.tags.split.map(&:downcase).include? tag.downcase }
|
|
80
|
+
else
|
|
81
|
+
a
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
end
|
|
85
|
+
|
|
70
86
|
def find_by_sms(raw_number, countrycode='44')
|
|
71
87
|
|
|
72
88
|
number = Regexp.new raw_number\
|
|
73
89
|
.sub(/^(?:0|#{countrycode})/,'').gsub(/[ -]*/,'')
|
|
74
|
-
|
|
90
|
+
|
|
75
91
|
@dx.all.find {|x| x.sms.gsub(/[ -]*/,'') =~ number \
|
|
76
|
-
or x.mobile.gsub(/[ -]*/,'') =~ number }
|
|
92
|
+
or x.mobile.gsub(/[ -]*/,'') =~ number }
|
|
77
93
|
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
# find using the tel, mobile, or mobile2 fields
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# find using the tel, mobile, or mobile2 fields
|
|
81
97
|
#
|
|
82
98
|
def find_by_telno(raw_number)
|
|
83
99
|
|
|
84
100
|
number = Regexp.new raw_number.gsub(/[ -]*/,'')
|
|
85
|
-
|
|
101
|
+
|
|
86
102
|
@dx.all.find do |x|
|
|
87
|
-
|
|
103
|
+
|
|
88
104
|
numbers = %i(tel mobile mobile2).map do |y|
|
|
89
105
|
x.method(y).call.gsub(/[ -]*/,'') if x.respond_to? y
|
|
90
106
|
end
|
|
91
|
-
|
|
107
|
+
|
|
92
108
|
puts 'numbers: ' + numbers.inspect if @debug
|
|
93
109
|
numbers.grep(number).any?
|
|
94
110
|
end
|
|
95
111
|
|
|
96
|
-
end
|
|
112
|
+
end
|
|
97
113
|
|
|
98
114
|
# returns a Dynarex object
|
|
99
|
-
#
|
|
115
|
+
#
|
|
100
116
|
def email_list()
|
|
101
117
|
@dx.filter {|x| x.email.length > 0}
|
|
102
118
|
end
|
|
103
|
-
|
|
119
|
+
|
|
104
120
|
def list_names()
|
|
105
|
-
|
|
121
|
+
|
|
106
122
|
@dx.all.inject([]) do |r, x|
|
|
107
123
|
x.fullname.length >= 1 ? r << x.fullname : r
|
|
108
124
|
end
|
|
109
125
|
|
|
110
126
|
end
|
|
111
|
-
|
|
127
|
+
|
|
112
128
|
def mobile_list()
|
|
113
129
|
@dx.filter {|x| x.mobile.length > 0}
|
|
114
|
-
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def multi_tel_index()
|
|
133
|
+
|
|
134
|
+
a = @dx.all.map do |x|
|
|
135
|
+
|
|
136
|
+
tel = %i(tel mobile mobile2).detect do |name|
|
|
137
|
+
!x.method(name).call.empty?
|
|
138
|
+
end
|
|
139
|
+
next unless tel
|
|
140
|
+
"%s %s" % [x.fullname, x.method(tel).call]
|
|
141
|
+
end.compact
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# group by first name
|
|
145
|
+
r = a.group_by {|x| x[0]}
|
|
146
|
+
|
|
147
|
+
a2 = a.clone
|
|
148
|
+
|
|
149
|
+
# group by last name
|
|
150
|
+
r2 = a.group_by {|x| x.split(/ /,2).last[0]}
|
|
151
|
+
c = r2.merge(r)
|
|
152
|
+
|
|
153
|
+
c.each do |k, v|
|
|
154
|
+
|
|
155
|
+
puts "k: %s v: %s" % [k, v]
|
|
156
|
+
v.concat(r2[k]) if r2[k]
|
|
157
|
+
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
h = c.sort.each {|k,v| v.uniq!}.to_h
|
|
161
|
+
|
|
162
|
+
out = []
|
|
163
|
+
|
|
164
|
+
h.each do |k,v|
|
|
165
|
+
|
|
166
|
+
out << ' ' + (' ' * 30) + k
|
|
167
|
+
|
|
168
|
+
v.each do |x|
|
|
169
|
+
|
|
170
|
+
name, phone = x.split(/(?=\d)/,2)
|
|
171
|
+
out << "\n" + (name.length >= 29 ? name[0..26] + '...' : name)
|
|
172
|
+
tel = (' ' + ' ' * (26 - phone.length)) + 't: ' + phone
|
|
173
|
+
out << tel + "\n"
|
|
174
|
+
out << ('-' * 30)
|
|
175
|
+
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
puts out.join("\n")
|
|
181
|
+
|
|
182
|
+
end
|
|
115
183
|
|
|
116
184
|
def save(filename=@filename)
|
|
117
|
-
|
|
185
|
+
|
|
118
186
|
s = dx_to_s(@dx)
|
|
119
187
|
FileX.write File.join(@path, filename), s
|
|
120
188
|
@dx.save File.join(@path, filename.sub(/\.txt$/,'.xml'))
|
|
121
|
-
|
|
189
|
+
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def to_dx()
|
|
193
|
+
@dx
|
|
122
194
|
end
|
|
123
|
-
|
|
195
|
+
|
|
124
196
|
def to_s()
|
|
125
197
|
dx_to_s @dx
|
|
126
198
|
end
|
|
@@ -128,9 +200,9 @@ class ContactsTxt
|
|
|
128
200
|
private
|
|
129
201
|
|
|
130
202
|
def dx_to_s(dx)
|
|
131
|
-
|
|
203
|
+
|
|
132
204
|
rows = dx.all.map do |row|
|
|
133
|
-
|
|
205
|
+
|
|
134
206
|
h = row.to_h
|
|
135
207
|
|
|
136
208
|
fullname = h.delete :fullname
|
|
@@ -140,11 +212,11 @@ class ContactsTxt
|
|
|
140
212
|
|
|
141
213
|
([fullname] + a.map {|x| x.join(': ') }).join("\n")
|
|
142
214
|
end
|
|
143
|
-
|
|
215
|
+
|
|
144
216
|
"<?contacts fields='%s'?>\n\n%s" % [@fields, rows.join("\n\n")]
|
|
145
|
-
|
|
217
|
+
|
|
146
218
|
end
|
|
147
|
-
|
|
219
|
+
|
|
148
220
|
def import_to_dx(raw_s)
|
|
149
221
|
|
|
150
222
|
s = if raw_s =~ /<?contacts / then
|
|
@@ -156,35 +228,97 @@ class ContactsTxt
|
|
|
156
228
|
found = s2[/(?<=#{keyword}=['"])[^'"]+/]
|
|
157
229
|
found ? r.merge(keyword.to_sym => found) : r
|
|
158
230
|
end
|
|
159
|
-
|
|
231
|
+
|
|
160
232
|
h = {
|
|
161
|
-
fields: @fields.join(', '),
|
|
162
|
-
}.merge attributes
|
|
233
|
+
fields: @fields.join(', '),
|
|
234
|
+
}.merge attributes
|
|
163
235
|
|
|
164
|
-
@fields = h[:fields].split(/ *, */)
|
|
236
|
+
@fields = h[:fields].split(/ *, */)
|
|
165
237
|
|
|
166
238
|
if h[:root] then
|
|
167
|
-
"\n\n" + h[:root] + "\n" +
|
|
239
|
+
"\n\n" + h[:root] + "\n" +
|
|
168
240
|
raw_contacts.strip.lines.map {|line| ' ' + line}.join
|
|
169
241
|
else
|
|
170
242
|
raw_contacts
|
|
171
243
|
end
|
|
172
|
-
|
|
244
|
+
|
|
173
245
|
else
|
|
174
|
-
|
|
246
|
+
|
|
175
247
|
raw_s.lstrip.lines[2..-1].join.strip
|
|
176
248
|
|
|
177
249
|
end
|
|
178
250
|
|
|
179
251
|
new_dx().import "--+\n" + s.split(/\s+(?=^[\w\s\(\)]+$)/)\
|
|
180
|
-
.map {|x| 'fullname: ' + x }.join("\n")
|
|
181
|
-
|
|
252
|
+
.map {|x| 'fullname: ' + x }.join("\n")
|
|
253
|
+
|
|
182
254
|
end
|
|
183
|
-
|
|
255
|
+
|
|
184
256
|
def new_dx()
|
|
185
|
-
|
|
257
|
+
|
|
186
258
|
Dynarex.new "contacts/contact(#{@fields.join ', '})"
|
|
187
|
-
|
|
259
|
+
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
class ContactsTxtAgent < ContactsTxt
|
|
265
|
+
|
|
266
|
+
def find_mobile_by_name(s)
|
|
267
|
+
|
|
268
|
+
result = find_by_name(s)
|
|
269
|
+
|
|
270
|
+
r = validate(result)
|
|
271
|
+
|
|
272
|
+
numbers = [r.sms.empty? ? r.mobile : r.sms, r.mobile].uniq\
|
|
273
|
+
.map {|x| x.sub(/\([^\)]+\)/,'').strip}
|
|
274
|
+
|
|
275
|
+
h = {}
|
|
276
|
+
h[:msg] = if numbers.length > 1 then
|
|
277
|
+
"The SMS number for %s is %s and the mobile number is %s" % \
|
|
278
|
+
[r.fullname, *numbers]
|
|
279
|
+
elsif numbers.first.length > 0 then
|
|
280
|
+
"The mobile number for %s is %s" % [r.fullname, numbers.first]
|
|
281
|
+
elsif r.tel.length > 0 then
|
|
282
|
+
"I don't have a mobile number, but the landline telephone " + \
|
|
283
|
+
"number for %s is %s" % [r.fullname, r.tel]
|
|
284
|
+
else
|
|
285
|
+
"I don't have a telephone number for " + r.fullname
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
h[:tags] = r.tags.to_s
|
|
289
|
+
h
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def find_tel_by_name(s)
|
|
293
|
+
|
|
294
|
+
result = find_by_name(s)
|
|
295
|
+
r = validate(result)
|
|
296
|
+
|
|
297
|
+
h = {}
|
|
298
|
+
|
|
299
|
+
if r.tel.empty? then
|
|
300
|
+
return find_mobile_by_name(s)
|
|
301
|
+
else
|
|
302
|
+
h[:msg] = "The telephone number for %s is %s" % [r.fullname, r.tel]
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
h[:tags] = r.tags.to_s
|
|
306
|
+
h
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
private
|
|
310
|
+
|
|
311
|
+
def validate(result)
|
|
312
|
+
|
|
313
|
+
case result.class.to_s
|
|
314
|
+
when 'RecordX'
|
|
315
|
+
result
|
|
316
|
+
when 'Array'
|
|
317
|
+
result.first
|
|
318
|
+
when 'NilClass'
|
|
319
|
+
return "I couldn't find that name."
|
|
320
|
+
end
|
|
321
|
+
|
|
188
322
|
end
|
|
189
323
|
|
|
190
324
|
end
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: contacts_txt
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- James Robertson
|
|
@@ -10,27 +10,32 @@ bindir: bin
|
|
|
10
10
|
cert_chain:
|
|
11
11
|
- |
|
|
12
12
|
-----BEGIN CERTIFICATE-----
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
13
|
+
MIIEXjCCAsagAwIBAgIBATANBgkqhkiG9w0BAQsFADAsMSowKAYDVQQDDCFnZW1t
|
|
14
|
+
YXN0ZXIvREM9amFtZXNyb2JlcnRzb24vREM9ZXUwHhcNMjIwMjIzMTk0ODIwWhcN
|
|
15
|
+
MjMwMjIzMTk0ODIwWjAsMSowKAYDVQQDDCFnZW1tYXN0ZXIvREM9amFtZXNyb2Jl
|
|
16
|
+
cnRzb24vREM9ZXUwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDlecEA
|
|
17
|
+
1V+ZCFfCwQwbOZ9S2Tn+ggDp85hVOoHZyfA+E6MMOShj1CE22RDfbyrAal+Z01C5
|
|
18
|
+
dol4wfM2s3x3QGwU/BhwoBs1el3beCkqEf86/bAfBMZ7TsxP8NcxeaQYxd4XUW52
|
|
19
|
+
f0UTA6EgM65L4F+K6vBWD76vjHwO6Z+hF9BrVVvifuT1jNykZ/PoDncs4nZaQKFP
|
|
20
|
+
yCtrrfjq9WOVG+ueHSm1+7rWqxBO2jH95Nlyfe2t2Q27gOz4hpcU6tyCGEb5Liz/
|
|
21
|
+
za+SUVNKbv8kxVBoQYYDMyHgZeS5YN1qlkxXSjSrUAIpp4eUHxaKMo6lTcXPXRPA
|
|
22
|
+
CezHTFC1cn276L80YXTj0Gw2Jp9On2AJXifKZ11nlOs+gBSS32r8UiqptAGe97Py
|
|
23
|
+
PotM+fYUjH7yunVnvsPIN+EC08vAhXCrMfFnvCuuyeSv8KKUFxmIeZE1Fn29MooE
|
|
24
|
+
Qd6QI6SJGWQ918Vj1NE4Lo/EKtgl5opL4cVPRzrH7yH82oyQiI/7NiemwrMCAwEA
|
|
25
|
+
AaOBijCBhzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUaABOt2ER
|
|
26
|
+
TZ9I1b5uj7HkRf+YVr4wJgYDVR0RBB8wHYEbZ2VtbWFzdGVyQGphbWVzcm9iZXJ0
|
|
27
|
+
c29uLmV1MCYGA1UdEgQfMB2BG2dlbW1hc3RlckBqYW1lc3JvYmVydHNvbi5ldTAN
|
|
28
|
+
BgkqhkiG9w0BAQsFAAOCAYEABS1c63h+vQL2hjWs7BvQM6vFxp1T4RDvviUqLUBt
|
|
29
|
+
YAg1/vWquUZ0PVi+Hf9gAaSumDjBb7qbbkn3Y2j/aV7wpG/yFtBoknIqihp7oH7/
|
|
30
|
+
wqGlntx9baORy7chaaBRA4CB4gGUFQ0wYHCBrHmj9zvfFWXnnRoFa06JIHm2DmOB
|
|
31
|
+
41DwQiiLflNj4iYbLzNQSI5X0iRu3H8zcAp45HJNF2LBrY32b8U+4Uf1w9QOJ4Io
|
|
32
|
+
bXdjMDxNnHEj2+V2yaq4J8v0o/xEE0Qv2TEeXyiv2fvIRz5VsS3ayYv+rHVmxGuo
|
|
33
|
+
VuXOnyLlTUjeB0IakaSYdBFWW3uno+fds/mIBL9VtmZzPJ4UhirVs0t4GvftJ2oT
|
|
34
|
+
weBCjBPmFwYPtn66vFgOaUHK421yIA2FC+AQO/pOOSgngHz0pm08NMpcTeTaufKu
|
|
35
|
+
x9gWyaB0gatLOaqUuwj8jCICpzNLo20JZQyEav2hZDxdB1EQjxq9jZrMaxwW3lF/
|
|
36
|
+
zHoZFKaw47O+Nd14HCqMVZUt
|
|
32
37
|
-----END CERTIFICATE-----
|
|
33
|
-
date:
|
|
38
|
+
date: 2022-02-23 00:00:00.000000000 Z
|
|
34
39
|
dependencies:
|
|
35
40
|
- !ruby/object:Gem::Dependency
|
|
36
41
|
name: dynarex
|
|
@@ -38,22 +43,22 @@ dependencies:
|
|
|
38
43
|
requirements:
|
|
39
44
|
- - "~>"
|
|
40
45
|
- !ruby/object:Gem::Version
|
|
41
|
-
version: '1.
|
|
46
|
+
version: '1.9'
|
|
42
47
|
- - ">="
|
|
43
48
|
- !ruby/object:Gem::Version
|
|
44
|
-
version: 1.
|
|
49
|
+
version: 1.9.6
|
|
45
50
|
type: :runtime
|
|
46
51
|
prerelease: false
|
|
47
52
|
version_requirements: !ruby/object:Gem::Requirement
|
|
48
53
|
requirements:
|
|
49
54
|
- - "~>"
|
|
50
55
|
- !ruby/object:Gem::Version
|
|
51
|
-
version: '1.
|
|
56
|
+
version: '1.9'
|
|
52
57
|
- - ">="
|
|
53
58
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: 1.
|
|
59
|
+
version: 1.9.6
|
|
55
60
|
description:
|
|
56
|
-
email:
|
|
61
|
+
email: digital.robertson@gmail.com
|
|
57
62
|
executables: []
|
|
58
63
|
extensions: []
|
|
59
64
|
extra_rdoc_files: []
|
|
@@ -78,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
78
83
|
- !ruby/object:Gem::Version
|
|
79
84
|
version: '0'
|
|
80
85
|
requirements: []
|
|
81
|
-
rubygems_version: 3.
|
|
86
|
+
rubygems_version: 3.2.22
|
|
82
87
|
signing_key:
|
|
83
88
|
specification_version: 4
|
|
84
89
|
summary: Reads a contacts.txt file
|
metadata.gz.sig
CHANGED
|
Binary file
|