domenica 28 ottobre 2007

geo localizzazione dei visitatori in 5 minuti

Ecco come dotare un sito della geo-localizzazione dei visitatori sfruttando due servizi gratuiti e un piccolo sorso di javascript. Per la geo-localizzazione occorre per prima cosa risalire alla latitudine e longitudine del visitatore sfruttando il suo indirizzo IP, ottenute queste informazioni bisogna poi mostrarle su una mappa.. Ci sono diversi servizi in rete che permettono di associare latitudine e longitudine ad un indirizzo IP, io qui mi sono servito di freeIpServices.com il quale, oltre ad essere gratuito, è anche molto semplice da usare, basta importare uno script javascript e sfruttare le due funzioni getLat() e getLng() che restituiscono rispettivamente latitudine e longitudine. Quello che ci rimane da fare è prendere una bella mappa e incollarci sopra la latitudine e la longitudine usando "..abbondante ccccolla vinilica" di muciacciana memoria. Qui le alternative sono principalmente due: Google Maps e Virtual Earth di casa Microsoft. Nell'esempio che segue ho usato Virtual Earth per il quale c'è in rete un ottimo SDK a questo indirizzo The Virtual Earth Interactive SDK, per caricare la mappa basta richiamare il metodo LoadMap al quale vengono passati in input latitudine e longitudine. Ed ecco il risultato del nostro "collage"



Qui di seguito invece l'esempio completo




<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Coffee Break - GeoLocalization By IP </title>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

<script type="text/javascript" src="http://freeipservices.com/ip2geo?v=1"></script>

<script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6"></script>

<script type="text/javascript">
var map = null;

function GetMap()
{
map = new VEMap('myMap');
map.LoadMap(new VELatLong(getLat(), getLng()), 10 ,'h' ,false);
document.getElementById("_fis").style.width="475px";
}

</script>

<style type="text/css">

#_fis {
color: white;
background-color: black;
font-family: verdana;
font-weight: bold;
}

</style type="text/css">

</head>

<body onload="GetMap();">

<div id='myMap' style="position:relative; width:500px; height:400px;"></div>

</body>

</html>


giovedì 18 ottobre 2007

Esprimere un numero in lettere

Oggi ho dovuto scrivere un modulo per la compilazione e la stampa automatica di assegni, nulla di che, uno di quei compiti poco stimolanti che si svolgono col cervello in standby e lo sguardo perso nel nulla. E poi odio avere a che fare con le stampanti, forse perchè tutte le stampanti che ho avuto mi hanno puntualmente abbandonato il giorno prima della consegna di qualche tesina. Ad essere sincero però, devo ammettere che cinque minuti di piacere me li sono ritagliati, ed è stato quando ho dovuto scrivere una funzione che mi permettesse di esprimere l'importo dell'assegno in lettere. Un momento di piacere che definirei dal sapore nostalgico! Non so perchè, ma mentre scrivevo la funzione mi sono venuti in mente i primi anni dell'università, quando studiavo Pascal e implementavo il BubbleSort piuttosto che la Torre di Hanoi o robe del genere. A volte il cervello fa collegamenti strani, forse dovrei smettere di bere caffè..


Public Class bcc_NumeriInLettere

Private mTabella1() As String = {"uno", _
"due", _
"tre", _
"quattro", _
"cinque", _
"sei", _
"sette", _
"otto", _
"nove", _
"dieci", _
"undici", _
"dodici", _
"tredici", _
"quattordici", _
"quindici", _
"sedici", _
"diciassette", _
"diciotto", _
"diciannove"}

Private mTabella2() As String = {"venti", _
"trenta", _
"quaranta", _
"cinquanta", _
"sessanta", _
"settanta", _
"ottanta", _
"novanta"}


Private Function m_FiniscePerVocale(ByVal tmp As String) As Boolean

Return
tmp.EndsWith("a") Or _
tmp.EndsWith("e") Or _
tmp.EndsWith("i") Or _
tmp.EndsWith("o") Or _
tmp.EndsWith("u")

End Function

Private Function
m_IniziaPerVocale(ByVal tmp As String) As Boolean

Return
tmp.StartsWith("a") Or _
tmp.StartsWith("e") Or _
tmp.StartsWith("i") Or _
tmp.StartsWith("o") Or _
tmp.StartsWith("u")

