<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Il blog di Mario Spada</title>
	<atom:link href="http://www.spadamar.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.spadamar.com</link>
	<description>&#34;Ama la verità ma perdona l&#039;errore&#34; [Voltaire]</description>
	<lastBuildDate>Sun, 11 Dec 2011 09:33:42 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>PHP: un socket TCP per acquisire dati dal GPS Tracker GPS-102 compatibile OpenGTS (terza parte)</title>
		<link>http://www.spadamar.com/2011/12/php-un-socket-tcp-per-acquisire-dati-dal-gps-tracker-gps-102-compatibile-opengts-terza-parte/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=php-un-socket-tcp-per-acquisire-dati-dal-gps-tracker-gps-102-compatibile-opengts-terza-parte</link>
		<comments>http://www.spadamar.com/2011/12/php-un-socket-tcp-per-acquisire-dati-dal-gps-tracker-gps-102-compatibile-opengts-terza-parte/#comments</comments>
		<pubDate>Sun, 11 Dec 2011 09:31:26 +0000</pubDate>
		<dc:creator>spadamar</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[GPS]]></category>
		<category><![CDATA[OpenGTS]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[socket]]></category>
		<category><![CDATA[tracker]]></category>

		<guid isPermaLink="false">http://www.spadamar.com/?p=388</guid>
		<description><![CDATA[In quest&#8217;ultimo articolo descrivo come si lancia in background lo script PHP su un server con sistema operativo Linux Ubuntu o Debian. Come vi sarete accorti lo script descritto nella seconda parte contiene nella prima riga il seguente codice: #!/usr/bin/env &#8230; <a href="http://www.spadamar.com/2011/12/php-un-socket-tcp-per-acquisire-dati-dal-gps-tracker-gps-102-compatibile-opengts-terza-parte/">Continua a leggere<span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div id="attachment_389" class="wp-caption alignleft" style="width: 276px"><a href="http://www.spadamar.com/wp-content/uploads/2011/12/php_daemon.jpg" rel="lightbox[388]"><img class="size-medium wp-image-389" title="php daemon" src="http://www.spadamar.com/wp-content/uploads/2011/12/php_daemon-266x300.jpg" alt="php daemon" width="266" height="300" /></a><p class="wp-caption-text">php daemon</p></div>
<p>In quest&#8217;ultimo articolo descrivo come si lancia in background lo script PHP su un server con sistema operativo Linux Ubuntu o Debian. Come vi sarete accorti lo script descritto nella <a title="Un socket PHP seconda parte" href="http://www.spadamar.com/2011/11/php-un-socket-tcp-per-acquisire-dati-dal-gps-tracker-gps-102-compatibile-opengts-seconda-parte/">seconda parte</a> contiene nella prima riga il seguente codice:</p>
<p><code>#!/usr/bin/env php</code></p>
<p>in gergo questa sintassi si chiama <a title="Shebang" href="http://en.wikipedia.org/wiki/Shebang_%28Unix%29" target="_blank">Shebang</a> e viene utilizzata per lanciare dalla shell l&#8217;interprete dello script che sta per essere eseguito. In questo caso il PHP. Sarà dunque necessario verificare che PHP5-CLI (command line interpreter) sia installato.</p>
<p><span id="more-388"></span><br />
Se proviamo a lanciare, semplicemente digitando gpsspck.php da un terminale, questo è l&#8217;output prodotto non appena viene &#8220;agganciato&#8221; il tracker:</p>
<div id="attachment_398" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.spadamar.com/wp-content/uploads/2011/12/Schermata.png" rel="lightbox[388]"><img class="size-medium wp-image-398" title="Schermata" src="http://www.spadamar.com/wp-content/uploads/2011/12/Schermata-300x59.png" alt="output di gpssock.php" width="300" height="59" /></a><p class="wp-caption-text">output di gpssock.php</p></div>
<p>Per lanciarlo in background, questo è lo script bash che ho preparato per gestire l&#8217;avvio e la chiusura del socket PHP:</p>
<pre class="brush:bash">#!/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
NAME=gpssock
PIDFILE="/var/run/${NAME}.pid"
WORKINGDIR="/path/to/gpssock/"
DAEMON="${WORKINGDIR}${NAME}.php"
DAEMONLOG="${WORKINGDIR}${NAME}.out"

case "$1" in
  start)
	start-stop-daemon --start  --make-pidfile --pidfile=$PIDFILE --exec $DAEMON&gt;&gt;$DAEMONLOG &amp;
	;;
  restart|reload|force-reload)
	echo "Error: argument '$1' not supported" &gt;&amp;2
	exit 3
	;;
  stop)
	start-stop-daemon --stop --pidfile=$PIDFILE
	;;
  *)
	echo "Usage: $0 start|stop" &gt;&amp;2
	exit 3
	;;
