south_african_air_quality_index 0.0.2 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.ruby-version +1 -0
- data/Gemfile.lock +49 -38
- data/README.md +1 -1
- data/lib/south_african_air_quality_index/client.rb +161 -30
- data/lib/south_african_air_quality_index/constants.rb +6 -1
- data/lib/south_african_air_quality_index/version.rb +1 -1
- data/lib/south_african_air_quality_index.rb +2 -0
- data/notes.txt +166 -0
- data/south_african_air_quality_index.gemspec +12 -11
- metadata +28 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4fed9722692598e0997347a56a67a78f2d01ce935113f518253f5c8ab6cb59fd
|
4
|
+
data.tar.gz: 1584032fc9f18b912a7de65ef1d80eaca6999504023b0b2ae4df5f90cbb97422
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dab813e91a783cd81b16be144989e3cd36e14fea44195a1cbfefb29e8a6b4ec81dbe5f3963ddf468ecd642201428f6e8a7764d7947f936fb3f8d13162a55ae85
|
7
|
+
data.tar.gz: 7888aa82244e3a1c1a2c36f5b8b6942a744045f234e2acd2ede61d553545bcd5c4f063c00f3611482466157b37f545747ce1a3b4ca9de94cce3f449a5028f319
|
data/.gitignore
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.3.0
|
data/Gemfile.lock
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
south_african_air_quality_index (0.0.
|
5
|
-
active_attr (~> 0.
|
6
|
-
httparty (~> 0.
|
4
|
+
south_african_air_quality_index (0.0.3)
|
5
|
+
active_attr (~> 0.16.0)
|
6
|
+
httparty (~> 0.21.0)
|
7
|
+
nokogiri (~> 1.16.3)
|
7
8
|
|
8
9
|
GEM
|
9
10
|
remote: https://rubygems.org/
|
@@ -21,10 +22,10 @@ GEM
|
|
21
22
|
erubi (~> 1.4)
|
22
23
|
rails-dom-testing (~> 2.0)
|
23
24
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
24
|
-
active_attr (0.
|
25
|
-
actionpack (>= 3.0.2, < 7.
|
26
|
-
activemodel (>= 3.0.2, < 7.
|
27
|
-
activesupport (>= 3.0.2, < 7.
|
25
|
+
active_attr (0.16.0)
|
26
|
+
actionpack (>= 3.0.2, < 7.2)
|
27
|
+
activemodel (>= 3.0.2, < 7.2)
|
28
|
+
activesupport (>= 3.0.2, < 7.2)
|
28
29
|
activemodel (7.0.4)
|
29
30
|
activesupport (= 7.0.4)
|
30
31
|
activesupport (7.0.4)
|
@@ -32,19 +33,21 @@ GEM
|
|
32
33
|
i18n (>= 1.6, < 2)
|
33
34
|
minitest (>= 5.1)
|
34
35
|
tzinfo (~> 2.0)
|
35
|
-
addressable (2.8.
|
36
|
+
addressable (2.8.6)
|
36
37
|
public_suffix (>= 2.0.2, < 6.0)
|
37
38
|
ansi (1.5.0)
|
39
|
+
bigdecimal (3.1.7)
|
38
40
|
builder (3.2.4)
|
39
41
|
coderay (1.1.3)
|
40
42
|
concurrent-ruby (1.1.10)
|
41
|
-
crack (0.
|
43
|
+
crack (1.0.0)
|
44
|
+
bigdecimal
|
42
45
|
rexml
|
43
46
|
crass (1.0.6)
|
44
47
|
erubi (1.11.0)
|
45
|
-
hashdiff (1.0
|
46
|
-
httparty (0.
|
47
|
-
|
48
|
+
hashdiff (1.1.0)
|
49
|
+
httparty (0.21.0)
|
50
|
+
mini_mime (>= 1.0.0)
|
48
51
|
multi_xml (>= 0.5.2)
|
49
52
|
i18n (1.12.0)
|
50
53
|
concurrent-ruby (~> 1.0)
|
@@ -52,25 +55,30 @@ GEM
|
|
52
55
|
crass (~> 1.0.2)
|
53
56
|
nokogiri (>= 1.5.9)
|
54
57
|
method_source (1.0.0)
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
minitest (
|
59
|
-
minitest-focus (1.1.2)
|
58
|
+
mini_mime (1.1.5)
|
59
|
+
mini_portile2 (2.8.5)
|
60
|
+
minitest (5.22.3)
|
61
|
+
minitest-focus (1.4.0)
|
60
62
|
minitest (>= 4, < 6)
|
61
|
-
minitest-reporters (1.
|
63
|
+
minitest-reporters (1.6.1)
|
62
64
|
ansi
|
63
65
|
builder
|
64
66
|
minitest (>= 5.0)
|
65
67
|
ruby-progressbar
|
66
|
-
mocha (1.
|
68
|
+
mocha (2.1.0)
|
69
|
+
ruby2_keywords (>= 0.0.5)
|
67
70
|
multi_xml (0.6.0)
|
68
|
-
nokogiri (1.
|
71
|
+
nokogiri (1.16.3)
|
72
|
+
mini_portile2 (~> 2.8.2)
|
69
73
|
racc (~> 1.4)
|
70
|
-
|
74
|
+
nokogiri (1.16.3-arm64-darwin)
|
75
|
+
racc (~> 1.4)
|
76
|
+
nokogiri (1.16.3-x86_64-linux)
|
77
|
+
racc (~> 1.4)
|
78
|
+
pry (0.14.2)
|
71
79
|
coderay (~> 1.1)
|
72
80
|
method_source (~> 1.0)
|
73
|
-
public_suffix (5.0.
|
81
|
+
public_suffix (5.0.4)
|
74
82
|
racc (1.6.1)
|
75
83
|
rack (2.2.4)
|
76
84
|
rack-test (2.0.2)
|
@@ -80,31 +88,34 @@ GEM
|
|
80
88
|
nokogiri (>= 1.6)
|
81
89
|
rails-html-sanitizer (1.4.4)
|
82
90
|
loofah (~> 2.19, >= 2.19.1)
|
83
|
-
rake (13.0
|
84
|
-
rexml (3.2.
|
85
|
-
ruby-progressbar (1.
|
86
|
-
|
91
|
+
rake (13.1.0)
|
92
|
+
rexml (3.2.6)
|
93
|
+
ruby-progressbar (1.13.0)
|
94
|
+
ruby2_keywords (0.0.5)
|
95
|
+
timecop (0.9.8)
|
87
96
|
tzinfo (2.0.5)
|
88
97
|
concurrent-ruby (~> 1.0)
|
89
|
-
webmock (3.
|
90
|
-
addressable (>= 2.
|
98
|
+
webmock (3.23.0)
|
99
|
+
addressable (>= 2.8.0)
|
91
100
|
crack (>= 0.3.2)
|
92
101
|
hashdiff (>= 0.4.0, < 2.0.0)
|
93
102
|
|
94
103
|
PLATFORMS
|
95
104
|
arm64-darwin-20
|
105
|
+
arm64-darwin-23
|
106
|
+
ruby
|
107
|
+
x86_64-linux
|
96
108
|
|
97
109
|
DEPENDENCIES
|
98
|
-
|
99
|
-
minitest (~>
|
100
|
-
minitest-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
rake (~> 13.0)
|
110
|
+
minitest (~> 5.22.3)
|
111
|
+
minitest-focus (~> 1.4.0)
|
112
|
+
minitest-reporters (~> 1.6.1)
|
113
|
+
mocha (~> 2.1.0)
|
114
|
+
pry (~> 0.14.2)
|
115
|
+
rake (~> 13.1.0)
|
105
116
|
south_african_air_quality_index!
|
106
|
-
timecop (~> 0.9.
|
107
|
-
webmock (~> 3.
|
117
|
+
timecop (~> 0.9.8)
|
118
|
+
webmock (~> 3.23.0)
|
108
119
|
|
109
120
|
BUNDLED WITH
|
110
|
-
2.
|
121
|
+
2.4.17
|
data/README.md
CHANGED
@@ -46,7 +46,7 @@ Or install it yourself as:
|
|
46
46
|
end_date = Time.now
|
47
47
|
client.station_report(station_name, start_date, end_date)
|
48
48
|
|
49
|
-
# To get a report from multiple stations at once
|
49
|
+
# To get a report from multiple stations at once (HTML is returned for now)
|
50
50
|
# Some defaults that are used:
|
51
51
|
# interval: DEFAULT_INTERVAL (60)
|
52
52
|
# report_type: REPORT_TYPE (average)
|
@@ -4,9 +4,10 @@ module SouthAfricanAirQualityIndex
|
|
4
4
|
|
5
5
|
attr_reader :base_path, :port, :stations
|
6
6
|
|
7
|
-
def initialize(base_path: BASE_PATH, port:
|
7
|
+
def initialize(base_path: BASE_PATH, port: BASE_PORT)
|
8
8
|
@base_path = base_path
|
9
9
|
@port = port
|
10
|
+
@cookie = authorise
|
10
11
|
end
|
11
12
|
|
12
13
|
def self.compatible_api_version
|
@@ -15,56 +16,91 @@ module SouthAfricanAirQualityIndex
|
|
15
16
|
|
16
17
|
# This is the version of the API docs this client was built off-of
|
17
18
|
def self.api_version
|
18
|
-
'v1
|
19
|
+
'v1 2024-03-18'
|
19
20
|
end
|
20
21
|
|
21
22
|
# Endpoints
|
23
|
+
def regions
|
24
|
+
return @regions if @regions
|
25
|
+
|
26
|
+
response = send_request(http_method: :get, path: '/v1/envista/regions', port: DATA_SOURCE_PORT, port_in_path: true)
|
27
|
+
|
28
|
+
if response["code"] != 200
|
29
|
+
puts "Fallback SAAQIS region fetch!"
|
30
|
+
@regions ||= fetch_regions_from_html
|
31
|
+
else
|
32
|
+
@regions ||= response["body"]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def fetch_regions_from_html
|
37
|
+
# https://saaqis.environment.gov.za/Report/HourlyReports
|
38
|
+
response = send_request(http_method: :get, path: 'Report/HourlyReports')
|
39
|
+
doc = Nokogiri::HTML(response["body"])
|
40
|
+
|
41
|
+
# JSON.parse(content).map { |j| j.dig("stations")}.flatten
|
42
|
+
# alex = JSON.parse(content).map { |j| j.dig("stations")}.flatten.select { |st| st["name"] == "Alexandra-NAQI" }.first
|
43
|
+
find_and_parse_m_regions(doc)
|
44
|
+
end
|
22
45
|
|
23
46
|
# Memoize stations as they are unlikely to change often
|
24
47
|
def stations
|
25
48
|
# This endpoint is no longer active:
|
26
|
-
@stations ||=
|
49
|
+
# @stations ||= send_request(http_method: :get, path: 'ajax/getAllStations')
|
50
|
+
|
51
|
+
@stations ||= regions.map { |regions| regions["stations"] }.flatten.uniq
|
27
52
|
end
|
28
53
|
|
29
54
|
def stations_from_code(codes, build_for_response: false)
|
30
|
-
|
31
|
-
codes
|
55
|
+
unless codes.is_a?(Array)
|
56
|
+
codes = [codes]
|
57
|
+
end
|
58
|
+
|
59
|
+
stations.select do |station|
|
60
|
+
codes.map(&:to_s).include?(station["stationId"].to_s)
|
32
61
|
end
|
33
62
|
end
|
34
63
|
|
35
64
|
def selected_stations(station_names)
|
36
|
-
|
65
|
+
unless station_names.is_a?(Array)
|
66
|
+
station_names = [station_names]
|
67
|
+
end
|
68
|
+
|
69
|
+
stations.select do |station|
|
37
70
|
station_matches?(station_names, station)
|
38
71
|
end
|
39
72
|
end
|
40
73
|
|
41
|
-
def station_report(station_name, start_date, end_date, interval: DEFAULT_INTERVAL, report_type: REPORT_TYPE)
|
74
|
+
def station_report(station_name, start_date, end_date, interval: DEFAULT_INTERVAL, report_type: REPORT_TYPE, precent_valid: DEFAULT_PERCENT_VALID)
|
42
75
|
station = selected_stations([station_name]).first
|
43
76
|
return if station.empty?
|
44
77
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
}.to_json
|
78
|
+
params = {
|
79
|
+
filterChannels: fetch_monitor_ids(station),
|
80
|
+
from: parse_time(start_date.to_s),
|
81
|
+
to: parse_time(end_date.to_s),
|
82
|
+
fromTimebase: interval,
|
83
|
+
toTimebase: interval,
|
84
|
+
precentValid: precent_valid,
|
85
|
+
timeBeginning: false,
|
86
|
+
useBackWard: true,
|
87
|
+
unitConversion: false,
|
88
|
+
includeSummary: true,
|
89
|
+
onlySummary: false, # TODO: Parameter?
|
90
|
+
}
|
59
91
|
|
60
|
-
|
92
|
+
path = "v1/envista/stations/#{station['stationId']}/#{report_type}"
|
93
|
+
send_request(http_method: :get, path: path, params: params, port: DATA_SOURCE_PORT, port_in_path: true)
|
61
94
|
end
|
62
95
|
|
96
|
+
# This now will only return HTML
|
97
|
+
# TODO: Parse the HTML
|
98
|
+
# May not work:
|
63
99
|
def multi_station_report(station_names, start_date, end_date, interval: DEFAULT_INTERVAL, report_type: REPORT_TYPE)
|
64
100
|
extracted_stations = selected_stations(station_names)
|
65
101
|
|
66
102
|
monitor_channels_by_station_id = extracted_stations.map { |station|
|
67
|
-
[station['
|
103
|
+
[station['stationId'].to_s, fetch_monitor_ids(station)]
|
68
104
|
}.to_h
|
69
105
|
|
70
106
|
body = {
|
@@ -88,19 +124,21 @@ module SouthAfricanAirQualityIndex
|
|
88
124
|
body = body.merge(hsh)
|
89
125
|
end
|
90
126
|
|
91
|
-
|
127
|
+
send_request(http_method: :get, path: 'report/MultiStationTable', body: body.to_json)
|
92
128
|
end
|
93
129
|
|
94
130
|
private
|
95
131
|
|
96
|
-
def
|
132
|
+
def send_request(http_method:, path:, body: {}, params: {}, headers: {}, port: @port, port_in_path: false)
|
97
133
|
start_time = micro_second_time
|
98
134
|
|
135
|
+
headers["Cookie"] = @cookie
|
136
|
+
|
99
137
|
response = HTTParty.send(
|
100
138
|
http_method.to_sym,
|
101
|
-
construct_base_path(path, params),
|
139
|
+
construct_base_path(path, params, port, port_in_path),
|
102
140
|
body: body,
|
103
|
-
headers: { 'Content-Type': 'application/json' },
|
141
|
+
headers: headers.merge({ 'Content-Type': 'application/json' }),
|
104
142
|
port: port,
|
105
143
|
format: :json
|
106
144
|
)
|
@@ -109,9 +147,19 @@ module SouthAfricanAirQualityIndex
|
|
109
147
|
construct_response_object(response, path, start_time, end_time)
|
110
148
|
end
|
111
149
|
|
150
|
+
# Quick n dirty time parsing
|
151
|
+
def parse_time(str_time)
|
152
|
+
time_components = str_time.to_s.split(' ')
|
153
|
+
|
154
|
+
# Have to leave out the timezone - #{time_components[2]}
|
155
|
+
"#{time_components[0]}T#{time_components[1]}"
|
156
|
+
end
|
157
|
+
|
112
158
|
def construct_response_object(response, path, start_time, end_time)
|
113
159
|
{
|
114
160
|
'body' => parse_body(response, path),
|
161
|
+
'code' => response.code,
|
162
|
+
'cookies' => response.headers.dig('set-cookie'),
|
115
163
|
'headers' => response.headers,
|
116
164
|
'metadata' => construct_metadata(response, start_time, end_time)
|
117
165
|
}
|
@@ -131,8 +179,12 @@ module SouthAfricanAirQualityIndex
|
|
131
179
|
(Time.now.to_f * 1_000_000).to_i
|
132
180
|
end
|
133
181
|
|
134
|
-
def construct_base_path(path, params)
|
135
|
-
|
182
|
+
def construct_base_path(path, params, port, port_in_path)
|
183
|
+
if port_in_path
|
184
|
+
constructed_path = "#{base_path}:#{port}/#{path}"
|
185
|
+
else
|
186
|
+
constructed_path = "#{base_path}/#{path}"
|
187
|
+
end
|
136
188
|
|
137
189
|
if params == {}
|
138
190
|
constructed_path
|
@@ -145,6 +197,8 @@ module SouthAfricanAirQualityIndex
|
|
145
197
|
JSON.parse(response.body) # Purposely not using HTTParty
|
146
198
|
rescue JSON::ParserError => _e
|
147
199
|
response.body
|
200
|
+
rescue TypeError => _e
|
201
|
+
nil
|
148
202
|
end
|
149
203
|
|
150
204
|
def process_params(params)
|
@@ -168,12 +222,89 @@ module SouthAfricanAirQualityIndex
|
|
168
222
|
|
169
223
|
def fetch_monitor_ids(station)
|
170
224
|
station['monitors'].map do |monitor|
|
171
|
-
monitor['
|
225
|
+
monitor['channelId']
|
172
226
|
end
|
173
227
|
end
|
174
228
|
|
175
229
|
def process_station(name)
|
176
230
|
name.to_s.downcase.gsub(' ', ' ')
|
177
231
|
end
|
232
|
+
|
233
|
+
def find_and_parse_m_regions(doc)
|
234
|
+
doc.xpath('//script').each do |script|
|
235
|
+
if script.content.include?("m_Regions")
|
236
|
+
content = script.content[/let\s+m_Regions\s*=\s*(.*?)\s*;/, 1]
|
237
|
+
return JSON.parse(content) if content
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
nil
|
242
|
+
end
|
243
|
+
|
244
|
+
def authorise
|
245
|
+
generate_token(get_api_token)
|
246
|
+
end
|
247
|
+
|
248
|
+
# This is terrible. Unsure why there is a JWT, since there is no secret
|
249
|
+
# and this is public information.
|
250
|
+
def generate_token(api_token)
|
251
|
+
headers = {
|
252
|
+
'Authorization': "ApiToken #{api_token}",
|
253
|
+
'Accept': "application/json",
|
254
|
+
'Content-Length': '0',
|
255
|
+
'Host': BASE_URI,
|
256
|
+
# 'envi-data-source': 'SAAQIS_ENVISTA',
|
257
|
+
# 'Access-Control-Allow-Origin': 'https://saaqis.environment.gov.za',
|
258
|
+
# 'Access-Control-Allow-Credentials': 'true',
|
259
|
+
# 'Authority': "#{BASE_URI}:#{DATA_SOURCE_PORT}",
|
260
|
+
}
|
261
|
+
|
262
|
+
res = send_request(http_method: :post, path: 'v1/GenerateToken', headers: headers, port: DATA_SOURCE_PORT, port_in_path: true)
|
263
|
+
|
264
|
+
@cookie ||= res["cookies"].first
|
265
|
+
end
|
266
|
+
|
267
|
+
def get_api_token
|
268
|
+
# Account/GetApiToken
|
269
|
+
body = { "userName": "Guest" }
|
270
|
+
res = send_request(http_method: :post, path: 'Account/GetApiToken', body: body.to_json)
|
271
|
+
|
272
|
+
res.dig("body")
|
273
|
+
end
|
274
|
+
|
275
|
+
# Experimental stuff
|
276
|
+
def generate_jwt
|
277
|
+
# header = {
|
278
|
+
# "alg": "HS256",
|
279
|
+
# "typ": "JWT"
|
280
|
+
# }
|
281
|
+
|
282
|
+
time_now = Time.now
|
283
|
+
|
284
|
+
payload = {
|
285
|
+
"unique_name": "Guest",
|
286
|
+
"nbf": time_now.to_i,
|
287
|
+
"exp": (time_now + 3600).to_i,
|
288
|
+
"iat": time_now.to_i
|
289
|
+
}
|
290
|
+
|
291
|
+
# IMPORTANT: set nil as password parameter
|
292
|
+
# token = JWT.encode payload, nil, 'none'
|
293
|
+
|
294
|
+
# hmac_secret = ""
|
295
|
+
# token = JWT.encode payload, hmac_secret, 'HS256'
|
296
|
+
|
297
|
+
# token = JWT.encode payload, nil, 'none', { typ: 'JWT' }
|
298
|
+
# token = JWT.encode payload, nil, 'HS256', { typ: 'JWT' }
|
299
|
+
|
300
|
+
hmac_secret = 'ApiToken '
|
301
|
+
_token = JWT.encode payload, hmac_secret, 'HS256', { typ: 'JWT' }
|
302
|
+
|
303
|
+
|
304
|
+
# Account/GetApiToken
|
305
|
+
# v1/GenerateToken
|
306
|
+
|
307
|
+
authorization = "ApiToken " + res
|
308
|
+
end
|
178
309
|
end
|
179
310
|
end
|
@@ -1,8 +1,13 @@
|
|
1
1
|
module SouthAfricanAirQualityIndex
|
2
2
|
module Constants
|
3
|
-
|
3
|
+
BASE_URI = 'saaqis.environment.gov.za'
|
4
|
+
BASE_PATH = "https://#{BASE_URI}"
|
5
|
+
|
6
|
+
BASE_PORT = 443
|
7
|
+
DATA_SOURCE_PORT = 44301
|
4
8
|
|
5
9
|
DEFAULT_INTERVAL = 60
|
10
|
+
DEFAULT_PERCENT_VALID = 75
|
6
11
|
STATION_REPORT = 'station report'.freeze
|
7
12
|
HOURLY_REPORT = 'hourly report'.freeze
|
8
13
|
REPORT_TYPE = 'Average'.freeze
|
data/notes.txt
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
|
1
2
|
https://aqicn.org/city/south-africa/ekurhuleni/bedfordview/
|
2
3
|
https://saaqis.environment.gov.za/
|
3
4
|
|
@@ -173,4 +174,169 @@ Types of SA Air Quality reports
|
|
173
174
|
- Index Report (AQI)
|
174
175
|
- Matrix Report (1 station 1 metric gives stats)
|
175
176
|
|
177
|
+
March 2024
|
178
|
+
https://saaqis.environment.gov.za/ajax/getAllStationsNew
|
179
|
+
|
180
|
+
curl 'https://saaqis.environment.gov.za/Report/stationreport?InPopUp=True' \
|
181
|
+
-H 'authority: saaqis.environment.gov.za' \
|
182
|
+
-H 'accept: */*' \
|
183
|
+
-H 'accept-language: en-GB,en-US;q=0.9,en;q=0.8' \
|
184
|
+
-H 'cookie: ASP.NET_SessionId=vldu0doftifewm5f1wrubrme; __RequestVerificationToken=mb7uM--kGvUTsScjOUsGIopNIJCn7BBY1kXuniYsvniLixU_TfQNWBc9nbi9uMbSX9lpIIHVf0s_-zMXNPjEKnMD6ZjVJvCHsS8thCvNVnI1; __FormVerificationToken=owO78ynW81P2O9ZDkqK0K30cT-MmY8bISAkF4yseane_nFfruM3Uvc1AVhk-3PDDnL4JcVatG1ob8Yy3wuAkid1LqvzuXoOmON7cMwv1nRY1; X-Access-Token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6Ikd1ZXN0IiwibmJmIjoxNzEwNTE3MTIzLCJleHAiOjE3MTA1MjA3MjMsImlhdCI6MTcxMDUxNzEyM30.aE39-GM-zc0PNlUJAukb37wGn7DuKUup2Qirq6UT3pA' \
|
185
|
+
-H 'dnt: 1' \
|
186
|
+
-H 'referer: https://saaqis.environment.gov.za/' \
|
187
|
+
-H 'sec-ch-ua: "Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121"' \
|
188
|
+
-H 'sec-ch-ua-mobile: ?0' \
|
189
|
+
-H 'sec-ch-ua-platform: "macOS"' \
|
190
|
+
-H 'sec-fetch-dest: empty' \
|
191
|
+
-H 'sec-fetch-mode: cors' \
|
192
|
+
-H 'sec-fetch-site: same-origin' \
|
193
|
+
-H 'sec-gpc: 1' \
|
194
|
+
-H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36' \
|
195
|
+
-H 'x-requested-with: XMLHttpRequest' \
|
196
|
+
-H 'x-requestverificationtoken: owO78ynW81P2O9ZDkqK0K30cT-MmY8bISAkF4yseane_nFfruM3Uvc1AVhk-3PDDnL4JcVatG1ob8Yy3wuAkid1LqvzuXoOmON7cMwv1nRY1' \
|
197
|
+
--compressed
|
198
|
+
|
199
|
+
curl 'https://saaqis.environment.gov.za/home/getPage?pageName=Hourly%20Monitoring%20Data&InPopUp=true' \
|
200
|
+
-H 'authority: saaqis.environment.gov.za' \
|
201
|
+
-H 'accept: */*' \
|
202
|
+
-H 'accept-language: en-GB,en-US;q=0.9,en;q=0.8' \
|
203
|
+
-H 'cookie: ASP.NET_SessionId=vldu0doftifewm5f1wrubrme; __RequestVerificationToken=VMM7f3rhky_AQ7cea4DpzOpnLa6VwibqHEiuFpB7QvpIKIhA3iweLsxtcUaFDTcfzRwBJAA477qe82Q1xELh1W5wNJ_g1QvRmUz4E4YYZEs1; __FormVerificationToken=CPVZjs1Bzr7xBI9fECT96iKK8auAmA21WS2j9o_ZiV58YoIcOoBqWSAyvmfG-HfcWFRsjpik55_672rbNNx3Jd-bADn0Zk17pkgGzQk1K7I1; X-Access-Token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6Ikd1ZXN0IiwibmJmIjoxNzEwNTE3MjMwLCJleHAiOjE3MTA1MjA4MzAsImlhdCI6MTcxMDUxNzIzMH0.5JNuKp15f0w9BQIpMwOiTc6Gx_3Gug3YD7i2efBwFE0' \
|
204
|
+
-H 'dnt: 1' \
|
205
|
+
-H 'referer: https://saaqis.environment.gov.za/' \
|
206
|
+
-H 'sec-ch-ua: "Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121"' \
|
207
|
+
-H 'sec-ch-ua-mobile: ?0' \
|
208
|
+
-H 'sec-ch-ua-platform: "macOS"' \
|
209
|
+
-H 'sec-fetch-dest: empty' \
|
210
|
+
-H 'sec-fetch-mode: cors' \
|
211
|
+
-H 'sec-fetch-site: same-origin' \
|
212
|
+
-H 'sec-gpc: 1' \
|
213
|
+
-H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36' \
|
214
|
+
-H 'x-requested-with: XMLHttpRequest' \
|
215
|
+
-H 'x-requestverificationtoken: CPVZjs1Bzr7xBI9fECT96iKK8auAmA21WS2j9o_ZiV58YoIcOoBqWSAyvmfG-HfcWFRsjpik55_672rbNNx3Jd-bADn0Zk17pkgGzQk1K7I1' \
|
216
|
+
--compressed
|
217
|
+
|
218
|
+
|
219
|
+
Needs cookie and JWT:
|
176
220
|
|
221
|
+
curl 'https://saaqis.environment.gov.za:44301/v1/envista/regions' \
|
222
|
+
-H 'authority: saaqis.environment.gov.za:44301' \
|
223
|
+
-H 'accept: application/json' \
|
224
|
+
-H 'accept-language: en-GB,en-US;q=0.9,en;q=0.8' \
|
225
|
+
-H 'access-control-allow-credentials: true' \
|
226
|
+
-H 'access-control-allow-origin: https://saaqis.environment.gov.za' \
|
227
|
+
-H 'authorization: JwtToken' \
|
228
|
+
-H 'cache-control: no-cache' \
|
229
|
+
-H 'compression: gzip' \
|
230
|
+
-H 'content-type: application/json; charset=utf-8' \
|
231
|
+
-H 'contentlength: 0' \
|
232
|
+
-H 'cookie: ASP.NET_SessionId=vldu0doftifewm5f1wrubrme; __RequestVerificationToken=u6thajdYfxMhX6czeh1L60HP3r_pGsGLqyXPwpBxYVuXLGbHqLEs0vyA0TX4kv3xHD9JcuP4cLxxWZvvVzwCG1V1F8H6VrUjuxWw7-qaMhg1; __FormVerificationToken=bpDKkVnfQ8bgG159kuknJXr9GvkzplWNAB18bKodU7O5oAJn0nQ1Q3rGyAsAydvMo1LM0EB6sCmOF9uGTrMeyFRcYyehUA03ZJbvLij_oBI1; X-Access-Token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6Ikd1ZXN0IiwibmJmIjoxNzEwNTE4MjMzLCJleHAiOjE3MTA1MjE4MzMsImlhdCI6MTcxMDUxODIzM30.ESillaQmk8cJBuUFUcOCoC5c0HeOAT5ix9m98zKiXLc' \
|
233
|
+
-H 'dnt: 1' \
|
234
|
+
-H 'domainname;' \
|
235
|
+
-H 'envi-data-source: SAAQIS_ENVISTA' \
|
236
|
+
-H 'origin: https://saaqis.environment.gov.za' \
|
237
|
+
-H 'pragma: no-cache' \
|
238
|
+
-H 'referer: https://saaqis.environment.gov.za/' \
|
239
|
+
-H 'sec-ch-ua: "Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121"' \
|
240
|
+
-H 'sec-ch-ua-mobile: ?0' \
|
241
|
+
-H 'sec-ch-ua-platform: "macOS"' \
|
242
|
+
-H 'sec-fetch-dest: empty' \
|
243
|
+
-H 'sec-fetch-mode: cors' \
|
244
|
+
-H 'sec-fetch-site: same-site' \
|
245
|
+
-H 'sec-gpc: 1' \
|
246
|
+
-H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36' \
|
247
|
+
-H 'x-requestverificationtoken: bpDKkVnfQ8bgG159kuknJXr9GvkzplWNAB18bKodU7O5oAJn0nQ1Q3rGyAsAydvMo1LM0EB6sCmOF9uGTrMeyFRcYyehUA03ZJbvLij_oBI1' \
|
248
|
+
--compressed
|
249
|
+
|
250
|
+
|
251
|
+
[
|
252
|
+
{
|
253
|
+
"regionId": 0,
|
254
|
+
"name": "None",
|
255
|
+
"stations": []
|
256
|
+
},
|
257
|
+
{
|
258
|
+
"regionId": 1,
|
259
|
+
"name": "Mpumalanga",
|
260
|
+
"stations": [
|
261
|
+
{
|
262
|
+
"stationId": 363,
|
263
|
+
"name": "Eskom-Wilge",
|
264
|
+
"shortName": "Wilge",
|
265
|
+
"stationsTag": "(null)",
|
266
|
+
"location": {
|
267
|
+
"latitude": -25.975444444,
|
268
|
+
"longitude": 28.985611
|
269
|
+
},
|
270
|
+
"timebase": 1,
|
271
|
+
"active": true,
|
272
|
+
"owner": "Eskom",
|
273
|
+
"ownerId": 6,
|
274
|
+
"regionId": 1,
|
275
|
+
"monitors": [
|
276
|
+
{
|
277
|
+
"channelId": 1,
|
278
|
+
"name": "Amb Pressure",
|
279
|
+
"alias": null,
|
280
|
+
"active": false,
|
281
|
+
"typeId": 71,
|
282
|
+
"pollutantId": 36,
|
283
|
+
"units": "mBar",
|
284
|
+
"unitID": 40,
|
285
|
+
"description": null,
|
286
|
+
"mapView": true,
|
287
|
+
"isIndex": false,
|
288
|
+
"PollutantCategory": 2,
|
289
|
+
"NumericFormat": "5.0",
|
290
|
+
"LowRange": 0.0,
|
291
|
+
"HighRange": 100.0,
|
292
|
+
"state": 1,
|
293
|
+
"PctValid": 75,
|
294
|
+
"MonitorTitle": "tl_BP",
|
295
|
+
"MON_StartDate": "10/17/2023 2:57:58 PM",
|
296
|
+
"MON_EndDate": "12/31/9999 11:59:59 PM"
|
297
|
+
},
|
298
|
+
{
|
299
|
+
"channelId": 2,
|
300
|
+
"name": "Amb RelHum",
|
301
|
+
"alias": null,
|
302
|
+
"active": false,
|
303
|
+
"typeId": 69,
|
304
|
+
"pollutantId": 18,
|
305
|
+
"units": "%",
|
306
|
+
"unitID": 1,
|
307
|
+
"description": null,
|
308
|
+
"mapView": true,
|
309
|
+
"isIndex": false,
|
310
|
+
"PollutantCategory": 2,
|
311
|
+
"NumericFormat": "5.2",
|
312
|
+
"LowRange": 0.0,
|
313
|
+
"HighRange": 100.0,
|
314
|
+
"state": 1,
|
315
|
+
"PctValid": 75,
|
316
|
+
"MonitorTitle": "tl_RH",
|
317
|
+
"MON_StartDate": "10/17/2023 2:57:58 PM",
|
318
|
+
"MON_EndDate": "12/31/9999 11:59:59 PM"
|
319
|
+
},
|
320
|
+
|
321
|
+
|
322
|
+
curl 'https://saaqis.environment.gov.za/report/MultiStationTable' \
|
323
|
+
-H 'authority: saaqis.environment.gov.za' \
|
324
|
+
-H 'accept: */*' \
|
325
|
+
-H 'accept-language: en-GB,en-US;q=0.9,en;q=0.8' \
|
326
|
+
-H 'content-type: application/json; charset=UTF-8' \
|
327
|
+
-H 'cookie: ASP.NET_SessionId=vldu0doftifewm5f1wrubrme; __RequestVerificationToken=u6thajdYfxMhX6czeh1L60HP3r_pGsGLqyXPwpBxYVuXLGbHqLEs0vyA0TX4kv3xHD9JcuP4cLxxWZvvVzwCG1V1F8H6VrUjuxWw7-qaMhg1; __FormVerificationToken=bpDKkVnfQ8bgG159kuknJXr9GvkzplWNAB18bKodU7O5oAJn0nQ1Q3rGyAsAydvMo1LM0EB6sCmOF9uGTrMeyFRcYyehUA03ZJbvLij_oBI1; X-Access-Token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6Ikd1ZXN0IiwibmJmIjoxNzEwNTE4MjMzLCJleHAiOjE3MTA1MjE4MzMsImlhdCI6MTcxMDUxODIzM30.ESillaQmk8cJBuUFUcOCoC5c0HeOAT5ix9m98zKiXLc' \
|
328
|
+
-H 'dnt: 1' \
|
329
|
+
-H 'origin: https://saaqis.environment.gov.za' \
|
330
|
+
-H 'referer: https://saaqis.environment.gov.za/' \
|
331
|
+
-H 'sec-ch-ua: "Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121"' \
|
332
|
+
-H 'sec-ch-ua-mobile: ?0' \
|
333
|
+
-H 'sec-ch-ua-platform: "macOS"' \
|
334
|
+
-H 'sec-fetch-dest: empty' \
|
335
|
+
-H 'sec-fetch-mode: cors' \
|
336
|
+
-H 'sec-fetch-site: same-origin' \
|
337
|
+
-H 'sec-gpc: 1' \
|
338
|
+
-H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36' \
|
339
|
+
-H 'x-requested-with: XMLHttpRequest' \
|
340
|
+
-H 'x-requestverificationtoken: bpDKkVnfQ8bgG159kuknJXr9GvkzplWNAB18bKodU7O5oAJn0nQ1Q3rGyAsAydvMo1LM0EB6sCmOF9uGTrMeyFRcYyehUA03ZJbvLij_oBI1' \
|
341
|
+
--data-raw '{"m_ReportConfig":{"reportName":"station report","reportType":"Average","actualReportType":"Average","startDate":"14/03/2024 00:01","endDate":"15/03/2024 00:00","startDateAbsolute":"14/03/2024 00:01","endDateAbsolute":"15/03/2024 00:00","fromTb":60,"toTb":60,"MonitorsChannels":[1,7,8,9,23,25,27,28,29,31],"StationId":73,"monitorChannelsByStationId":{"73":[1,7,8,9,23,25,27,28,29,31]},"monitorChannelsByStationId[0].Key":"73","monitorChannelsByStationId[0].Value":[1,7,8,9,23,25,27,28,29,31]},"reportConfig":{"reportName":"station report","reportType":"Average","actualReportType":"Average","startDate":"14/03/2024 00:01","endDate":"15/03/2024 00:00","startDateAbsolute":"14/03/2024 00:01","endDateAbsolute":"15/03/2024 00:00","fromTb":60,"toTb":60,"MonitorsChannels":[1,7,8,9,23,25,27,28,29,31],"StationId":73,"monitorChannelsByStationId":{"73":[1,7,8,9,23,25,27,28,29,31]},"monitorChannelsByStationId[0].Key":"73","monitorChannelsByStationId[0].Value":[1,7,8,9,23,25,27,28,29,31]},"InPopUp":true,"isSummaryOnBottomTable":true}' \
|
342
|
+
--compressed
|
@@ -22,17 +22,18 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
23
|
spec.require_paths = ["lib"]
|
24
24
|
|
25
|
-
spec.add_dependency "httparty", "~> 0.
|
26
|
-
spec.add_dependency "active_attr", "~> 0.
|
25
|
+
spec.add_dependency "httparty", "~> 0.21.0"
|
26
|
+
spec.add_dependency "active_attr", "~> 0.16.0"
|
27
|
+
# spec.add_dependency "jwt", "~> 2.8.1"
|
28
|
+
spec.add_dependency "nokogiri", "~> 1.16.3"
|
27
29
|
|
28
30
|
# Development dependancies
|
29
|
-
spec.add_development_dependency "
|
30
|
-
spec.add_development_dependency "
|
31
|
-
spec.add_development_dependency "minitest", "~>
|
32
|
-
spec.add_development_dependency "minitest-
|
33
|
-
spec.add_development_dependency "
|
34
|
-
spec.add_development_dependency "
|
35
|
-
spec.add_development_dependency "
|
36
|
-
spec.add_development_dependency "
|
37
|
-
spec.add_development_dependency "webmock", "~> 3.8.3"
|
31
|
+
spec.add_development_dependency "rake", "~> 13.1.0"
|
32
|
+
spec.add_development_dependency "minitest", "~> 5.22.3"
|
33
|
+
spec.add_development_dependency "minitest-focus", "~> 1.4.0"
|
34
|
+
spec.add_development_dependency "minitest-reporters", "~> 1.6.1"
|
35
|
+
spec.add_development_dependency "timecop", "~> 0.9.8"
|
36
|
+
spec.add_development_dependency "mocha", "~> 2.1.0"
|
37
|
+
spec.add_development_dependency "pry", "~> 0.14.2"
|
38
|
+
spec.add_development_dependency "webmock", "~> 3.23.0"
|
38
39
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: south_african_air_quality_index
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- trex22
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-03-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -16,154 +16,154 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.21.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 0.21.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: active_attr
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 0.16.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 0.16.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: nokogiri
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
48
|
-
type: :
|
47
|
+
version: 1.16.3
|
48
|
+
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 1.16.3
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rake
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 13.1.0
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: 13.1.0
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: minitest
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
75
|
+
version: 5.22.3
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
82
|
+
version: 5.22.3
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: minitest-focus
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: 1.
|
89
|
+
version: 1.4.0
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: 1.
|
96
|
+
version: 1.4.0
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: minitest-reporters
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 1.
|
103
|
+
version: 1.6.1
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 1.
|
110
|
+
version: 1.6.1
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: timecop
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 0.9.
|
117
|
+
version: 0.9.8
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: 0.9.
|
124
|
+
version: 0.9.8
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: mocha
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: 1.
|
131
|
+
version: 2.1.0
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: 1.
|
138
|
+
version: 2.1.0
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: pry
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
143
|
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: 0.14.
|
145
|
+
version: 0.14.2
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: 0.14.
|
152
|
+
version: 0.14.2
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: webmock
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
156
156
|
requirements:
|
157
157
|
- - "~>"
|
158
158
|
- !ruby/object:Gem::Version
|
159
|
-
version: 3.
|
159
|
+
version: 3.23.0
|
160
160
|
type: :development
|
161
161
|
prerelease: false
|
162
162
|
version_requirements: !ruby/object:Gem::Requirement
|
163
163
|
requirements:
|
164
164
|
- - "~>"
|
165
165
|
- !ruby/object:Gem::Version
|
166
|
-
version: 3.
|
166
|
+
version: 3.23.0
|
167
167
|
description: A client for using the South African Air Quality Index API in Ruby. This
|
168
168
|
is an unofficial project.
|
169
169
|
email:
|
@@ -173,6 +173,7 @@ extensions: []
|
|
173
173
|
extra_rdoc_files: []
|
174
174
|
files:
|
175
175
|
- ".gitignore"
|
176
|
+
- ".ruby-version"
|
176
177
|
- CODE_OF_CONDUCT.md
|
177
178
|
- Gemfile
|
178
179
|
- Gemfile.lock
|
@@ -206,7 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
206
207
|
- !ruby/object:Gem::Version
|
207
208
|
version: '0'
|
208
209
|
requirements: []
|
209
|
-
rubygems_version: 3.3
|
210
|
+
rubygems_version: 3.5.3
|
210
211
|
signing_key:
|
211
212
|
specification_version: 4
|
212
213
|
summary: A client for using the South African Air Quality Index API in Ruby.
|