End Function

Private Function
m_da1a999(ByVal strval As String) As String

Dim
l As Int16 = strval.Length
Dim i, j, k As Int16

Dim tmp, dec, uni As String
Dim
c As String

tmp = ""
j = 0

For i = l To 1 Step -1

c = strval.Chars(j)
j = j + 1

If c <> "0" Then

Select Case i

Case 3

If c = "1" Then

tmp &= "cento"

Else

k = CInt(c) - 1
tmp &= mTabella1(k) & "cento"

End If

Case 2

' controlla se è un numero conosciuto
k = CInt(c & strval.Chars(j))

If k < color="blue">Then


tmp &= mTabella1(k - 1)

ElseIf (k Mod 10) = 0 Then

' venti, trenta, quaranta...
tmp &= mTabella2((k / 10) - 2)

Else

' ventuno, ventidue, ventitre..
k -= k Mod 10
k = (k / 10) - 2
dec = mTabella2(k)

k = CInt(strval.Chars(j).ToString) - 1
uni = mTabella1(k)

If m_FiniscePerVocale(dec) And m_IniziaPerVocale(uni) Then

' per esempio ventuno, ventotto
' tronchiamo venti a vent e concateniamo uno, otto..

dec = dec.SubString(0, dec.Length - 1)

End If

tmp &= dec & uni

End If

Return tmp

Case 1

' basta tradurre l'unita
k = CInt(c) - 1
tmp &= mTabella1(k)

End Select

End If

Next

Return
tmp

End Function

Public Function
NumeriInLettere(ByVal strval As String) As String

Dim
part1 As String
Dim
part2 As String
Dim
tmp As String
Dim
rv As String
Dim
len As Int16
Dim i As Int16

part1 = strval
part2 = ""
tmp = ""
rv = ""

i = strval.IndexOf(",")
If i <> -1 Then

part1 = strval.SubString(0, i)
part2 = strval.SubString(i + 1)

End If

While True


len = part1.Length
If len > 12 Then

' ci fermiamo solo ai miliardi..
Return
"numero troppo grande"

ElseIf (12 >= len) And (len > 9) Then

' miliardi
i = len - 9
tmp = part1.SubString(0, i)
part1 = part1.SubString(i)

tmp = m_da1a999(tmp)
rv = IIf(tmp = "uno", "unmiliardo", tmp & "miliardi")

ElseIf (9 >= len) And (len > 6) Then

' milioni
i = len - 6
tmp = part1.SubString(0, i)
part1 = part1.SubString(i)

tmp = m_da1a999(tmp)
rv &= IIf(tmp = "uno", "unmilione", tmp & "milioni")

ElseIf (6 >= len) And (len > 3) Then

i = len - 3
tmp = part1.SubString(0, i)
part1 = part1.SubString(i)

tmp = m_da1a999(tmp)
rv &= IIf(tmp = "uno", "mille", tmp & "mila")

Else

tmp = m_da1a999(part1)
rv &= tmp & "/" & IIf(part2 <> "", part2, "00")
Return rv

End If

End While

End Function

End Class


domenica 14 ottobre 2007

FoxBurner: le statistiche di FeedBurner sulla statusbar del tuo browser

Questa settimana ho dedicato parte del mio tempo libero alla scrittura di una estensione per FireFox, era già da un pò che mi ero ripromesso di implementarne una, mi mancava solo l'ispirazione.. che finalmente è arrivata.. I feed generati da questo blog sono gestiti tramite FeedBurner, strumento che personalmente trovo utilissimo e che interrogo milioni di volte al giorno (perdendo ovviamente un sacco di tempo..) per sapere quanto popolari siano i miei feed (poco, pochissimo devo dire.. :D). E da qui nasce l'ispirazione, le statistiche di FeedBurner nella statusbar del mio FireFox! Scrivere una estensione per FireFox che si limiti a svolgere questo compito non è per nulla complicato, ci sono molti tutorial in rete sull'argomento ( a tal proposito vi consiglio Creating a dynamic status bar extension ), la parte più fastidiosa poteva essere recuperare le statistiche da FeedBurner ma, per fortuna, nemmeno questo punto si è poi rivelato complicato da risolvere, FeedBurner infatti mette a disposizioni delle API per la gestione del proprio account e dei propri feed. Per mettere insieme il tutto mi sono bastate un paio di ore di lavoro grazie anche all'aiuto fondamentale della Console degli errori e della Extension Developer ( scaricabile da questo link ) che hanno sveltito di molto il processo di sviluppo. Da questo indirizzo è possibile scaricare la mia FoxBurner, per installarla basta aprire la finestra delle estensioni ( Strumenti->Componenti Aggiuntivi ) e trascinare li il file foxburner.xpi. Per tutti coloro che invece volessero dare una occhiata al codice ricordo che basta cambiare l'estensione del file foxburner da xpi a zip e poi decomprimere..

