Il pensiero di Einstein sulla crisi

Ieri sera in una pizzeria ho trovato questo pensiero di Einstein in bella vista attaccato al muro. Gli sono molto affezionato, sto finendo di studiare un suo importante lavoro, e mi ha colpito che lui, socialista, antimilitarista, dicesse cose del genere. In effetti quando le ha dette non aveva ancora visto la seconda guerra mondiale, non aveva ancora fatto nascere il progetto Manhattan, quindi tutto si spiega. Però sono righe che trasmettono una grande forza e invitano ad essere fiduciosi in se stessi. Le riporto verbatim da The World As I See It (Il mondo come io lo vedo), pubblicato nel 1934.

 

Let’s not pretend that things will change if we keep doing the same things. A crisis can be a real blessing to any person, to any nation. For all crises bring progress. Creativity is born from anguish, just like the day is born from the dark night. It’s in crisis that inventiveness is born, as well as discoveries made and big strategies. He who overcomes crisis, overcomes himself, without getting overcome.
He who blames his failure to a crisis neglects his own talent and is more interested in problems than in solutions. Incompetence is the true crisis. The greatest inconvenience of people and nations is the laziness with which they attempt to find the solutions to their problems. There’s no challenge without a crisis. Without challenges, life becomes a routine, a slow agony. There’s no merit without crisis. It’s in the crisis where we can show the very best in us. Without a crisis, any wind becomes a tender touch. To speak about a crisis is to promote it. Not to speak about it is to exalt conformism. Let us work hard instead. Let us stop once and for all the menacing crisis that represents the tragedy of not being willing to overcome it.

XML beautifier con xmllint

xmllint è una utility che fa parte del pacchetto:

libxml2-utils

Per installarlo

$ sudo apt-get install libxml2-utils

Avevo bisogno di un “abbellitore” (beautifier) per codice XML. Ci sono tanti bei servizi anche online, ma me ne serviva uno di integrato con l’editor PHP che uso, Geany.

Geany consente di inviare frammenti di codice sezionati dal file (anche tutto il file) a questo programma che mi produce l’output abbellito direttamente nell’editor.

Esempio, ho questo file

xmllint0

 

Seleziono il file e richiamo da menu la funzione xmllint:

 

 

xmllint1

 

Il risultato è questo

 

xmllint2

 

Geany è configurabile per aggiungere comandi di questo tipo. Per farlo si segue lo stesso menu della seconda figura e si seleziona la voce “Imposta i comandi personalizzati”:

 

impostaSi edita il comando, nel mio caso il comando è

xmllint --format -

(mi raccomando il alla fine, che in questo caso significa standard input, file da passare come argomento al comando)

Aiuto!!! LA CPU bolle!

AMD Heat SinkSe vi siete trovati come me ad iniziare l’estate con il PC che scotta, vi consiglio queste utilities:

  • i8kmon
  • i8kctl

che vi servono per monitorare e controllare i parametri per il raffrescamento.

Ulteriori informazioni nel Wiki.

Fonti:

  • http://www.cyberciti.biz/faq/controlling-dell-fan-speeds-temperature-on-ubuntu-debian-linux/
  • http://manpages.ubuntu.com/manpages/karmic/man1/i8kctl.1.html
  • http://askubuntu.com/questions/281478/fan-speed-in-ubuntu-pwmconfig-no-pwm-capable-sensor-modules-installed

 

Pillole CSS: Responsive design

Today's latte, World Wide Web Consortium (W3C).Il responsive web design è l’arte di disegnare pagine web visibili da tutti i tipi di viewport, cioè di dispositivi: dal browser su computer desktop, al notebook, al tablet e allo smartphone.

Ne abbiamo già parlato qui.

Fondamentalmente si tratta di saper usare i fogli di stile (CSS) che, essendo “cascading” vengono applicati a cascata per cui la stessa regola presente in vari fogli di stile viene resa dal browser come uguale a quella letta nell’ultimo foglio di stile.

Il problema della decisione del tipo di dispositivo (e della sua orientazione) si risolve con lo strumento delle media queries: una grammatica che ci permette di istruire il browser su quali fogli di regole deve caricare a seconda del risultato di queste interrogazioni.

Prendo spunto da questo sito.

