gooby 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +144 -180
- data/bin/example_usage.txt +55 -0
- data/bin/gooby_been_there.rb +35 -0
- data/bin/gooby_config.rb +16 -0
- data/bin/gooby_gen_gmap.rb +16 -0
- data/bin/gooby_parser.rb +19 -0
- data/bin/gooby_splitter.rb +18 -0
- data/bin/gooby_version.rb +16 -0
- data/bin/run_all.sh +23 -0
- data/bin/run_been_there.sh +16 -0
- data/bin/run_db_gen.sh +11 -0
- data/bin/run_db_load.sh +11 -0
- data/bin/run_gen_gmaps.sh +20 -0
- data/bin/run_parse.sh +43 -0
- data/bin/run_parse_named.sh +19 -0
- data/bin/run_split.sh +23 -0
- data/config/gooby_config.yaml +137 -0
- data/data/20050305_corporate_cup_hm.csv +251 -251
- data/data/20050430_nashville_marathon.csv +1208 -1208
- data/data/20060115_phoenix_marathon.csv +1280 -1280
- data/data/davidson_11m_20070101.csv +251 -0
- data/data/davidson_11m_20070101.xml +2020 -0
- data/data/davidson_5K_20070505.csv +286 -0
- data/data/davidson_5K_20070505.xml +2875 -0
- data/lib/gooby.rb +889 -361
- data/samples/20050305_corporate_cup_hm.html +270 -270
- data/samples/20050430_nashville_marathon.html +1240 -1240
- data/samples/20060115_phoenix_marathon.html +1312 -1312
- data/samples/been_there.txt +744 -0
- data/samples/davidson_11m_20070101.html +432 -0
- data/samples/davidson_5K_20070505.html +395 -0
- data/sql/gooby.ddl +56 -0
- data/sql/gooby_load.dml +35 -0
- metadata +30 -32
- data/bin/20050305_corporate_cup_hm_to_csv.rb +0 -9
- data/bin/20050430_nashville_marathon_to_csv.rb +0 -9
- data/bin/20060115_phoenix_marathon_to_csv.rb +0 -9
- data/bin/activity_2007_03_10_13_02_32.xml_to_csv.rb +0 -9
- data/bin/example_usage.rb +0 -46
- data/bin/example_usage.sh +0 -52
- data/bin/gen_gap_phx.rb +0 -10
- data/bin/gen_gmap_cc_2005.rb +0 -10
- data/bin/gen_gmap_cc_2007.rb +0 -10
- data/bin/gen_gmap_nashville.rb +0 -10
- data/bin/gen_gmap_phx.rb +0 -10
- data/bin/phx_to_csv.rb +0 -47
- data/bin/split_forerunner_logbook_2007.rb +0 -10
- data/bin/split_training_center_2007.rb +0 -8
- data/data/2007_03_10.tcx +0 -28445
- data/data/activity_2007_03_10_13_02_32.csv +0 -1168
- data/data/activity_2007_03_10_13_02_32.xml +0 -11695
- data/data/forerunner_2007.xml +0 -31872
- data/data/geo_data.txt +0 -171
- data/pkg/code_header.txt +0 -21
- data/pkg/pkg.rb +0 -238
- data/pkg/test_header.txt +0 -19
- data/samples/20070310_corporate_cup_hm.html +0 -1367
- data/samples/gps_point_capture.html +0 -54
- data/samples/phoenix_marathon.html +0 -1596
- data/tests/ts_gooby.rb +0 -1109
- data/tests/ts_gooby_min.rb +0 -550
    
        data/lib/gooby.rb
    CHANGED
    
    | @@ -6,36 +6,41 @@ This file contains the classes and modules for the Gooby project. | |
| 6 6 | 
             
            See file 'tests/ts_gooby.rb' for the regression test suite.
         | 
| 7 7 |  | 
| 8 8 | 
             
            Index of Modules and Classes in this file:
         | 
| 9 | 
            -
            line  type    Module or Class name
         | 
| 10 | 
            -
            ----  ------  ---------------------------
         | 
| 11 | 
            -
               | 
| 12 | 
            -
               | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 9 | 
            +
                line  type    Module or Class name
         | 
| 10 | 
            +
                ----  ------  ---------------------------
         | 
| 11 | 
            +
                  57  module  Gooby
         | 
| 12 | 
            +
                  64  module  GoobyKernel
         | 
| 13 | 
            +
                 191  module  TestHelper
         | 
| 14 | 
            +
                 209  class   GoobyObject
         | 
| 15 | 
            +
                 222  class   CounterHash
         | 
| 16 | 
            +
                 305  class   DelimLine
         | 
| 17 | 
            +
                 340  class   DtTm
         | 
| 18 | 
            +
                 417  class   Duration
         | 
| 19 | 
            +
                 496  class   ForerunnerXmlParser
         | 
| 20 | 
            +
                 665  class   ForerunnerXmlSplitter
         | 
| 21 | 
            +
                 775  class   TrainingCenterXmlParser
         | 
| 22 | 
            +
                 962  class   TrainingCenterXmlSplitter
         | 
| 23 | 
            +
                1067  class   GeoData
         | 
| 24 | 
            +
                1250  class   GoogleMapGenerator
         | 
| 25 | 
            +
                1625  class   History
         | 
| 26 | 
            +
                1656  class   Lap
         | 
| 27 | 
            +
                1671  class   Line
         | 
| 28 | 
            +
                1749  class   Configuration
         | 
| 29 | 
            +
                1848  class   Point
         | 
| 30 | 
            +
                1987  class   CsvPoint
         | 
| 31 | 
            +
                2042  class   CvsRun
         | 
| 32 | 
            +
                2060  class   CsvReader
         | 
| 33 | 
            +
                2121  class   Trackpoint
         | 
| 34 | 
            +
                2319  class   Run
         | 
| 35 | 
            +
                2521  class   SimpleXmlParser
         | 
| 36 | 
            +
                2561  class   Track
         | 
| 37 | 
            +
                2593  class   Course
         | 
| 38 | 
            +
                2713  class   CodeScanner
         | 
| 39 | 
            +
                3003  class   GoobyCommand
         | 
| 36 40 |  | 
| 37 41 | 
             
            Gooby - Copyright 2007 by Chris Joakim.
         | 
| 38 42 | 
             
            Gooby is available under GNU General Public License (GPL) license.
         | 
| 43 | 
            +
             | 
| 39 44 | 
             
            =end
         | 
| 40 45 |  | 
| 41 46 | 
             
            require 'date'
         | 
| @@ -43,6 +48,7 @@ require 'find' | |
| 43 48 | 
             
            require 'rbconfig'
         | 
| 44 49 | 
             
            require 'rexml/document'
         | 
| 45 50 | 
             
            require 'rexml/streamlistener'
         | 
| 51 | 
            +
            require 'singleton'
         | 
| 46 52 | 
             
            require 'time'
         | 
| 47 53 | 
             
            require 'yaml'
         | 
| 48 54 |  | 
| @@ -57,19 +63,19 @@ module Gooby | |
| 57 63 |  | 
| 58 64 | 
             
              module GoobyKernel
         | 
| 59 65 |  | 
| 60 | 
            -
              # Return a String version number, like '1. | 
| 66 | 
            +
              # Return a String version number, like '1.1.0'.
         | 
| 61 67 |  | 
| 62 68 | 
             
                def project_name
         | 
| 63 69 | 
             
                  'Gooby'
         | 
| 64 70 | 
             
                end
         | 
| 65 71 |  | 
| 66 72 | 
             
                def project_version_number   
         | 
| 67 | 
            -
                  '1. | 
| 73 | 
            +
                  '1.1.0'
         | 
| 68 74 | 
             
                end
         | 
| 69 75 |  | 
| 70 76 | 
             
              # Return a String date, like '2007/03/21'.  
         | 
| 71 77 | 
             
                def project_date       
         | 
| 72 | 
            -
                  '2007/ | 
| 78 | 
            +
                  '2007/06/10'
         | 
| 73 79 | 
             
                end
         | 
| 74 80 |  | 
| 75 81 | 
             
                # Return a String containing the project author name.
         | 
| @@ -372,10 +378,10 @@ module Gooby | |
| 372 378 | 
             
                  @time.strftime("%Y-%m-%d")
         | 
| 373 379 | 
             
                end
         | 
| 374 380 |  | 
| 375 | 
            -
                def yyyy_mm_dd_hh_mm_ss
         | 
