Amarok logoMettiamo che, come il sottoscritto, reputate la vecchia versione di Amarok (Amarok 1.4) come la migliore. Mettiamo che, come il sottoscritto, volete ancora utilizzarla sulla vostra Debian (qualsiasi versione).

Bene, Amarok 1.4 è ancora presente – al momento in cui scrivo – su Debian Lenny, l’attuale old-stable: vediamo come reperirlo, come conservarlo (prima o poi i repository di Debian Lenny andranno off, anche se con un po’ di impegno si può accedere ancora a repository molto più vecchi, che qualcuno conserva qua e là) e come installarlo.

Innanzitutto, se i repository di Debian Lenny sono ancora disponibili, configuriamo il pinning (se non lo abbiamo ancora fatto) come spiegato qui e poi aggiungiamo al nostro sources.list il repository:

deb http://ftp.it.debian.org/debian/ lenny main contrib non-free

Fatto questo, aggiorniamo e poi scarichiamo i pacchetti che ci servono (li scarichiamo proprio per conservarli per il futuro):

aptitude update
aptitude -t lenny download amarok amarok-common amarok-engine-xine libgpod3-nogtk libmtp7 libmysqlclient15off

I pacchetti verranno scaricati nell’attuale directory e dovrebbero essere (può cambiare l’architettura):

amarok_1.4.10-2lenny1_i386.deb
amarok-common_1.4.10-2lenny1_all.deb
amarok-engine-xine_1.4.10-2lenny1_i386.deb
libgpod3-nogtk_0.6.0-6_i386.deb
libmtp7_0.2.6.1-3_i386.deb
libmysqlclient15off_5.0.51a-24+lenny5_i386.deb

Semmai i repository di Lenny non dovessero essere più presenti, ho preparato un archivio con questi pacchetti per 32bit e 64bit. Scaricate e decomprimete.

Fatto questo, è necessario procedere con l’installazione di alcune dipendenze necessarie:

aptitude install kdelibs4c2a libqt3-mt libifp4 libkarma0 libnjb5 libpq5 libtunepimp5

Notate che queste dipendenze dovrebbero essere presenti anche nella vostra versione di Debian, quindi in questo caso non si necessita di pinning. Le dipendenze non più presenti (cioè obsolete) le abbiamo già reperite. Bisogna prima installare queste perché il resto verrà installato tramite dpkg, che non si preoccupa di installare eventuali dipendenze mancanti.

Infatti, a questo punto non resta che installare Amarok e le dipendenze ormai obsolete. Nella cartella in cui abbiamo precedentemente scaricato:

dpkg -i amarok*.deb libgpod3-nogtk*.deb libmtp*.deb libmysqlclient15off*.deb

Ed è fatta. Due accorgimenti:

  1. il lanciatore nel menù è nascosto di default, quindi (in Gnome 2) click destro del mouse sul menù, “Modifica menù”, andate sotto “Audio e video” e mettete la spunta alla relativa opzione;
  2. il nostro gestore dei pacchetti, rilevata una versione più recente di Amarok, insisterà nel farci aggiornare. Per risolvere è sufficiente bloccare i pacchetti amarok e amarok-common. In aptitude:
    aptitude hold amarok amarok-common

    In synaptic cercate (guardate sotto “Installato (aggiornabile)”) i due pacchetti, selezionatene uno alla volta, poi andate sul menù “Pacchetto” e mettete la spunta a “Blocca versione”.
    Notate che dovete seguire entrambe le procedure.

Et voilà:

Amarok

Sometimes we need some dependencies are installed on the operating system to run a bash script. So you can create a script that installs the missing dependencies.

After making a list of required dependencies, there are two ways to do this:

  1. pass the entire list to the package manager. Then the package manager will check which packages are already installed and will proceed with the installation of those that are missing;
  2. check what dependencies are already installed, make a list of dependencies that are missing, then pass to the package manager only missing dependencies list.

The second choice is the best choice, besides being more elegant. First, because it has a better chance of success (by hypothesis, some package managers may not work, if we ask it to install a package that’s already installed); second, ’cause if we were having some problems with the installation (for whatever reason), we can say exactly to the user what are the packages that he has to install manually.

Now let’s see what we have to do. As I have already said, we should:

  1. make a list of required dependencies (it’ll be the DEPENDENCIES array);
  2. check what dependencies are missing and save them in a new list (it’ll be the PKGSTOINSTALL string);
  3. install missing dependencies (from the PKGSTOINSTALL string).

Well, let’s go to the code. We need to create a list of required dependencies, for example foo and bar packages:

DEPENDENCIES=(foo bar)

Now we need to check which of those packages are already installed. The missing packages will be added to the PKGSTOINSTALL string, separated by a space:

