domenica 5 aprile 2015

Che tipo di triangolo è? [Brevi Esercizi]

Salve!

È la vigilia di Pasqua, cosa faccio cosa non faccio, alla fine decido di scrivere uno script in bash.

Lo script chiede tre numeri interi, che sarebbero le misure dei lati di un triangolo, e restituisce il tipo del triangolo stesso, equilatero, isoscele, scaleno.

Può sembrare un'operazione semplice, ma in realtà non lo è. E non lo è per tutta una serie di ragioni. Anzitutto perché bash, confrontato con altri linguaggi, come Python ad esempio, non si presta molto a queste cose. Ed è proprio questo il bello. Spingersi oltre per vedere l'effetto che fa.

E poi, quando tutto sembra funzionare, vieni assalito da mille dubbi. E se al posto di un numero intero passi una stringa o un numero pari a zero o addirittura negativo? E poi bastano veramente tre lati per costruire un triangolo? Sì, bastano tre lati, ma non tre lati qualsiasi. Avete mai sentito parlare di disuguaglianza triangolare? La regola della disuguaglianza triangolare dice che ogni lato deve essere inferiore alla somma degli altri due. Vi faccio un esempio. Vi do la misura di tre lati, 1m, 2m, 80m, provate ora a costruire mentalmente un triangolo...Ecco, evidentemente un triangolo consta di tre lati, ma non basta, serve dell'altro.

E se passo allo script un numero decimale? Un casino, dovrei riscrivere alcune parti...magari lo lascio come esercizio, ci sarebbe bc... :)

Con Python è tutto più semplice, con bash mica tanto. Io ci ho provato. Sicuramente l'esercizio è migliorabile, perfezionabile e via dicendo.

#!/bin/bash

read -p "Digita la misura del primo lato: " a
read -p "Digita la misura del secondo lato: " b
read -p "Digita la misura del terzo lato: " c 


for i in $a $b $c; do
      if [ $i -gt 0 ] 2>/dev/null; then
             echo "" 
      else
             echo "devi immettere numeri interi e maggiori di zero" && exit 1
      fi
done


let d=$b+$c
let e=$a+$c
let f=$a+$b

if [[ $a -gt $d || $b -gt $e || $c -gt $f ]]; then
 clear
 echo -e "\nNon è stata rispettata la disuguaglianza triangolare\n" && exit 1
fi       


ordina=$( printf '%s\n' $a $b $c | sort -n )
risultato=$( uniq -c <<< "$ordina" | wc -l )

clear
case $risultato in
    1) echo -e "\nTRIANGOLO EQUILATERO\n" ;;
    2) echo -e "\nTRIANGOLO ISOSCELE\n"   ;;
    3) echo -e "\nTRIANGOLO SCALENO\n"    ;;
esac

Con read -p chiedo i tre lati. Poi il primo controllo. Se digito una stringa al posto di un numero intero oppure, se digito un numero non maggiore di zero, lo script mi ritorna exit 1. Ho usato un ciclo for, e il controllo lo fa l'operatore -gt che accetta solo numeri interi.
Poi il secondo controllo, quello della disuguaglianza triangolare, se ogni lato non è inferiore alla somma degli altri due, lo script mi ritorna un exit 1.

Passato questo secondo controllo, magari ne potremmo aggiungere altri, ma ora non mi viene niente, si passa all'elaborazione dei dati.

Printf mette in colonna i dati e sort -n li ordina. I dati ordinati vengono dati in pasto a uniq -c attraverso il "<<<", che si chiama here strings, e poi passati in input a wc -l.
P

Per capire che fa uniq -c dobbiamo fare un esempio. Poniamo che passi allo script i seguenti dati: 2 1 2

Questi tre dati vengono messi in colonna da printf:

2
1
2

Poi sort -n li ordina, dal più piccolo al più grande:

1
2
2

uniq -c conta quante volte compare un dato, in questo caso:

1 1
2 2

Infine wc -l conta quante righe ci sono. Se le righe sono 3, il triangolo è scaleno, se ce ne sono due, il triangolo è isoscele, se una, è equilatero.

Facciamo un altro esempio. Passo allo script i seguenti dati:  6, 4, 5;

printf li mette in colonna, sort -n li ordina, uniq -c conta le frequenze di ogni numero. In questo caso:

1 4
1 5
1 6

wc -l darà come risultato 3, che significa tre lati disuguali, quindi triangolo scaleno. E sarà il case a darci una risposta.


Alla prossima! E Buona Pasqua.

sabato 4 aprile 2015

Corso Lua - puntata 5 - Operazioni logiche e stringhe