Prendiamo ad esempio queste istruzioni di importazione che si trovano nelle intestazioni delle pagine html:

    <link rel="stylesheet" media="(max-width: 640px)" href="max-640px.css">
    <link rel="stylesheet" media="(min-width: 640px)" href="min-640px.css">
    <link rel="stylesheet" media="(orientation: portrait)" href="portrait.css">
    <link rel="stylesheet" media="(orientation: landscape)" href="landscape.css">

In sostanza il browser adotta il foglio di stile max-640px.css se la pagina è stata caricata in un dispositivo piccolino (uno smartphone), oppure caricherà il foglio min-640px.css se il viewport è più comodo (ad esempio un computer desktop o laptop).

Inoltre il browser sceglie al volo il foglio portrait.css (disposizione tipo “ritratto”) o landscape.css (disposizione tipo “paesaggio”) a seconda di come ruotiamo lo smartphone o il tablet, oppure se ridimensioniamo il browser in una finestra stretta e alta.

I diversi fogli di stile contengono regole diverse per gli stessi oggetti; per esempio ne l mio caso avevo un layout a tre colonne che si poteva visualizzare solo su uno schermo grande; per gli schermi piccoli mando a capo una sotto l’altra le tre colonne.

Versione responsive per desktopdesktop

Versioneresponsive per smartphone

Responsive design

Responsive design

Pillole PHP/Yii: far transitare parametri da HTTP alla pagina web

yiiDalla request alla pagina web

Grande è la tentazione di utilizzare i valori provenienti dalla $_REQUEST direttamente nella view, ma così facendo rischiamo di perdere pezzi per strada.

Il percorso corretto da compiere è questo

  $_REQUEST ---> controller ---> action ---> view.

Esempio, voglio far transitare una variabile $payment_id dal flusso HTTP alla pagina web

  index.php?r=voucher/create&payment_id=2

Step 1: dalla request al controller

Supponiamo di voler creare un nuovo record per l’oggetto voucher, che ha bisogno di essere agganciato al record payment_id=1

  • file VoucherController.php
   public function actionCreate()
   {
       $model=new Voucher;
       if(isset($_REQUEST['Voucher']))
       {
           $model->attributes=$_REQUEST['Voucher'];
           $payment_id = $model->payment_id;
           if($model->save())
               $this->redirect(array('index','id'=>$model->id, 'payment_id' => $payment_id));
       }
       else 
       {
           $payment_id = $_REQUEST['payment_id'];
       }
       $this->render('create',array(
           'model'=>$model,
           'payment_id' => $payment_id,
       ));
   }

con questo frammento valorizziamo la variabile da passare e la passiamo al metodo create nell’array dei parametri (il secondo parametro della funzione render).

Step 2: dal controller alla action

  • file voucher/create.php
   <?php echo $this->renderPartial('_form', array('model'=>$model, 'payment_id' => $payment_id)); >?>

il valore $payment_id è quello che arriva dalla funzione render citata sopra. Con questa istruzione passiamo al template _form.php l’array che contiene $model e $payment_id

Step 3: dalla action alla view

  • file voucher/_form.php
   <?php echo $form->hiddenField($model,'payment_id', array('value' => $payment_id)); ?>

questo è l’ultimo passaggio, siamo arrivati. L’html generato al volo conterrà questo campo hidden:

<input id=”Voucher_payment_id” type=”hidden” name=”Voucher[payment_id]” value=”2“>.

Segui tutto l’articolo sul Wiki.

Pillola PHP/Yii lavorare con le date

yiiSalvare una data 25/12/2015 in MySQL, leggerla e visualizzarla nello stesso formato

Occorre un po’ di magheggio per gestire le date con Yii. Il formato con cui MySQL registra out-of-the-box i campi data è quello ISO (yyyy-mm-dd). Per rendere compatibile la nostra applicazione con questo formato (non andiamo a cambiare il locale del database, e non ci poniamo al momento obiettivi sul rendere localizzabile l’applicazione) occorre

  • trasformare 25/12/2015 in ISO in fase di scrittura e
  • trasformare da ISO a 25/12/2015 in fase di lettura

Lettura di un campo data