# What dependencies are missing?
PKGSTOINSTALL=""
for (( i=0; i /dev/null; then
		if [[ ! `dpkg -l | grep -w "ii  ${DEPENDENCIES[$i]} "` ]]; then
			PKGSTOINSTALL=$PKGSTOINSTALL" "${DEPENDENCIES[$i]}
		fi
	# OpenSuse, Mandriva, Fedora, CentOs, ecc. (with rpm)
	elif which rpm &> /dev/null; then
		if [[ ! `rpm -q ${DEPENDENCIES[$i]}` ]]; then
			PKGSTOINSTALL=$PKGSTOINSTALL" "${DEPENDENCIES[$i]}
		fi
	# ArchLinux (with pacman)
	elif which pacman &> /dev/null; then
		if [[ ! `pacman -Qqe | grep "${DEPENDENCIES[$i]}"` ]]; then
			PKGSTOINSTALL=$PKGSTOINSTALL" "${DEPENDENCIES[$i]}
		fi
	# If it's impossible to determine if there are missing dependencies, mark all as missing
	else
		PKGSTOINSTALL=$PKGSTOINSTALL" "${DEPENDENCIES[$i]}
	fi
done

With a loop we will be checked every necessary dependency. Dpkg will be used for the deb-based distros (Debian, Ubuntu and derivatives, as Mint), rpm for the rpm-based (OpenSuse, Mandriva, Fedora, CentOs, etc.) and pacman for ArchLinux. If none of these is available on the system (for whatever reason), all the required dependencies will be marked as missing.

At this point, as I said before, the PKGSTOINSTALL string contains the list of required dependencies that are missing. We can proceed to install them:

# If some dependencies are missing, asks if user wants to install
if [ "$PKGSTOINSTALL" != "" ]; then
	echo -n "Some dependencies are missing. Want to install them? (Y/n): "
	read SURE
	# If user want to install missing dependencies
	if [[ $SURE = "Y" || $SURE = "y" || $SURE = "" ]]; then
		# Debian, Ubuntu and derivatives (with apt-get)
		if which apt-get &> /dev/null; then
			apt-get install $PKGSTOINSTALL
		# OpenSuse (with zypper)
		elif which zypper &> /dev/null; then
			zypper in $PKGSTOINSTALL
		# Mandriva (with urpmi)
		elif which urpmi &> /dev/null; then
			urpmi $PKGSTOINSTALL
		# Fedora and CentOS (with yum)
		elif which yum &> /dev/null; then
			yum install $PKGSTOINSTALL
		# ArchLinux (with pacman)
		elif which pacman &> /dev/null; then
			pacman -Sy $PKGSTOINSTALL
		# Else, if no package manager has been founded
		else
			# Set $NOPKGMANAGER
			NOPKGMANAGER=TRUE
			echo "ERROR: impossible to found a package manager in your sistem. Please, install manually ${DEPENDENCIES[*]}."
		fi
		# Check if installation is successful
		if [[ $? -eq 0 && ! -z $NOPKGMANAGER ]] ; then
			echo "All dependencies are satisfied."
		# Else, if installation isn't successful
		else
			echo "ERROR: impossible to install some missing dependencies. Please, install manually ${DEPENDENCIES[*]}."
		fi
	# Else, if user don't want to install missing dependencies
	else
		echo "WARNING: Some dependencies may be missing. So, please, install manually ${DEPENDENCIES[*]}."
	fi
fi

Now I’ll explain this portion of code. First of all, the script asks the user if he wanna proceed with the installation (else, it will tell the user which packages have to install manually). Then it proceeds by using the package manager avaible on the system: apt-get for Debian, Ubuntu and derivateves, zypper for OpenSuse, urpmi for Mandriva, yum for Fedora and CentOS and pacman for Archlinux.

If none is available, the user indicates which packages have to install manually. Finally it verifies if the installation was successful and in case of problems, again, alerts the user.

Good luck.

(in italiano: Bash scripting: verificare e installare dipendenze mancanti)

CakePHPAs you know, CakePHP can manage flash messages, information messages for the user that are stored by and in session. They are particularly used to notify some operations (result of authentication operations, operations on the database, etc..).

Essentially, flash messages are used whenever you want to say to an user: “hey man, everything is fine, or something went wrong”.

As the CakePHP documentation explains:

Often in web applications, you will need to display a one-time notification message to the user after processing a form or acknowledging data. In CakePHP, these are referred to as “flash messages”. You can set flash messages with the SessionComponent and display them with the SessionHelper::flash(). To set a message, use setFlash.

To store a message inside a controller, you can use the setFlash() method (API) provided by SessionComponent; to show a message inside a view, you can instead use the flash() method (API) provided by SessionHelper.

For example, inside a controller like this:

public function myAction() {
   // do something...
   $this->Session->setFlash("it works!");
   // do something...
}

Inside a view:

Session->flash(); ?>

As my example says, this will work correctly and will produce this html:

<div id="flashMessage" class="message">it works!</div>

This is really nice, especially because flash messages are “one-time messages” and the developer doesn’t have to worry about manage directly the session (Cake’s core will take care of this, not you). But there are problems when you wanna store more messages in a single action of a controller. Indeed this one:

public function myAction() {
   // do something...
   $this->Session->setFlash("does it work?");
   $this->Session->setFlash("it works!");
   // do something...
}

will remember only the second flash message. And the first one? Another problem is: and if I wanted to differentiate between different types of messages (for example: warnings, errors, confirmations, etc..)?
As the documentation explains, “using the $key parameter you can store multiple messages, which can be output separately” (quoting the documentation example):

// set a bad message.
$this->Session->setFlash('Something bad.', 'default', array(), 'bad');
// set a good message.
$this->Session->setFlash('Something good.', 'default', array(), 'good');

These flash messages will be output as html and styled differently:

// in a view.
echo $this->Session->flash('good');
echo $this->Session->flash('bad');

You can also pass a class in $params array using again $this->Session->setFlash:

$this->Session->setFlash('Example message text', 'default', array('class' => 'example_class'));

Using $this->Session->flash(), the output will be:

<div id="flashMessage" class="example_class">Example message text</div>

But all this is very uncomfortable to use and is very difficult to develop using the proposal syntax.
So, how to solve? It’s simple: rewrite component and helper.
First, you need to copy

lib/Cake/Controller/Component/SessionComponent.php

in

app/Controller/Component/

and

lib/Cake/View/Helper/SessionHelper.php

in

app/View/Helper/

This allows you to override the classes of Cake’s core with yours, that will be used first (note: you must not edit directly Cake’s core, never! Just rewrite components, helpers, views, etc.).

Then, in app/Controller/Component/SessionComponent.php replace the setFlash() function with this one:

public function setFlash($message, $type="message") {
	//If flash messages are already stored in session, fetch array
	if(CakeSession::check('flashMessages'))
		$messages = CakeSession::read('flashMessages');
	//Else, create a new empty array
	else
		$messages = array();
	//If the flash message type is not supported (only "error", "notice", "success" and "warning"), set it to "notice"
	if(!in_array($type = strtolower($type), array("error", "notice", "success", "warning")))
		$type = "notice";
	//Add the passed flash message to the array
	$messages[$type][] = $message;
	//Store in sessione
	CakeSession::write('flashMessages', $messages);
}

With this, now you can store flash messages like this (it will store an error):

echo $this->Session->flash('something has gone wrong', 'error');

Again, in app/View/Helper/SessionHelper.php replace the flash() function with this one:

public function flash() {
	//Check if flash messages are stored in session
	if(CakeSession::check('flashMessages')) {
		//Retrieve saved flash messages and deletes them from the session
		$messages = CakeSession::read('flashMessages');
		CakeSession::delete('flashMessages');
		//Prepare the $out variable that will contain the final output
		$out = "";
		//Loop every flash message that is stored in session, appending to the variable $out
		foreach ($messages as $type => $message) {
			foreach ($message as $text)
				$out .= '<div class="'.$type.'">'.$text.'</div>';
		}
		//Return flash messages in html
		return $out;
	}
}

It will return flash messages as:

<div class="$type">$text</div>

Now a new example. Inside your controller:

$this->Session->setFlash("This is just a warning", "warning");
$this->Session->setFlash("It's ok!", "success");
$this->Session->setFlash("Something seems to have gone wrong", "error");
$this->Session->setFlash("A simple, innocent news.", "notice");

It will be displayed like this:

<div class="warning">This is just a warning</div>
<div class="success">It's ok!</div>
<div class="error">Something seems to have gone wrong</div>
<div class="notice">A simple, innocent news.</div>

Wonderful, is not it?

Since we are here, just add a little style for flash messages. In the view, you have to display messages like this:

<div id="flashMessages">
	<?php echo $this->Session->flash(); ?>
</div>

Download these files and move them to app/webroot/img/, then add to your style sheet:

#flashMessages div {
	background: no-repeat 5px 5px;
	border-radius: 5px;
	border-style: solid;
	border-width: 2px;
	box-shadow: 0 5px 5px -5px #555;
	margin-bottom: .5em;
	min-height: 24px;
	padding: 5px 10px 5px 35px;
}

#flashMessages .error {
	background-color: #FFCCCC;
    background-image: url("/img/error.png");
    border-color: #8F0000;
    color: #8F0000;
}

