Aug 27

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. ;-)

Tagged with:
Mar 05

Não sei o que acham do sistema de notificações dos portais da rede IOL mas eu simplesmente não SUPORTO. É extremamente intrusivo, não permite ser desactivado e pior que tudo está sistematicamente a repetir-se (basta fazer um refresh da página e já lá está novamente! *g*).

Felizmente há várias formas de acabar com esta praga, e uma delas é usar o fabuloso plugin AdBlock Plus. Nada mais simples que abrir as opções do plugin no vosso browser favorito (Espero que seja o Firefox ou Chrome :p) e acrescentar as seguintes regras nos filtros:

iol.pt###iolpush_wrapBoxPush
iol.pt##.iolpush_open

20130305224231121

Et voila! A caixa de noticias irritante desapareceu! :D

Tagged with:
Sep 15

Hi,

Today I’m going to show you a very small script that allows you to convert any video (as long as it is supported by mplayer) to a GIF.

Required tools:

* mplayer

* convert

 

mplayer is popular media player available for multiple operating systems that support a wide range of video formats. The convert tool is an utility that lets you convert between multiple image formats among other definitions.  Since the mplayer takes screenshots using jpeg format, we need to use the convert tool to do the convertion to aGIF format.

 

Copy the following code, save it to a file and change its permissions (chmod a+x) and you are ready to roll :)

 

 

#!/bin/sh
TMPDIR=/tmp/animated
shopt -s nocaseglob
if [ ! -d "$TMPDIR" ]
then
        mkdir $TMPDIR
fi
 