Si scrive un filtro (afterFind) da aggiungere al model degli oggetti (tabelle) in cui ci sono le date che vogliamo gestire:

   protected function afterFind(){
                                                
       foreach($this->metadata->tableSchema->columns as $columnName => $column)
       {                        
           if (!strlen($this->$columnName)) continue;
           
           if ($column->dbType == 'date')
           {
               $timestamp = CDateTimeParser::parse($this->$columnName, 'yyyy-MM-dd');
               $this->$columnName = Yii::app()->dateFormatter->formatDateTime(
                 $timestamp,'short',null);
           }
           elseif ($column->dbType == 'datetime')
           {
               $timestamp = CDateTimeParser::parse($this->$columnName, 
                  'yyyy-MM-dd  hh:mm:ss');
               $this->$columnName = Yii::app()->dateFormatter->formatDateTime(
                  $timestamp);
           }
       }
       
             return true;
   }

Con il parser (CDateTimeParser::parse) catturiamo la data ISO che esce dalla query e la riformattiamo con il formatter (Yii::app()->dateFormatter->formatDateTime) nel formato short (dd/mm/yyyy) e senza l’orario se il campo è date, con l’orario se è datetime: in particolare, ‘short’, null dice che la data è in formato dd/mm/yyyy e non visualizza l’ora e i minuti.

Nota bene

Non è necessario ricompilare lo scaffold se si cambia il tipo campo database da date a datetime.

Scrittura di un campo data

Anche qui si aggiunge un metodo (beforeSave) al model (sempre nello stesso file quindi)

   protected function beforeSave(){
       foreach($this->metadata->tableSchema->columns as $columnName => $column)
       {
           if ($column->dbType == 'date')
           {
               $this->$columnName = date('Y-m-d', CDateTimeParser::parse(
                   $this->$columnName, 'dd/MM/yyyy'));
           }
           elseif ($column->dbType == 'datetime')
           {
               $this->$columnName = date('Y-m-d H:i:s', CDateTimeParser::parse(
                   $this->$columnName, 'dd/MM/yyyy'));
           }
       
       }
   
   return true;
   }

Grazie al sito forum di Yiiframework.

Il Wiki completo

Pillola Oracle

logo-oracle-large

Oggi la pillola parla di Oracle.

Più volte mi sono trovato a gestire errori Oracle che hanno origini diverse.

In questo sito ho trovato quasi tutti i casi a cui mi sono trovato di fronte. In questo caso però affrontiamo solo l’aspetto fondamentale del collegamento tra un client e un server.

Caso d’uso

La situazione è raffigurata qui di seguito, un client Oracle (C) cerca di collegarsi ad un server Oracle (S):

Oracle: collegamento client-server
Oracle: collegamento client-server

In realtà più che due macchine fisiche, client e server sono due processi che possono anche coesistere nella stessa macchina.

Quando il client chiama il server, viene eseguita una serie di operazioni: devono infatti essere instradati da TCP/IP dei pacchetti di informazioni; occorre stabilire qual è l’host da chiamare, qual è il nome del servizio in ascolto e della porta in cui è in ascolto.

Il descrittore TNS

Queste informazioni sono contenute in architetture diverse: può essere un LDAP, un servizio Oracle di risoluzione dei nomi (Oracle Names Server) oppure, nel caso più semplice, un file che risiede in un filesystem accessibile dalla macchina in cui viene eseguito il client. Questo file si chiama tnsnames.ora ed è un elenco di descrittori simili a quello che segue:

ora_descriptor_name =
(DESCRIPTION =
    (ADDRESS_LIST =
        (ADDRESS = 
            (PROTOCOL = TCP)(HOST = ora_host_name)(PORT = 1521)
        )
    )
    (CONNECT_DATA =
        (SERVICE_NAME = ora_service_name)
    )
)

I parametri fondamentali sono

  • il nome del descrittore (ora_descriptor_name) che è quello che sarà utilizzato dal programma che vuole effettuare la chiamata (ad esempio sqlplus, oppure un programma PHP o Java)
  • il nome dell’host (ora_host_name) che ospita il server (il nome ora_service_name deve essere presente nel file /etc/hosts della macchina che ospita il client, oppure deve esistere un nome DNS nella rete a cui accede il client)
  • la porta (1521)
  • il nome del servizio in ascolto nel server (ora_service_name)

I nomi ora_descriptor_name, ora_host_name, ora_service_name sono nella realtà dei nomi di fantasia (pur secondo un determinato schema di nomi) che possono essere dati a macchine e servizi; ad esempio

  • ora_descriptor_name = alberghi.mydomain.com
  • ora_host_name = oracle1.mydomain.com
  • ora_service_name = alberghi

