tac_scribe 0.4.0 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f6540479b0949db23d8dcbfc7965a716d4909b7e03b314f9b1687b7b7b044e1b
4
- data.tar.gz: 9c6ee7a6e020b81eea6cd809c043eb31f2353256a41463da5349ee78699d3f1b
3
+ metadata.gz: f98aa241fcbc438f272781cdf33a6add2ec0cdd0fd07c488e5db31055b6f665c
4
+ data.tar.gz: c937ed8364f5d8db30badcc05ac7883bd946030576c33b3402ac7dba71b5d18d
5
5
  SHA512:
6
- metadata.gz: 5236421e641674570e47e65c309ed12c0beff782cfd7fddea75d09687a4aa7660a445cc5249e2d8489f4a56df2cba8ec9fd76df1390b916053cd35ab9dc19f84
7
- data.tar.gz: 3a500080c5d44f78c1bfd0914face93c40d318eb8721d7a2e0876a7e5cfdc9cfdddded214fe0f99da2fbcb356420d1319159f085cbcbdd2d61eac3064afaf4c3
6
+ metadata.gz: 6e078ace132775b4cc7815223975d4b47a9a6b3c6e89e654c3707d045ec3e7fb6864e49511d4f064657a19747e59304d30ecac256574fd4677c4a634ef6b1529
7
+ data.tar.gz: 3790de8e1e2c52650c103c1dfc1275ed774311e406c267adb0863309b05f1fe9e79e536a7242ad59ef84b037f586a0f3ec4c968b57be2d212e99508430d829bb
@@ -14,7 +14,10 @@ Metrics/BlockLength:
14
14
  # There isn't much sense breaking up the OptionParser block since splitting
15
15
  # into db and tacview option methods will just break the method length cop
16
16
  # and splitting further doesn't aid readability
17
- - exe/start_scribe
17
+ - exe/tac_scribe
18
+ # Cannot really avoid this
19
+ - tac_scribe.gemspec
20
+
18
21
  Metrics/MethodLength:
19
22
  Exclude:
20
23
  # Breaking up the initializer doesn't really do much for readability
@@ -29,3 +32,13 @@ Style/GlobalVars:
29
32
  Exclude:
30
33
  # Using a global variable makes it available to the Pry console
31
34
  - bin/console
35
+ AllCops:
36
+ Exclude:
37
+ # These files will need a MAJOR refactoring to get rid of these warnings
38
+ - lib/tac_scribe/cache.rb
39
+ - lib/tac_scribe/datastore.rb
40
+ - lib/tac_scribe/daemon.rb
41
+ ClassVars:
42
+ Exclude:
43
+ # We are fine with this and understand the risks. We are not inheriting.
44
+ - lib/tac_scribe/event_processor.rb
@@ -1 +1 @@
1
- ruby-2.6.3
1
+ ruby-2.7.0
@@ -4,7 +4,26 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [Unreleased]
7
+ ## [0.6.2]
8
+ ### Changed
9
+ - Fixed typo causing app to fail
10
+
11
+ ## [0.6.1]
12
+ ### Changed
13
+ - Test build for gem issue
14
+
15
+ ## [0.6.0]
16
+ ### Added
17
+ - Calculates and stores speed of units
18
+
19
+ ### Fixed
20
+ - Made more robust against failures and more logging messages
21
+
22
+ ## [0.5.0]
23
+ ### Changed
24
+ - Added missing db column to migration file
25
+ - Clear the cache on server restart
26
+ - Add more info to logging
8
27
 
9
28
  ## [0.4.0]
10
29
  ### Changed
@@ -0,0 +1,5 @@
1
+ Sea+Watercraft+AircraftCarrier
2
+ Air+Rotorcraft
3
+ Air+FixedWing
4
+ Ground+Static+Aerodrome
5
+ Navaid+Static+Bullseye
@@ -12,7 +12,9 @@ Sequel.migration do
12
12
  String :group, null: true
13
13
  Integer :coalition
14
14
  Integer :heading
15
+ Integer :speed
15
16
  Time :updated_at
