geoptima 0.1.12 → 0.1.13

Sign up to get free protection for your applications and to get access to all the features.
data/bin/show_geoptima CHANGED
@@ -8,13 +8,18 @@ require 'date'
8
8
  require 'geoptima'
9
9
  require 'geoptima/options'
10
10
 
11
- Geoptima::assert_version(">=0.1.9")
11
+ Geoptima::assert_version(">=0.1.13")
12
12
 
13
13
  $debug=false
14
14
 
15
15
  $event_names=[]
16
16
  $files = []
17
17
  $print_limit = 10000
18
+ $gpx_options = {
19
+ 'scale' => 195, 'padding' => 5,
20
+ 'limit' => 2, 'png_limit' => 10,
21
+ 'points' => true, 'point_size' => 2, 'point_color' => '0000aa'
22
+ }
18
23
 
19
24
  $files = Geoptima::Options.process_args do |option|
20
25
  option.p {$print = true}
@@ -26,11 +31,13 @@ $files = Geoptima::Options.process_args do |option|
26
31
  option.l {$more_headers = true}
27
32
  option.e {$show_error_stats = true}
28
33
  option.g {$export_gpx = true}
34
+ option.t {$split_time = true}
29
35
  option.P {$export_prefix = ARGV.shift}
30
36
  option.E {$event_names += ARGV.shift.split(/[\,\;\:\.]+/)}
31
37
  option.T {$time_range = Geoptima::DateRange.from ARGV.shift}
32
38
  option.L {$print_limit = [1,ARGV.shift.to_i].max}
33
39
  option.M {$mapfile = ARGV.shift}
40
+ option.G {$gpx_options.merge! ARGV.shift.split(/[\,\;]+/).inject({}){|a,v| k=v.split(/[\:\=]+/);a[k[0]]=k[1]||true;a}}
34
41
  end.map do |file|
35
42
  File.exist?(file) ? file : puts("No such file: #{file}")
36
43
  end.compact
@@ -124,12 +131,25 @@ Usage: show_geoptima <-dwvpxomlsafegh> <-P export_prefix> <-L limit> <-E types>
124
131
  -f flush stdout #{cw $flush_stdout}
125
132
  -e show error statistics #{cw $show_error_stats}
126
133
  -g export GPX traces #{cw $export_gpx}
134
+ -t split time colum to multiple columns #{cw $split_time}
127
135
  -h show this help
