geoptima 0.1.18 → 0.1.19
Sign up to get free protection for your applications and to get access to all the features.
- data/CONTRIBUTORS +1 -1
- data/Gemfile +4 -2
- data/README.rdoc +59 -3
- data/bin/show_geoptima +87 -18
- data/examples/show_geoptima.rb +87 -18
- data/geoptima.gemspec +33 -7
- data/lib/geoptima/after.ports +17 -0
- data/lib/geoptima/before.ports +16 -0
- data/lib/geoptima/data.rb +12 -19
- data/lib/geoptima/locator.rb +172 -0
- data/lib/geoptima/version.rb +1 -1
- metadata +50 -32
data/CONTRIBUTORS
CHANGED
data/Gemfile
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
source :gemcutter
|
2
|
-
|
3
1
|
gemspec
|
4
2
|
|
5
3
|
group 'test' do
|
@@ -10,6 +8,10 @@ group 'test' do
|
|
10
8
|
gem "test-unit"
|
11
9
|
end
|
12
10
|
|
11
|
+
gem "multi_json", ">= 1.1.0"
|
12
|
+
gem "json_pure", ">= 1.6.5"
|
13
|
+
gem "json", ">= 1.6.5"
|
14
|
+
|
13
15
|
#gem 'ruby-debug-base19' if RUBY_VERSION.include? "1.9"
|
14
16
|
#gem 'ruby-debug-base' if RUBY_VERSION.include? "1.8"
|
15
17
|
#gem "ruby-debug-ide"
|
data/README.rdoc
CHANGED
@@ -24,10 +24,11 @@ This script imports the JSON files on the command-line and then:
|
|
24
24
|
|
25
25
|
Which event types to include and various other options are available using the command-line. Run it with the -h option to get a full list of options. The current version should support:
|
26
26
|
|
27
|
-
Usage: show_geoptima <-
|
27
|
+
Usage: show_geoptima <-dwvpxomlsafegh> <-P export_prefix> <-L limit>
|
28
|
+
<-E types> <-T min,max> <-M mapfile> file <files>
|
28
29
|
-d debug mode (output more context during processing) (false)
|
29
30
|
-w verbose mode (output extra information to console)
|
30
|
-
-v print geoptima library version 0.1.
|
31
|
+
-v print geoptima library version 0.1.19
|
31
32
|
-p print mode (print out final results to console)
|
32
33
|
-x export IMEI specific CSV files for further processing
|
33
34
|
-o export field statistis
|
@@ -36,12 +37,67 @@ Which event types to include and various other options are available using the c
|
|
36
37
|
-s seperate the export files by event type
|
37
38
|
-a combine all IMEI's into a single dataset
|
38
39
|
-f flush stdout
|
40
|
+
-e show error statistics
|
41
|
+
-g export GPX traces
|
42
|
+
-t split time colum to multiple columns
|
39
43
|
-h show this help
|
40
44
|
-P prefix for exported files (default: ''; current: )
|
41
45
|
-E comma-seperated list of event types to show and export (default: all; current: )
|
46
|
+
-A application category map file (default: app names)
|
42
47
|
-T time range to limit results to (default: all; current: )
|
48
|
+
-B location limited to specified bounds in one of these formats:
|
49
|
+
minlat,minlon,maxlat,maxlon
|
50
|
+
minlat..maxlat,minlon..maxlon
|
51
|
+
DIST(distance_in_km,lat,lon)
|
52
|
+
RANGE[minlat,minlon,maxlat,maxlon]
|
53
|
+
RANGE[minlat..maxlat,minlon..maxlon]
|
54
|
+
(default: all; current: )
|
43
55
|
-L limit verbose output to specific number of lines (10000)
|
44
56
|
-M mapfile of normal->altered header names:
|
57
|
+
-G GPX export options as ';' separated list of key:value pairs
|
58
|
+
Current GPX options: {"scale"=>190, "padding"=>5, "limit"=>2,
|
59
|
+
"png_limit"=>10, "points"=>true, "point_size"=>2, "point_color"=>"auto"}
|
60
|
+
-X Geolocation options as ';' separated list of key:value pairs
|
61
|
+
Current geolocation options: {"algorithm"=>"window", "window"=>60}
|
62
|
+
|
63
|
+
The GPX and Geolocation options require futher explanation:
|
64
|
+
|
65
|
+
Known supported GPX options (might be more, see data.rb code):
|
66
|
+
limit:2 Limit GPX output to traces with at least this number of events
|
67
|
+
png_limit:10 Limit PNG output to traces with at least this number of events
|
68
|
+
merge: Merge all traces into a single trace
|
69
|
+
only_merge: Do not export unmerged traces
|
70
|
+
scale:190 Size of print area in PNG output
|
71
|
+
padding:5 Space around print area
|
72
|
+
points:true Turn on/off points
|
73
|
+
point_size:2 Set point size
|
74
|
+
point_color:auto Set point color: RRGGBBAA in hex (else 'auto')
|
75
|
+
format: Export format: 'gpx', 'csv', 'png', default 'all'
|
76
|
+
waypoints: Export waypoints for events: <event_type>, default 'all'
|
77
|
+
|
78
|
+
PNG images will be 'scale + 2 * padding' big (200 for current settings).
|
79
|
+
The scale will be used for the widest dimension, and the other will be reduced
|
80
|
+
to fit the actual size of the trace. No projection is used, with the points
|
81
|
+
simply mapped to their GPS locations. This will cause visual distortions far
|
82
|
+
from the equator where dlat!=dlon.
|
83
|
+
|
84
|
+
Known supported geolocation options (might be more, see data.rb code):
|
85
|
+
algorithm:window Which geolocation algorithm to use
|
86
|
+
window:60 Time window in seconds, has slightly different
|
87
|
+
meanings for different algorithms
|
88
|
+
|
89
|
+
Currently supported algorithms:
|
90
|
+
window: select GPS point within window seconds of event,
|
91
|
+
GPS points after the event take priority.
|
92
|
+
(this is the default for geoptima GEM version >= 0.1.19)
|
93
|
+
+win: select only GPS points after event (within time window)
|
94
|
+
-win: select only GPS points before event (within time window)
|
95
|
+
(this is the default for geoptima GEM version < 0.1.19)
|
96
|
+
closest: select closest GPS point within window seconds of event
|
97
|
+
(similar to window option, but chooses closest)
|
98
|
+
interpolate: Linear interpolation between two closest points
|
99
|
+
(experimental, do not use yet)
|
100
|
+
(read redmine wiki page for explanation of algorithm)
|
45
101
|
|
46
102
|
Currently the script also locates events that are close enough in time to GPS events. We hope to improve this with interpolation in the near future to be more compatible with the results from the commercial solutions. This time-window is also used for some of the extended header information, like LAC and CI, and effectively duplicates those fields from their own events to others. Take this into account when doing statistics on the results. It is better to use the original values, not the duplicates, if you want reliable statistics.
|
47
103
|
|
@@ -150,7 +206,7 @@ To get the optimized json gem installed, or to get chart support working you wil
|
|
150
206
|
|
151
207
|
==== Running on Windows
|
152
208
|
|
153
|
-
The best way to run on windows is to edit your system path (usually go to 'my computer->properties->advanced->environment), and add the path to your ruby bin directory (usually C
|
209
|
+
The best way to run on windows is to edit your system path (usually go to 'my computer->properties->advanced->environment), and add the path to your ruby bin directory (usually C:\\Ruby\\bin) to the end of the system PATH. After that, open a command-prompt (start->cmd.exe) and type 'ruby -v' to see that it worked. Then you can execute the 'gem install' commands and the 'show_geoptima' commands from this console.
|
154
210
|
|
155
211
|
==== Installing Gruff for Charting
|
156
212
|
|
data/bin/show_geoptima
CHANGED
@@ -8,7 +8,7 @@ require 'date'
|
|
8
8
|
require 'geoptima'
|
9
9
|
require 'geoptima/options'
|
10
10
|
|
11
|
-
Geoptima::assert_version(">=0.1.
|
11
|
+
Geoptima::assert_version(">=0.1.19")
|
12
12
|
|
13
13
|
$debug=false
|
14
14
|
|
@@ -21,6 +21,18 @@ $gpx_options = {
|
|
21
21
|
'points' => true, 'point_size' => 2, 'point_color' => 'auto'
|
22
22
|
}
|
23
23
|
|
24
|
+
$geolocation_options = {
|
25
|
+
'algorithm' => 'window', 'window' => 60
|
26
|
+
}
|
27
|
+
|
28
|
+
def make_hash_options(arg)
|
29
|
+
arg.split(/[\,\;]+/).inject({}) do |a,v|
|
30
|
+
k=v.split(/[\:\=]+/)
|
31
|
+
a[k[0]]=k[1]||true
|
32
|
+
a
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
24
36
|
$files = Geoptima::Options.process_args do |option|
|
25
37
|
option.p {$print = true}
|
26
38
|
option.x {$export = true}
|
@@ -38,8 +50,9 @@ $files = Geoptima::Options.process_args do |option|
|
|
38
50
|
option.B {$location_range = Geoptima::LocationRange.from ARGV.shift}
|
39
51
|
option.L {$print_limit = [1,ARGV.shift.to_i].max}
|
40
52
|
option.M {$mapfile = ARGV.shift}
|
41
|
-
option.G {$gpx_options.merge! ARGV.shift
|
53
|
+
option.G {$gpx_options.merge! make_hash_options(ARGV.shift)}
|
42
54
|
option.A {$app_categories = Geoptima::AppCategories.new(ARGV.shift)}
|
55
|
+
option.X {$geolocation_options.merge! make_hash_options(ARGV.shift)}
|
43
56
|
end.map do |file|
|
44
57
|
File.exist?(file) ? file : puts("No such file: #{file}")
|
45
58
|
end.compact
|
@@ -116,10 +129,33 @@ end
|
|
116
129
|
|
117
130
|
exit 0 if($print_version && !$verbose)
|
118
131
|
|
132
|
+
class String
|
133
|
+
def wrappad(max=80,pad=8)
|
134
|
+
max = [max,pad+1].max
|
135
|
+
wrapped = [self.to_s]
|
136
|
+
while wrapped[-1].length > max
|
137
|
+
a,b = wrapped[-1][0..(max-1)],wrapped[-1][max..-1]
|
138
|
+
if (si = a.rindex(/\s+/)) && (a[0..(si-1)] =~ /\S/)
|
139
|
+
b = [a[si..-1],b].join.gsub(/^\s+/,'')
|
140
|
+
a = a[0..(si-1)]
|
141
|
+
else
|
142
|
+
a+='-'
|
143
|
+
end
|
144
|
+
a = a.gsub(/\s+$/,'')
|
145
|
+
b = b.gsub(/^\s+/,'')
|
146
|
+
wrapped[-1] = a
|
147
|
+
wrapped << [' '*pad,b].join
|
148
|
+
puts "WRAP[#{max}:#{pad}]: #{wrapped.inspect}"
|
149
|
+
end
|
150
|
+
wrapped
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
119
154
|
$help = true if($files.length < 1)
|
120
155
|
if $help
|
121
156
|
puts <<EOHELP
|
122
|
-
Usage: show_geoptima <-dwvpxomlsafegh> <-P export_prefix> <-L limit>
|
157
|
+
Usage: show_geoptima <-dwvpxomlsafegh> <-P export_prefix> <-L limit>
|
158
|
+
<-E types> <-T min,max> <-M mapfile> file <files>
|
123
159
|
-d debug mode (output more context during processing) #{cw $debug}
|
124
160
|
-w verbose mode (output extra information to console) #{cw $verbose}
|
125
161
|
-v print geoptima library version #{Geoptima::VERSION}
|
@@ -149,20 +185,47 @@ Usage: show_geoptima <-dwvpxomlsafegh> <-P export_prefix> <-L limit> <-E types>
|
|
149
185
|
-L limit verbose output to specific number of lines #{cw $print_limit}
|
150
186
|
-M mapfile of normal->altered header names: #{$mapfile}
|
151
187
|
-G GPX export options as ';' separated list of key:value pairs
|
152
|
-
Current GPX options:
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
188
|
+
#{(' Current GPX options: '+$gpx_options.inspect).wrappad(80,6).join("\n")}
|
189
|
+
-X Geolocation options as ';' separated list of key:value pairs
|
190
|
+
#{(' Current geolocation options: '+$geolocation_options.inspect).wrappad(80,6).join("\n")}
|
191
|
+
|
192
|
+
The GPX and Geolocation options require futher explanation:
|
193
|
+
|
194
|
+
Known supported GPX options (might be more, see data.rb code):
|
195
|
+
limit:#{$gpx_options['limit']} \t Limit GPX output to traces with at least this number of events
|
196
|
+
png_limit:#{$gpx_options['png_limit']}\t Limit PNG output to traces with at least this number of events
|
197
|
+
merge:#{$gpx_options['merge']} \t Merge all traces into a single trace
|
198
|
+
only_merge:#{$gpx_options['merge']}\t Do not export unmerged traces
|
199
|
+
scale:#{$gpx_options['scale']}\t Size of print area in PNG output
|
200
|
+
padding:#{$gpx_options['padding']}\t Space around print area
|
201
|
+
points:#{$gpx_options['points']}\t Turn on/off points
|
202
|
+
point_size:#{$gpx_options['point_size']}\t Set point size
|
203
|
+
point_color:#{$gpx_options['point_color']} Set point color: RRGGBBAA in hex (else 'auto')
|
204
|
+
format:#{$gpx_options['format']} \t Export format: 'gpx', 'csv', 'png', default 'all'
|
205
|
+
waypoints:#{$gpx_options['waypoints']}\t Export waypoints for events: <event_type>, default 'all'
|
206
|
+
PNG images will be 'scale + 2 * padding' big (#{$gpx_options['scale'].to_i+2*$gpx_options['padding'].to_i} for current settings).
|
207
|
+
The scale will be used for the widest dimension, and the other will be reduced
|
208
|
+
to fit the actual size of the trace. No projection is used, with the points
|
209
|
+
simply mapped to their GPS locations. This will cause visual distortions far
|
210
|
+
from the equator where dlat!=dlon.
|
211
|
+
|
212
|
+
Known supported geolocation options (might be more, see data.rb code):
|
213
|
+
algorithm:#{$geolocation_options['algorithm']} Which geolocation algorithm to use
|
214
|
+
window:#{$geolocation_options['window']}\t Time window in seconds, has slightly different
|
215
|
+
meanings for different algorithms
|
216
|
+
|
217
|
+
Currently supported algorithms:
|
218
|
+
window: select GPS point within window seconds of event,
|
219
|
+
GPS points after the event take priority.
|
220
|
+
(this is the default for geoptima GEM version >= 0.1.19)
|
221
|
+
+win: select only GPS points after event (within time window)
|
222
|
+
-win: select only GPS points before event (within time window)
|
223
|
+
(this is the default for geoptima GEM version < 0.1.19)
|
224
|
+
closest: select closest GPS point within window seconds of event
|
225
|
+
(similar to window option, but chooses closest)
|
226
|
+
interpolate: Linear interpolation between two closest points
|
227
|
+
(experimental, do not use yet)
|
228
|
+
(read redmine wiki page for explanation of algorithm)
|
166
229
|
EOHELP
|
167
230
|
show_header_maps
|
168
231
|
exit 0
|
@@ -171,7 +234,13 @@ end
|
|
171
234
|
$verbose = $verbose || $debug
|
172
235
|
show_header_maps if($verbose)
|
173
236
|
|
174
|
-
$datasets = Geoptima::Dataset.make_datasets($files,
|
237
|
+
$datasets = Geoptima::Dataset.make_datasets($files,
|
238
|
+
:locate => true,
|
239
|
+
:time_range => $time_range,
|
240
|
+
:location_range => $location_range,
|
241
|
+
:geolocation_options => $geolocation_options,
|
242
|
+
:combine_all => $combine_all
|
243
|
+
)
|
175
244
|
|
176
245
|
class Export
|
177
246
|
attr_reader :files, :imei, :names, :headers
|
data/examples/show_geoptima.rb
CHANGED
@@ -8,7 +8,7 @@ require 'date'
|
|
8
8
|
require 'geoptima'
|
9
9
|
require 'geoptima/options'
|
10
10
|
|
11
|
-
Geoptima::assert_version(">=0.1.
|
11
|
+
Geoptima::assert_version(">=0.1.19")
|
12
12
|
|
13
13
|
$debug=false
|
14
14
|
|
@@ -21,6 +21,18 @@ $gpx_options = {
|
|
21
21
|
'points' => true, 'point_size' => 2, 'point_color' => 'auto'
|
22
22
|
}
|
23
23
|
|
24
|
+
$geolocation_options = {
|
25
|
+
'algorithm' => 'window', 'window' => 60
|
26
|
+
}
|
27
|
+
|
28
|
+
def make_hash_options(arg)
|
29
|
+
arg.split(/[\,\;]+/).inject({}) do |a,v|
|
30
|
+
k=v.split(/[\:\=]+/)
|
31
|
+
a[k[0]]=k[1]||true
|
32
|
+
a
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
24
36
|
$files = Geoptima::Options.process_args do |option|
|
25
37
|
option.p {$print = true}
|
26
38
|
option.x {$export = true}
|
@@ -38,8 +50,9 @@ $files = Geoptima::Options.process_args do |option|
|
|
38
50
|
option.B {$location_range = Geoptima::LocationRange.from ARGV.shift}
|
39
51
|
option.L {$print_limit = [1,ARGV.shift.to_i].max}
|
40
52
|
option.M {$mapfile = ARGV.shift}
|
41
|
-
option.G {$gpx_options.merge! ARGV.shift
|
53
|
+
option.G {$gpx_options.merge! make_hash_options(ARGV.shift)}
|
42
54
|
option.A {$app_categories = Geoptima::AppCategories.new(ARGV.shift)}
|
55
|
+
option.X {$geolocation_options.merge! make_hash_options(ARGV.shift)}
|
43
56
|
end.map do |file|
|
44
57
|
File.exist?(file) ? file : puts("No such file: #{file}")
|
45
58
|
end.compact
|
@@ -116,10 +129,33 @@ end
|
|
116
129
|
|
117
130
|
exit 0 if($print_version && !$verbose)
|
118
131
|
|
132
|
+
class String
|
133
|
+
def wrappad(max=80,pad=8)
|
134
|
+
max = [max,pad+1].max
|
135
|
+
wrapped = [self.to_s]
|
136
|
+
while wrapped[-1].length > max
|
137
|
+
a,b = wrapped[-1][0..(max-1)],wrapped[-1][max..-1]
|
138
|
+
if (si = a.rindex(/\s+/)) && (a[0..(si-1)] =~ /\S/)
|
139
|
+
b = [a[si..-1],b].join.gsub(/^\s+/,'')
|
140
|
+
a = a[0..(si-1)]
|
141
|
+
else
|
142
|
+
a+='-'
|
143
|
+
end
|
144
|
+
a = a.gsub(/\s+$/,'')
|
145
|
+
b = b.gsub(/^\s+/,'')
|
146
|
+
wrapped[-1] = a
|
147
|
+
wrapped << [' '*pad,b].join
|
148
|
+
puts "WRAP[#{max}:#{pad}]: #{wrapped.inspect}"
|
149
|
+
end
|
150
|
+
wrapped
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
119
154
|
$help = true if($files.length < 1)
|
120
155
|
if $help
|
121
156
|
puts <<EOHELP
|
122
|
-
Usage: show_geoptima <-dwvpxomlsafegh> <-P export_prefix> <-L limit>
|
157
|
+
Usage: show_geoptima <-dwvpxomlsafegh> <-P export_prefix> <-L limit>
|
158
|
+
<-E types> <-T min,max> <-M mapfile> file <files>
|
123
159
|
-d debug mode (output more context during processing) #{cw $debug}
|
124
160
|
-w verbose mode (output extra information to console) #{cw $verbose}
|
125
161
|
-v print geoptima library version #{Geoptima::VERSION}
|
@@ -149,20 +185,47 @@ Usage: show_geoptima <-dwvpxomlsafegh> <-P export_prefix> <-L limit> <-E types>
|
|
149
185
|
-L limit verbose output to specific number of lines #{cw $print_limit}
|
150
186
|
-M mapfile of normal->altered header names: #{$mapfile}
|
151
187
|
-G GPX export options as ';' separated list of key:value pairs
|
152
|
-
Current GPX options:
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
188
|
+
#{(' Current GPX options: '+$gpx_options.inspect).wrappad(80,6).join("\n")}
|
189
|
+
-X Geolocation options as ';' separated list of key:value pairs
|
190
|
+
#{(' Current geolocation options: '+$geolocation_options.inspect).wrappad(80,6).join("\n")}
|
191
|
+
|
192
|
+
The GPX and Geolocation options require futher explanation:
|
193
|
+
|
194
|
+
Known supported GPX options (might be more, see data.rb code):
|
195
|
+
limit:#{$gpx_options['limit']} \t Limit GPX output to traces with at least this number of events
|
196
|
+
png_limit:#{$gpx_options['png_limit']}\t Limit PNG output to traces with at least this number of events
|
197
|
+
merge:#{$gpx_options['merge']} \t Merge all traces into a single trace
|
198
|
+
only_merge:#{$gpx_options['merge']}\t Do not export unmerged traces
|
199
|
+
scale:#{$gpx_options['scale']}\t Size of print area in PNG output
|
200
|
+
padding:#{$gpx_options['padding']}\t Space around print area
|
201
|
+
points:#{$gpx_options['points']}\t Turn on/off points
|
202
|
+
point_size:#{$gpx_options['point_size']}\t Set point size
|
203
|
+
point_color:#{$gpx_options['point_color']} Set point color: RRGGBBAA in hex (else 'auto')
|
204
|
+
format:#{$gpx_options['format']} \t Export format: 'gpx', 'csv', 'png', default 'all'
|
205
|
+
waypoints:#{$gpx_options['waypoints']}\t Export waypoints for events: <event_type>, default 'all'
|
206
|
+
PNG images will be 'scale + 2 * padding' big (#{$gpx_options['scale'].to_i+2*$gpx_options['padding'].to_i} for current settings).
|
207
|
+
The scale will be used for the widest dimension, and the other will be reduced
|
208
|
+
to fit the actual size of the trace. No projection is used, with the points
|
209
|
+
simply mapped to their GPS locations. This will cause visual distortions far
|
210
|
+
from the equator where dlat!=dlon.
|
211
|
+
|
212
|
+
Known supported geolocation options (might be more, see data.rb code):
|
213
|
+
algorithm:#{$geolocation_options['algorithm']} Which geolocation algorithm to use
|
214
|
+
window:#{$geolocation_options['window']}\t Time window in seconds, has slightly different
|
215
|
+
meanings for different algorithms
|
216
|
+
|
217
|
+
Currently supported algorithms:
|
218
|
+
window: select GPS point within window seconds of event,
|
219
|
+
GPS points after the event take priority.
|
220
|
+
(this is the default for geoptima GEM version >= 0.1.19)
|
221
|
+
+win: select only GPS points after event (within time window)
|
222
|
+
-win: select only GPS points before event (within time window)
|
223
|
+
(this is the default for geoptima GEM version < 0.1.19)
|
224
|
+
closest: select closest GPS point within window seconds of event
|
225
|
+
(similar to window option, but chooses closest)
|
226
|
+
interpolate: Linear interpolation between two closest points
|
227
|
+
(experimental, do not use yet)
|
228
|
+
(read redmine wiki page for explanation of algorithm)
|
166
229
|
EOHELP
|
167
230
|
show_header_maps
|
168
231
|
exit 0
|
@@ -171,7 +234,13 @@ end
|
|
171
234
|
$verbose = $verbose || $debug
|
172
235
|
show_header_maps if($verbose)
|
173
236
|
|
174
|
-
$datasets = Geoptima::Dataset.make_datasets($files,
|
237
|
+
$datasets = Geoptima::Dataset.make_datasets($files,
|
238
|
+
:locate => true,
|
239
|
+
:time_range => $time_range,
|
240
|
+
:location_range => $location_range,
|
241
|
+
:geolocation_options => $geolocation_options,
|
242
|
+
:combine_all => $combine_all
|
243
|
+
)
|
175
244
|
|
176
245
|
class Export
|
177
246
|
attr_reader :files, :imei, :names, :headers
|
data/geoptima.gemspec
CHANGED
@@ -12,13 +12,39 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.rubyforge_project = 'geoptima'
|
13
13
|
s.summary = "Ruby access to Geoptima JSON files"
|
14
14
|
s.description = <<-EOF
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
|
16
|
+
Geoptima is a suite of applications for measuring and locating
|
17
|
+
mobile/cellular subscriber experience on GPS enabled smartphones. It is
|
18
|
+
produced by AmanziTel AB in Helsingborg, Sweden, and supports many phone
|
19
|
+
manufacturers, with free downloads from the various app stores, markets or
|
20
|
+
marketplaces. This Ruby library is capable of reading the JSON format files
|
21
|
+
produced by these phones and reformating them as CSV, GPX and PNG for
|
22
|
+
further analysis in Excel. This is a simple and independent way of
|
23
|
+
analysing the data, when compared to the full-featured analysis applications
|
24
|
+
and servers available from AmanziTel. If you want to analyse a limited
|
25
|
+
amount of data in excel, or with Ruby, then this GEM might be for you. If
|
26
|
+
you want to analyse large amounts of data, from many subscribers, or over
|
27
|
+
long periods of time then rather consider the NetView and Customer IQ
|
28
|
+
applications from AmanziTel at www.amanzitel.com.
|
29
|
+
|
30
|
+
Current features available in the library and the show_geoptima command:
|
31
|
+
* Import one or many JSON files
|
32
|
+
* Organize data by device id (IMEI) into datasets
|
33
|
+
* Split by event type
|
34
|
+
* Time ordering and time correlation (associate data from one event to another):
|
35
|
+
** Add GPS locations to other events (time window and interpolation algorithms)
|
36
|
+
** Add signal strenth, battery level, etc. to other events
|
37
|
+
* Export event tables to CSV format for further processing in excel
|
38
|
+
* Make and export GPS traces in GPX and PNG format for simple map reports
|
39
|
+
|
40
|
+
The amount of data possible to process is limited by memory, since all data
|
41
|
+
is imported in ruby data structures for procssing. If you need to process
|
42
|
+
larger amounts of data, you will need a database-driven approach, like that
|
43
|
+
provided by AmanziTel's NetView and Customer IQ solutions. This Ruby gem is
|
44
|
+
actually used by parts of the data pre-processing chain of 'Customer IQ',
|
45
|
+
but it not used by the main database and statistics engine that generates
|
46
|
+
the reports.
|
47
|
+
|
22
48
|
EOF
|
23
49
|
|
24
50
|
s.require_path = 'lib'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
tcp 0 0 127.0.0.1:53748 0.0.0.0:* LISTEN
|
2
|
+
tcp 0 0 127.0.0.1:53 0.0.0.0:* LISTEN
|
3
|
+
tcp 0 0 192.168.122.1:53 0.0.0.0:* LISTEN
|
4
|
+
tcp 0 0 127.0.0.1:34678 0.0.0.0:* LISTEN
|
5
|
+
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
|
6
|
+
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN
|
7
|
+
tcp 0 0 0.0.0.0:17500 0.0.0.0:* LISTEN
|
8
|
+
tcp 0 0 0.0.0.0:445 0.0.0.0:* LISTEN
|
9
|
+
tcp 0 0 0.0.0.0:60648 0.0.0.0:* LISTEN
|
10
|
+
tcp 0 0 0.0.0.0:139 0.0.0.0:* LISTEN
|
11
|
+
tcp6 0 0 127.0.0.1:7473 :::* LISTEN
|
12
|
+
tcp6 0 0 127.0.0.1:7474 :::* LISTEN
|
13
|
+
tcp6 0 0 :::22 :::* LISTEN
|
14
|
+
tcp6 0 0 ::1:631 :::* LISTEN
|
15
|
+
tcp6 0 0 :::3000 :::* LISTEN
|
16
|
+
tcp6 0 0 :::1337 :::* LISTEN
|
17
|
+
tcp6 0 0 :::34495 :::* LISTEN
|
@@ -0,0 +1,16 @@
|
|
1
|
+
tcp 0 0 127.0.0.1:53748 0.0.0.0:* LISTEN
|
2
|
+
tcp 0 0 127.0.0.1:53 0.0.0.0:* LISTEN
|
3
|
+
tcp 0 0 192.168.122.1:53 0.0.0.0:* LISTEN
|
4
|
+
tcp 0 0 127.0.0.1:34678 0.0.0.0:* LISTEN
|
5
|
+
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
|
6
|
+
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN
|
7
|
+
tcp 0 0 0.0.0.0:17500 0.0.0.0:* LISTEN
|
8
|
+
tcp 0 0 0.0.0.0:445 0.0.0.0:* LISTEN
|
9
|
+
tcp 0 0 0.0.0.0:60648 0.0.0.0:* LISTEN
|
10
|
+
tcp 0 0 0.0.0.0:139 0.0.0.0:* LISTEN
|
11
|
+
tcp6 0 0 127.0.0.1:7473 :::* LISTEN
|
12
|
+
tcp6 0 0 127.0.0.1:7474 :::* LISTEN
|
13
|
+
tcp6 0 0 :::22 :::* LISTEN
|
14
|
+
tcp6 0 0 ::1:631 :::* LISTEN
|
15
|
+
tcp6 0 0 :::1337 :::* LISTEN
|
16
|
+
tcp6 0 0 :::34495 :::* LISTEN
|
data/lib/geoptima/data.rb
CHANGED
@@ -4,6 +4,7 @@ require 'rubygems'
|
|
4
4
|
require 'multi_json'
|
5
5
|
require 'geoptima/daterange'
|
6
6
|
require 'geoptima/locationrange'
|
7
|
+
require 'geoptima/locator'
|
7
8
|
require 'geoptima/timer'
|
8
9
|
begin
|
9
10
|
require 'png'
|
@@ -16,8 +17,6 @@ end
|
|
16
17
|
#
|
17
18
|
module Geoptima
|
18
19
|
|
19
|
-
SPERDAY = 60*60*24
|
20
|
-
MSPERDAY = 1000*60*60*24
|
21
20
|
SHORT = 256*256
|
22
21
|
MIN_VALID_DATETIME = DateTime.parse("1970-01-01")
|
23
22
|
MAX_VALID_DATETIME = DateTime.parse("2040-01-01")
|
@@ -484,7 +483,8 @@ module Geoptima
|
|
484
483
|
}
|
485
484
|
|
486
485
|
include ErrorCounter
|
487
|
-
|
486
|
+
include Locatable
|
487
|
+
attr_reader :file, :gps, :header, :name, :data, :fields, :time, :latitude, :longitude, :timeoffset
|
488
488
|
def initialize(file,start,name,header,data,previous=nil)
|
489
489
|
@file = file
|
490
490
|
@name = name
|
@@ -553,14 +553,12 @@ module Geoptima
|
|
553
553
|
def location
|
554
554
|
@location ||= latitude && Point.new(latitude,longitude)
|
555
555
|
end
|
556
|
-
def
|
556
|
+
def set_location(gps)
|
557
557
|
incr_error "GPS String Data" if(gps['latitude'].is_a? String)
|
558
558
|
@latitude = gps['latitude'].to_f
|
559
559
|
@longitude = gps['longitude'].to_f
|
560
560
|
@location = nil
|
561
|
-
|
562
|
-
def locate_if_closer_than(gps,seconds=60)
|
563
|
-
locate(gps) if(closer_than(gps,seconds))
|
561
|
+
@gps = gps
|
564
562
|
end
|
565
563
|
def puts line
|
566
564
|
Kernel.puts "#{name}[#{time}]: #{line}"
|
@@ -868,6 +866,7 @@ module Geoptima
|
|
868
866
|
@options = options
|
869
867
|
@time_range = options[:time_range] || DateRange.new(Config[:min_datetime],Config[:max_datetime])
|
870
868
|
@location_range = options[:location_range] || LocationRange.everywhere
|
869
|
+
@geolocation_options = options[:geolocation_options] || {}
|
871
870
|
@fields = {}
|
872
871
|
end
|
873
872
|
|
@@ -1098,20 +1097,14 @@ module Geoptima
|
|
1098
1097
|
end
|
1099
1098
|
|
1100
1099
|
def locate_events
|
1101
|
-
prev_gps = nil
|
1102
|
-
count = 0
|
1103
1100
|
puts "Locating #{sorted.length} events" if(true||$debug)
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
count += 1 if(event.locate_if_closer_than(prev_gps,60))
|
1111
|
-
end
|
1112
|
-
timer('locate.each').stop
|
1101
|
+
locator = Geoptima::Locator.new self.sorted, @geolocation_options
|
1102
|
+
timer("locate.all").start
|
1103
|
+
locator.locate
|
1104
|
+
timer("locate.all").stop
|
1105
|
+
if (true||$debug)
|
1106
|
+
puts "Located #{locator.located.length} / #{sorted.length} events (timed: #{timer("locate.all")}"
|
1113
1107
|
end
|
1114
|
-
puts "Located #{count} / #{sorted.length} events" if($debug)
|
1115
1108
|
end
|
1116
1109
|
|
1117
1110
|
def to_s
|
@@ -0,0 +1,172 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'geoptima/locationrange'
|
4
|
+
|
5
|
+
module Geoptima
|
6
|
+
|
7
|
+
SPERDAY = 60*60*24
|
8
|
+
MSPERDAY = 1000*SPERDAY
|
9
|
+
|
10
|
+
class LocatorAlgorithm
|
11
|
+
def locate(locatable)
|
12
|
+
if locatable.next_point
|
13
|
+
locatable.location = locatable.next_point
|
14
|
+
elsif locatable.previous_point
|
15
|
+
locatable.location = locatable.previous_point
|
16
|
+
else
|
17
|
+
locatable.location = nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
class BeforeLocatorAlgorithm < LocatorAlgorithm
|
22
|
+
def locate(locatable)
|
23
|
+
if locatable.previous_point
|
24
|
+
locatable.location = locatable.previous_point
|
25
|
+
else
|
26
|
+
locatable.location = nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
class AfterLocatorAlgorithm < LocatorAlgorithm
|
31
|
+
def locate(locatable)
|
32
|
+
if locatable.next_point
|
33
|
+
locatable.location = locatable.next_point
|
34
|
+
else
|
35
|
+
locatable.location = nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
class ClosestLocatorAlgorithm < LocatorAlgorithm
|
40
|
+
def locate(locatable)
|
41
|
+
results = [
|
42
|
+
[locatable.next_point_gap,locatable.next_point],
|
43
|
+
[locatable.previous_point_gap,locatable.previous_point]
|
44
|
+
].reject do |x|
|
45
|
+
x[0].nil? && x[1].nil?
|
46
|
+
end.sort do |a,b|
|
47
|
+
a[0] <=> b[0]
|
48
|
+
end[0]
|
49
|
+
locatable.location = results && results[1]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
class InterpolationLocatorAlgorithm < ClosestLocatorAlgorithm
|
53
|
+
def locate(locatable)
|
54
|
+
if locatable.previous_poing && locatable.next_point && locatable.next_point.prev_point
|
55
|
+
correlateEvent2Point(point,wavg(point.prev,point.next,point),'interpolated');
|
56
|
+
elsif closest = super.locate(locatable)
|
57
|
+
correlateEvent2Point(point,closest,'correlated');
|
58
|
+
else
|
59
|
+
puts "No correlation possible for point: "+point
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
module Locatable
|
64
|
+
attr_accessor :previous_point, :next_point, :previous_point_gap, :next_point_gap, :location
|
65
|
+
def closer_than(gps,window=0.0)
|
66
|
+
if $debug && gps && window > 0
|
67
|
+
puts "Comparing times:"
|
68
|
+
puts "\tGPS: #{gps.time}"
|
69
|
+
puts "\tEvent: #{self.time}"
|
70
|
+
puts "\tTDiff: #{(self - gps).abs.to_f}"
|
71
|
+
puts "\tWindow: #{window}"
|
72
|
+
end
|
73
|
+
gps && (window <= 0.0 || (self - gps).abs < window)
|
74
|
+
end
|
75
|
+
def set_next_if(gps,time_window=0.0)
|
76
|
+
if closer_than(gps,time_window)
|
77
|
+
self.next_point = gps.location
|
78
|
+
self.next_point_gap = (self - gps).abs
|
79
|
+
end
|
80
|
+
end
|
81
|
+
def set_previous_if(gps,time_window=0.0)
|
82
|
+
if closer_than(gps,time_window)
|
83
|
+
self.previous_point = gps.location
|
84
|
+
self.previous_point_gap = (self - gps).abs
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
class LocatableImpl
|
89
|
+
attr_reader :name, :attributes
|
90
|
+
attr_accessor :time
|
91
|
+
include Locatable
|
92
|
+
def initialize(attributes)
|
93
|
+
@attributes = Hash[*attributes.map{|k,v| [k.to_s,v]}.flatten]
|
94
|
+
@name = @attributes['name']
|
95
|
+
@time = @attributes['time']
|
96
|
+
end
|
97
|
+
def [](key)
|
98
|
+
@attributes[key.to_s] || @attributes[key.to_s.gsub(/#{name}\./,'')]
|
99
|
+
end
|
100
|
+
def []=(key,value)
|
101
|
+
@attributes[key.to_s] = value
|
102
|
+
end
|
103
|
+
def -(other)
|
104
|
+
(self.time - other.time) * SPERDAY
|
105
|
+
end
|
106
|
+
def to_s
|
107
|
+
@attributes.inspect
|
108
|
+
end
|
109
|
+
end
|
110
|
+
class Locator
|
111
|
+
attr_reader :sorted, :located, :failed, :options
|
112
|
+
def initialize(sorted, options={})
|
113
|
+
@sorted = sorted
|
114
|
+
@options = Hash[*options.map{|k,v| [k.to_s.intern,v]}.flatten]
|
115
|
+
@options[:algorithm] ||= 'window'
|
116
|
+
@options[:window] ||= 60
|
117
|
+
puts "Initialized geo-location on #{@sorted.length} events with options: #{@options.inspect}" if($debug)
|
118
|
+
end
|
119
|
+
def start
|
120
|
+
@start ||= sorted[0] && sorted[0][:time] || DateTime.now
|
121
|
+
end
|
122
|
+
def algorithm
|
123
|
+
@algorithm ||= case @options[:algorithm].to_s
|
124
|
+
when /^\-win/
|
125
|
+
BeforeLocatorAlgorithm.new
|
126
|
+
when /^\+win/
|
127
|
+
AfterLocatorAlgorithm.new
|
128
|
+
when /closest/
|
129
|
+
ClosestLocatorAlgorithm.new
|
130
|
+
when /inter/
|
131
|
+
InterpolationLocatorAlgorithm.new
|
132
|
+
else
|
133
|
+
LocatorAlgorithm.new
|
134
|
+
end
|
135
|
+
end
|
136
|
+
def locate
|
137
|
+
gps = nil
|
138
|
+
@located = []
|
139
|
+
@failed = []
|
140
|
+
locatables = []
|
141
|
+
time_window = @options[:window].to_i
|
142
|
+
time_window = 60 if(time_window<1)
|
143
|
+
puts "Locating within window[#{time_window}] using algorithm:#{algorithm.class}" if($debug)
|
144
|
+
sorted.each do |event|
|
145
|
+
event.time ||= start + event[:timestamp].to_f / Geoptima::MSPERDAY
|
146
|
+
if event.name === 'gps'
|
147
|
+
gps = event
|
148
|
+
puts "Setting GPS location point: #{gps.inspect}" if($debug)
|
149
|
+
gps.location = Point.new(gps['latitude'].to_f, gps['longitude'].to_f)
|
150
|
+
locatables.each do |event|
|
151
|
+
event.set_next_if(gps,time_window)
|
152
|
+
end
|
153
|
+
locatables = []
|
154
|
+
else
|
155
|
+
event.set_previous_if(gps,time_window)
|
156
|
+
locatables << event
|
157
|
+
@located << event
|
158
|
+
end
|
159
|
+
end
|
160
|
+
@located = @located.map do |l|
|
161
|
+
if self.algorithm.locate(l)
|
162
|
+
l
|
163
|
+
else
|
164
|
+
@failed << l
|
165
|
+
nil
|
166
|
+
end
|
167
|
+
end.compact
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
|
data/lib/geoptima/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: geoptima
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.19
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,14 +9,14 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-05-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: multi_json
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ">="
|
20
20
|
- !ruby/object:Gem::Version
|
21
21
|
version: 1.1.0
|
22
22
|
type: :runtime
|
@@ -24,7 +24,7 @@ dependencies:
|
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
26
26
|
requirements:
|
27
|
-
- -
|
27
|
+
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: 1.1.0
|
30
30
|
- !ruby/object:Gem::Dependency
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
none: false
|
34
34
|
requirements:
|
35
|
-
- -
|
35
|
+
- - ">="
|
36
36
|
- !ruby/object:Gem::Version
|
37
37
|
version: 1.6.5
|
38
38
|
type: :runtime
|
@@ -40,31 +40,43 @@ dependencies:
|
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
|
-
- -
|
43
|
+
- - ">="
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: 1.6.5
|
46
|
-
description:
|
47
|
-
subscriber experience on GPS enabled smartphones.
|
46
|
+
description: |2+
|
48
47
|
|
49
|
-
|
50
|
-
|
48
|
+
Geoptima is a suite of applications for measuring and locating
|
49
|
+
mobile/cellular subscriber experience on GPS enabled smartphones. It is
|
50
|
+
produced by AmanziTel AB in Helsingborg, Sweden, and supports many phone
|
51
|
+
manufacturers, with free downloads from the various app stores, markets or
|
52
|
+
marketplaces. This Ruby library is capable of reading the JSON format files
|
53
|
+
produced by these phones and reformating them as CSV, GPX and PNG for
|
54
|
+
further analysis in Excel. This is a simple and independent way of
|
55
|
+
analysing the data, when compared to the full-featured analysis applications
|
56
|
+
and servers available from AmanziTel. If you want to analyse a limited
|
57
|
+
amount of data in excel, or with Ruby, then this GEM might be for you. If
|
58
|
+
you want to analyse large amounts of data, from many subscribers, or over
|
59
|
+
long periods of time then rather consider the NetView and Customer IQ
|
60
|
+
applications from AmanziTel at www.amanzitel.com.
|
51
61
|
|
52
|
-
|
53
|
-
|
62
|
+
Current features available in the library and the show_geoptima command:
|
63
|
+
* Import one or many JSON files
|
64
|
+
* Organize data by device id (IMEI) into datasets
|
65
|
+
* Split by event type
|
66
|
+
* Time ordering and time correlation (associate data from one event to another):
|
67
|
+
** Add GPS locations to other events (time window and interpolation algorithms)
|
68
|
+
** Add signal strenth, battery level, etc. to other events
|
69
|
+
* Export event tables to CSV format for further processing in excel
|
70
|
+
* Make and export GPS traces in GPX and PNG format for simple map reports
|
54
71
|
|
55
|
-
|
56
|
-
|
72
|
+
The amount of data possible to process is limited by memory, since all data
|
73
|
+
is imported in ruby data structures for procssing. If you need to process
|
74
|
+
larger amounts of data, you will need a database-driven approach, like that
|
75
|
+
provided by AmanziTel's NetView and Customer IQ solutions. This Ruby gem is
|
76
|
+
actually used by parts of the data pre-processing chain of 'Customer IQ',
|
77
|
+
but it not used by the main database and statistics engine that generates
|
78
|
+
the reports.
|
57
79
|
|
58
|
-
compared to the full-featured analysis applications and servers available from AmanziTel.
|
59
|
-
If you want to analyse a limited amount
|
60
|
-
|
61
|
-
of data in excel, or with Ruby, then this GEM might be for you. If you want to analyse
|
62
|
-
large amounts of data, from many subscribers, or over long periods of time
|
63
|
-
|
64
|
-
then rather consider the NetView and Customer IQ applications from AmanziTel at
|
65
|
-
www.amanzitel.com.
|
66
|
-
|
67
|
-
'
|
68
80
|
email: craig@amanzi.com
|
69
81
|
executables:
|
70
82
|
- show_geoptima
|
@@ -90,8 +102,11 @@ files:
|
|
90
102
|
- lib/geoptima/daterange.rb
|
91
103
|
- lib/geoptima/options.rb
|
92
104
|
- lib/geoptima/timer.rb
|
105
|
+
- lib/geoptima/before.ports
|
93
106
|
- lib/geoptima/file_time.rb
|
94
107
|
- lib/geoptima/locationrange.rb
|
108
|
+
- lib/geoptima/after.ports
|
109
|
+
- lib/geoptima/locator.rb
|
95
110
|
- lib/geoptima.rb
|
96
111
|
- examples/show_geoptima_sos.rb
|
97
112
|
- examples/show_geoptima.rb
|
@@ -111,30 +126,33 @@ homepage: http://github.com/craigtaverner/geoptima.rb
|
|
111
126
|
licenses: []
|
112
127
|
post_install_message:
|
113
128
|
rdoc_options:
|
114
|
-
- --quiet
|
115
|
-
- --title
|
129
|
+
- "--quiet"
|
130
|
+
- "--title"
|
116
131
|
- Geoptima.rb
|
117
|
-
- --line-numbers
|
118
|
-
- --main
|
132
|
+
- "--line-numbers"
|
133
|
+
- "--main"
|
119
134
|
- README.rdoc
|
120
|
-
- --inline-source
|
135
|
+
- "--inline-source"
|
121
136
|
require_paths:
|
122
137
|
- lib
|
123
138
|
required_ruby_version: !ruby/object:Gem::Requirement
|
124
139
|
none: false
|
125
140
|
requirements:
|
126
|
-
- -
|
141
|
+
- - ">="
|
127
142
|
- !ruby/object:Gem::Version
|
128
143
|
version: 1.8.6
|
129
144
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
145
|
none: false
|
131
146
|
requirements:
|
132
|
-
- -
|
147
|
+
- - ">="
|
133
148
|
- !ruby/object:Gem::Version
|
134
149
|
version: '0'
|
150
|
+
segments:
|
151
|
+
- 0
|
152
|
+
hash: 909654323
|
135
153
|
requirements: []
|
136
154
|
rubyforge_project: geoptima
|
137
|
-
rubygems_version: 1.8.
|
155
|
+
rubygems_version: 1.8.25
|
138
156
|
signing_key:
|
139
157
|
specification_version: 3
|
140
158
|
summary: Ruby access to Geoptima JSON files
|