\rm $TMPDIR/* &> /dev/null
 
if [ $# -lt 3 ]
then
        echo -e "Usage: $0    []\nExample:\n$0 00:15:11 10 myvideo.avi 320:240"
        exit 1
fi
 
if [ -n "$4" ]
then
        SCALE="scale=$4"
fi
 
echo "Generating screenshots. Please be patitent..."
mplayer -ao null -ss $1 -endpos $2 $3 -vo jpeg:outdir=$TMPDIR/ -vf $SCALE &amp;&gt; /dev/null
if [ -f $TMPDIR/00000001.jpg ]
then
        echo "Finished generating frames. Assembling the animated GIF..."
        convert -delay 5 $TMPDIR/*.jpg $TMPDIR/output.gif
        echo "Done! Please check the $TMPDIR/output.gif"
        exit 0
else
        echo -e "Oops\! Something went wrong and the frames were not generated. Check your parameters\!"
        exit 1
fi

Just try it and let me know ;-)

Tagged with:
Nov 24

If you do a quick search in google, you can find several links which explain how to hide the taskbar under Windows CE. Unfortunately, almost everything that you can find either is directed to unmanaged languages like C++ and VB6 or is based on C# language.

Here goes a quick snippet that do the same thing using VB.Net:

    Public Const SW_HIDE As Integer = &amp;H0
    Public Const SW_HIDEWINDOW As Integer = &amp;H0
    Public Const SW_SHOWNORMAL As Integer = &amp;H1
 
     _
    Public Function FindWindow(ByVal className As String, ByVal windowName As String) As IntPtr
    End Function
 
     _
    Public Function ShowWindow(ByVal hWnd As IntPtr, ByVal cmdShow As Integer) As Boolean
    End Function
 
    Public Sub HideMyTaskBar()
        Dim taskBarHWnd As IntPtr = FindWindow("HHTaskBar", String.Empty)
        ShowWindow(taskBarHWnd, SW_HIDE)
    End Sub

Now just call the HideMyTaskBar() sub and that’s it! :)

Tagged with:
Oct 09

The following code is a .Net class that can be used to update a dyndns host alias. It is pretty simple to use. All you have to do is instantiate the class passing the username/password/host to the constructor.

This is the class:

' .Net DynDNS client class by David Gouveia - me[_@_]davidgouveia.net
' Feel free to use it as long as you don't remove the credits :o)
 
Imports System.Net
Imports System.IO
Public Class DynDnsUpdater
    Private _username, _password, _host, _ip As String
 
    Public Enum UpdateStatus
        SUCESS
        FAIL
        NOCHANGE
    End Enum
 
    Private Function checkip() As String
        Dim ipRegex As New System.Text.RegularExpressions.Regex("[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}", System.Text.RegularExpressions.RegexOptions.Singleline)
 
        Try
            Dim UpdateClient As System.Net.HttpWebRequest = WebRequest.Create( _
            New Uri("http://checkip.dyndns.org"))
            UpdateClient.Timeout = 15000
            Dim response As WebResponse = UpdateClient.GetResponse()
            Dim content As Stream = response.GetResponseStream()
            Dim readstream As New StreamReader(content, System.Text.Encoding.Default)
            Dim IpAddress As String = readstream.ReadToEnd
            readstream.Close()
            content.Close()
            If ipRegex.IsMatch(IpAddress) Then
                Return ipRegex.Match(IpAddress).Groups(0).Value
            Else
                Return Nothing
            End If
        Catch
            Return Nothing
        End Try
    End Function
 
    Public Sub New(ByVal username As String, ByVal password As String, ByVal host As String)
        _username = username
        _password = password
        _host = host
    End Sub
 
    Public Function update() As UpdateStatus
        _ip = checkip()
 
        Dim UpdateClient As System.Net.HttpWebRequest = WebRequest.Create( _
        New Uri("http://members.dyndns.org/nic/update?hostname=" + _host + "&amp;myip=" + _ip))
        UpdateClient.Credentials = New NetworkCredential(_username, _password)
        UpdateClient.PreAuthenticate = True
        UpdateClient.UserAgent = ".Net DynDNS Updater Client"
        UpdateClient.Timeout = 15000
 
        Dim response As WebResponse = UpdateClient.GetResponse()
        Dim content As Stream = response.GetResponseStream()
        Dim readstream As New StreamReader(content, System.Text.Encoding.Default)
        Dim DynDnsResponse As String = readstream.ReadToEnd
        readstream.Close()
        content.Close()
 
        If DynDnsResponse.Contains("good " + _ip) Then
            Return UpdateStatus.SUCESS
        ElseIf DynDnsResponse.Contains("nochg " + _ip) Then
            Return UpdateStatus.NOCHANGE
        Else
            Return UpdateStatus.FAIL
        End If
 
    End Function
End Class

And this is how you can use it:

Dim updater As New DynDnsUpdater("dyndns username", "dyndns password", "hostalias")
        If updatert.update() <> DynDnsUpdater.UpdateStatus.FAIL Then
            MsgBox("SUCCESS!")
        Else
            MsgBox("ERROR!")
        End If

have fun :-)

Tagged with:
Jun 14

Depois do último algoritmo para validar o contribuinte, aqui fica uma versão para validar o NIB.

function isValidNib($nib){
$result = "";
if(strlen(intval($nib)) != 21)
return "NIB INVALIDO (Standard: 21 algarismos. Introduzido: " . strlen(intval($nib)) . ")";
 
$nnib = str_split(intval($nib));
 
for($i=0; $i&lt; 19 ; $i++){
        $result = (($result + $nnib[$i]) * 10) % 97;
}
$result = 98 - (($result * 10) % 97);
 
if($result &lt; 10)
        $result = "0" + $result;
 
if(substr($nib, 19, 2) != $result)
        return "NIB INVALIDO";
else
        return "NIB VALIDO";
}

Se preferirem podem trocar o texto enviado no retorno das funções e utilizar um boleano true/false.

EDIT: Agradecimentos ao Nuno Cancelo pela dica de optimização enviada! :)

Tagged with:
Jun 14

Já tenho visto por aí vários algoritmos para validar o numero de contribuinte, mas não vi um feito em PHP.

Disponibilizo aqui um pedaço de código em PHP para que possam incluir nos vossos serviços.

function isValidNif($nif){
 
//Verificar se e' um numero e se e' composto exactamente por 9 digitos
if(!is_numeric($nif) || strlen($nif) != 9) return false;
 
$narray = str_split($nif);
 
//verificar se o primeiro digito e' valido. O primeiro digito indica o tipo de contribuinte.
if($narray[0] != 1 &amp;&amp; $narray[0] != 2 &amp;&amp;  $narray[0] != 5 &amp;&amp; $narray[0] != 6 &amp;&amp; $narray[0] != 8 &amp;&amp; $narray[0] != 9)
        return false;
 
$checkbit = $narray[0] * 9;
 
for($i=2; $i&lt;=8; $i++){
        $checkbit += $nif[$i-1] * (10 - $i);
}
 
$checkbit = 11 - ($checkbit % 11);
 
if($checkbit &gt;= 10) $checkbit=0;
 
if($nif[8] == $checkbit) return true;
echo "$nif - $checkbit";
return false;
}
Tagged with:
Apr 27

Summary: with this mod you will be able to insert any script into your clipbucket. I’m using it to manage google analytics.

1st – Open styles/cbv2new/layout/global_header.html. Find:

<!-- Setting Template Variables -->
{php}
	if(!$_COOKIE['current_style'])
    	$_COOKIE['current_style'] = 'grid_view';
{/php}

Add below:

<!-- Google Analytics -->;
{show_analytics|html_entity_decode}

2nd – includes/common.php. Find:

$Smarty-&gt;register_function('cbtitle','cbtitle');

Add below:

$Smarty-&gt;register_function('show_analytics', 'show_analytics');

3rd – Open includes/functions.php. Find:

	/**
	 * Function used to load clipbucket title
	 */
	function cbtitle($params=false)
	{

Add above:

	/**
	* Function used to load Google Analytics - me( at )davidgouveia.net
	*/
	function show_analytics()
	{
		global $Cbucket;
		// code to convert html entities back useful code.
		echo base64_decode($Cbucket-&gt;configs['google_analytics']);
 
	}

4th – Open admin_area/main.php. Find:

	'gravatars',

Add above:

	'google_analytics',

Find:

	$value = mysql_clean($_POST[$field]);
	if(in_array($field,$num_array))

Add above:

	if($field == 'google_analytics')
		$value = base64_encode($_POST['google_analytics']);
	else

(the “else” MUST be in the line immediately above “$value = mysql_clean($_POST[$field]);”).

Finally, open /admin_area/styles/cbv2/layout/main.html. Find:

            <tr>
              <td valign="top">Meta Description</td>
              <td valign="top"><textarea name="description" id="description" cols="45" rows="5">{$row.description}</textarea></td>
            </tr>

Add below:

       	    <tr>
              <td valign="top">Google Analytics</td>
              <td valign="top"><textarea name="google_analytics" id="google_analytics" cols="45" rows="5">{$row.google_analytics|base64_decode|html_entity_decode}</textarea></td>
            </tr>

Done! You shoud see another option under Web Settings.

Tested under ClipBucket 2.0.6.

PS: I’m using base64_encode/decode because I want to save the script as its original values and I need to avoid using functions like mysql_clean() to sanitize the code. By saving it as a base64 string I avoid potential malicious SQL injection problems. I’m sure there are other ways of doing it but this works OK (I think :p).

Tagged with:
Apr 15

Estive com uns problemas na empresa relacionados com o sendmail.
Quando nada fazia prever, o sendmail simplesmente crasha começando a recusar activamente todos os pedidos de envio de email.

Criei um script genérico para verificar se uma determinada porta de um servidor está a responder. Basta editar o endereço, porta e opcionalmente definir um timeout máximo para o pedido.

#!/usr/bin/php -q
<?
 
/*****************************************************
 
    Check For Open Ports - David Gouveia
 
*****************************************************/
 
$address = '127.0.0.1';
$port = 25;
$timeout = 5;  //Max time to wait before give up.
 
$checkport = fsockopen($address, $port, $errnum, $errstr, $timeout);
 
if(!$checkport){
        print "CRITICAL: Host $address at port $port not responding!\n";
        fclose($checkport);
        exit(2);
}
 
print "OK: Host $address at port $port is responding!\n";
fclose($checkport);
exit(0);
 
?>

Coloquem na pasta dos plugins e não se esqueçam de dar as permissões correctas (755).
Alternativamente podem passar o valor do IP e porta como argumentos via consola.

basta trocar isto :

    $address = ’127.0.0.1′;
    $port = 25;

por isto :

    $address = $argv[1];
    $port = $argv[2]
Tagged with:
preload preload preload