#flashMessages .notice {
	background-color: #e6ecf2;
	background-image: url("/img/notice.png");
	border-color: #314e6c;
	color: #314e6c;
}

#flashMessages .success {
    background-color: #DEFADE;
    background-image: url("/img/success.png");
    border-color: #267726;
    color: #267726;
}

#flashMessages .warning {
    background-color: #FFEEBF;
    background-image: url("/img/warning.png");
    border-color: #B87D00;
    color: #B87D00;
}

This is the result:

flash messages

A great work guys! ;-)

Pillola del giorno dopoL’articolo è qui, a firma di Cinzia Sasso. Si legge chiaramente come una ragazza, per abortire, abbia fatto ricorso alla pillola del giorno dopo. Le ipotesi plausibili (o meglio: che mi vengono in mente) sono due:

  1. la giornalista è venuta a sapere che la ragazza aveva fatto uso della pillola del giorno dopo e ha dedotto (erroneamente) che ha abortito e che quindi fosse rimasta incinta;
  2. viceversa, che la ragazza era rimasta incinta e ha abortito e ha dedotto (sempre erroneamente) che l’abbia fatto tramite l’uso della pillola del giorno dopo.

In ogni caso – diciamo per sintesi – la giornalista ha lavorato di fantasia per arricchire l’articolo. E il risultato è quello che si vede.

Il problema è che la discussione su aborto da una parte e contraccettivi dall’altra, ad oggi, nel nostro Paese, è basata quasi esclusivamente sulla disinformazione, sia di chi è contrario ai due (soprattutto), sia (anche e non di meno) di chi è favore delle due o di una delle due.
In questo contesto, un giornalista può permettersi, senza troppe responsabilità, di alimentare la disinformazione? Non si sente la necessità di aderire a un codice deontologico oppure, quanto meno, di informarsi come requisito per informare (“informarsi per informare…”), assumendo che si sia in buona fede?

Avevo già scritto qualcosa sui menù a tendina, arrivando a consigliare di utilizzare SuperFish, che a tutt’ora considero un ottimo plugin. Vediamo però come realizzare da zero un menù a tendina completo, utilizzando solo e semplicemente Jquery e limitandoci (per questo articolo, più in là semmai approfondirò) a un solo livello di profondità (in altri termini: i sotto-menù, a loro volta, non si espanderanno).

Due piccole premesse:

  1. dovete conoscere bene html e css, in quanto qui ci limiteremo (per questi due) allo stretto indispensabile;
  2. qui utilizzeremo un menù principale orizzontale (quindi le voci del menù affiancate) con sotto-menù in verticale (quindi voci elencate). Nulla toglie che poi, in base alle proprie esigenze e con le giuste modifiche, si possa operare diversamente (esempio: entrambi verticali).

Innanzitutto è necessario e doveroso scrivere del codice html pulito e conforme. Potete tenere a riferimento le considerazioni già espresse nel precedente articolo, e quindi scrivere un codice di questo genere:

<ul>
	<li><a href="pagina1.html">Pagina 1</a></li>
	<li>
            <a href="#">Pagina 2</a>
            <ul>
               <li><a href="paginaA.html">Pagina A</a></li>
               <li><a href="paginaB.html">Pagina B</a></li>
               <li><a href="paginaC.html">Pagina C</a></li>
            </ul>
        </li>
	<li><a href="pagina3.html">Pagina 3</a></li>
</ul>

È fondamentale notare come sia corretto organizzare il sotto-menù: il tag <ul> del sotto-menù (riga 5) è all’interno del tag <li> (riga 3) da cui si estende, che include anche il tag <a> (riga 4) che funge da finto-collegamento (in questo caso, perché deve essere funzionale solo all’estensione del sotto-menù) e da testo di riferimento per il sotto-menù. Potete vedere un primo esempio (solo html) qui.