esac</pre>
<p>Lo script esegue <code>start-stop-daemon</code> che è un programma frequentemente utilizzato su Ubuntu per avviare e terminare i processi che funzionano come demoni. Se ne possono trovare diversi esempi nella directory <code>/etc/init.d/</code> ed infatti è proprio lì che andremo a collocare il nostro script. Gli unici due settaggi da fare sono quelli di modificare, se necessario, la variabile <code>NAME</code> con il nome del file PHP da lanciare (nel nostro caso gpssock) e di impostare la directory di lavoro <code>WORKINGDIR</code> con il percorso corretto di gpssock.php<br />
Notate che l&#8217;ultimo parametro di <code>start-stop-daemon</code> è &amp; questo indica che il processo deve essere eseguito in background. Infine tutti gli output vengono rediretti in un file di log che ha lo stesso nome dello script PHP ed estensione <code>.out</code></p>
<p>Per lanciare lo script da riga di comando:</p>
<p><code>/etc/init.d/gpssock start</code></p>
<p>Per terminare lo script da riga di comando:</p>
<p><code>/etc/init.d/gpssock stop</code></p>
<p>Se vogliamo che lo script parta all&#8217;avvio in esecuzione automatica, è necessario registrarlo con questa istruzione:</p>
<p><code>update-rc.d gpssock defaults</code></p>
<p>Riferimenti:</p>
<ul>
<li><a title="OpenGTS" href="http://www.opengts.org/" target="_blank">OpenGTS</a></li>
<li><a title="Open GPS Tacking Server" href="http://sourceforge.net/projects/traccar/" target="_blank">Open GPS Tracking Server</a></li>
<li><a title="Socket Programming with PHP" href="http://www.devshed.com/c/a/PHP/Socket-Programming-With-PHP/" target="_blank">Socket Programming With PHP</a></li>
<li><a title="Manuale PHP: i socket" href="http://php.net/manual/en/book.sockets.php" target="_blank">PHP: Sockets &#8211; Manual</a></li>
</ul>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spadamar.com/2011/12/php-un-socket-tcp-per-acquisire-dati-dal-gps-tracker-gps-102-compatibile-opengts-terza-parte/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP: un socket TCP per acquisire dati dal GPS Tracker GPS-102 compatibile OpenGTS (seconda parte)</title>
		<link>http://www.spadamar.com/2011/11/php-un-socket-tcp-per-acquisire-dati-dal-gps-tracker-gps-102-compatibile-opengts-seconda-parte/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=php-un-socket-tcp-per-acquisire-dati-dal-gps-tracker-gps-102-compatibile-opengts-seconda-parte</link>
		<comments>http://www.spadamar.com/2011/11/php-un-socket-tcp-per-acquisire-dati-dal-gps-tracker-gps-102-compatibile-opengts-seconda-parte/#comments</comments>
		<pubDate>Wed, 30 Nov 2011 07:18:17 +0000</pubDate>
		<dc:creator>spadamar</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[GPS]]></category>
		<category><![CDATA[OpenGTS]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[socket]]></category>
		<category><![CDATA[tracker]]></category>

		<guid isPermaLink="false">http://www.spadamar.com/?p=375</guid>
		<description><![CDATA[Nella prima parte di questo articolo ho illustrato come creare le tabelle del DB dove registrare i dati provenienti dal tracker GPS, le principali funzionalità dello script e la possibilità di &#8220;agganciare&#8221; questo socket direttamente al software Open Source: OpenGTS. &#8230; <a href="http://www.spadamar.com/2011/11/php-un-socket-tcp-per-acquisire-dati-dal-gps-tracker-gps-102-compatibile-opengts-seconda-parte/">Continua a leggere<span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div id="attachment_376" class="wp-caption alignleft" style="width: 310px"><a href="http://www.spadamar.com/wp-content/uploads/2011/11/socketphp.jpg" rel="lightbox[375]"><img src="http://www.spadamar.com/wp-content/uploads/2011/11/socketphp.jpg" alt="Socket PHP" title="Socket PHP" width="300" height="292" class="size-full wp-image-376" /></a><p class="wp-caption-text">Socket PHP</p></div>
<p>Nella <a href='http://www.spadamar.com/2011/11/php-un-socket-tcp-per-acquisire-dati-dal-gps-tracker-gps-102-compatibile-opengts-prima-parte/'>prima parte</a> di questo articolo ho illustrato come creare le tabelle del DB dove registrare i dati provenienti dal tracker GPS, le principali funzionalità dello script e la possibilità di &#8220;agganciare&#8221; questo socket direttamente al software Open Source: OpenGTS.</p>
<p>Quest&#8217;ultima caratteristica, la ritengo particolarmente interessante in quanto permette di evitare di scriversi tutta la parte che riguarda la visualizzazione dei punti inviati dal tracker, sulle mappe.<br style='clear:both' /></p>
<table>
<caption>Settaggi del socket</caption>
<tbody>
<tr>
<th>Chiave</th>
<th>Valori possibili</th>
<td>Descrizione</td>
</tr>
<tr>
<td>VERBOSE</td>
<td>true|false</td>
<td>Se impostato a true fornisce un output dettagliato degli errori</td>
</tr>
<tr>
<td>MOVING_THRESHOLD</td>
<td>.05</td>
<td>Soglia minima in Km per la registrazione del dato [.05 = 50 metri]</td>
</tr>
<tr>
<td>OPENGTS</td>
<td>true|false</td>
<td>Se impostato a true invia query per le tabelle OpenGTS</td>
</tr>
<tr>
<td>IP_ADDR</td>
<td>xxx.xxx.xxx.xxx</td>
<td>Indirizzo IP in ascolto [0 = tutti gli indirizzi]</td>
</tr>
<tr>
<td>TCP_PORT</td>
<td>0..65535</td>
<td>La porta TCP da utilizzare</td>
</tr>
<tr>
<td>DBHOST</td>
<td>localhost</td>
<td>Indirizzo del DB MySQL</td>
</tr>
<tr>
<td>DBUSER</td>
<td>dbuser</td>
<td>utente del DB MySQL</td>
</tr>
<tr>
<td>DBPASS</td>
<td>dbpassword</td>
<td>password dell&#8217;utente del DB MySQL</td>
</tr>
<tr>
<td>DBNAME</td>
<td>gpsd</td>
<td>nome del DB MySQL</td>
</tr>
<tr>
<td>POLL_TIME</td>
<td>20|30|60|300|600</td>
<td>Tempo di polling del tracker in secondi</td>
</tr>
<tr>
<td>SPEED_CONV</td>
<td>1.609344|1.852</td>
<td>Conversione da Miglia (terrestri|marine) a Km</td>
</tr>
<tr>
<td>DFLT_MSG</td>
<td>&#8216;tracker&#8217;</td>
<td>Messaggio di default del tracker</td>
</tr>
<tr>
<td>SOCK_RCV_TIMEOUT</td>
<td>120</td>
<td>Timeout in secondi per il socket in ricezione</td>
</tr>
</tbody>
</table>
<p>Ed ecco il codice PHP del loop del socket (L&#8217;intero script è disponibile <a href='http://www.spadamar.com/files/gpssock/gpssock.zip'>qui</a>):</p>
<p><span id="more-375"></span></p>
<pre class="brush:php">
#!/usr/bin/env php
< ?php
/***********************************************************************
 *  SETTINGS
 * ********************************************************************/
define("VERBOSE", true);
define("MOVING_THRESHOLD",.04); //.05 = 50 metres
define("OPENGTS",false);
/* HOST                                                               */
define("IP_ADDR","0");	// "0" = listen all ip
define("TCP_PORT",5050);
/* DATABASE                                                           */
define("DBHOST","localhost");
define("DBUSER","dbuser");
define("DBPASS","dbpassword");
define("DBNAME","gpsd");
/* TRACKER                                                            */
define("POLL_TIME",60); // SET POLL TIME 20,30,60,300,600 default:60 secs
define("SPEED_CONV",1.852); //From NM to Km
define("DFLT_MSG","tracker");
/* SOCKET                                                             */
define("SOCK_RCV_TIMEOUT",120); // Socket receive timeout in seconds
/***********************************************************************
 * END SETTINGS
 * ********************************************************************/
// Do not edit here-----------------------------------------------------
error_reporting(E_ALL);
// Do not exit while waiting for connect...
set_time_limit(0);
// Turn implicit flush on
ob_implicit_flush();

$dblink = dbConnect();
$address =  IP_ADDR;
$port = TCP_PORT;
$allowedIMEI = getAllowedImei($dblink);
$sendPollTime = false;

// Create the socket and bind it to the host and port, with infinite loop.

if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {
   writeLog("socket_create() failed: ".socket_strerror($sock),true);
}
if (($ret = socket_bind($sock, $address, $port)) < 0) {
   writeLog("socket_bind() failed: ".socket_strerror($ret),true);
}
if (($ret = socket_listen($sock, 5)) < 0) {
   writeLog("socket_listen() failed: ".socket_strerror($ret),true);
}
do {
	if (!mysql_ping ($dblink)) { //check if mysql connection is active
		mysql_close($dblink);
		$dblink = dbConnect(); //if not, connect!
	}
	try {
		if (FALSE === ($msgsock = socket_accept($sock))) {
		  throw new Exception("socket_accept() failed: " . socket_strerror(socket_last_error($msgsock)));
		}
		socket_set_option($msgsock, SOL_SOCKET, SO_RCVTIMEO, array('sec' => SOCK_RCV_TIMEOUT,'usec' => 0));
		writeLog("CONNECT");
		if (FALSE === ($buf = socket_read($msgsock, 2048))) {
		  throw new Exception("socket_read() failed: " . socket_strerror(socket_last_error($msgsock)));
		}
		writeLog("RECEIVED: ".$buf);
		$actualIMEI = "";
		$outData = array();
		$buf = trim($buf); // clean up input string
		$dirtyMode = (substr($buf, 0, 2) == "##") ? false : true;
		$actualIMEI = (!$dirtyMode) ? substr($buf, 8, 15) : substr($buf, 5, 15);  // returns IMEI

		if (!in_array($actualIMEI, $allowedIMEI)){
		  throw new Exception("Received: $actualIMEI from $buf, IMEI not allowed");
		}
		if (!$dirtyMode){
			$output = "LOAD". "\n";
			writeLog("SEND: LOAD");
			// Send intructions
			socket_write($msgsock, $output, strlen($output));
			if (FALSE === ($buf = socket_read($msgsock, 2048))) {
		  		throw new Exception("socket_read() failed: " . socket_strerror(socket_last_error($msgsock)));
			}
			$buf = trim($buf);
			writeLog("RECEIVED: ".$buf);
			if (empty($buf)){
				 throw new Exception("Received: nothing, disconnect");
			}

			if (($sendPollTime === false)) {
				$output = "ON". "\n";
				writeLog("SEND: ON");
				socket_write($msgsock, $output, strlen($output));
				$output = "**,imei:".$actualIMEI."," . pollTimeString(POLL_TIME)."\n";
				socket_write($msgsock, $output, strlen($output));
				writeLog("SEND: ".$output);
				if (FALSE === ($buf = socket_read($msgsock, 2048))) {
					$sendPollTime = false;
					throw new Exception("socket_read() failed: " . socket_strerror(socket_last_error($msgsock)));
				}
				$buf = empty($buf) ? "NO DATA" : trim($buf);
				$sendPollTime = true;
			}
		}
		$outData = explode ( "," , $buf );
		writeLog("DATA: ".$buf);
		if(count($outData)>=5){
			$outDecodedData = decodeData($outData);
			if ($outDecodedData['DATA_FL'] == "F" || $outDecodedData['MSG'] !== DFLT_MSG){
				if (OPENGTS) {
					$res = updatePosOpenGTS($outDecodedData);
				}
				else{
					$res = updatePos($outDecodedData);
				}
			}
		}
	} catch (Exception $e) {
		writeLog(" ".$e->getMessage(),true);
	}
	socket_close($msgsock);
	writeLog("SOCKET CLOSE");
} while (true);
socket_close($sock);
dbClose($dblink);
// ... continua
?>
</pre>
<p>Come si può notare il socket <code>$sock</code> è in costante ascolto, e quando arriva una richiesta di connessione viene creato il socket <code>$msgsock</code> che si prende il carico dell&#8217;intera comunicazione. Se il tracker sta trasmettendo in &#8220;single point&#8221;, i primi due caratteri sono: <code>##</code>, in questo caso viene inviato il comando di polling forzando l&#8217;apparecchio a trasmettere in &#8220;multi point&#8221; con l&#8217;intervallo desiderato.</p>
<p>Vediamo adesso la funzione che si occupa della decodifica del messaggio che contiene i dati veri e propri. Questo è formato da 12 campi separati da virgola. Nei commenti iniziali è riportata la loro composizione, il formato e i possibili valori.</p>
<pre class="brush:php">
function decodeData($arr){
/* *********************************************************************
*   0 = imei:000000000000000	[imei]
*   1 = tracker					[Msg: help me / low battery / stockade /
* 											dt /move / speed / tracker]
*   2 = 0809231929				[acquisition time: YYMMDDhhmm +8GMT cn]
*   3 = 13554900601				[adminphone?]
*   4 = F						[Data: F - full / L - low]
*   5 = 112909.397				[Time (HHMMSS.SSS)]
*   6 = A						[A = available?]
*   7 = 2234.4669				[Latitude (DDMM.MMMM)]
*   8 = N						[Lat direction: N / S]
*   9 = 11354.3287				[Longitude (DDDMM.MMMM)]
*  10 = E						[Lon direction: E / O]
*  11 = 0.11					[speed Mph]
***********************************************************************/
	$out = array();
	$out['IMEI'] = substr($arr[0], 5, 15);
	$out['MSG'] = trim($arr[1]);
	$out['ACQUISITION_TIME'] = substr($arr[2], 0, 2)."-".
						substr($arr[2], 2, 2)."-".substr($arr[2], 4, 2).
						" ".substr($arr[2],6,2).":".substr($arr[2],8,2);
	$out['ADMINPHONE'] = trim($arr[3]);
	$out['DATA_FL'] = trim($arr[4]);
	 if ($out['DATA_FL'] === "F"){
		 $out['TIME'] = substr($arr[5], 0, 2).":" . substr($arr[5], 2, 2).":" . sprintf("%2d",round(floatval(substr($arr[5], 4, 6))));
		 $out['AVAILABLE'] = $arr[6]==="A" ? 1 : 0;
		 $out['LAT'] = floatval(substr($arr[7], 0, 2)) +
					   floatval(substr($arr[7], 2, 7)) / 60;
		 $out['LAT'] = $arr[8]==="N" ? $out['LAT'] : -$out['LAT'];
		 $out['LON'] = floatval(substr($arr[9], 0, 3))  +
					   floatval(substr($arr[9], 3, 7)) / 60;
		 $out['LON'] = $arr[10]==="E" ? $out['LON'] : -$out['LON'];
		 $out['SPEED'] = floatval($arr[11]) * SPEED_CONV;
	}
	else {
		 $out['TIME'] = "00:00:00";
		 $out['AVAILABLE'] = 0;
		 $out['LAT'] = (float) 0;
		 $out['LON'] = (float) 0;
		 $out['SPEED'] = (float) 0;
	}
	return $out;
}
</pre>
<p>Rimane un dubbio sul campo 3, che quasi sicuramente dovrebbe essere il numero di telefono abilitato alla comunicazione SMS con il tracker e sull&#8217;unità di misura utilizzata per la velocità. I cinesi della Cobanch dicono che è Km, ma sperimentalmente è facile smentirli. Sempre sperimentalmente, ho potuto verificare con accettabile precisione che si tratta di NM (miglia nautico internazionale)</p>
<p>Nella terza parte di questo articolo vedremo come avviare lo script su un server Linux facendolo funzionare in background come &#8220;demone&#8221;. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.spadamar.com/2011/11/php-un-socket-tcp-per-acquisire-dati-dal-gps-tracker-gps-102-compatibile-opengts-seconda-parte/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PHP: un socket TCP per acquisire dati dal GPS Tracker GPS-102 compatibile OpenGTS (prima parte)</title>
		<link>http://www.spadamar.com/2011/11/php-un-socket-tcp-per-acquisire-dati-dal-gps-tracker-gps-102-compatibile-opengts-prima-parte/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=php-un-socket-tcp-per-acquisire-dati-dal-gps-tracker-gps-102-compatibile-opengts-prima-parte</link>
		<comments>http://www.spadamar.com/2011/11/php-un-socket-tcp-per-acquisire-dati-dal-gps-tracker-gps-102-compatibile-opengts-prima-parte/#comments</comments>
		<pubDate>Sun, 27 Nov 2011 07:24:01 +0000</pubDate>
		<dc:creator>spadamar</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[GPS]]></category>
		<category><![CDATA[OpenGTS]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[socket]]></category>
		<category><![CDATA[tracker]]></category>

		<guid isPermaLink="false">http://www.spadamar.com/?p=328</guid>
		<description><![CDATA[Alcuni mesi fa mi è stato regalato questo questo tracker GPS per studiare come registrare su un database MySQL i dati che vengono trasmessi. L&#8217;apparecchio si chiama GPS-102 viene prodotto dalla Cobanch ed è disponibile anche in Italia ad un &#8230; <a href="http://www.spadamar.com/2011/11/php-un-socket-tcp-per-acquisire-dati-dal-gps-tracker-gps-102-compatibile-opengts-prima-parte/">Continua a leggere<span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div id="attachment_331" class="wp-caption alignleft" style="width: 310px"><a href="http://www.spadamar.com/wp-content/uploads/2011/11/IMG_8644p.jpg" rel="lightbox[328]"><img class="size-medium wp-image-331" title="tracker_GPS-102" src="http://www.spadamar.com/wp-content/uploads/2011/11/IMG_8644p-300x200.jpg" alt="Tracker GPS 102" width="300" height="200" /></a><p class="wp-caption-text">Tracker GPS 102</p></div>
<p>Alcuni mesi fa mi è stato regalato questo questo tracker GPS per studiare come registrare su un database MySQL i dati che vengono trasmessi. L&#8217;apparecchio si chiama GPS-102 viene prodotto dalla <a title="Shenzhen Coban Electronic" href="http://www.cobanch.com/" target="_blank">Cobanch</a> ed è disponibile anche in Italia ad un costo inferiore a 100€ su questo sito: <a title="www.nonsolorevenzione.it" href="http://www.nonsoloprevenzione.it/" target="_blank">www.nonsoloprevenzione.it</a></p>
<p>Poiché le informazioni della documetazione allegata sono, come spesso accade, piuttosto scarse, mi sono messo alla ricerca nel Web delle specifiche tecniche e del datagramma per la comunicazione dei dati forniti dal tracker (coordinate, velocità, ecc). Fortunatamente ho trovato <a title="GPRS-Data-Protocol" href="http://www.spadamar.com/wp-content/uploads/2011/11/GPRS-Data-Protocol.xls">questo</a> foglio di calcolo, che si riferisce ai modelli TK102, TK103 ma il protocollo risulta identico e fornisce dunque le informazioni necessarie allo sviluppo del software. <span id="more-328"></span></p>
<p>Va detto che l&#8217;apparecchio necessita di una scheda GSM (come mostrato in foto) e normalmente utilizza SMS sia per le impostazioni che per comunicare i dati relativi alla sua posizione. Se la scheda viene abilitata al traffico <a title="General Packet Radio Service" href="http://it.wikipedia.org/wiki/General_Packet_Radio_Service" target="_blank">GPRS</a>, è possibile inviare i dati sotto forma di pacchetti TCP direttamente ad un server nella rete semplicemente impostando, sempre tramite SMS, l&#8217;indirizzo IP del server e la porta di comunicazione TCP.</p>
<p>Sebbene una gran parte dei tracker in commercio utilizzino connessioni UDP, questo apparecchio utilizza il protocollo <a title="Transmission Control Protocol" href="http://it.wikipedia.org/wiki/Transmission_Control_Protocol" target="_blank">TCP</a> orientato alla connessione, che a discapito di una maggiore banda richiesta e di una modesta diminuzione delle prestazioni velocistiche, garantisce una trasmissione senza errori.</p>
<p>I dati da registrare sono principalmente:</p>
<ol>
<li>Latitudine</li>
<li>Longitudine</li>
<li>Velocità</li>
</ol>
<p>Questi sono i dati necessari per rendere su <a title="Google Maps" href="http://maps.google.it/" target="_blank">Google Maps</a>, o qualsiasi altro sistema di mappe di geolocalizzazione (p.e.: <a title="Open street map" href="http://www.openstreetmap.org/" target="_blank">OpenstreetMap</a>) il percorso fornito dal tracker. Le altre informazioni sono: il codice <a title="International Mobile Equipmment Identity" href="http://it.wikipedia.org/wiki/International_Mobile_Equipment_Identity" target="_blank">IMEI</a> (necessario per l&#8217;univoca identificazione dell&#8217;apparecchio), i codici di allarme (batteria scarica, ecc), la data e l&#8217;ora e la validità del dato.</p>
<p>Ecco l&#8217;SQL per la creazione delle due tabelle necessarie, in un DB MySQL:</p>
<pre class="brush:sql">-- DATABASE SCHEMA:
CREATE SCHEMA IF NOT EXISTS `gpsd` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;
USE `gpsd` ;
-- -----------------------------------------------------
-- Table `gpsd`.`devices`
-- -----------------------------------------------------
CREATE  TABLE IF NOT EXISTS `gpsd`.`devices` (
  `id` INT NOT NULL AUTO_INCREMENT ,
  `imeiNumber` VARCHAR(16) NOT NULL ,
  PRIMARY KEY (`id`) )
ENGINE = MyISAM;
-- -----------------------------------------------------
-- Table `gpsd`.`positions`
-- -----------------------------------------------------
CREATE  TABLE IF NOT EXISTS `gpsd`.`positions` (
  `IDpositions` INT NOT NULL AUTO_INCREMENT ,
  `msg` VARCHAR(255) NULL ,
  `timestamp` INT NOT NULL ,
  `acq_time` DATETIME NULL ,
  `track_time` TIME NULL ,
  `is_valid` TINYINT NOT NULL DEFAULT 0 ,
  `latitude` DOUBLE NULL ,
  `longitude` DOUBLE NULL ,
  `speedKPH` DOUBLE NULL ,
  `course` DOUBLE NULL DEFAULT 0 ,
  `device_id` INT NOT NULL ,
  PRIMARY KEY (`IDpositions`) )
ENGINE = MyISAM;</pre>
<p>Veniamo al codice PHP per la realizzazione del socket. Le caratteristiche sviluppate sono:</p>
<ul>
<li>Un socket in loop infinito, in ascolto sulla porta impostata</li>
<li>Un socket preposto alla comunicazione</li>
<li>Una funzione di decodifica dei dati</li>
<li>Una funzione per l&#8217;aggiornamento delle tabelle del DB</li>
<li>Una funzione per il controllo della distanza dall&#8217;ultimo punto memorizzato</li>
<li>Funzioni di servizio per la connessione al DB, l&#8217;eco dei messaggi, ecc</li>
</ul>
<p>In particolare, da una analisi preventiva dello stream TCP attraverso <a title="TCPDUMP/LIBCAP" href="http://www.tcpdump.org/" target="_blank">TCPDUMP</a> ho osservato che il tracker invia i dati secondo 2 differenti modalità:</p>
<ol>
<li>Single point: Richiede che il server risponda con un determinato messaggio, consente l&#8217;invio di particolare impostazioni come p.e. il tempo di polling.</li>
<li>Multi point: non richiede alcuna risposta, invia direttamente il datagramma.</li>
</ol>
<p>Per questo motivo ho realizzato il codice necessario a &#8220;capire&#8221; automaticamente se il client sta trasmettendo in una delle due modalità (quella multi point, l&#8217;ho chiamata &#8220;dirty&#8221;).</p>
<p>Un&#8217;altra osservazione è che quando il tracker è fermo, a causa di una relativa imprecisione del sistema GPS (i satelliti non sono immobili e non sono sempre gli stessi), le coordinate fornite differiscono leggermente. Questo, oltre a fornire un sovraccarico di dati inutili al DB, comporta come output grafico sulla mappa una nuvola indecifrabile di punti (markers). La contromisura è stata di realizzare una funzione che calcola la distanza fra le coordinate del punto appena trasmesso e quelle dell&#8217;ultimo punto registrato. Se la distanza è minore di una certa soglia (definita nei settaggi iniziali), il punto non viene registrato nel DB.</p>
<div id="attachment_360" class="wp-caption alignleft" style="width: 310px"><a href="http://www.spadamar.com/wp-content/uploads/2011/11/TrackMap.jpg" rel="lightbox[328]"><img class="size-medium wp-image-360" title="Screenshot di OpenGTS" src="http://www.spadamar.com/wp-content/uploads/2011/11/TrackMap-300x262.jpg" alt="Screenshot di OpenGTS" width="300" height="262" /></a><p class="wp-caption-text">Screenshot di OpenGTS</p></div>
<p>Un&#8217;ultima caratteristica da sottolineare è la possibilità di utilizzare il database MySQL dell&#8217;applicazione <a title="Wikipedia: Open Source" href="http://it.wikipedia.org/wiki/Open_source" target="_blank">Open Source</a>: <a title="OpenGTS" href="http://www.opengts.org/" target="_blank">OpenGTS</a>, un sistema integrato basato su Java/Tomcat che permette di visualizzare su mappe personalizzabili, i dati delle coordinate fornite da un vasto numero di tracker commerciali.</p>
<p>Nel prossimo post, fornirò l&#8217;intero sorgente dello script e la spiegazione dettagliata dei settaggi iniziali.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spadamar.com/2011/11/php-un-socket-tcp-per-acquisire-dati-dal-gps-tracker-gps-102-compatibile-opengts-prima-parte/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>P4A 3 Framework: helper per sincronizzare le tabelle sequence in MySQL</title>
		<link>http://www.spadamar.com/2010/01/p4a-3-framework-helper-per-sincronizzare-le-tabelle-sequence-in-mysql/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=p4a-3-framework-helper-per-sincronizzare-le-tabelle-sequence-in-mysql</link>
		<comments>http://www.spadamar.com/2010/01/p4a-3-framework-helper-per-sincronizzare-le-tabelle-sequence-in-mysql/#comments</comments>
		<pubDate>Sun, 31 Jan 2010 14:16:45 +0000</pubDate>
		<dc:creator>spadamar</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[p4a]]></category>
		<category><![CDATA[p4a3]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.spadamar.com/?p=323</guid>
		<description><![CDATA[Chi utilizza l&#8217;RDBMS MySQL in P4A avrà certamente notato che il framework produce in certi casi, delle tabelle il cui nome termina in &#8216;_seq&#8217;. Queste tabelle servono ad avere una compatibilità nella gestione di tutti gli RDBMS supportati (MySQL, PostgreSQL, &#8230; <a href="http://www.spadamar.com/2010/01/p4a-3-framework-helper-per-sincronizzare-le-tabelle-sequence-in-mysql/">Continua a leggere<span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.spadamar.com/wp-content/uploads/2011/06/p4a32.png" rel="lightbox[323]"><img src="http://www.spadamar.com/wp-content/uploads/2011/06/p4a32.png" alt="P4A 3 Logo" title="p4a3" width="350" height="130" class="alignleft size-full wp-image-324" /></a>Chi utilizza l&#8217;<a href="http://it.wikipedia.org/wiki/Relational_database_management_system" target="_blank" title="Wikipedia: Relational database management system">RDBMS</a> <a href="http://www.mysql.it/" target="_blank" title="MySQL">MySQL</a> in P4A avrà certamente notato che il framework produce in certi casi, delle tabelle il cui nome termina in &#8216;_seq&#8217;. Queste tabelle servono ad avere una compatibilità nella gestione di tutti gli RDBMS supportati (MySQL, <a href="http://www.postgresql.org/" target="_blank" title="PostgreSQL">PostgreSQL</a>, <a href="http://www.sqlite.org/" target="_blank" title="SQLite">SQLite</a>, <a href="http://www.oracle.com/global/it/index.html" target="_blank" title="Oracle">Oracle</a>). PostgreSQL e Oracle, non hanno lo stesso tipo di gestione delle chiavi primarie con l&#8217;attributo &#8216;<a href="http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html" target="_blank" title="MySQL autoincrement">AUTOINCREMENT</a>&#8216;, rispetto a MySQL e SQLite. La soluzione adottata è di costruire, per ogni tabella con chiave primaria di tipo &#8216;AUTOINCREMENT&#8217;, delle tabelle accessorie che hanno un campo &#8216;id&#8217; di tipo &#8216;AUTOINCREMENT&#8217; e di riferirsi a quest&#8217;ultime per ottenre il &#8216;<a href="http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html" target="_blank" title="MySQL: LAST INSERT ID()">LAST INSERT ID</a>&#8216;. In questo modo viene ricalcato il comportamento delle chiavi primarie di tipo &#8216;SERIAL&#8217; in PostgreSQL, e anche quelle di Oracle (leggermente diverse).</p>
<p>Prima di tutto una precisazione: questo articolo è riferito esclusivamente agli utenti MySQL.<br /> Se si pensa di utilizzare esclusivamente P4A Framework per la gestione dei dati del nostro database, sarebbe bene in fase di progettazione evitare di usare gli AUTOINCREMENT perché, come detto, non necessari. Nel caso in cui il framework venga utilizzato come &#8216;backoffice&#8217; per la gestione di dati che vengono alimentati da un form di un sito web, oppure si abbia la necessità di utilizzare una struttura dati pre-esistente con tanto di chiavi primarie &#8216;AUTOINCREMENT&#8217;, potremmo prima o poi trovarci di fronte ad un problema di disallineamento dei valori fra la chiave primaria della tabella e l&#8217;id&#8217; della tabella &#8216;_seq&#8217; associata.</p>
<p>Immaginiamo di avere una tabella &#8220;<em>test</em>&#8221; con questi due campi:</p>
<pre>+----+---------+
| id | name    |
+----+---------+
</pre>
<p>
con &#8216;id&#8217; chiave primaria, P4A creerà automaticamente una tabella &#8220;<em>test_id_seq</em>&#8221; con una campo &#8216;id&#8217; chiave primaria e &#8216;AUTOINCREMENT&#8217;, ed userà i valori forniti da quest&#8217;ultima sia per l&#8217;inserimento di nuovi record nella tabella &#8220;<em>test</em>&#8220;, che per altre operazioni sulla chiave primaria. Dunque utilizzando un programma esterno al framework per fare degli inserimenti e volendo mantenere allineate le tabelle principali e le tabelle &#8220;_seq&#8221; sarà necessario, per ogni &#8220;INSERT&#8221; nella tabella principale, fare altrettanto nella &#8220;_seq&#8221;!<br />Anche utilizzando questo metodo, potrebbe verificarsi prima o poi il problema di un disallineamento, in questo caso ho pensato potesse utile scrivere un metodo della classe &#8220;P4A_DB_SOURCE&#8221; da utilizzare <em>in extremis</em>, per risistemare le cose.</p>
<p>Per maggiori informazioni sull&#8217;utilizzo degli &#8216;helper&#8217; in P4A suggerisco questo <a href="http://p4a.crealabsfoundation.org/wiki/Helpers" target="_blank" title="P4A - PHP For Applications Wiki - Helpers">link</a>
</p>
<p>Ecco il codice dell&#8217;helper, in pratica viene prelevato il valore massimo della chiave primaria &#8216;AUTOINCREMENT&#8217; della tabella che funge da sorgente dati, quindi viene eliminata la tabella &#8216;_seq&#8217; associata e successivamente ricostruita con il valore corretto.</p>
<pre class="brush:php"> function p4a_db_source_resync_seq($source)

 {
	$table = $source-&gt;getTable();
	$pKField = $source-&gt;getPk();
	$seqTable =  $table."_".$pKField."_seq";
	$lastId = P4A_DB::singleton()-&gt;fetchOne("SELECT MAX($pKField) FROM $table");
	$query = "DROP TABLE IF EXISTS `$seqTable`";
	$resQ1 = P4A_DB::singleton()-&gt;query($query);
	$query = "CREATE TABLE `$seqTable` (
	`id` int(11) NOT NULL auto_increment,
	PRIMARY KEY  (`id`)
	) TYPE=MyISAM AUTO_INCREMENT=$lastId";

	$resQ2 = P4A_DB::singleton()-&gt;query($query);
	$query = "INSERT INTO `$seqTable` VALUES ($lastId)";
	$resQ3 = P4A_DB::singleton()-&gt;query($query);
  return ($resQ1 &amp;&amp; $resQ2 &amp;&amp; $resQ3); 

 }
</pre>
<p>Questo codice deve essere inserito in un file con il nome: &#8220;<em>p4a_db_source_resync_seq.php</em>&#8221; che deve essere posizionato nella directory &#8220;libraries&#8221; della nostra applicazione P4A.</p>
<p>Ecco infine un po&#8217; di codice di esempio da aggiungere alla nostra ipotetica maschera di manutenzione del db:</p>
<pre class="brush:php">class test extends P4A_Base_Mask

{

	public function __construct()

	{

		parent::__construct();

		// DB Source

		$this-&gt;build("p4a_db_source", "source")

			-&gt;setTable("test")
			-&gt;setPk("id")
			-&gt;load();
		$this-&gt;setSource($this-&gt;source);

		// ....

	    $this-&gt;build("p4a_button", "btn_resync")

			-&gt;setLabel("resync")

			-&gt;implement("onclick", $this, "resync_seq_table");

		// ....
	}

	public function resync_seq_table()
	{
		$res = $this-&gt;source-&gt;resync_seq();
	}

	// ....
}
</pre>
<p>Conclusioni</p>
<p>Questo metodo dovrebbe essere usato con una certa cautela, e solo come procedura di emergenza. Non consiglio l&#8217;utilizzo se c&#8217;è la possibilità di accesso in scrittura alla tabella coinvolta da parte di altri utenti.</p>
<p>Riferimenti ed approfondimenti:</p>
<ul>
<li><a href="http://p4a.crealabsfoundation.org/" target="_blank" title="P4A - PHP For Applications - PHP RAD Framework">P4A &#8211; PHP For Applications &#8211; PHP RAD Framework</a></li>
<li><a href="http://p4a.crealabsfoundation.org/wiki/Helpers" target="_blank" title="P4A - PHP For Applications Wiki - Helpers">P4A &#8211; PHP For Applications Wiki &#8211; Helpers</a></li>
<li><a href="http://p4a.crealabsfoundation.org/code-reference/li_p4a_helpers.html" target="_blank" title="Documentazione: p4a_helpers">Documentazione: p4a_helpers</a></li>
<li><a href="http://sourceforge.net/projects/p4a/forums/forum/340765/topic/3428594" target="_blank" title="P4A forum: disable the auto increment">P4A forum: disable the auto increment</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.spadamar.com/2010/01/p4a-3-framework-helper-per-sincronizzare-le-tabelle-sequence-in-mysql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenOffice Calc: come creare una funzione che genera password random</title>
		<link>http://www.spadamar.com/2009/11/openoffice-calc-come-creare-una-funzione-che-genera-password-random/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=openoffice-calc-come-creare-una-funzione-che-genera-password-random</link>
		<comments>http://www.spadamar.com/2009/11/openoffice-calc-come-creare-una-funzione-che-genera-password-random/#comments</comments>
		<pubDate>Mon, 23 Nov 2009 14:07:19 +0000</pubDate>
		<dc:creator>spadamar</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[Calc]]></category>
		<category><![CDATA[OpenOffice]]></category>
		<category><![CDATA[password]]></category>

		<guid isPermaLink="false">http://www.spadamar.com/?p=319</guid>
		<description><![CDATA[Vi è mai capitato di dover generare una lunga serie di password random da inserire in un database? Esistono diversi generatori, anche piuttosto sofisticati e flessibili nelle regole, ma normalmente generano una password alla volta. Ne ho trovati alcuni, che &#8230; <a href="http://www.spadamar.com/2009/11/openoffice-calc-come-creare-una-funzione-che-genera-password-random/">Continua a leggere<span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.spadamar.com/wp-content/uploads/2011/06/OOoCalc.png" rel="lightbox[319]"><img src="http://www.spadamar.com/wp-content/uploads/2011/06/OOoCalc.png" alt="Logo della OpenOffice Calc" title="OOoCalc" width="126" height="124" class="alignleft size-full wp-image-320" /></a>
<p>
Vi è mai capitato di dover generare una lunga serie di password random da inserire in un database? Esistono diversi generatori, anche piuttosto sofisticati e flessibili nelle regole, ma normalmente generano una password alla volta. Ne ho trovati alcuni, che nelle versioni freeware, generano un massimo di 100 password. Ma se abbiamo la necessità di generarne 10000 o più?</p>
<p>Ho pensato di creare una formula per <a href="http://it.openoffice.org/informazioni/prodotto/calc.html" target="_blank" title="OpenOffice Calc in italiano">OpenOffice Calc</a>, che possa generare una stringa alfanumerica rispettando certi requisiti di casualità, lunghezza e robustezza.</p>
<p>Il codice che genera la password è tratto da <a href="http://www.webtoolkit.info/php-random-password-generator.html" target="_blank" title="PHP random password generator">questo articolo</a>, e tradotto in linguaggio Basic per OO.</p>
<p>E&#8217; possibile stabilire la lunghezza della password e la robustezza. Quest&#8217;ultima viene definita da un valore minimo di 0 fin ad un massimo di 8</p>
<ul>
<li>Robustezza = 0, solo consonanti e vocali minuscole </li>
<li>Robustezza = 1, consonanti minuscole e maiuscole e vocali minuscole </li>
<li>Robustezza = 2, consonanti minuscole e maiuscole e vocali minuscole e maiuscole</li>
<li>Robustezza = 4, consonanti minuscole e maiuscole, numeri e vocali minuscole e maiuscole</li>
<li>Robustezza = 8, consonanti minuscole e maiuscole, numeri, caratteri speciali e vocali minuscole e maiuscole</li>
</ul>
<p>Per la compilazione e l&#8217;esecuzione della macro in OpenOffice Calc, ho seguito scrupolosamente le indicazioni di <a href="http://wiki.services.openoffice.org/wiki/Documentation/OOo3_User_Guides/Calc_Guide/Write_your_own_functions" target="_blank" title="Write your own functions">questo post</a> sul sito Wiki di OpenOffice.<br />In pratica si tratta di creare una nuova macro associata ad un foglio di calcolo &#8220;Calc&#8221;, utilizzando:</p>
<p><code>Strumenti &gt; Macro &gt; Organizza Macro &gt; OpenOffice.org Basic</code></p>
<p>Qunidi cliccando sul bottone &#8220;Gestisci&#8221; e sul tab &#8220;Libreria&#8221;, è possibile creare una nuova libreria associata al foglio di calcolo, nel nostro caso in <strong>calcTestMacros.ods</strong> creo (con poca fantasia&#8230;) la libreria: <strong>AuthorsCalcMacros</strong>.</p>
<p>Utilizzando il bottone &#8220;Modifica&#8221; si apre un <a href="http://it.wikipedia.org/wiki/Integrated_development_environment" target="_blank" title="Wikipedia: Integrated development environment">IDE</a> per poter scrivere, con l&#8217;aiuto del <a href="http://it.wikipedia.org/wiki/Syntax_highlighting" target="_blank" title="Wikipedia: Syntax highlighting">Syntax highlighting</a>, il codice della macro in linguaggio Basic.<br />La macro in realtà corrisponde all&#8217;implementazione, ma non è la funzione che richiameremo all&#8217;interno delle celle del foglio di lavoro. Il motivo è da imputarsi al fatto che, a parte la libreria di default denominata &#8220;Standard&#8221;, tutte le altre non vengono automaticamente caricate all&#8217;avvio, dunque si rende necessario creare una funzione che potremmo chiamare &#8220;prototipo&#8221; nella libreria &#8220;Standard&#8221;, che a sua volta richiama l&#8217;implementazione vera e propria. </p>
<p>Questo è il codice della implementazione inserito nella libreria &#8220;AuthorsCalcMacros&#8221;:</p>
<pre class="brush:vb">Function Passwdgen_implementation(ByVal length AS Integer, ByVal strength As Integer)
	Dim vowels As string
	Dim consonants As string
	Dim password As string
	Dim alt As Integer
	Dim i As Integer

	vowels = "aeuy"
	consonants = "bdghjmnpqrstvz"
	If (strength &gt;= 1) Then
		consonants = consonants + "BDGHJLMNPQRSTVWXZ"
	End If
	If (strength &gt;= 2) Then
		vowels = vowels + "AEUY"
	End If
	If (strength &gt;= 4) Then
		consonants = consonants + "23456789"
	End If
	If (strength &gt;= 8) Then
		consonants = consonants + "@#$%"
	End If
	password = ""
	Randomize()
	alt = Int((2 * Rnd) + 1)
	For i = 0 To length-1
		If (alt = 2) Then
			password = password + Mid(consonants, Int((Len(consonants) * Rnd) + 1), 1)
			alt = 1
		Else
			password = password + Mid(vowels, Int((Len(vowels) * Rnd) + 1), 1)
			alt = 2
		End If
	Next i
	Passwdgen_implementation = password
End Function
</pre>
<p>Questo è il codice del &#8220;prototipo&#8221; inserito nella libreria &#8220;Standard&#8221;:</p>
<pre class="brush:vb">Function Passwdgen(ByVal l as Integer, ByVal s as Integer)
  If NOT BasicLibraries.isLibraryLoaded("AuthorsCalcMacros") Then
    BasicLibraries.LoadLibrary("AuthorsCalcMacros")
  End If
  Passwdgen = Passwdgen_Implementation(l, s)
End Function
</pre>
<p>Ed ecco infine il risultato della funzione nel foglio di calcolo:</p>
<p><img class="normale" src="http://www.spadamar.com/files/oo/calcDump.png" alt="screenshot del foglio di calcolo: calcTestMacros.ods" /></p>
<p>Per permettere l&#8217;esecuzione delle macro, è necessario impostare il livello di sicurezza su &#8220;Medio&#8221;<br />
Questo parametro si imposta da:</p>
<p><code>Strumenti &gt; Opzioni</code></p>
<p>Selezionare: &#8220;Sicurezza, quindi premere il bottone &#8220;Sicurezza delle macro&#8230;&#8221;</p>
<p>Aprendo il documento, ovviamente è necessario abilitare le macro, come mostrato nella figura qui sotto:</p>
<p><img class="normale" src="http://www.spadamar.com/files/oo/abilitaMacro.png" alt="screenshot della finestra di dialogo abilita macro" /></p>
<p>Download:</p>
<p>Il documento ods che contiene la macro è disponibile <a href="http://www.spadamar.com/files/oo/calcTestMacros.ods" title="Scarica il file calcTestMacros.ods">qui</a></p>
<p>Riferimenti e Links:</p>
<ul>
<li><a href="http://wiki.services.openoffice.org/wiki/Documentation/OOo3_User_Guides/Calc_Guide/Write_your_own_functions" target="_blank" title="OpenOffice.org Wiki: Write your own functions">OpenOffice.org Wiki: Write your own functions (in inglese)</a></li>
<li><a href="http://wiki.services.openoffice.org/wiki/Documentation/OOo3_User_Guides/Calc_Guide/Using_a_macro_as_a_function" target="_blank" title="OpenOffice.org Wiki: Using a macro as a function">OpenOffice.org Wiki: Using a macro as a function (in inglese)</a></li>
<li><a href="http://wiki.services.openoffice.org/wiki/Documentation/BASIC_Guide" target="_blank" title="OpenOffice.org Wiki: OpenOffice.org BASIC Programming Guide">OpenOffice.org Wiki: OpenOffice.org BASIC Programming Guide (in inglese)</a></li>
<li><a href="http://www.webtoolkit.info/php-random-password-generator.html" target="_blank" title="PHP random password generator">PHP random password generator (in inglese)</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.spadamar.com/2009/11/openoffice-calc-come-creare-una-funzione-che-genera-password-random/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Il famoso problema di Einstein</title>
		<link>http://www.spadamar.com/2009/09/il-famoso-problema-di-einstein/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=il-famoso-problema-di-einstein</link>
		<comments>http://www.spadamar.com/2009/09/il-famoso-problema-di-einstein/#comments</comments>
		<pubDate>Wed, 23 Sep 2009 13:59:39 +0000</pubDate>
		<dc:creator>spadamar</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[Einstein]]></category>
		<category><![CDATA[logica]]></category>

		<guid isPermaLink="false">http://www.spadamar.com/?p=315</guid>
		<description><![CDATA[Albert Einstein, probabilmente il più grande fisico del XX secolo, è anche riconosciuto come l&#8217;icona dell&#8217;intelligenza. Non si direbbe dall&#8217;espressione che assume nella famosa foto del 1951 scattata dal fotografo Arthur Sasse! In questo mini post, vi propongo il famoso &#8230; <a href="http://www.spadamar.com/2009/09/il-famoso-problema-di-einstein/">Continua a leggere<span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div id="attachment_316" class="wp-caption alignleft" style="width: 326px"><a href="http://www.spadamar.com/wp-content/uploads/2011/06/albert-einstein-1951.jpg" rel="lightbox[315]"><img src="http://www.spadamar.com/wp-content/uploads/2011/06/albert-einstein-1951.jpg" alt="albert einstein 1951, foto di Arthur Sasse, nital.it" title="albert-einstein-1951" width="316" height="400" class="size-full wp-image-316" /></a><p class="wp-caption-text">albert einstein 1951, foto di Arthur Sasse, nital.it</p></div>
<p><a href="http://it.wikipedia.org/wiki/Albert_Einstein" target="_blank" title="Wikipedia: Albert Einstein">Albert Einstein</a>, probabilmente il più grande fisico del XX secolo, è anche riconosciuto come l&#8217;icona dell&#8217;intelligenza. Non si direbbe dall&#8217;espressione che assume nella famosa foto del 1951 scattata dal fotografo Arthur Sasse!</p>
<p>In questo mini post, vi propongo il famoso problema di Einstein: si tratta di un enigma da risolvere mediante la logica, rispettando le 15 condizioni imposte. </p>
<p>Ho preparato uno script PHP con un form e una tabella per formalizzare il problema e trovare la soluzione (o le soluzioni&#8230;), <strong>al termine, vi verrà&nbsp; comunicato se avete indovinato o no</strong> (<em>mi raccomando, non andate subito a guardare la soluzione nei link qui sotto!!</em>). Dimenticavo, un&#8217;ultima cosa: Einstein disse che il <b>98%</b> della popolazione <b>non</b> sarebbe riuscita a risolverlo, la sfida è lanciata&#8230; </p>
<p><a href="http://www.spadamar.com/files/einstein/problema.php" title="Problema di Einstein: CHI POSSIEDE IL PESCE?">Problema di Einstein: chi ha il pesce?</a></p>
<p>Referenza immagine</p>
<p><em>Fotografo</em>: Arthur Sasse, Bettmann/CORBIS, <em>Fonte</em>: nital.it</p>
<p>&nbsp;</p>
<p>Soluzione e links:</p>
<ul>
<li><a href="http://digilander.libero.it/basecinque/logica/einstein.htm" target="_blank" title="BASE Cinque - Appunti di Matematica ricreativa">BASE Cinque &#8211; Appunti di Matematica ricreativa</a></li>
<li><a href="http://lanostramatematica.splinder.com/post/13464427" target="_blank" title="Who has the fish? Un problema di Albert Einstein">Who has the fish? Un problema di Albert Einstein</a></li>
<li><a href="http://www.amazeingart.com/fun/einstein-quiz-answer.html" target="_blank" title="The Real Solution to the Einstein Quiz">The Real Solution to the Einstein Quiz (in inglese)</a></li>
<li><a href="http://www.stanford.edu/%7Elaurik/fsmbook/examples/Einstein%27sPuzzle.html" target="_blank" title="Einstein's Puzzle">Einstein&#8217;s Puzzle (in inglese)</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.spadamar.com/2009/09/il-famoso-problema-di-einstein/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ANSI C: Test di numeri primi con la Wheel Factorization</title>
		<link>http://www.spadamar.com/2009/09/ansi-c-test-di-numeri-primi-con-la-wheel-factorization/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=ansi-c-test-di-numeri-primi-con-la-wheel-factorization</link>
		<comments>http://www.spadamar.com/2009/09/ansi-c-test-di-numeri-primi-con-la-wheel-factorization/#comments</comments>
		<pubDate>Sun, 20 Sep 2009 13:46:05 +0000</pubDate>
		<dc:creator>spadamar</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[ANSI C]]></category>
		<category><![CDATA[C/C++]]></category>
		<category><![CDATA[numeri primi]]></category>

		<guid isPermaLink="false">http://www.spadamar.com/?p=308</guid>
		<description><![CDATA[Cosa sono i numeri primi e perché tanto interesse intorno a loro? Un numero n &#62; 0 si definisce primo se è divisibile solo per 1 e per sé stesso con resto 0. L&#8217;interesse è dovuto a due motivi, principalmente: &#8230; <a href="http://www.spadamar.com/2009/09/ansi-c-test-di-numeri-primi-con-la-wheel-factorization/">Continua a leggere<span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.spadamar.com/wp-content/uploads/2011/06/eratostene.gif" rel="lightbox[308]"><img src="http://www.spadamar.com/wp-content/uploads/2011/06/eratostene.gif" alt="Crivello di eratostene: animazione" title="eratostene" width="377" height="377" class="alignleft size-full wp-image-309" /></a>Cosa sono i numeri primi e perché tanto interesse intorno a loro? Un numero n &gt; 0 si definisce primo se è divisibile solo per 1 e per sé stesso con resto 0. L&#8217;interesse è dovuto a due motivi, principalmente:
<p>1) I numeri primi sono le basi di tutta l&#8217;aritmetica come si può evincere dal Teorema Fondamentale della matematica che recita:<em>&#8220;Ogni intero si fattorizza in modo unico come prodotto di numeri primi&#8221;</em> e questo li rende indubbiamente affascinanti.<br />2) I numeri primi molto grandi (ordine di 2<sup>1024</sup>), sono alla base del più utilizzato sistema di crittografia: l&#8217;<a href="http://it.wikipedia.org/wiki/RSA" target="_blank" title="Wikipedia: RSA">RSA</a> questo invece, attira molto gli esperti in sicurezza informatica&#8230;!</p>
<p><strong>Come si trovano i numeri primi?</strong></p>
<p>Fu <a href="http://it.wikipedia.org/wiki/Eratostene" target="_blank" title="Wikipedia: Eratostene">Eratostene</a> di Cirene (276 &#8211; 194 a.c.), il primo a proporre un metodo per &#8220;setacciare&#8221; i numeri primi, detto appunto: <a href="http://it.wikipedia.org/wiki/Crivello_di_Eratostene" target="_blank" title="Wikipedia: Crivello di Eratostene">crivello di Eratostene</a>. Esistono diversi algoritmi che risolvono il crivello di Eratostene, questo che propongo mi sembra il più efficiente. Supponiamo dunque di voler trovare tutti i numeri primi da 1 a <em>n</em>, l&#8217;algoritmo in pseudocodice è il seguente:</p>
<p><code><br />
for i := 2 to n-1 do<br />
&nbsp;a[i] := 1<br />
for i := 2 to n-1 do<br />
&nbsp;if a[i]<br />
&nbsp;&nbsp;for j := i to (j*i)&lt;n do<br />
&nbsp;&nbsp;&nbsp;a[i*j] := 0<br />
for i := 2 to n-1 do<br />
&nbsp;if a[i]<br />
&nbsp;&nbsp;print i<br />
</code></p>
<p>In pratica si procede da <em>i</em>=2 a <em>n</em>, eliminando tutti i multipli di <em>i</em><br />
<em>(nella immagine in alto a sinistra è possibile vedere un&#8217;animazione del processo)</em>. Va detto che ancora oggi, pur non essendo l&#8217;algoritmo più efficiente in assoluto, è molto utilizzato quando si lavora su numeri relativamente piccoli, per la sua estrema semplicità.</p>
<p><strong>Il metodo della ruota di fattorizzazione</strong> (<a href="http://en.wikipedia.org/wiki/Wheel_factorization" target="_blank" title="Wikipedia: Wheel Factorization (in inglese)">Wheel Factorization</a>)</p>
<p>Già il crivello di Eratostene permette un notevole incremento di prestazioni rispetto ad un processo di &#8220;forza bruta&#8221; specialmente se l&#8217;algoritmo è opportunamente ottimizzato. Il metodo della ruota risulta ancora più efficiente, e vediamo il perché:<br />Si scelgono inizialmente come numeri primi di partenza: 2, 3, 5 per ottenere una ruota di lunghezza 30. La lunghezza della ruota è determinta dal prodotto dei numeri primi che decidiamo di utilizzare. Nel nostro caso 2 * 3 * 5 = 30. A questo punto troviamo tutti gli interi che non sono multipli di 2, 3 e 5, il vettore risultate sarà: <code>s[] = {1, 7, 11, 13, 17, 19, 23, 29 }</code>. Abbiamo ottenuto un insieme di numeri che, non sono multipli di 2, 3, 5 e anche se sommati alla lunghezza della ruota o ai suoi multipli (30, 60, 90, ecc), non daranno mai multipli di 2, 3, 5.<br />Il concetto è più chiaro osservando la figura sotto, le colonne gialle della tabella contengono i soli numeri che andremo a testare, i rimanenenti non sono sicuramente primi, esclusi i numeri di partenza (2, 3, 5). Se provassimo a visualizzare ciascuna riga della tabella come una circonferenza, potremmo immaginare la tabella come una ruota in cui le colonne gialle rappresentano i raggi dove cercare i numeri primi.</p>
<div id="attachment_310" class="wp-caption alignleft" style="width: 310px"><a href="http://www.spadamar.com/wp-content/uploads/2011/06/wheelFactorTable.png" rel="lightbox[308]"><img src="http://www.spadamar.com/wp-content/uploads/2011/06/wheelFactorTable-300x81.png" alt="Tabella di fattorizzazione" title="wheelFactorTable" width="300" height="81" class="size-medium wp-image-310" /></a><p class="wp-caption-text">Tabella di fattorizzazione</p></div>
<p>Il codice è tratto dall&#8217;articolo: &#8220;<a href="http://www.codeproject.com/KB/recipes/PrimeSuspect.aspx" target="_blank" title="Prime Number Determination Using Wheel Factorization">Prime Number Determination Using Wheel Factorization</a>&#8221; di <a href="http://www.codeproject.com/script/Articles/MemberArticles.aspx?amid=5220711" target="_blank" title="rickoshay">rickoshay</a> originariamente scritto in C#, e da me convertito in ANSI C</p>
<p><br style='clear:both' /></p>
<pre class="brush:c">#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

unsigned long FirstDivisor(unsigned long candidatePrime);
int isPrime(unsigned long primeSuspect);

unsigned long FirstDivisor(unsigned long candidatePrime)
{
 const int wheelFactor = 30;
 int aSieve30[] = {7, 11, 13, 17, 19, 23, 29, 31};
 int firstPrimes[] = {2, 3, 5}, i;
 unsigned long sqrtmax, pass;

 if (candidatePrime == 1)
 {
    return 0;
 }
 for (i=0;i&lt;sizeof(firstPrimes)/sizeof(int);i++) {
     if (candidatePrime % firstPrimes[i] == 0) {
        return firstPrimes[i];
     }
 }

 sqrtmax  = (unsigned long) sqrt(candidatePrime);
 for (pass=0; pass&lt;sqrtmax; pass+=wheelFactor) {
  for (i=0;i&lt;sizeof(aSieve30)/sizeof(int);i++) {
      if (candidatePrime % (pass + aSieve30[i]) == 0) {
         return pass + aSieve30[i];
      }
  }
 }
 return candidatePrime;
}

int isPrime(unsigned long primeSuspect)
{
   if (primeSuspect == 0) {
      return 0;
   }
   if (FirstDivisor(primeSuspect) == primeSuspect) {
      return 1;
   }
   else {
      return 0;
   }
}

int main(int argc, char *argv[])
{
  unsigned long x, i;

  if (argc == 2) {
     x = strtoul(argv[1],NULL,10);
     if (isPrime(x)) {
        printf("%u e' un numero primo\n",x);
     }
     else {
        printf("%u non e' un numero primo\n",x);
     }
  }
  else {
   printf ("\nUsage: %s n \nWhere n is an integer number to check for primality\n",argv[0]);
  }
  system("PAUSE");
  return 0;
}
</pre>
<p>Download</p>
<p>Il download dell&#8217;applicazione (compilata per Win32) è disponibile <a href="http://www.spadamar.com/files/numeri_primi/isPrime.zip" target="_blank" title="Download della classe TartFibo">qui</a>, in formato compresso zip. Sono compresi i sorgenti e i files di progetto per il compilatore <a href="http://www.bloodshed.net/" target="_blank" title="Bloodshed Software">DevC++</a> (ver.: 4.9.9.2). Per l&#8217;utilizzo è sufficiente lanciare il programma da una console DOS e passare come parametro il numero da testare.</p>
<p>Conclusioni:</p>
<p>Adottare il metodo della Wheel Factorization per testare la primalità di un numero, consente un incremento di performance pari a (1 &#8211; 8 /30) * 100 = 73% con una ruota di dimensioni 30. Le prestazioni possono crescere aumentando le dimensioni della ruota, specialmente quando si ragiona con numeri abbastanza grandi. Il codice proposto utilizza al massimo numeri di 4 byte (unsigned long int = 4,294,967,295) e le performance rimangono accettabili ricompilando per numeri di 8 byte (unsigned long long = 18,446,744,073,709,551,615). In questo caso però sarebbe consigliabile utilizzare una ruota prodotta dai primi 8 numeri primi, come suggerito nell&#8217;articolo da cui ho tratto lo spunto per il codice.</p>
<p>Riferimenti ed approfondimenti:</p>
<ul>
<li><a href="http://it.wikipedia.org/wiki/Numero_primo" target="_blank" title="Wikipedia: Numero primo">Wikipedia: Numero primo</a></li>
<li><a href="http://www.codeproject.com/KB/recipes/PrimeSuspect.aspx" target="_blank" title="Prime Number Determination Using Wheel Factorization">Prime Number Determination Using Wheel Factorization (in inglese)</a></li>
<li><a href="http://www.math.unipd.it/%7Elanguasc/lavoripdf/R8it.pdf" target="_blank" title="A Languasco e A. Perelli: Numeri primi e crittografia">A Languasco e A. Perelli: Numeri primi e crittografia (pdf)</a></li>
<li><a href="http://web.math.unifi.it/users/dolcetti/crivello.pdf" target="_blank" title="Il Crivello di Eratostene">Il Crivello di Eratostene (pdf)</a></li>
<li><a href="http://www.troubleshooters.com/codecorn/primenumbers/primenumbers.htm" target="_blank" title="Fun With Prime Numbers">Fun With Prime Numbers (in inglese)</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.spadamar.com/2009/09/ansi-c-test-di-numeri-primi-con-la-wheel-factorization/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP: Quando Tartaglia e Fibonacci si davano la mano</title>
		<link>http://www.spadamar.com/2009/09/php-quando-tartaglia-e-fibonacci-si-davano-la-mano/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=php-quando-tartaglia-e-fibonacci-si-davano-la-mano</link>
		<comments>http://www.spadamar.com/2009/09/php-quando-tartaglia-e-fibonacci-si-davano-la-mano/#comments</comments>
		<pubDate>Tue, 01 Sep 2009 13:34:32 +0000</pubDate>
		<dc:creator>spadamar</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[matematica]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.spadamar.com/?p=304</guid>
		<description><![CDATA[Di certo, in vita i due non si sarebbero mai potuti dare la mano, essendo vissuti in epoche distanti ben tre secoli. Fibonacci, al secolo Leonardo Pisano, visse infatti a cavallo del 1200 ed era di famiglia benestante essendo il &#8230; <a href="http://www.spadamar.com/2009/09/php-quando-tartaglia-e-fibonacci-si-davano-la-mano/">Continua a leggere<span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.spadamar.com/wp-content/uploads/2011/06/tartefibo.png" rel="lightbox[304]"><img src="http://www.spadamar.com/wp-content/uploads/2011/06/tartefibo.png" alt="Tartaglia e Fibonacci" title="tartefibo" width="350" height="212" class="alignleft size-full wp-image-305" /></a>Di certo, in vita i due non si sarebbero mai potuti dare la mano, essendo vissuti in epoche distanti ben tre secoli. <a href="http://it.wikipedia.org/wiki/Leonardo_Fibonacci" target="_blank" title="Wikipedia: Leonardo Fibonacci">Fibonacci</a>, al secolo Leonardo Pisano, visse infatti a cavallo del 1200 ed era di famiglia benestante essendo il padre (Bonaccio, da qui il nome FiBonacci) il segretario della Repubblica di Pisa e responsabile del commercio con l&#8217;Africa. Fu proprio in Africa che ebbe modo di studiare le avanzate tecniche matematiche, al tempo in possesso del mondo arabo.<br /><a href="http://it.wikipedia.org/wiki/Niccol%C3%B2_Tartaglia" target="_blank" title="Wikipedia: Niccolò Tartaglia">Tartaglia</a>, al secolo Niccolò Fontana visse a cavallo del 1500 fra Brescia e Verona. Era di famiglia tutt&#8217;altro che ricca, e rimase orfano di padre quando era ancora molto giovane. Ebbe anche la disgrazia di rimanere sfregiato durante il sacco di Brescia del 1512 ad opera dell&#8217;esercito francese. A leggere il suo stesso racconto c&#8217;è da stupirsi di come sia riuscito a sopravvivere a ferite così gravi. Rimase diversi giorni senza poter parlare e mangiare cibi solidi proprio a causa dei colpi di spada inferti sulla sua testa, e quando guarì non riuscì più a parlare senza balbettare, da questo il suo soprannome Tartaglia con il quale divenne famoso.</p>
<p><strong>Il triangolo di Tartaglia</strong></p>
<p>Tutti noi ricordiamo, dai tempi delle superiori, la piramide di numeri che compongono il famoso triangolo di Tartaglia, e lo ricordiamo soprattutto in relazione allo studio delle <a href="http://it.wikipedia.org/wiki/Teorema_binomiale" target="_blank" title="Wikipedia: Teorema binomiale">potenze di un binomio</a>.</p>
<p><img class="normale" src="http://www.spadamar.com/files/tarta_fibo/triangolo.png" alt="Triangolo di Tartaglia" />
<p>Ogni riga, riporta i coefficienti dell&#8217;espansione del binomio con esponente uguale al numero di riga &#8211; 1 (<em>iniziando a contare dal vertice della piramide</em>) Così ad esempio, per esponente 3 avremo:<br />(<em>a</em> + <em>b</em>)<sup>3</sup> =  <strong>1</strong><em>a</em><sup>3</sup> + <strong>3</strong><em>a</em><sup>2</sup><em>b</em> + <strong>3</strong><em>a</em><em>b</em><sup>2</sup> + <strong>1</strong><em>b</em><sup>3</sup></p>
<p><strong>La successione di Fibonacci</strong></p>
<p>La successione dei numeri di Fibonacci è nota soprattutto per la particolarità che il rapporto tra un numero e quello precedente, man mano che si procede nella successione, tende alla <a href="http://it.wikipedia.org/wiki/Sezione_aurea" target="_blank" title="Wikipedia: Sezione Aurea">sezione aurea</a> La successione fu trovata da Fibonacci, rispondendo al quesito: &#8220;Supponiamo di avere una coppia di conigli, che dopo un mese è in grado di generare una seconda coppia di conigli, quante coppie avremo in un anno?&#8221; (<em>Ammesso che ogni coppia generi sempre e solo una coppia al mese e nessuno muoia&#8230;</em>). Il procedimento è molto semplice: ogni numero, ad eccezione dei primi due (1, 1), è la somma dei due che lo precedono. Quindi:<br />F(12) = <code>1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144</code> </p>
<p><strong>Dove si incontrano Tartaglia e Fibonacci?</strong></p>
<p>Per capire il punto di contatto fra i due, è necessario modificare la forma del triangolo di Tartaglia, disponendo i numeri nelle celle che costituiscono un triangolo rettangolo piuttosto che isoscele, in questo modo:</p>
<p><img class="normale" src="http://www.spadamar.com/files/tarta_fibo/triangolor.png" alt="Triangolo di Tartaglia" />
<p>I numeri che costituiscono le diagonali ascendenti di questa matrice triangolare, sommati fra loro, generano la successione di Fibonacci.</p>
<p>Ecco dunque una classe PHP che calcola i valori del triangolo di Tartaglia e poi estrae dalle diagonali ascendenti i numeri della successione di Fibonacci.</p>
<pre class="brush:php">class tartfibo
{
  var $tartaglia;
  var $fibonacci;
  var $max;

  function tartfibo($max=10)
  {
    $this-&gt;max = $max;
    $this-&gt;tartaglia = array();
    $this-&gt;fibonacci = array();
    $this-&gt;makeTartaglia();
    $this-&gt;makeFibonacci();
  }

  function makeTartaglia ()
  {
    $this-&gt;tartaglia[1][1] = 1;
    $this-&gt;tartaglia[2][1] = 1;
    $this-&gt;tartaglia[2][2] = 1;
    for($row=3; $row&lt;=$this-&gt;max; ++$row) {
      $this-&gt;tartaglia[$row][1] = 1;
      for ($col=2; $col&lt;$row; ++$col) {
        $this-&gt;tartaglia[$row][$col] = $this-&gt;tartaglia[$row-1][$col-1]
                                + $this-&gt;tartaglia[$row-1][$col];
      }
      $this-&gt;tartaglia[$row][$row] = 1;
    }
  }

  function makeFibonacci ()
  {
    for ($d=1; $d&lt;=$this-&gt;max; ++$d) {
      $t = 0;
      for($el=1; $el&lt;=($d+1)/2; ++$el) {
        $t += $this-&gt;tartaglia[$d+1-$el][$el];
      }
      $this-&gt;fibonacci[$d] = $t;
    }
  }
}
</pre>
<p>Demo:</p>
<p>In <a href="http://www.spadamar.com/files/tarta_fibo/tartafibo.php" target="_blank" title="Demo della classe TartFibo">questa pagina</a> è visibile una demo della classe per n=15.</p>
<p>Download</p>
<p>Il download della classe è disponibile <a href="http://www.spadamar.com/files/tarta_fibo/tartfibo.zip" target="_blank" title="Download della classe TartFibo">qui</a>.</p>
<p>Conclusioni:</p>
<p>Il triangolo di Tartaglia racchiude nei suoi numeri, diversi piccoli segreti e non è solo un metodo per calcolare i coefficienti binomiali. Provate, per esempio a sommare i numeri di ciascuna riga, partendo dall&#8217;alto, danno le potenze di 2. Esistono persino dei frattali! Infine, due grandi matematici, Newton e Pascal hanno rielaborato il suo triangolo per lo studio del calcolo combinatorio. Anche i numeri di Fibonacci, oltre alla relazione con la sezione aurea, hanno implicazioni interessanti, sia con la disposizione geometrica di molte strutture naturali (piante soprattutto) che con l&#8217;informatica, per esempio: <a href="http://en.wikipedia.org/wiki/Fibonacci_heap" target="_blank" title="Wikipedia: Fibonacci heap">Fibonacci heap</a></p>
<p>Riferimenti ed approfondimenti:</p>
<ul>
<li><a href="http://www.amolamatematica.it/appunti/Tartaglia.pdf" target="_blank" title="Le magie del triangolo di tartaglia">Le magie del triangolo di tartaglia (pdf)</a></li>
<li><a href="http://www2.dm.unito.it/paginepersonali/romagnoli/cappa.pdf" target="_blank" title="Le Proprietà del triangolo di Tartaglia e la successione di Fibonacci">Le Proprietà del triangolo di Tartaglia e la successione di Fibonacci (pdf)</a></li>
<li><a href="http://www.vialattea.net/esperti/mat/fibonacci/" target="_blank" title="Vialattea.net: Fibonacci">Vialattea.net: Fibonacci</a></li>
<li><a href="http://www2.polito.it/didattica/polymath/htmlS/argoment/APPUNTI/TESTI/Feb_02/Cap6.html" target="_blank" title="Progetto PolyMath: Dal Triangolo di Tartaglia ai frattali">Progetto PolyMath: Dal Triangolo di Tartaglia ai frattali</a></li>
<li><a href="http://www.archweb.it/geometrie/serie_fibonacci.htm" target="_blank" title="Archweb: La serie di Fibonacci">Archweb: La serie di Fibonacci</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.spadamar.com/2009/09/php-quando-tartaglia-e-fibonacci-si-davano-la-mano/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Gestione fatture: un&#8217;applicazione completa in P4A</title>
		<link>http://www.spadamar.com/2009/04/gestione-fatture-unapplicazione-completa-in-p4a/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=gestione-fatture-unapplicazione-completa-in-p4a</link>
		<comments>http://www.spadamar.com/2009/04/gestione-fatture-unapplicazione-completa-in-p4a/#comments</comments>
		<pubDate>Mon, 13 Apr 2009 13:16:29 +0000</pubDate>
		<dc:creator>spadamar</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[p4a]]></category>
		<category><![CDATA[p4a3]]></category>

		<guid isPermaLink="false">http://www.spadamar.com/?p=301</guid>
		<description><![CDATA[Questa applicazione web si basa sul framework PHP: P4A 3. Si tratta di una versione migliorata e corretta del codice già presentato in questo post. E&#8217; un&#8217;applicazione completa per la gestione delle fatture, pensata soprattutto per chi eroga prestazioni, più &#8230; <a href="http://www.spadamar.com/2009/04/gestione-fatture-unapplicazione-completa-in-p4a/">Continua a leggere<span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><div id="attachment_302" class="wp-caption alignleft" style="width: 310px"><a href="http://www.spadamar.com/wp-content/uploads/2011/06/gestionefatture.png" rel="lightbox[301]"><img src="http://www.spadamar.com/wp-content/uploads/2011/06/gestionefatture-300x131.png" alt="Screenshot di Gestione fatture" title="gestionefatture" width="300" height="131" class="size-medium wp-image-302" /></a><p class="wp-caption-text">Screenshot di Gestione fatture</p></div>Questa applicazione web si basa sul framework PHP: P4A 3. Si tratta di una versione migliorata e corretta del codice già presentato in <a href="http://www.spadamar.com/2008/04/p4a3-framework-porting-del-codice-dellapplicazione-per-la-gestione-delle-fatture/" target="_blank" title="P4A3 framework: porting del codice dell'applicazione per la gestione delle fatture">questo post</a>. E&#8217; un&#8217;applicazione completa per la gestione delle fatture, pensata soprattutto per chi eroga prestazioni, più che prodotti, in quanto non contempla una gestione del magazzino. Può essere utile per chi, come me, fa consulenze informatiche e realizza software, oppure per piccole aziende di autotrasporto che lavorano principalmente conto terzi o per artigiani e professionisti che non utilizzano un magazzino.<br />
Non può essere utilizzata però da coloro i quali sono iscritti ad un albo professionale, in quanto, da informazioni ricevute da un commercialista, mi risulta che il calcolo della ritenuta d&#8217;acconto e delle trattenute INPS sia leggermente differente.
<p>Maschere:</p>
<ul>
<li><em>Gestione azienda</em>: in questa maschera è possibile definire la ragione sociale, i dati anagrafici e il logo dell&#8217;azienda, definire l&#8217;utente e la password  e impostare il tipo di fatturazione: IVA fissa, IVA variabile, ritenuta d&#8217;acconto, contributo INPS (queste ultime due opzioni sono possibili solo con IVA fissa).</li>
<li><em>Gestione clienti</em>: in questa maschera vengono immessi i dati anagrafici dei clienti.</li>
<li><em>Fatture</em>: è la maschera principale per creare e modificare le fatture. E&#8217; divisa in due parti selezionabili attraverso delle &#8216;linguette&#8217; come per gli schedari. La sezione &#8216;fatture&#8217; permette di inserire una nuova fattura vuota, indicando la data, il numero, il cliente e la tipologia di pagamento. E&#8217; anche possibile indicare se la fattura è stata pagata attraverso un flag ed inserire eventuali note. Il numero viene suggerito automaticamente seguendo la progressione dell&#8217;anno in corso, è però possibile immetterlo manualmente, in questo caso esiste un controllo per evitare duplicati.<br />La sezione &#8216;Dettaglio fattura&#8217; serve per inserire la lista di prestazioni o prodotti da fatturare. E&#8217; possibile raggruppare una lista attraverso il campo &#8216;sezione&#8217;. Gli altri campi da riempire sono la descrizione, la quantità il prezzo e l&#8217;IVA (se non si è scelta la modalità IVA fissa). In fondo alla maschera vengono riportati i valori del totale imponibile, totale IVA e totale fattura. (totale ritenuta d&#8217;acconto e contributo INPS, solo se lo si è attivato nella <em>Gestione azienda</em>).<br />Attraverso il pulsante di stampa, viene generato un documento pdf stampabile con la fattura impaginata in una o più pagine (in questo caso numerate) e la dicitura del destinatario allineata con l&#8217;apertura delle buste a &#8216;finestra&#8217; standard. </li>
<li><em>Lista fatture</em>: attraverso questo report è possibile filtrare le fatture di un certo periodo, visualizzare e stampare su pdf l&#8217;elenco e i totali dell&#8217;imponibile, delle fatture e i totali di quelle pagate e quelle no.</li>
<li><em>Tipo pagamenti</em>: E&#8217; possibile inserire le varie modalità di pagamento (assegno, bonifico, riba ecc.)</li>
<li><em>Unità di misura</em>: E&#8217; possibile inserire le unità di misura (ore, pezzi, kg, ecc.)</li>
</ul>
<p>Alcune note sull&#8217;utilizzo:<br />Per aggiungere un nuovo record, è sempre necessario utilizzare il pulsante &#8216;Inserisci un nuovo elemento&#8217;, e una volta compilati i campi, premere il pulsante &#8216;Conferma e salva&#8217;. Nel caso di inserimento di una nuova fattura, dopo aver salvato e prima di inserire la lista delle prestazioni, è necessario selezionare con il puntatore (triangolino nero) la fattura appena creata. Per creare dei blocchi di prestazioni, inserire una dicitura nel campo &#8216;sezione&#8217;, in questo modo, i nuovi record creati con la stessa dicitura nel campo sezione, saranno raggruppati e ordinati alfabeticamente in fattura.
</p>
<p>Installazione</p>
<p>Deve innazitutto essere installato il framework P4A versione 3.2.x (dettagli per il <a href="https://sourceforge.net/project/showfiles.php?group_id=98294&amp;package_id=105252" target="_blank" title="Download P4A 3.2.2">download</a> e <a href="http://p4a.crealabsfoundation.org/code-reference/" target="_blank" title="P4A API Reference">l&#8217;installazione</a>). Poi è sufficiente scompattare l&#8217;archivio compresso nella direcory &#8216;applications&#8217; che si trova sotto la directory &#8216;P4A&#8217;, caricare il dump .sql del database che si trova nella directory &#8216;_private&#8217; in un server &#8216;MySQL&#8217; e impostare i parametri per la connessione nel file &#8216;index.php&#8217; (Nella maggioranza dei casi questo potrebbe non essere necessario). Chi utilizza linux, deve ricordarsi di dare i permessi di scrittura alla directory &#8216;uploads&#8217; e alle sue subdirectories. Se il server web è installato localmente, per accedere all&#8217;applicazione digitare la url &#8216;http://localhost/p4a/applications/gestionefatture/&#8217;<br /> Infine, volendo personalizzare l&#8217;aspetto grafico dell&#8217;applicazione, suggerisco <a href="http://www.spadamar.com/2009/02/p4a-3-framework-personalizzare-il-tema-grafico-con-icone-e-colori/" target="_blank" title="P4A 3 framework: personalizzare il tema grafico con icone e colori">questo articolo</a>.</p>
<p>Il nome utente e la password per l&#8217;accesso iniziale sono: user = &#8216;utente&#8217; e password = &#8216;utente&#8217;</p>
<p>Demo:</p>
<p><em>La demo è temporaneamente sospesa.</em></p>
<p>Download</p>
<ul>
<li><a href="http://www.spadamar.com/files/gestionefatture/gestionefatture.zip" title="Pacchetto Gestione fatture compresso in formato zip">gestione fatture in formato compresso zip</a></li>
<li><a href="http://www.spadamar.com/files/gestionefatture/gestionefatture.tar.bz2" title="Pacchetto Gestione fatture compresso in formato tar">gestione fatture in formato compresso tar bz2</a></li>
</ul>
<p>Licenza</p>
<p>La licenza applicata è la <a href="http://www.gnu.org/licenses/lgpl.html" target="_blank" title="LGPL3">LGPLv3</a></p>
<p>Conclusioni:</p>
<p>Considerando che l&#8217;applicazione viene fornita gratuitamente, non garantisco nessun supporto ufficiale e non mi assumo alcuna responsabilità per eventuali anomalie di funzionamento. Sono comunque disponibile a correggere gli errori che mi segnalerete e a valutare eventuali upgrade, compatibilmente con il tempo richiesto.</p>
<p>Riferimenti ed approfondimenti:</p>
<ul>
<li><a href="http://www.spadamar.com/2008/04/p4a3-framework-porting-del-codice-dellapplicazione-per-la-gestione-delle-fatture/" target="_blank" title="P4A3 framework: porting del codice dell applicazione per la gestione delle fatture">P4A3 framework: porting del codice dell&#8217;applicazione per la gestione delle fatture</a></li>
<li><a href="http://p4a.crealabsfoundation.org/" target="_blank" title="P4A - PHP for applications">P4A &#8211; PHP for applications</a></li>
<p><a href="http://p4a.crealabsfoundation.org/" target="_blank" title="P4A - PHP for applications">  </a>
<li><a href="http://www.fattureopen.net/" target="_blank" title="Fattureopen fatture open source web based">Fattureopen fatture open source web based</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.spadamar.com/2009/04/gestione-fatture-unapplicazione-completa-in-p4a/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP: una classe per il calcolo di matrici di distanze euclidee, cityblock e Minkowski</title>
		<link>http://www.spadamar.com/2009/03/php-una-classe-per-il-calcolo-di-matrici-di-distanze-euclidee-cityblock-e-minkowski/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=php-una-classe-per-il-calcolo-di-matrici-di-distanze-euclidee-cityblock-e-minkowski</link>
		<comments>http://www.spadamar.com/2009/03/php-una-classe-per-il-calcolo-di-matrici-di-distanze-euclidee-cityblock-e-minkowski/#comments</comments>
		<pubDate>Mon, 23 Mar 2009 13:05:16 +0000</pubDate>
		<dc:creator>spadamar</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[distanze euclidee]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.spadamar.com/?p=298</guid>
		<description><![CDATA[Sono diversi gli ambiti nei quali può essere necessario raggruppare elementi di un certo insieme in base a differenze registrate attraverso misure sul campo. In questi casi per la determinazione dell&#8217;entità delle differenze, viene usata la distanza che può essere &#8230; <a href="http://www.spadamar.com/2009/03/php-una-classe-per-il-calcolo-di-matrici-di-distanze-euclidee-cityblock-e-minkowski/">Continua a leggere<span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.spadamar.com/wp-content/uploads/2011/06/euclide.jpg" rel="lightbox[298]"><img src="http://www.spadamar.com/wp-content/uploads/2011/06/euclide.jpg" alt="Euclide" title="euclide" width="262" height="311" class="alignleft size-full wp-image-299" /></a>Sono diversi gli ambiti nei quali può essere necessario raggruppare elementi di un certo insieme in base a differenze registrate attraverso misure sul campo. In questi casi per la determinazione dell&#8217;entità delle differenze, viene usata la <em>distanza</em> che può essere considerata al di là del suo significato metrico, una misura della diversità. I campi di applicazione possono essere i più disparati: dagli aspetti biologici come per esempio differenze genotipiche o fenotipiche di individui o popolazioni, agli aspetti socio-economici come redditi, produttività o consumo.<br />Non tutte le variabili, però, possono essere trattate allo stesso modo. Solo le variabili che vengono definite &#8220;ad intervallo&#8221;, possono essere utilizzate per calcolare distanze di tipo metrico come le distanze euclidee, city-block (o Manhattan) e di Minkowski. Parliamo quindi di variabili quantitative. Negli altri casi, a seconda del tipo di variabile utilizzato (dicotomiche, categoriali, ecc) le differenze possono essere comunque calcolate mediante l&#8217;utilizzo di distanze non metriche o ultra-metriche.<br />A questo punto è bene definire cosa sono le distanze metriche. Sono quelle che rispettano i seguenti enunciati:</p>
<ul>
<li>la distanza tra due punti che non coincidono deve essere positiva;</li>
<li>la distanza tra due punti che coincidono è pari a 0;</li>
<li>la distanza tra due punti deve essere simmetrica (<em>d</em> AB = <em>d</em> BA),</li>
</ul>
<p>e non contravvengono la proprietà della disuguaglianza triangolare, cioè dati tre punti A, B e C deve essere verificata la condizione che:<br /><em>d</em> AB &lt; <em>d</em> AC + <em>d</em> BC <br />riassumendo, si può dire che sono quelle che seguono la metrica pitagorica.</p>
<p>Fatta questa doverosa premessa, passiamo ad analizzare le formule delle distanze metriche utilizzate<br />
nella classe PHP.</p>
<p><strong>Distanze Euclidee</strong></p>
<p>E&#8217; senza dubbio il tipo di distanza più diffuso. La formula per il calcolo deriva dalla formula della distanza fra 2 punti in un piano cartesiano e può essere espressa come:</p>
<p><img class="normale" src="http://www.spadamar.com/files/distance_matrix/euclideanf.png" alt="Formula per il calcolo delle distanze euclidee" /></p>
<p>in cui <em>x<sub>ik</sub></em> e <em>x<sub>jk</sub></em> sono le misure in posizione <em>i</em> e <em>j</em> rispettivamente della <em>k</em>-esima di <em>n</em> variabili.</p>
<p><strong>Distanze city-block (Manhattan)</strong></p>
<p>Viene anche detta distanza assoluta o della metrica del taxi. La sua formula è: </p>
<p><img class="normale" src="http://www.spadamar.com/files/distance_matrix/manhattanf.png" alt="Formula per il calcolo delle distanze city-block" /></p>
<p>La particolarità di questa formula sta nel fatto che, considerando la distanza euclidea fra 2 punti A e C di un triangolo ABC, e che questa distanza può essere espressa come la radice quadrata della somma dei quadrati costruiti sui cateti del triangolo ABC, la distanza di city-block è la somma dei cateti di questo triangolo. Il concetto risulta forse più chiaro osservando la figura qui sotto.</p>
<p><img class="normale" src="http://www.spadamar.com/files/distance_matrix/triangolo.png" alt="Triangolo di esempio" /></p>
<p>Non a caso, il nome Manhattan deriva proprio dalla particolare disposizione delle strade del famoso quartiere di New York, che si incrociano ad angolo retto, formando una sorta di scacchiera. In effetti questo tipo di distanza, ben si presta a rappresentare il percorso reale fra due punti che si trovano in prossimità degli angoli opposti di un palazzo (&#8230;o grattacielo!)</p>
<p><strong>Distanze di Minkowski</strong></p>
<p>Rappresenta la forma più generalizzata di distanza metrica. La sua formula è: </p>
<p><img class="normale" src="http://www.spadamar.com/files/distance_matrix/minkowskif.png" alt="Formula per il calcolo delle di minkowski" /></p>
<p>Si dice di ordine <em>p</em>, e in particolare quando <em>p</em>=1, coincide con la distanza city-block,<br />
e quando <em>p</em>=2, coincide con la distanza euclidea, come si evince dalla formula. Per p -&gt; infinito coincide con la distanza di Lagrange o di Chebychev.</p>
<p>La classe PHP che ho preparato permette di calcolare, scegliendo una delle distanze illustrate sopra, una matrice triangolare (nella quale la diagonale assume valori = 0) di confronto fra tutti i campioni passati in input. La matrice dati da passare come parametro al costruttore deve avere questo formato:  </p>
<pre class="brush:php">$dataTest = array (
                "sample01" =&gt; array(82.897,488,0.6381,8.576),
                "sample02" =&gt; array(37.04,512,0.7935,7.9293),
                "sample03" =&gt; array(86.571,617,0.1518,0.9705),
                "sample04" =&gt; array(76.038,876,0.0883,5.5867),
                "sample05" =&gt; array(67.726,687,0.9145,9.2478),
                "sample06" =&gt; array(34.407,979,0.8148,3.8348),
                "sample07" =&gt; array(52.258,462,0.7132,3.716),
                "sample08" =&gt; array(75.141,652,0.8453,8.3466),
                "sample09" =&gt; array(17.546,322,0.0483,1.5812),
                "sample10" =&gt; array(35.786,502,0.6899,3.1447)
                );
</pre>
<p>Ed ecco dunque il codice PHP della classe:</p>
<pre class="brush:php">class DistanceMatrix
{
 var $dataArray = null;
 var $dataSize = 0;
 var $dataVectSize = 0;

 function DistanceMatrix($data)
 {
  $this-&gt;dataArray = array();
  $this-&gt;dataArray = $data;
  $this-&gt;checkData();
 }

 function checkData()
 {
  $this-&gt;dataSize = count($this-&gt;dataArray);
  if($this-&gt;dataSize &lt; 2){
   die("Cannot proceed: only one sample, or missing data");
  }
  reset ($this-&gt;dataArray);
  $this-&gt;dataVectSize = count(current($this-&gt;dataArray));
  foreach ($this-&gt;dataArray as $key =&gt; $vectData){
   $vectSize = count($vectData);
   if ($vectSize != $this-&gt;dataVectSize){
    die("Cannot proceed: different size vectors!");
   }
  }
 }

 function euclidean ($vect1,$vect2)
 {
  $qdist = 0.0;
  for($i=0;$i&lt;$this-&gt;dataVectSize;$i++){
   $qdist += pow($vect1[$i]-$vect2[$i],2);
  }
  return sqrt($qdist);
 }

 function manhattan ($vect1,$vect2)
 {
  $dist = 0.0;
  for($i=0;$i&lt;$this-&gt;dataVectSize;$i++){
   $dist += abs($vect1[$i]-$vect2[$i]);
  }
  return $dist;
 }

 function minkowski($vect1,$vect2,$exp) {
  $edist = 0.0;
  for($i=0; $i&lt;$this-&gt;dataVectSize; $i++){
   $edist += pow(abs($vect1[$i]-$vect2[$i]), $exp);
  }
  return pow($edist, 1/$exp);
 }

 function printData($distType,$exp=1)
 {
  if (!method_exists($this,$distType)) {
   die ("Sorry, can't find $distType method!");
  }
  echo ("&lt;h1&gt;Matrix of $distType distances &lt;/h1&gt;\n");
  echo ("&lt;table class='datatable' summary='Results'&gt;\n");
  echo ("&lt;thead&gt;&lt;tr&gt;");
  echo ("&lt;th&gt;&nbsp;&lt;/th&gt;");
  foreach ($this-&gt;dataArray as $key=&gt;$data){
   echo ("&lt;th&gt;".$key."&lt;/th&gt;");
  }
  echo ("&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;\n");
  foreach ($this-&gt;dataArray as $keyA=&gt;$dataA){
   echo ("&lt;tr&gt;");
   echo ("&lt;td&gt;&lt;strong&gt;".$keyA."&lt;/strong&gt;&lt;/td&gt;");
   foreach ($this-&gt;dataArray as $keyB=&gt;$dataB){
    if ($distType=="minkowski"){
     printf("&lt;td&gt;%.4f&lt;/td&gt;",$this-&gt;minkowski($dataA,$dataB,$exp));
    }
    else{
     printf("&lt;td&gt;%.4f&lt;/td&gt;",$this-&gt;$distType($dataA,$dataB));
    }
   }
   echo ("&lt;/tr&gt;\n");
  }
  echo ("&lt;/tbody&gt;&lt;/table&gt;\n");
 }
}
</pre>
<p>Demo:</p>
<p>In <a href="http://www.spadamar.com/files/distance_matrix/distmatdemo.php" target="_blank" title="Demo della classe DistanceMatrix">questa pagina</a> è visibile una demo della classe con dei campioni ipotetici e delle variabili di test.</p>
<p>Download</p>
<p>Il download della classe completa del file di esempio è disponibile <a href="http://www.spadamar.com/files/distance_matrix/distmat.zip" target="_blank" title="Download della classe DistanceMatrix">qui</a>.
</p>
<p>Conclusioni:</p>
<p>La naturale conclusione della produzione di una matrice di distanze è l&#8217;elaborazione di una cluster analisys. Questo metodo permette di leggere visivamente i raggruppamenti dovuti alle similarità o diseguaglianze indicate dalle distanze calcolate. Tali raggruppamenti potranno essere espressi in forma gerarchica. Un software distribuito con licenza GNU che permette queste elaborazioni, e che suggerisco<br />
è <a href="http://bonsai.ims.u-tokyo.ac.jp/%7Emdehoon/software/cluster/software.htm" target="_blank" title="Cluster 3.0">Cluster 3.0</a>, disponibile per Linux, Windows e MacOSX.</p>
<p>Riferimenti ed approfondimenti:</p>
<ul>
<li><a href="http://it.wikipedia.org/wiki/Distanza_euclidea" target="_blank" title="Wikipedia: Distanza euclidea">Wikipedia: Distanza euclidea</a></li>
<li><a href="http://it.wikipedia.org/wiki/Metrica_%28matematica%29" target="_blank" title="Wikipedia: Distanza (matematica)">Wikipedia: Distanza (matematica)</a></li>
<li><a href="http://it.wikipedia.org/wiki/Geometria_del_taxi" target="_blank" title="Wikipedia: Geometria del taxi">Wikipedia: Geometria del taxi</a></li>
<li><a href="http://www.unich.it/labgeogr/didatticadir/02%20RE.pdf" target="_blank" title="G. Massimi, La distanza, WP Web 2001 (pdf)">G. Massimi, La distanza, WP Web 2001 (pdf)</a></li>
<li><a href="http://areadocenti.eco.unicas.it/iodice/images/cluster_analysis.pdf" target="_blank" title="Alfonso Iodice D'Enza - Universita degli studi di Cassino - Analisi dei dati e Cluster Analysis">Alfonso Iodice D&#8217;Enza &#8211; Universita degli studi di Cassino &#8211; Analisi dei dati e Cluster Analysis (pdf)</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.spadamar.com/2009/03/php-una-classe-per-il-calcolo-di-matrici-di-distanze-euclidee-cityblock-e-minkowski/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