17
+ Boolean :deleted
16
18
  # TODO: GIST Index on the position
17
19
  end
18
20
  end
@@ -52,7 +52,7 @@ OptionParser.new do |opts|
52
52
  'Postgresql server port (Default: 5432)') do |v|
53
53
  options[:db_port] = v
54
54
  end
55
- opts.on('-u', '--db-username=username',
55
+ opts.on('-u', '--db-user=username',
56
56
  'Postgresql username (Required)') do |v|
57
57
  options[:db_user] = v
58
58
  end
@@ -5,8 +5,11 @@ require 'sequel'
5
5
  require 'sequel-postgis-georuby'
6
6
  require 'singleton'
7
7
  require 'concurrent-ruby'
8
+ require 'haversine'
8
9
 
9
10
  module TacScribe
11
+ # The in-memory cache that is updated by events in real-time before the data
12
+ # is synced to the DB
10
13
  class Cache
11
14
  include Singleton
12
15
  include GeoRuby::SimpleFeatures
@@ -35,22 +38,25 @@ module TacScribe
35
38
  object.delete(key)
36
39
  end
37
40
 
41
+ # https://wiki.hoggitworld.com/view/DCS_singleton_coalition
38
42
  if object[:coalition]
39
43
  object[:coalition] = case object[:coalition]
40
- when 'Allies'
41
- 0
42
- when 'Enemies'
43
- 1
44
- else
44
+ when 'Enemies' # Enemies is Bluefor
45
45
  2
46
+ when 'Allies' # Allies is Redfor
47
+ 1
48
+ else # Neutral
49
+ 0
46
50
  end
47
51
  end
48
52
 
49
53
  if cache_object
50
54
  object[:heading] = calculate_heading(cache_object, object)
55
+ object[:speed] = calculate_speed(cache_object, object)
51
56
  cache_object.merge!(object)
52
57
  else
53
58
  object[:heading] = -1
59
+ object[:speed] = 0
54
60
  cache_object = object
55
61
  end
56
62
 
@@ -76,6 +82,12 @@ module TacScribe
76
82
  @@cache[id][:deleted] = true if @@cache[id]
77
83
  end
78
84
 
85
+ def clear
86
+ @@cache.clear
87
+ self.reference_latitude = nil
88
+ self.reference_longitude = nil
89
+ end
90
+
79
91
  private
80
92
 
81
93
  def localize_position(object)
@@ -91,20 +103,25 @@ module TacScribe
91
103
  longitude = if object.key?(:longitude)
92
104
  object[:longitude]
93
105
  else
94
- cache_object[:position].y
106
+ cache_object[:position].x
95
107
  end
96
108
 
97
109
  latitude = if object.key?(:latitude)
98
110
  object[:latitude]
99
111
  else
100
- cache_object[:position].x
112
+ cache_object[:position].y
101
113
  end
102
114
 
115
+ # This "Point" class is not lat/long aware which is why we are
116
+ # flipping things up here because when it converts to SQL we need
117
+ # the long to be first since that is what postgresql expects.
103
118
  Point.from_x_y(longitude, latitude)
104
119
  end
105
120
 
106
121
  def calculate_heading(cache_object, object)
107
- return cache_object[:heading] if cache_object[:position] == object[:position]
122
+ if cache_object[:position] == object[:position]
123
+ return cache_object[:heading]
124
+ end
108
125
 
109
126
  begin
110
127
  cache_object[:position].bearing_to(object[:position]).to_i
@@ -114,5 +131,21 @@ module TacScribe
114
131
  puts 'New Position: ' + object[:position].inspect
115
132
  end
116
133
  end
134
+
135
+ def calculate_speed(cache_object, object)
136
+ time = object[:game_time] - cache_object[:game_time]
137
+
138
+ start_point = cache_object[:position]
139
+ end_point = object[:position]
140
+
141
+ # Because of the above issues with Point and Lat/Lon
142
+ # the values are reverse here :(
143
+ distance = Haversine.distance(start_point.y, start_point.x,
144
+ end_point.y, end_point.x).to_meters
145
+
146
+ speed = distance / time
147
+
148
+ speed.to_i
149
+ end
117
150
  end
118
151
  end
@@ -31,7 +31,7 @@ module TacScribe
31
31
 
32
32
  @populate_airfields = populate_airfields
33
33
  @thread_count = thread_count
34
- @threads = []
34
+ @threads = {}
35
35
  @whitelist = Set.new(IO.read(whitelist).split) if whitelist
36
36
 
37
37
  @client = TacviewClient::Client.new(
@@ -50,43 +50,57 @@ module TacScribe
50
50
  # for example
51
51
  def start_processing
52
52
  loop do
53
- kill_threads
53
+ puts 'Starting processing loop'
54
54
  @event_queue.clear
55
55
  Datastore.instance.truncate_table
56
+ Cache.instance.clear
56
57
  start_processing_threads
57
58
  start_db_sync_thread
58
59
  start_reporting_thread
59
60
  populate_airfields if @populate_airfields
61
+ @threads.each_pair do |key, _value|
62
+ puts "#{key} thread started"
63
+ end
60
64
  @client.connect
65
+ # If this code is executed it means we have been disconnected without
66
+ # exceptions. We will still sleep to stop a retry storm. Just not as
67
+ # long.
68
+ puts "Disconnected from Tacview"
69
+ kill_threads
70
+ sleep 10
61
71
  # Rescuing reliably from Net::HTTP is a complete bear so rescue
62
72
  # StandardError. It ain't pretty but it is reliable. We will puts
63
73
  # the exception just in case
64
74
  # https://stackoverflow.com/questions/5370697/what-s-the-best-way-to-handle-exceptions-from-nethttp
65
75
  rescue StandardError => e
76
+ puts 'Exception in processing loop'
66
77
  puts e.message
67
78
  puts e.backtrace
79
+ kill_threads
68
80
  sleep 30
69
81
  next
70
82
  end
71
83
  end
72
84
 
73
85
  def kill_threads
74
- @threads.each do |thr|
75
- thr.kill
76
- thr.join
86
+ puts 'Killing Threads'
87
+ @threads.each_pair do |key, thread|
88
+ puts "Killing #{key} thread"
89
+ thread.kill
90
+ thread.join
77
91
  end
78
92
  end
79
93
 
80
94
  def start_processing_threads
81
95
  @event_processor = EventProcessor.new(cache: Cache.instance,
82
- datastore: Datastore.instance,
83
- event_queue: @event_queue,
84
- whitelist: @whitelist)
96
+ datastore: Datastore.instance,
97
+ event_queue: @event_queue,
98
+ whitelist: @whitelist)
85
99
  event_processor_thread = Thread.new do
86
100
  @event_processor.start
87
101
  end
88
- event_processor_thread.name = "Event Processor"
89
- @threads << event_processor_thread
102
+ event_processor_thread.name = 'Event Processor'
103
+ @threads[:processing] = event_processor_thread
90
104
  end
91
105
 
92
106
  def start_db_sync_thread
@@ -95,34 +109,42 @@ module TacScribe
95
109
  sleep 1
96
110
  deleted = Datastore.instance.write_objects(Cache.instance.data.values)
97
111
  deleted.each { |id| Cache.instance.data.delete(id) }
112
+ rescue StandardError
113
+ next
98
114
  end
99
115
  end
100
- db_write_thread.name = "Database Writing"
101
- @threads << db_write_thread
116
+ db_write_thread.name = 'Database Writing'
117
+ @threads[:database] = db_write_thread
102
118
  end
103
119
 
104
120
  def start_reporting_thread
105
121
  return unless @verbose_logging
106
122
 
107
123
  reporting_thread = Thread.new do
124
+ sleep 5
108
125
  loop do
109
- puts "#{Time.now.strftime('%FT%T')}\t" +
110
- "Events Incoming: #{@event_queue.events_written}\t" +
111
- "Processed: #{@event_processor.events_processed}\t" +
112
- "Ignored: #{@event_processor.events_ignored}\t" +
113
- "Queue Size: #{@event_queue.size}"
126
+ puts "#{Time.now.strftime('%FT%T')}\t" \
127
+ "Events Incoming: #{@event_queue.events_written}\t" \
128
+ "Processed: #{@event_processor.events_processed}\t" \
129
+ "Ignored: #{@event_processor.events_ignored}\t" \
130
+ "Queue Size: #{@event_queue.size}\t" \
131
+ "Objects Written: #{Datastore.instance.written}\t" \
132
+ "Deleted: #{Datastore.instance.deleted}"
114
133
  @event_queue.events_written = 0
115
134
  @event_processor.events_processed = 0
116
135
  @event_processor.events_ignored = 0
136
+ Datastore.instance.written = 0
137
+ Datastore.instance.deleted = 0
117
138
  sleep 1
118
139
  end
119
140
  end
120
- reporting_thread.name = "Reporting"
121
- @threads << reporting_thread
141
+ reporting_thread.name = 'Reporting'
142
+ @threads[:reporting] = reporting_thread
122
143
  end
123
144
 
124
145
  def populate_airfields
125
- json = File.read(File.join(File.dirname(__FILE__), '../../data/airfields.json'))
146
+ json = File.read(File.join(File.dirname(__FILE__),
147
+ '../../data/airfields.json'))
126
148
  airfields = JSON.parse(json)
127
149
  airfields.each_with_index do |airfield, i|
128
150
  @event_queue.update_object(
@@ -132,7 +154,7 @@ module TacScribe
132
154
  altitude: BigDecimal(airfield['alt'].to_s),
133
155
  type: 'Ground+Static+Aerodrome',
134
156
  name: airfield['name'],
135
- coalition: 2
157
+ coalition: 0 # Neutral
136
158
  )
137
159
  end
138
160
  end
@@ -14,7 +14,7 @@ module TacScribe
14
14
  include Singleton
15
15
  include GeoRuby::SimpleFeatures
16
16
 
17
- attr_accessor :db
17
+ attr_accessor :db, :written, :deleted
18
18
 
19
19
  @configuration = nil
20
20
  @db = nil
@@ -53,17 +53,27 @@ module TacScribe
53
53
  end
54
54
 
55
55
  def write_objects(objects)
56
+ objects = objects.map do |object|
57
+ obj = object.clone
58
+ obj.delete(:game_time)
59
+ obj
60
+ end
61
+
56
62
  @db[:units].insert_conflict(
57
63
  constraint: :units_pkey,
58
64
  update: { position: Sequel[:excluded][:position],
59
65
  altitude: Sequel[:excluded][:altitude],
60
66
  heading: Sequel[:excluded][:heading],
67
+ speed: Sequel[:excluded][:speed],
61
68
  updated_at: Sequel[:excluded][:updated_at],
62
69
  deleted: Sequel[:excluded][:deleted] }
63
70
  )
64
71
  .multi_insert(objects)
65
72
  deleted_ids = @db[:units].where(deleted: true).select_map(:id)
66
73
  @db[:units].where(deleted: true).delete
74
+ self.written = objects.size
75
+ self.deleted = deleted_ids.size
76
+
67
77
  deleted_ids
68
78
  end
69
79
 
@@ -23,11 +23,12 @@ module TacScribe
23
23
 
24
24
  def start
25
25
  loop do
26
- wrapped_event = @event_queue.get_event
26
+ wrapped_event = @event_queue.shift
27
27
  process_event(wrapped_event)
28
28
  rescue StandardError => e
29
29
  puts wrapped_event
30
30
  puts e.inspect
31
+ puts e.backtrace
31
32
  next
32
33
  end
33
34
  end
@@ -38,6 +39,10 @@ module TacScribe
38
39
  update_object(wrapped_event[:event], wrapped_event[:time])
39
40
  when :delete_object
40
41
  delete_object(wrapped_event[:object_id])
42
+ when :set_latitude
43
+ update_latitude wrapped_event[:value]
44
+ when :set_longitude
45
+ update_longitude wrapped_event[:value]
41
46
  end
42
47
  end
43
48
 
@@ -60,20 +65,28 @@ module TacScribe
60
65
  # format.
61
66
  # @option event [BigDecimal] :altitude The object altitude above sea level
62
67
  # in meters to 1 decimal place.
63
- def update_object(event, _time)
68
+ def update_object(event, time)
69
+ return if ignore_unit?(event)
70
+
71
+ event[:game_time] = time
72
+
73
+ self.events_processed += 1
74
+ @cache.write_object(event)
75
+ end
76
+
77
+ def ignore_unit?(event)
64
78
  if @@ignored_units.include?(event[:object_id])
65
79
  self.events_ignored += 1
66
- return
80
+ return true
67
81
  end
68
82
 
69
83
  if @whitelist && event[:type] && !@whitelist.include?(event[:type])
70
84
  @@ignored_units << event[:object_id]
71
85
  self.events_ignored += 1
72
- return
86
+ return true
73
87
  end
74
88
 
75
- self.events_processed += 1
76
- @cache.write_object(event)
89
+ false
77
90
  end
78
91
 
79
92
  # Process a delete event for an object
@@ -81,12 +94,19 @@ module TacScribe
81
94
  # @param id [String] A hexadecimal number representing the object ID
82
95
  def delete_object(id)
83
96
  if @@ignored_units.delete?(id)
84
- self.events_processed += 1
85
- return
97
+ nil
86
98
  else
87
- self.events_processed += 1
88
99
  @cache.delete_object(id)
89
100
  end
101
+ self.events_processed += 1
102
+ end
103
+
104
+ def update_latitude(value)
105
+ Cache.instance.reference_latitude = value
106
+ end
107
+
108
+ def update_longitude(value)
109
+ Cache.instance.reference_longitude = value
90
110
  end
91
111
  end
92
112
  end
@@ -6,7 +6,6 @@ require 'time'
6
6
  module TacScribe
7
7
  # Processes the events emitted by the Ruby Tacview Client
8
8
  class EventQueue < TacviewClient::BaseProcessor
9
-
10
9
  attr_accessor :events_written
11
10
 
12
11
  def initialize
@@ -22,7 +21,7 @@ module TacScribe
22
21
  @events.size
23
22
  end
24
23
 
25
- def get_event
24
+ def shift
26
25
  @events.shift
27
26
  end
28
27
 
@@ -44,7 +43,7 @@ module TacScribe
44
43
  # @option event [BigDecimal] :altitude The object altitude above sea level
45
44
  # in meters to 1 decimal place.
46
45
  def update_object(event)
47
- self.events_written +=1
46
+ self.events_written += 1
48
47
  @events << { type: :update_object, event: event, time: @time }
49
48
  end
50
49
 
@@ -53,7 +52,7 @@ module TacScribe
53
52
  # @param object_id [String] A hexadecimal number representing the object
54
53
  # ID
55
54
  def delete_object(object_id)
56
- self.events_written +=1
55
+ self.events_written += 1
57
56
  @events << { type: :delete_object, object_id: object_id }
58
57
  end
59
58
 
@@ -72,9 +71,9 @@ module TacScribe
72
71
  def set_property(property:, value:)
73
72
  case property
74
73
  when 'ReferenceLatitude'
75
- Cache.instance.reference_latitude = BigDecimal(value)
74
+ @events << { type: :set_latitude, value: BigDecimal(value) }
76
75
  when 'ReferenceLongitude'
77
- Cache.instance.reference_longitude = BigDecimal(value)
76
+ @events << { type: :set_longitude, value: BigDecimal(value) }
78
77
  when 'ReferenceTime'
79
78
  @reference_time = @time = Time.parse(value)
80
79
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TacScribe
4
- VERSION = '0.4.0'
4
+ VERSION = '0.7.0'
5
5
  end
@@ -4,6 +4,8 @@ lib = File.expand_path('lib', __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require 'tac_scribe/version'
6
6
 
7
+ puts "RUBY_PLATFORM = #{RUBY_PLATFORM}"
8
+
7
9
  Gem::Specification.new do |spec|
8
10
  spec.name = 'tac_scribe'
9
11
  spec.version = TacScribe::VERSION
@@ -24,6 +26,8 @@ Gem::Specification.new do |spec|
24
26
 
25
27
  spec.metadata['yard.run'] = 'yri'
26
28
 
29
+ spec.platform = RUBY_PLATFORM == 'java' ? 'java' : 'ruby'
30
+
27
31
  if RUBY_PLATFORM == 'java'
28
32
  spec.add_dependency 'activerecord-jdbcpostgresql-adapter'
29
33
  else
@@ -36,6 +40,7 @@ Gem::Specification.new do |spec|
36
40
  # of an API breaking change are higher then normal. Therefore lock the
37
41
  # version
38
42
  spec.add_dependency 'concurrent-ruby', '~>1.1.5'
43
+ spec.add_dependency 'haversine', '~>0.3'
39
44
  spec.add_dependency 'sequel-postgis-georuby', '0.1.2'
40
45
  spec.add_dependency 'tacview_client', '~>0.1'
41
46
 
metadata CHANGED
@@ -1,178 +1,192 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tac_scribe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeffrey Jones
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-13 00:00:00.000000000 Z
11
+ date: 2020-07-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
+ name: pg
14
15
  requirement: !ruby/object:Gem::Requirement
15
16
  requirements:
16
- - - ">="
17
+ - - "~>"
17
18
  - !ruby/object:Gem::Version
18
- version: '0'
19
- name: activerecord-jdbcpostgresql-adapter
20
- prerelease: false
19
+ version: '1.1'
21
20
  type: :runtime
21
+ prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '1.1'
27
27
  - !ruby/object:Gem::Dependency
28
+ name: georuby
28
29
  requirement: !ruby/object:Gem::Requirement
29
30
  requirements:
30
31
  - - "~>"
31
32
  - !ruby/object:Gem::Version
32
33
  version: '2.5'
33
- name: georuby
34
- prerelease: false
35
34
  type: :runtime
35
+ prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.5'
41
41
  - !ruby/object:Gem::Dependency
42
+ name: sequel
42
43
  requirement: !ruby/object:Gem::Requirement
43
44
  requirements:
44
45
  - - "~>"
45
46
  - !ruby/object:Gem::Version
46
47
  version: '5.22'
47
- name: sequel
48
- prerelease: false
49
48
  type: :runtime
49
+ prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '5.22'
55
55
  - !ruby/object:Gem::Dependency
56
+ name: concurrent-ruby
56
57
  requirement: !ruby/object:Gem::Requirement
57
58
  requirements:
58
59
  - - "~>"
59
60
  - !ruby/object:Gem::Version
60
61
  version: 1.1.5
61
- name: concurrent-ruby
62
- prerelease: false
63
62
  type: :runtime
63
+ prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 1.1.5
69
69
  - !ruby/object:Gem::Dependency
70
+ name: haversine
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.3'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sequel-postgis-georuby
70
85
  requirement: !ruby/object:Gem::Requirement
71
86
  requirements:
72
87
  - - '='
73
88
  - !ruby/object:Gem::Version
74
89
  version: 0.1.2
75
- name: sequel-postgis-georuby
76
- prerelease: false
77
90
  type: :runtime
91
+ prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - '='
81
95
  - !ruby/object:Gem::Version
82
96
  version: 0.1.2
83
97
  - !ruby/object:Gem::Dependency
98
+ name: tacview_client
84
99
  requirement: !ruby/object:Gem::Requirement
85
100
  requirements:
86
101
  - - "~>"
87
102
  - !ruby/object:Gem::Version
88
103
  version: '0.1'
89
- name: tacview_client
90
- prerelease: false
91
104
  type: :runtime
105
+ prerelease: false
92
106
  version_requirements: !ruby/object:Gem::Requirement
93
107
  requirements:
94
108
  - - "~>"
95
109
  - !ruby/object:Gem::Version
96
110
  version: '0.1'
97
111
  - !ruby/object:Gem::Dependency
112
+ name: bundler
98
113
  requirement: !ruby/object:Gem::Requirement
99
114
  requirements:
100
115
  - - "~>"
101
116
  - !ruby/object:Gem::Version
102
117
  version: '2.0'
103
- name: bundler
104
- prerelease: false
105
118
  type: :development
119
+ prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
122
  - - "~>"
109
123
  - !ruby/object:Gem::Version
110
124
  version: '2.0'
111
125
  - !ruby/object:Gem::Dependency
126
+ name: rake
112
127
  requirement: !ruby/object:Gem::Requirement
113
128
  requirements:
114
129
  - - "~>"
115
130
  - !ruby/object:Gem::Version
116
131
  version: '10.0'
117
- name: rake
118
- prerelease: false
119
132
  type: :development
133
+ prerelease: false
120
134
  version_requirements: !ruby/object:Gem::Requirement
121
135
  requirements:
122
136
  - - "~>"
123
137
  - !ruby/object:Gem::Version
124
138
  version: '10.0'
125
139
  - !ruby/object:Gem::Dependency
140
+ name: rspec
126
141
  requirement: !ruby/object:Gem::Requirement
127
142
  requirements:
128
143
  - - "~>"
129
144
  - !ruby/object:Gem::Version
130
145
  version: '3.8'
131
- name: rspec
132
- prerelease: false
133
146
  type: :development
147
+ prerelease: false
134
148
  version_requirements: !ruby/object:Gem::Requirement
135
149
  requirements:
136
150
  - - "~>"
137
151
  - !ruby/object:Gem::Version
138
152
  version: '3.8'
139
153
  - !ruby/object:Gem::Dependency
154
+ name: rubocop
140
155
  requirement: !ruby/object:Gem::Requirement
141
156
  requirements:
142
157
  - - "~>"
143
158
  - !ruby/object:Gem::Version
144
159
  version: '0.73'
145
- name: rubocop
146
- prerelease: false
147
160
  type: :development
161
+ prerelease: false
148
162
  version_requirements: !ruby/object:Gem::Requirement
149
163
  requirements:
150
164
  - - "~>"
151
165
  - !ruby/object:Gem::Version
152
166
  version: '0.73'
153
167
  - !ruby/object:Gem::Dependency
168
+ name: simplecov
154
169
  requirement: !ruby/object:Gem::Requirement
155
170
  requirements:
156
171
  - - "~>"
157
172
  - !ruby/object:Gem::Version
158
173
  version: '0.17'
159
- name: simplecov
160
- prerelease: false
161
174
  type: :development
175
+ prerelease: false
162
176
  version_requirements: !ruby/object:Gem::Requirement
163
177
  requirements:
164
178
  - - "~>"
165
179
  - !ruby/object:Gem::Version
166
180
  version: '0.17'
167
181
  - !ruby/object:Gem::Dependency
182
+ name: yard
168
183
  requirement: !ruby/object:Gem::Requirement
169
184
  requirements:
170
185
  - - "~>"
171
186
  - !ruby/object:Gem::Version
172
187
  version: '0.9'
173
- name: yard
174
- prerelease: false
175
188
  type: :development
189
+ prerelease: false
176
190
  version_requirements: !ruby/object:Gem::Requirement
177
191
  requirements:
178
192
  - - "~>"
@@ -201,6 +215,7 @@ files:
201
215
  - bin/console
202
216
  - bin/setup
203
217
  - data/airfields.json
218
+ - data/whitelist.example
204
219
  - db/001_create_unit_table.rb
205
220
  - db/README.md
206
221
  - exe/tac_scribe
@@ -218,7 +233,7 @@ licenses:
218
233
  - AGPL-3.0-or-later
219
234
  metadata:
220
235
  yard.run: yri
221
- post_install_message:
236
+ post_install_message:
222
237
  rdoc_options: []
223
238
  require_paths:
224
239
  - lib
@@ -233,9 +248,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
233
248
  - !ruby/object:Gem::Version
234
249
  version: '0'
235
250
  requirements: []
236
- rubyforge_project:
237
- rubygems_version: 2.7.6
238
- signing_key:
251
+ rubygems_version: 3.1.2
252
+ signing_key:
239
253
  specification_version: 4
240
254
  summary: Write Tacview data to PostGIS database
241
255
  test_files: []