Passiamo al foglio di stile. Innanzitutto aggiungiamo un id al menù principale (nell’esempio sarà navbar e quindi <ul id=”navbar”>), così da facilitarne la selezione (sia nel foglio di stile, sia con Jquery; e ricordo che in entrambi bisogna anteporre il cancelletto (#) davanti al nome), poi aggiungiamo delle proprietà css di base affinché il menù diventi così. Non le riporto per intero in questo articolo, potete trovare il foglio di stile qui.

Alcuni commenti:

  1. si seleziona il menù principale con #navbar (avendo l’<ul> principale id navbar, come già detto), i sotto-menù con #navbar ul (non solo quelli di primo livello, semmai ce ne fossero di inferiori!), entrambi (menù principale e sotto-menù) unendo le due con una virgola (quindi: #navbar, #navbar ul su un’unica riga);
  2. il menù principale si estende orizzontalmente, i sotto-menù (anche qui, non solo quelli di primo livello, ma tutti) verticalmente. Ciò significa che che una regola generale potrebbe (e spesso ha bisogno di) essere riscritta o perfezionata per essere applicata a uno stesso elemento contenuto in un sotto-menù di livello inferiore (il punto 4 di questo elenco ne è un esempio);
  3. dare una posizione assoluta ai sotto-menù (riga 13) è utile affinché siano indipendenti per quanto riguarda le misure (che saranno automatiche e calcolate in base al contenuto). Per eventuali altri sotto-livelli, ho notato dei problemi (sempre con le misure) credo imputabili ai limiti di Css 2. In questi casi, è bene specificare delle larghezze minime assolute per i sotto-menù, che potrebbe comunque essere – a prescindere – una buona pratica, anche per motivi estetici;
  4. i <li> del menù principale devono essere “flottanti” a sinistra per essere mostrati uno affianco all’altro (riga 23), visto che di default un elenco (<ul>) si estende in verticale. Questa regola viene annullata per i <li> dei sotto-menù (riga 30), visto che l’ordinamento di default va bene (anche i sotto-menù si estendono in verticale);
  5. bisogna annullare lo stile dei menù (riga 24);
  6. le <a> hanno bisogno della proprietà display impostata a block (riga 36), altrimenti non avranno le stesse dimensioni dei <li> che le contengono;
  7. le modifiche di stile al passaggio del mouse (righe 45-47) vengono “attivate” al passaggio del mouse su un <li> (infatti troviamo li:hover), ma vengono applicate alla <a> contenuta in quel <li>, visto che è alla <a> che viene definito un stile (righe 34-40). Le modifiche vengono applicate solo alla <a> “primo figlio” (meglio in inglese: first child) tramite il > (riga 45), per evitare comportamenti non voluti (se togliete il > e passate sul <li> che contiene un sotto-menù, noterete che le modifiche vengono applicate anche a tutte le <a> del sotto-menù e non solo a quella che apre il sotto-menù – è normale, visto che anche quelle sono “figlie” del <li> principale, proprio per la struttura html che abbiamo (correttamente) definito).

In questo esempio – come sicuramente avrete già notato – il sotto-menù è mostrato sempre, diremmo “fisso”: ho scelto così per permettere di visualizzare nel complesso l’applicazione del foglio di stile. Normalmente, però, non dovrebbe essere così, quindi dobbiamo nasconderlo. Per farlo utilizzeremo la proprietà display settata su none, da applicare a tutti i sotto-menù. Quindi, a questo punto, dobbiamo aggiungere sotto la riga 12 quanto segue:

display: none;

Notare che si potrebbe usare anche la regola visibility (settata su hidden), che porta allo stesso risultato ed è anche migliore da un punto di vista strettamente semantico; ma dobbiamo necessariamente ricorrere a display, perché Jquery lavora su questa proprietà per modificare la visibilità di un elemento.
Fatto questo, l’esempio aggiornato è questo e il relativo foglio di stile questo qui.

Non resta che aggiungere Jquery. L’operazione da eseguire è: al passaggio del mouse su un <li>, mostra l’<ul> first child (anche qui, altrimenti se usiamo più livelli di sotto-menù, li estenderebbe subito tutti). Va da sé che se un <li> non ha nessun <ul> figlio, non accade nulla. Quindi innanzitutto includiamo Jquery (all’interno dei tag <head>):

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script>
	$(document).ready(function(){
	 	//Il nostro codice andrà qui...
	});
</script>

Per attivare un effetto al passaggio del mouse su un <li>, possiamo usare l’evento hover() (documentazione). Il nostro codice diventa quindi (ometto l’inclusione del .js di Jquery e i vari tag <script>):

$(document).ready(function(){
	$("#navbar li").hover(function (){
		//L'effetto da applicare va qui...
	});
});

Che semplicemente corrisponde a: al passaggio del mouse (evento hover()) su un (qualsiasi) <li> contenuto nell’<ul> #navbar (quindi #navbar li), applica la funzione alla riga 3 (che qui dobbiamo implementare).

Di effetti disponibili ce ne sono parecchi (lista completa): noi utilizzeremo slideToggle() (documentazione), ma si valutino anche il classico toggle() (documentazione) e fadeToggle() (documentazione), che differiscono per lo più per il tipo di animazione (si fa prima a provare che a descrivere in questo articolo). Il codice diventa quindi:

$(document).ready(function(){
	$("#navbar li").hover(function (){
		$(this).children("ul").slideToggle();
	});
});

Che sta a significare: applica l’effetto slideToggle() al figlio <ul> (grazie a children() (documentazione)) dell’attuale <li> (this) su cui si è passato il mouse. Ecco quindi il nuovo esempio (il foglio di stile è sempre lo stesso, non lo abbiamo toccato), che soddisfa le necessità iniziali.

Manca giusto una (ultima) cosa, per lo più un “orpello”: come fare a capire (ad occhio, per il visitatore) quali menù contengono un sotto-menù. È diffusa l’abitudine di aggiungere il carattere “»” (ascii &#187;) ai menù che contengono un sotto-menù, pratica chiara e immediata. Potremmo occuparci di questa “aggiunta” manualmente, ma perché farlo (e faticare e rischiare di commettere errori o di non aggiornare in là col tempo), quando Jquery può occuparsi anche di questo e al posto nostro?
D’altronde la cosa è semplice: ciclare tutti i <li> del menù (<li> a qualsiasi profondità, ovviamente), verificare se hanno un <ul> figlio (con un costrutto if) e in caso positivo aggiungere il carattere (preceduto da uno spazio!) alla fine del link.

Bene, passiamo al codice. Per ciclare possiamo utilizzare each() (documentazione):

$("#navbar li").each(function() {
	//Fa qualcosa ad ogni <li> all'interno di #navbar...
});

che, in questo caso, eseguire la funzione qui dichiarata su ogni elemento <li> all’interno di #navbar. Quindi la verifica, per la quale possiamo affidarci a length (documentazione):

$("#navbar li").each(function() {
	if ($(this).children("ul").length) //Fa qualcosa ad ogni <li> all'interno di #navbar che contiene un <ul>...
});

In sostanza, in questo esempio lenght è pari al numero degli <ul> figli del <li> per il quale stiamo eseguendo il ciclo (sempre il famoso selettore this), e quindi l’if avrà esito negativo se non ci sono <ul> figli, viceversa positivi se c’è almeno un <ul> figlio – nota: questo if può essere generalmente utilizzato per verificare se un tag ne contiene un altro ed eventualmente in quale quantità.
Quindi l’aggiunta:

$("#navbar li").each(function() {
	//Se un <li> contiene un sotto-menù, aggiunge al collegamento " »"
	if ($(this).children("ul").length) $(this).children("a").append(" &#187;");
});

Utilizziamo il manipolatore append() (documentazione) per aggiungere uno spazio e un carattere alla <a> figlia di ogni <li> che ha come figlio un <ul> – sembra un ragionamento contorto, sì, lo so; ma riflettete un po’ sul codice e ci arriverete: l’aggiunta va fatta alla <a> contenuta nel <li> e non al <li> sul quale abbiamo eseguito il controllo.

Ecco quindi il codice Jquery finale e completo:

$(document).ready(function(){
	$("#navbar li").hover(function (){
		$(this).children("ul").slideToggle();
	});
	$("#navbar li").each(function() {
		//Se un <li> contiene un sotto-menù, aggiunge al collegamento " »"
		if ($(this).children("ul").length) $(this).children("a").append(" &#187;");
	});
});

Nonché, l’ultimo esempio.

Mettiamo che – come nel mio caso – state scrivendo uno script (magari proprio in bash, ma – perché no… – anche in altri linguaggi) che ha bisogno che sul sistema siano correttamente installate determinate dipendenze, utili alla sua esecuzione .
Mettiamo che – come nel mio caso – avete previsto uno script bash che si occupi dell’installazione dello script (qualcosa del tipo install.sh, che crea, sposta, modifica alcuni file) e che vogliate che questo si occupi anche dell’installazione delle suddette dipendenze.

Si può fare? Sì, si può fare. Vi spiego come.
Analizziamo innanzitutto i passaggi che si dovrebbero svolgere, ordinandoli:

  1. vengono elencate (ad esempio, tramite un array) le dipendenze necessarie;
  2. ricerca di un gestore di pacchetti valido;
  3. verifica delle dipendenze mancanti nel sistema in uso, elencando anche queste (un nuovo array);
  4. ricerca di un gestore di pacchetti valido;
  5. installazione delle dipendenze segnate come mancanti.

Prima osservazione, più che lecita: i punti 2) e 4) non fanno la stessa cosa? A che serve ripetere due volte la stessa operazione?
Risposta: serve ripetere la stessa operazione perché sì, nonostante facciano la stessa cosa (ricerca un gestore di pacchetti valido), la ricerca, nei due casi, può e anzi dovrebbe portare a risultati diversi; questo perché bisogna tenere in conto che il gestore selezionato al punto 2) deve svolgere l’operazione indicata come 3), mentre il gestore selezionato al punto 4) svolgerà il compito 5).
E non è detto che per entrambe le operazioni sia opportuno utilizzare lo stesso gestore (anche se è cosa possibile), anzi…