Operatori logici

Gli operatori logici 'and' 'or' e 'not' danno luogo ad alcune espressioni idiomatiche di Lua.
Cominciamo con 'or': è un operatore logico binario. Se il primo operando è vero lo restituisce altrimenti restituisce il secondo.

Ricordatevi che in Lua un'espressione è vera se è il valore 'true' oppure se è un valore non nil, quindi per esempio nel seguente codice 'a' vale sempre 123.

local a = 123 or "mai assegnato"
print(a)


L'operatore 'and' restituisce il primo operando se esso è falso altrimenti restituisce il secondo operando.

Con and e or combinati otteniamo l'operatore ternario del C++ che è "a ? b:c" in Lua: Ecco l'espressione in un esempio di codice: se 'a' è vero restituisce 'b' altrimenti 'c':

local val = (a and b) or c

Poiché 'and' ha priorità maggiore rispetto a 'or' nell'espressione precedente possiamo omettere le parentesi per un codice più idiomatico:

local val = a and b or c


Il massimo tra due numeri è un'espressione condizionale:

local x = 45.69
local y = 564.3

local max
if x > y then
    max = x
else
    max = y
end

ma con gli operatori logici è tutto più Lua...
local x = 45.69
local y = 564.3

local max = (x > y) and x or y

L'operatore logico 'not' restituisce true se l'operando è nil oppure se è false --- valore booleano --- e viceversa restituisce false se l'operando non è nil oppure è true. Alcuni esempi:
print(not 5)       --> 'false'
print(not not 5)   --> 'true'
print(not true)    --> 'false'
print(not false)   --> 'true'
print(not nil)     --> 'true'

L'operatore di negazione può essere usato per controllare se una variabile è valida oppure no. Per esempio possiamo controllare se in una tabella esiste un campo 'prezzo':
local t = {} -- una tabella vuota

if not t.prezzo then -- t.prezzo è nil
    print("assente")
else
    print("presente")
end

t.prezzo = 12.00
if not t.prezzo then
    print("assente")
else
    print("presente")
end

Le stringhe

In Lua le stringhe rappresentano uno dei tipi di base del linguaggio.
Per rappresentare valori stringa letterali ci sono tre diversi delimitatori:
  • doppi apici: carattere ";
  • apice semplice: carattere ';
  • doppie parentesi quadre: delimitatori [[ e ]] con o senza =.

In una stringa delimitata da doppi apici possiamo inserire liberamente apici semplici e viceversa, e caratteri non stampabili come il ritorno a capo (\n) e la tabulazione (\t), tramite il carattere di escape backslash che quindi va inserito come doppio backslash:
local s1 = "doppi 'apici'"
local s2 = 'apici semplici e non "doppi"'
local s3 = "prima riga\nseconda riga"
local s4 = "una \\macro"
local s5 = "\""
assert( s5 == '"')

print(s1)
print(s2)
print(s3)
print(s4)
print(s5)

In Lua non esiste il tipo carattere quindi gli Autori del linguaggio hanno pensato di utilizzare i delimitatori normalmente destinati a rappresentare i char per consentire all'utente di creare stringhe contenenti i delimitatori doppi apici e viceversa, senza utilizzare l'escaping. Infatti i caratteri \" e \' rappresentano comunque i caratteri apici corrispondenti, come si vede nella variabile s5 del codice precedente.

Il terzo tipo di delimitatore per le stringhe è una coppia si parentesi quadre e ha la proprietà di ammettere il ritorno a capo. Si possono così introdurre nel sorgente interi brani di testo nel quale i caratteri di escaping non saranno interpretati.
local long_text = [[
Questo è un testo multiriga
dove i caratteri di escape non contano
come \n o \" o \' o \\.

Inoltre, se il testo come in questo caso
comincia con un ritorno a capo allora questo
carattere \n sarà ignorato.
]]

print(long_text)

Se per caso nel testo fossero presenti i delimitatori di chiusura è possibile inserire un numero qualsiasi di caratteri '=' tra le parentesi quadre, purché il numero sia lo stesso per i delimitatori di apertura e chiusura, esempio:
local long_text = [=[
Questo è il codice Lua da stampare:

local tab = {10, 20, 30}
local idx = {3, 2, 1}
print(tab[idx[1]]) -- notare doppia parentesi quadra chiusa

local long_text = [[ -- questo non potremo farlo...
    Testo lungo...
]]

Tutto chiaro?
In Lua le stringhe letterali nel codice
possono essere proprio letterali
senza caratteri di escape e senza
preoccupazioni sulla presenza di gruppi
di delimitazione di chiusura...
]=]

