venerdì 30 gennaio 2015

Ruotare velocemente

Oggi vedremo come creare l'animazione di un oggetto che ruota velocemente. Questo è un argomento dove molto programmatori sono esperti nel codice, ma mancano di senso praticano e si impazziscono per raggiungere prestazioni inutili.
Prima di affrontare questo argomento dal punto di vista informatico, bisogna fare una premessa dal punto di vista tecnico, non ha senso cercare di essere realmente veloci, molte volte basta far sentire la velocità, magari. Inoltre gli schermi hanno una frequenza di aggiornamento di 60Hz, cioè ogni 0.017 secondi, ogni variazione sotto questo tempo è ignorata. Quindi basterà aumentare l'angolo di rotazione ad ogni aggiornamento, invece di aumentare il numero degli aggiornamenti, per avere l'effetto desiderato.
Fatta questa premessa, passiamo al codice.  Creiamo uno stack con un poligono, un pulsante e uno scroller che chiameremo angolo:
Per ruotarlo basta sfruttare la proprietà angle.
Scrivendo questo codice, possiamo ruotare il triangolo ad ogni fotogramma dell'angolo voluto:

on mouseUp
   if the label of me is "START" then
      set the label of me to "STOP"
      ruotafigura
   else
      set the label of me to "START"      
   end if  
end mouseUp

on ruotafigura
   if the label of me is "START" then
      exit ruotafigura
   end if
   put the thumbpos of scrollbar "angolo" into Dangolo
   put the angle of graphic 1 into curangolo
   put dangolo + curangolo into curangolo
   set the angle of graphic 1 to curangolo
   send ruotafigura to me in 0.017 sec #non ha senso scendere sotto questo valore
end ruotafigura