Un esempio concreto chiarificherà questa spiegazione: visto che il gestore selezionato al punto 4) dovrà procedere all’installazione di alcuni pacchetti – come indicato al punto 5) – se la distribuzione è openSuse si utilizzerà zypper, se è Mandriva si utilizzerà urpmi, se è Fedora si utilizzerà yum. Mentre invece il punto 3), in tutti questi tre casi (openSuse, Mandriva e Fedora) può essere sempre svolto da rpm. Che per giunta svolge il compito 3) meglio degli altri già elencati; al contrario, non sarebbe invece molto indicato per svolgere il punto 5), per motivi che tutti conosciamo.
Lo stesso dicasi per altre distribuzioni. Ad esempio, per Debian, Ubuntu e derivate varie, il punto 3) verrà svolto da dpkg, il punto 5) da apt-get.

Seconda osservazione: è proprio necessario verificare quali dipendenze sono mancanti? Non si fa prima a proporre l’installazione di tutte le dipendenze, così che sia poi il gestore a occuparsi di installare solo quelle mancanti e eventualmente a segnalare quelle già presenti? Sì, certo, si può fare e sicuramente è più comodo e veloce. Ma qui si valuterà il processo “più complesso”, negli altri casi non dovrebbe essere difficile (per voi, per chi legge, per chi è interessato) snellire la procedura, a seconda delle proprie esigenze.
Si tenga anche in conto che lo script potrebbe fallire, per tanti motivi (perché non è stato trovato un gestore di pacchetti adatto, cosa possibile perché non si possono considerare tutte le distribuzioni Linux esistenti, con i loro relativi gestori): in questo caso, potremo indicare all’utente quali dipendenze sono appunto mancanti, e invitarlo a installarle manualmente. Cosa che è molto più elegante, in questo caso, dell’indicare tutte le dipendenze necessarie, installate o meno, mettendo così l’utente nella condizione di dover controllare quali deve provvedere a installare manualmente.