print(long_text)

Commenti multiriga

Questi delimitatori variabili con numero qualsiasi di segni '=' li troviamo nei commenti multiriga di Lua. Abbiamo incontrato fino a ora i commenti di riga che si introducono nel codice con un doppio trattino '--'.

I commenti multiriga sono comodi quando si vuol escludere dall'esecuzione un intero blocco di righe: iniziano con i doppi trattini seguiti da un delimitatore di stringa multiriga e terminano con la corrispondente chiusura:
-- questo è un commento di riga

--[[
questo è un commento
multiriga
]]

--[=[
e anche questo è un commento
multiriga
]=]

Normalmente in Lua i commenti multiriga vengono chiusi premettendo i doppi trattini anche al gruppo delimitatore di chiusura. Questo è solo un trucco per riattivare rapidamente il codice eventualmente contenuto nel commento, basta uno spazio per far diventare il commento multiriga :
--[[ righe di codice non attive

local tab = {}
--]]

-- [[ notare lo spazio dopo i doppi trattini
-- questo codice invece viene eseguito

local tab = {}
--]] -- e questo diventa una normale riga di commento

L'editor SciTE che vi consiglio per scrivere il codice Lua, è in grado di colorare correttamente il testo dei commenti di riga e di quelli multiriga.

Concatenare stringhe e immutabilità

In Lua l'operatore '..' concatena due stringhe, in questo modo:
local s1 = "Hello" .. " " .. "world"
local s2 = s1 .. " Ok"
s2 = s2 .. "."

print(s1 .. "!")
print(s2)

Il concetto importante riguardo alle stringhe è se queste siano o no immutabili. Se non lo sono la concatenazione di stringhe non comporta la creazione di una nuova stringa risultato dell'operazione. In Lua, come in molti altri linguaggi, le stringhe sono invece immutabili.
Ciò significa che una volta create le stringhe non possono essere modificate e nel codice precedente, l'operazione di concatenare il carattere punto in coda alla stringa 's2', genera una nuova stringa che è assegnata alla stessa variabile.

Per poche operazioni di concatenazione ciò non è un problema, ma in alcuni casi invece si. Consideriamo il seguente codice apparentemente innocuo:
local s = ""

for i = 1, 100 do
    s = s .. "**"
end

