21 gennaio 2012

Debutto tra le app Android

Facebook Friends Monitor: questo il nome della mia prima app nativa per Android (>=2.3).
La pagina del progetto è consultabile sul mio sito web, e spiega con più dettagli cos'è.




In breve, l'applicazione si compone di alcune activity e un service che monitora gli amici di Facebook e il loro status sulla chat, in modo che (in base a un sistema di priorità assegnate agli amici stessi) l'utente riceva una notifica quando un suo amico "monitorato" è disponibile per chattare.

Maggiori informazioni nella pagina del progetto.

27 novembre 2011

3+ script in python semplici e utili per sviluppatori

Avete scritto un solo file o un intero progetto i cui sorgenti sono suddivisi tra 100 directory e subdirectory?
Avete dimenticato di includere una delle licenze GPL all'inizio del file?
Avete dimenticato la shebang a inizio file?
Avete dimenticato di includere la vim modeline alla fine dei vostri file?

Allora questa serie di (per ora) 3 script scritti in python vi potrebbe essere utile.
Segnalate tranquillamente errori/miglioramenti/idee per altri script.
Sono nati in modo molto spartano per esigenze personali, li pubblico perchè potrebbero servire ad altre persone:

bzr branch lp:~lorenzosfarra/+junk/simpledevelutils

13 ottobre 2011

RIP Ritchie

Ero indeciso se scrivere 2 righe ma, visti i precedenti degli ultimi giorni, questo altrettanto (e probabilmente più) grande uomo merita una piccola citazione.
Sarò onesto, non avevo in mente il suo viso, o meglio l'ho sempre associato a questa figura :) :



Grazie per UNIX, il linguaggio C, il libro "The C Programming Language" (detto K&R).

04 ottobre 2011

intercettazioni di cultura

Non so cosa cercano gli utenti di Wikipedia, questo è un DL che rispetta la privacy in favore della popolazione italiana tutta. 1

http://it.wikipedia.org/wiki/Wikipedia:Comunicato_4_ottobre_2011



1: Questo è come avreste visto il messaggio corretto dai diretti interessati.
La mia versione originale era: non ho parole per lo scempio, da quando "DL" per esteso vuol dire "puttanata"?

18 settembre 2011

Roma - L'Aquila: i 100km più lunghi della storia

INTRODUZIONE
Quella che leggerete è una tragicomica verità.
Pensate che le unità di misura siano oggettive, matematiche, precise?
Non sulla A24. O meglio, non nel tratto urbano della A24 Roma - L'Aquila, dove i km sono più lunghi che in ogni altra parte del mondo.
Pensate che sia una storia lunga? Vi garantisco che c'è da divertirsi, e che seguirà almeno 1 altra puntata.

IL FATTO
L'ARPA (Autolinee Regionali Pubbliche Abruzzesi), gloriosa (si fa per dire) compagnia che a quanto ne so è l'unica a coprire questa tratta con un autobus, segnala sul biglietto che il tempo di percorrenza è di 1 ora e 40 minuti.
Tantino, ma ci può stare.
Fino a qualche mese fa la media del Venerdì sera intorno alle 19 era di circa 2 ore, gran parte passate nel tratto che dalla stazione Tiburtina porta al casello in zona Lunghezza, quasi a passo d'uomo per vari tratti.
Poi sono cominciati i lavori per le complanari, opera discutibile (es.: non si poteva potenziare la linea FR2 da Lunghezza a Tiburtina, senza altri Nmila milioni di euro per tonnellate di cemento?) che comporta la chiusura di ALMENO una corsia in entrambi i sensi, con tempi di percorrenza ormai diventati assurdi.
Un pendolare ha scritto questa interessante lettera aperta all'ARPA in cui spiega bene il problema, propone delle soluzioni e solleva il non banale problema del "confort" degli autobus.
Bene, a questa lettera è seguita una risposta del direttore dell'ARPA che io ho letto in un venerdì pomeriggio poco prima di ripartire da Roma verso L'Aquila.
In questa lettera si snobbano completamente le soluzioni proposte con un politichese ormai noto a noi poveri italiani, sottolineando che vengono investite grandi risorse su questa tratta: «lo dimostra l’anzianità media dei bus impiegati sull’Aquila - Roma che si attesta sui sette anni, a fronte di una media aziendale del parco autobus di 9 anni e mezzo».
Vorrei far presente che non è tanto l'età a rendere migliori/peggiori (suggerirei al direttore di dare uno sguardo a Sharon Stone), ma il valore assoluto delle cose, e come quest'ultime vengono gestite e mantenute.
Ma torniamo a noi.
Letta questa bellissima lettera mi dirigo da Termini verso Tiburtina con la metro B (NO COMMENT, almeno stavolta, per non dilungarmi ulteriormente!).
Bene, salgo sull'autobus sul quale il nostro direttore ha investito grandi risorse, ed ecco lo stato:





In pratica aria condizionata a SECCHIATE.
Considerando che l'autobus è sempre strapieno, qualcuno si doveva pur sedere in quei posti.
Io.
Ora, per me va anche bene, ma immaginate un anziano. Bene, dopo la vita passata per raggiungere l'autostrada, ecco comparire un cartello luminoso con la scritta "Veicolo fermo al km. 65".
Ovviamente ho subito pensato "100 euro che è un autobus dell'ARPA!". Peccato che non c'era nessuno con cui scommettere, adesso avrei 100 euro in più.

A questo aggiungiamo il fatto che le tariffe sono aumentate a inizio Settembre 2011, per cui il singolo biglietto andata-ritorno costa 1 euro in più.
Caro direttore, spero che con questo euro potrete finalmente comprare più carta per coprire le bocchette dell'aria condizionata.

14 agosto 2011

Ma veramente!? - Cronaca del crtime su sistemi Linux

Ok, non scrivo da un bel po' su questo blog, ma questa cosa vorrei condividerla.

LA PREMESSA
Non voglio dire di essere un grande esperto, ma ho comunque anni e anni di esperienza su sistemi Linux che rendono la questione ancora più interessante...e questo ha contribuito ancora di più a farmi sentire un pirla nella "scoperta" che ho fatto :)

IL FATTO
A lavoro per diverse ragioni dovevo risalire alla data di creazione di un file.
Bene, così per abitudine:

$ ls -l

mmh no vero, non c'è.

$ man ls

mmmh niente di utile.

$ stat

mmh Access, Modify e Change, ma niente Create o Creation.

$ man stat

[...]
%x Time of last access

%X Time of last access as seconds since Epoch

%y Time of last modification

%Y Time of last modification as seconds since Epoch

%z Time of last change

%Z Time of last change as seconds since Epoch
[..]
mmh niente da fare. Iniziano i primi FORTI dubbi. Al che per togliersene un bel po'

$ man 2 fstat

[..]
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for file system I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
};
[..]
ma...ma...NON C'È!

LA "SCOPERTA"
Finalmente è stato introdotto con l'arrivo di ext4.
In aggiunta ai campi tradizionali (access,modification,change) sono stati aggiunti il crtime(creation) e dtime(deletion) legati all'inode.
Al momento sembra mancare negli strumenti tradizionali (stat, find, ls) la possibilità di ottenere informazioni dal filesystem ext4 maggiori rispetto a quanto possibile per ext2 o ext3.
Per ottenere queste informazioni:

# debugfs -R 'stat /percorso/file' /dev/sda1

dove /dev/sda1 è il dispositivo su cui è montato il filesystem dove risiede il file di cui vogliamo vedere queste informazioni.

