aix-errlog 1.0.0 → 1.1.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/lib/aix/errlog/entry.rb +33 -3
- data/lib/aix/errlog/errlog.rb +43 -140
- data/lib/aix/errlog/match.rb +133 -8
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e5294c01b19b7bd0a1977c511df790d5d002c34fa968c4c1ccc432d927f7406a
|
4
|
+
data.tar.gz: a7e9fe17605da84b4f4c0cc694c99886a3690859cbf52a37854a045e151a6e0f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee963b63a3877ca69c5e180e7f20613ac41c0a9ba424cdda648e1ba9aefb089b4280d8b7212081ea9e74dfe3f792a7edd7bbd82dd2d7cfc80f69d46e5953c286
|
7
|
+
data.tar.gz: 6d34ac53693e129524de2ddeac04559e1ed8a33d0cc0c12b80090977e95316bf8d54b04e9e229fbdcb5c2541be7404c2f83dca0bf671ed141124042efba29eab
|
data/lib/aix/errlog/entry.rb
CHANGED
@@ -4,14 +4,21 @@ require 'aix/errlog/constants'
|
|
4
4
|
|
5
5
|
module AIX
|
6
6
|
module Errlog
|
7
|
+
PARSE_REGEX = /(?:^Detail Data$\n(.*?))?(?:^Symptom Data$\n(.*))?\z/m.freeze
|
8
|
+
|
7
9
|
##
|
8
10
|
# An errlog entry class. Used to parse the raw errlog_entry_t struct into a
|
9
11
|
# more useful Ruby object.
|
10
12
|
#
|
11
13
|
# You shouldn't need to invoke this class directly; it is generated by the
|
12
14
|
# Errlog#forward_each and Errlog#reverse_each.
|
15
|
+
#
|
16
|
+
# Unfortunately, the retreived detail and symptom fields aren't horribly
|
17
|
+
# useful, and IBM has presented no API for parsing these correctly, so the
|
18
|
+
# only canonical path to getting the correct detail and symptom data is
|
19
|
+
# through a call to the errpt command.
|
13
20
|
class Entry
|
14
|
-
attr_reader :magic, :sequence, :label, :timestamp, :crcid, :errdiag, :machineid, :nodeid, :class, :type, :resource, :rclass, :rtype, :vpd_ibm, :vpd_user, :in, :connwhere, :flags, :
|
21
|
+
attr_reader :magic, :sequence, :label, :timestamp, :crcid, :errdiag, :machineid, :nodeid, :class, :type, :resource, :rclass, :rtype, :vpd_ibm, :vpd_user, :in, :connwhere, :flags, :raw_detail, :raw_symptom, :dup_count, :dup_time1, :dup_time2, :wparid
|
15
22
|
|
16
23
|
def initialize(raw)
|
17
24
|
@magic = raw[:el_magic]
|
@@ -33,14 +40,37 @@ module AIX
|
|
33
40
|
@connwhere = raw[:el_connwhere].to_s.freeze
|
34
41
|
@flags = raw[:el_flags]
|
35
42
|
length = raw[:el_detail_length]
|
36
|
-
@
|
43
|
+
@raw_detail = raw[:el_detail_data].to_ptr.get_bytes(0, length).freeze
|
37
44
|
length = raw[:el_symptom_length]
|
38
|
-
@
|
45
|
+
@raw_symptom = raw[:el_symptom_data].to_ptr.get_bytes(0, length).freeze
|
39
46
|
@dup_count = raw[:el_errdup][:ed_dupcount]
|
40
47
|
@dup_time1 = Time.at(raw[:el_errdup][:ed_time1]).freeze
|
41
48
|
@dup_time2 = Time.at(raw[:el_errdup][:ed_time2]).freeze
|
42
49
|
@wparid = raw[:el_wparid].to_s.freeze
|
43
50
|
end
|
51
|
+
|
52
|
+
def errpt
|
53
|
+
@errpt ||= %x(errpt -al#{@sequence}).freeze
|
54
|
+
end
|
55
|
+
|
56
|
+
def parse_errpt
|
57
|
+
unless @parsed
|
58
|
+
@detail, @symptom = errpt.match(PARSE_REGEX).captures
|
59
|
+
@detail ||= ''.freeze
|
60
|
+
@symptom ||= ''.freeze
|
61
|
+
@detail.freeze
|
62
|
+
@symptom.freeze
|
63
|
+
@parsed = true
|
64
|
+
end
|
65
|
+
end
|
66
|
+
def detail
|
67
|
+
parse_errpt unless @parsed
|
68
|
+
@detail
|
69
|
+
end
|
70
|
+
def symptom
|
71
|
+
parse_errpt unless @parsed
|
72
|
+
@symptom
|
73
|
+
end
|
44
74
|
end
|
45
75
|
end
|
46
76
|
end
|
data/lib/aix/errlog/errlog.rb
CHANGED
@@ -30,11 +30,10 @@ module AIX
|
|
30
30
|
# operates as a cursor, so if you try to re-invoke one before it is
|
31
31
|
# finished, the cursor will get reset, and you'll get jumbled results).
|
32
32
|
# While one of these enumerators as active, trying to re-invoke one will
|
33
|
-
# raise an EnumeratorError.
|
33
|
+
# raise an Errors::EnumeratorError.
|
34
34
|
#
|
35
|
-
# If you need to do complex matching, use
|
36
|
-
#
|
37
|
-
# to how to create those.
|
35
|
+
# If you need to do complex matching, use #match or ::match to build a match
|
36
|
+
# expression using a DSL.
|
38
37
|
#
|
39
38
|
# A simple example, showing how to get a list of all labels of all log
|
40
39
|
# entries in forward order which contain the string 'KILL' in their label
|
@@ -47,19 +46,19 @@ module AIX
|
|
47
46
|
# require 'aix/errlog'
|
48
47
|
#
|
49
48
|
# AIX::Errlog.open do |log|
|
50
|
-
# log.forward_each(match:
|
51
|
-
#
|
49
|
+
# log.forward_each(match: log.match {
|
50
|
+
# label.include?('KILL') & (
|
52
51
|
# (
|
53
|
-
# (
|
54
|
-
# (
|
55
|
-
# (
|
52
|
+
# (sequence > 1000) &
|
53
|
+
# (timestamp >= DateTime.new(2017, 1, 1)) &
|
54
|
+
# (timestamp < DateTime.new(2017, 2, 1))
|
56
55
|
# ) | (
|
57
|
-
# (
|
58
|
-
# (
|
59
|
-
# (
|
56
|
+
# (sequence < 500) &
|
57
|
+
# (timestamp >= DateTime.new(2016, 12, 1)) &
|
58
|
+
# (timestamp < DateTime.new(2017, 1, 1))
|
60
59
|
# )
|
61
60
|
# )
|
62
|
-
# )
|
61
|
+
# }).map(&:label)
|
63
62
|
# end
|
64
63
|
#
|
65
64
|
# Certainly, that looks a little complex, but it is a bit more efficient
|
@@ -156,7 +155,7 @@ module AIX
|
|
156
155
|
# An active enumerator can not be nested within another active enumerator,
|
157
156
|
# including the block form of this. If you invoke any of the #each_
|
158
157
|
# methods while another has not finished and exited, you'll raise an
|
159
|
-
# EnumeratorError. You can create an enumerator of one within the other,
|
158
|
+
# Errors::EnumeratorError. You can create an enumerator of one within the other,
|
160
159
|
# as long as you don't activate it until the first one has exited.
|
161
160
|
#
|
162
161
|
# Warning: if the sequence does not exist (which is common when error logs
|
@@ -190,7 +189,7 @@ module AIX
|
|
190
189
|
# An active enumerator can not be nested within another active enumerator,
|
191
190
|
# including the block form of this. If you invoke any of the #each_
|
192
191
|
# methods while another has not finished and exited, you'll raise an
|
193
|
-
# EnumeratorError. You can create an enumerator of one within the other,
|
192
|
+
# Errors::EnumeratorError. You can create an enumerator of one within the other,
|
194
193
|
# as long as you don't activate it until the first one has exited.
|
195
194
|
#
|
196
195
|
# Warning: if the sequence does not exist (which is common when error logs
|
@@ -208,129 +207,33 @@ module AIX
|
|
208
207
|
end
|
209
208
|
|
210
209
|
##
|
211
|
-
#
|
212
|
-
|
213
|
-
|
214
|
-
Match.new(left: :sequence)
|
215
|
-
end
|
216
|
-
##
|
217
|
-
# Match convenience function. Gets a Leaf match for comparing against
|
218
|
-
# label.
|
219
|
-
def match_label
|
220
|
-
Match.new(left: :label)
|
221
|
-
end
|
222
|
-
##
|
223
|
-
# Match convenience function. Gets a Leaf match for comparing against
|
224
|
-
# timestamp.
|
225
|
-
def match_timestamp
|
226
|
-
Match.new(left: :timestamp)
|
227
|
-
end
|
228
|
-
##
|
229
|
-
# Match convenience function. Gets a Leaf match for comparing against
|
230
|
-
# crcid.
|
231
|
-
def match_crcid
|
232
|
-
Match.new(left: :crcid)
|
233
|
-
end
|
234
|
-
##
|
235
|
-
# Match convenience function. Gets a Leaf match for comparing against
|
236
|
-
# machineid.
|
237
|
-
def match_machineid
|
238
|
-
Match.new(left: :machineid)
|
239
|
-
end
|
240
|
-
##
|
241
|
-
# Match convenience function. Gets a Leaf match for comparing against
|
242
|
-
# nodeid.
|
243
|
-
def match_nodeid
|
244
|
-
Match.new(left: :nodeid)
|
245
|
-
end
|
246
|
-
##
|
247
|
-
# Match convenience function. Gets a Leaf match for comparing against
|
248
|
-
# class.
|
249
|
-
def match_class
|
250
|
-
Match.new(left: :class)
|
251
|
-
end
|
252
|
-
##
|
253
|
-
# Match convenience function. Gets a Leaf match for comparing against
|
254
|
-
# type.
|
255
|
-
def match_type
|
256
|
-
Match.new(left: :type)
|
257
|
-
end
|
258
|
-
##
|
259
|
-
# Match convenience function. Gets a Leaf match for comparing against
|
260
|
-
# resource.
|
261
|
-
def match_resource
|
262
|
-
Match.new(left: :resource)
|
263
|
-
end
|
264
|
-
##
|
265
|
-
# Match convenience function. Gets a Leaf match for comparing against
|
266
|
-
# rclass.
|
267
|
-
def match_rclass
|
268
|
-
Match.new(left: :rclass)
|
269
|
-
end
|
270
|
-
##
|
271
|
-
# Match convenience function. Gets a Leaf match for comparing against
|
272
|
-
# rtype.
|
273
|
-
def match_rtype
|
274
|
-
Match.new(left: :rtype)
|
275
|
-
end
|
276
|
-
##
|
277
|
-
# Match convenience function. Gets a Leaf match for comparing against
|
278
|
-
# vpd_ibm.
|
279
|
-
def match_vpd_ibm
|
280
|
-
Match.new(left: :vpd_ibm)
|
281
|
-
end
|
282
|
-
##
|
283
|
-
# Match convenience function. Gets a Leaf match for comparing against
|
284
|
-
# vpd_user.
|
285
|
-
def match_vpd_user
|
286
|
-
Match.new(left: :vpd_user)
|
287
|
-
end
|
288
|
-
##
|
289
|
-
# Match convenience function. Gets a Leaf match for comparing against in.
|
290
|
-
def match_in
|
291
|
-
Match.new(left: :in)
|
292
|
-
end
|
293
|
-
##
|
294
|
-
# Match convenience function. Gets a Leaf match for comparing against
|
295
|
-
# connwhere.
|
296
|
-
def match_connwhere
|
297
|
-
Match.new(left: :connwhere)
|
298
|
-
end
|
299
|
-
##
|
300
|
-
# Match convenience function. Gets a Leaf match for comparing against
|
301
|
-
# flag_err64.
|
302
|
-
def match_flag_err64
|
303
|
-
Match.new(left: :flag_err64)
|
304
|
-
end
|
305
|
-
##
|
306
|
-
# Match convenience function. Gets a Leaf match for comparing against
|
307
|
-
# flag_errdup.
|
308
|
-
def match_flag_errdup
|
309
|
-
Match.new(left: :flag_errdup)
|
310
|
-
end
|
311
|
-
##
|
312
|
-
# Match convenience function. Gets a Leaf match for comparing against
|
313
|
-
# detail_data.
|
314
|
-
def match_detail_data
|
315
|
-
Match.new(left: :detail_data)
|
316
|
-
end
|
317
|
-
##
|
318
|
-
# Match convenience function. Gets a Leaf match for comparing against
|
319
|
-
# symptom_data.
|
320
|
-
def match_symptom_data
|
321
|
-
Match.new(left: :symptom_data)
|
322
|
-
end
|
323
|
-
##
|
324
|
-
# Match convenience function. Gets a Leaf match for comparing against
|
325
|
-
# errdiag.
|
326
|
-
def match_errdiag
|
327
|
-
Match.new(left: :errdiag)
|
210
|
+
# Calls ::match
|
211
|
+
def match(&block)
|
212
|
+
Errlog.match(&block)
|
328
213
|
end
|
214
|
+
|
329
215
|
##
|
330
|
-
#
|
331
|
-
#
|
332
|
-
|
333
|
-
|
216
|
+
# Used to build a match expression using a DSL. This simply calls
|
217
|
+
# instance_eval on Match, so remember the semantics of block scope. If
|
218
|
+
# you have a local +sequence+ variable, for instance, you'll need to use
|
219
|
+
# an explicit self to escape that:
|
220
|
+
#
|
221
|
+
# [2] pry(main)> AIX::Errlog::Errlog.match { sequence }
|
222
|
+
# => #<AIX::Errlog::Match:0xeb32a4df @left=:sequence, @operator=nil, @right=nil>
|
223
|
+
# [3] pry(main)> sequence = 5
|
224
|
+
# => 5
|
225
|
+
# [4] pry(main)> AIX::Errlog::Errlog.match { sequence }
|
226
|
+
# => 5
|
227
|
+
# [5] pry(main)> AIX::Errlog::Errlog.match { self.sequence }
|
228
|
+
# => #<AIX::Errlog::Match:0xcb7d8c03 @left=:sequence, @operator=nil, @right=nil>
|
229
|
+
# [6] pry(main)> AIX::Errlog::Errlog.match { self.sequence > sequence }
|
230
|
+
# => #<AIX::Errlog::Match:0x7be0bbf5 @left=:sequence, @operator=:gt, @right=5>
|
231
|
+
#
|
232
|
+
# In any case, this function lets you use a block as a shortcut to call a
|
233
|
+
# bunch of public class methods on the Match class, in order to build
|
234
|
+
# complex match expressions, as shown in the summary of this class.
|
235
|
+
def self.match(&block)
|
236
|
+
Match.instance_eval(&block)
|
334
237
|
end
|
335
238
|
|
336
239
|
private
|
@@ -344,7 +247,7 @@ module AIX
|
|
344
247
|
return if status == :done
|
345
248
|
Errors.throw(status, "handle: #{@handle}, sequence: #{id}") unless status == :ok
|
346
249
|
|
347
|
-
Entry.new(entry)
|
250
|
+
Entry.new(entry)
|
348
251
|
end
|
349
252
|
|
350
253
|
##
|
@@ -356,7 +259,7 @@ module AIX
|
|
356
259
|
return if status == :done
|
357
260
|
Errors.throw(status, "handle: #{@handle}, match: #{match}") unless status == :ok
|
358
261
|
|
359
|
-
Entry.new(entry)
|
262
|
+
Entry.new(entry)
|
360
263
|
end
|
361
264
|
|
362
265
|
##
|
@@ -366,7 +269,7 @@ module AIX
|
|
366
269
|
status = Lib.errlog_find_next(@handle, entry)
|
367
270
|
return if status == :done
|
368
271
|
Errors.throw(status, "handle: #{@handle}") unless status == :ok
|
369
|
-
Entry.new(entry)
|
272
|
+
Entry.new(entry)
|
370
273
|
end
|
371
274
|
|
372
275
|
##
|
@@ -393,7 +296,7 @@ module AIX
|
|
393
296
|
# An active enumerator can not be nested within another active enumerator,
|
394
297
|
# including the block form of this. If you invoke any of the #each_
|
395
298
|
# methods while another has not finished and exited, you'll raise an
|
396
|
-
# EnumeratorError. You can create an enumerator of one within the other,
|
299
|
+
# Errors::EnumeratorError. You can create an enumerator of one within the other,
|
397
300
|
# as long as you don't activate it until the first one has exited.
|
398
301
|
#
|
399
302
|
# Warning: if the sequence does not exist (which is common when error logs
|
data/lib/aix/errlog/match.rb
CHANGED
@@ -9,8 +9,7 @@ module AIX
|
|
9
9
|
# A class that is useful for building errlog matchers.
|
10
10
|
#
|
11
11
|
# You usually won't need to access this class directly; you'll be able to
|
12
|
-
# create instances of it indirectly through the
|
13
|
-
# available in Errlog.
|
12
|
+
# create instances of it indirectly through the use of Errlog::match
|
14
13
|
#
|
15
14
|
# You can build field matchers using the methods on the errlog and standard
|
16
15
|
# logical operators, and there are standard conversions for certain things
|
@@ -18,18 +17,18 @@ module AIX
|
|
18
17
|
# entries only in January 2018 with +FOO+ in the label somewhere, you cold
|
19
18
|
# use a match like this with an Errlog instance.
|
20
19
|
#
|
21
|
-
#
|
22
|
-
# (
|
23
|
-
# (
|
24
|
-
#
|
25
|
-
#
|
20
|
+
# errlog.match {
|
21
|
+
# (timestamp >= DateTime.new(2018, 1, 1)) &
|
22
|
+
# (timestamp < DateTime.new(2018, 2, 1)) &
|
23
|
+
# label.include?('FOO')
|
24
|
+
# }
|
26
25
|
#
|
27
26
|
# It really is that easy. The rest of the magic is done for you behind the
|
28
27
|
# scenes, as long as you follow the rules and know how to make these matches
|
29
28
|
# in the C equivalent. Note that there must always be a Match on the left
|
30
29
|
# side of all comparisons, so something like
|
31
30
|
#
|
32
|
-
# DateTime.new(2018, 1, 1) <= errlog.
|
31
|
+
# DateTime.new(2018, 1, 1) <= errlog.match{timestamp}
|
33
32
|
#
|
34
33
|
# is not possible.
|
35
34
|
#
|
@@ -151,6 +150,132 @@ module AIX
|
|
151
150
|
operator: :not,
|
152
151
|
)
|
153
152
|
end
|
153
|
+
|
154
|
+
##
|
155
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
156
|
+
# sequence.
|
157
|
+
def self.sequence
|
158
|
+
new(left: :sequence)
|
159
|
+
end
|
160
|
+
##
|
161
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
162
|
+
# label.
|
163
|
+
def self.label
|
164
|
+
new(left: :label)
|
165
|
+
end
|
166
|
+
##
|
167
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
168
|
+
# timestamp.
|
169
|
+
def self.timestamp
|
170
|
+
new(left: :timestamp)
|
171
|
+
end
|
172
|
+
##
|
173
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
174
|
+
# crcid.
|
175
|
+
def self.crcid
|
176
|
+
new(left: :crcid)
|
177
|
+
end
|
178
|
+
##
|
179
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
180
|
+
# machineid.
|
181
|
+
def self.machineid
|
182
|
+
new(left: :machineid)
|
183
|
+
end
|
184
|
+
##
|
185
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
186
|
+
# nodeid.
|
187
|
+
def self.nodeid
|
188
|
+
new(left: :nodeid)
|
189
|
+
end
|
190
|
+
##
|
191
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
192
|
+
# class.
|
193
|
+
def self.class
|
194
|
+
new(left: :class)
|
195
|
+
end
|
196
|
+
##
|
197
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
198
|
+
# type.
|
199
|
+
def self.type
|
200
|
+
new(left: :type)
|
201
|
+
end
|
202
|
+
##
|
203
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
204
|
+
# resource.
|
205
|
+
def self.resource
|
206
|
+
new(left: :resource)
|
207
|
+
end
|
208
|
+
##
|
209
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
210
|
+
# rclass.
|
211
|
+
def self.rclass
|
212
|
+
new(left: :rclass)
|
213
|
+
end
|
214
|
+
##
|
215
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
216
|
+
# rtype.
|
217
|
+
def self.rtype
|
218
|
+
new(left: :rtype)
|
219
|
+
end
|
220
|
+
##
|
221
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
222
|
+
# vpd_ibm.
|
223
|
+
def self.vpd_ibm
|
224
|
+
new(left: :vpd_ibm)
|
225
|
+
end
|
226
|
+
##
|
227
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
228
|
+
# vpd_user.
|
229
|
+
def self.vpd_user
|
230
|
+
new(left: :vpd_user)
|
231
|
+
end
|
232
|
+
##
|
233
|
+
# Match convenience function. Gets a Leaf match for comparing against in.
|
234
|
+
def self.in
|
235
|
+
new(left: :in)
|
236
|
+
end
|
237
|
+
##
|
238
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
239
|
+
# connwhere.
|
240
|
+
def self.connwhere
|
241
|
+
new(left: :connwhere)
|
242
|
+
end
|
243
|
+
##
|
244
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
245
|
+
# flag_err64.
|
246
|
+
def self.flag_err64
|
247
|
+
new(left: :flag_err64)
|
248
|
+
end
|
249
|
+
##
|
250
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
251
|
+
# flag_errdup.
|
252
|
+
def self.flag_errdup
|
253
|
+
new(left: :flag_errdup)
|
254
|
+
end
|
255
|
+
##
|
256
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
257
|
+
# detail_data.
|
258
|
+
def self.detail_data
|
259
|
+
new(left: :detail_data)
|
260
|
+
end
|
261
|
+
##
|
262
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
263
|
+
# symptom_data.
|
264
|
+
def self.symptom_data
|
265
|
+
new(left: :symptom_data)
|
266
|
+
end
|
267
|
+
##
|
268
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
269
|
+
# errdiag.
|
270
|
+
def self.errdiag
|
271
|
+
new(left: :errdiag)
|
272
|
+
end
|
273
|
+
##
|
274
|
+
# Match convenience function. Gets a Leaf match for comparing against
|
275
|
+
# wparid.
|
276
|
+
def self.wparid
|
277
|
+
new(left: :wparid)
|
278
|
+
end
|
154
279
|
end
|
155
280
|
end
|
156
281
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aix-errlog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Taylor C. Richberger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-05-
|
11
|
+
date: 2018-05-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|