E questo è il risultato:
Notate come se la velocità supera quella del monitor, si creano strani effetti ottici stroboscopici  (ad esempio che sembra ruotare all'indietro), come nella realtà.

giovedì 29 gennaio 2015

Piccoli problemi di manutenzione

Da oggi, quando si traducono i post utilizzando Google translator (il menù in alto a destra), il codice dei programmi non verrà modificato. Ciò è possibile grazie al codice:

class=notranslate

che ho aggiunto in tutti (o quasi) gli elementi che hanno del codice.
Per fare ciò estratto il backup del blog, che blogger fornisce sotto forma di XML, ho sostituito il codice e ho importato il file XML. Qui nasce il problema, blogger non sostituisce i post, ma li aggiunge, così mi sono ritrovato con tutti i post doppi.
Ho cancellato tutti i doppioni, ma se trovate qualche link mancante, per favore segnalatemelo.

mercoledì 28 gennaio 2015

Salvare le immagini in un database

Oggi vedremo come salvare le immagini dentro un database per poi utilizzarle successivamente.
In livecode potete sfruttare due informazioni riguardo le immagini: la proprietà imagedata e la proprietà text. Queste due proprietà rappresentano l'immagine, ma in due modi diversi. La proprietà imagedata contiene le informazioni sui pixels dell'immagine e basta; la proprietà text contiene più informazioni: il tipo di immagine (bmp,jpg, ecc.), il tipo di compressione dei dati, i pixels, ecc.
Se dobbiamo lavorare con più immagini di diverso formato (jpg, gif, png, ecc.), non possiamo mettere direttamente solo l'imagedata in una immagine di livecode, perchè se i formati sono differenti livecode dà errore e l'immagine non compare.
Dobbiamo lavorare con la proprietà text, ma vediamo nel dettaglio come fare.
Per scegliere un'immagine da caricare conviene utilizzare questo codice:

answer file "Scegli il nuovo file per l'immagine da salvare:"
if the result is not "Cancel" then
   put it into tpath
   lock screen
   put the rect of image "logo" into temp
   put url ("binfile:" & tpath) into image 1
   set the rect of image 1 to temp
   unlock screen
end if

Notate due cose, l'immagine può non avere la dimensione (altezza e larghezza) desiderata, memorizzando prima la proprietà rect e poi impostandola dopo aver caricato l'immagine, non rischiamo di trovarci immagini con dimensioni assurde fluttuanti  in giro per il programma.
Il secondo elemento da notare è il codice per mettere tutti i dati dell'immagine del computer dentro al controllo immagine di livecode (che ho chiamato semplicemente image 1):

   put url ("binfile:" & tpath) into image 1

solo così la nostra immagine image 1 contiene la proprietà text.
Il database dovrà avere un campo di tipo TEXT (testo), ciò ci permette di non dover impazzirci con i dati in formato binario, che di solito sono un problema quando si trasferiscono da un sistema ad un altro.
Ora i dati dell'immagine, cioè la proprietà text,  deve essere salvata nel database preservando tutte le informazioni, il sistema migliore è utilizzare la funzione base64encode(); in questo moto tutti i bit sono trasformati in caratteri accettati dai campi text dei database. Ecco un esempio di codice per inserire un'immagine in un database:

put base64encode(the text of image 1) into temp
put "UPDATE bandiere SET immagine='"& temp &"' WHERE nome='italia' ;" into tSQL
revExecuteSQL connID,tSQL

Per recuperare l'immagine, basta fare il procedimento inverso. La proprietà si ottiene utilizzando la funzione base64decode(), e poi la inseriamo nel controllo immagine, nel nostro caso image 1, di livecode.

put "SELECT immagine FROM bandiere WHERE nome='italia' "   into tSQL
put revDataFromQuery(tab,return,connID,tSQL) into tRecord
lock screen
put the rect of image 1 into tempR   
put base64decode(tRecord) into temp
put temp into image 1         
set the rect of image 1 to tempR
unlock screen

Separare i dati utilizzando il carattere TAB è molto utile, perchè se dovete richiedere più dati insieme non avrete possibilità di confondere i dati, poichè il carattere TAB non esce dalla funzione base64encode().

martedì 27 gennaio 2015

Cifratura a chiave asimmetrica

Nel post precedente abbiamo visto come cifrare utilizzando un sistema a chiave simmetrica, oggi vedremo come cifrare utilizzando un sistema a chiave asimmetrica.
Prima di vedere gli strumenti che livecode ci mette a disposizione, preferisco fare un'introduzione a questo nuovo tipo di cifratura. Questo sistema è di tipo molto recente, e basa la sua affidabilità sulla lentezza dei computer moderni. Quando si vuole offuscare un testo con questo sistema, si generano una coppia di chiavi: una pubblica e una privata. Chi vuole inviarvi un testo deve cifrarlo utilizzando la vostra chiave pubblica, mentre solo voi in possesso della chiave controparte privata sarete in grado di decifrarlo.
Quindi lo scambio di informazioni fra due persone si può ottenere solo con 2 coppie di chiave, una coppia per destinatario; ecco uno schema esemplificatore:
Finchè i nostri computer non saranno in grado di risalire velocemente alla chiave pubblica dalla chiave privata, questo sistema sarà sicuro. D'altro canto è sempre matematicamente possibile risalire alla chiave pubblica per tentativi con i computer, ma il tempo attuale è sui 100 anni.
Enti governativi con a disposizione enormi gruppi di calcolatori, possono ridurre questo tempo utilizzando una potenza di calcolo molto elevata, e la cifratura di tipo simmetrico allora diviene più sicura. Altri sostenitori della cifratura asimmetrica preferiscono allungare in numero di bit di cui è formata la chiave, poichè questo allunga il tempo di elaborazione per scovare la chiave privata della chiave pubblica; ma questo stratagemma allunga anche il tempo per decifrare un messaggio, anche avendo la chiave privata.
A titolo di esempio generiamo una coppia di chiavi RSA a 512 bit. Quella pubblica sarà:

-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALaULMjivN2L2xGBnUTqyGAwFY9AJE6b
8bT0CZPA9XMt+M0DULRzE5lL6JkstBAqep3iopd0/285lFnoSyVYQkkCAwEAAQ==
-----END PUBLIC KEY-----


Notate che è obbligatorio mettere anche i trattini e le scritte BEGIN/END public key.
Quella privata sarà:

-----BEGIN RSA PRIVATE KEY-----
MIIBPAIBAAJBALaULMjivN2L2xGBnUTqyGAwFY9AJE6b8bT0CZPA9XMt+M0DULRz
E5lL6JkstBAqep3iopd0/285lFnoSyVYQkkCAwEAAQJAcRn9XDxJLxzyCjg2ynh+
xEdFM8ZSN3gXFTePrz37TuuBZJquvi3d5LtfS8yLX0Ucy6PcndlsDY5TCJjdBAN+
uQIhAOMeEfwF2PHzhs/Q8eE6h4X8l2++UtN01QUURywxM483AiEAzcwgCP7IKa1h
FneEd5RErzywIGMG5NFtrIzL5sOcen8CIQDSZJ3WcPhLEwTU6UPZGKZJCfijjJUf
zEA151YTazTPOwIhAIaxyW3ZxAxzLA5WX18cre+72tL3vXVaFVxQMsxwzyPlAiEA
4xaelAVHHsClDuCw6i3NkoYTD7wg9ysNx1d/1nbMB98=
-----END RSA PRIVATE KEY-----


Facciamo uno stack contenente  sia il messaggio che vogliamo cifrare, sia le chiavi (le potete generare anche on line dal sito: http://travistidwell.com/jsencrypt/demo/).

Ora dobbiamo considerare che il sistema RSA prevede che il messaggio sia un multiplo di 52 lettere, quindi bisogna fare un controllo sul testo e aggiungere tanti spazi vuoti, quanti necessitiamo per ottenere un testo lungo un multiplo di 52 lettere. Nel pulsante cifra possiamo mettere il seguente codice:

on mouseUp
   put the text of field "testo" into testo
   put the number of chars of testo into lungtesto
   put round(lungtesto / 52) into cicli
   if (( lungtesto mod 52) is not 0 ) then
      put cicli + 1 into cicli
      put lungtesto mod 52 into temp
      #aggiungiamo gli spazi necessari
      repeat for temp times
         put " " after testo
      end repeat
   end if
   put the text of field "publickey" into passw
   put the text of field "privatekey" into passw2
   repeat with i=1 to cicli
      put char (52 * (i-1) + 1) to (i * 52) of testo into temp
      encrypt temp using rsa with public key passw      
      if the result is not empty then
         answer the result #c'è un errore, vediamo qual è
      else
         put it after tutto         
      end if
   end repeat
   set the text of field "cifrato" to tutto   
end mouseUp


e otteniamo per ogni gruppo di 52 lettere, 64 lettere cifrate. Nel campo cifrato apparirà il testo cifrato e incomprensibile.
Notate che il sistema RSA aggiunge delle variabili casuali, quindi, nonostante il messaggio originale sia sempre lo stesso, il risultato cifrato è sempre diverso.
Nel codice rsa non  è virgolettato.
Ora per recuperare il testo originale dobbiamo fare il procedimento inverso, 64 lettere alla volta; per questo nel pulsante decifra possiamo mettere il seguente codice:

on mouseUp
   put the text of field "cifrato" into testo
   put the text of field "privatekey" into passw   
   put the number of chars of testo into lungtesto   
   if (lungtesto mod 64) is not 0 then
      answer "non è un messaggio cifrato con RSA"
      exit mouseup
   end if
   put lungtesto / 64 into cicli
   repeat with i=1 to cicli
      put char (64 * (i-1) + 1) to (i * 64) of testo into temp
      decrypt temp using rsa with private key passw
      put it after tutto
   end repeat   
   answer tutto
end mouseUp


Se in decrypt usate la parola public invece di private, state solo verificando se è stato cifrato con la chiave pubblica corretta.
Ora sapete come inviare un messaggio utilizzando solo una cifratura asimmetrica.
Siccome ogni forma di dato può essere trasformato in testo con la funzione base64encode, potrete inviare anche musiche, immagini, filmati o qualsiasi altro tipo di file in maniera cifrata.

venerdì 23 gennaio 2015

Cifratura simmetrica

Livecode permette di cifrare sia in maniera simmetrica che asimmetrica. Oggi vedremo il sistema più semplice di cifratura: la cifratura simmetrica. La cifratura simmetrica è la più semplice e la più utilizzata al mondo, con la stessa parola chiave (password) si camuffa un testo,cioè si cifra, e con la stessa password si ricostruisce il testo originale, cioè si decifra.
Livecode supporta diversi sistemi di cifratura, sia asimmtrica che simmetrica; per avere una lista dei sistemi supportati e con che modalità basta utilizzare la funzione ciphernames(), ecco un breve riassunto

  • aes
  • bf
  • blowfish
  • camellia
  • cast
  • cast5
  • des
  • des3
  • desx
  • id-aes128-GCM
  • id-aes192-GCM
  • id-aes256-GCM
  • rc2
  • rc4
  • seed

Per inciso, tutti i sistemi più avanzati che dichiarano di utilizzare una cifratura più difficile di tipo asimmetrico, in realtà non riescono ad utilizzarla completamente, perchè un procedimento del genere richiede un tempo molto grande. Per questo motivi cifrano in maniera asimmetrica solo la password simmetrica di un testo cifrato in modo simmetrico.

Nel nostro caso cifreremo simmetricamente utilizzando il sistema blowfish.

Facciamo uno stack con  con i seguenti campi: testo, password e cifrato. Aggiungiamo due pulsanti: cifra e decifra. Mettiamo nel pulsante cifra il seguente codice:

on mouseUp
   put the text of field "testo" into testo
   put the text of field "password" into passw
   encrypt testo using "bf" with password passw
   set the text of field "cifrato" to it
end mouseUp

In questo modo, premendo sul pulsante cifra, nel campo cifrato apparirà il testo cifrato:
Per decifrare possiamo mettere il seguente codice nel pulsante decifra:

on mouseUp
   put the text of field "cifrato" into testo
   put the text of field "password" into passw
   decrypt testo using "bf" with password passw
   answer it
end mouseUp

Nel prossimo post vedremo come utilizzare i sistemi asimmetrici.
Il limite di sicurezza nella cifratura simmetrica risiede nel fatto che a chi inviamo un messaggio cifrato, dobbiamo far sapere anche la chiave utilizzata, e quindi se cade nelle mani di qualcun altro, anche quest'ultimo potrà decifrare i nostri messaggi.

giovedì 22 gennaio 2015

Rimuovere livecode da Linux

Nuove versioni di Livecode escono continuamente, quindi rischiate di avere il menu di avvio pieno di tutte le versione installate; per fortuna i programmatori hanno installato un sistema per eliminare le vecchie versioni su Linux in maniera semplicissima.
Tutte le versioni si installano dentro la cartella /opt/runrev, ognuna con la propria cartella:

max@max-desktop /opt/runrev $ ls
livecodecommunity-6.6.2
livecodecommunity-7.0.0-rc-1 (x86_64)
livecodecommunity-7.0.0-rc-2 (x86_64)
livecodecommunity-7.0.0 (x86_64)
livecodecommunity-7.0.1-rc-1 (x86_64)
livecodecommunity-7.0.1-rc-3 (x86_64)
livecodecommunity-7.0.1 (x86_64)



Dentro le cartelle di ogni versione c'è un file nascosto chiamato ".setup.x86", basta posizionarsi dentro la cartella /opt/runrev/, senza essere root (dopo vi chiederà la password), e lanciare il comando ".setup.x86 -uninstall" della cartella che contiene la versione da disinstallare. L'importante è non essere dentro la cartella stessa da cancellare. Ecco le schermate che vi appariranno:


mercoledì 21 gennaio 2015

Frattali

I frattali sono particolari figure geometriche che rappresentano se stesse qualunque ingrandimento fatto.
Mi sono esercitato un po' con la formula per quello di Mandenlbrot e il risultato è stato il seguente:
Nel caso di Mandrelbrot il calcolo iterativo è dato da P(z+1)= P(z)^2 + P(x,y). Il codice è il seguente:


on mouseUp
   put "1,1" into cc
   put cc & CR into nn
   delete image "frattale"
   create image "frattale"
   put field "grandezza" into kk #deve essere un numero pari
   put field "maxiter" into rip   
   set the width of image frattale to kk
   set the height of image frattale to kk
   #centriamo l'immagine
   set the loc of image "frattale" to the loc of scrollbar "progr"
   set the top of image "frattale" to the bottom of scrollbar "progr"
   set the layer of image "frattale" to 1
   repeat with x= 1 to kk
      repeat with y= 1 to kk
         put x / kk * 4 - 2 into tx
         put y / kk * 4 - 2 into ty
         put fract(tx,ty,rip) & CR after contlist
         add 1 to cont
         set the thumbpos of scrollbar "progr" to (round(100/(kk * kk) * cont) )
      end repeat
   end repeat   
   set the lista of me to contlist #per debug
   repeat for each line tLine in contlist      
      put numtochar(255) after timag
      put numtochar(tLine* 255 / rip) after timag
      put numtochar(tLine*255 / rip) after timag
      put numtochar(tLine*255 / rip) after timag      
   end repeat
   set the imagedata of image "frattale" to timag
   #answer "fatto"
end mouseUp

function fract x,y,rip
   put x & comma & y into cc
   put "0,0" into xy
   put 0 into d
   put 0 into cont
   repeat while d < 2
      add 1 to cont      
      if cont > rip then
         put 0 into cont
         exit repeat
      end if
      put compadd(compmult(xy,xy), cc) into xy
      put item 1 of xy into xx
      put item 2 of xy into yy
      put sqrt(xx^2 + yy^2) into d         
   end repeat
   return cont
end fract

function compadd aa,bb
   put item 1 of aa into aax
   put item 2 of aa into aay
   put item 1 of bb into bbx
   put item 2 of bb into bby
   put (aax + bbx) , (aay + bby) into temp
   return temp
end compadd


function compmult aa,bb
   put item 1 of aa into aax
   put item 2 of aa into aay
   put item 1 of bb into bbx
   put item 2 of bb into bby
   put (aax * bbx - aay * bby) , (aax * bby + aay * bbx) into temp   
   return temp
end compmult




Il programma completo lo potete scaricare da qui. Non è che sia entusiasta della velocità di calcolo ottenuta, voi riuscireste a migliorare il codice?

lunedì 19 gennaio 2015

Creare un programma DIFF (parte 2)

Nel post precedente abbiamo visto come trovare correttamente le differenze fra le righe di due testi, ma quali applicazione ha?
Innanzitutto premettiamo che il metodo visto si può applicare alle righe di un testo, come alle parole, alle lettere, ai puntini che compongono un'immagine, a qualsiasi cosa.
I siti come Dropbox, Google, Mega, offrono di ospitare i vostri file e, ogni volta che aggiornate un file, di mantenere le versioni precedenti. Per risparmiare spazio, invece di avere più copie di file con piccole differenza, mantengono nei loro archivi solo un file e le successive differenze.
Anche nei formati video digitali, ogni 5 fotogrammi, abbiamo i dati di un fotogramma intero e solo le differenze per i successivi 4 fotogrammi; sempre per ridurre spazio.
Trovare le differenza ci serve anche in biologia e medicina, per capire cosa è effettivamente cambiato in un DNA, da una specie ad un'altra, o una lunga molecola organica come si è modificata.
Nel campo dell'informatica, si possono mandare solo i DIFF di un programma, e i programmi di patch, applicheranno solo le modifiche; in questo modo non c'è bisogno di inviare tutto il programma.
Ora vediamo di creare un programma che ci faccia vedere le differenze fra sue testi, molto usato in informatica.
Ci basterà sfruttare il codice mostrato nell'altro post, aggiungendo il solo il modo di colorare il testo.
Otterremo un programma simile a questo:

Nelle due colonne in basso a destra abbiamo i due testi affiancati con le righe eliminate in rosso e quelle aggiunte in verde. Chiamando questi due campi rispettivamente: VersAdiff e VersBdiff, il codice per ottenere il testo colorato è il seguente:

on mouseUp
   #trasformiamo i testi in array, dove ogni riga è un elemento dell'array   
   put the text field "versA" into tOldSource
   put the text field "versB" into tNewSource
   split tOldSource using return
   split tNewSource using return
   #cerchiamo di capire di quanti elementi, cioè righe, è fatto ogni array
   #extents mostra una serie di righe con due numeri, il numero minimo e il massimo per ogni dimensione dell'array
   #qui la dimensione è 1
   put item 2 of the extents of tOldSource into tOldLineCount
   put item 2 of the extents of tNewSource into tNewLineCount
   #calcoliamo le varie sequenze con il massimo testo in comune (LCSL)   
   put CalculateLCSLengths(tOldSource, tNewSource, tOldLineCount, tNewLineCount) into LCLS
   #e adesso calcoliamo il DIFF      
   lock screen
   put empty into field "VersAdiff"
   put empty into field "VersBdiff"   
   DetermineDiff LCLS, tOldSource, tNewSource, tOldLineCount, tNewLineCount
   DetermineDiff2 LCLS, tOldSource, tNewSource, tOldLineCount, tNewLineCount
   unlock screen
end mouseUp

function CalculateLCSLengths tOldSource, tNewSource, tOldLineCount, tNewLineCount   
   #costruiamo la tabella per il calcolo LCSL
   #la riga 0 è tutti 0
   repeat with tRow = 0 to tOldLineCount
      put 0 into pLCSLength[tRow,0]
   end repeat
   #la colonna 0 è tutti 0
   repeat with tCol = 0 to tNewLineCount
      put 0 into pLCSLength[0,tCol]
   end repeat
   #ora calcoliamo le altre varie celle della matrice LCLS
   repeat with tRow = 1 to tOldLineCount
      repeat with tCol = 1 to tNewLineCount
         put tOldSource[tRow] into tOldLine
         put tNewSource[tCol] into tNewLine
         if tOldLine = tNewLine then
            put pLCSLength[tRow - 1,tCol - 1] + 1 into pLCSLength[tRow,tCol]
         else
            put max(pLCSLength[tRow - 1,tCol],pLCSLength[tRow,tCol - 1]) into pLCSLength[tRow,tCol]
         end if
      end repeat
   end repeat
   #finito
   return pLCSLength
end CalculateLCSLengths


#abbiamo un messaggio che chiama se stesso parecchie volte
#qui usiamo le @ per risparmiare meomoria ed evitare troppe copie della stessa variabile, però stiamo attenti a non modificarle!
on DetermineDiff @pLCSLength, @pOldSource, @pNewSource, pRow, pCol
   put pOldSource[pRow] into tOldLine #la riga nel file originale
   put pNewSource[pCol] into tNewLine #la riga nella nuova versione
   if pRow > 0 and pCol > 0 and tOldLine = tNewLine then
      #sono uguali, andiamo alla cella in alto a sinistra rispetto all'attuale nel LCLS            
      DetermineDiff pLCSLength, pOldSource, pNewSource, pRow - 1, pCol - 1
      put the htmltext of field versAdiff into temp
      set the htmltext of field VersAdiff to ( temp & prow & "&#9;" & tOldLine )
   else if pCol > 0 and (pRow = 0 or pLCSLength[pRow,pCol - 1]   >= pLCSLength[pRow - 1, pCol]) then
      ##caso la cella a sinistra è maggiore o uguale di quella sopra
      #è stata aggiunta una riga, moviamoci a sinistra nella tabella LCLS         
      DetermineDiff pLCSLength, pOldSource, pNewSource, pRow,   pCol - 1
      #set the text of field uscita to (field uscita & prow& "+" & tab & tNewLine & return )
   else if pRow > 0 and (pCol = 0 or pLCSLength[pRow,pCol - 1] < pLCSLength[pRow - 1, pCol]) then
      ##caso la cella a sinistra è minore di quella sopra
      #è stata rimossa una riga, saliamo di una riga nella tabella LCLS         
      DetermineDiff pLCSLength, pOldSource, pNewSource, pRow - 1, pCol
      put the htmltext of field VersAdiff into temp
      set the htmltext of field VersAdiff to (temp &"<font bgcolor=red>" & prow & "&#9;" & tOldLine & "</font>" )
   end if
end DetermineDiff

#abbiamo un messaggio che chiama se stesso parecchie volte
#qui usiamo le @ per risparmiare meomoria ed evitare troppe copie della stessa variabile, però stiamo attenti a non modificarle!
on DetermineDiff2 @pLCSLength, @pOldSource, @pNewSource, pRow, pCol
   put pOldSource[pRow] into tOldLine #la riga nel file originale
   put pNewSource[pCol] into tNewLine #la riga nella nuova versione
   if pRow > 0 and pCol > 0 and tOldLine = tNewLine then
      #sono uguali, andiamo alla cella in alto a sinistra rispetto all'attuale nel LCLS            
      DetermineDiff2 pLCSLength, pOldSource, pNewSource, pRow - 1, pCol - 1
      put the htmltext of field versBdiff into temp
      set the htmltext of field VersBdiff to ( temp & prow & "&#9;" & tOldLine )
   else if pCol > 0 and (pRow = 0 or pLCSLength[pRow,pCol - 1]   >= pLCSLength[pRow - 1, pCol]) then
      ##caso la cella a sinistra è maggiore o uguale di quella sopra
      #è stata aggiunta una riga, moviamoci a sinistra nella tabella LCLS         
      DetermineDiff2 pLCSLength, pOldSource, pNewSource, pRow,   pCol - 1
      put the htmltext of field VersBdiff into temp
      set the htmltext of field VersBdiff to (temp & "<font bgcolor=green>" & prow & "&#9;" & tNewLine & "</font>")      
   else if pRow > 0 and (pCol = 0 or pLCSLength[pRow,pCol - 1] < pLCSLength[pRow - 1, pCol]) then
      ##caso la cella a sinistra è minore di quella sopra
      #è stata rimossa una riga, saliamo di una riga nella tabella LCLS         
      DetermineDiff2 pLCSLength, pOldSource, pNewSource, pRow - 1, pCol   
   end if
end DetermineDiff2


Possiamo renderlo graficamente più professionale facendo in modo che muovendo un solo scroller, tutte i due testi scorrano contemporaneamente, mostrando sempre proporzionalmente la stesse parti. Ci basterà levare lo scroll verticale dal campo VersAdiff, e mettere nel secondo campo (VersBdiff) il seguente codice:

on scrollbardrag tdrag
   put the formattedheight of me into myh
   put the formattedheight of field versAdiff into ah
   put tdrag / myh into perc
   put round(perc * ah) into ah2
   set the vscroll of field "VersADiff" to ah2
end scrollbardrag

arrivati a questo punto, affiancandoli bene avremo il risultato voluto.
Come vedete si riesce a vedere bene cosa è stato aggiunto e cosa è stato levato.
Il programma è scaricabile da qui: diff.livecode
Questo tipo di analisi, tipica dell'informatica, è applicabile a qualunque campo. Voi dove l'applichereste?