Inode: 524360 Type: regular Mode: 0644 Flags: 0x80000
Generation: 1374299388 Version: 0x00000000:00000001
User: 0 Group: 0 Size: 515
File ACL: 0 Directory ACL: 0
Links: 1 Blockcount: 8
Fragment: Address: 0 Number: 0 Size: 0
ctime: 0x4d62a41b:29f0e708 -- Mon Feb 21 18:42:51 2011
atime: 0x4e44d538:d129cbbc -- Fri Aug 12 09:24:40 2011
mtime: 0x4d62a41b:1d8b1d3c -- Mon Feb 21 18:42:51 2011
crtime: 0x4d62a41b:1d8b1d3c -- Mon Feb 21 18:42:51 2011
Size of extra inode fields: 28
EXTENTS:
(0):2167296

CONCLUSIONI
Le conclusioni in questa storia sono:
  1. non si finisce mai di imparare...;
  2. è terribile quando sei straconvinto di una cosa per anni e accorgersi che era completamente sbagliata;
  3. La maggior parte di chi legge aveva la mia stessa convinzione ma non lo dirà mai, anzi dirà che lo sapeva perfettamente;
  4. Non so che gli costava aggiungere questo campo anche prima.

Ogni altra aggiunta e spiegazione su questo fatto sono ben voluti.

12 maggio 2011

Finalmente si alza il sipario: ecco il nuovo sito di ubuntu-it

Signore e signori,
dopo mesi di durissimo lavoro (che in realtà è il lavoro-dopo-il-vero-lavoro-ovvero-tempo-libero) siamo felicissimi e fieri di presentare la nuova veste del sito ufficiale di ubuntu-it:



Un cambio che vede il passaggio ad un nuovo CMS (Drupal), una grande attenzione ai contenuti, e una grandissima attenzione all'aspetto grafico.
Alcuni aspetti non sono ancora stabili al 100% ma abbiamo deciso di non temporeggiare ulteriormente, e di verificare insieme agli utenti dove occorre intervenire.

Detto questo, non resta che godersi il sito.

Enjoy!

05 maggio 2011

ubuntu-it, il nuovo sito sta arrivando....

Il nuovo sito di ubuntu-it sta prendendo vita e manca davvero poco al suo esordio.
Un forte e costante lavoro che ha portato ad un risultato incredibile. Mancano pochi dettagli per andare online, questione di giorni...stay tuned!






20 aprile 2011

Ubuntu Party 2011 @ Schio

Mancano ormai pochi giorni al primo Ubuntu Party italiano.
L'evento si terrà a Schio, in provincia di Vicenza, il 30 Aprile e 1 Maggio 2011. Organizzato dalla Comunità Italiana Ubuntu, da AVi LUG e da Piazza Telematica del Comune di Schio.

Il nostro Fabio Colinelli ha preparato una piccola presentazione dell'evento:



Partecipate numerosi!

23 gennaio 2011

bash tip: impostare redirezione output dall'interno di uno script

Piccola ma utile tip.
Se si ha per qualche motivo la necessità di impostare la redirezione dell'output di uno script (stdout e/o stderr) senza utilizzare gli operatori per la redirezione (come ben descritto per esempio sul sito dell'ILDP) dall'interno dello script o direttamente dalla linea di comando, ecco una possibile soluzione:


#!/bin/sh

exec > prova.log 2 > &1

echo "queste due linee stampate"
echo "andranno in prova.log"

08 ottobre 2010

Ubuntu 10.10 in arrivo

Ci siamo quasi.
The next version of Ubuntu is coming soon

La Comunità di ubuntu-it è pronta per l'arrivo di Maverick Meerkat.
Utilizzo questa release dalla versione Beta, e devo ammettere che è davvero sorprendente.
Appuntamento a domenica.

03 settembre 2010

#iuseubuntubecause

Il Design Team di Canonical ha lanciato un'interessante iniziativa con lo scopo di migliorare il sito di Ubuntu e mettere in luce i motivi per cui usare la distribuzione stessa sottolineando le caratteristiche del prodotto.



