Merge Strava’s GPX exported files

Last Weekend something happened during a morning ride on my bike with some friends and my GPS device turned off for no reason. When I turned it back on I didn’t have the choice of continuing a previous ride and I had to create a new ride.

When I got home and tried to upload the information the Strava I couldn’t find any feature which could let me merge rides and fixe the issue. Instead I ended up having two different rides which really annoyed me.

I started googling around and found someone suggesting that I export the rides and merge the contents of the files. They also suggested that this could be done directly concatenating the files which isn’t true. The trick here is to extract the tracking data from the files (GPX files exported from Strava are XML based) and using the first one as the metadata template.

This was the result of a very simple GPX merger:

#!/usr/bin/env php -q
<?php
/*
* StravaMerger © David Gouveia - http://www.davidgouveia.net
* Simple script to merge tracking data from Strava's exported GPX files.
* The backtrack_limit is there because some files could not be parsed due to their size.
* Feel free to raise the limit but be carrefull not to cross the limit.
* Instead of using regex, I could have used a XML cursor to overcome the backtrack limit
* but either I would have to use the php_xml extension or build my own parser.
*/
ini_set("pcre.backtrack_limit", "10000000");
 
if ( !trim( $argv[1] ) || trim( !$argv[2] ) || sizeof($argv) < 4 )
               die("Usage:\n$argv[0] file1.gpx file2.gpx <fileN.gpx> output.gpx\n" );
 
$segments ="";
 
 
for($i = 1; $i < sizeof($argv) - 1; $i++)
{
        echo "Processing $argv[$i] ...";
        if (!is_file( $argv[$i] ) ) die( "Invalid file: $argv[$i]\n" );
 
        $gpx = file_get_contents( $argv[$i] );
        if ( $i == 1 )  preg_match( "/^(.*?)<trkseg>.*?<\/trkseg>(.*?)$/is", $gpx, $metadata );
        preg_match("/<trkseg>(.*?)<\/trkseg>/ims", $gpx, $matches);
        if( trim( $matches[1] ) )
        {
                $segments .= $matches[1];
                echo "[OK]\n";
        }
        else
                echo "[FAIL]\n";
 
}
 
$output_file = $metadata[1] . "<trkseg>" . $segments . "</trkseg>" . $metadata[2];
 
file_put_contents($argv[sizeof($argv) -1], $output_file) or die( "Unable to create destination GPX\n" );
print "File " . $argv[sizeof($argv) -1] . " successfully created.\n";

I’m going to put an online version of this script to make it easier to use. ;-)

Use nagios to check your raid arrays

As a sysadmin, I should always search and check for errors on every machine that I manage. Unfortunately one of them has an Adaptec 5405 which I forgot to monitor using nagios and just like Murphy’s Law says – “Anything that can go wrong will go wrong” – something went wrong and I have lost information. Not a really big problem because I have backups of everything but it could have been avoided if I had monitored the status of the Adaptec just the way I do with software raid arrays (/proc/mdstat rules!).

So I developed another simple script using Perl (again :-P ) to check the status of all the available arrays.

#!/usr/bin/perl -w
use strict;
use warnings;
 
my $adaptec_tool = "/usr/src/cmdline/arcconf";
 
my $dump = `$adaptec_tool getconfig 1 ld`;
my @raids = ();
 
while ($dump =~ /Logical device name.*?:.*?([a-z0-9]+).*?raid level.*?:.*?([0-9]+).*?status of logical device.*?:.*?([a-z0-9]+)/gsi) {
        push @raids, {"name" => $1, "raidlevel" => $2, "status" => $3};
 
}
 
foreach my $raid (@raids)
{
        if ( $$raid{status} ne "Optimal" )
        {
                print "Critical: Raid not Optimal! (Array Name: $$raid{name}, Level: $$raid{raidlevel}, Status: $$raid{status})\n";
                exit(1);
        }
}
 
print "OK: All arrays in optimal shape\n";
exit (0);

You just need to download the “Adaptec Storage Manager” to connect to the RAID card and read the status. You can use this link to do it.

How to receive an alert everytime a website changes…

I’ve been trying to learn how to use Perl to do some simple stuff whenever I just cannot use PHP. PERL is a language that I have access on every machine under my control, but unfortunately I cannot say the same thing about PHP and that is why I have decided to start learning using this ultra flexible language.

Now, the first thing I have developed (aside from the popular Hello World – LOL) was a simple script to check for website updates. This was particularly useful to check for updates on a website related to a contest.

use strict;
use warnings;
use LWP::Simple;
use Digest::MD5 qw(md5 md5_hex md5_base64);
use Encode qw(encode_utf8);
 
my $link                = 'http://www.foobar.com';
my $email_from          = 'foo@bar.com';
my $email               = 'bar@foo.com';
my $email_subject       = 'Website Changed!';
my $email_body          = 'Hello! I just want to let you know that the website ' 
                          . $link . ' have just changed!';
my $tmp_file            = '/tmp/stored_hash';
 
my $web_source = get( $link );
my $current_hash =  md5_hex(encode_utf8($web_source));
 
if(-e $tmp_file)
{
        open FH, "<$tmp_file" or die "could not open: $!\n";
        my $mod_hash = <FH>;
        if( $current_hash ne $mod_hash )
        {
                open(MAIL, "|/usr/sbin/sendmail -t");
                print MAIL "To: $email\n";
                print MAIL "From: $email_from\n";
                print MAIL "Subject: $email_subject\n\n";
                print MAIL "$email_body\n";
                close(MAIL);
 
        }
        close FH;
}
        open FH, ">$tmp_file" or die "could not create: $!\n";
        print FH $current_hash;
        close FH;

Just replace the email and link stuff to suite your needs and you are all set! Enjoy!