my_gpsd_client 0.1.30

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
+ SHA256:
3
+ metadata.gz: ee600b4280ec136fb4493892c58b4bb008e33c1f8224ce20bbf1991ea534e469
4
+ data.tar.gz: 2b760c07a8cb3e090f2b4a2d53f11edbc3811425004e093e902913fdceeaba52
5
+ SHA512:
6
+ metadata.gz: 9596d2cd259de9f857a47124e0b171be2a3378cc73b47de6b22e00eee3bea431caf15af18e97d4ace0864808c0c73325604887e3426ca5315d1400dc2efac105
7
+ data.tar.gz: 731aea1ff46f96c1c60909c4cf41c02c45772b5bf458f7177129df18fc6ca17cb220a318d2fc9de3f8a7cc24fd019ea75427e211ebc3da16beca8d922244300f
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/Deploy.md ADDED
@@ -0,0 +1,4 @@
1
+ Procedure to build gem and push to rubygem.org
2
+ 1. Verify **lib/my_gpsd_client/version.rb** contains an updated version
3
+ 2. gem build my_gpsd_client.gemspec
4
+ 3. gem push my_gpsd_client-x.x.xx.gem
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in my_gpsd_client.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,20 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ my_gpsd_client (0.1.25)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ rake (10.5.0)
10
+
11
+ PLATFORMS
12
+ ruby
13
+
14
+ DEPENDENCIES
15
+ bundler (~> 1.17)
16
+ my_gpsd_client!
17
+ rake (~> 10.0)
18
+
19
+ BUNDLED WITH
20
+ 1.17.3
data/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # MyGpsdClient
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/my_gpsd_client`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'my_gpsd_client'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install my_gpsd_client
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+
34
+ ## To build, load and run a gem (from my notes)
35
+
36
+ From the gem's main folder...
37
+
38
+ $ gem build my_gpsd_client.gemspec
39
+ $ gem install my_gpsd_client-0.1.10.gem
40
+
41
+ $ irb
42
+ irb(main):001:0> require 'my_gpsd_client'
43
+ => true
44
+ irb(main):002:0> gps = MyGpsdClient.new()
45
+ => #<MyGpsdClient:0x00007fd8b98806a0...
46
+ irb(main):003:0> gps.version
47
+ => "0.1.17"
48
+ irb(main):004:0>
49
+
50
+ To release to rubygems.org...
51
+
52
+ $ rake build
53
+ my_gpsd_client 0.1.10 built to pkg/my_gpsd_client-0.1.0.gem.
54
+
55
+ $ rake release
56
+ my_gpsd_client 0.1.10 built to pkg/my_gpsd_client-0.1.0.gem.
57
+ Tagged v0.1.10.
58
+ Pushed git commits and tags.
59
+ Pushed my_gpsd_client 0.1.10 to https://rubygems.org
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "my_gpsd_client"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,3 @@
1
+ class MyGpsdClient_version
2
+ VERSION = "0.1.30"
3
+ end
@@ -0,0 +1,318 @@
1
+ require "my_gpsd_client/version"
2
+ require 'socket'
3
+ require 'json'
4
+ require 'date'
5
+
6
+ class MyGpsdClient
7
+ attr_accessor :host, :port, :watch, :verbose, :min_speed, :watchdog_max, :watchdog_force
8
+ attr_reader :version, :socket_ready, :msg_counts, :watchdog_fired_count
9
+
10
+ DEFAULT_WATCH = {"enable":true,"json":true,"nmea":false}
11
+
12
+ # A simple gpsd client that dump's json objects contianing all info received from the gpsd deamon
13
+ # you need to at least setup either the raw callback (on_raw_change) or position callback (on_position_change) to use GPSD2JSON. the raw callback just passes the json objects it received from the daemon on to the block you pass it. the on_position_change and on_satellites_change are a bit easier to use.
14
+ # @example Easy setup
15
+ # gps = GPSD2JSON.new()
16
+ # gps.on_satellites_change { |sats| STDERR.puts "found #{sats.length} satellites, of which #{sats.count{|sat| sat['used']} } active" }
17
+ # gps.on_position_change { |pos| STDERR.puts "lat: #{pos['lat']}, lng: #{pos['lon']}, alt: #{pos['alt']}, speed: #{pos['speed']} at #{pos['time']}, which is #{(Time.now - pos['time'].to_time) * 1000}ms old" }
18
+ # gps.start
19
+ # #when done
20
+ # gps.stop
21
+ # @example Quickest raw mode, just dumping all json packets as the are
22
+ # gps = GPSD2JSON.new()
23
+ # gps.on_raw_change { |raw| STDERR.puts raw.inspect }
24
+ # gps.start
25
+ # #when done
26
+ # gps.stop
27
+ def initialize(host: 'localhost', port: 2947, watch: DEFAULT_WATCH, verbose: false)
28
+ @version = MyGpsdClient_version::VERSION
29
+ @verbose = verbose
30
+ @socket = nil
31
+ @socket_ready = false
32
+ @host = host
33
+ @port = port
34
+ @watch = watch
35
+ @trackthread = nil
36
+ @socket_init_thread = nil
37
+ @watchdog_thread = nil
38
+ @watchdog_count = 0
39
+ @watchdog_max = 10
40
+ @watchdog_fired_count = 0
41
+ @watchdog_force = false
42
+ @min_speed = 0 # speed needs to be higher than this to make the gps info count
43
+ @last = nil #last gps info
44
+ @sats = nil # last satellites info
45
+ @sent_raw_callback = nil
46
+ @json_raw_callback = nil
47
+ @json_pos_callback = nil
48
+ @json_sat_callback = nil
49
+ @json_pps_callback = nil
50
+ @json_unk_callback = nil
51
+ @msg_counts = {wtch: 0, ver: 0, tpv: 0, sky: 0, gst: 0, att: 0,
52
+ toff: 0, pol: 0, pps: 0, dev: 0, devs: 0, err: 0,
53
+ unk: 0}
54
+ puts "Version: #{@version}" if @verbose
55
+ end
56
+
57
+ def on_raw_send(options:{}, &block)
58
+ @sent_raw_callback = block
59
+ end
60
+
61
+ # @param [Object] options Possible options to pass (not used yet)
62
+ # @param [Block] block Block to call when new json object comes from gpsd
63
+ def on_raw_change(options:{}, &block)
64
+ @json_raw_callback = block
65
+ end
66
+
67
+ # @param [Object] options Possible options to pass (not used yet)
68
+ # @param [Block] block Block to call when new gps position json object comes from gpsd
69
+ def on_position_change(options:{}, &block)
70
+ @json_pos_callback = block
71
+ end
72
+
73
+ # @param [Object] options Possible options to pass (not used yet)
74
+ # @param [Block] block Block to call when new satellite info json object comes from gpsd
75
+ def on_satellites_change(options:{}, &block)
76
+ @json_sat_callback = block
77
+ end
78
+
79
+ # @param [Object] options Possible options to pass (not used yet)
80
+ # @param [Block] block Block to call when new pps info json object comes from gpsd
81
+ def on_pps_change(options:{}, &block)
82
+ @json_pps_callback = block
83
+ end
84
+
85
+ # @param [Object] options Possible options to pass (not used yet)
86
+ # @param [Block] block Block to call when new pps info json object comes from gpsd
87
+ def on_unk_change(options:{}, &block)
88
+ @json_unk_callback = block
89
+ end
90
+
91
+ def reset_msg_counts
92
+ @msg_counts.each_key { |k| @msg_counts[k] = 0 }
93
+ end
94
+
95
+ def self.version
96
+ MyGpsdClient_version::VERSION
97
+ end
98
+
99
+
100
+ # Open the socket and when ready request the position flow from the gps daemon
101
+ def start
102
+ # background thread that is used to open the socket and wait for it to be ready
103
+ @socket_init_thread = Thread.start do
104
+ #open the socket
105
+ retry_count = 10
106
+ while (retry_count -= 1) > 0
107
+ #while not @socket_ready
108
+ init_socket
109
+ #wait for it to be ready
110
+ sleep 0.1
111
+ break if @socket_ready
112
+ end
113
+
114
+ unless @socket_ready
115
+ puts 'Socket Initialization Error' if @verbose
116
+ else
117
+ # it's ready, tell it to start watching and passing
118
+ puts "socket ready, start watching" if @verbose
119
+ str = "?WATCH=#{@watch.to_json}"
120
+ puts "sending: #{str}" if @verbose
121
+ @sent_raw_callback.call( str) if @sent_raw_callback
122
+ @socket.puts str
123
+ #puts 'sending: ?WATCH={"enable":true,"json":true}' if @verbose
124
+ #@socket.puts '?WATCH={"enable":true,"json":true}'
125
+ end
126
+ end
127
+
128
+ # background thead that is used to read info from the socket and use it
129
+ @trackthread = Thread.start do
130
+ while true do
131
+ begin
132
+ read_from_socket
133
+ rescue
134
+ "error while reading socket: #{$!}" if @verbose
135
+ end
136
+ end
137
+ end
138
+
139
+ Thread.kill(@watchdogthread) if @watchdog_thread
140
+ @watchdogthread = Thread.start do
141
+ @watchdog_count = 0
142
+ while true do
143
+ if @watchdog_force
144
+ @watchdog_force = false
145
+ @watchdog_count = @watchdog_max
146
+ end
147
+ if (@watchdog_count += 1) >= @watchdog_max
148
+ @watchdog_count = 0
149
+ @watchdog_fired_count += 1
150
+ stop
151
+ sleep 1
152
+ start
153
+ end
154
+ sleep 1
155
+ end
156
+ end
157
+
158
+ end
159
+
160
+ # @return [string] status info string containing nr satellites, fix, speed
161
+ def to_status
162
+ return "lat: #{last['lat']}, lng: #{last['lon']}, speed:#{last['speed']}, sats: #{@sats.length}(#{@sats.count{|sat| sat['used']}})" if @socket_ready and @last and @sats
163
+ return "lat: #{last['lat']}, lng: #{last['lon']}, speed:#{last['speed']}" if @socket_ready and @last and @sats.nil?
164
+ return "sats: #{@sats.length}(#{@sats.count{|sat| sat['used']}}), no fix yet" if @socket_ready and @last.nil? and @sats
165
+ return "connected with gpsd, waiting for data" if @socket_ready
166
+ return "waiting for connection with gpsd" if @socket_ready == false
167
+ end
168
+
169
+ # Stop the listening loop and close the socket. It will read the last bit of data from the socket, close it, and clean it up
170
+ def stop
171
+ # last read(s)
172
+ 3.times { read_from_socket }
173
+ # then close
174
+ close_socket
175
+ # then cleanup
176
+ @socket_ready = false
177
+ Thread.kill(@socket_init_thread) if @socket_init_thread
178
+ Thread.kill(@trackthread) if @trackthread
179
+ end
180
+
181
+ # initialize gpsd socket
182
+ def init_socket
183
+ begin
184
+ puts "init_socket" if @verbose
185
+ close_socket if @socket
186
+ @socket = TCPSocket.new(@host, @port)
187
+ #msg="w+"
188
+ msg="This space for rent"
189
+ @sent_raw_callback.call( msg) if @sent_raw_callback
190
+ @socket.puts(msg) #contents seem to be irrelevant here
191
+
192
+ puts "reading socket..." if @verbose
193
+ welcome = ::JSON.parse @socket.gets.chomp
194
+ @json_raw_callback.call(welcome) if @json_raw_callback
195
+ puts "welcome: #{welcome.inspect}" if @verbose
196
+ @socket_ready = (welcome and welcome['class'] and welcome['class'] == 'VERSION')
197
+ @msg_counts[:ver] += 1 if @socket_ready
198
+ puts "@socket_ready: #{@socket_ready.inspect}" if @verbose
199
+ rescue
200
+ @socket_ready = false
201
+ puts "#$!" if @verbose
202
+ end
203
+ end
204
+
205
+ # Read from socket. this should happen in a Thread as a continues loop. It should try to read data from the socket but nothing might happen if the gps deamon might not be ready. If ready it will send packets that we read and proces
206
+ def read_from_socket
207
+ if @socket_ready
208
+ begin
209
+ if input = @socket.gets.chomp and not input.to_s.empty?
210
+ parse_socket_json(json: JSON.parse(input))
211
+ @watchdog_count = 0
212
+ else
213
+ sleep 0.1
214
+ end
215
+ rescue
216
+ puts "error reading from socket: #{$!}" if @verbose
217
+ end
218
+ else
219
+ sleep 0.1
220
+ end
221
+ end
222
+
223
+ # Proceses json object returned by gpsd daemon. The TPV and SKY object
224
+ # are used the most as they give info about satellites used and gps locations
225
+ # @param [JSON] json The object returned by the daemon
226
+ def parse_socket_json(json:)
227
+ case json['class']
228
+ when 'TOFF'
229
+ @msg_counts[:toff] += 1
230
+ when 'ATT'
231
+ @msg_counts[:att] += 1
232
+ when 'ERR'
233
+ @msg_counts[:err] += 1
234
+ when 'GST'
235
+ @msg_counts[:gst] += 1
236
+ when 'POL'
237
+ @msg_counts[:pol] += 1
238
+ when 'DEVICE'
239
+ @msg_counts[:dev] += 1
240
+ when 'DEVICES'
241
+ # devices that are found, not needed
242
+ @msg_counts[:devs] += 1
243
+ when 'WATCH'
244
+ # gps deamon is ready and will send other packets, not needed yet
245
+ @msg_counts[:wtch] += 1
246
+ when 'TPV'
247
+ # gps position
248
+ # "tag"=>"RMC", # "device"=>"/dev/ttyS0", # "mode"=>3,
249
+ # "time"=>"2017-11-28T12:54:54.000Z", # "ept"=>0.005, # "lat"=>52.368576667,
250
+ # "lon"=>4.901715, # "alt"=>-6.2, # "epx"=>2.738, # "epy"=>3.5,
251
+ # "epv"=>5.06, # "track"=>198.53, # "speed"=>0.19, # "climb"=>0.0,
252
+ # "eps"=>7.0, # "epc"=>10.12
253
+ @msg_counts[:tpv] += 1
254
+ if json['mode'] > 1
255
+ #we have a 2d or 3d fix
256
+ if is_new_measurement(json: json)
257
+ json['time'] = DateTime.parse(json['time'])
258
+ puts "lat: #{json['lat']}, lng: #{json['lon']}, alt: #{json['alt']}, speed: #{json['speed']} at #{json['time']}, which is #{(Time.now - json['time'].to_time) * 1000}ms old" if @verbose
259
+ @json_pos_callback.call(json) if @json_pos_callback
260
+ end
261
+ end
262
+ when 'SKY'
263
+ # report on found satellites
264
+ @msg_counts[:sky] += 1
265
+ sats = json['satellites']
266
+ if satellites_changed(sats: sats)
267
+ puts "found #{sats.length} satellites, of which #{sats.count{|sat| sat['used']}} are used" if @verbose
268
+ @json_sat_callback.call(sats) if @json_sat_callback
269
+ end
270
+ when 'PPS'
271
+ @msg_counts[:pps] += 1
272
+ puts "found PPS tag: #{json.inspect}" if @verbose
273
+ @json_pps_callback.call(json) if @json_pps_callback
274
+ else
275
+ @msg_counts[:unk] += 1
276
+ puts "found unknown tag: #{json.inspect}" if @verbose
277
+ @json_unk_callback.call(json) if @json_unk_callback
278
+ end
279
+ @json_raw_callback.call(json) if @json_raw_callback
280
+ end
281
+
282
+ # checks if the new satellites object return by the deamon is different enough compared
283
+ # to the last one, to use it
284
+ def satellites_changed(sats:)
285
+ if @sats.nil? or (@sats.length != sats.length or @sats.count{|sat| sat['used']} != sats.count{|sat| sat['used']})
286
+ @sats = sats
287
+ return true
288
+ end
289
+ return false
290
+ end
291
+
292
+ # checks if the new location object return by the deamon is different enough compared
293
+ # to the last one, to use it. it could be disregarded for example because the speed is to low, and you don't want to have the location jumping around when you stand still
294
+ def is_new_measurement(json:)
295
+ if @last.nil? or (@last['lat'] != json['lat'] and @last['lon'] != json['lon'] and json['speed'] >= @min_speed)
296
+ @last = json
297
+ return true
298
+ end
299
+ return false
300
+ end
301
+
302
+ # Close the gps deamon socket
303
+ def close_socket
304
+ begin
305
+ if @socket
306
+ msg = '?WATCH={"enable":false}'
307
+ @sent_raw_callback.call( msg) if @sent_raw_callback
308
+ @socket.puts msg
309
+ @socket.close
310
+ end
311
+ @socket = nil
312
+ rescue
313
+ puts "#$!" if @verbose
314
+ end
315
+ end
316
+
317
+
318
+ end
@@ -0,0 +1,41 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "my_gpsd_client/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "my_gpsd_client"
8
+ spec.version = MyGpsdClient_version::VERSION
9
+ spec.authors = ["Steven Finnegan"]
10
+ spec.email = ["steven@rustyshamrock.com"]
11
+
12
+ spec.summary = %q{My version of gpsd2json gem}
13
+ # spec.description = %q{TODO: Write a longer description or delete this line.}
14
+ spec.homepage = "https://github.com/sjf-control/my_gpsd_client"
15
+ spec.license = 'MIT'
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata["allowed_push_host"] = 'https://rubygems.org'
21
+
22
+ spec.metadata["homepage_uri"] = spec.homepage
23
+ spec.metadata["source_code_uri"] = 'https://github.com/sjf-control/my_gpsd_client'
24
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
25
+ else
26
+ raise "RubyGems 2.0 or newer is required to protect against " \
27
+ "public gem pushes."
28
+ end
29
+
30
+ # Specify which files should be added to the gem when it is released.
31
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
32
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
33
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
34
+ end
35
+ spec.bindir = "exe"
36
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
37
+ spec.require_paths = ["lib"]
38
+
39
+ spec.add_development_dependency "bundler", "~> 1.17"
40
+ spec.add_development_dependency "rake", "~> 10.0"
41
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: my_gpsd_client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.30
5
+ platform: ruby
6
+ authors:
7
+ - Steven Finnegan
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-10-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.17'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.17'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description:
42
+ email:
43
+ - steven@rustyshamrock.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - Deploy.md
50
+ - Gemfile
51
+ - Gemfile.lock
52
+ - README.md
53
+ - Rakefile
54
+ - bin/console
55
+ - bin/setup
56
+ - lib/my_gpsd_client.rb
57
+ - lib/my_gpsd_client/version.rb
58
+ - my_gpsd_client.gemspec
59
+ homepage: https://github.com/sjf-control/my_gpsd_client
60
+ licenses:
61
+ - MIT
62
+ metadata:
63
+ allowed_push_host: https://rubygems.org
64
+ homepage_uri: https://github.com/sjf-control/my_gpsd_client
65
+ source_code_uri: https://github.com/sjf-control/my_gpsd_client
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubygems_version: 3.0.4
82
+ signing_key:
83
+ specification_version: 4
84
+ summary: My version of gpsd2json gem
85
+ test_files: []