Errori che possono accadere

1) non c’è una voce ora_descriptor_name nel tnsnames.ora

    => “ORA-12154: TNS:could not resolve the connect identifier specified”

2) c’è la voce MA ora_host_name non c’è nel dns né nel file etc/hosts

    => “ORA-12545: Connect failed because target host or object does not exist”

3) c’è la voce, c’è ora_host_name in /etc/hosts MA punta ad un ip inesistente

    => “ORA-12545: Connect failed because target host or object does not exist”

4) c’è la voce, c’è ora_host_name, l’IP è corretto MA lato server non c’è un listener in ascolto

    => “ORA-12541: TNS:no listener”

5) c’è la voce, c’è ora_host_name, IP corretto, listener in ascolto MA in una porta diversa dalla 1521

    => “ORA-12560: TNS:protocol adapter error”

6) c’è la voce, c’è ora_host_name, IP corretto, listener in ascolto sulla porta giusta MA non esiste ora_service_name

    => “ORA-12514: TNS:listener does not currently know of service requested in connect descriptor”


Analisi di log con Elasticsearch “Kibana”

Sto prendendo un po’ di confidenza con questo sistema di analisi di file log che sembra molto potente e flessibile.

Nello specifico, la pillola di oggi consiste nello scrivere un filtro per data che estragga tutti i record da una certa data in poi.

La linea di log ha un aspetto simile:

{"ID":"9ec1468a-c200-469f-8586-31e30b0043fb","sequence_id":"10942701","source":null,"type":"result",
"@timestamp":"2015-02-13T11:36:29.218Z","status":"ERROR","raw_data":"<result>...

Quello che voglio fare è applicare il filtro sul campo @timestamp quindi dalla lista in basso a sx:

kibana1

Successivamente occorre personalizzare il filtro come nella figura seguente (usare le parentesi quadre se si vogliono includere gli estremo di ricerca, cioè >= o <=, le graffe nel caso NON si vogliano includere, cioè > o <):

kibana2

In questo caso, per esempio, seleziono tutte le righe di log dal 2 febbraio 2015 (giorno incluso) in poi.

Yii pillole

yiiContinuiamo la nostra serie di pillole su piccoli ma spesso fastidiosi task, questa volta sul gestore di design pattern Yii. Come realizzare un menu a tendina, o combo box, o casella di selezione o dropdown menu con Yii, prendendo i valori da una tabella di un database.

In sostanza ciò che vogliamo realizzare è una cosa del genere:

dropdownIl dettaglio delle operazioni da fare è nel Wiki.

Bluefish: come salvare i parametri di configurazione

800px-PHP-n_logo PNGUso Bluefish editor per scrivere codice PHP/JavaScript e HTML.

Consente anche di gestire progetti un po’ come fa Eclipse, ma lo uso sostanzialmente come editor.

Da un po’ di tempo avevo questo comportamento fastidioso: impostavo come carattere di default dell’editor un Monospace 9pt

 

(Modifica > Preferenze > Caratteri e colori > caratteri dell’editor)

ma dopo che avevo chiuso il programma, alla prossima riapertura mi ritrovavo il font a 10pt.

Evidentemente non riuscivo a scrivere nel file di configurazione.

Lanciando da consolle bluefish infatti avevo questo output:

 marcob@jsbach:~/.bluefish$ bluefish
 error reading list 1 Errore nell'aprire il file: File o directory non esistente
 
 ** (bluefish:4731): WARNING **: no configfile rcfile-2.0, try to convert config 
 files from older versions
 
 config file migration error 1:Errore nell'aprire il file: File o directory non esistente
 error reading list 1 Errore nell'aprire il file: File o directory non esistente
 cleanup_scanner, memory scancache 0(0Kb+0Kb) found 0(0Kb) fcontext 0(0Kb) = 0Kb
 error reading list 14 Errore nell'aprire il file: Permesso negato
 
 ** (bluefish:4731): WARNING **: failed to delete recovered autosave_journal /home/marcob/.bluefish/autosave_journal.32486: Errore nel rimuovere il file: Permesso negato

I problemi erano due (no config file e failed to delete) ma la causa comune era nella ownership della cartella ~/.bluefish, che era di root e scrivibile solo da lui. Quindi è stato sufficiente far acquisire all’utente “normale” la proprietà della cartella:

  $ sudo chown -R marcob:marcob .bluefish/