domenica 29 gennaio 2017

Prompt con orario

Io non uso mai dei prompt shell multi-riga, li trovo scomodi dal punto di vista visivo.
Inoltre non ho mai utilizzato il "tempo" (ora, minuti, secondi) nel prompt stesso. Ultimante ho cambiato idea su quest'ultimo punto: anche se apparentemente inutile può risultare conveniente avere un "timestamp" di quanto è stato eseguito un comando in una data shell.
Questo permette ad esempio di sapere quando si è fatta l'ultima sincronizzazione remota con rsync, oppure di sapere indicativamente quanto è durato un comando lanciato prima di andare a prendere un caffé...

Nella mi configurazione di zshell ho i seguenti due prompt:


PROMPT="%{$fg_bold[yellow]%}[%{$reset_color%}%{$fg_bold[blue]%}%n%{$reset_color%}%{$fg[yellow]%}@%{$reset_color%}%{$fg_bold[white]%}%m%{$reset_color%} %{$fg_bold[green]%}%*%{$reset_color%}%{$fg_bold[yellow]%}]%{$reset_color%}%{$fg_bold[red]%}%%%{$reset_color%} "
 

RPROMPT="%{$reset_color%}%{$fg_bold[magenta]%}%~%{$reset_color%}"


A sinistra viene visualizzato lo username, l'hostname e l'orario, oltre al prompt "%"; a destra viene riportata la directory locale (CWD).
Questo permette di tenere il prompt a sinistra sempre costante e allineato, mentre la cartella di lavoro viene sempre visualizzata in fondo alla riga corrente.

sabato 28 gennaio 2017

Perlbrew e i threads...

RTFM!
Ormai sono un affezzionato utente di perlbrew, ma solo da poco ho scoperto che prevede un flag apposito per la compilazione di Perl 5 con supporto multithread. Tale flag, come si può facilmente intuire, è "--threads":

% perlbrew install --threads --as PERL_5.25.9_WITH_THREADS perl-5.25.9