sabato 6 ottobre 2007

Interfaccia IEditableObject, una implementazione generica

Ecco una classe che uso spesso come base dei miei Business Object, implementa l'interfaccia IEditableObject così da fornire la modifica dei dati transazionale a tutte le classi che la ereditano. L'interfaccia IEditableObject richiede di implementare i metodi BeginEdit, EndEdit e CancelEdit. Il metodo BeginEdit viene chiamato prima di iniziare la modifica dell'oggetto e si occupa di salvarne da qualche parte lo stato, il metodo CancelEdit serve per annullare l'operazione di modifica e ripristinare lo stato iniziale dell'oggetto, mentre il metodo EndEdit serve a confermare le modifiche eseguite sull'oggetto. E' da sottolineare il fatto che tra la chiamata a BeginEdit e la chiamata a uno tra EndEdit e CancelEdit possono intercorrere altre chiamate al metodo BeginEdit che devono essere ignorate. Come già detto il compito di BeginEdit è quello di salvare lo stato dell'oggetto così da poterlo poi ripristinare nel caso in cui l'utente volesse annullare le modifiche. A tale scopo sfrutteremo una Collection e la potenza della classe Reflection. Vediamo come: facendo uso della Reflection scoveremo tutte le proprietà pubbliche dell'oggetto e, scorrendole una dopo l'altra, salveremo il valore di ognuna di esse in una Collection usando come chiave il nome della proprietà. All'inizio del metodo BeginEdit metteremo un controllo sul valore della Collection, se questa non è nothing vuol dire che non si tratta della prima chiamata a BeginEdit e quindi usciamo dalla procedura, viceversa se la Collection è nothing allora possiamo istanziarla e procedere con il salvataggio dello stato. Il metodo EndEdit si occupa della conferma dei dati, ci limiteremo quindi a settare la Collection a nothing per far si che una successiva chiamata a BeginEdit non venga ignorata. Nel metodo CancelEdit vengono compiute le operazione inverse di quelle che si eseguono nel metodo BeginEdit, si leggono cioè i valori salvati nella Collection e si settano le proprietà dell'oggetto.



Public Class bcc_EditableObject
Implements System.ComponentModel.IEditableObject

Private mTmpData As Collection

Public Sub BeginEdit() _
Implements System.ComponentModel.IEditableObject.BeginEdit

' solo la prima BeginEdit ha effetto
If Not IsNothing(mTmpData) Then Exit Sub

Dim pi_src As Reflection.PropertyInfo

mTmpData = New Collection

For Each pi_src In _
Me.GetType.GetProperties( _
Reflection.BindingFlags.Public Or _
Reflection.BindingFlags.Instance)

' la proprietà non deve essere ReadOnly
If pi_src.CanWrite Then

mTmpData.Add(pi_src.GetValue(Me, Nothing), pi_src.Name)

End If

Next

End Sub


Public Sub CancelEdit() _
Implements System.ComponentModel.IEditableObject.CancelEdit

' nulla da ripristinare
If IsNothing(mTmpData) Then Exit Sub

Dim pi_src As Reflection.PropertyInfo

For Each pi_src In _
Me.GetType.GetProperties( _
Reflection.BindingFlags.Public Or _
Reflection.BindingFlags.Instance)

' la proprietà non deve essere ReadOnly
If pi_src.CanWrite Then

pi_src.SetValue(Me, mTmpData.Item(pi_src.Name), Nothing)

End If

Next

End Sub


Public Sub EndEdit() _
Implements System.ComponentModel.IEditableObject.EndEdit

' via libera alla prossima BeginEdit
mTmpData = Nothing

End Sub

End Class