print(#s) -- l'operatore length funziona anche per le stringhe!

Ma cosa succede in dettaglio? Perché questo codice non è efficiente?
Ad ogni concatenazione viene creata una nuova stringa. La prima volta vengono copiati due byte per dare la stringa "**". La seconda iterazione la memoria copiata sarà di 4 byte, e alla terza di 6 byte, eccetera.
Ad ogni iterazione la memoria copiata cresce di due byte con il risultato che per produrre una stringa di 200 asterischi (200 byte) avremo copiato in totale la memoria equivalente a 10100 byte!

In Java e negli altri linguaggi con stringhe immutabili normalmente si corre ai ripari mettendo a disposizione una struttura dati o una funzione che risolve il problema, per esempio un tipo StringBuffer. In Lua la soluzione è una funzione della libreria table che, anticipando rispetto alle nostre chiaccherate è table.concat():
local t = {}
for i = 1, 100 do
    t[#t + 1] = "**"
end

print(#table.concat(t))

Per la cronaca, nel caso specifico avremo dovuto usare la funzione string.rep() ma table.concat() è più generale.

Esercizi


1 - Prevedere il risultato delle seguenti espressioni Lua:
local a = 1 or 2
local b = 1 and 2
local c = "text" or 45

local d = not 12 or "ok"
local e = not nil or "ok"

2 - Usando gli operatori logici di Lua codificare l'espressione che restituisce la stringa "grande", "uguale" o "piccolo" a seconda dei valori numerici contenuti in due variabili.

3 - Come fare in Lua per creare una stringa letterale contenente sia il carattere apice semplice che doppio?

4 - Quale sarà il risultato dell'esecuzione del seguente codice?

local s = "'"..'"'.."ok"..[["']]
print(s)

5 - Creare la stringa "\/".

6 - Scrivere un programma che a partire dalla stringa "*" crei e stampi la stringa di 64 asterischi senza utilizzare l'operatore di concatenazione o la funzione string.rep().

7 - Scrivere un programma che a partire dalla stringa "*" crei e stampi la stringa di 64 asterischi usando l'operatore di concatenazione il minimo indispensabile di volte.

Riassunto della puntata

Oggi abbiamo introdotto gli operatori logici, le modalità di inserimento delle stringhe e la loro concatenazione. Una puntata un po' noiosa se vogliamo, ma questi dettagli devono pur essere conosciuti per programmare.

D'altra parte non possiamo --- specie per le stringhe --- studiare esempi significativi fino a che non avremmo introdotto la libreria standard di Lua che a sua volta non possiamo introdurre fino a che non avremmo parlato delle funzioni.

E allora facciamolo, la prossima volta parleremo delle funzioni in Lua.
Alla prossima.

venerdì 3 aprile 2015

Lubit & Cloud

Salve, 
iniziamo con una domanda:

Chi di voi usa, o ha usato almeno una volta, il famoso Dropbox, oppure Box.net, Google drive, skyDrive, solo per citare alcuni tra i più famosi?


Sicuramente molti! 


I servizi di archiviazione cloud disponibili in rete sono ormai davvero tanti e molto utili, alcuni sono anche gratuiti sebbene con dei limiti.
Questi servizi ci permettono, come è noto, di conservare i nostri files in servers remoti, sicuri e veloci ma non di nostra proprietà e con dei limiti di capacità e personalizzazione, almeno nelle versioni gratuite.
A volte, come nel mio caso, capita di utilizzare più servizi avendo così i files sparsi nei vari cloud.
Come fare quindi per avere una soluzione analoga a quelle commerciali, che sia di nostra proprietà dove possiamo implementare tutte le funzionalità che ci servono e magari che faccia anche da aggregatore dei files che abbiamo sparsi in giro nei vari cloud?
Beh, una valida risposta per creare un nostro cloud privato è il software open source OwnCloud.
In questo articolo vedremo come installarlo e configurarlo partendo da zero con solo un sistema linux, naturalmente Lubit :).
La scelta di Lubit linux si addice molto bene al lavoro che andiamo a realizzare perché è un sistema operativo molto leggero , veloce e che necessita di poche risorse di sistema. 

Pronti? Iniziamo! 

Prepariamo l'ambiente server

Owncloud è un applicativo web, funziona quindi come un sito web.
Per quanto riguarda la gestione degli archivi si può scegliere, in fase di installazione, di utilizzare Sqlite, strumento più leggero ma poco adatto a un uso intensivo, oppure si può usare mysql o postgresql.
Per realizzare il nostro cloud personale utilizzeremo il più robusto e affidabile mysql che ci consente di avere una soluzione più adatta anche all' uso da parte molti utenti.
Come primo passo andiamo ad installare il server web apache2, il supporto per php e mysql, per fare ciò con lubit procediamo da riga di comando digitando nel terminale:
 
aggiorniamo il sistema



sudo apt-get update 
sudo apt-get upgrade

installiamo  l’ambiente LAMP


sudo tasksel install lamp-server


ci viene chiesta la password per l’utente root di mysql , la digitiamo , e l’installazione viene completata. (consiglio di annotare la password, servirà più avanti)
A questo punto abbiamo tutto quello che ci serve per poter proseguire con l’installazione di OwnCloud.

Installiamo OwnCloud

 Da terminale digitiamo:

per scaricare  le chiavi: 
 


wget http://download.opensuse.org/repositories/isv:ownCloud:community/xUbuntu_14.10/Release.key


sudo apt-key add - < Release.key

fatto questo aggiungiuamo il repo ufficiale al source.list e aggiorniamo:

sudo sh -c "echo 'deb http://download.opensuse.org/repositories/isv:/ownCloud:/community/xUbuntu_14.10/ /' >> /etc/apt/sources.list.d/owncloud.list"


sudo apt-key add - < Release.key


sudo apt-get update
a questo punto procediamo con l’installazione digitando

sudo apt-get install owncloud

Creiamo il database

Come dicevo all’ inizio abbiamo scelto di usare mysql, quindi dobbiamo creare un database riservato a owncloud.

Da terminale digitiamo:

mysql -u root -p


digitiamo la password di root che abbiamo inserito al momento dell’ installazione.

A questo punto ci troviamo nel prompt di mysql, digitiamo:

create database daticloud;


Creiamo l’utente per il database e diamogli i  privilegi:

grant all privileges on daticloud.* to 'utente'@'localhost' identified by 'password' with grant option;


dove al posto di utente scriviamo il nome utente e in password la password per l’utente creato.

digitiamo quit per uscire da mysql.
Ok adesso siamo pronti ad usare il nostro cloud personale? beh si, ma c’è da tener presente che tutti i dati gestiti dal nostro sistema , fino ad ora, vengono trasmessi “in chiaro” e quindi potrebbero essere intercettati.

Per ovviare al problema procediamo  ad installare il supporto alla cifratura ssl.

Un pò di sicurezza! 

Sempre da terminale digitiamo:

sudo apt-get install openssl
sudo a2enmod ssl
sudo mkdir /etc/apache2/ssl
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/apache2/ssl/owncloud.key -out /etc/apache2/ssl/owncloud.crt

a questo punto il sistema genera il certificato e le chiavi ssl , per fare questo ci richede delle informazioni.

Riassumendo i campi richiesti (e le risposte suggerite) sono:

Country Name ( IT);
State (Italia);
Locality Name (possiamo lasciare vuoto);
Organization Name (un nome qualsiasi);
Organization Unit Name (lasciamo vuoto);
Common Name (IP pubblico, il nostro dominio dinamico o l’indirizzo web del server);
email (possiamo lasciare vuoto).

ora abilitiamo i certificati appena creati digitando:

sudo leafpad /etc/apache2/sites-available/default-ssl.conf


 modifichiamo le voci come segue:

ServerName (IP-pubblico digitato in Common Name)
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/owncloud.crt
SSLCertificateKeyFile /etc/apache2/ssl/owncloud.key

Se alcune di queste voci non vengono trovate si può tranquillamente digitarle in uno spazio vuoto .

Salviamo il file di configurazione e da terminale digitiamo:


sudo a2ensite default-ssl
sudo service apache2 restart

Finalmente ci siamo.
Adesso siamo pronti per il  primo accesso al nostro cloud e al wizard di configurazione.

Da web browser andiamo all’ indirizzo:

https://localhost/owncloud

Il browser ci avvertirà che il stiamo facendo accesso ad un sito cifrato, clicchiamo su “sono consapevole dei rischi”, poi “aggiungi eccezione”
 



 

seguito da “acquisisci certificati” e “conferma eccezione di sicurezza” . 



Ecco che ci appare la schermata di configurazione di OwnCloud !!!
 


compiliamo il form con i dati richiesti:

nome utente  e  password

clicchiamo su Storage & database quindi scegliamo mysql e nei campi a seguire digitiamo l’utente creato per il database e la sua password,
il nome del database “daticloud” e lasciamo inalterato localhost.



Confermiamo e, se tutto è andato per il verso giusto, in pochi secondi ci troveremo il nostro server cloud perfettamente funzionante.

Per ultimo attiviamo la forzatura del protocollo https  andando nel menu in alto a destra (sul nostro nome utente) e scegliendo “Admin”  spuntiamo la voce “Forza HTTPS”.

Finito! 

Resterebbe da configurare le porte del nostro router per poter accedere al sistema da remoto ma questa è un'altra storia ;)
 
Saluti.

giovedì 2 aprile 2015

Le funzioni ord() e chr(). [Brevi Esercizi]

Salve!

Oggi facciamo un breve esercizio con Python3.

Problema.

Se a Python do in pasto la stringa "baro", mi dovrà restituire la stringa "caro". In altri termini, mi dovrà sostituire il primo carattere di una stringa con quello successivo nell'alfabeto e poi stamparlo

Gli ingredienti per svolgere l'esercizio.

La funzione ord() mi restituisce il codice corrispondente al carattere nella scala unicode

Esempio, se nella shell di Python scrivo

>> ord("b")

la funzione ord() mi restituirà 98, che rappresenta il codice corrispondente al carattere nella scala unicode.

Se poi scrivo:

>> chr(98)

Avrò come risultato

'b'

La funzione chr() traduce il codice 98 nella lettera corrispondente, che è "b". Abbiamo fatto così la prova del nove.

Ancora, come faccio a conoscere il primo carattere di una stringa, tenuto anche conto che python inizia a contare sempre da zero?

>> parola = "baro" #Variabile
>> parola[0] #Cerco il primo carattere della stringa "baro"

la shell mi restituirà "b"

Ecco, penso che ora abbiamo tutti gli elementi per svolgere l'esercizio.


>> print(chr(ord(parola[0])+1) + parola[1:])

Abbiamo detto che la funzione ord() trasforma, in questo caso, la lettere b in un codice. Questo codice, che sappiamo essere 98, lo sommiamo ad 1, quindi diventerà 99, che la funzione chr() tradurrà nel carattere corrispondente, che è "c", successivo a "b" nell'alfabeto. Poi sommiamo il carattere "c" con la stringa "baro", escluso il primo carattere. Infine passiamo tutto alla funzione print(), il cui compito è quello di stampare a video il risultato.


Ritornerò con gli esercizi di Python3 ogni giovedì.

Alla prossima!