Terza osservazione: l’installazione, ovvero il passaggio 5), avviene del tutto automaticamente, cioè senza nessun interazione con l’utente? No, volutamente no. Lo script che propongo lancia il gestore con il corretto comando d’installazione: è facile e molto probabile che poi – qualsiasi sia la distribuzione, qualsiasi sia il gestore selezionato – verrà chiesto all’utente di confermare.
È una scelta voluta, perché esperienza mi ha insegnato che non è corretto installare software senza renderne consapevole e partecipe l’utente e che non è corretto installare senza aver prima visionato quali cambiamenti verranno apportati al sistema (in alcuni casi, l’installazione di alcuni pacchetti, per via di errati calcoli o problemi con le dipendenze che si portano dietro, possono rendere un sistema instabile…).

Finite le osservazioni, passiamo al codice. È innanzitutto necessario stabilire quali sono le dipendenze necessarie. Vorrei subito chiarire, a scanso di equivoci, che:

  1. quando parlo di “dipendenze” o di “dipendenze necessarie” mi riferisco alle dipendenze richieste dal nostro script (affinché funzioni correttamente);
  2. quando parlo di “dipendenze mancanti” mi riferisco alle dipendenze del nostro script e che mancano sul sistema in uso (è quindi questo un sotto-insieme o una selezione del precedente).

Avevamo previsto un array, che mi sembra la scelta più opportuna:

DEPENDENCIES=(adduser curlftpfs dialog inotify-tools libnotify-bin nfs-common)

Questo soddisfa il punto 1) nella lista dei passaggi da compiere. Passiamo ai punti 2) e 3), ovvero alla selezione di un opportuno gestore di pacchetti e alla verifica di quali dipendenze sono mancanti:

# What dependencies are missing?
PKGSTOINSTALL=""
for (( i=0; i<${tLen=${#DEPENDENCIES[@]}}; i++ )); do
	# Debian, Ubuntu and derivatives (with dpkg)
	if which dpkg &> /dev/null; then
		if [[ ! `dpkg -l | grep -w "ii  ${DEPENDENCIES[$i]} "` ]]; then
			PKGSTOINSTALL=$PKGSTOINSTALL" "${DEPENDENCIES[$i]}
		fi
	# OpenSuse, Mandriva, Fedora, CentOs, ecc. (with rpm)
	elif which rpm &> /dev/null; then
		if [[ ! `rpm -q ${DEPENDENCIES[$i]}` ]]; then
			PKGSTOINSTALL=$PKGSTOINSTALL" "${DEPENDENCIES[$i]}
		fi
	# ArchLinux (with pacman)
	elif which pacman &> /dev/null; then
		if [[ ! `pacman -Qqe | grep "${DEPENDENCIES[$i]}"` ]]; then
			PKGSTOINSTALL=$PKGSTOINSTALL" "${DEPENDENCIES[$i]}
		fi
	# If it's impossible to determine if there are missing dependencies, mark all as missing
	else
		PKGSTOINSTALL=$PKGSTOINSTALL" "${DEPENDENCIES[$i]}
	fi
done

Nonostante reputi questo codice abbastanza comprensibile, vado a commentare:

  1. innanzitutto vado a creare la variabile (vuota) PKGSTOINSTALL, che conterrà l’elenco (non è un array, ma una stringa, con gli spazi a mò di divisore) delle dipendenze mancanti;
  2. viene quindi eseguito un ciclo (riga 3) per ognuna delle dipendenze da verificare;
  3. all’interno del ciclo, tramite un (complesso) costrutto if-elif-else, vado a verificare se è disponibile un gestore di pacchetti, avvalendomi di which (che stampa la localizzazione di un eseguibile, quando è presente, altrimenti nulla) e, se disponibile, quale (righe 5, 10 e 15).
    Qui, in particolare, ricerchiamo tra dpkg (per Debian, Ubuntu e derivate, come Mint), rpm (per OpenSuse, Mandriva, Fedora, CentOs e altre) e pacman (per ArchLinux), che dovrebbero coprire la stragrande maggioranza delle distribuzioni, sicuramente tutte quelle più diffuse;
  4. viene quindi verificata se la singola dipendenza (che stiamo ciclando) è già installata o meno, eseguendo un comando specifico per il gestore che abbiamo selezionato (righe 6, 11 e 16);
  5. se la dipendenza non risulta installata, viene accodata alla stringa PKGSTOINSTALL (righe 7, 12 e 17), preceduta da uno spazio. Se invece è già installata, passa alla successiva dipendenza da controllare;
  6. se non viene trovato un gestore utile (alternativo quindi a quanto descritto al punto 3) di questo elenco), allora segna automaticamente la dipendenza come mancante (riga 21), segnando di fatto tutte le dipendenze come mancanti (perché, ovviamente, anche la successiva iterazione del ciclo porterà allo stesso risultato…).

Alla fine di questo blocco di codice – come per altro già accennato – la variabile PKGSTOINSTALL conterrà quindi l’elenco delle dipendenze mancanti (e quindi da installare!), separate l’un l’altra da uno spazio (come tutti i gestori si aspettano siano passato l’elenco).

Si noti che questo codice non è “perfetto”: ad ogni ciclo, di fatti, si va a rieseguire il controllo del gestore. Non dovrebbe portare a chissà quali performance negative e/o penalizzanti, ma non escludo assolutamente che si possano scrivere numerosi varianti migliori di questa e che portino allo stesso risultato. Anzi, se ne avete voglia, prendetelo come un esercizio, visto che sicuramente si può fare (e si dovrebbe fare…) di meglio.

Passiamo al codice che si occupa dell’installazione effettiva:

# If some dependencies are missing, asks if user wants to install
if [ "$PKGSTOINSTALL" != "" ]; then
	echo -n "Some dependencies are missing. Want to install them? (Y/n): "
	read SURE
	# If user want to install missing dependencies
	if [[ $SURE = "Y" || $SURE = "y" || $SURE = "" ]]; then
		# Debian, Ubuntu and derivatives (with apt-get)
		if which apt-get &> /dev/null; then
			apt-get install $PKGSTOINSTALL
		# OpenSuse (with zypper)
		elif which zypper &> /dev/null; then
			zypper in $PKGSTOINSTALL
		# Mandriva (with urpmi)
		elif which urpmi &> /dev/null; then
			urpmi $PKGSTOINSTALL
		# Fedora and CentOS (with yum)
		elif which yum &> /dev/null; then
			yum install $PKGSTOINSTALL
		# ArchLinux (with pacman)
		elif which pacman &> /dev/null; then
			pacman -Sy $PKGSTOINSTALL
		# Else, if no package manager has been founded
		else
			# Set $NOPKGMANAGER
			NOPKGMANAGER=TRUE
			echo "ERROR: impossible to found a package manager in your sistem. Please, install manually ${DEPENDENCIES[*]}."
		fi
		# Check if installation is successful
		if [[ $? -eq 0 && ! -z $NOPKGMANAGER ]] ; then
			echo "All dependencies are satisfied."
		# Else, if installation isn't successful
		else
			echo "ERROR: impossible to install some missing dependencies. Please, install manually ${DEPENDENCIES[*]}."
		fi
	# Else, if user don't want to install missing dependencies
	else
		echo "WARNING: Some dependencies may be missing. So, please, install manually ${DEPENDENCIES[*]}."
	fi
fi

Vado anche qui a commentare:

  1. innanzitutto, un semplice costrutto if verifica che la variabile PKGSTOINSTALL non sia vuota (riga 2) e quindi – in altri termini – verifica che ci sia qualcosa da installare. Ricordo – visto che l’avevo già precisato – che se precedentemente non è stato possibile determinare quali dipendenze siano mancanti e quali presenti, qui risulteranno tutte come mancanti;
  2. a questo punto, viene chiesto all’utente se vuole procedere con l’installazione (la riga 3 stampa la richiesta, la riga 4 salva l’input in READ);
  3. se la risposta è affermativa (riga 6), allora viene ricercato un gestore di pacchetti (righe 8, 11, 14, 17, 20) tra apt-get, zypper, urpmi, yum e pacman, sempre tramite un costrutto if-elif-else;
  4. se è stato trovato un gestore dei pacchetti, allora procede con l’installazione, avvalendosi dell’opportuna istruzione (righe 9, 12, 15, 18, 21). Altrimenti (riga 23), imposta la variabile NOPKGMANAGER a TRUE (riga 25, ci servirà successivamente per controllo) e stampa a schermo un errore (riga 26);
  5. quindi viene verificato l’esito dell’installazione (riga 29). Se l’istruzione di installazione non ha restituito nessun errore (per qualsiasi motivo che abbia portato il gestore di turno ad un fallimento) e se non è presente la variabile NOPKGMANAGER (impostata quando non viene correttamente rilevato un gestore di pacchetti), allora l’installazione ha avuto successo e quindi stampa un messaggio di conferma (riga 30). Se invece le due ipotesi non sono entrambe e contemporaneamente vere (riga 32), allora l’installazione non è andata a buon fine e quindi stampa un messaggio di errore e la lista delle dipendenze segnate come mancanti, che l’utente dovrà (a questo punto) provvedere a installare manualmente (riga  33);
  6. se invece l’utente ha inizialmente risposto negativamente alla richiesta di procedere con l’installazione (riga 36), allora stampa un messaggio di avviso e – anche qui – la lista delle dipendenze da installare manualmente.

Linux Day 2011

Il 22 ottobre in tutta Italia è il Linux day.

Il Linux Day è una manifestazione nazionale articolata in eventi locali che ha lo scopo di promuovere GNU/Linux e il software libero. Il Linux Day è promosso da ILS (Italian Linux Society) e organizzato localmente dai LUG italiani e dagli altri gruppi che condividono le finalità della manifestazione.
La responsabilità dei singoli eventi locali è lasciata ai rispettivi gruppi organizzatori, che hanno libertà di scelta per quanto riguarda i dettagli delle iniziative locali, nel rispetto delle linee guida generali della manifestazione. La prima edizione del Linux Day si è tenuta il 1 dicembre 2001 in circa quaranta città sparse su tutto il territorio nazionale. Il numero è notevolmente cresciuto negli anni divenendo ormai un appuntamento immancabile nel panorama del software libero italiano.

Date un’occhiata al sito ufficiale, dove trovate la mappa delle 109 città italiane, dell’utile materiale informativo e le ultime news sull’iniziativa.

Se tutto andrà bene, io sarò presente a quello di Pescara, organizzato dal Pescara Lug. Il programma (se ci fossero altri della zona interessati):

Mattina Inizio ore 9.30
Ore 10.00 Introduzione e saluti
Ore 10.15 Panoramica del mondo Linux
Ore 10.45 Utilizzo di Linux tutti i giorni
Ore 12.30 Pausa Pranzo

Pomeriggio Inizio ore 15.30
Ore 15.30 Impaginazione e Scribus
Ore 16.00 Crittografia dei dati e Tomb
Ore 17.00 Sicurezza reti Wifi
Ore 17.30 Android

p.s. non ne sono stati organizzati in provincia di Chieti. Ce ne sono invece due a L’Aquila (quello dell’hAQ-lab e quello Linux Crew CaseMatte), uno ad Avezzano e uno a Teramo.

CheckgmailGooglando qua e là, ho scoperto che il problema che mi perseguita ormai da un mesetto, affligge molti utenti: checkgmail non riesce ad accedere al server di posta e notifica un errore 401, “unauthorized”.

Conseguenza diretta è che, imperterrito, checkgmail chiede continuamente le credenziali di accesso alla casella di posta:

Checkgmail Errore 401

Checkgmail Errore 401

Lanciando l’update da terminale (`checkmail -update`), qualcosa viene aggiornato, ma la situazione non cambia, tant’è che lo stesso terminale dà in output un tristissimo:

Unable to find gmail_ik ... full message text won't work :(

Per nostra fortuna, qualche buon samaritano si è preso la briga di realizzare una piccola patch per checkgmail che potete scaricare da qui. Terminato il download, la potete applicare come segue (sono necessari i privilegi di root):

# patch /usr/bin/checkgmail checkgmail.patch

Ovviamente dovete indicare la path corretta di checkgmail.path. A questo punto sarà sufficiente riavviare checkgmail (click destro sull’icona, quindi “Restart…”) e tutto dovrebbe tornare alla normalità.

PopstarSfrutto lo spazio del mio blog per pubblicizzare il progetto di un’amica, perché mi sembra meritevole ed interessante. Di seguito trovate la presentazione dello stesso. Se qualcuno fosse interessato – e mi rivolgo principalmente ai giovani della provincia di Chieti – si faccia riferimento all’apposito gruppo su Facebook.

“Pop” da popolare, come la cultura viva che crea la nostra identità di individui e di collettività. “Stars” da stelle, non quelle del divismo spettacolare ma quelle naturali che ci portano indietro ad un tempo dove gli uomini erano in equilibrio con la natura, e questo dava loro un benessere individuale e collettivo.

Il Comune di Palombaro in qualità di comune capofila e la provincia di Chieti, annunciano l’avvio di “Popstars”, unico progetto abruzzese, selezionato nel bando “Piccoli Comuni per il Coinvolgimento dei giovani nella valorizzazione delle specificità territoriali – Giovani Energie in comune” promosso dall’Anci e dal Dipartimento della Gioventù della Presidenza del Consiglio dei Ministri.

Il progetto abruzzese coinvolge una rete di comuni dislocati in diverse zone dell’entroterra della Provincia di Chieti: Altino, Carunchio, Castelfrentano, Fraine, Miglianico, Pennapiedimonte, Pretoro, Rapino, Roccamontepiano, Roccaspinalveti, Sant’Eusanio del Sangro. I partners istituzionali oltre la Provincia di Chieti sono: CUSPD Centro Universitario di Sociologia della Prevenzione Disagio – Facoltà di Scienze Sociali Università G. D’Annunzio, Comunità Montana Alto Vastese, Comunità Montana della Maielletta, C.M.A – Centro Montano di Assistenza, Pro loco Carunchio, Pro loco Roccaspinalveti, Pro loco Fraine. Il consorzio Civica è responsabile del project Management.

La finalità principale di Pop Stars è quella di guidare i giovani in un percorso di recupero della memoria e dell’identità culturale del territorio attingendo al bagaglio di conoscenze e saperi di cui sono custodi gli anziani. Gli elementi della tradizione popolare saranno ri-letti e ri-utilizzati dai giovani attraverso i linguaggi della comunicazione e dell’arte contemporanea. Il progetto prevede per i mesi estivi lo svolgimento di un’attività di ricerca nei territori che coinvolge gli anziani. A partire da settembre e per tutto l’autunno, si svolgeranno i percorsi formativi in ambito socio – culturale rivolti ai giovani: laboratori di teatro, musica e canto, performance, video, fotografia e gestione siti web.

Le attività formative ideate e coordinate dalla regista Annamaria Talone dell’Associazione Maglab saranno realizzate da artisti ed operatori culturali esperti appartenenti alle associazioni abruzzesi Euritmi e Rogoteatro, e da una formatrice d’eccellenza Helen Chadwick  – musicista inglese, vocal trainer della Royal Shakespeare Company e del National Theatre. Le attività di ricerca e monitoraggio saranno guidate dal CUSPD diretto dal prof. Benvenuti – Facoltà di Scienze Sociali Università G. D’Annunzio.

Per poter partecipare i giovani devono avere un’età compresa tra i 18 e i 30 anni e la residenza in uno dei comuni coinvolti. Nel caso in cui non si raggiunge il numero minimo di adesioni per singolo laboratorio, sarà data la possibilità di fare domanda di partecipazione anche ai giovani residenti in tutti i comuni della Provincia di Chieti. Per informazioni sulle modalità di partecipazione ci si può rivolgere al proprio comune di residenza oppure visitare il sito www.giovanipopstars.it. La domanda va presentata entro il 30.07.2011

Il progetto si conclude con delle feste finali promosse dai giovani insieme agli anziani e a tutta la popolazione dei paesi. Il valore sociale del progetto non tocca solo le giovani generazioni ma ha una ricaduta positiva sulle comunità dei paesi coinvolti, rafforzando il senso di appartenenza, l’identità territoriale e la comunicazione tra diverse generazioni.

ApacheDue veloci tips and tricks per chi – come il sottoscritto – sviluppa applicazioni web in locale.

Apache in ascolto solo in locale

Questo impedisce che il nostro server Apache sia raggiungibile dall’esterno, lan inclusa. In altri termini, sarà raggiungibile solo dall’host locale, ovvero dalla stessa macchina su cui è in funzione il web server.
Modificare il file /etc/apache2/ports.conf da:

Listen 80

a:

Listen 127.0.0.1:80

È possibile indicare un indirizzo per riga. Quindi, volendo abilitare anche la lan (e supponendo che l’ip della macchina, al suo interno, sia 192.168.0.100), modificare in:

Listen 127.0.0.1:80
Listen 192.168.0.100:80

E quindi riavviare il servizio:

# /etc/init.d/apache2 restart

PhpMyAdmin senza password

Questo ci permette di loggarci automaticamente all’interno di PhpMyAdmin senza doverci autenticare ogni volta. Di default, è richiesta l’autenticazione, che viene mantenuta tramite l’utilizzo di cookie.
Modificare il file /etc/phpmyadmin/config.inc.php da:

/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'cookie';

a:

/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'config';
$cfg['Servers'][$i]['user'] = 'root';
$cfg['Servers'][$i]['password'] = 'mypwd';

(dove mypwd è la password dell’utente root)

Assicurarsi, in questo caso, che PhpMyAdmin non sia accessibile dall’esterno (modificando come prima illustrato), onde evitare di esporsi a gravi pericoli (ovvero avere i propri database mysql accessibili a tutti).