| 376 | 
            -
                  @time.strftime("%Y-%m-%d | 
| 381 | 
            +
                def yyyy_mm_dd_hh_mm_ss(delim=' ')
         | 
| 382 | 
            +
                  @time.strftime("%Y-%m-%d#{delim}%H:%M:%S")
         | 
| 377 383 | 
             
                end
         | 
| 378 | 
            -
             | 
| 384 | 
            +
                  
         | 
| 379 385 | 
             
                def hh_mm_ss
         | 
| 380 386 | 
             
                  @time.strftime("%H:%M:%S")
         | 
| 381 387 | 
             
                end
         | 
| @@ -386,7 +392,7 @@ module Gooby | |
| 386 392 | 
             
                    t = @time - (anotherDtTm.to_i)
         | 
| 387 393 | 
             
                    t.strftime("%H:%M:%S")
         | 
| 388 394 | 
             
                  else
         | 
| 389 | 
            -
                    ' | 
| 395 | 
            +
                    '00:00:00'  
         | 
| 390 396 | 
             
                  end
         | 
| 391 397 | 
             
                end
         | 
| 392 398 |  | 
| @@ -527,6 +533,7 @@ module Gooby | |
| 527 533 | 
             
                    @run_count = @run_count + 1
         | 
| 528 534 | 
             
                    @lap_count = 0
         | 
| 529 535 | 
             
                    @track_count = 0
         | 
| 536 | 
            +
                    @trackpoint_count = 0        
         | 
| 530 537 | 
             
                    @curr_run  = Run.new(@run_count)
         | 
| 531 538 | 
             
                    @history.add_run(@curr_run)
         | 
| 532 539 | 
             
                    @cv_hash['Notes'] = ''
         | 
| @@ -542,7 +549,6 @@ module Gooby | |
| 542 549 | 
             
                  if is_tag?('Track', tagname)
         | 
| 543 550 | 
             
                    @track_count = @track_count + 1      
         | 
| 544 551 | 
             
                    @curr_track  = Track.new(@track_count)
         | 
| 545 | 
            -
                    @trackpoint_count = 0   
         | 
| 546 552 | 
             
                    return   
         | 
| 547 553 | 
             
                  end
         | 
| 548 554 | 
             
                end
         | 
| @@ -555,20 +561,20 @@ module Gooby | |
| 555 561 | 
             
                    if is_tag?('Position', tagname)
         | 
| 556 562 | 
             
                      lat  = @cv_hash['Latitude']
         | 
| 557 563 | 
             
                      long = @cv_hash['Longitude']
         | 
| 558 | 
            -
                      @curr_begin_position =  | 
| 559 | 
            -
                      @@curr_end_position | 
| 564 | 
            +
                      @curr_begin_position = Point.new(lat.strip, long.strip)
         | 
| 565 | 
            +
                      @@curr_end_position  = Point.new(lat.strip, long.strip)       
         | 
| 560 566 | 
             
                    end 
         | 
| 561 567 |  | 
| 562 568 | 
             
                    if is_tag?('BeginPosition', tagname)
         | 
| 563 569 | 
             
                      lat  = @cv_hash['Latitude']
         | 
| 564 570 | 
             
                      long = @cv_hash['Longitude']
         | 
| 565 | 
            -
                      @curr_begin_position =  | 
| 571 | 
            +
                      @curr_begin_position = Point.new(lat.strip, long.strip)      
         | 
| 566 572 | 
             
                    end
         | 
| 567 573 |  | 
| 568 574 | 
             
                    if is_tag?('EndPosition', tagname)
         | 
| 569 575 | 
             
                      lat  = @cv_hash['Latitude']
         | 
| 570 576 | 
             
                      long = @cv_hash['Longitude']
         | 
| 571 | 
            -
                      @@curr_end_position =  | 
| 577 | 
            +
                      @@curr_end_position = Point.new(lat.strip, long.strip)      
         | 
| 572 578 | 
             
                    end
         | 
| 573 579 |  | 
| 574 580 | 
             
                    if is_tag?('Trackpoint', tagname)
         | 
| @@ -576,7 +582,7 @@ module Gooby | |
| 576 582 | 
             
                      lat  = @cv_hash['Latitude']
         | 
| 577 583 | 
             
                      long = @cv_hash['Longitude']
         | 
| 578 584 | 
             
                      alt  = @cv_hash['Altitude']   
         | 
| 579 | 
            -
                      time = @cv_hash['Time'] | 
| 585 | 
            +
                      time = @cv_hash['Time']            
         | 
| 580 586 | 
             
                      tp   = Trackpoint.new(@trackpoint_count, lat, long, alt, time)
         | 
| 581 587 | 
             
                      @curr_track.add_trackpoint(tp)
         | 
| 582 588 | 
             
                    end
         | 
| @@ -629,10 +635,8 @@ module Gooby | |
| 629 635 | 
             
                end
         | 
| 630 636 |  | 
| 631 637 | 
             
              # Iterate all parsed Run objects and print each with put_tkpt_csv.
         | 
| 632 | 
            -
                def put_all_run_tkpt_csv( | 
| 633 | 
            -
                  @history.runs.each { |run| 
         | 
| 634 | 
            -
                    run.put_tkpt_csv(with_header_comment)
         | 
| 635 | 
            -
                  } 
         | 
| 638 | 
            +
                def put_all_run_tkpt_csv() 
         | 
| 639 | 
            +
                  @history.runs.each { |run| run.put_tkpt_csv() } 
         | 
| 636 640 | 
             
                end
         | 
| 637 641 |  | 
| 638 642 | 
             
                private 
         | 
| @@ -760,7 +764,7 @@ module Gooby | |
| 760 764 | 
             
            # =============================================================================
         | 
| 761 765 |  | 
| 762 766 | 
             
            =begin rdoc
         | 
| 763 | 
            -
              Instances of this class are used to parse a Garmin TrainingCenter XML file
         | 
| 767 | 
            +
              Instances of this class are used to parse a Garmin TrainingCenter XML(TCX) file
         | 
| 764 768 | 
             
              in a SAX-like manner.  Instances of the model classes - History, Run, Track,
         | 
| 765 769 | 
             
              Trackpoint, etc. are created in this parsing process.  
         | 
| 766 770 |  | 
| @@ -779,19 +783,21 @@ module Gooby | |
| 779 783 | 
             
                attr_reader :history, :cvHash, :tagCount
         | 
| 780 784 |  | 
| 781 785 | 
             
                def initialize
         | 
| 782 | 
            -
                  @cv_hash | 
| 783 | 
            -
                  @tag_count | 
| 784 | 
            -
                  @run_count | 
| 785 | 
            -
                  @lap_count | 
| 786 | 
            -
                  @track_count | 
| 787 | 
            -
                  @trackpoint_count | 
| 788 | 
            -
                  @curr_text | 
| 789 | 
            -
                  @history | 
| 790 | 
            -
                  @curr_run | 
| 791 | 
            -
                  @curr_lap | 
| 792 | 
            -
                  @curr_track | 
| 793 | 
            -
                  @curr_begin_position | 
| 794 | 
            -
                  @@curr_end_position | 
| 786 | 
            +
                  @cv_hash               = Hash.new("")
         | 
| 787 | 
            +
                  @tag_count             = 0
         | 
| 788 | 
            +
                  @run_count             = 0
         | 
| 789 | 
            +
                  @lap_count             = 0
         | 
| 790 | 
            +
                  @track_count           = 0
         | 
| 791 | 
            +
                  @trackpoint_count      = 0
         | 
| 792 | 
            +
                  @curr_text             = "";
         | 
| 793 | 
            +
                  @history               = History.new
         | 
| 794 | 
            +
                  @curr_run              = nil
         | 
| 795 | 
            +
                  @curr_lap              = nil
         | 
| 796 | 
            +
                  @curr_track            = nil
         | 
| 797 | 
            +
                  @curr_begin_position   = nil
         | 
| 798 | 
            +
                  @@curr_end_position    = nil
         | 
| 799 | 
            +
                  @first_lap_start_time  = nil
         | 
| 800 | 
            +
                  @curr_lap_start_time   = ''
         | 
| 795 801 | 
             
                end
         | 
| 796 802 |  | 
| 797 803 | 
             
                public
         | 
| @@ -810,6 +816,7 @@ module Gooby | |
| 810 816 | 
             
                    @run_count = @run_count + 1
         | 
| 811 817 | 
             
                    @lap_count = 0
         | 
| 812 818 | 
             
                    @track_count = 0
         | 
| 819 | 
            +
                    @trackpoint_count = 0
         | 
| 813 820 | 
             
                    @curr_run  = Run.new(@run_count)
         | 
| 814 821 | 
             
                    @history.add_run(@curr_run)
         | 
| 815 822 | 
             
                    @cv_hash['Notes'] = ''
         | 
| @@ -817,16 +824,26 @@ module Gooby | |
| 817 824 | 
             
                  end
         | 
| 818 825 |  | 
| 819 826 | 
             
                  if is_tag?('Lap', tagname)
         | 
| 820 | 
            -
                    @lap_count = | 
| 827 | 
            +
                    @lap_count =  @lap_count + 1
         | 
| 821 828 | 
             
                    @curr_lap  = Lap.new(@lap_count)
         | 
| 822 | 
            -
                     | 
| 829 | 
            +
                    
         | 
| 830 | 
            +
                    attrs.each { |attr|
         | 
| 831 | 
            +
                      name = attr[0]
         | 
| 832 | 
            +
                      val  = attr[1]
         | 
| 833 | 
            +
                      if (name && (name == 'StartTime')) 
         | 
| 834 | 
            +
                        if (@first_lap_start_time == nil)
         | 
| 835 | 
            +
                          @first_lap_start_time = "#{val}"
         | 
| 836 | 
            +
                        end
         | 
| 837 | 
            +
                        @curr_lap_start_time = "#{val}" 
         | 
| 838 | 
            +
                      end
         | 
| 839 | 
            +
                    }
         | 
| 840 | 
            +
                    # TODO - capture value of 'StartTime' attribute.
         | 
| 823 841 | 
             
                    return
         | 
| 824 842 | 
             
                  end
         | 
| 825 843 |  | 
| 826 844 | 
             
                  if is_tag?('Track', tagname)
         | 
| 827 845 | 
             
                    @track_count = @track_count + 1      
         | 
| 828 846 | 
             
                    @curr_track  = Track.new(@track_count)
         | 
| 829 | 
            -
                    @trackpoint_count = 0   
         | 
| 830 847 | 
             
                    return   
         | 
| 831 848 | 
             
                  end
         | 
| 832 849 |  | 
| @@ -840,20 +857,20 @@ module Gooby | |
| 840 857 | 
             
                    if is_tag?('Position', tagname)
         | 
| 841 858 | 
             
                      lat  = @cv_hash['LatitudeDegrees']
         | 
| 842 859 | 
             
                      long = @cv_hash['LongitudeDegrees']
         | 
| 843 | 
            -
                      @curr_begin_position =  | 
| 844 | 
            -
                      @@curr_end_position | 
| 860 | 
            +
                      @curr_begin_position = Point.new(lat.strip, long.strip)
         | 
| 861 | 
            +
                      @@curr_end_position  = Point.new(lat.strip, long.strip)       
         | 
| 845 862 | 
             
                    end 
         | 
| 846 863 |  | 
| 847 864 | 
             
                    if is_tag?('BeginPosition', tagname)
         | 
| 848 865 | 
             
                      lat  = @cv_hash['LatitudeDegrees']
         | 
| 849 866 | 
             
                      long = @cv_hash['LongitudeDegrees']
         | 
| 850 | 
            -
                      @curr_begin_position =  | 
| 867 | 
            +
                      @curr_begin_position = Point.new(lat.strip, long.strip)      
         | 
| 851 868 | 
             
                    end
         | 
| 852 869 |  | 
| 853 870 | 
             
                    if is_tag?('EndPosition', tagname)
         | 
| 854 871 | 
             
                      lat  = @cv_hash['LatitudeDegrees']
         | 
| 855 872 | 
             
                      long = @cv_hash['LongitudeDegrees']
         | 
| 856 | 
            -
                      @@curr_end_position =  | 
| 873 | 
            +
                      @@curr_end_position = Point.new(lat.strip, long.strip)      
         | 
| 857 874 | 
             
                    end
         | 
| 858 875 |  | 
| 859 876 | 
             
                    if is_tag?('Trackpoint', tagname)
         | 
| @@ -861,8 +878,14 @@ module Gooby | |
| 861 878 | 
             
                      lat  = @cv_hash['LatitudeDegrees']
         | 
| 862 879 | 
             
                      long = @cv_hash['LongitudeDegrees']
         | 
| 863 880 | 
             
                      alt  = @cv_hash['AltitudeMeters']   
         | 
| 864 | 
            -
                      time = @cv_hash['Time'] | 
| 865 | 
            -
             | 
| 881 | 
            +
                      time = @cv_hash['Time'] 
         | 
| 882 | 
            +
             | 
| 883 | 
            +
                      hash = Hash.new('')
         | 
| 884 | 
            +
                      hash['lap_number']           = "#{@lap_count}"          
         | 
| 885 | 
            +
                      hash['first_lap_start_time'] = "#{@first_lap_start_time}"
         | 
| 886 | 
            +
                      hash['curr_lap_start_time']  = "#{@curr_lap_start_time}"
         | 
| 887 | 
            +
                                       
         | 
| 888 | 
            +
                      tp = Trackpoint.new(@trackpoint_count, lat, long, alt, time, hash)
         | 
| 866 889 | 
             
                      @curr_track.add_trackpoint(tp)
         | 
| 867 890 | 
             
                    end
         | 
| 868 891 |  | 
| @@ -872,14 +895,7 @@ module Gooby | |
| 872 895 | 
             
                      end
         | 
| 873 896 | 
             
                    end
         | 
| 874 897 |  | 
| 875 | 
            -
                    if is_tag?('Lap', tagname)
         | 
| 876 | 
            -
                      # TotalTimeSeconds DistanceMeters
         | 
| 877 | 
            -
                      # TODO - rework tnd of Lap for tcx
         | 
| 878 | 
            -
                      # @curr_lap.startTime = @cv_hash['StartTime']
         | 
| 879 | 
            -
                      # @curr_lap.duration  = Duration.new(@cv_hash['Duration'])
         | 
| 880 | 
            -
                      # @curr_lap.length    = @cv_hash['Length']                          
         | 
| 881 | 
            -
                      # @curr_lap.begin_position = @curr_begin_position
         | 
| 882 | 
            -
                      # @curr_lap.end_position   = @@curr_end_position        
         | 
| 898 | 
            +
                    if is_tag?('Lap', tagname)      
         | 
| 883 899 | 
             
                      @curr_run.add_lap(@curr_lap)
         | 
| 884 900 | 
             
                    end
         | 
| 885 901 |  | 
| @@ -916,10 +932,8 @@ module Gooby | |
| 916 932 | 
             
                end
         | 
| 917 933 |  | 
| 918 934 | 
             
              # Iterate all parsed Run objects and print each with put_tkpt_csv.
         | 
| 919 | 
            -
                def put_all_run_tkpt_csv( | 
| 920 | 
            -
                  @history.runs.each { |run| 
         | 
| 921 | 
            -
                    run.put_tkpt_csv(with_header_comment)
         | 
| 922 | 
            -
                  } 
         | 
| 935 | 
            +
                def put_all_run_tkpt_csv() 
         | 
| 936 | 
            +
                  @history.runs.each { |run| run.put_tkpt_csv() } 
         | 
| 923 937 | 
             
                end
         | 
| 924 938 |  | 
| 925 939 | 
             
                private 
         | 
| @@ -1243,7 +1257,10 @@ module Gooby | |
| 1243 1257 | 
             
                # 1 | 2006-01-15T18:31:10Z | 1279 | 33.42601 | -111.92927 | 347.654 | 26.3514930151813
         | 
| 1244 1258 | 
             
                # 1 | 2004-11-13T13:05:20Z | 2 | 37.54318 | -77.43636 | -58.022 | 0.00297286231747969 
         | 
| 1245 1259 |  | 
| 1246 | 
            -
                 | 
| 1260 | 
            +
                # primary_key|run_id|date|time|tkpt_num|latitude|longitude|altitude_ft|run_distance|run_elapsed|lap_tkpt_number|lap_distance|lap_elapsed
         | 
| 1261 | 
            +
                # 2005-03-05T13:00:29Z.2|2005-03-05T13:00:29Z|2005-03-05|13:00:49|2|35.22054|-80.84506|738.4161312|0.046918021941152|00:00:20|2|0.046918021941152|00:00:20
         | 
| 1262 | 
            +
                
         | 
| 1263 | 
            +
                def initialize(csv_file, dttm_idx=1, num_idx=4, lat_idx=5, lng_idx=6, alt_idx=7, cdist_idx=8)
         | 
| 1247 1264 | 
             
                  @csv_file  = csv_file
         | 
| 1248 1265 | 
             
                  @dttm_idx  = dttm_idx
         | 
| 1249 1266 | 
             
                  @num_idx   = num_idx
         | 
| @@ -1251,30 +1268,31 @@ module Gooby | |
| 1251 1268 | 
             
                  @lng_idx   = lng_idx
         | 
| 1252 1269 | 
             
                  @alt_idx   = alt_idx
         | 
| 1253 1270 | 
             
                  @cdist_idx = cdist_idx
         | 
| 1254 | 
            -
             | 
| 1255 | 
            -
                  # Override default csv value indices if specified in the  | 
| 1256 | 
            -
                  @ | 
| 1257 | 
            -
                  @dttm_idx  = @ | 
| 1258 | 
            -
                  @num_idx   = @ | 
| 1259 | 
            -
                  @lat_idx   = @ | 
| 1260 | 
            -
                  @lng_idx   = @ | 
| 1261 | 
            -
                  @alt_idx   = @ | 
| 1262 | 
            -
                  @title     = @ | 
| 1271 | 
            +
                        
         | 
| 1272 | 
            +
                  # Override default csv value indices if specified in the configuration yaml file.
         | 
| 1273 | 
            +
                  @configuration =  Gooby::Configuration.get_config
         | 
| 1274 | 
            +
                  @dttm_idx  = @configuration.get('csv_dttm_idx')  if @configuration.get('csv_dttm_idx')
         | 
| 1275 | 
            +
                  @num_idx   = @configuration.get('csv_num_idx')   if @configuration.get('csv_num_idx')
         | 
| 1276 | 
            +
                  @lat_idx   = @configuration.get('csv_lat_idx')   if @configuration.get('csv_lat_idx')
         | 
| 1277 | 
            +
                  @lng_idx   = @configuration.get('csv_lng_idx')   if @configuration.get('csv_lng_idx')
         | 
| 1278 | 
            +
                  @alt_idx   = @configuration.get('csv_alt_idx')   if @configuration.get('csv_alt_idx')
         | 
| 1279 | 
            +
                  @title     = @configuration.get("#{@csv_file}")  
         | 
| 1263 1280 |  | 
| 1264 1281 | 
             
                  @content_hash = Hash.new('')
         | 
| 1265 1282 | 
             
                  @run   = Gooby::Run.new(1)
         | 
| 1266 1283 | 
             
                  @track = Gooby::Track.new(1)
         | 
| 1267 1284 | 
             
                  @run.add_track(@track)
         | 
| 1268 1285 | 
             
                  @tkpts = Array.new
         | 
| 1269 | 
            -
                  @icon_url_base = @ | 
| 1270 | 
            -
                   | 
| 1271 | 
            -
                   | 
| 1272 | 
            -
             | 
| 1273 | 
            -
             | 
| 1274 | 
            -
             | 
| 1275 | 
            -
             | 
| 1276 | 
            -
             | 
| 1277 | 
            -
             | 
| 1286 | 
            +
                  @icon_url_base = @configuration.get('gmap_icon_url_base')
         | 
| 1287 | 
            +
                  
         | 
| 1288 | 
            +
                  list = Array.new
         | 
| 1289 | 
            +
                  list << @csv_file
         | 
| 1290 | 
            +
                  @cvs_reader = Gooby::CsvReader.new(list)
         | 
| 1291 | 
            +
                  @cvs_points = @cvs_reader.read
         | 
| 1292 | 
            +
                  @cvs_points.each { |cvs_point| 
         | 
| 1293 | 
            +
                    tkpt = cvs_point.as_trackpoint
         | 
| 1294 | 
            +
                    if tkpt
         | 
| 1295 | 
            +
                      @track.add_trackpoint(tkpt)
         | 
| 1278 1296 | 
             
                    end
         | 
| 1279 1297 | 
             
                  }
         | 
| 1280 1298 | 
             
                  @run.finish
         | 
| @@ -1283,15 +1301,15 @@ module Gooby | |
| 1283 1301 | 
             
            =begin
         | 
| 1284 1302 | 
             
            Returns a Hash with specific generated content at the following keys:
         | 
| 1285 1303 | 
             
            =end
         | 
| 1286 | 
            -
                def generate( | 
| 1287 | 
            -
                  if ( | 
| 1288 | 
            -
                    @ | 
| 1304 | 
            +
                def generate(configuration)
         | 
| 1305 | 
            +
                  if (configuration == nil)
         | 
| 1306 | 
            +
                    @configuration = Gooby::Configuration.get_config
         | 
| 1289 1307 | 
             
                  else
         | 
| 1290 | 
            -
                    @ | 
| 1308 | 
            +
                    @configuration = configuration
         | 
| 1291 1309 | 
             
                  end  
         | 
| 1292 1310 | 
             
                  @content_hash['when_generated'] = Time.now
         | 
| 1293 1311 | 
             
                  @content_hash['title'] = @title
         | 
| 1294 | 
            -
                  @icon_url_base = @ | 
| 1312 | 
            +
                  @icon_url_base = @configuration.get('gmap_icon_url_base')               
         | 
| 1295 1313 | 
             
                  filter_trackpoints  
         | 
| 1296 1314 | 
             
                  compute_center_point
         | 
| 1297 1315 | 
             
                  generate_key_js
         | 
| @@ -1307,8 +1325,8 @@ Returns a Hash with specific generated content at the following keys: | |
| 1307 1325 |  | 
| 1308 1326 | 
             
                def filter_trackpoints        
         | 
| 1309 1327 | 
             
                  count, @tkpts = 0, Array.new
         | 
| 1310 | 
            -
                  firstTkpt = @ | 
| 1311 | 
            -
                  lastTkpt  = @ | 
| 1328 | 
            +
                  firstTkpt = @configuration.get('gmap_first_tkpt_number')
         | 
| 1329 | 
            +
                  lastTkpt  = @configuration.get('gmap_last_tkpt_number')
         | 
| 1312 1330 | 
             
                  @run.tracks.each { |trk| 
         | 
| 1313 1331 | 
             
                    trk.trackpoints.each { |tkpt|
         | 
| 1314 1332 | 
             
                      count = count + 1
         | 
| @@ -1322,7 +1340,7 @@ Returns a Hash with specific generated content at the following keys: | |
| 1322 1340 | 
             
            =begin
         | 
| 1323 1341 | 
             
            Returns a Hash with specific generated content at the following keys:
         | 
| 1324 1342 | 
             
            =end 
         | 
| 1325 | 
            -
                def generate_page( | 
| 1343 | 
            +
                def generate_page(configuration)
         | 
| 1326 1344 |  | 
| 1327 1345 | 
             
                  # puts "generate_page #{@csv_file} #{@csv_lines.size}"
         | 
| 1328 1346 | 
             
                  content_hash = generate(nil)
         | 
| @@ -1381,18 +1399,19 @@ HERE | |
| 1381 1399 | 
             
                end
         | 
| 1382 1400 |  | 
| 1383 1401 | 
             
                def generate_key_js              
         | 
| 1384 | 
            -
                  key  = @ | 
| 1402 | 
            +
                  key  = @configuration.get('gmap_key')    
         | 
| 1385 1403 | 
             
                  key.strip!
         | 
| 1386 | 
            -
                   | 
| 1404 | 
            +
                  # <script src="http://maps.google.com/maps?file=api&v=2&key=<%= @gmap_key -%>"  type="text/javascript"></script>
         | 
| 1405 | 
            +
                  s  = "<script src='http://maps.google.com/maps?file=api&v=2&key=" 
         | 
| 1387 1406 | 
             
                  s << key
         | 
| 1388 | 
            -
                  s << ' | 
| 1407 | 
            +
                  s << "' type='text/javascript'></script>"
         | 
| 1389 1408 | 
             
                  @content_hash['key_js'] = s
         | 
| 1390 1409 | 
             
                end
         | 
| 1391 1410 |  | 
| 1392 1411 | 
             
                def generate_map_div
         | 
| 1393 | 
            -
                  width  = @ | 
| 1394 | 
            -
                  height = @ | 
| 1395 | 
            -
                  id     = @ | 
| 1412 | 
            +
                  width  = @configuration.get('gmap_width')
         | 
| 1413 | 
            +
                  height = @configuration.get('gmap_height')
         | 
| 1414 | 
            +
                  id     = @configuration.get('gmap_map_element_id')      
         | 
| 1396 1415 | 
             
                  s = '<div id="'
         | 
| 1397 1416 | 
             
                  s << id
         | 
| 1398 1417 | 
             
                  s << '" style="width: '
         | 
| @@ -1411,13 +1430,13 @@ HERE | |
| 1411 1430 | 
             
                end
         | 
| 1412 1431 |  | 
| 1413 1432 | 
             
                def generate_main_js_start
         | 
| 1414 | 
            -
                  id       = @ | 
| 1415 | 
            -
                  size     = @ | 
| 1416 | 
            -
                  type     = @ | 
| 1417 | 
            -
                  zoom     = @ | 
| 1418 | 
            -
                  title    = @ | 
| 1433 | 
            +
                  id       = @configuration.get('gmap_map_element_id')  
         | 
| 1434 | 
            +
                  size     = @configuration.get('gmap_size_control')
         | 
| 1435 | 
            +
                  type     = @configuration.get('gmap_type')
         | 
| 1436 | 
            +
                  zoom     = @configuration.get('gmap_zoom_level')
         | 
| 1437 | 
            +
                  title    = @configuration.get("#{@csv_file}") 
         | 
| 1419 1438 | 
             
                  title    = '' if title == nil
         | 
| 1420 | 
            -
                  zoom_tab = @ | 
| 1439 | 
            +
                  zoom_tab = @configuration.get('gmap_zoom_tab') 
         | 
| 1421 1440 | 
             
                  if size
         | 
| 1422 1441 | 
             
                    if size == 'smallmap'
         | 
| 1423 1442 | 
             
                      size = 'GSmallMapControl'
         | 
| @@ -1474,8 +1493,8 @@ HERE | |
| 1474 1493 |  | 
| 1475 1494 | 
             
                def generate_main_js_route_overlay
         | 
| 1476 1495 | 
             
                  tkpt_count   = @tkpts.size.to_f
         | 
| 1477 | 
            -
                  app_max      = @ | 
| 1478 | 
            -
                  gen_comments = @ | 
| 1496 | 
            +
                  app_max      = @configuration.get('gmap_approx_max_points').to_f
         | 
| 1497 | 
            +
                  gen_comments = @configuration.get('gmap_gen_comments')   
         | 
| 1479 1498 | 
             
                  ratio        = tkpt_count / app_max
         | 
| 1480 1499 | 
             
                  @start_dttm  = nil
         | 
| 1481 1500 | 
             
                  if ratio > 1.0
         | 
| @@ -1489,7 +1508,8 @@ HERE | |
| 1489 1508 | 
             
                    curr_idx = curr_idx + 1
         | 
| 1490 1509 | 
             
                    if curr_idx == 0
         | 
| 1491 1510 | 
             
                      @start_dttm = tkpt.dttm
         | 
| 1492 | 
            -
                      @start_pos  = tkpt. | 
| 1511 | 
            +
                      @start_pos  = tkpt.point
         | 
| 1512 | 
            +
                      
         | 
| 1493 1513 | 
             
                      time        = Time.parse(@start_dttm.dateTime().to_s)
         | 
| 1494 1514 | 
             
                    end
         | 
| 1495 1515 | 
             
                    if ((curr_idx == next_idx) || (curr_idx == last_idx) || (tkpt.is_split()))
         | 
| @@ -1717,28 +1737,42 @@ HERE | |
| 1717 1737 | 
             
              end
         | 
| 1718 1738 |  | 
| 1719 1739 | 
             
            # =============================================================================
         | 
| 1740 | 
            +
            =begin
         | 
| 1720 1741 |  | 
| 1721 | 
            -
             | 
| 1722 | 
            -
              
         | 
| 1723 | 
            -
             | 
| 1742 | 
            +
            This is a singleton class whose values are loaded from a YAML file when your
         | 
| 1743 | 
            +
            GoobyCommand class is created.  The default filename is 'gooby_config.yaml"'.
         | 
| 1744 | 
            +
             | 
| 1745 | 
            +
            The YAML file contains configuration parameters, such as your Google Map key,
         | 
| 1746 | 
            +
            map HTML options, points of interest, and courses.
         | 
| 1747 | 
            +
             
         | 
| 1748 | 
            +
            =end
         | 
| 1749 | 
            +
              class Configuration < GoobyObject
         | 
| 1750 | 
            +
             | 
| 1751 | 
            +
                @@singleton_instance = nil
         | 
| 1752 | 
            +
             | 
| 1753 | 
            +
                attr_reader :yaml_filename, :configuration
         | 
| 1724 1754 |  | 
| 1725 | 
            -
                 | 
| 1726 | 
            -
             | 
| 1727 | 
            -
             | 
| 1755 | 
            +
                private_class_method :new
         | 
| 1756 | 
            +
                
         | 
| 1757 | 
            +
                def Configuration.init(yaml_filename='gooby_config.yaml')
         | 
| 1758 | 
            +
                  return @@singleton_instance if  @@singleton_instance
         | 
| 1759 | 
            +
                   @@singleton_instance = new(yaml_filename)      
         | 
| 1728 1760 | 
             
                end
         | 
| 1729 | 
            -
             | 
| 1730 | 
            -
             | 
| 1731 | 
            -
             | 
| 1732 | 
            -
             | 
| 1733 | 
            -
             | 
| 1734 | 
            -
             | 
| 1761 | 
            +
                
         | 
| 1762 | 
            +
                def self.get_config
         | 
| 1763 | 
            +
                  @@singleton_instance
         | 
| 1764 | 
            +
                end
         | 
| 1765 | 
            +
                
         | 
| 1766 | 
            +
                def initialize(yaml_filename) 
         | 
| 1767 | 
            +
                  @yaml_filename = yaml_filename
         | 
| 1768 | 
            +
                  File.open("#{@yaml_filename}") { |fn| @configuration = YAML::load(fn) }
         | 
| 1735 1769 | 
             
                end
         | 
| 1736 1770 |  | 
| 1737 1771 | 
             
                def get(name)    
         | 
| 1738 1772 | 
             
                  if name == nil
         | 
| 1739 1773 | 
             
                    return ''
         | 
| 1740 1774 | 
             
                  end
         | 
| 1741 | 
            -
                  s = @ | 
| 1775 | 
            +
                  s = @configuration["#{name}"]
         | 
| 1742 1776 |  | 
| 1743 1777 | 
             
                  # Provide "sensible defaults".
         | 
| 1744 1778 | 
             
                  if s == nil
         | 
| @@ -1774,44 +1808,102 @@ HERE | |
| 1774 1808 | 
             
                  end
         | 
| 1775 1809 | 
             
                  s
         | 
| 1776 1810 | 
             
                end
         | 
| 1811 | 
            +
             | 
| 1812 | 
            +
                def print_all
         | 
| 1813 | 
            +
                  @configuration.keys.sort.each { |key| puts "#{key}: #{@configuration["#{key}"]}" }
         | 
| 1814 | 
            +
                end
         | 
| 1815 | 
            +
             | 
| 1816 | 
            +
                def print_all_poi
         | 
| 1817 | 
            +
                  @configuration.keys.sort.each { |key|
         | 
| 1818 | 
            +
                    if (key.match(/poi[\.]/))
         | 
| 1819 | 
            +
                      val = @configuration["#{key}"]
         | 
| 1820 | 
            +
                      poi = Point.new(val)
         | 
| 1821 | 
            +
                      puts poi.to_s
         | 
| 1822 | 
            +
                    end
         | 
| 1823 | 
            +
                  }
         | 
| 1824 | 
            +
                end
         | 
| 1825 | 
            +
                
         | 
| 1826 | 
            +
                def get_poi(number)
         | 
| 1827 | 
            +
                  val = @configuration["poi.#{number}"]
         | 
| 1828 | 
            +
                  (val) ? Point.new(val) : nil
         | 
| 1829 | 
            +
                end
         | 
| 1830 | 
            +
                
         | 
| 1831 | 
            +
                def get_course(number)
         | 
| 1832 | 
            +
                  val = @configuration["course.#{number}"]
         | 
| 1833 | 
            +
                  (val) ? Course.new(val) : nil
         | 
| 1834 | 
            +
                end
         | 
| 1777 1835 |  | 
| 1778 1836 | 
             
                def size
         | 
| 1779 | 
            -
                  @ | 
| 1837 | 
            +
                  @configuration.size
         | 
| 1780 1838 | 
             
                end
         | 
| 1781 1839 |  | 
| 1782 1840 | 
             
              # Return a String containing yaml filename and entry count.  
         | 
| 1783 1841 | 
             
                def to_s
         | 
| 1784 | 
            -
                  return " | 
| 1842 | 
            +
                  return "# Configuration: filename: #{@yaml_filename} entries: #{@configuration.size}"
         | 
| 1785 1843 | 
             
                end
         | 
| 1786 1844 | 
             
              end 
         | 
| 1787 1845 |  | 
| 1788 1846 | 
             
            # =============================================================================
         | 
| 1789 | 
            -
             | 
| 1790 | 
            -
            =begin rdoc
         | 
| 1791 | 
            -
              Instances of this class represent a <Position> aggregate object from a
         | 
| 1792 | 
            -
              Forerunner XML file.  Each contains a latitude and longitude.
         | 
| 1793 | 
            -
              Instances within a Trackpoint will also contain an altitude.
         | 
| 1794 | 
            -
            =end
         | 
| 1795 1847 |  | 
| 1796 | 
            -
              class  | 
| 1848 | 
            +
              class Point < GoobyObject  
         | 
| 1797 1849 |  | 
| 1798 | 
            -
                attr_accessor :latitude, :longitude, :altitude, :note
         | 
| 1850 | 
            +
                attr_accessor :number, :latitude, :longitude, :altitude, :note
         | 
| 1799 1851 |  | 
| 1800 | 
            -
                def initialize( | 
| 1801 | 
            -
                  @latitude | 
| 1802 | 
            -
                   | 
| 1803 | 
            -
             | 
| 1804 | 
            -
             | 
| 1852 | 
            +
                def initialize(*args)
         | 
| 1853 | 
            +
                  @number, @latitude, @longitude, @altitude, @note = '', '', '', '', ''
         | 
| 1854 | 
            +
                  if args
         | 
| 1855 | 
            +
                    if args.size == 1
         | 
| 1856 | 
            +
                      initialize_from_string(args[0]) # yaml 
         | 
| 1857 | 
            +
                    else
         | 
| 1858 | 
            +
                      initialize_from_array(args)
         | 
| 1859 | 
            +
                    end      
         | 
| 1860 | 
            +
                  end
         | 
| 1805 1861 | 
             
                end
         | 
| 1806 | 
            -
             | 
| 1862 | 
            +
                
         | 
| 1863 | 
            +
                def csv_delim
         | 
| 1864 | 
            +
                  '|'
         | 
| 1865 | 
            +
                end
         | 
| 1866 | 
            +
                
         | 
| 1867 | 
            +
                def initialize_from_array(args)
         | 
| 1868 | 
            +
                  @latitude  = args[0] if args.size > 0
         | 
| 1869 | 
            +
                  @longitude = args[1] if args.size > 1
         | 
| 1870 | 
            +
                  @altitude  = args[2] if args.size > 2
         | 
| 1871 | 
            +
                  @note      = args[3] if args.size > 3
         | 
| 1872 | 
            +
                end
         | 
| 1873 | 
            +
                
         | 
| 1874 | 
            +
                def initialize_from_string(yaml_value_string) 
         | 
| 1875 | 
            +
                  tokens = yaml_value_string.split
         | 
| 1876 | 
            +
                  if (tokens.size > 2)
         | 
| 1877 | 
            +
                    @latitude    = tokens[0]
         | 
| 1878 | 
            +
                    @longitude   = tokens[1]
         | 
| 1879 | 
            +
                    @note        = ''
         | 
| 1880 | 
            +
                    count        = 0
         | 
| 1881 | 
            +
                    tokens.each { |tok|
         | 
| 1882 | 
            +
                      count = count + 1
         | 
| 1883 | 
            +
                      if (count > 2)
         | 
| 1884 | 
            +
                        @note << tok
         | 
| 1885 | 
            +
                        @note << ' '
         | 
| 1886 | 
            +
                      end
         | 
| 1887 | 
            +
                    } 
         | 
| 1888 | 
            +
                  end
         | 
| 1889 | 
            +
                end
         | 
| 1890 | 
            +
                  
         | 
| 1807 1891 | 
             
                public
         | 
| 1808 1892 |  | 
| 1809 1893 | 
             
                def to_s
         | 
| 1810 1894 | 
             
                  return "lat: #{@latitude} lng: #{@longitude} alt: #{@altitude} note: #{@note}"
         | 
| 1811 1895 | 
             
                end
         | 
| 1896 | 
            +
             | 
| 1897 | 
            +
                def to_formatted_string
         | 
| 1898 | 
            +
                  s =  "lat: #{@latitude.to_s.ljust(20)}"
         | 
| 1899 | 
            +
                  s << " lng: #{@longitude.to_s.ljust(20)}"
         | 
| 1900 | 
            +
                  s << " poi.#{@number.to_s.ljust(12)}"  if @number
         | 
| 1901 | 
            +
                  s << " #{@note}" if @note
         | 
| 1902 | 
            +
                  s      
         | 
| 1903 | 
            +
                end
         | 
| 1812 1904 |  | 
| 1813 1905 | 
             
                def to_csv
         | 
| 1814 | 
            -
                  return "#{@latitude} | 
| 1906 | 
            +
                  return "#{@latitude}#{csv_delim}#{@longitude}#{csv_delim}#{@altitude}"
         | 
| 1815 1907 | 
             
                end
         | 
| 1816 1908 |  | 
| 1817 1909 | 
             
                def latitude_as_float
         | 
| @@ -1825,7 +1917,394 @@ HERE | |
| 1825 1917 | 
             
                def altitude_as_float
         | 
| 1826 1918 | 
             
                  @altitude ? @altitude.to_f : invalid_altitude
         | 
| 1827 1919 | 
             
                end
         | 
| 1920 | 
            +
                
         | 
| 1921 | 
            +
                def degrees_diff(another_point)      
         | 
| 1922 | 
            +
                  if (another_point)
         | 
| 1923 | 
            +
                    puts "this:  #{to_s}" if false
         | 
| 1924 | 
            +
                    puts "other: #{another_point.to_s}"  if false
         | 
| 1925 | 
            +
                    puts "lats:  #{latitude_as_float}  #{another_point.latitude_as_float}"  if false
         | 
| 1926 | 
            +
                    puts "lngs:  #{longitude_as_float}  #{another_point.longitude_as_float}"  if false
         | 
| 1927 | 
            +
                    lat_diff = latitude_as_float  - another_point.latitude_as_float
         | 
| 1928 | 
            +
                    lng_diff = longitude_as_float - another_point.longitude_as_float
         | 
| 1929 | 
            +
                    diff = lat_diff.abs + lng_diff.abs
         | 
| 1930 | 
            +
                    puts "diff: #{diff} #{lat_diff} #{lng_diff}"  if false
         | 
| 1931 | 
            +
                    diff
         | 
| 1932 | 
            +
                  else
         | 
| 1933 | 
            +
                    360
         | 
| 1934 | 
            +
                  end
         | 
| 1935 | 
            +
                end 
         | 
| 1936 | 
            +
                
         | 
| 1937 | 
            +
                def proximity(another_point, units)
         | 
| 1938 | 
            +
                  if (another_point)
         | 
| 1939 | 
            +
                    arg1  = latitude_as_float
         | 
| 1940 | 
            +
                    arg2  = another_point.latitude_as_float
         | 
| 1941 | 
            +
                    arg3  = latitude_as_float
         | 
| 1942 | 
            +
                    arg4  = another_point.latitude_as_float
         | 
| 1943 | 
            +
                    theta = longitude_as_float - another_point.longitude_as_float  
         | 
| 1944 | 
            +
                    res1  = Math.sin(deg2rad(arg1))
         | 
| 1945 | 
            +
                    res2  = Math.sin(deg2rad(arg2))
         | 
| 1946 | 
            +
                    res3  = Math.cos(deg2rad(arg3))
         | 
| 1947 | 
            +
                    res4  = Math.cos(deg2rad(arg4))
         | 
| 1948 | 
            +
                    res5  = Math.cos(deg2rad(theta.to_f))
         | 
| 1949 | 
            +
                    dist  = ((res1 * res2) + (res3 * res4 * res5)).to_f
         | 
| 1950 | 
            +
                    
         | 
| 1951 | 
            +
                    if (!dist.nan?)
         | 
| 1952 | 
            +
                      dist = Math.acos(dist.to_f)
         | 
| 1953 | 
            +
                      if (!dist.nan?)    
         | 
| 1954 | 
            +
                        dist = rad2deg(dist)
         | 
| 1955 | 
            +
                        if (!dist.nan?)
         | 
| 1956 | 
            +
                          dist = dist * 60 * 1.1515;
         | 
| 1957 | 
            +
                          if (!dist.nan?)
         | 
| 1958 | 
            +
                            if units == "K"
         | 
| 1959 | 
            +
                               dist = dist * 1.609344;
         | 
| 1960 | 
            +
                            end 
         | 
| 1961 | 
            +
                            if units == "N"
         | 
| 1962 | 
            +
                               dist = dist * 0.8684;
         | 
| 1963 | 
            +
                            end  
         | 
| 1964 | 
            +
                          end
         | 
| 1965 | 
            +
                        end
         | 
| 1966 | 
            +
                      end
         | 
| 1967 | 
            +
                      return dist.to_f
         | 
| 1968 | 
            +
                    else
         | 
| 1969 | 
            +
                      return 0
         | 
| 1970 | 
            +
                    end
         | 
| 1971 | 
            +
                  else
         | 
| 1972 | 
            +
                    return 0
         | 
| 1973 | 
            +
                  end
         | 
| 1974 | 
            +
                end  
         | 
| 1975 | 
            +
              
         | 
| 1976 | 
            +
                def deg2rad(degrees)
         | 
| 1977 | 
            +
                  (((0 + degrees) * Math::PI) / 180)
         | 
| 1978 | 
            +
                end
         | 
| 1979 | 
            +
              
         | 
| 1980 | 
            +
                def rad2deg(radians)
         | 
| 1981 | 
            +
                  (((0 + radians) * 180) / Math::PI)
         | 
| 1982 | 
            +
                end
         | 
| 1983 | 
            +
              end
         | 
| 1984 | 
            +
             | 
| 1985 | 
            +
            # =============================================================================
         | 
| 1986 | 
            +
             | 
| 1987 | 
            +
              class CsvPoint < Point
         | 
| 1988 | 
            +
                
         | 
| 1989 | 
            +
                attr_reader   :rawdata, :tokens
         | 
| 1990 | 
            +
                attr_reader   :id, :run_id, :date, :time, :tkpt_num, :distance, :elapsed 
         | 
| 1991 | 
            +
                attr_reader   :lap_number, :lap_distance, :lap_elapsed
         | 
| 1992 | 
            +
                attr_accessor :course_distance, :course_elapsed, :degrees_diff
         | 
| 1993 | 
            +
             | 
| 1994 | 
            +
                def initialize(csv_line)
         | 
| 1995 | 
            +
                  @rawdata = "#{csv_line}"
         | 
| 1996 | 
            +
                  @tokens  = @rawdata.split(csv_delim)
         | 
| 1997 | 
            +
                  if (tokens.size > 12)
         | 
| 1998 | 
            +
                    @id           = tokens[0]  # <-- consists of @run_id.@tkpt_num for uniqueness and use as a DB table primary key.
         | 
| 1999 | 
            +
                    @run_id       = tokens[1]
         | 
| 2000 | 
            +
                    @date         = tokens[2]
         | 
| 2001 | 
            +
                    @time         = tokens[3]
         | 
| 2002 | 
            +
                    @tkpt_num     = tokens[4].strip.to_i
         | 
| 2003 | 
            +
                    @latitude     = tokens[5].to_f
         | 
| 2004 | 
            +
                    @longitude    = tokens[6].to_f 
         | 
| 2005 | 
            +
                    @altitude     = tokens[7].strip.to_f 
         | 
| 2006 | 
            +
                    @distance     = tokens[8].strip.to_f 
         | 
| 2007 | 
            +
                    @elapsed      = tokens[9]
         | 
| 2008 | 
            +
                    @lap_number   = tokens[10].strip.to_i 
         | 
| 2009 | 
            +
                    @lap_distance = tokens[11].strip.to_f                                                     
         | 
| 2010 | 
            +
                    @lap_elapsed  = tokens[12]
         | 
| 2011 | 
            +
                  end
         | 
| 2012 | 
            +
                end
         | 
| 2013 | 
            +
             | 
| 2014 | 
            +
                def as_trackpoint
         | 
| 2015 | 
            +
                  tkpt = Trackpoint.new(@tkpt_num,  @latitude, @longitude, @altitude, "#{date}T#{time}Z")
         | 
| 2016 | 
            +
                  tkpt.lap_number   = @lap_number
         | 
| 2017 | 
            +
                  tkpt.lap_distance = @lap_distance
         | 
| 2018 | 
            +
                  tkpt.lap_elapsed  = @lap_elapsed
         | 
| 2019 | 
            +
                  tkpt
         | 
| 2020 | 
            +
                end
         | 
| 2021 | 
            +
                
         | 
| 2022 | 
            +
                def to_s
         | 
| 2023 | 
            +
                  return "lat: #{@latitude} lng: #{@longitude} alt: #{@altitude} note: #{@note}"
         | 
| 2024 | 
            +
                end  
         | 
| 2025 | 
            +
                
         | 
| 2026 | 
            +
                def to_formatted_string
         | 
| 2027 | 
            +
                  s =  "lat: #{@latitude.to_s.ljust(20)}"
         | 
| 2028 | 
            +
                  s << " lng: #{@longitude.to_s.ljust(20)}"
         | 
| 2029 | 
            +
                  s << " time:            #{@time}"
         | 
| 2030 | 
            +
                  pad = ''.ljust(70)
         | 
| 2031 | 
            +
                  s << "\n#{pad} course elapsed:  #{@course_elapsed}"
         | 
| 2032 | 
            +
                  s << "\n#{pad} distance:        #{@distance}"
         | 
| 2033 | 
            +
                  s << "\n#{pad} course distance: #{@course_distance}"
         | 
| 2034 | 
            +
                  s << "\n#{pad} altitude:        #{@altitude}"
         | 
| 2035 | 
            +
                  s << "\n#{pad} degrees diff:    #{@degrees_diff}"
         | 
| 2036 | 
            +
                  s
         | 
| 2037 | 
            +
                end
         | 
| 2038 | 
            +
              end
         | 
| 2039 | 
            +
             | 
| 2040 | 
            +
            # =============================================================================
         | 
| 2041 | 
            +
             | 
| 2042 | 
            +
              class CvsRun < GoobyObject
         | 
| 2043 | 
            +
              
         | 
| 2044 | 
            +
                attr_reader :id, :points
         | 
| 2045 | 
            +
                
         | 
| 2046 | 
            +
                def initialize(id)
         | 
| 2047 | 
            +
                  @id     = "#{id}"
         | 
| 2048 | 
            +
                  @points = Array.new  
         | 
| 2049 | 
            +
                end
         | 
| 2050 | 
            +
                
         | 
| 2051 | 
            +
                def add_point(point)
         | 
| 2052 | 
            +
                  if point
         | 
| 2053 | 
            +
                    @points << point  
         | 
| 2054 | 
            +
                  end  
         | 
| 2055 | 
            +
                end
         | 
| 1828 2056 | 
             
              end
         | 
| 2057 | 
            +
              
         | 
| 2058 | 
            +
            # =============================================================================
         | 
| 2059 | 
            +
             | 
| 2060 | 
            +
              class CsvReader < GoobyObject
         | 
| 2061 | 
            +
             | 
| 2062 | 
            +
                attr_reader :files, :cvs_points
         | 
| 2063 | 
            +
                
         | 
| 2064 | 
            +
                def initialize(array_of_filenames=nil)
         | 
| 2065 | 
            +
                  @files      = Array.new
         | 
| 2066 | 
            +
                  @cvs_points = Array.new
         | 
| 2067 | 
            +
                  if array_of_filenames
         | 
| 2068 | 
            +
                    array_of_filenames.each { |filename| add_file(filename) } 
         | 
| 2069 | 
            +
                  end
         | 
| 2070 | 
            +
                end
         | 
| 2071 | 
            +
                
         | 
| 2072 | 
            +
                def add_file(filename)
         | 
| 2073 | 
            +
                  if (filename)
         | 
| 2074 | 
            +
                    if (File.exist?(filename))
         | 
| 2075 | 
            +
                      @files << filename
         | 
| 2076 | 
            +
                    end
         | 
| 2077 | 
            +
                  end
         | 
| 2078 | 
            +
                end
         | 
| 2079 | 
            +
                
         | 
| 2080 | 
            +
                def read
         | 
| 2081 | 
            +
                  @files.each { |filename|
         | 
| 2082 | 
            +
                    lines = read_lines(filename, true)
         | 
| 2083 | 
            +
                    lines.each { |line|
         | 
| 2084 | 
            +
                      if (line.match('^#'))
         | 
| 2085 | 
            +
                        if (line.match('^#cols: '))
         | 
| 2086 | 
            +
                          col_names_header = line[7, line.size]
         | 
| 2087 | 
            +
                          @col_names = col_names_header.split('|')
         | 
| 2088 | 
            +
                        end
         | 
| 2089 | 
            +
                      else
         | 
| 2090 | 
            +
                        if (line.size > 50)
         | 
| 2091 | 
            +
                           @cvs_points << Gooby::CsvPoint.new(line)
         | 
| 2092 | 
            +
                        end
         | 
| 2093 | 
            +
                      end
         | 
| 2094 | 
            +
                    }
         | 
| 2095 | 
            +
                  }
         | 
| 2096 | 
            +
                  @cvs_points
         | 
| 2097 | 
            +
                end 
         | 
| 2098 | 
            +
                
         | 
| 2099 | 
            +
                def display_formatted_record(record_index=2)
         | 
| 2100 | 
            +
                  tokens = @cvs_points[record_index].rawdata.split('|')
         | 
| 2101 | 
            +
                  puts "\nCsvReader.display_formatted_record  hdr_cols=#{@col_names.size} data_cols=#{tokens.size}"
         | 
| 2102 | 
            +
                  size   = 0
         | 
| 2103 | 
            +
                  @col_names.each { |col_name|
         | 
| 2104 | 
            +
                    size = size + 1
         | 
| 2105 | 
            +
                    if size <= tokens.size
         | 
| 2106 | 
            +
                      value = tokens[size - 1]
         | 
| 2107 | 
            +
                      puts "#{col_name.strip.ljust(20)} #{(size - 1).to_s.ljust(3)} #{value}"
         | 
| 2108 | 
            +
                    end
         | 
| 2109 | 
            +
                  }
         | 
| 2110 | 
            +
                end
         | 
| 2111 | 
            +
                
         | 
| 2112 | 
            +
                def to_s
         | 
| 2113 | 
            +
                  s = "CsvReader - file count: #{files.size}  total points: #{cvs_points.size}"
         | 
| 2114 | 
            +
                  @files.each { |file| s << "\n  file: #{file} "}
         | 
| 2115 | 
            +
                  s
         | 
| 2116 | 
            +
                end         
         | 
| 2117 | 
            +
              end
         | 
| 2118 | 
            +
              
         | 
| 2119 | 
            +
            # =============================================================================
         | 
| 2120 | 
            +
              
         | 
| 2121 | 
            +
              class Trackpoint < Point
         | 
| 2122 | 
            +
                
         | 
| 2123 | 
            +
                attr_accessor  :first, :last, :number, :run_number, :dttm, :prev_tkpt, :lap_number, :lap_seq, :lap_distance, :lap_elapsed
         | 
| 2124 | 
            +
                attr_accessor  :cumulative_distance, :cumulative_pace, :incremental_distance, :split, :prev_split
         | 
| 2125 | 
            +
                attr_accessor  :first, :last, :run_id, :run_number
         | 
| 2126 | 
            +
                attr_accessor  :run_start_dttm 
         | 
| 2127 | 
            +
              
         | 
| 2128 | 
            +
                def initialize(num, lat, lng, alt, time_string, auxInfoHash=Hash.new(''))
         | 
| 2129 | 
            +
                  @number       = num
         | 
| 2130 | 
            +
                  @run_number   = 0
         | 
| 2131 | 
            +
                  @auxInfoHash  = auxInfoHash
         | 
| 2132 | 
            +
                  @lap_seq      = 1
         | 
| 2133 | 
            +
                  @lap_distance = 0
         | 
| 2134 | 
            +
                  lap_num = @auxInfoHash['lap_number']
         | 
| 2135 | 
            +
                  if (lap_num && lap_num.size > 0)
         | 
| 2136 | 
            +
                    @lap_number = lap_num.to_i
         | 
| 2137 | 
            +
                  else
         | 
| 2138 | 
            +
                    @lap_number = 0
         | 
| 2139 | 
            +
                  end
         | 
| 2140 | 
            +
                  # initialize superclass variables:
         | 
| 2141 | 
            +
                  @latitude  = lat.to_s
         | 
| 2142 | 
            +
                  @longitude = lng.to_s
         | 
| 2143 | 
            +
                  feet = alt.to_f * 3.2736  # Convert from meters (in the Garmin xml) to feet.
         | 
| 2144 | 
            +
                  @altitude  = feet.to_s
         | 
| 2145 | 
            +
                  @note      = note.to_s
         | 
| 2146 | 
            +
                  @dttm      = DtTm.new(time_string)
         | 
| 2147 | 
            +
                  @first     = false
         | 
| 2148 | 
            +
                  @last      = false
         | 
| 2149 | 
            +
                  @prev_tkpt  = nil      
         | 
| 2150 | 
            +
                  @cumulative_distance, @incremental_distance, @split = 0.0, 0.0, 0.0
         | 
| 2151 | 
            +
                  @cumulative_pace = ""
         | 
| 2152 | 
            +
                end
         | 
| 2153 | 
            +
              
         | 
| 2154 | 
            +
                public
         | 
| 2155 | 
            +
             | 
| 2156 | 
            +
                def point
         | 
| 2157 | 
            +
                  Point.new(@latitude, @longitude, @altitude, @note)
         | 
| 2158 | 
            +
                end
         | 
| 2159 | 
            +
                  
         | 
| 2160 | 
            +
                def position
         | 
| 2161 | 
            +
                  Point.new(@latitude, @longitude, @altitude, @note)
         | 
| 2162 | 
            +
                end
         | 
| 2163 | 
            +
                
         | 
| 2164 | 
            +
                def to_s
         | 
| 2165 | 
            +
                  "Tkpt: #{@number} #{super.to_s} date: #{@dttm.to_s} cdist: #{@cumulative_distance}"
         | 
| 2166 | 
            +
                end
         | 
| 2167 | 
            +
              
         | 
| 2168 | 
            +
                def to_csv(prev_tkpt=nil)    
         | 
| 2169 | 
            +
                  first_lap_start_time_s = @auxInfoHash['first_lap_start_time']
         | 
| 2170 | 
            +
                  curr_lap_start_time_s  = @auxInfoHash['curr_lap_start_time']
         | 
| 2171 | 
            +
                  lap_elapsed   = ''
         | 
| 2172 | 
            +
                  total_elapsed = ''
         | 
| 2173 | 
            +
                  
         | 
| 2174 | 
            +
                  if ((first_lap_start_time_s.size > 0) && (curr_lap_start_time_s.size > 0)) # garmin205 & 305
         | 
| 2175 | 
            +
                    first_lap_start_time = DtTm.new(first_lap_start_time_s)
         | 
| 2176 | 
            +
                    first_lap_start_time = @run_start_dttm
         | 
| 2177 | 
            +
                    curr_lap_start_time  = DtTm.new(curr_lap_start_time_s)
         | 
| 2178 | 
            +
                    lap_elapsed   = @dttm.hhmmss_diff(curr_lap_start_time) 
         | 
| 2179 | 
            +
                    total_elapsed = @dttm.hhmmss_diff(first_lap_start_time)
         | 
| 2180 | 
            +
                  else # garmin 201
         | 
| 2181 | 
            +
                    total_elapsed = @dttm.hhmmss_diff(@run_start_dttm)
         | 
| 2182 | 
            +
                    lap_elapsed   = total_elapsed
         | 
| 2183 | 
            +
                  end
         | 
| 2184 | 
            +
             | 
| 2185 | 
            +
                  delim = csv_delim
         | 
| 2186 | 
            +
                  csv =  "#{@run_id}.#{@number}" # <-- primary key
         | 
| 2187 | 
            +
                  csv << "#{delim}#{@run_id}"      
         | 
| 2188 | 
            +
                  csv << "#{delim}#{@dttm.yyyy_mm_dd_hh_mm_ss('|')}"
         | 
| 2189 | 
            +
                  csv << "#{delim}#{@number}"
         | 
| 2190 | 
            +
                  csv << "#{delim}#{position.to_csv}"
         | 
| 2191 | 
            +
                  csv << "#{delim}#{@cumulative_distance}"
         | 
| 2192 | 
            +
                  csv << "#{delim}#{total_elapsed}"
         | 
| 2193 | 
            +
                  csv << "#{delim}#{@lap_seq}"
         | 
| 2194 | 
            +
                  csv << "#{delim}#{@lap_distance}"
         | 
| 2195 | 
            +
                  csv << "#{delim}#{lap_elapsed}"
         | 
| 2196 | 
            +
                  csv
         | 
| 2197 | 
            +
                end
         | 
| 2198 | 
            +
                
         | 
| 2199 | 
            +
                def self.csv_header
         | 
| 2200 | 
            +
                  "#cols: primary_key|run_id|date|time|tkpt_num|latitude|longitude|altitude_ft|run_distance|run_elapsed|lap_tkpt_number|lap_distance|lap_elapsed"
         | 
| 2201 | 
            +
                end
         | 
| 2202 | 
            +
                
         | 
| 2203 | 
            +
                def to_geo_s
         | 
| 2204 | 
            +
                  ss = position.to_csv
         | 
| 2205 | 
            +
                  "Tkpt: #{@number} | #{ss} | #{@descr}"
         | 
| 2206 | 
            +
                end
         | 
| 2207 | 
            +
                
         | 
| 2208 | 
            +
                def compute_distance_and_pace(curr_index, start_dttm, prev_cumulative_dist, prev_trackpoint, units)
         | 
| 2209 | 
            +
                  @prev_tkpt = prev_trackpoint
         | 
| 2210 | 
            +
                  @cumulative_distance = prev_cumulative_dist.to_f
         | 
| 2211 | 
            +
                  @run_start_dttm = start_dttm
         | 
| 2212 | 
            +
                    
         | 
| 2213 | 
            +
                  if @prev_tkpt
         | 
| 2214 | 
            +
                    @incremental_distance = proximity(@prev_tkpt, units)         
         | 
| 2215 | 
            +
                    if (!@incremental_distance.nan?)
         | 
| 2216 | 
            +
                      @cumulative_distance =  @cumulative_distance + @incremental_distance.to_f
         | 
| 2217 | 
            +
                      if (@lap_number == prev_trackpoint.lap_number)
         | 
| 2218 | 
            +
                        @lap_seq      = prev_trackpoint.lap_seq + 1                  
         | 
| 2219 | 
            +
                        @lap_distance = prev_trackpoint.lap_distance + @incremental_distance
         | 
| 2220 | 
            +
                      else
         | 
| 2221 | 
            +
                        @lap_seq = 1
         | 
| 2222 | 
            +
                        @lap_distance = @incremental_distance
         | 
| 2223 | 
            +
                      end
         | 
| 2224 | 
            +
                    end
         | 
| 2225 | 
            +
                    compute_cumulative_pace(start_dttm)
         | 
| 2226 | 
            +
                    @cumulative_distance
         | 
| 2227 | 
            +
                  else
         | 
| 2228 | 
            +
                    @lap_seq = 1
         | 
| 2229 | 
            +
                    0  
         | 
| 2230 | 
            +
                  end    
         | 
| 2231 | 
            +
                end
         | 
| 2232 | 
            +
              
         | 
| 2233 | 
            +
                def compute_cumulative_pace(start_dttm)      
         | 
| 2234 | 
            +
                  if @cumulative_distance > 0
         | 
| 2235 | 
            +
                    secsDiff  = @dttm.seconds_diff(start_dttm)
         | 
| 2236 | 
            +
                    secsMile  = ((secsDiff.to_f) / (@cumulative_distance.to_f))
         | 
| 2237 | 
            +
                    minsMile  = (secsMile / 60)
         | 
| 2238 | 
            +
                    wholeMins = minsMile.floor 
         | 
| 2239 | 
            +
                    secsBal   = secsMile - (wholeMins * 60)
         | 
| 2240 | 
            +
                    s1 = "#{secsDiff} #{secsMile} #{minsMile} #{wholeMins} #{secsBal} #{@cumulative_distance} | "
         | 
| 2241 | 
            +
                    s2 = sprintf("%d:%2.1f", minsMile, secsBal)
         | 
| 2242 | 
            +
                    @cumulative_pace = "#{s2}"
         | 
| 2243 | 
            +
                  else 
         | 
| 2244 | 
            +
                    @cumulative_pace = ""
         | 
| 2245 | 
            +
                  end
         | 
| 2246 | 
            +
                end
         | 
| 2247 | 
            +
              
         | 
| 2248 | 
            +
                def set_split(n, tkpt)
         | 
| 2249 | 
            +
                  @split, @prev_split = n, tkpt
         | 
| 2250 | 
            +
                end
         | 
| 2251 | 
            +
              
         | 
| 2252 | 
            +
                def is_split()
         | 
| 2253 | 
            +
                 (@split >= 1)
         | 
| 2254 | 
            +
                end
         | 
| 2255 | 
            +
              
         | 
| 2256 | 
            +
                def split_info(dtTm) 
         | 
| 2257 | 
            +
                  if is_split
         | 
| 2258 | 
            +
                    hhmmss = ''
         | 
| 2259 | 
            +
                    if @prev_split
         | 
| 2260 | 
            +
                      return "#{@split} #{@dttm.hhmmss_diff(@prev_split.dttm())}"
         | 
| 2261 | 
            +
                    else
         | 
| 2262 | 
            +
                      return "#{@split} #{@dttm.hhmmss_diff(dtTm)}"
         | 
| 2263 | 
            +
                    end
         | 
| 2264 | 
            +
                  else
         | 
| 2265 | 
            +
                      ""
         | 
| 2266 | 
            +
                  end
         | 
| 2267 | 
            +
                end
         | 
| 2268 | 
            +
             | 
| 2269 | 
            +
                public 
         | 
| 2270 | 
            +
                
         | 
| 2271 | 
            +
                def as_glatlng(comment_out, gen_comments, tkpt_count, curr_idx, start_dttm)
         | 
| 2272 | 
            +
                  comment_out ? comment = '// ' : comment = ''
         | 
| 2273 | 
            +
                  if gen_comments
         | 
| 2274 | 
            +
                    secs_diff = @dttm.seconds_diff(start_dttm)
         | 
| 2275 | 
            +
                    fmt_time  = @dttm.hhmmss_diff(start_dttm)
         | 
| 2276 | 
            +
                      "\n            #{comment}points.push(new GLatLng(#{latitude_as_float},#{longitude_as_float})); " +
         | 
| 2277 | 
            +
                        "// (#{curr_idx + 1} of #{tkpt_count}) #{@dttm.to_s} #{secs_diff} #{fmt_time} #{@cumulative_distance} #{split_info(start_dttm)} #{project_embedded_comment} "
         | 
| 2278 | 
            +
                  else
         | 
| 2279 | 
            +
                      "\n            #{comment}points.push(new GLatLng(#{latitude_as_float},#{longitude_as_float})); // #{project_embedded_comment} "  
         | 
| 2280 | 
            +
                  end      
         | 
| 2281 | 
            +
                end
         | 
| 2282 | 
            +
              
         | 
| 2283 | 
            +
                def as_info_window_html(checkpoint, start_dttm)
         | 
| 2284 | 
            +
                  s = "\"<table align='left'>"
         | 
| 2285 | 
            +
                  if checkpoint
         | 
| 2286 | 
            +
                    secs_diff = @dttm.seconds_diff(start_dttm)
         | 
| 2287 | 
            +
                    fmt_time  = @dttm.hhmmss_diff(start_dttm)
         | 
| 2288 | 
            +
                            
         | 
| 2289 | 
            +
                    if checkpoint == 'Start'
         | 
| 2290 | 
            +
                      s << "<tr><td colspan='2'><b>Start!</b></td></tr>"
         | 
| 2291 | 
            +
                    elsif checkpoint == 'Finish'
         | 
| 2292 | 
            +
                      s << "<tr><td colspan='2'><b>Finish!</b></td></tr>"
         | 
| 2293 | 
            +
                    else
         | 
| 2294 | 
            +
                      s << "<tr><td colspan='2'><b>Checkpoint #{checkpoint}</b></td></tr>"
         | 
| 2295 | 
            +
                    end
         | 
| 2296 | 
            +
                    s << "<tr><td>Distance: </td><td>#{@cumulative_distance}</td></tr>"
         | 
| 2297 | 
            +
                    s << "<tr><td>Time of Day: </td><td>#{@dttm.to_s} </td></tr>" 
         | 
| 2298 | 
            +
                    s << "<tr><td>Elapsed Time: </td><td>#{fmt_time} </td></tr>"  
         | 
| 2299 | 
            +
                    s << "<tr><td>Average Pace: </td><td>#{@cumulative_pace} </td></tr>"      
         | 
| 2300 | 
            +
                    s << "<tr><td>Lat/Lng: </td><td>#{latitude_as_float} , #{longitude_as_float} </td></tr>" 
         | 
| 2301 | 
            +
                    #s << "<tr><td>Altitude: </td><td>#{altitude_as_float}m </td></tr>"
         | 
| 2302 | 
            +
                    s
         | 
| 2303 | 
            +
                  end
         | 
| 2304 | 
            +
                  s << "</table>\""
         | 
| 2305 | 
            +
                  s
         | 
| 2306 | 
            +
                end
         | 
| 2307 | 
            +
              end  
         | 
| 1829 2308 |  | 
| 1830 2309 | 
             
            # =============================================================================
         | 
| 1831 2310 |  | 
| @@ -1839,19 +2318,20 @@ HERE | |
| 1839 2318 |  | 
| 1840 2319 | 
             
              class Run < GoobyObject 
         | 
| 1841 2320 |  | 
| 1842 | 
            -
                attr_accessor :number, :descr, :notes, :tracks, :tkpts, :laps, :distance
         | 
| 2321 | 
            +
                attr_accessor :number, :run_id, :descr, :notes, :tracks, :tkpts, :laps, :distance
         | 
| 1843 2322 |  | 
| 1844 2323 | 
             
                def initialize(number=0, descr='')
         | 
| 1845 2324 | 
             
                  @number = number
         | 
| 2325 | 
            +
                  @run_id = nil      
         | 
| 1846 2326 | 
             
                  @descr  = descr
         | 
| 1847 2327 | 
             
                  @notes  = ''         
         | 
| 1848 2328 | 
             
                  @tracks = Array.new
         | 
| 1849 2329 | 
             
                  @tkpts  = Array.new
         | 
| 1850 2330 | 
             
                  @laps   = Array.new 
         | 
| 1851 2331 | 
             
                  @distance = 0
         | 
| 1852 | 
            -
                  @ | 
| 2332 | 
            +
                  @configuration = Hash.new
         | 
| 1853 2333 | 
             
                  @logProgress = true
         | 
| 1854 | 
            -
                  @finished | 
| 2334 | 
            +
                  @finished    = false
         | 
| 1855 2335 | 
             
                end
         | 
| 1856 2336 |  | 
| 1857 2337 | 
             
                public
         | 
| @@ -1860,7 +2340,7 @@ HERE | |
| 1860 2340 | 
             
                def finish()
         | 
| 1861 2341 | 
             
                   @logProgress = false
         | 
| 1862 2342 | 
             
                   unless @finished
         | 
| 1863 | 
            -
                     @tracks.each { |trk| | 
| 2343 | 
            +
                     @tracks.each { |trk| 
         | 
| 1864 2344 | 
             
                       trk.trackpoints().each { |tkpt|
         | 
| 1865 2345 | 
             
                         tkpt.run_number = @number
         | 
| 1866 2346 | 
             
                         @tkpts.push(tkpt)             
         | 
| @@ -1868,6 +2348,7 @@ HERE | |
| 1868 2348 | 
             
                     }      
         | 
| 1869 2349 | 
             
                     compute_distance_and_pace
         | 
| 1870 2350 | 
             
                     compute_splits
         | 
| 2351 | 
            +
                     set_run_ids
         | 
| 1871 2352 | 
             
                     @finished = true
         | 
| 1872 2353 | 
             
                   end  
         | 
| 1873 2354 | 
             
                 end  
         | 
| @@ -1920,7 +2401,7 @@ HERE | |
| 1920 2401 | 
             
                      return last.hhmmss_diff(first)
         | 
| 1921 2402 | 
             
                    end
         | 
| 1922 2403 | 
             
                  end
         | 
| 1923 | 
            -
                  return " | 
| 2404 | 
            +
                  return "00:00:00" 
         | 
| 1924 2405 | 
             
                end
         | 
| 1925 2406 |  | 
| 1926 2407 | 
             
                def start_yyyy_mm_dd
         | 
| @@ -1965,12 +2446,14 @@ HERE | |
| 1965 2446 | 
             
                  puts "#{@number}|#{}|#{start_yyyy_mm_dd()}|#{start_hh_mm_ss()}|#{end_hh_mm_ss}|#{duration()}|#{@distance}|#{@tracks.size}|#{trackpoint_count()}|#{lap_count}|#{@notes.strip}" 
         | 
| 1966 2447 | 
             
                end
         | 
| 1967 2448 |  | 
| 1968 | 
            -
                def put_tkpt_csv( | 
| 2449 | 
            +
                def put_tkpt_csv()
         | 
| 1969 2450 | 
             
                  finish() unless @finished    
         | 
| 1970 | 
            -
                   | 
| 1971 | 
            -
                     | 
| 1972 | 
            -
             | 
| 1973 | 
            -
             | 
| 2451 | 
            +
                  @tkpts.each { | tkpt | 
         | 
| 2452 | 
            +
                    if (@prev_tkpt == nil)
         | 
| 2453 | 
            +
                      @prev_tkpt = tkpt
         | 
| 2454 | 
            +
                    end
         | 
| 2455 | 
            +
                    puts tkpt.to_csv(@prev_tkpt) 
         | 
| 2456 | 
            +
                  }
         | 
| 1974 2457 | 
             
                end
         | 
| 1975 2458 |  | 
| 1976 2459 | 
             
                def put_laps
         | 
| @@ -1988,19 +2471,19 @@ HERE | |
| 1988 2471 | 
             
                    curr_index = curr_index + 1
         | 
| 1989 2472 | 
             
                    if curr_index == 0
         | 
| 1990 2473 | 
             
                      start_dttm = tkpt.dttm()
         | 
| 1991 | 
            -
                      prev_tkpt  = tkpt | 
| 2474 | 
            +
                      prev_tkpt  = tkpt
         | 
| 1992 2475 | 
             
                    else
         | 
| 1993 2476 | 
             
                      cumulative_dist = tkpt.compute_distance_and_pace(curr_index, start_dttm, cumulative_dist, prev_tkpt, 'M')  
         | 
| 1994 2477 | 
             
                      prev_tkpt = tkpt      
         | 
| 1995 2478 | 
             
                    end
         | 
| 1996 2479 | 
             
                  }
         | 
| 1997 | 
            -
                  @distance = cumulative_dist | 
| 2480 | 
            +
                  @distance = cumulative_dist
         | 
| 1998 2481 | 
             
                end
         | 
| 1999 2482 |  | 
| 2000 | 
            -
                def compute_splits | 
| 2483 | 
            +
                def compute_splits
         | 
| 2001 2484 | 
             
                  nextSplitDist = 1.00
         | 
| 2002 2485 | 
             
                  prev_splitTkpt = nil
         | 
| 2003 | 
            -
                  loop1Count | 
| 2486 | 
            +
                  loop1Count = 0;
         | 
| 2004 2487 | 
             
                  @tkpts.each { |tkpt|
         | 
| 2005 2488 | 
             
                    loop1Count = loop1Count + 1
         | 
| 2006 2489 | 
             
                    if tkpt.cumulative_distance() >= nextSplitDist
         | 
| @@ -2017,6 +2500,15 @@ HERE | |
| 2017 2500 | 
             
                    tkpt.last  = true  if count == loop1Count
         | 
| 2018 2501 | 
             
                  }         
         | 
| 2019 2502 | 
             
                end
         | 
| 2503 | 
            +
                
         | 
| 2504 | 
            +
                def set_run_ids
         | 
| 2505 | 
            +
                  @tkpts.each { |tkpt|
         | 
| 2506 | 
            +
                    if (@run_id == nil)
         | 
| 2507 | 
            +
                      @run_id = tkpt.dttm.rawdata
         | 
| 2508 | 
            +
                    end
         | 
| 2509 | 
            +
                    tkpt.run_id = @run_id
         | 
| 2510 | 
            +
                  }
         | 
| 2511 | 
            +
                end
         | 
| 2020 2512 | 
             
              end
         | 
| 2021 2513 |  | 
| 2022 2514 | 
             
            # =============================================================================
         | 
| @@ -2092,201 +2584,117 @@ HERE | |
| 2092 2584 |  | 
| 2093 2585 | 
             
                def dump
         | 
| 2094 2586 | 
             
                  puts "Track: '#{@descr}'  tkpts: #{size}"
         | 
| 2095 | 
            -
                  @trackpoints.each { |tkpt| puts tkpt.to_csv }  | 
| 2587 | 
            +
                  @trackpoints.each { |tkpt| puts tkpt.to_csv } 
         | 
| 2096 2588 | 
             
                end
         | 
| 2097 2589 | 
             
              end 
         | 
| 2098 | 
            -
             | 
| 2099 | 
            -
            # =============================================================================
         | 
| 2100 | 
            -
             | 
| 2101 | 
            -
            =begin rdoc
         | 
| 2102 | 
            -
              Instances of this class represent a <Trackpoint> aggregate from a Forerunner 
         | 
| 2103 | 
            -
              XML file.  Additionally, there is distance, pace, and Google Map generation 
         | 
| 2104 | 
            -
              logic in this class.
         | 
| 2105 | 
            -
             | 
| 2106 | 
            -
              <Trackpoint>
         | 
| 2107 | 
            -
                  <Position>
         | 
| 2108 | 
            -
                      <Latitude>35.49577</Latitude>
         | 
| 2109 | 
            -
                      <Longitude>-80.83281</Longitude>
         | 
| 2110 | 
            -
                      <Altitude>232.296</Altitude>
         | 
| 2111 | 
            -
                  </Position>
         | 
| 2112 | 
            -
                  <Time>2007-01-06T15:27:51Z</Time>
         | 
| 2113 | 
            -
              </Trackpoint>
         | 
| 2114 | 
            -
            =end
         | 
| 2115 | 
            -
              
         | 
| 2116 | 
            -
              class Trackpoint < Position
         | 
| 2117 | 
            -
              
         | 
| 2118 | 
            -
                attr_reader :first, :last, :number, :run_number, :dttm, :prev_tkpt, :descr
         | 
| 2119 | 
            -
                attr_reader :cumulative_distance, :cumulative_pace, :incremental_distance, :split, :prev_split
         | 
| 2120 | 
            -
                attr_writer :first, :last, :run_number
         | 
| 2121 2590 |  | 
| 2122 | 
            -
             | 
| 2123 | 
            -
             | 
| 2124 | 
            -
             | 
| 2125 | 
            -
             | 
| 2126 | 
            -
                   | 
| 2127 | 
            -
             | 
| 2128 | 
            -
                   | 
| 2129 | 
            -
             | 
| 2130 | 
            -
             | 
| 2131 | 
            -
             | 
| 2132 | 
            -
             | 
| 2133 | 
            -
             | 
| 2134 | 
            -
             | 
| 2135 | 
            -
             | 
| 2136 | 
            -
             | 
| 2137 | 
            -
             | 
| 2138 | 
            -
             | 
| 2139 | 
            -
             | 
| 2140 | 
            -
             | 
| 2141 | 
            -
             | 
| 2142 | 
            -
             | 
| 2143 | 
            -
             | 
| 2144 | 
            -
             | 
| 2145 | 
            -
             | 
| 2146 | 
            -
             | 
| 2147 | 
            -
             | 
| 2148 | 
            -
                end
         | 
| 2149 | 
            -
              
         | 
| 2150 | 
            -
                def to_csv
         | 
| 2151 | 
            -
                  ss = position.to_csv
         | 
| 2152 | 
            -
                  "#{@run_number} | #{@dttm.to_s} | #{@number} | #{ss} | #{@cumulative_distance} "
         | 
| 2153 | 
            -
                end
         | 
| 2154 | 
            -
                
         | 
| 2155 | 
            -
                def to_geo_s
         | 
| 2156 | 
            -
                  ss = position.to_csv
         | 
| 2157 | 
            -
                  "Tkpt: #{@number} | #{ss} | #{@descr}"
         | 
| 2158 | 
            -
                end
         | 
| 2159 | 
            -
                
         | 
| 2160 | 
            -
                def compute_distance_and_pace(curr_index, start_dttm, prev_cumulative_dist, prev_trackpoint, units)     
         | 
| 2161 | 
            -
                  @prev_tkpt = prev_trackpoint
         | 
| 2162 | 
            -
                  @cumulative_distance = prev_cumulative_dist.to_f
         | 
| 2163 | 
            -
                    
         | 
| 2164 | 
            -
                  if @prev_tkpt
         | 
| 2165 | 
            -
                    arg1  = latitude().to_f
         | 
| 2166 | 
            -
                    arg2  = @prev_tkpt.latitude().to_f
         | 
| 2167 | 
            -
                    arg3  = latitude().to_f
         | 
| 2168 | 
            -
                    arg4  = @prev_tkpt.latitude().to_f
         | 
| 2169 | 
            -
                    theta = longitude().to_f - @prev_tkpt.longitude().to_f   
         | 
| 2170 | 
            -
                  
         | 
| 2171 | 
            -
                    res1  = Math.sin(deg2rad(arg1))
         | 
| 2172 | 
            -
                    res2  = Math.sin(deg2rad(arg2))
         | 
| 2173 | 
            -
                    res3  = Math.cos(deg2rad(arg3))
         | 
| 2174 | 
            -
                    res4  = Math.cos(deg2rad(arg4))
         | 
| 2175 | 
            -
                    res5  = Math.cos(deg2rad(theta.to_f))
         | 
| 2176 | 
            -
                          
         | 
| 2177 | 
            -
                    incremental_distance =  ((res1 * res2) + (res3 * res4 * res5)).to_f
         | 
| 2178 | 
            -
             | 
| 2179 | 
            -
                    if (!incremental_distance.nan?)
         | 
| 2180 | 
            -
                      incremental_distance = Math.acos(incremental_distance.to_f)
         | 
| 2181 | 
            -
                      if (!incremental_distance.nan?)    
         | 
| 2182 | 
            -
                        incremental_distance = rad2deg(incremental_distance)
         | 
| 2183 | 
            -
                        if (!incremental_distance.nan?)
         | 
| 2184 | 
            -
                          incremental_distance = incremental_distance * 60 * 1.1515;
         | 
| 2185 | 
            -
                          if (!incremental_distance.nan?)
         | 
| 2186 | 
            -
                            if units == "K"
         | 
| 2187 | 
            -
                               incremental_distance = incremental_distance * 1.609344;
         | 
| 2188 | 
            -
                            end 
         | 
| 2189 | 
            -
                            if units == "N"
         | 
| 2190 | 
            -
                               incremental_distance = incremental_distance * 0.8684;
         | 
| 2191 | 
            -
                            end  
         | 
| 2192 | 
            -
                            @cumulative_distance =  @cumulative_distance + incremental_distance.to_f 
         | 
| 2591 | 
            +
              # =============================================================================
         | 
| 2592 | 
            +
             | 
| 2593 | 
            +
                class Course < GoobyObject  
         | 
| 2594 | 
            +
             | 
| 2595 | 
            +
                  attr_accessor :name, :distance, :point_numbers, :points
         | 
| 2596 | 
            +
             | 
| 2597 | 
            +
                  def initialize(yaml_csv)
         | 
| 2598 | 
            +
                    @name, @distance = '', 0.0
         | 
| 2599 | 
            +
                    @point_numbers, @points, @bad_points = Array.new, Array.new, Array.new
         | 
| 2600 | 
            +
                    @points_hash, @matched_points = Hash.new, Hash.new
         | 
| 2601 | 
            +
                    tokens    = yaml_csv.split(',')
         | 
| 2602 | 
            +
                    @name     = tokens[0]      if tokens.size > 0
         | 
| 2603 | 
            +
                    @distance = tokens[1].to_f if tokens.size > 1 
         | 
| 2604 | 
            +
                    if tokens.size > 2
         | 
| 2605 | 
            +
                      index = 0
         | 
| 2606 | 
            +
                      tokens.each { |tok|
         | 
| 2607 | 
            +
                        index = index + 1
         | 
| 2608 | 
            +
                        if (index > 2)
         | 
| 2609 | 
            +
                          poi = Configuration.get_config.get_poi(tok)
         | 
| 2610 | 
            +
                          if (poi)
         | 
| 2611 | 
            +
                            poi.number     =  "#{tok}"
         | 
| 2612 | 
            +
                            @point_numbers << "#{tok}"
         | 
| 2613 | 
            +
                            @points        << poi
         | 
| 2614 | 
            +
                            @points_hash["#{tok}"] = poi
         | 
| 2615 | 
            +
                          else
         | 
| 2616 | 
            +
                            @bad_points << tok
         | 
| 2193 2617 | 
             
                          end
         | 
| 2194 2618 | 
             
                        end
         | 
| 2195 | 
            -
                       | 
| 2196 | 
            -
                    end | 
| 2197 | 
            -
                    compute_cumulative_pace(start_dttm)
         | 
| 2198 | 
            -
                    @cumulative_distance
         | 
| 2199 | 
            -
                  else
         | 
| 2200 | 
            -
                    0  
         | 
| 2201 | 
            -
                  end    
         | 
| 2202 | 
            -
                end
         | 
| 2203 | 
            -
              
         | 
| 2204 | 
            -
                def compute_cumulative_pace(start_dttm)      
         | 
| 2205 | 
            -
                  if @cumulative_distance > 0
         | 
| 2206 | 
            -
                    secsDiff  = @dttm.seconds_diff(start_dttm)
         | 
| 2207 | 
            -
                    secsMile  = ((secsDiff.to_f) / (@cumulative_distance.to_f))
         | 
| 2208 | 
            -
                    minsMile  = (secsMile / 60)
         | 
| 2209 | 
            -
                    wholeMins = minsMile.floor 
         | 
| 2210 | 
            -
                    secsBal   = secsMile - (wholeMins * 60)
         | 
| 2211 | 
            -
                    s1 = "#{secsDiff} #{secsMile} #{minsMile} #{wholeMins} #{secsBal} #{@cumulative_distance} | "
         | 
| 2212 | 
            -
                    s2 = sprintf("%d:%2.1f", minsMile, secsBal)
         | 
| 2213 | 
            -
                    @cumulative_pace = "#{s2}"
         | 
| 2214 | 
            -
                  else 
         | 
| 2215 | 
            -
                    @cumulative_pace = ""
         | 
| 2619 | 
            +
                      }
         | 
| 2620 | 
            +
                    end 
         | 
| 2216 2621 | 
             
                  end
         | 
| 2217 | 
            -
             | 
| 2218 | 
            -
             | 
| 2219 | 
            -
             | 
| 2220 | 
            -
                   | 
| 2221 | 
            -
             | 
| 2222 | 
            -
             | 
| 2223 | 
            -
             | 
| 2224 | 
            -
             | 
| 2225 | 
            -
             | 
| 2226 | 
            -
             | 
| 2227 | 
            -
             | 
| 2228 | 
            -
                   | 
| 2229 | 
            -
             | 
| 2230 | 
            -
             | 
| 2231 | 
            -
             | 
| 2232 | 
            -
                     | 
| 2233 | 
            -
             | 
| 2234 | 
            -
             | 
| 2235 | 
            -
             | 
| 2236 | 
            -
                       | 
| 2622 | 
            +
                  
         | 
| 2623 | 
            +
                  def has_errors
         | 
| 2624 | 
            +
                    (@bad_points.size > 0) ? true : false
         | 
| 2625 | 
            +
                  end
         | 
| 2626 | 
            +
                  
         | 
| 2627 | 
            +
                  def matched(number, point)
         | 
| 2628 | 
            +
                    @matched_points["#{number}"] = point if point
         | 
| 2629 | 
            +
                  end
         | 
| 2630 | 
            +
                  
         | 
| 2631 | 
            +
                  def matched?
         | 
| 2632 | 
            +
                    (@matched_points.size == @point_numbers.size) ? true : false
         | 
| 2633 | 
            +
                  end
         | 
| 2634 | 
            +
                  
         | 
| 2635 | 
            +
                  def display_matches
         | 
| 2636 | 
            +
                    puts ''
         | 
| 2637 | 
            +
                    calculate_matches
         | 
| 2638 | 
            +
                    @point_numbers.each { |num|
         | 
| 2639 | 
            +
                      point  = @points_hash["#{num}"]
         | 
| 2640 | 
            +
                      mpoint = @matched_points["#{num}"]
         | 
| 2641 | 
            +
                      puts ''
         | 
| 2642 | 
            +
                      puts "  Course Point:    #{point.to_formatted_string}"   if point
         | 
| 2643 | 
            +
                      puts "    Matched Point: #{mpoint.to_formatted_string}"  if mpoint
         | 
| 2644 | 
            +
                    }
         | 
| 2645 | 
            +
                    puts ''
         | 
| 2237 2646 | 
             
                  end
         | 
| 2238 | 
            -
                end
         | 
| 2239 | 
            -
              
         | 
| 2240 | 
            -
                private 
         | 
| 2241 | 
            -
              
         | 
| 2242 | 
            -
                def deg2rad(degrees)
         | 
| 2243 | 
            -
                 (((0 + degrees) * Math::PI) / 180)
         | 
| 2244 | 
            -
                end
         | 
| 2245 | 
            -
              
         | 
| 2246 | 
            -
                def rad2deg(radians)
         | 
| 2247 | 
            -
                 (((0 + radians) * 180) / Math::PI)
         | 
| 2248 | 
            -
                end
         | 
| 2249 2647 |  | 
| 2250 | 
            -
             | 
| 2251 | 
            -
             | 
| 2252 | 
            -
                def as_glatlng(comment_out, gen_comments, tkpt_count, curr_idx, start_dttm)
         | 
| 2253 | 
            -
                  comment_out ? comment = '// ' : comment = ''
         | 
| 2254 | 
            -
                  if gen_comments
         | 
| 2255 | 
            -
                    secs_diff = @dttm.seconds_diff(start_dttm)
         | 
| 2256 | 
            -
                    fmt_time  = @dttm.hhmmss_diff(start_dttm)
         | 
| 2257 | 
            -
                      "\n            #{comment}points.push(new GLatLng(#{latitude_as_float},#{longitude_as_float})); " +
         | 
| 2258 | 
            -
                        "// (#{curr_idx + 1} of #{tkpt_count}) #{@dttm.to_s} #{secs_diff} #{fmt_time} #{@cumulative_distance} #{split_info(start_dttm)} #{project_embedded_comment} "
         | 
| 2259 | 
            -
                  else
         | 
| 2260 | 
            -
                      "\n            #{comment}points.push(new GLatLng(#{latitude_as_float},#{longitude_as_float})); // #{project_embedded_comment} "  
         | 
| 2261 | 
            -
                  end      
         | 
| 2262 | 
            -
                end
         | 
| 2263 | 
            -
              
         | 
| 2264 | 
            -
                def as_info_window_html(checkpoint, start_dttm)
         | 
| 2265 | 
            -
                  s = "\"<table align='left'>"
         | 
| 2266 | 
            -
                  if checkpoint
         | 
| 2267 | 
            -
                    secs_diff = @dttm.seconds_diff(start_dttm)
         | 
| 2268 | 
            -
                    fmt_time  = @dttm.hhmmss_diff(start_dttm)
         | 
| 2269 | 
            -
                            
         | 
| 2270 | 
            -
                    if checkpoint == 'Start'
         | 
| 2271 | 
            -
                      s << "<tr><td colspan='2'><b>Start!</b></td></tr>"
         | 
| 2272 | 
            -
                    elsif checkpoint == 'Finish'
         | 
| 2273 | 
            -
                      s << "<tr><td colspan='2'><b>Finish!</b></td></tr>"
         | 
| 2274 | 
            -
                    else
         | 
| 2275 | 
            -
                      s << "<tr><td colspan='2'><b>Checkpoint #{checkpoint}</b></td></tr>"
         | 
| 2276 | 
            -
                    end
         | 
| 2277 | 
            -
                    s << "<tr><td>Distance: </td><td>#{@cumulative_distance}</td></tr>"
         | 
| 2278 | 
            -
                    s << "<tr><td>Time of Day: </td><td>#{@dttm.to_s} </td></tr>" 
         | 
| 2279 | 
            -
                    s << "<tr><td>Elapsed Time: </td><td>#{fmt_time} </td></tr>"  
         | 
| 2280 | 
            -
                    s << "<tr><td>Average Pace: </td><td>#{@cumulative_pace} </td></tr>"      
         | 
| 2281 | 
            -
                    s << "<tr><td>Lat/Lng: </td><td>#{latitude_as_float} , #{longitude_as_float} </td></tr>" 
         | 
| 2282 | 
            -
                    s << "<tr><td>Altitude: </td><td>#{altitude_as_float}m </td></tr>"
         | 
| 2283 | 
            -
                    s
         | 
| 2648 | 
            +
                  def reset
         | 
| 2649 | 
            +
                    @matched_points = Hash.new
         | 
| 2284 2650 | 
             
                  end
         | 
| 2285 | 
            -
                   | 
| 2286 | 
            -
                   | 
| 2651 | 
            +
                  
         | 
| 2652 | 
            +
                  def to_s
         | 
| 2653 | 
            +
                    "#{@name} #{@distance}  points: #{@points.size} errors: #{has_errors}" 
         | 
| 2654 | 
            +
                  end 
         | 
| 2655 | 
            +
                  
         | 
| 2656 | 
            +
                  def dump
         | 
| 2657 | 
            +
                    puts "Course:   #{@name}"
         | 
| 2658 | 
            +
                    puts "Distance: #{@distance}"
         | 
| 2659 | 
            +
                    points.each { |pt| puts pt } #{@points.size} errors: #{has_errors}" 
         | 
| 2660 | 
            +
                  end 
         | 
| 2661 | 
            +
                  
         | 
| 2662 | 
            +
                  private
         | 
| 2663 | 
            +
                  
         | 
| 2664 | 
            +
                  def calculate_matches        
         | 
| 2665 | 
            +
                    # first, identify the high and low distance points and their indices.
         | 
| 2666 | 
            +
                    idx, low_dist, low_dist_idx, low_time, high_dist, high_dist_idx = -1, 999999.0, 0, '', -1.0, 0
         | 
| 2667 | 
            +
                    @point_numbers.each { |num|
         | 
| 2668 | 
            +
                      idx = idx + 1
         | 
| 2669 | 
            +
                      mpoint = @matched_points["#{num}"]
         | 
| 2670 | 
            +
                      if mpoint && mpoint.distance < low_dist
         | 
| 2671 | 
            +
                        low_dist     = mpoint.distance
         | 
| 2672 | 
            +
                        low_dist_idx = idx
         | 
| 2673 | 
            +
                        low_time     = mpoint.elapsed
         | 
| 2674 | 
            +
                      end
         | 
| 2675 | 
            +
                      if mpoint && mpoint.distance > high_dist
         | 
| 2676 | 
            +
                        high_dist     = mpoint.distance
         | 
| 2677 | 
            +
                        high_dist_idx = idx
         | 
| 2678 | 
            +
                      end          
         | 
| 2679 | 
            +
                    }   
         | 
| 2680 | 
            +
                    low_dttm = DtTm.new("2007-06-09T#{low_time}Z")
         | 
| 2681 | 
            +
                    
         | 
| 2682 | 
            +
                    # reorder the entries in @point_numbers if necessary - 'low-to-high distance'.
         | 
| 2683 | 
            +
                    if (high_dist_idx < low_dist_idx)
         | 
| 2684 | 
            +
                      @point_numbers.reverse!
         | 
| 2685 | 
            +
                    end
         | 
| 2686 | 
            +
                            
         | 
| 2687 | 
            +
                    @point_numbers.each { |num|
         | 
| 2688 | 
            +
                      mpoint = @matched_points["#{num}"]
         | 
| 2689 | 
            +
                      if mpoint
         | 
| 2690 | 
            +
                        mpoint.course_distance = mpoint.distance - low_dist
         | 
| 2691 | 
            +
                        dttm = DtTm.new("2007-06-09T#{mpoint.elapsed}Z")
         | 
| 2692 | 
            +
                        mpoint.course_elapsed  = dttm.hhmmss_diff(low_dttm) 
         | 
| 2693 | 
            +
                      end
         | 
| 2694 | 
            +
                    }        
         | 
| 2695 | 
            +
                  end           
         | 
| 2287 2696 | 
             
                end
         | 
| 2288 | 
            -
             | 
| 2289 | 
            -
             | 
| 2697 | 
            +
                        
         | 
| 2290 2698 | 
             
            # =============================================================================
         | 
| 2291 2699 |  | 
| 2292 2700 | 
             
            =begin rdoc
         | 
| @@ -2361,7 +2769,7 @@ HERE | |
| 2361 2769 | 
             
                    type  = tokens[0].ljust(6)
         | 
| 2362 2770 | 
             
                    name  = tokens[1]
         | 
| 2363 2771 | 
             
                    count = tokens[2].rjust(6)
         | 
| 2364 | 
            -
                    puts "  #{count}  #{type}  #{name}" | 
| 2772 | 
            +
                    puts "  #{count}  #{type}  #{name}"   
         | 
| 2365 2773 | 
             
                  }
         | 
| 2366 2774 | 
             
                end
         | 
| 2367 2775 |  | 
| @@ -2409,8 +2817,6 @@ HERE | |
| 2409 2817 | 
             
                    count = @tokens_hash.value(name)
         | 
| 2410 2818 | 
             
                    puts "method: #{name}   (#{count})" 
         | 
| 2411 2819 | 
             
                  }  
         | 
| 2412 | 
            -
                  # puts @tokens_hash.to_s
         | 
| 2413 | 
            -
                  # puts @tokens_hash.size
         | 
| 2414 2820 | 
             
                end
         | 
| 2415 2821 |  | 
| 2416 2822 | 
             
                def parse_code_lines
         | 
| @@ -2596,13 +3002,40 @@ HERE | |
| 2596 3002 |  | 
| 2597 3003 | 
             
              class GoobyCommand < GoobyObject 
         | 
| 2598 3004 |  | 
| 2599 | 
            -
                 | 
| 3005 | 
            +
                attr_reader :configuration
         | 
| 3006 | 
            +
                
         | 
| 3007 | 
            +
                def initialize(gooby_yaml_filename=nil)
         | 
| 3008 | 
            +
                  @configuration = Gooby::Configuration.init(gooby_yaml_filename)
         | 
| 2600 3009 | 
             
                end
         | 
| 2601 3010 |  | 
| 2602 | 
            -
                def  | 
| 2603 | 
            -
                   | 
| 3011 | 
            +
                def display_version
         | 
| 3012 | 
            +
                  s = "# #{project_name} #{project_version_number} #{project_date}.  #{project_copyright}."
         | 
| 3013 | 
            +
                  puts s
         | 
| 2604 3014 | 
             
                end
         | 
| 2605 3015 |  | 
| 3016 | 
            +
                def split_garmin_export_file(argv)
         | 
| 3017 | 
            +
                  if (argv == nil)
         | 
| 3018 | 
            +
                    puts "ERROR: no ARGV args passed."
         | 
| 3019 | 
            +
                  elsif (argv.size < 3)
         | 
| 3020 | 
            +
                    puts ""
         | 
| 3021 | 
            +
                    puts "Invalid program args; three args required - format, input filename, output directory"
         | 
| 3022 | 
            +
                    puts "  the first arg, format, should be one of: garmin201, garmin205, garmin305, etc."
         | 
| 3023 | 
            +
                    puts "  the second arg is the input filename - which is a garmin export file"
         | 
| 3024 | 
            +
                    puts "  the third arg is the output directory where the split files are written to\n\n"
         | 
| 3025 | 
            +
                    puts "Please correct the program arguments and try again. \n\n"
         | 
| 3026 | 
            +
                  else
         | 
| 3027 | 
            +
                    format   = argv[0].downcase
         | 
| 3028 | 
            +
                    filename = argv[1]
         | 
| 3029 | 
            +
                    out_dir  = argv[2]
         | 
| 3030 | 
            +
                    
         | 
| 3031 | 
            +
                    if (format == 'garmin201')
         | 
| 3032 | 
            +
                      split_garmin_forerunner_logbook_xml(filename, out_dir)
         | 
| 3033 | 
            +
                    else
         | 
| 3034 | 
            +
                      split_garmin_training_center_xml(filename, out_dir) 
         | 
| 3035 | 
            +
                    end
         | 
| 3036 | 
            +
                  end
         | 
| 3037 | 
            +
                end
         | 
| 3038 | 
            +
                
         | 
| 2606 3039 | 
             
                def split_garmin_forerunner_logbook_xml(xml_filename, out_dir)  
         | 
| 2607 3040 | 
             
                  splitter = Gooby::ForerunnerXmlSplitter.new(xml_filename, out_dir)  
         | 
| 2608 3041 | 
             
                  splitter.split
         | 
| @@ -2612,22 +3045,117 @@ HERE | |
| 2612 3045 | 
             
                  splitter = Gooby::TrainingCenterXmlSplitter.new(tcx_filename, out_dir)  
         | 
| 2613 3046 | 
             
                  splitter.split
         | 
| 2614 3047 | 
             
                end
         | 
| 3048 | 
            +
                
         | 
| 3049 | 
            +
                def parse_garmin_xml_file(argv)
         | 
| 3050 | 
            +
                  if (argv == nil)
         | 
| 3051 | 
            +
                    puts "ERROR: no ARGV args passed."
         | 
| 3052 | 
            +
                  elsif (argv.size < 2)
         | 
| 3053 | 
            +
                    puts ""
         | 
| 3054 | 
            +
                    puts "Invalid program args; two args required - format, input (xml) filename, output directory"
         | 
| 3055 | 
            +
                    puts "  the first arg, format, should be one of: garmin201, garmin205, garmin305, etc."
         | 
| 3056 | 
            +
                    puts "  the second arg, input xml filename, was produced by the Gooby 'splitter.rb' program."
         | 
| 3057 | 
            +
                    puts "Please correct the program arguments and try again. \n\n"
         | 
| 3058 | 
            +
                  else
         | 
| 3059 | 
            +
                    format   = argv[0].downcase
         | 
| 3060 | 
            +
                    filename = argv[1]
         | 
| 3061 | 
            +
                    puts Trackpoint.csv_header        
         | 
| 3062 | 
            +
                    if (format == 'garmin201')
         | 
| 3063 | 
            +
                      parse_garmin_forerunner_logbook_xml(filename)
         | 
| 3064 | 
            +
                    else
         | 
| 3065 | 
            +
                      parse_garmin_training_center_xml(filename) 
         | 
| 3066 | 
            +
                    end
         | 
| 3067 | 
            +
                  end
         | 
| 3068 | 
            +
                end    
         | 
| 2615 3069 |  | 
| 2616 3070 | 
             
                def parse_garmin_forerunner_logbook_xml(xml_filename)  
         | 
| 2617 3071 | 
             
                  handler = Gooby::ForerunnerXmlParser.new     
         | 
| 2618 3072 | 
             
                  Document.parse_stream((File.new xml_filename), handler)
         | 
| 2619 | 
            -
                  handler.put_all_run_tkpt_csv( | 
| 3073 | 
            +
                  handler.put_all_run_tkpt_csv()
         | 
| 2620 3074 | 
             
                end
         | 
| 2621 3075 |  | 
| 2622 3076 | 
             
                def parse_garmin_training_center_xml(tcx_filename)  
         | 
| 2623 3077 | 
             
                  handler = Gooby::TrainingCenterXmlParser.new     
         | 
| 2624 3078 | 
             
                  Document.parse_stream((File.new tcx_filename), handler)
         | 
| 2625 | 
            -
                  handler.put_all_run_tkpt_csv( | 
| 3079 | 
            +
                  handler.put_all_run_tkpt_csv()
         | 
| 3080 | 
            +
                end
         | 
| 3081 | 
            +
             | 
| 3082 | 
            +
                def read_csv_files(array_of_filenames, record_index=0)
         | 
| 3083 | 
            +
                  @cvs_reader = Gooby::CsvReader.new(array_of_filenames)
         | 
| 3084 | 
            +
                  @cvs_points = @cvs_reader.read
         | 
| 3085 | 
            +
                  puts @cvs_reader.to_s
         | 
| 3086 | 
            +
                  if (record_index > 0)
         | 
| 3087 | 
            +
                    @cvs_reader.display_formatted_record(record_index) 
         | 
| 3088 | 
            +
                  end
         | 
| 3089 | 
            +
                  @cvs_points
         | 
| 2626 3090 | 
             
                end
         | 
| 2627 3091 |  | 
| 2628 | 
            -
                def  | 
| 2629 | 
            -
                   | 
| 2630 | 
            -
             | 
| 3092 | 
            +
                def been_there(course_id, proximity=0.0070, uom='deg')
         | 
| 3093 | 
            +
                  unless @cvs_points
         | 
| 3094 | 
            +
                    puts "You must first invoke method 'read_csv_files' with a list of parsed CSV filenames."
         | 
| 3095 | 
            +
                    return
         | 
| 3096 | 
            +
                  end
         | 
| 3097 | 
            +
                  course = configuration.get_course("#{course_id}")
         | 
| 3098 | 
            +
                  unless course
         | 
| 3099 | 
            +
                    puts "Unable to find course id '#{course_id}' in the gooby config yaml file."
         | 
| 3100 | 
            +
                    return
         | 
| 3101 | 
            +
                  end
         | 
| 3102 | 
            +
                  puts ''
         | 
| 3103 | 
            +
                  # collect the cvs_points into run arrays
         | 
| 3104 | 
            +
                  @curr_run_id = 'x'      
         | 
| 3105 | 
            +
                  @cvs_runs = Array.new  
         | 
| 3106 | 
            +
                  @cvs_points.each { |cvs_point|      
         | 
| 3107 | 
            +
                    if (cvs_point.run_id == @curr_run_id)
         | 
| 3108 | 
            +
                      @curr_run.add_point(cvs_point)  
         | 
| 3109 | 
            +
                    else
         | 
| 3110 | 
            +
                      @curr_run_id = cvs_point.run_id
         | 
| 3111 | 
            +
                      @curr_run = Gooby::CvsRun.new(@curr_run_id)
         | 
| 3112 | 
            +
                      @curr_run.add_point(cvs_point)
         | 
| 3113 | 
            +
                      @cvs_runs << @curr_run
         | 
| 3114 | 
            +
                    end
         | 
| 3115 | 
            +
                  }
         | 
| 3116 | 
            +
                  
         | 
| 3117 | 
            +
                  # iterate the runs - looking for a match vs the course
         | 
| 3118 | 
            +
                  @cvs_runs.each { |cvs_run|
         | 
| 3119 | 
            +
                    puts "Scanning run id '#{cvs_run.id}', point count= #{cvs_run.points.size}" if false
         | 
| 3120 | 
            +
                    run_points = cvs_run.points
         | 
| 3121 | 
            +
                    course.reset
         | 
| 3122 | 
            +
                    course.points.each { |course_point|
         | 
| 3123 | 
            +
                      closest_diff  = 999
         | 
| 3124 | 
            +
                      closest_point = nil
         | 
| 3125 | 
            +
                      run_points.each { |run_point|
         | 
| 3126 | 
            +
                        diff  = course_point.degrees_diff(run_point) 
         | 
| 3127 | 
            +
                        if ((diff < proximity) && (diff < closest_diff))
         | 
| 3128 | 
            +
                            closest_diff  = diff
         | 
| 3129 | 
            +
                            closest_point = run_point
         | 
| 3130 | 
            +
                            closest_point.degrees_diff = diff
         | 
| 3131 | 
            +
                            course.matched(course_point.number, run_point)
         | 
| 3132 | 
            +
                        end            
         | 
| 3133 | 
            +
                      }
         | 
| 3134 | 
            +
                    }
         | 
| 3135 | 
            +
                    if course.matched?
         | 
| 3136 | 
            +
                      puts "Course '#{course.name}' matched vs run id '#{cvs_run.id}'" 
         | 
| 3137 | 
            +
                      course.display_matches
         | 
| 3138 | 
            +
                    else
         | 
| 3139 | 
            +
                      puts "course not matched" if false
         | 
| 3140 | 
            +
                    end
         | 
| 3141 | 
            +
                  }
         | 
| 3142 | 
            +
                end
         | 
| 3143 | 
            +
                
         | 
| 3144 | 
            +
                def generate_google_map(argv)  
         | 
| 3145 | 
            +
                  if (argv == nil)
         | 
| 3146 | 
            +
                    puts "ERROR: no ARGV args passed."
         | 
| 3147 | 
            +
                  elsif (argv.size < 1)
         | 
| 3148 | 
            +
                    puts ""
         | 
| 3149 | 
            +
                    puts "Invalid program args; one required - input csv filename"
         | 
| 3150 | 
            +
                    puts "  the first arg, csv filename, was produced by the Gooby 'parser.rb' program."
         | 
| 3151 | 
            +
                    puts "Please correct the program arguments and try again. \n\n"
         | 
| 3152 | 
            +
                  else
         | 
| 3153 | 
            +
                    csv_filename  = argv[0]
         | 
| 3154 | 
            +
                    configuration = Gooby::Configuration.get_config
         | 
| 3155 | 
            +
                    generator = Gooby::GoogleMapGenerator.new(csv_filename)  
         | 
| 3156 | 
            +
                    generator.generate_page(configuration)
         | 
| 3157 | 
            +
                  end
         | 
| 3158 | 
            +
                  
         | 
| 2631 3159 | 
             
                end
         | 
| 2632 3160 | 
             
              end
         | 
| 2633 3161 | 
             
            end # end of module
         |