Si noti bene che non è mai molto sano costruire una versione "dispari" di Perl 5, poiché sono versioni non mainstream-stable (chi si ricorda la numerazione dei kernel Linux prima dell'avvento di git?).

venerdì 27 gennaio 2017

TAP: alcuni concetti

Il Test Anything Protocol (TAP per gli amici) è un formato semplice ed efficace per la reportistica di test automatici.
Nato nell'ecosistema Perl nel 1988, il protocollo si è evoluto ed è uscito dai confini Perl per giungere ad altri linguaggi e sistemi, perfino database con PostgreSQL e pgTap.

Il formato TAP è abbastanza semplice e si basa su alcuni concetti semplice:
  • producer è un'applicazione che si occupa di produrre un output TAP compatibile (su stdout)
  • consumer è un'applicazione che si occupa di interpretare l'output di un producer e fornire un report finale.

Ad esempio "prove" è un consumer dell'output prodotto da "Test::More" e similari, che a sua volta fungono da producer.
Nell'esempio relativo a PostgreSQL si ha che "pg_prove" è un consumer, e le funzioni importate da pgTap e i relativi script SQL sono i producer.

Il formato TAP è abbastanza semplice e prevede un solo paio di elementi obbligatori.
Anzitutto occorre inserire il numero di test, ovvero il piano di esecuzione, indicato come 1..N (con N > 0), e solitamente questo compare come primo elemento nell'output. Grazie a questa informazione il consumer sa se ha raggiunto la fine dei test (N) correttamente o se qualcosa ha causato un abort del sistema. Con l'evoluzione TAP supporta anche che N sia zero, indicando così che si vuole saltare la porzione di test. Inoltre è possibile specificare il piano di esecuzione alla fine, che in altre parole è come dire che non c'è un vero piano di esecuzione.

Successivamente, per ogni test effettuato, ci deve essere almeno una riga che inizia con "ok" oppure "not ok". Questo è l'unico elemento obbligatorio, anche se altri sono suggeriti per una migliore comprensione e analisi dei tool consumer.
Subito dopo lo stato del test si dovrebbe indicare il numero progressivo del test stesso, come pure una descrizione del test (affinché si possa capire meglio quale test è stato eseguito). Da ultimo vi è la possibilità di una direttiva (commentata in stile Perl, ossia con "#") che può indicare di saltare il test (SKIP) o che il test non è ancora completo (TODO).

Riassumento l'output di TAP può essere considerato come:


<# direttiva>

Ed ecco quindi un esempio pratico:

1..2
ok 1 - First comparison test
ok 2 - Second comparison


Qualora il piano di esecuzione non sia corretto TAP dovrebbe fornire una indicazione (non una direttiva) di tale fatto:

1..10
ok 1 - First comparison test
ok 2 - Second comparison
# Looks like you planned 10 tests but ran 2.

Solitamente durante la fase di sviluppo non si utilizza un piano di esecuzione, ma all'atto del rilascio del software il piano di esecuzione deve essere "congelato" in modo da aumentare la verifica automatica di errori.


Nell'output di TAP tutte le linee che iniziano con un commento in stile Perl ("#") vengono ignorate e usate, ad esempio, per fornire all'utente dei messaggi diagnostici per aiutarlo a capire perché un test è fallito.

Una direttiva di emergenza, denominata "Bail out!", indica che il sistema di test ha deciso di non proseguire per errori (controllati) troppo gravi. Ad esempio si può annullare una sessione di testing perché la rete non è disponibile, o il compilatore non è alla versione corretta, ecc.

Nel caso in cui non sia fornito un vero piano di esecuzione, e quindi l'output di TAP non inizi con "1..N", il sistema non sa quanti test deve eseguire. In questa eventualità si deve procedere con i test, aumentando in modo incrementale l'eventuale numero riportato in uscita, e alla fine stampando il "presunto" piano di esecuzione:

ok 1 - First comparison test
ok 2 - Second comparison
1..2

Tuttavia in questo caso il sistema non può sapere autonomamente se i test sono finiti o se c'è stato un abort di esecuzione, e per questo si richiede al programmatore di inserire una chiamata di fine esecuzione (ad esempio in Perl done_tsting() ).


Fino a qui ci si è occupati di TAP dal lato del producer. L'output di TAP viene poi analizzato a sua volta da un consumer, ad esempio "prove" o "pg_prove" che forniscono un riassunto su quanti test sono stati eseguiti, quanti sono andati bene e quanti sono falliti. L'idea dei consumer è che, all'aumentare del numero di test, l'utente dovrebbe potersi concentrare solo sul risultato finale e non sui singoli output dei vari test.

Per maggiori informazioni sulle specifiche TAP si veda qui.

KDE Slimbook

Finalmente!
Anche KDE (e Linux in generale) inizia ad acquistare coesione con l'hardware.
E' nato KDE Slimbook, un notebook interamente basato su KDE (neon).


Reboot ITPUG (Le mie dimissioni da ITPUG...parte 3)

Il consiglio di ITPUG è nuovamente in forze: dopo le mie dimissioni di circa un mese fa è stato eletto un nuovo socio per sostituirmi.
Questo permetterà ad ITPUG di proseguire le normali attività fino alle prossime elezioni di fine biennio, direi Aprile.
Presto sparirà il mio nome dalla lista dei consiglieri , immagino ci vorrà tempo perché si dia la giusta visione al mio sostituto.

A seguito delle mie dimissioni ho assistito ad un approccio abbastanza roccambolesco nella gestione del da farsi. Premesso che non ho intenzione di polemizzare e che quanto qui descritto rappresenta solo (e ovviamente) il mio punto di vista, ecco cosa è successo.

Anzitutto un po' di delusione perché le mie dimissioni non sono nemmeno state verbalizzate. Non è mania di protagonismo, ma un consiglio che vuoel una gestione trasparente deve quanto meno prendere atto di quanto sta accadendo al suo interno e "scolpirlo" nella pietra. Amarezza anche per la presidenza, che nonostante io avessi chiesto si pronunciasse, si è limitata a convocare l'assemblea straordinaria.

Stupore anche per la decisione, quasi unilaterale e a colpi di rima baciata (ossia in modo molto prolisso), di delegittimazione del consiglio stesso. Essendone io uscito si è deciso, applicando in maniera molto rigida e forse non regolare lo statuto, di delegittimare il consiglio stesso. A nulla è servito portare alla memoria dei consiglieri (alcuni storici quasi quanto me) e dei soci che già in passato, in analoga situazione e con dimissioni presentate, il consiglio aveva comunque proseguito la sua attività. E a nulla è servito ricordare che anche i soci pendenti potevano essere ammessi all'associazione (anche perché lo statuto stesso prevede 30 giorni per una decisione).

I soci stessi sono stati posti in discussione, utilizzando una logica boolean abbastanza contorta per la quale chi non aveva pagato/rinnovato la quota 2017 risultava "non in regola" e quindi non ammesso alle votazioni del mio sostituto. Ora, in assenza di un regolamento specifico e considerato che le quote vengono rinnovate in occasione dell'assemblea ordinaria (solitamente Aprile), questa mi è sembrata una contromisura molto forte. Inoltre, non essendoci un termine stabilito per il rinnovo, definire la morosità dei soci risulta abbastanza discutibile.
E anche qui i consiglieri storici avrebbero potuto ricordarsi di cosa accaduto nel 2014, situazione differente ma valutazione di "morosità" analoga.
Ancora peggio: c'è la garanzia che i consiglieri fossero tutti in regola con la quota?
E se non lo erano, anche se per un breve periodo nel loro mandato, il consiglio non deve essere analogamente delegittimato?

Ma andiamo avanti. E' stata convocata una assemblea straordinaria dei soci, sbagliandone la convocazione e facendo quindi slittare di un giorno l'assemblea stessa. Che poi è stata verbalizzata come ordinaria, e non come straordinaria.
Piccolezze, sviste, e concordo! Ma una associazione che vuole applicare rigidamente lo statuto non può fare simili sviste, almeno secondo me.
E se anche succedono queste sviste, perché in un caso la convocazione è stata annullata (ritardando quindi la "rilegittimazione" del consiglio) e nell'altro caso no?

Insomma, come si evince, ritengo che sia stato applicato uno statuto mirato piu' a legare le mani all'associazioni che non a sostenere la stessa.
Fermo restando che l'approccio difensivo difficilmente risulta inadeguato, forse questo accanimento ha causato piu' danni che utile.

Detto questo penso, in tutta onestà, che a parte i miei impedimenti personali forse è un bene che io sia uscito da questo consiglio: le incongruenze fra il mio modo di vivere l'associazione e quello degli altri membri è ormai abbastanza distante, e questo avrebbe comunque impedito un sano lavoro di entrambi.

In bocca al lupo al nuovo consiglio, e buon lavoro!
Sperando che si riprenda a pubblicare ai soci i verbali delle riunioni, anche questi trattenuti a colpi di statuto...

Un'ultima nota: fino alle mie dimissioni io sono stato l'unico consigliere ad essere stato in carica dall'inizio dell'attività ITPUG con assoluta continuità. Ahimé ritengo che la mia memoria storica non sia stata utilizzata in modo costruttivo come avrebbe potuto.

P.S.
dai messaggi che passano in lista soci penso di sapere chi sarà il prossimo presidente: 47605db981f8

sabato 21 gennaio 2017

Da 5 a 6: i sigilli in Perl 6

Una delle prime difficoltà mentali che ho incontrato nell'apprendere Perl 6 è stata la variazione dell'uso dei sigilli, e non perché fosse difficoltosa in sé (anzi risulta semplificata!), ma perché mi appariva incoerente.
In Perl 5 era abbastanza facile, almeno per me, comprendere che $ indicava "un singolo elemento", fosse questo un valore di array, hash o un riferimento (ad un oggetto, sub o altro).
In Perl 6 la cosa non è così e infatti il sigillo del tipo di "container" rimane invariato per tutto il ciclo di vita, e questo significa che ad esempio un array avrà sempre @ come sigillo anche quando si vuole accedere ad un singolo elemento di questo.
Per maggiori dettagli si legga ad esempio "A sigil is for life, not just for value type" nella Exegis 2 .
La cosa che inizialmente mi disturbava era che il sigillo $ era in un certo senso "sovraccaricato": funzionava per i normali scalari (es. stringhe, numeri) e anche per gli oggetti. Si noti che questo è esattamente il comportamento che si ha in Perl 5, quindi perché scomodarsi a variare i sigilli degli altri cointainers?
La spiegazione mentale che mi sono dato è intrinseca al fatto che in Perl 6 tutto è un oggetto (un po' come in Ruby): anche le stringhe sono oggetti, così come i numeri, ecc.

% perl6

> "hello".^name
Str
> 10.^name
Int

In un certo senso questo significa che il sigillo $ viene usato come "singolo oggetto", non piu' come "scalare primitivo o oggetto", perché di fatto non esistono piu' "scalari primitivi".

E la pace è tornata nella mia mente!

giovedì 19 gennaio 2017

Perl 5 e le eccezioni: come funziona Try::Tiny

Perl 5 non prevede un meccanismo di gestione del flusso delle eccezioni, pur prevedendo queste ultime, come altri linguaggi fanno, spesso ereditando da C++ i blocchi e gli operatori try/catch e similari.
In Perl5 le eccezioni sono riportate come variabili globali, in particolare:

  • $! (errno) contiene la versione numerica o stringa della variabile globale C-Unix errno(3);
  • $? (child error) lo stato riportato dalla exit dell'ultimo sottoprocesso creato per pipe, backtick, chiamata a system (simile in questo alla stessa variabile della bourne shell);
  • $@ (eval error) lo stato di errore dell'ultimo blocco eval eseguito.

Unitamente a questo, Perl 5 prevede la funzione speciale "die" che solleva un'eccezione: se questo avviene nel programma principale questo termina (muore, da qui il nome), se invece si è in un blocco eval il blocco termina e la variabile globale $@ viene impostata a quanto specificato nell'eccezione. Da notare che è possibile passare anche un riferimento a "die", quindi anche un oggetto (eccezione) che viene poi assegnato alla variabile $@.

L'uso di variabili globali per la gestione delle eccezioni non è certo ottimale, almeno nella programmazione OOP. Si rischia infatti che il sollevamento di una eccezione, in blocco annidato, faccia sollevare una nuova eccezione e quindi che la propagazione sia a piu' livelli e con cause differenti. Essendo $@ unica, solo l'ultimo livello di propagazione viene riportato. Non solo: essendo $@ globale si rischia che il suo valore sia resettato in punti inaspettati e quindi è necessario "ricordarsi" di analizzare $@ quanto prima possibile.


Sono quindi nati molti moduli su CPAN per la gestione delle eccezioni, e uno del quale parlare è Try::Tiny.
Questo è un modulo molto semplice, non gestisce alcuni casi particolari (es. return in eval), ma fornisce comunque una sintassi "carina" e che ogni programmatore riesce a comprendere:

try{
die "Argh!";
}
catch { say "Eccezione: $_"; };

In particolare Try::Tiny imposta la variabile topic a $@ appena si entra nel blocco catch, permettendo quindi di dimenticarsi di $@ stessa. Ma come riesce a fare la magia della sintassi e a introdurre try-catch? Beh, ancora una volta entra in gioco la magia e la flessibilità di Perl 5.

Anzitutto si noti il ';' al termine del blocco catch: questo indica che in realtà si sta eseguendo una istruzione Perl 5 valida, o per meglio dire una funzione. E infatti Try::Tiny esporta tre funzioni che si chiamano "try", "catch" e "finally".
Si consideri un estratto di "catch" prima:

sub catch (&;@) {
  my ( $block, @rest ) = @_;

  croak 'Useless bare catch()' unless wantarray;

...
  return (
   bless(\$block, 'Try::Tiny::Catch'),
        @rest,
  );
}


Anzitutto la funzione accetta come primo parametro un blocco di codice o una sub (il carattere & del prototipo), e si aspetta di essere chiamato in contesto di lista, quindi ad esempio come

my ($catch) = ( catch { say "Eccezione: $_"; } );

La fine della funzione catch converte il blocco di codice in un oggetto di tipo 'Try::Tiny::Catch', e questo serve per dei controlli interni.

Vediamo brevemente la funzione "try", sicuramente piu' interessante:


sub try (&;@) {
  my ( $try, @code_refs ) = @_;
  my $wantarray = wantarray;
  my ( $catch, @finally ) = ();


  foreach my $code_ref (@code_refs) {

   if ( ref($code_ref) eq 'Try::Tiny::Catch' ) {
      croak 'A try() may not be followed by multiple catch() blocks'
     if $catch;
    $catch = ${$code_ref};
  } elsif ( ref($code_ref) eq 'Try::Tiny::Finally' ) {
     push @finally, ${$code_ref};
  } else {
    croak(
    'try() encountered an unexpected argument ('
       . ( defined $code_ref ? $code_ref : 'undef' )
.      ') - perhaps a missing semi-colon before or'
    );
  }
}

...

  my $failed = not eval {
  $@ = $prev_error;

    # evaluate the try block in the correct context
    if ( $wantarray ) {
      @ret = $try->();
    } elsif ( defined $wantarray ) {
      $ret[0] = $try->();
   } else {
      $try->();
  };

  return 1; # properly set $failed to false
};


  $error = $@;
  $@ = $prev_error;


  if ( $failed ) {
   ...
    if ( $catch ) {

     for ($error) {
      return $catch->($error);
    }

 }

  return;
 } else {
  return $wantarray ? @ret : $ret[0];
 }
}

Anche qui la funzione si aspetta come primo argomento un blocco o una sub. Gli altri argomenti vengono trattati a loro volta come argomenti o sub, e si controlla nel primo loop che siano di tipo 'Try::Tiny::Catch', o finally o vengono considerati come alieni.
Successivamente si esegue l'eval del blocco passato come primo argomento e, qualora questo abbia impostato un errore, si esegue anche il blocco catch passanto la variabile di errore come primo argomento.

Chiarito come avviene la magia sintattica di try-catch è possibile anche scrivere il blocco esplicitando le funzioni e i loro argomenti:

try( sub { die "Eccezione!" }, 
     catch( sub { say "Presa: $_" } ) );

Ma come vengono gestiti i blocchi finally? Il meccanismo è abbastanza elegante: all'interno della funzione "try" vengono creati degli oggetti (blessed reference) per ogni blocco finally incontrato. Tali oggetti hanno un metodo DESTROY che invoca il code ref (blocco o funzione) specificato. Quando la funzione try termina gli oggetti vanno fuori visibilità e quindi vengono distrutti, e di conseguenza viene eseguito DESTROY che a sua volta richiama il codice specificato dall'utente.

mercoledì 18 gennaio 2017

Quanto ITPUG? (Le mie dimissioni da ITPUG parte 2)

Avendo marcato la fine della mia attività da consigliere con le dimissioni di circa un mese fà, ho deciso, quasi per curiosità, di cercare di quantificare il lavoro svolto da ITPUG e dal suo consiglio negli ultimi due mandati.
Si tratta di dati ovviamente indicativi, visto che strumenti diversi offrono opzioni di statistica differenti, ma possono essere utilizzati per un grezzo lavoro di analisi quantitativa.
E' bene sottolinearlo: si parla di attività quantitativa, non qualitativa!
Tuttavia l'attività quantitativa spesso indica e sottointende la presenza in associazione e la vitalità della stessa, da qui il mio interesse per questi semplici dati.

Ovviamente non sto svelando alcun segreto, questi dati sono comunque visibili e calcolabili da ogni consigliere e socio, con un po' di impegno e pazienza. Potrei anche aver commesso qualche errore di computazione, nel qual caso ogni correzione è ben accetta.

Considerando quindi la data del 30 aprile come termine di un biennio (e il relativo inizio del successivo), e sottolineando come il biennio 2015-2017 non sia ancora giunto al termine (e quindi i dati di tali biennio si riferiscono alla data attuale), si ha che:
  • biennio 2013-2015
  1.  301 commits
  2. 281 tickets
  3. 19 verbali riunioni di consiglio
  4. 108 thread in lista itpug-consiglio@
  5. 170 thread in lista itpug-soci@
  • biennio 2015-2017
  1. 103 commits
  2. 190 tickets
  3. 7 verbali riunioni di consiglio
  4. 160 thread in lista itpug-consiglio@ 
  5. 130 thread in lista itpug-soci@

L'attività del consiglio può essere quantificata con il numero di commits nel repository documentale, ovvero quanti documenti il consiglio ha ritenuto di inserire fra quelli ufficiali (fra questi, i verbali delle riunioni di consiglio), nonché dal numero ti tickets (ovvero di problematiche e task da affrontare). Come si può notare il valore di entrambi è drasticamente calato nell'ultimo biennio, segno che non si utilizza piu' né il repository né il sistema di ticketing come strumento base per la gestione delle attività del consiglio.
Questo è in parte confermato anche dall'aumento del numero di thread nella mailing list consiglio, che rispecchia il maggior uso e preferenza di questo canale di discussione rispetto agli altri strumenti.
A mio avviso questa è una regressione, poiché l'email non rappresenta lo strumento ideale per gestire scadenze, priorità, condivione di documenti.
Il dato però piu' allarmante, a mio avviso, è quello delle riunioni di consiglio, o meglio, dei verbali delle riunioni di consiglio. Come si può vedere le riunioni di consiglio sono scese del 60% circa, segno che il consiglio non ritiene sufficientemente utile riunirsi con regolarità (ulteriore conferma della preferenza del canale e-mail), o ha delle difficoltà a riunirsi.
Appare anche diminuita l'attività e la presenza del consglio nella mailing list dei soci, visto che il numero di thread si è abbassato. Ora, questo dato in particolare non coinvolge direttamente il consiglio, visto che i thread possono anche essere creati dai singoli soci (e anzi, questo è quello che dovrebbe accadere); tuttavia l'abbassamento del numero di discussioni evidenzia, secondo me, un raffreddamento del "networking" fra i soci al quale il consiglio dovrebbe cercare di porre rimedio.

Lascio ad altri il computo dei post e della frequenza di aggiornamento del planet italiano perché sarei sicuramente male interpretato.

ITPUG ha una struttura di supporto informatico sicuramente complessa e funzionale (si veda qui), di gran lunga superiore a quella di molte altre associazioni PostgreSQL analoghe. Ritengo sia di vitale importanza per l'associazione che ogni consiglio riesca ad usare al meglio questa infrastruttura, nonché la storia che essa contiene (archivi, logs, ecc.) poiché rappresenta un bagaglio culturale di enorme valore.

GNU tar e l'ordine delle opzioni

Passando dalla versione di GNU tar 1.25 alla versione piu' recente 1.29 sono incappato in un piccolo e subdolo problema: la sintassi del comando è leggermente cambiata (orrore!).
In particolare la clausola --exclude deve essere specificata prima del file da archiviare (ma ovviamente dopo l'archivio stesso), altrimenti non verra' onorata e l'archivio conterrà file non voluti.
Quindi la sintassi:

tar cjvf archivio.tar.bz2 . --exclude=db

accettata e valida per GNU tar 1.25, deve essere riscritta per GNU tar 1.29 come

tar cjvf archivio.tar.bz2 --exclude=db .

Ora, considerando che essendo una opzione (--) facilmente riconoscibile, si poteva almeno inserire un warning per la sintassi errata!

martedì 17 gennaio 2017

Perl e gli operatori logici a differente priorità

Alcune difficoltà che noto in molti colleghi che iniziano a programmare in Perl venendo da altri linguaggi è il concetto di contesto, la differenza fra array e liste e gli operatori a bassa e alta priorità. Con riferimento a questi ultimi mi sono reso conto di non aver mai pensato realmente al loro utilizzo, basandomi per lo piu' sul fatto che "Perl farà la cosa giusta".

Per comprendere meglio la differenza fra "or" e "and" a bassa priorità e i loro duali "||" e "&&" ad alta priorità si consideri il seguente pezzetto di codice:

my $x = 10;
my $y = 20;

my $z = $x and $y;
say "Bassa priorita' = $z";
$z = $x && $y;
say "Alta priorita' = $z";

che produce come output

Bassa priorita' = 10
Alta priorita' = 20


Anzitutto utilizzo un and-logico con il primo valore ($x) non falso per evitare che sia cortocircuitato. Inoltre si tenga presente che, a differenza di altri linguaggi, gli operatori logici di cui sopra restituiscono l'ultimo valore valutato (Perl farà la cosa giusta...), che significa che prese singolarmente le due righe di codice seguente

$x and $y;
$x && $y;

restituiscono entrambe il valore $y. Ma l'and verbale "and" ha bassa priorità, e questo significa che viene applicato successivamente ad altri operatori, nell'esempio di cui sopra dopo l'operatore di assegnamento "=". Viceversa l'and-logico simbolico viene applicato prima di altri operatori, ovvero aggiungendo un po' di parentesi il programma di cui sopra è come se fosse valutato così:

( my $z = $x ) and $y;
$z = ( $x && $y );


Ecco un esempio piu' utile:

sub value{ my ( $value ) = @_; $value; }
$z = value( 0 ) or $y;
say "Bassa priorita' = $z";
$z = value( 0 ) || $y;
say "Alta priorita' = $z";


che produce il risultato

Bassa priorita' = 0
Alta priorita' = 20

subito.it e i compratori a "ondate"

Ho notato un trend particolare negli annunci che pubblico su subito.it: si verifica a ondata la richiesta per lo stesso pezzo/articolo e in un lasso di tempo spesso molto breve.
Vado a spiegare meglio.
Immaginiamo di mettere in vendita un articolo con i suoi accessori, ad esempio una macchina fotogratica con i relativi obiettivi. Ebbene si verifica che, negli stessi giorni, e comunque in un lasso di tempo che non supera mai le due settimane, vi siano piu' compratori interessati ad un particolare pezzo (ad esempio il flash) e solo a quel pezzo.
Questo mi ha portato a riflettere sul fatto che vi sia un possibile mercato parallelo ove vengono pubblicate ricerche di un determinato pezzo (nel mio esempio il flash) e quindi alcuni intermediari cerchino di accaparrarsi su subito.it il pezzo in questione per poi rivenderlo.
Un'altra teoria potrebbe essere che in club, gruppi di discussione, social network, un annuncio abbia maggiore risalto e tutti si accaniscano (magari dopo una discussione interna) per accaparrarsi uno dei pezzi in vendita.

Si tratta ovviamente solo di teorie e congetture, ma nella mia esperienza mi capita sempre piu' spesso di assistere a vere e proprie ondate di acquirenti sempre su quel singolo pezzo che magari è esposto da settimane o mesi.

Coincidenze?

sabato 14 gennaio 2017

Eclipse Neon, Tomcat 7 e il nome del server non editabile...

Sono inciampato in un piccolo bug di Eclipse Neon 1: ero impossibilitato a creare qualunque server Tomcat 7 perchè non mi era possibile inserire il nome del server, come invece avveniva correttamente per le altre versioni di Tomcat (sia inferiori che maggiori).
La soluzione, nel mio caso, è stata quella di rimuovere i due file

org.eclipse.jst.server.tomcat.core.prefs
org.eclipse.wst.server.core.prefs

dalla directory .metadata/.plugins/org.eclipse.core.runtime/.settings dentro al workspace.
Ovviamente tutto fatto ad Eclipse spento (e con backup di tali file).

Panda: un installer di distribuzioni Perl 6

Perché uno degli installer delle distribuzioni Perl 6 si chiama Panda e non qualcosa di piu' coerente come avviene per Perl 5 e cpan, cpanm e similari? Da giorni mi chiedevo questa cosa, ma non avevo il coraggio di chiderla, ma alla fine la risposta era tanto semplice quanto non tecnologica.
L'autore di panda ha chiamato quel software così perché era il nome del suo cane.

venerdì 13 gennaio 2017

KDE 5.9 e i menu' detached

KDE 5.9 (non ancora production-ready) riporterà una opzione interessante e alla quale gli utenti Mac OS 9-X sono sicuramente affezionati: i menu' staccati delle applicazioni.



KDE ha avuto questa funzione fin dalla versione 1, e in effetti la usavo quando muovevo i primi passi con questo meraviglioso desktop environment. Dopo tanti anni di KDE e altrettanti anni di non-menu'-staccati non so se troverò utile o meno questa funzionalità, diciamo che una caratteristica interessante è quella di poter stringere lo spazio occupato dal "contorno" di una applicazione lasciando quindi maggior spazio visivo all'utente che si può concentrare sui contenuti.

Ad ogni modo, meglio avere una opzione in piu' che una in meno; sicuramente questa possibilità rendere piu' facile la migrazione di utenti da un altro sistema operativo (con mele morsicate) a *nix + KDE!

Josh Berkus lascia il core team di PostgreSQL

E' di ieri la notizia che Josh Berkus, uno dei membri del core-team di PostgreSQL, si dimette dal core team stesso, e in effetti come diretta e rapida conseguenza non appare piu' il suo nome nell'elenco dei contributor (si veda il suo annuncio ufficiale qui.

Ho avuto poche occasioni di vedere Josh dal vivo, e quello che mi ha sempre colpito è la sua capacità come speaker, oltre alle sue competenze tecniche dettate da una grande esperienza. Ma un'altra cosa mi ha sempre colpito: Josh si è sempre dimostrato (nelle sue apparizioni nonché nelle sue comunicazioni nelle varie mailing list) una persona corretta e aperta, in una sola parola mi ha sempre dato l'impressione di essere una persona "pura" per quanto riguarda il progetto stesso.
Questo perché, a differenza di altri membri del progetto, si sono viste anche reazioni molto piu' business-oriented e meno community-centric.

Ritengo che Josh abbia svolto un ruolo molto importante per l'advocacy e la qualità del progetto PostgreSQL e, anche se il team è composto da persone piu' che valide, penso sarà difficile rimpiazzare pienamente un simile personaggio.

sabato 7 gennaio 2017

KDE Flickering

Problema: KDE 5.9 su Kubuntu 15.10 e scheda grafica NVIDIAGeforce 9600M GT e lo scherma sfarfalla ad ogni visualizzazione/cambio di finestra.

Nelle impostazoni del Composer ho modificato il rendered ad OpenGL 2 a OpenGL 3.1 e tutto ha iniziato subito a funzionare.

NOn è la prima volta che mi capita, ma solitamente questa impostazione sballata aveva solo l'effetto noioso di non far funzionare bene i cambi di desktop (tridimensionali), ma questa volta si è presentato con uno sfarfallio veramente molto noioso.

Padre, SQLite3 e security level (2) ...

Con riferimento al piccolo esperimento fatto sul codice di Padre, del quale ho già parlato e che non mi sono inventato io, ho trovato questo riferimento nei commit che indica esattamente la stessa soluzione.

Questo ovviamente sarebbe naturale se non si considera la data del commit stesso: infatti è risaputo che le versioni bundle delle installazioni possono mascherare alcuni bug che nel frattempo sono stati risolti nel codice sorgente. Ma il fatto è che il commit è di Febbraio 2016 e io ho installato la versione bundle in Gennaio 2017!

Chi deve essere incolpato? Secondo me il sistema di pacchetizzazione di ubuntu, anche se non sono certo che sia solo colpa loro. Sicuramente questo problema è indice che Padre viene usato poco o che lo si installa sempre e solo tramite CPAN.
Da notare che la versione bundle installata è la 1, mentre quella disponibile al momento nel repository è la 1.01.

venerdì 6 gennaio 2017

Padre, SQLite3, security level...

Mentre sono ancora alle prese per riuscire ad installare l'ultimo Padre da CPAN sul mio perlbrew non ho resistito alla tentazione, e così ho installato la versione bundle per kubuntu...tutto semplice, no?
NO!
Ecco cosa succede se si cerca di lanciare l'IDE:



$ padre
DBD::SQLite::db do failed: Safety level may not be changed inside a transaction at (eval 1904) l
ine 37.
Perl exited with active threads:
       1 running and unjoined
       0 finished and unjoined
       0 running and detached



Fortunatamente la soluzione è abbastanza semplice e nota: modificare il file Locker.pm e spostare la direttiva pragma da dopo l'inizio della transazione a subito prima, ossia


$ diff -p /usr/share/perl5/Padre/Locker.pm /usr/shar
e/perl5/Padre/Locker.pm~
*** /usr/share/perl5/Padre/Locker.pm    2017-01-06 19:01:45.429692436 +0100
--- /usr/share/perl5/Padre/Locker.pm~   2013-11-09 04:43:41.000000000 +0100
*************** sub shutdown {
*** 102,108 ****
 sub db_increment {
       my $self = shift;
       unless ( $self->{db_depth}++ ) {
!
 
               # Database operations we lock on are the most likely to
               # involve writes. So opportunistically prevent blocking
--- 102,108 ----
 sub db_increment {
       my $self = shift;
       unless ( $self->{db_depth}++ ) {
!               Padre::DB->begin;
 
               # Database operations we lock on are the most likely to
               # involve writes. So opportunistically prevent blocking
*************** sub db_increment {
*** 110,117 ****
               # database write operations faster, at the risk of config.db
               # corruption if (and only if) there is a power outage,
               # operating system crash, or catastrophic hardware failure.
!           Padre::DB->pragma( synchronous => 0 );
!           Padre::DB->begin;
       }
       return;
 }
--- 110,116 ----
               # database write operations faster, at the risk of config.db
               # corruption if (and only if) there is a power outage,
               # operating system crash, or catastrophic hardware failure.
!               Padre::DB->pragma( synchronous => 0 );
       }
       return;
 }


Le mie dimissioni da ITPUG

Cari soci,
anzitutto buon anno (anche se in ritardo)!
E' con dispiacere e un po' di imbarazzo che vi informo che qualche giorno addietro, precisamente prima di Natale, ho presentato le mie dimissioni dal ruolo di consigliere.
La mia partecipazione in ITPUG si è ridotta per cause esterne, e ultimamente mi trovo anche in difficoltà nel rappresentare l'associazione.
In considerazione di tutto ciò, sperando nel meglio per l'associazione, e senza voler occupare un ruolo in modo "sterile", mi faccio quindi da parte.

Preciso, qualora necessario, che dalla data della presentazione delle mie dimissioni mi sto astenendo da esprimere ogni opinione in consiglio, se non espressamente richiesto.

Ho seguito e servito ITPUG dalla sua costituzione, la ritengo una esperienza interessante ed utile, grazie anche a voi.

Ad ogni modo non vi sbarazzerete facilmente di me, e ci ritroveremo a conferenze e sui vari canali informatici come al solito!

Grazie,
Luca



Questa è la lettera che ho inviato nella mailing list soci di ITPUG per confermare le mie dimissioni dal ruolo di consigliere.
Niente di drammatico, né tanto meno melodrammatico, ma spero con questo mio post di poter chiarire meglio la situazione e la mia decisione, che sono certo potrà essere interpretata negativamente, molto piu' di quanto non lo sia.

La parola chiave di tutto questo è coerenza.
Coerenza con me stesso, con gli impegni presi, con l'associazione che ho contribuito a creare e che ho risollevato.
Non posso piu' onorare gli impegni presi, perché vicissitudine esterne ad ITPUG mi tengono lontano dall'associazione, e di questo ne sono mortificato.
Quindi, per coerenza con l'impegno preso, trovo corretto farmi da parte.
Ma c'è anche la coerenza con me stesso: io ho una visione della vita di associazione che, sicuramente per una mia interpretazione sbagliata, tende a stridere con quanto osservo ultimamente in ITPUG. In particolare se ripenso all'enorme impegno che mi ero assunto come presidente anni fà, quando sono riuscito a risollevare (non da solo!) sia l'associazione, prossima alla chiusura, che il PGDay.IT; entrambi versavano ormai in uno stato comatoso e sicuramente non open.

Come ho scritto brevemente sopra è stata una esperienza interessante, ma anche impegnativa. Sono passato attraverso molte soddisfazioni e anche molte delusioni, perfino interrogativi. Mi sono state rivolte belle parole e brutte parole, perfino azzardi su conflitti di interesse. Sorrido se ci ripenso, anche perché per me PostgreSQL non è mai stato piu' che un hobby, una passione. E anche perché, se ben ricordo, all'ultimo PGDay.IT al quale ho partecipato sono stato l'unico organizzatore a segnarsi come membro ITPUG invece che di una azienda, ente, università.

Ho sempre tentato di svolgere una attività sana e alla luce del sole, cercando di dare pari opportunità a tutti quanti. Ho sempre tentato di portare avanti il nome dell'associazione, facendola comparire anche nel planet.postgresql.org, sulle riviste per le quali scrivevo articoli, e nelle piccole interviste fatte.

Ho conosciuto molta gente interessante, molti stereotipi altrettanto interessanti e molte realtà aziendali ed enti che fanno duro lavoro per mantenere quello spirito open che mi ha sempre affascinato.

Ora, inutile farla tanto melodrammatica: non sarò stato infallibile, non sarò stato impeccabile, ma ho speso veramente tante energie per questa associazione, e il solo fatto che sia qui a scrivere a riguardo testimonia quanto sia stata per me una decisione difficile.

Perché anticipare le dimissioni visto che il consiglio sta per giungere alla sua "naturale" scadenza? Già, è una domanda lecita, sulla quale i maliziosi potranno lucrare teorie complottiste, ma la questione è realmente semplice come eseguire una rollback.
Il fatto è che non mi sento piu' di fare parte del consiglio, e avere senzazioni senza-azioni non è da me. Come dicevo, coerenza...

Cosa succederà adesso?
Beh, niente panico! ITPUG ha un consiglio formato da gente esperta che saprà portare avanti l'associazione. Dopotutto io non sono certo indispensabile!
E comunque mi rendo disponibile ad affiancare il consiglio qualora lo si riterrà opportuno.

giovedì 5 gennaio 2017

Perl non ha paura di Alma!

F.E.A.R. è sicuramente il mio gioco preferito di tutti i tempi.
All'epoca del primo episodio che ha dato inizio alla saga horror c'era una versione utilizzabile gratuitamente solo on-line, chiamato FEAR Multiplayer. Il concetto non era certo nuovo: un server e tanti giocatori che si affrontavano in un deathmatch, capture the flag o slow motion.

E qui arriva la potenza di CPAN: esiste un modulo per analizzare in modo "preciso" e portabile i risultati delle partite.

Ok, utilità prossima allo zero (almeno per me), ma questo dà l'idea della vastità di CPAN...

mercoledì 4 gennaio 2017

Perl: come si scrivono i numeri?

Dovendo insegnare a mio figlio la matematica di base, ovvero i numeri, ho passato qualche minuto nello scrivere un semplice programmino Perl che mostra come si scrivono i nomi dei numeri in italiano.
Il giro è abbastanza semplice: si definiscono degli array per i nomi delle unità e delle decine, dopodiché si divide il numero per le decine in modo da ottenere il numero aritmeticamente scomposto.
Come esempio, da 57 si ottiene 50 + 7. Con questi due valori si estraggono i nomi simbolici di decine e unità, poi si tagliano le eventuali vocali doppie nell'unione dei nomi.
Ovviamente una complicazione è data dal range 10-20, quello dei teen.


#!/usr/bin/env perl

use v5.10;

my $units = {
         1 => 'uno'
       , 2 => 'due'
       , 3 => 'tre'
       , 4 => 'quattro'
       , 5 => 'cinque'
       , 6 => 'sei'
       , 7 => 'sette'
       , 8 => 'otto'
       , 9 => 'nove'
       , 0 => ''
};


my $tenths = {
   10 => 'dieci'
       , 11 => 'undici'
       , 12 => 'dodici'
       , 13 => 'tredici'
       , 14 => 'quattordici'
       , 15 => 'quindici'
       , 16 => 'sedici'
       , 17 => 'diciassette'
       , 18 => 'diciannove'
       , 20 => 'venti'
       , 30 => 'trenta'
       , 40 => 'quaranta'
       , 50 => 'cinquanta'
       , 60 => 'sessanta'
       , 70 => 'settanta'
       , 80 => 'ottanta'
       , 90 => 'novanta'
       , 100 => 'cento'
};


for my $value ( 1..99 ){


   my ( $unita, $decine ) = 0;

   if ( $value < 10 ){
       $unita  = $value;
       $decine = 0;
   } elsif ( $value >= 10 && $value < 20 ){
       $unita  = 0;
       $decine = $value;
   }
   else{
       $unita  = $value % 10;
       $decine = $value - $unita;
   }
   

   my $risultato = sprintf "%s %s %s = %s %s %s",
   ( $tenths->{ $decine }  ? $tenths->{ $decine } : "" ),
   ( $tenths->{ $decine }  && $units->{ $unita }  ? "+" : "" ),
   ( $units->{ $unita }  ? $units->{ $unita } : "" ),
   ( $tenths->{ $decine }  ? $tenths->{ $decine } : "" ),
   ( $tenths->{ $decine }  && $units->{ $unita }  ? "+" : "" ),
   ( $units->{ $unita }  ? $units->{ $unita } : "" );

   my $slang = $tenths->{ $decine };
   if ( $tenths->{ $decine } =~ /[aeiou]$/
        && $units->{ $unita } =~ /^[aeiou]/ ){
       $slang =~ s/[aeiou]$//;
   }
   $slang .= $units->{ $unita };
   say "$value si compone di $risultato\n\te si legge \t" . uc( $slang );
}



Il risultato finale è qualcosa di simile:



90 si compone di  90 + 0 = novanta
       e si legge      NOVANTA
91 si compone di  90 + 1 = novanta + uno
       e si legge      NOVANTUNO
92 si compone di  90 + 2 = novanta + due
       e si legge      NOVANTADUE
93 si compone di  90 + 3 = novanta + tre


martedì 3 gennaio 2017

Un brutto ma veloce meccanismo di interpolazione di stringhe in Perl

Ecco un meccanismo semplice e veloce, quanto brutto, per fare una interpolazione di stringa in Perl via nome dei parametri invece che posizione. L'idea è quella di associare i parametri in un hash con le chiavi relative, e poi effettuare una sostituzione tramite regexp sulla stringa per sostituire i parametri ovunque appaiano.
La stringa di inizio/fine interpolazione può essere ovviamente qualunque sequenza sensata, nell'esempio che segue ho usato quella dell'interpolazione Ruby.


#!/usr/bin/env perl

use v5.10;

my $params = {
   foo => "this is foo"
       , bar => 'this is bar'
       , baz => 'this is baz'
};


my $string = "Here is a string that needs to substitute variables #{foo} and #{bar} and last #{b
az}!";

( my $result = $string ) =~ s/\#{(\w+)}/$params->{$1}/ge;

say $result;


Come si può notare ogni parametro da interpolare è racchiuso fra la stringa #{ e ], con il nome relativo al parametro. Quindi #{foo} viene poi sostuito con il valore di $params->{foo}. Per fare questo si utilizza un backreference nella cattura della parola \w+ racchiusa come primo parametro $1 nell'espressione regolare.

Ecco un esempio piu' utile di questa interpolazione:


my $params = {  
   username => 'luca'
       , server => 'remote.node.com'
       , port => 22
       , protocol => 'ssh'
};


my $connection_string = "#{protocol}://#{username}@#{server}:#{port}";

( my $url = $connection_string ) =~ s/\#{(\w+)}/$params->{$1}/ge;

che produce come risultato finale ssh://luca@remote.node.com:22

java: No such file or directory (!)

Ci sono applicazioni che richiedono un JDK per eseguire correttamente, così l'unica cosa che si può fare è quella di scaricare dal sito Oracle una qualche versione, installarla, configurare JAVA_HOME o qualcosa di simile (a seconda dell'applicazione) e lanciare il programma desiderato.
Abbastanza semplice, no?
Eppure oggi ho dovuto combattere con una installazione della JDK 1.8 (111) e un errore abbastanza subdolo riportato dalla shell:

/opt/jdk1.8.0_111/bin/java: No such file or directory

quando ovviamente il file era al suo posto, eseguibile e pronto a servire il sistema.
Inizialmente ero protato a pensare ad un classico problema di permessi, ma come ho già scritto il file era correttamente eseguibile. Forse un problema di exec sul filesystem? No, nemmeno questo.
Dopo un po' di ricerca ho scoperto che il mio pc mancava di una libreria, e quindi ben presto si è fatto un passo avanti:

sudo apt-get install libc6-i386

ma questo ancora non era sufficiente a far funzionare tutto l'ambiente, specialmente quello grafico, e così ho dovuto installare anche

sudo apt-get install libxrender1:i386 libxtst6:i386 libxi6:i386

e finalmente ho un jdk funzionante perfettamente.
Certo che il primo errore, quello riportato dalla shell, è piuttosto fuorviante!