128
136
  -P prefix for exported files (default: ''; current: #{$export_prefix})
129
137
  -E comma-seperated list of event types to show and export (default: all; current: #{$event_names.join(',')})
130
138
  -T time range to limit results to (default: all; current: #{$time_range})
131
139
  -L limit verbose output to specific number of lines #{cw $print_limit}
132
140
  -M mapfile of normal->altered header names: #{$mapfile}
141
+ -G GPX export options as ';' separated list of key:value pairs
142
+ Current GPX options: #{$gpx_options.inspect}
143
+ Known supported GPX options (might be more, see data.rb code):
144
+ limit:#{$gpx_options['limit']}\tLimit GPX output to traces with at least this number of events
145
+ png_limit:#{$gpx_options['png_limit']}\tLimit PNG output to traces with at least this number of events
146
+ scale:#{$gpx_options['scale']}\tSize of print area in PNG output
147
+ padding:#{$gpx_options['padding']}\tSpace around print area
148
+ points:#{$gpx_options['points']}\tTurn on/off points
149
+ point_size:#{$gpx_options['point_size']}\tSet point size
150
+ point_color:#{$gpx_options['point_color']}\tSet point color: RRGGBBAA in hex
151
+ PNG images will be 'scale + 2 * padding' big. The scale will be used for
152
+ the widest dimension, and the other will be reduced to fit the trace.
133
153
  EOHELP
134
154
  show_header_maps
135
155
  exit 0
@@ -172,7 +192,7 @@ class Export
172
192
  if $header_maps
173
193
  file.puts $header_maps.find{|hm| hm.event == key}.columns.map{|c| c[0]}.join("\t")
174
194
  else
175
- file.puts map_headers(base_headers+more_headers+header(key)).join("\t")
195
+ file.puts map_headers(time_headers+base_headers+more_headers+header(key)).join("\t")
176
196
  end
177
197
  end
178
198
  if $debug || $verbose
@@ -184,6 +204,17 @@ class Export
184
204
  def export_imei
185
205
  ($combine_all || $more_headers)
186
206
  end
207
+ def time_headers
208
+ $split_time ? ['Year','Month','Day','Hour','Minute','Second','Millisecond'] : []
209
+ end
210
+ def time_fields(event)
211
+ if $split_time
212
+ t = event.utc
213
+ [t.year,t.month,t.day,t.hour,t.minute,t.second,(t.second_fraction.to_f * 1000).to_i]
214
+ else
215
+ []
216
+ end
217
+ end
187
218
  def base_headers
188
219
  ['Time','Event','Latitude','Longitude'] +
189
220
  (export_imei ? ['IMEI'] : [])
@@ -223,9 +254,6 @@ class Export
223
254
  end
224
255
  end
225
256
  end
226
- def get_field(event,name)
227
- h=(base_headers+more_headers).grep(/#{name}/)
228
- end
229
257
  def cap(array,sep="")
230
258
  array.map do |v|
231
259
  "#{v[0..0].upcase}#{v[1..-1]}"
@@ -264,6 +292,15 @@ class Export
264
292
  out.puts trace.as_gpx
265
293
  end
266
294
  end
295
+ def export_png(trace)
296
+ puts "Exporting #{trace.length} GPS events to PNG: #{trace}"
297
+ if $verbose
298
+ puts "\tBounds: #{trace.bounds}"
299
+ puts "\tWidth: #{trace.width}"
300
+ puts "\tHeight: #{trace.height}"
301
+ end
302
+ trace.to_png "#{$export_prefix}#{trace}.png", $gpx_options
303
+ end
267
304
  def header(name=nil)
268
305
  @headers[name]
269
306
  end
@@ -324,8 +361,15 @@ $datasets.keys.sort.each do |imei|
324
361
  export = Export.new(imei,names,dataset)
325
362
  export.export_stats(dataset.stats) if($export_stats)
326
363
  if $export_gpx
364
+ merged_traces = Geoptima::MergedTrace.new(dataset)
327
365
  dataset.each_trace do |trace|
328
- export.export_gpx(trace)
366
+ export.export_gpx(trace) if(trace.length>=($gpx_options['limit'] || 1).to_i)
367
+ export.export_png(trace) if(trace.length>=($gpx_options['png_limit'] || 10).to_i)
368
+ merged_traces << trace if($gpx_options['merge'])
369
+ end
370
+ if($gpx_options['merge'])
371
+ export.export_gpx(merged_traces)
372
+ export.export_png(merged_traces)
329
373
  end
330
374
  end
331
375
  if $header_maps && $header_maps.length > 0
@@ -347,7 +391,7 @@ $datasets.keys.sort.each do |imei|
347
391
  names.each do |name|
348
392
  if event.name === name
349
393
  fields = export.header($seperate ? name : nil).map{|h| event[h]}
350
- b_fields = export.base_fields(event) + export.more_fields(event,dataset)
394
+ b_fields = export.time_fields(event) + export.base_fields(event) + export.more_fields(event,dataset)
351
395
  export.puts_to "#{b_fields.join("\t")}\t#{fields.join("\t")}", name
352
396
  if_le{puts "#{b_fields.join("\t")}\t#{event.fields.inspect}"}
353
397
  end
@@ -8,13 +8,18 @@ require 'date'
8
8
  require 'geoptima'
9
9
  require 'geoptima/options'
10
10
 
11
- Geoptima::assert_version(">=0.1.9")
11
+ Geoptima::assert_version(">=0.1.13")
12
12
 
13
13
  $debug=false
14
14
 
15
15
  $event_names=[]
16
16
  $files = []
17
17
  $print_limit = 10000
18
+ $gpx_options = {
19
+ 'scale' => 195, 'padding' => 5,
20
+ 'limit' => 2, 'png_limit' => 10,
21
+ 'points' => true, 'point_size' => 2, 'point_color' => '0000aa'
22
+ }
18
23
 
19
24
  $files = Geoptima::Options.process_args do |option|
20
25
  option.p {$print = true}
@@ -26,11 +31,13 @@ $files = Geoptima::Options.process_args do |option|
26
31
  option.l {$more_headers = true}
27
32
  option.e {$show_error_stats = true}
28
33
  option.g {$export_gpx = true}
34
+ option.t {$split_time = true}
29
35
  option.P {$export_prefix = ARGV.shift}
30
36
  option.E {$event_names += ARGV.shift.split(/[\,\;\:\.]+/)}
31
37
  option.T {$time_range = Geoptima::DateRange.from ARGV.shift}
32
38
  option.L {$print_limit = [1,ARGV.shift.to_i].max}
33
39
  option.M {$mapfile = ARGV.shift}
40
+ option.G {$gpx_options.merge! ARGV.shift.split(/[\,\;]+/).inject({}){|a,v| k=v.split(/[\:\=]+/);a[k[0]]=k[1]||true;a}}
34
41
  end.map do |file|
35
42
  File.exist?(file) ? file : puts("No such file: #{file}")
36
43
  end.compact
@@ -124,12 +131,25 @@ Usage: show_geoptima <-dwvpxomlsafegh> <-P export_prefix> <-L limit> <-E types>
124
131
  -f flush stdout #{cw $flush_stdout}
125
132
  -e show error statistics #{cw $show_error_stats}
126
133
  -g export GPX traces #{cw $export_gpx}
134
+ -t split time colum to multiple columns #{cw $split_time}
127
135
  -h show this help
128
136
  -P prefix for exported files (default: ''; current: #{$export_prefix})
129
137
  -E comma-seperated list of event types to show and export (default: all; current: #{$event_names.join(',')})
130
138
  -T time range to limit results to (default: all; current: #{$time_range})
131
139
  -L limit verbose output to specific number of lines #{cw $print_limit}
132
140
  -M mapfile of normal->altered header names: #{$mapfile}
141
+ -G GPX export options as ';' separated list of key:value pairs
142
+ Current GPX options: #{$gpx_options.inspect}
143
+ Known supported GPX options (might be more, see data.rb code):
144
+ limit:#{$gpx_options['limit']}\tLimit GPX output to traces with at least this number of events
145
+ png_limit:#{$gpx_options['png_limit']}\tLimit PNG output to traces with at least this number of events
146
+ scale:#{$gpx_options['scale']}\tSize of print area in PNG output
147
+ padding:#{$gpx_options['padding']}\tSpace around print area
148
+ points:#{$gpx_options['points']}\tTurn on/off points
149
+ point_size:#{$gpx_options['point_size']}\tSet point size
150
+ point_color:#{$gpx_options['point_color']}\tSet point color: RRGGBBAA in hex
151
+ PNG images will be 'scale + 2 * padding' big. The scale will be used for
152
+ the widest dimension, and the other will be reduced to fit the trace.
133
153
  EOHELP
134
154
  show_header_maps
135
155
  exit 0
@@ -172,7 +192,7 @@ class Export
172
192
  if $header_maps
173
193
  file.puts $header_maps.find{|hm| hm.event == key}.columns.map{|c| c[0]}.join("\t")
174
194
  else
175
- file.puts map_headers(base_headers+more_headers+header(key)).join("\t")
195
+ file.puts map_headers(time_headers+base_headers+more_headers+header(key)).join("\t")
176
196
  end
177
197
  end
178
198
  if $debug || $verbose
@@ -184,6 +204,17 @@ class Export
184
204
  def export_imei
185
205
  ($combine_all || $more_headers)
186
206
  end
207
+ def time_headers
208
+ $split_time ? ['Year','Month','Day','Hour','Minute','Second','Millisecond'] : []
209
+ end
210
+ def time_fields(event)
211
+ if $split_time
212
+ t = event.utc
213
+ [t.year,t.month,t.day,t.hour,t.minute,t.second,(t.second_fraction.to_f * 1000).to_i]
214
+ else
215
+ []
216
+ end
217
+ end
187
218
  def base_headers
188
219
  ['Time','Event','Latitude','Longitude'] +
189
220
  (export_imei ? ['IMEI'] : [])
@@ -223,9 +254,6 @@ class Export
223
254
  end
224
255
  end
225
256
  end
226
- def get_field(event,name)
227
- h=(base_headers+more_headers).grep(/#{name}/)
228
- end
229
257
  def cap(array,sep="")
230
258
  array.map do |v|
231
259
  "#{v[0..0].upcase}#{v[1..-1]}"
@@ -264,6 +292,15 @@ class Export
264
292
  out.puts trace.as_gpx
265
293
  end
266
294
  end
295
+ def export_png(trace)
296
+ puts "Exporting #{trace.length} GPS events to PNG: #{trace}"
297
+ if $verbose
298
+ puts "\tBounds: #{trace.bounds}"
299
+ puts "\tWidth: #{trace.width}"
300
+ puts "\tHeight: #{trace.height}"
301
+ end
302
+ trace.to_png "#{$export_prefix}#{trace}.png", $gpx_options
303
+ end
267
304
  def header(name=nil)
268
305
  @headers[name]
269
306
  end
@@ -324,8 +361,15 @@ $datasets.keys.sort.each do |imei|
324
361
  export = Export.new(imei,names,dataset)
325
362
  export.export_stats(dataset.stats) if($export_stats)
326
363
  if $export_gpx
364
+ merged_traces = Geoptima::MergedTrace.new(dataset)
327
365
  dataset.each_trace do |trace|
328
- export.export_gpx(trace)
366
+ export.export_gpx(trace) if(trace.length>=($gpx_options['limit'] || 1).to_i)
367
+ export.export_png(trace) if(trace.length>=($gpx_options['png_limit'] || 10).to_i)
368
+ merged_traces << trace if($gpx_options['merge'])
369
+ end
370
+ if($gpx_options['merge'])
371
+ export.export_gpx(merged_traces)
372
+ export.export_png(merged_traces)
329
373
  end
330
374
  end
331
375
  if $header_maps && $header_maps.length > 0
@@ -347,7 +391,7 @@ $datasets.keys.sort.each do |imei|
347
391
  names.each do |name|
348
392
  if event.name === name
349
393
  fields = export.header($seperate ? name : nil).map{|h| event[h]}
350
- b_fields = export.base_fields(event) + export.more_fields(event,dataset)
394
+ b_fields = export.time_fields(event) + export.base_fields(event) + export.more_fields(event,dataset)
351
395
  export.puts_to "#{b_fields.join("\t")}\t#{fields.join("\t")}", name
352
396
  if_le{puts "#{b_fields.join("\t")}\t#{event.fields.inspect}"}
353
397
  end
data/lib/geoptima/data.rb CHANGED
@@ -3,6 +3,11 @@
3
3
  require 'rubygems'
4
4
  require 'multi_json'
5
5
  require 'geoptima/daterange'
6
+ begin
7
+ require 'png'
8
+ rescue
9
+ puts "No PNG library installed, ignoring PNG output of GPX results"
10
+ end
6
11
 
7
12
  #
8
13
  # The Geoptima Module provides support for the Geoptima Client JSON file format
@@ -34,7 +39,7 @@ module Geoptima
34
39
  end
35
40
 
36
41
  class Trace
37
- attr_reader :dataset, :name, :tracename, :bounds, :events
42
+ attr_reader :dataset, :name, :tracename, :bounds, :events, :scale, :padding
38
43
  def initialize(dataset)
39
44
  @dataset = dataset
40
45
  @name = dataset.name
@@ -60,6 +65,8 @@ module Geoptima
60
65
  check_bounds_min :minlon, e.longitude
61
66
  check_bounds_max :maxlat, e.latitude
62
67
  check_bounds_max :maxlon, e.longitude
68
+ @width = nil
69
+ @height = nil
63
70
  end
64
71
  def check_bounds_min(key,value)
65
72
  @bounds[key] = value if(@bounds[key].nil? || @bounds[key] > value)
@@ -70,6 +77,46 @@ module Geoptima
70
77
  def each
71
78
  events.each{|e| yield e}
72
79
  end
80
+ def scale=(a)
81
+ @rescaled = false
82
+ @scale = a && (a.respond_to?('max') ? a : [a.to_i,a.to_i]) || [100,100]
83
+ end
84
+ def padding=(a)
85
+ @padding = a && (a.respond_to?('max') ? a : [a.to_i,a.to_i]) || [0,0]
86
+ end
87
+ def size
88
+ @size = [scale[0]+2*padding[0],scale[1]+2*padding[1]]
89
+ end
90
+ def scale
91
+ @scale ||= [100,100]
92
+ unless @rescaled
93
+ major,minor = (width > height) ? [0,1] : [1,0]
94
+ puts "About to rescale scale=#{@scale.inspect} using major=#{major}, minor=#{minor}, height=#{height}, width=#{width}" if($debug)
95
+ @scale[minor] = (@scale[major].to_f * height / width).to_i
96
+ @rescaled = true
97
+ end
98
+ @scale
99
+ end
100
+ def width
101
+ @width ||= @bounds[:maxlon].to_f - @bounds[:minlon].to_f
102
+ end
103
+ def height
104
+ @height ||= @bounds[:maxlat].to_f - @bounds[:minlat].to_f
105
+ end
106
+ def left
107
+ @left ||= @bounds[:minlon].to_f
108
+ end
109
+ def bottom
110
+ @bottom ||= @bounds[:minlat].to_f
111
+ end
112
+ def scale_event(e)
113
+ p = [e.longitude.to_f, e.latitude.to_f]
114
+ if scale
115
+ p[0] = padding[0] + ((p[0] - left) * (scale[0].to_f - 1) / (width)).to_i
116
+ p[1] = padding[1] + ((p[1] - bottom) * (scale[1].to_f - 1) / (height)).to_i
117
+ end
118
+ p
119
+ end
73
120
  def too_far(other)
74
121
  events && events[-1] && (events[-1].days_from(other) > 0.5 || events[-1].distance_from(other) > 0.002)
75
122
  end
@@ -90,16 +137,119 @@ module Geoptima
90
137
  <name>#{tracename}</name>
91
138
  <trkseg>
92
139
  } +
93
- events.map do |e|
94
- ei += 1
95
- event_as_gpx(e,ei)
96
- end.join("\n ") +
140
+ traces.map do |trace|
141
+ trace.events.map do |e|
142
+ ei += 1
143
+ event_as_gpx(e,ei)
144
+ end.join("\n ")
145
+ end.join("\n </trkseg><trkseg>") +
97
146
  """
98
147
  </trkseg>
99
148
  </trk>
100
149
  </gpx>
101
150
  """
102
151
  end
152
+ def fix_options(options={})
153
+ options.keys.each do |key|
154
+ val = options[key]
155
+ if val.to_s =~ /false/i
156
+ val = false
157
+ elsif val != true && val.to_i.to_s == val
158
+ val = val.to_i
159
+ end
160
+ options[key] = val
161
+ end
162
+ end
163
+ def traces
164
+ [self]
165
+ end
166
+ def colors
167
+ @colors ||= PNG::Color.constants.reject{|c| (c.is_a?(PNG::Color)) || c.to_s =~ /max/i || c.to_s =~ /background/i}.map{|c| PNG::Color.const_get c}.reject{|c| c == PNG::Color::Background}
168
+ end
169
+ def color(index=1)
170
+ self.colors[index%(self.colors.length)]
171
+ end
172
+ def to_png(filename, options={})
173
+ fix_options options
174
+ puts "Exporting with options: #{options.inspect}"
175
+ self.scale = options['scale']
176
+ self.padding = options['padding']
177
+ ['scale','padding','size','bounds','width','height'].each do |a|
178
+ puts "\t#{a}: #{self.send(a).inspect}"
179
+ end
180
+ canvas = PNG::Canvas.new size[0],size[1]
181
+
182
+ traces.each_with_index do |trace,index|
183
+ prev = nil
184
+ point_color = color(index)
185
+ line_color = PNG::Color.from "0x00006688"
186
+ if options['point_color'] && !(options['point_color'] =~ /auto/i)
187
+ pc = options['point_color'].gsub(/^\#/,'').gsub(/^0x/,'').upcase
188
+ pc = "0x#{pc}FFFFFFFF"[0...10]
189
+ begin
190
+ point_color = PNG::Color.from pc
191
+ rescue
192
+ puts "Failed to interpret color #{pc}, use format 0x00000000: #{$!}"
193
+ end
194
+ end
195
+ puts "Got point color #{point_color} from index #{index}"
196
+ trace.events.each do |e|
197
+ p = scale_event(e)
198
+ begin
199
+ # draw an anti-aliased line
200
+ if prev && prev != p
201
+ canvas.line prev[0], prev[1], p[0], p[1], line_color
202
+ end
203
+
204
+ if options['points']
205
+ # Set a point to a color
206
+ n = options['point_size'].to_i / 2
207
+ r = (-n..n)
208
+ r.each do |x|
209
+ r.each do |y|
210
+ canvas[p[0]+x, p[1]-y] = point_color
211
+ end
212
+ end
213
+ end
214
+ rescue
215
+ puts "Error in writing PNG: #{$!}"
216
+ end
217
+
218
+ prev = p
219
+ end
220
+ end
221
+
222
+ png = PNG.new canvas
223
+ png.save filename
224
+ end
225
+ end
226
+
227
+ class MergedTrace < Trace
228
+ attr_reader :traces
229
+ def initialize(dataset)
230
+ @dataset = dataset
231
+ @name = dataset.name
232
+ @traces = []
233
+ end
234
+ def tracename
235
+ @tracename ||= "Merged-#{traces.length}-traces-#{traces[0]}"
236
+ end
237
+ def <<(t)
238
+ check_bounds(t)
239
+ @traces << t
240
+ end
241
+ def length
242
+ @length ||= traces.inject(0){|a,t| a+=t.length;a}
243
+ end
244
+ def check_bounds(t)
245
+ @bounds ||= {}
246
+ check_bounds_min :minlat, t.bounds[:minlat]
247
+ check_bounds_min :minlon, t.bounds[:minlon]
248
+ check_bounds_max :maxlat, t.bounds[:maxlat]
249
+ check_bounds_max :maxlon, t.bounds[:maxlon]
250
+ @width = nil
251
+ @height = nil
252
+ end
103
253
  end
104
254
 
105
255
  module ErrorCounter
@@ -174,6 +324,7 @@ module Geoptima
174
324
  a
175
325
  end
176
326
  @timeoffset = (@fields['timeoffset'].to_f / MSPERDAY.to_f)
327
+ @time = start + timeoffset # Note we set this again later after corrections (need it now for puts output)
177
328
  if(@timeoffset<-0.0000001)
178
329
  puts "Have negative time offset: #{@fields['timeoffset']}" if($debug)
179
330
  incr_error "#4506 negative offsets"
@@ -229,6 +380,9 @@ module Geoptima
229
380
  def locate_if_closer_than(gps,seconds=60)
230
381
  locate(gps) if(closer_than(gps,seconds))
231
382
  end
383
+ def puts line
384
+ Kernel.puts "#{name}[#{time}]: #{line}"
385
+ end
232
386
  def to_s
233
387
  "#{name}[#{time}]: #{@fields.inspect}"
234
388
  end
@@ -237,9 +391,10 @@ module Geoptima
237
391
  # The Geoptima::Data is an entire JSON file of events
238
392
  class Data
239
393
  include ErrorCounter
240
- attr_reader :path, :json, :count
394
+ attr_reader :path, :name, :json, :count
241
395
  def initialize(path)
242
396
  @path = path
397
+ @name = File.basename(path)
243
398
  # @json = JSON.parse(File.read(path))
244
399
  @json = MultiJson.decode(File.read(path))
245
400
  @fields = {}
@@ -261,6 +416,9 @@ module Geoptima
261
416
  def to_s
262
417
  json.to_json[0..100]
263
418
  end
419
+ def puts line
420
+ Kernel.puts "#{name}: #{line}"
421
+ end
264
422
  def geoptima
265
423
  @geoptima ||= json['geoptima']
266
424
  end
@@ -273,6 +431,9 @@ module Geoptima
273
431
  def imei
274
432
  @imei ||= self['imei']
275
433
  end
434
+ def id
435
+ @id ||= self['id'] || self['udid'] || self['imei']
436
+ end
276
437
  def [](key)
277
438
  @fields[key] ||= subscriber[key] || subscriber[key.downcase]
278
439
  end
@@ -628,18 +789,40 @@ module Geoptima
628
789
  "Dataset:#{name}, IMEI:#{imeis.join(',')}, IMSI:#{imsis.join(',')}, Platform:#{platforms.join(',')}, Model:#{models.join(',')}, OS:#{oses.join(',')}, Files:#{file_count}, Events:#{sorted && sorted.length}"
629
790
  end
630
791
 
631
- def self.make_datasets(files, options={})
632
- datasets = {}
633
- files.each do |file|
792
+ def self.add_file_to_datasets(datasets,file,options={})
793
+ if File.directory?(file)
794
+ add_directory_to_datasets(datasets,file,options)
795
+ else
634
796
  geoptima=Geoptima::Data.new(file)
635
797
  unless geoptima.valid?
636
798
  puts "INVALID: #{geoptima.start}\t#{file}\n\n"
637
799
  else
638
- key = options[:combine_all] ? 'all' : geoptima['imei']
800
+ key = options[:combine_all] ? 'all' : geoptima.id
639
801
  datasets[key] ||= Geoptima::Dataset.new(key, options)
640
802
  datasets[key] << geoptima
641
803
  end
642
804
  end
805
+ end
806
+
807
+ def self.add_directory_to_datasets(datasets,directory,options={})
808
+ Dir.open(directory).each do |file|
809
+ next if(file =~ /^\./)
810
+ path = "#{directory}/#{file}"
811
+ if File.directory? path
812
+ add_directory_to_datasets(datasets,path,options)
813
+ elsif file =~ /\.json/i
814
+ add_file_to_datasets(datasets,path,options)
815
+ else
816
+ puts "Ignoring files without JSON extension: #{path}"
817
+ end
818
+ end
819
+ end
820
+
821
+ def self.make_datasets(files, options={})
822
+ datasets = {}
823
+ files.each do |file|
824
+ add_file_to_datasets(datasets,file,options)
825
+ end
643
826
  datasets
644
827
  end
645
828
 
@@ -1,6 +1,6 @@
1
1
  module Geoptima
2
2
 
3
- VERSION = "0.1.12"
3
+ VERSION = "0.1.13"
4
4
 
5
5
  class Version
6
6
  attr_reader :comparator, :version, :major, :minor, :patch
metadata CHANGED
@@ -1,75 +1,81 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: geoptima
3
- version: !ruby/object:Gem::Version
4
- hash: 3
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.13
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 1
9
- - 12
10
- version: 0.1.12
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Craig Taverner
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2012-06-08 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
12
+ date: 2012-07-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
21
15
  name: multi_json
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
24
17
  none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- hash: 19
29
- segments:
30
- - 1
31
- - 1
32
- - 0
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
33
21
  version: 1.1.0
34
22
  type: :runtime
35
- version_requirements: *id001
36
- - !ruby/object:Gem::Dependency
37
- name: json_pure
38
23
  prerelease: false
39
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.1.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: json_pure
32
+ requirement: !ruby/object:Gem::Requirement
40
33
  none: false
41
- requirements:
42
- - - ">="
43
- - !ruby/object:Gem::Version
44
- hash: 5
45
- segments:
46
- - 1
47
- - 6
48
- - 5
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
49
37
  version: 1.6.5
50
38
  type: :runtime
51
- version_requirements: *id002
52
- description: |
53
- Geoptima is a suite of applications for measuring and locating mobile/cellular subscriber experience on GPS enabled smartphones.
54
- It is produced by AmanziTel AB in Helsingborg, Sweden, and supports many phone manufacturers, with free downloads from the
55
- various app stores, markets or marketplaces. This Ruby library is only capable of reading the JSON format files priduced by these phones
56
- and reformating them as CSV for further analysis in Excel. This is a simple and independent way of analysing the data, when
57
- compared to the full-featured analysis applications and servers available from AmanziTel. If you want to analyse a limited amount
58
- of data in excel, or with Ruby, then this GEM might be for you. If you want to analyse large amounts of data, from many subscribers, or over long periods of time
59
- then rather consider the NetView and Customer IQ applications from AmanziTel at www.amanzitel.com.
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 1.6.5
46
+ description: ! 'Geoptima is a suite of applications for measuring and locating mobile/cellular
47
+ subscriber experience on GPS enabled smartphones.
48
+
49
+ It is produced by AmanziTel AB in Helsingborg, Sweden, and supports many phone manufacturers,
50
+ with free downloads from the
60
51
 
52
+ various app stores, markets or marketplaces. This Ruby library is only capable of
53
+ reading the JSON format files priduced by these phones
54
+
55
+ and reformating them as CSV for further analysis in Excel. This is a simple and
56
+ independent way of analysing the data, when
57
+
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
+ '
61
68
  email: craig@amanzi.com
62
- executables:
69
+ executables:
63
70
  - show_geoptima
64
71
  - geoptima_file_time
65
72
  - csv_chart
66
73
  - csv_stats
67
74
  - csv_merge
68
75
  extensions: []
69
-
70
- extra_rdoc_files:
76
+ extra_rdoc_files:
71
77
  - README.rdoc
72
- files:
78
+ files:
73
79
  - bin/show_geoptima_sos
74
80
  - bin/show_geoptima
75
81
  - bin/csv_chart
@@ -98,9 +104,8 @@ files:
98
104
  - geoptima.gemspec
99
105
  homepage: http://github.com/craigtaverner/geoptima.rb
100
106
  licenses: []
101
-
102
107
  post_install_message:
103
- rdoc_options:
108
+ rdoc_options:
104
109
  - --quiet
105
110
  - --title
106
111
  - Geoptima.rb
@@ -108,34 +113,24 @@ rdoc_options:
108
113
  - --main
109
114
  - README.rdoc
110
115
  - --inline-source
111
- require_paths:
116
+ require_paths:
112
117
  - lib
113
- required_ruby_version: !ruby/object:Gem::Requirement
118
+ required_ruby_version: !ruby/object:Gem::Requirement
114
119
  none: false
115
- requirements:
116
- - - ">="
117
- - !ruby/object:Gem::Version
118
- hash: 59
119
- segments:
120
- - 1
121
- - 8
122
- - 6
120
+ requirements:
121
+ - - ! '>='
122
+ - !ruby/object:Gem::Version
123
123
  version: 1.8.6
124
- required_rubygems_version: !ruby/object:Gem::Requirement
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
125
  none: false
126
- requirements:
127
- - - ">="
128
- - !ruby/object:Gem::Version
129
- hash: 3
130
- segments:
131
- - 0
132
- version: "0"
126
+ requirements:
127
+ - - ! '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
133
130
  requirements: []
134
-
135
131
  rubyforge_project: geoptima
136
- rubygems_version: 1.8.15
132
+ rubygems_version: 1.8.24
137
133
  signing_key:
138
134
  specification_version: 3
139
135
  summary: Ruby access to Geoptima JSON files
140
136
  test_files: []
141
-