OGTraf 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/ogtraf +85 -0
- data/lib/ogtraf.rb +141 -0
- data/lib/ogtraf/connection.rb +29 -0
- data/lib/ogtraf/departure.rb +15 -0
- data/lib/ogtraf/deviation.rb +29 -0
- data/lib/ogtraf/journey.rb +42 -0
- data/lib/ogtraf/line.rb +25 -0
- data/lib/ogtraf/stop.rb +32 -0
- data/lib/ogtraf/version.rb +3 -0
- metadata +137 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6791fcdbb6bee86906c6e14792a247e2daa29eb96c4bc95a443cb7c18deed138
|
4
|
+
data.tar.gz: bbe5d1094ea389bfa067477011c5e759faa9227734689131ddac263d2953807d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 38f6ed583d443925f144940f272d7bbcdcb7fd93199f25ca5cf6f774c43d41072f53a77c1288c2da50b287efe31d98d14fa97ef936d92ba4013fccefb7117be4
|
7
|
+
data.tar.gz: f0b0dbffcced85e577061ae99e699eed2c22b38b4bed086d49180e25e738f04a9891b7a572c4ebfce0ebcb789509dd328d2a58eff56fbc8145454bcb9f94262d
|
data/bin/ogtraf
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'ogtraf'
|
4
|
+
require 'time'
|
5
|
+
require 'thor'
|
6
|
+
|
7
|
+
# Implements the OGTraf CLI
|
8
|
+
class OGTrafCLI < Thor
|
9
|
+
class_option :verbose, type: :boolean, default: false, aliases: '-v'
|
10
|
+
|
11
|
+
desc 'journey FROM TO', 'Plans a journey from FROM to TO'
|
12
|
+
option :walk, default: false, type: :boolean, desc: 'Is walking allowed?'
|
13
|
+
option :num, default: 5, type: :numeric, desc: 'Number of entries wanted',
|
14
|
+
aliases: '-n'
|
15
|
+
|
16
|
+
option :time, default: nil, type: :string, desc: 'Date+Time to search from',
|
17
|
+
aliases: '-t'
|
18
|
+
|
19
|
+
def journey(from, to)
|
20
|
+
from_s = OGTraf.stops(from).first
|
21
|
+
to_s = OGTraf.stops(to).first
|
22
|
+
time = Time.now
|
23
|
+
time = Time.parse(options[:date]) if options[:date]
|
24
|
+
|
25
|
+
puts "Next #{options[:num]} journeys from #{from_s} to #{to_s} after #{time}:"
|
26
|
+
|
27
|
+
shown = 0
|
28
|
+
until shown >= options[:num]
|
29
|
+
avail = OGTraf.journey(
|
30
|
+
from, to,
|
31
|
+
date: time,
|
32
|
+
span: :after,
|
33
|
+
walk: options[:walk],
|
34
|
+
verbose: options[:verbose]
|
35
|
+
)
|
36
|
+
|
37
|
+
avail.each do |j|
|
38
|
+
next if j.departure < Time.now
|
39
|
+
|
40
|
+
time_left = j.departure - Time.now
|
41
|
+
|
42
|
+
hours = (time_left / 3600).floor
|
43
|
+
minutes = ((time_left % 3600) / 60).floor
|
44
|
+
|
45
|
+
puts
|
46
|
+
puts "In #{format('%02d:%02d', hours, minutes)}:" if hours > 0
|
47
|
+
puts "In #{minutes} minutes:" if hours.zero?
|
48
|
+
|
49
|
+
j.connections.each do |c|
|
50
|
+
if c.line.walk
|
51
|
+
puts format('- (%s - %s) walk to %s',
|
52
|
+
c.departure.strftime('%H:%M'),
|
53
|
+
c.arrival.strftime('%H:%M'),
|
54
|
+
c.to.to_s)
|
55
|
+
else
|
56
|
+
puts format('- (%s - %s) %s from %s to %s',
|
57
|
+
c.departure.strftime('%H:%M'),
|
58
|
+
c.arrival.strftime('%H:%M'),
|
59
|
+
c.line.to_s,
|
60
|
+
c.from.to_s,
|
61
|
+
c.to.to_s)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
shown += 1
|
66
|
+
break if shown >= options[:num]
|
67
|
+
|
68
|
+
time = j.departure
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
desc 'stop STOP', 'Finds a stop by the given name'
|
74
|
+
option :limit, default: 5, type: :numeric, desc: 'Number of entries wanted',
|
75
|
+
aliases: '-l'
|
76
|
+
def stop(name)
|
77
|
+
puts 'Found stops:'
|
78
|
+
puts OGTraf.stops(
|
79
|
+
name,
|
80
|
+
verbose: options[:verbose]
|
81
|
+
).take(options[:limit]).map(&:name)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
OGTrafCLI.start
|
data/lib/ogtraf.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'json'
|
3
|
+
require 'logging'
|
4
|
+
require 'net/http'
|
5
|
+
require 'ogtraf/connection'
|
6
|
+
require 'ogtraf/departure'
|
7
|
+
require 'ogtraf/deviation'
|
8
|
+
require 'ogtraf/journey'
|
9
|
+
require 'ogtraf/line'
|
10
|
+
require 'ogtraf/stop'
|
11
|
+
require 'ogtraf/version'
|
12
|
+
require 'uri'
|
13
|
+
|
14
|
+
module OGTraf
|
15
|
+
module Priority
|
16
|
+
SHORTEST_TIME = 0
|
17
|
+
FEWER_CHANGES = 1
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.stops(name, options = {})
|
21
|
+
query = {
|
22
|
+
pointType: nil
|
23
|
+
}.merge(options)
|
24
|
+
|
25
|
+
query[:q] = CGI.escape name.to_s
|
26
|
+
|
27
|
+
uri = URI('https://rest.ostgotatrafiken.se/stops/Find')
|
28
|
+
uri.query = URI.encode_www_form(query)
|
29
|
+
|
30
|
+
j = run_query(uri)
|
31
|
+
j.map { |v| Stop.new v }
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.departures(departure_start, options = {})
|
35
|
+
query = {
|
36
|
+
date: nil,
|
37
|
+
delay: 0,
|
38
|
+
maxNumberOfResultPerColumn: 8,
|
39
|
+
columnsPerPageCount: 1,
|
40
|
+
pagesCount: 1,
|
41
|
+
lines: nil,
|
42
|
+
trafficTypes: nil,
|
43
|
+
stopPoints: nil
|
44
|
+
}.merge(options)
|
45
|
+
|
46
|
+
departure_start = stops(departure_start).first unless departure_start.is_a? Stop
|
47
|
+
|
48
|
+
raise 'Date must be a Time' unless query[:date].is_a? Time
|
49
|
+
|
50
|
+
query.merge!(
|
51
|
+
date: query[:date].strftime('%Y-%m-%d+%H:%M'),
|
52
|
+
stopAreaId: departure_start.id
|
53
|
+
)
|
54
|
+
|
55
|
+
uri = URI('https://rest.ostgotatrafiken.se/stopdepartures/departures')
|
56
|
+
uri.query = URI.encode_www_form(query)
|
57
|
+
|
58
|
+
j = run_query(uri)
|
59
|
+
j[:groups].first.map { |v| Departure.new v[:Line] }
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.journey(journey_start, journey_end, options = {})
|
63
|
+
query = {
|
64
|
+
date: Time.now,
|
65
|
+
direction: 0,
|
66
|
+
span: :default,
|
67
|
+
traffictypes: 0,
|
68
|
+
changetime: 0,
|
69
|
+
priority: Priority::SHORTEST_TIME,
|
70
|
+
walk: false
|
71
|
+
}.merge(options)
|
72
|
+
|
73
|
+
journey_start = stops(journey_start).first unless journey_start.is_a? Stop
|
74
|
+
journey_end = stops(journey_end).first unless journey_end.is_a? Stop
|
75
|
+
|
76
|
+
raise 'Date must be a Time' unless query[:date].is_a? Time
|
77
|
+
|
78
|
+
query.merge!(
|
79
|
+
time: query[:date].strftime('%H:%M'),
|
80
|
+
date: query[:date].strftime('%Y-%m-%d'),
|
81
|
+
|
82
|
+
startId: journey_start.id,
|
83
|
+
startType: journey_start.type,
|
84
|
+
startLl: journey_start.gps_ll,
|
85
|
+
startName: journey_start.name,
|
86
|
+
endId: journey_end.id,
|
87
|
+
endType: journey_end.type,
|
88
|
+
endLl: journey_end.gps_ll,
|
89
|
+
endName: journey_end.name
|
90
|
+
)
|
91
|
+
|
92
|
+
uri = URI('https://rest.ostgotatrafiken.se/journey/Find')
|
93
|
+
uri.query = URI.encode_www_form(query)
|
94
|
+
|
95
|
+
j = run_query(uri, error: true)
|
96
|
+
j[:Journeys].map { |v| Journey.new v }
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.run_query(uri, _options = {})
|
100
|
+
logger.debug uri
|
101
|
+
|
102
|
+
h = Net::HTTP.new(uri.host, uri.port)
|
103
|
+
h.use_ssl = uri.scheme == 'https'
|
104
|
+
|
105
|
+
r = h.start do |http|
|
106
|
+
http.request(Net::HTTP::Get.new(uri))
|
107
|
+
end
|
108
|
+
|
109
|
+
logger.debug r
|
110
|
+
|
111
|
+
begin
|
112
|
+
j = JSON.parse(r.body, symbolize_names: true)
|
113
|
+
|
114
|
+
logger.debug j
|
115
|
+
|
116
|
+
raise j unless r.is_a? Net::HTTPSuccess
|
117
|
+
|
118
|
+
if j.is_a? Array
|
119
|
+
first = j.first
|
120
|
+
if first.key? :ErrorCode
|
121
|
+
raise first[:ErrorText] unless first[:ErrorCode].zero?
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
j
|
126
|
+
rescue JSON::ParserError
|
127
|
+
raise "HTTP #{r.code} Response with unparseable JSON."
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.debug!
|
132
|
+
logger.level = :debug
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.logger
|
136
|
+
@logger ||= Logging.logger[self].tap do |logger|
|
137
|
+
logger.add_appenders Logging.appenders.stdout
|
138
|
+
logger.level = :info
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
module OGTraf
|
4
|
+
class Connection
|
5
|
+
attr_reader :departure, :real_departure, :arrival, :real_arrival, :from,
|
6
|
+
:to, :line, :deviations
|
7
|
+
|
8
|
+
def initialize(datablock)
|
9
|
+
@departure = Time.parse datablock[:DepDateTime]
|
10
|
+
@real_departure = @departure
|
11
|
+
|
12
|
+
@arrival = Time.parse datablock[:ArrDateTime]
|
13
|
+
@real_arrival = @arrival
|
14
|
+
|
15
|
+
if datablock[:RealTime] && datablock[:RealTime][:RealTimeInfo]
|
16
|
+
datablock[:RealTime][:RealTimeInfo].each do |rti|
|
17
|
+
@departure += rti[:DepTimeDeviation] * 60
|
18
|
+
@arrival += rti[:ArrTimeDeviation] * 60
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
@from = Stop.new datablock[:From]
|
23
|
+
@to = Stop.new datablock[:To]
|
24
|
+
|
25
|
+
@line = Line.new datablock[:Line]
|
26
|
+
@deviations = datablock[:Deviations].map { |d| Deviation.new d }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module OGTraf
|
2
|
+
#
|
3
|
+
class Departure
|
4
|
+
attr_reader :from, :to, :time, :real_time, :name, :stops
|
5
|
+
|
6
|
+
def initialize(datablock)
|
7
|
+
@from = datablock[:from]
|
8
|
+
@to = datablock[:to]
|
9
|
+
@time = datablock[:time]
|
10
|
+
@real_time = datablock[:real_time]
|
11
|
+
@name = datablock[:name]
|
12
|
+
@stops = datablock[:stops]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
module OGTraf
|
4
|
+
#
|
5
|
+
class Deviation
|
6
|
+
attr_reader :header, :summary, :details, :text, :from, :to
|
7
|
+
|
8
|
+
def initialize(datablock)
|
9
|
+
@header = datablock[:Header]
|
10
|
+
@summary = datablock[:Summary] || datablock[:PublicNote]
|
11
|
+
@details = datablock[:Details]
|
12
|
+
@text = datablock[:ShortText]
|
13
|
+
|
14
|
+
@from = Time.now
|
15
|
+
@to = Time.now
|
16
|
+
|
17
|
+
datablock[:DeviationScopes].each do |dev|
|
18
|
+
from = Time.parse dev[:FromDateTime]
|
19
|
+
@from = from if @from > from
|
20
|
+
to = Time.parse dev[:ToDateTime]
|
21
|
+
@to = to if @to < to
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
@header.to_s
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
module OGTraf
|
4
|
+
#
|
5
|
+
class Journey
|
6
|
+
attr_reader :departure, :arrival, :from, :to,
|
7
|
+
:real_departure, :real_arrival,
|
8
|
+
:connections
|
9
|
+
|
10
|
+
def initialize(datablock)
|
11
|
+
@real_departure = Time.parse(datablock[:Departure])
|
12
|
+
@real_arrival = Time.parse(datablock[:Arrival])
|
13
|
+
|
14
|
+
@from = Stop.new datablock[:UsedStartPlace]
|
15
|
+
@to = Stop.new datablock[:UsedEndPlace]
|
16
|
+
|
17
|
+
@connections = datablock[:Routelinks].map { |r| Connection.new r }
|
18
|
+
|
19
|
+
@departure = @connections.first.departure
|
20
|
+
arrival_point = @connections.find { |c| c.to == @to }
|
21
|
+
@arrival = @real_arrival
|
22
|
+
@arrival = arrival_point.arrival unless arrival_point.nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
def on_time?(side = :arr, allowed_drift = 60)
|
26
|
+
raise ArgumentError unless
|
27
|
+
%i[both dep departure arr arrival].include? side
|
28
|
+
|
29
|
+
if side == :both
|
30
|
+
return (@departure - @real_departure).abs < allowed_drift &&
|
31
|
+
(@arrival - @real_arrival).abs < allowed_drift
|
32
|
+
end
|
33
|
+
|
34
|
+
case side
|
35
|
+
when :dep, :departure
|
36
|
+
(@departure - @real_departure).abs < allowed_drift
|
37
|
+
when :arr, :arrival
|
38
|
+
(@arrival - @real_arrival).abs < allowed_drift
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/ogtraf/line.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module OGTraf
|
2
|
+
#
|
3
|
+
class Line
|
4
|
+
attr_reader :name, :number, :note, :operator, :type, :towards, :train_nr,
|
5
|
+
:walk
|
6
|
+
|
7
|
+
def initialize(datablock)
|
8
|
+
@name = datablock[:LineName]
|
9
|
+
@number = datablock[:LineNrReal]
|
10
|
+
@note = datablock[:FootNote]
|
11
|
+
@operator = {
|
12
|
+
id: datablock[:OperatorId],
|
13
|
+
name: datablock[:OperatorName]
|
14
|
+
}
|
15
|
+
@type = datablock[:LineTypeName].to_sym
|
16
|
+
@towards = datablock[:Towards]
|
17
|
+
@train_nr = datablock[:TrainNo]
|
18
|
+
@walk = datablock[:IsWalk]
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
@name.to_s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/ogtraf/stop.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module OGTraf
|
2
|
+
#
|
3
|
+
class Stop
|
4
|
+
include Comparable
|
5
|
+
attr_reader :name, :id, :gps, :clean_name, :type
|
6
|
+
|
7
|
+
def initialize(datablock)
|
8
|
+
@name = datablock[:PlaceName]
|
9
|
+
@id = datablock[:Id]
|
10
|
+
if datablock.key?(:Ll) && !datablock[:Ll].nil?
|
11
|
+
@gps = {
|
12
|
+
lon: datablock[:Ll][0],
|
13
|
+
lat: datablock[:Ll][1]
|
14
|
+
}
|
15
|
+
end
|
16
|
+
@clean_name = datablock[:OgtStopUrlSegment]
|
17
|
+
@type = datablock[:OgtType].to_sym
|
18
|
+
end
|
19
|
+
|
20
|
+
def gps_ll
|
21
|
+
[@gps[:lon], @gps[:lat]].join ','
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
@name.to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
def <=>(other)
|
29
|
+
@id <=> other.id
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: OGTraf
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alexander "Ace" Olofsson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-08-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: logging
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: thor
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.19'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.19'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.7'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.7'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '5.9'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '5.9'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.41'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.41'
|
97
|
+
description: Allows querying Östgötatrafiken's APIs
|
98
|
+
email: ace@haxalot.com
|
99
|
+
executables:
|
100
|
+
- ogtraf
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- bin/ogtraf
|
105
|
+
- lib/ogtraf.rb
|
106
|
+
- lib/ogtraf/connection.rb
|
107
|
+
- lib/ogtraf/departure.rb
|
108
|
+
- lib/ogtraf/deviation.rb
|
109
|
+
- lib/ogtraf/journey.rb
|
110
|
+
- lib/ogtraf/line.rb
|
111
|
+
- lib/ogtraf/stop.rb
|
112
|
+
- lib/ogtraf/version.rb
|
113
|
+
homepage:
|
114
|
+
licenses:
|
115
|
+
- MIT
|
116
|
+
metadata: {}
|
117
|
+
post_install_message:
|
118
|
+
rdoc_options: []
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
requirements: []
|
132
|
+
rubyforge_project:
|
133
|
+
rubygems_version: 2.7.7
|
134
|
+
signing_key:
|
135
|
+
specification_version: 4
|
136
|
+
summary: Östgötatrafiken
|
137
|
+
test_files: []
|