Da qui l'idea di invitare gli utenti a inviare un tweet (twitter o identi.ca) con il tag #iuseubuntubecause e mostrarlo nel sito web, dando voce alla comunità sul sito stesso. Già è stato fatto un test interessante (twitter / identi.ca).

In realtà l'idea non è completamente nuova, in quanto microsoft aveva introdotto un servizio simile da tempo per il suo Windows 7.

25 agosto 2010

Piccoli tips & tricks con Smarty

Preparando il nuovo sito web (a breve completamente online, rimanete in attesa! :) ) ho utilizzato alcuni di questi metodi con Smarty che non sono complicati ma molto utili, e potrebbero risultare utili.

1. Mostrare l'età, che si aggiorna dinamicamente
In questo esempio verrà sempre mostrata la mia reale età (1985 è la mia data di nascita) sfruttando un'equazione matematica e utilizzando $smarty.now per recuperare l'anno corrente:


{math equation="x - 1985" x=$smarty.now|date_format:"%Y"}


2. Utilizzare le variabili della request
(In realtà non l'ho più utilizzato, meglio parsarle nel PHP)

Questi gli equivalenti rispettivamente di $_GET['item'], $_POST['item'], $_COOKIE['item']:

{$smarty.get.item}
{$smarty.post.item}
{$smarty.cookies.item}


3. Modifier 'default' per variabili vuote
Per controllare una variabile vuota, invece di diverse righe di codice e l'uso di un if come in questo caso:


{if $item eq ''}
default item value
{else}
{$item}
{/if}



si può sfruttare il modifier default in questo modo:

{$item|default:'default item value'}



4. Alternare stili CSS
Potrebbe essere il caso di liste o tabelle o altri elementi, nelle quali si vorrebbero alternare 2 colori diversi di background:


{foreach from=$projects name=workslist item=project}

{if $smarty.foreach.workslist.iteration is not odd}

{else}

{/if}
{/foreach}


Ancora più elegante potrebbe essere una soluzione con la funzione cycle.

5. Lista separata da un carattere
Ad esempio, se vogliamo stampare una lista di nomi separati da una virgola ma (ovviamente) evitare la virgola finale:

{section name=sectionname loop=$names}
{$names[sectionname]}{if $smarty.section.sectionname.last == false}, {/if}
{/section}

L'output sarebbe qualcosa come:
Warty, Feisty, Karmic, Breezy, Lucid

13 agosto 2010

ubuntu-it ha un nuovo contact

Milo Casagrande è il nuovo contact di ubuntu-it.
Complimenti a Milo e mille volte grazie a Matthew East per il lavoro svolto in tutti questi anni da contact e non solo.
La notizia ufficiale è consultabile sul sito web di ubuntu-it.

10 agosto 2010

forum admins @ work

Capita ogni tanto, ma proprio ogni tanto, di incontrarsi con coloro che lavorano su ubuntu-it e che si trovano a Roma, dove lavoro, o nei dintorni. Per questa sera abbiamo organizzato (con sottofondo della partita della nazionale) un incontro tra admins del forum di ubuntu-it, con volans (a casa sua, tra l'altro).
Verranno apportate delle modifiche al forum attuale e continueranno i test per la prossima piattaforma.
Non ci credete ancora? Ok...ecco a voi la prova fotografica presa con cheese..:

18 luglio 2010

Un terminale reale nel browser con JQuery e Django, parte II

Mentre la prima parte è incentrata sull'HTML, il codice javascript e il CSS, in questa seconda parte ci si concentrerà sul lato server-side, ovvero il codice python associato al framework Django.

Per la spiegazione del funzionamento di Django ovviamente rimando al sito ufficiale, in questo articolo vengono riportati solo i passaggi principali.
Vediamo innanzitutto il contenuto del file urls.py, che descrive lo schema delle URL di questa applicazione (molto semplice):

# Copyright (C) 2010 Lorenzo Sfarra (lorenzosfarra@ubuntu.com)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#


from django.conf.urls.defaults import *
from django.conf import settings

MEDIA_ROOT = settings.MEDIA_ROOT

urlpatterns = patterns('',
(r'^cmd/(?P.*)$', 'terminaljs.terminal.views.cmd'),
(r'^media/(?P.*)$', 'django.views.static.serve',
{'document_root': MEDIA_ROOT}),
(r'^$', 'terminaljs.terminal.views.index'),
)



Definiamo quindi che una URL con cmd/ iniziale richiama la view cmd con un parametro "command", il comando da eseguire. Definiamo inoltre che le URL con "media/" iniziale devono essere processate staticamente, ed infine definiamo la URL predefinita che richiama la view index.

Passiamo quindi a vedere il codice delle view, definito nel file views.py:


# Copyright (C) 2010 Lorenzo Sfarra (lorenzosfarra@ubuntu.com)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#


from django.shortcuts import render_to_response
from django.http import HttpResponse
from commands import getoutput
import os.path

# global variable
CWD = "/home/lorenzo"

def index(request):
return render_to_response("index.html")

def is_trusted_command(command):
#TODO: check if it's a trusted command
return True

def cmd(request, command):
global CWD
if command.startswith("cd "):
new_path = command.split(" ")[1]
if not new_path.startswith("/"):
# relative path
new_path = os.path.join(CWD, new_path)
if os.path.isdir(new_path):
CWD = new_path
output = ""
else:
output = "cd: " + new_path + ": No such file or directory"
elif is_trusted_command(command):
output = getoutput("cd %s; %s" %(CWD,command))
else:
output = "Untrusted command."
return HttpResponse(output)



Da sottolineare, così come fatto nella prima parte, la funzione is_trusted_command che deve essere implementata anche server-side.

Ovviamente il tutto è puramente dimostrativo, per chi fosse interessato a migliorarlo è presente tutto il codice su Google Code.

17 luglio 2010

Un terminale reale nel browser con JQuery e Django, parte I

Nell'articolo vediamo come realizzare un terminale che accetta comandi e che li esegue effettivamente su una macchina reale.
Questa prima parte si concentra sull'HTML, il codice Javascript e il CSS necessario.
La seconda parte verrà invece incentrata sul lato della programmazione python con il framework Django.
Il lato server è stato realizzato con il web framework Python Django, il lato client sfrutta la libreria JS JQuery anche per le chiamate AJAX.

L'HTML è piuttosto semplice e si trova nel file templates/index.html


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
<head>
<title>Lorenzo Sfarra :: DJSterminal</title>
<link rel="stylesheet" href="/media/css/terminal.css"/>
<script type="text/javascript"
src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
// You may specify partial version numbers, such as "1" or "1.3",
// with the same result. Doing so will automatically load the
// latest version matching that partial revision pattern
// (e.g. 1.3 would load 1.3.2 today and 1 would load 1.4.2).
google.load("jquery", "1.4.2");


</script>

<script src="/media/js/terminal.js" type="text/javascript">/* Terminal */</script>

<script type="text/javascript">
google.setOnLoadCallback(function() {
/* Handle the enter keycode */
$("#commandline").keypress(function(event) {
if (event.keyCode == '13') {
event.preventDefault();
onEnterKey();
}
});
});
</script>
</head>

<body>
<div id="terminal">
<div id="terminaltop"><img src="/media/css/imgs/buttons.png" alt="buttons" align="left"/> <br/>Javascript Terminal</div>

<!-- Command line -->
<textarea id="commandline" cols="80" rows="15">lorenzo@josie:~$ </textarea>
<!-- End command line -->
</div>
</body>
</html>


Nelle prime righe importiamo i file necessari. In particolare sfruttiamo Google per caricare la libreria JQuery.
Nelle linee 20-29 catturiamo il tasto Invio per gestire l'input come una riga di comando.

Il file terminal.js che contiene il sorgente javascript necessario si trova nella directory media/js, ed è il seguente:


/* Copyright (C) 2010 Lorenzo Sfarra (lorenzosfarra@ubuntu.com)

* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.

* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the
* GNU General Public License for more details.

* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA.
*/



// The command line prompt
var cliPrompt = "lorenzo@josie:~$ ";

// the server address where the real console exists
var cliHost = "http://localhost:8000/";

function isTrustedCommand(command) {
/**
* Function to check that the given command is trusted.
* @param command the command to check
* @return boolean
*/
// TODO: check that this is a trusted command!
return true;
}

function executeCommand(text, cliPrompt, command) {
/**
* Function to execute the given command through an AJAX call
* and retrieve the result to update the textarea value.
* @param text the current textarea value
* @param cliPrompt the prompt
* @param command the command to execute
*/
// build the URL for the command
remoteCommand = cliHost + "cmd/" + command;
output = "";
// Perform the AJAX call
$.ajax({
url: remoteCommand,
type: 'GET',
dataType: 'text',
error: function(data, textStatus, errorThrown) {
// readyState == 4? Error.
if (data.readyState == 4) {
output = "Connection error.\n"
}
},
success: function(data) {
output = data + "\n";
$("#commandline").val([text, output, cliPrompt].join("\n"));
// Textarea with focus at bottom
$("#commandline").animate({ scrollTop: 99999}, 10);
}
});

}

function onEnterKey() {
/* Function called when a user press the Enter key on its keyboard. */
text = $("#commandline").val();
// Get the command
promptIndex = text.lastIndexOf(cliPrompt);
// build the command
command = text.substring(promptIndex + cliPrompt.length);
if (command == "clear") {
// simply clear the textarea value
$("#commandline").val(cliPrompt);
} else if (isTrustedCommand(command)) {
executeCommand(text, cliPrompt, command);
} else {
output = "Invalid command.";
$("#commandline").val([text,output,cliPrompt].join("\n"));
}
}



La funzione principale è ovviamente executeCommand() che effettua la chiamata AJAX necessaria per eseguire realmente il comando sul server di riferimento.

ATTENZIONE: una funzione importantissima è isTrustedCommand(command) che ritorna "true" se il comando ha il "permesso" per essere eseguito. Questo ovviamente è necessario per proteggere il server. Al momento la funzione non effettua alcun controllo e ritorna immediatamente "true".

Il foglio di stile terminal.css si trova nella directory media/css.
Passa alla parte II ».

Per lo stile è stato preso come modello di riferimento il terminale presente nell'articolo "Forwarding E-Mails with Postfix".

19 giugno 2010

GoogleCL: Google Command Line Tool

GoogleCL è uno strumento creato da Google per interagire con alcuni dei suoi servizi direttamente dalla linea di comando.

Se si vuole aggiungere un contatto, un evento, un articolo sul blog Blogger (cosa che sto provando proprio per questo articolo), sarà possibile farlo quindi con un comando specifico. Questo articolo ad esempio, dopo aver creato il file post.html con il contenuto, è stato pubblicato con il comando:

google blogger post --tags "GoogleCL, terminale, linea di comando, Linux, Google" --title "GoogleCL: Google Command Line Tool" post.html
L'applicazione è scritta in python ed è già pronto un .deb, oltre ai sorgenti, sulla pagina del progetto.

12 giugno 2010

Top 5 Design del mese, Maggio

Ogni giorno visito vari siti web per studiarne la grafica e prendere ispirazione.
Catalogo spesso quelli che mi hanno più colpito, quindi condivido questi siti web nel blog, sperando che alcuni possano essere utili anche ad altri.
Continuiamo con altri 5 design :)

1. The Croquis (http://www.thecroquis.com)



2. BAHUR78 (http://www.bahur78.com/)



3. Kiwi (http://kiwi-app.net/)



4. Square (https://squareup.com/)



5. Narhir Design (http://www.narhir.com/)