Tutti gli articoli di ephestione

Il driver di rete bridged Virtualbox rallenta la velocità della LAN

Quando sono passato dal WiFi ad una connessione fisica con cablaggio CAT5E dal router nell’altra stanza a questo PC, sono saltato da velocità di trasferimento dei file di massimo 2-3MB/s (ma quasi sempre 1MB/s, spesso meno) a 11-12MB/s.

Ultimamente ho notato come la velocità per scaricare alcuni fansub dal server domestico era scesa a 5-6MB/s, esattamente la metà di quella a cui ero abituato; dall’icona di rete nell’area di notifiche di Windows 7 ho notato che era presente un secondo adattatore di rete, che ho fatto risalire alla scheda virtuale di rete in modalità bridged installata da Virtualbox. Siccome l’avevo recentemente installato per testare una cosa di cui ora non ho più bisogno, ho disinstallato Virtualbox, e non appena il driver dell’adattatore di rete virtuale è stato rimosso, la velocità tornata a 11-12MB/s.

Questo dovrebbe essere un comportamento normale?

Query MySQL con ORDER BY,GROUP BY per ordinare e rimuovere righe doppie

Apparentemente questo è un dilemma piuttosto discusso; molti “niubbi” di MySQL (me compreso) vogliono usare un SELECT su righe di una tabella, dove sanno che il campo ‘a’ ha valori ripetuti più volte, ma vogliono estrarre una sola riga per ogni valore, al tempo stesso facendo in modo tale che la riga estratta, tra tutte quelle disponibili, sia quella che ha il campo ‘b’ col valore più basso, o alto, o lungo, o corto tra tutte le possibili… bene, il primo tentativo che fanno questi niubbi è una query come questa:

SELECT a, b, c FROM table WHERE <conditions> ORDER BY b DESC GROUP BY a

e ottenendo un errore si rendono conto che non è possibile, perché la sintassi MySQL vuole che la clausola GROUP BY venga prima di quella ORDER BY, come nel seguente esempio:

SELECT a, b, c FROM table WHERE <conditions> GROUP BY a ORDER BY b DESC

In questo caso però, le righe prima vengono sfoltite rimuovendo i doppioni del campo ‘a’ (con un criterio che non possiamo scegliere noi), e solo dopo vengono ordinate per ‘b’, e questo non ci serve.

Quindi come si fa per ordinare prima le righe così come ci servono, e poi rimuovere quelle di troppo?

Per essere brevi, ecco come:

SELECT t.a, t.b, t.c
  FROM table t
  JOIN (SELECT MIN(b) as b
    FROM table
    GROUP BY a) t2 ON t2.b = t.b
  WHERE <condizioni>
  GROUP BY a
  ORDER BY NULL

Quello che fa questo “scheletro di query”, è ordinare le righe per il campo ‘b’ (in senso crescente, cioè ASC, siccome è stata usata la  funzione MIN(), altrimenti potreste usare MAX() per un ordinamento decrescente, e/o altre funzioni in base al tipo di ordinamento che vi serve) all’interno dell’operatore JOIN, e quindi raggruppa per valori unici del campo ‘a’ le righe nella query esterna. L’operatore ORDER BY NULL serve a evitare che l’interprete MySQL perda tempo a ordinare le righe risultanti, siccome un ordinamento viene già fatto con l’operatore GROUP BY. La query è efficace, ma poco efficiente, siccome risulta molto lenta.

All’inizio pensavo che mi sarei dovuto accontentare, tuttavia non soddisfatto, siccome imparando PHP e MySQL sono col tempo diventato ossessionato con l’ottimizzazione per le prestazioni, ho pensato di provare un approccio alternativo, cioè richiedere via SQL le righe “grezze”, e poi rielaborarle successivamente in PHP.

Esaminiamo questo approccio:

$results=doquery("
  SELECT a, b, c
    FROM table
    WHERE <condizioni>
  ");
$datagrid=array();
while ($slot=mysql_fetch_array($results)) $datagrid[]=$slot;
sort($datagrid);
$compare="";
foreach ($datagrid as $k=>$row)
  if ($row[0]==$compare)
    unset($datagrid[$k]);
  else
    $compare=$row[0];

Alla fine di questas routine, $datagrid contiene tutti i dati di cui avete bisogno, e solo quelli; spieghiamo:

  • la query SQL restituisce le righe non processate che corrispondono alle condizioni di WHERE, quindi con i doppioni del campo ‘a’, e senza nessun ordinamento particolare
  • dopo aver inserito i campi delle righe in un array multidimensionale, la funzione PHP sort() si occupa dell’ordinamento dell’array in base agli elementi dei sotto-array, prima per subarray[0], poi per subarray[1] e così via (apriamo una parentesi su questo discorso: se cercate su internet “ordinamento di un array multimensionale in PHP” -meglio se in inglese-, troverete ogni tipo di script artigianale, come se la sola funzoine sort() funzionasse solo sugli array monodimensionali; beh, io ho PHP5 sul mio hosting, ed ho provato a passare il suddetto array multimendionale a sort(), sorpresa delle sorprese l’ha messo in ordine esattamente come serviva a me; se però per voi non dovesse funzionare, recatevi sulla pagina di php.net dedicata alla funzione sort, e nella sezione dei commenti troverete molti esempi già compilati di script “casalinghi”, anche se non saranno mai veloci come sort() che è una funzione propria di PHP)
  • la stringa $compare è inizializzata, e usata nel successivo ciclo foreach per fare un unset() di tutti i subarray dove l’elemento [0] (il nostro campo ‘a’) è uguale a quello del precedente subarray, quindi rimuovendo i duplicati oltre la prima riga

Dopo di ciò potete passare l’array risultate ad un’altra routine per processare i dati così come vi servono.

Per portare la performance ancora oltre, nel caso abbiate bisogno di eseguire una procedura semplice sui dati ottenuti, potete modificare il ciclo foreach dell’esempio come segue:

foreach ($datagrid as $row)
  if ($row[0]!=$compare) {
    $compare=$row[0];
    <routine di elaborazione in questo spazio>
  }

Chiarendo, questo ciclo foreach non si occupa di eliminare i subarray duplicati, ma si limita ad eseguire la routine di elaborazione solo sulla prima istanza di un subarray, ignorando le copie successive; in questo modo, tagliate diverse volte sui tempi di esecuzione:

  1. risparmiate il tempo di un secondo foreach per scorrere l’array ed eseguire le operazioni di elaborazione, siccome queste vengono lanciate direttamente dal primo foreach
  2. evitate di lanciare la funzione unset() tante volte quanti sono i doppioni
  3. risparmiate i cicli di CPU e la memoria necessari a definire un secondo array per contenere i dati sfoltiti, siccome state lavorando direttamente sul primo array costruito sui risultati della query
  4. semplificate il foreach perché non richiedete più un elemento associativo ($k=>$row) ma solo il valore dell’elemento

Con i miei benchmark (su un set di dati MOLTO ristretto, lo ammetto), ho misurato un incredibile aumento di prestazioni di cento volte (già, 100 volte più veloce) per l’ordinamento/sfoltimento in PHP, paragonato al “doppio GROUP BY” in MySQL (0.08 secondi per MySQL/PHP, contro 8 secondi per la query complessa, su 100 iterazioni). I vostri risultati potrebbero essere diversi, ma partendo da un vantaggio di cento volte, c’è molto spazio di manovra.

Ricerca invertita in MySQL: controlla se le parole chiave nel campo corrispondono ad un testo

Di solito, “cercare in un database” significa cercare quelle righe che contengono un “documento” in un campo, che corrisponde a delle parole chiave (di solito usando la funzione MATCH AGAINST); mettiamo invece che vogliate fare il contrario, cioè avete una tabella con delle righe che contengono un campo in cui avete memorizzato delle parole chiave, e volete selezionare solo quelle righe in cui le parole chiave corrispondono ad un testo o un particolare documento. Questa è quella che io chiamo una ricerca invertita.

Uno scenario reale: avete un sito di offerte di lavoro, ed i candidati cercano annunci di loro gradimento, ma non ne trovano nessuno, oppure ce ne sono troppo pochi e non interessanti. O continuano a collegarsi al sito ripetendo la ricerca periodicamente (ad esempio con le parole chiave “veterinar* gatt*“, perché vogliono prendersi cura degli animali, e hanno un debole per i gatti in praticolare), o si iscrivono al feed RSS di quella ricerca (se ne avete uno)… oppure “salvano” la ricerca e aspettano che sia il sito ad inviare loro una mail non appena compare un nuovo annuncio pertinente, ed è qui che torna utile questo articolo.

Salvare le parole chiave per ogni utente in una tabella MySQL è semplice, ma quanto è semplice verificare se un annuncio appena inserito corrisponde alle parole chiave? In PHP, costruireste un array delle parole chiave, e per ogni elemento richiamereste strpos() per verificare che siano tutte contenute nel testo.

In MySQL la funzione INSTR() è l’equivalente di strpos() in PHP, ma non potete salvare degli array in un campo (intendo array veri e propri, non serializzati), e d’altra parte salvare tante righe quante sono le parole chiave scelte da ogni utente è sconveniente, siccome la normalizzazione non è necessaria: un “insieme di parole chiave” è quasi sempre unico per ogni utente che si iscrive ad una ricerca, per cui ha senso salvarlo in un campo testuale nella forma di “parola1,parola2,parola3,…“; anche qui, in PHP useremmo explode(“,”,$parole) per ottenere un array, ma in MySQL non esiste nessuna funzione simile, per cui è necessario crearne una.

Idealmente, avreste bisogno di una funzione a cui passare il testo/documento in vostro possesso (la somma di titolo e corpo dell’offerta di lavoro, in questo caso), la stringa nella forma “parola1,…,parolaN“, e un parametro per indicare che il delimitatore (“colla” nel caso di implode/explode) è una virgola, quindi:

funzione(document, keywords, delimiter)

Questa funzione dovrebbe restituire un valore intero positivo se tutte le parole chiave sono presenti nel testo, oppure 0 in caso contrario.

La funzione che ho messo assieme incollando informazioni prese un po’ dovunque è:

DELIMITER ;;

DROP FUNCTION IF EXISTS `matchkwdarray`;;
CREATE FUNCTION `matchkwdarray`(`str` text, `arr` text, `delimit` tinytext) RETURNS char(1) CHARSET utf8
 DETERMINISTIC
BEGIN
 DECLARE i INT DEFAULT 1;
 DECLARE matches INT DEFAULT 1;
 DECLARE token TINYTEXT;
 label:WHILE(matches>0) DO
 SET token=replace(substring(substring_index(arr, delimit, i), length(substring_index(arr, delimit, i - 1)) + 1), delimit, '');
 IF token='' THEN LEAVE label; END IF;

 SET matches=INSTR(str, token);
 SET i=i+1;
 END WHILE;
 RETURN matches;
END;;

DELIMITER ;

Per aggiungere questa funzione al vostro database MySQL, potete collegarvi sia tramite CLI, sia usando una interfaccia web al database, come dovranno fare tutti gli utenti su un hosting condiviso, non avendo accesso alla linea di comando; phpMyAdmin, rigonfio com’è, non supporta comunque routine e funzioni, per cui avete bisogno di un altro DB manager, ed io ho scelto Adminer che svolge il suo lavoro egregiamente, più rapido di phpMyAdmin, e tutto in un piccolissimo singolo file PHP di circa 150kb.

Un esempio d’uso della funzione:

SELECT matchkwdarray('questo è solo un piccolo test molto semplice', 'solo,test', ',')
Restituisce: 2

SELECT matchkwdarray('questo è solo un piccolo test molto semplice', 'casa,albero', ',')
Restituisce: 0

SELECT matchkwdarray('questo è solo un piccolo test molto semplice', 'solo,test,semplice,albero', ',')
Restituisce: 0

Questa funzione è efficiente: appena verifica che una parola chiave non è contenuta nel testo interrompe la procedura e restituisce subito 0; ovviamente, se non cercate una precisione del 100% ma vi accontentate di una corrispondenza inferiore, potete modificarla per verificare comunque tutte le parole chiave, e restituire una percentuale di corrispondenza; potete anche rimuovere l’ultimo carattere dalle singole parole in modo tale che siano ammesse più varianti delle stesse.

Una query MySQL SELECT con numerose condizioni WHERE è più veloce

Per un certo motivo volevo aggiungere più condizioni WHERE ridondanti all’interno di una query MySQL SELECT, ma temevo di rallentare l’esecuzione della stessa.

In breve, sto lavorando a questo sito di annunci, dove per ogni oggetto c’è una tabella contenente tra le altre le righe comune_id, provincia_id e regione_id. Conoscendo il valore di comune_id, è possibile usare la query:

SELECT * FROM oggetti WHERE comune_id='12'

invece di:

SELECT * FROM oggetti WHERE comune_id='12' AND provincia_id='34' AND regione_id='56'

siccome i risultati sono gli stessi… ma conviene?

Ho preparato un veloce test:

include "db.inc.php";
$creationstart=strtok(microtime()," ")+strtok(" ");
for($i=0;$i<=999;$i++)
 $test=doquery("SELECT * FROM oggetti WHERE comune_id='58003'");
$creationend=strtok(microtime()," ")+strtok(" ");
$creationtime=number_format($creationend-$creationstart,4);
echo "solo comune: $creationtime<br />";

$creationstart=strtok(microtime()," ")+strtok(" ");
for($i=0;$i<=999;$i++)
 $test=doquery("SELECT * FROM oggetti WHERE comune_id='58003' AND provincia_id='58' AND regione_id='12'");
$creationend=strtok(microtime()," ")+strtok(" ");
$creationtime=number_format($creationend-$creationstart,4);
echo "tutti i parametri: $creationtime<br />";

A sorpresa, ci è voluto un tempo variabile dai 2.4s ai 4.5s per eseguire le 1000 iterazioni con “tutti i parametri”, mentre la versione “solo comune” richiedeva circa 0.4s in più. All’inizio ho pensato che si trattasse della cache MySQL in azione, ma invertendo la posizione delle due routine all’interno del codice i risultati sono rimasti gli stessi.

Quindi, anche se vi sembra ridondante, aggiungere più clausole WHERE ... AND ... nelle vostre query accelera l’esecuzione della ricerca.

This article has been Digiproved

Mamme tempestose

Giorno in ufficio fuori programma, faccio “presenza” per supplire alle ferie di una collega il cui ruolo non sono in grado di ricoprire; ma tanto vale esserci per avvisare di persona chi dovesse presentarsi.

Cominciano ad affacciarsi all’ingresso i clienti che si aspettavano di trovare qualcun altro, spiego brevemente la situazione, alcuni li conosco anch’io, quasi tutti rispondono con un “ah, va bene, grazie lo stesso…”, seguito da un sorriso di cortesia, e se ne vanno salutando cordialmente.

Ma c’è una categoria in particolare che proprio non ci sta: le signore ultraquarantenni, diciamo tra i 40 ed i 50; ho avuto le prime avvisaglie con una di loro che ha storto il naso e se n’è andata visibilmente contrariata pronunciando solo un “vabbè”, ma il culmine è stato una decina di minuti fa: forse 45 anni, “in tiro” come si suol dire, giubbino sbarazzino sopra la vita, pantaloni attillati e stivaletti in velluto nero col tacco  da 10cm, capelli pel di carota artificiale e labbra rossissime, tanta volontà di apparire più giovane di una trentina d’anni (ormai sono le quindicenni che girano vestite in quel modo), tanto restaurata quanto acida, con alla mano una bambinetta in uniforme scolastica e zainetto alle spalle. Mi affaccio perché sento un vociare movimentato nell’ingresso, era lei che incitava alla ribellione le altre persone entrate poco prima. Non le sta proprio bene che la collega che stava cercando se ne fosse andata in ferie, quando lei ha bisogno di qualcosa evidentemente è abituata a trovare tutti incatenati al loro posto; non bastava neppure il cartello affisso alla porta ormai da tempo, che avvisava del prossimo periodo di ferie, “eh, ma da quanto c’è quel cartello?!? non è che l’ha messo stamattina?!?”… “e se uno ha una urgenza come fa?? lei oggi ci doveva essere!”

A nulla è valso ripetergli due o tre volte che la collega ha preso accordi con una sostituta che, a parte oggi, segue i suoi stessi orari per la settimana in corso. Naturalmente se ne va senza neppure salutare, poco manca che mi mandi a quel paese. Ed anzi una volta rientrato sento sbattere la porta esterna come per ripicca. Qualche secondo dopo la porta viene riaperta e subito sbattura ancora una volta, conto che almeno si sia sfogata per oggi, altrimenti povero marito! Se ce l’ha ancora, un marito…

  This article has been Digiproved

Attivare il force feedback del Logitech Driving Force Wheel in windows

Qualche tempo fa ho ottenuto in regalo da Freecycle il Logitech Driving Force (ancora grazie Claudia), un volante per la Playstation 2 che avevo letto essere compatibile anche col PC, infatti usa una normale porta USB; appena collegato è stato riconosciuto da Windows 7 che lo ha configurato come un normale controller per giochi, anche se non ne supportava tutte le funzioni; in Need For Speed: Hot Pursuit la mancanza del force feedback, e la presenza della zona morta al centro rendevano quasi noioso il gioco; finalmente mi è venuta l’idea, dopo averne letto su un altro sito web, di scaricare il “Logitech Profiler”, una utility di configurazione per i controller ludici logitech; purtroppo sul sito ufficiale la pagina del Driving Force non è presente, ce ne sono solo per le versioni aggiornate (Driving Force qualchecosa), ma ho comunque prelevato la versione per Windows 7 64bit (ci sono versioni anche per Windows XP e Vista) dalla pagina di un altro volante, il G27, trattandosi da quanto ho capito sempre dello stesso file per tutti i controller. Ebbene, quando dopo l’installazione ho lanciato il programma, si è finalmente acceso il led del force feedback sul volante dopo che sono stati installati dei driver aggiornati, ed ho potuto usare il Driving Force a pieno, e hot pursuit si è trasformato in un gioco divertentissimo!

Rumori e vibrazioni di airbag passeggero e cruscotto Rover 75

I rumori di vibrazioni nel cruscotto mentre guido mi fanno impazzire, né più né meno.

Ho iniziato a guidare la mia Rover 75 da meno di un anno, e per i primi tempi la soddisfazione di avere un’auto classica ed elegante mi ha aiutato a soprassedere sui numerosi rumoretti che si sentivano dovunque durante la guida (soprattutto nella zona dell’airbag del passeggero), ad ogni modo sono arrivato ad un punto in cui mi saltavano tanto i nervi che ogni tanto davo forti schiaffi dovunque sul cruscotto tentando disperatamente di far cessare le vibrazioni, ma anche, lo ammetto, per sfogare la rabbia che mi provocava la cosa.

Devo ringraziare MikeM dei forum MG-Rover per le istruzioni scritte che mi hanno aiutato nella procedura di risoluzione del problema, e ispirato a creare questa guida anti-vibrazioni per immagini.

rover 75 glovebox removal screws
Questo portaoggetti è stato già smontato, comunque facciamo finta che non lo sia: bisogna rimuovere le sette viti di tipo torx evidenziate in rosso, le tre inferiori si trovano sotto il tappetino sintetico che deve essere scollato a forza dal fondo. Per rendere più comodo l'accesso alle viti vanno rilasciati i braccetti di plastica evidenziati in verde, in modo da poter aprire completamente lo sportello.
rover 75 glovebox arm hinge
Vista ravvicinata dei "dentini" che vanno spinti da entrambi i lati per far aprire completamente lo sportello.
rover 75 glovebox socket
Questo è il buco vuoto dopo aver rimosso il vano portaoggetti; evidenziato in verde è visibile lo spinotto di alimentazione della luce che va staccato prima di tirare completamente fuori il cassetto; la parte che vi interessa si trova dietro la parete superiore del buco, bisogna accedervi da sotto nella direzione della freccia rossa.
rover 75 bcu near glovebox
Questo è il guastafeste: la BCU (body control unit, anche se sulla scatola è scritto "Control Unit Body"); in verde ho evidenziato il bullone che fissa la scatola al pannello metallico visibile subito sotto; in pratica, la punta del bullone, a circa 2000 giri per minuto del motore vibra sbattendo contro la struttura metallica tubolare nella zona indicata dalla freccia rossa.
packaging plastic sheet
Serve qualcosa da interporre tra le due estremità metalliche, dovrebbe andar bene qualunque cosa, ma io ho usato questo foglio di plastica da imballaggi, che saggiamente avevo tenuto da parte per eventuali usi futuri.
rover 75 bcu rattle isolation
Ho preso circa 10cm di striscia di plastica, l'ho piegata in due, ho tirato verso il basso il pannello metallico liberando un certo spazio tra bullone e tubo metallico, ed ho fatto scorrere tra le due parti il materiale isolante; una volta rilasciata la scatola si è poggiata sullo strato interposto; da quel momento non ho sentito più alcuna vibrazione da sotto l'airbag passeggero.
rover 75 dash under panel
Giacché c'ero, ho deciso di risolvere le vibrazioni anche sotto il cruscotto nella zona del tachimetro; in rosso sono evidenziate le due viti da rimuovere, in verde indico le zone da cui sembravano originare i rumori.
rover 75 isolated under dash panel
Ho usato buona parte del materiale da imballaggio rimanente per formare una specie di cuscino attorno ai tre gancetti di ritenzione indicati dalle frecce verdi; alle due estremità ho fermato il tutto con un po' di nastro isolante; basta rimettere tutto in posizione per non sentire più nulla neppure in quella zona.

  This article has been Digiproved

Estrarre una stringa tra due chiavi in un testo con uno script shell bash

L’altro giorno, da totale incompetente, stavo scrivendo uno script in bash per processare una pagina HTML, cercare un URL al suo interno, e scaricare il contenuto di quell’URL, in maniera ricorsiva per una serie di pagine; l’avevo già compilato in linguaggio AutoHotKey, tuttavia il mio PC con Windows non è sempre acceso, mentre il mio server domestico linux sì, quindi ho deciso che sarebbe stato opportuno imparare un po’ di linguaggio bash per rendere la procedura più efficiente.

In questo script devo estrarre un segmento di stringa contenuto tra due parole chiavi note, o “token” in inglese, per ottenere l’URL di cui ho bisogno; in AutoHotKey salvavo la posizione di entrambe le parole chiavi, quindi operavo una istruzione di substring tra questi due offset, e stavo cercando di far lo stesso in bash, siccome stavo pedissequamente traducendo lo script, piuttosto semplice, da un linguaggio all’altro.

Con mia sorpresa, questa non è una cosa che si può fare in bash, siccome l’unica operazione di ricerca di una stringa all’interno di un’altra stringa in realtà cerca il primo carattere della parola chiave; quindi, per esempio, se si cerca “mio” all’interno di “La melliflua pelliccia del mio gatto è marrone”, si ottiene 3, e non 27 come ci si aspetterebbe, perché come dicevo expr index "$string" $substring restituisce solo la posizione del primo carattere di substring, quindi la prima posizione di “m” nella stringa.

In realtà, a me non serviva conoscere la posizione delle parole chiavi, purché riuscissi ad estrarre la stringa tra loro due, quindi ogni operazione che servisse a questo scopo andava bene; purtroppo me ne sono reso conto solo dopo aver buttato un’ora di tempo a cercare la soluzione, quindi pubblico i miei risultati per far risparmiare tempo a chi dovesse finire su questa pagina.

Fondamentalmente consiste nel tagliare dalla stringa tutto quello che precede la prima parola chiave (inclusa la prima chiave), e quindi tagliare dalla stringa così ottenuta tutto quello che segue la seconda patola chiave (seconda chiave inclusa):

#dichiarazione delle variabili
testo="lungotestodacontrollare"
primachiave="qualcosa"
secondachiave="qualcosaltro"

#elaborazione vera e propria
stringacentrale=${testo#*$primachiave}
stringacentrale=${stringacentrale%%$secondachiave*}

Questo restituisce $stringacentrale come la stringa contenuta tra la prima occorrenza di $primachiave (simbolo # singolo), e la prima occorrenza di $secondachiave (doppio simbolo %, che indica l’occorrenza più distante dalla fine della stringa).

  This article has been Digiproved

Questa benedetta crisi c’è o non c’è? O gioca a nascondino?

Me lo son chiesto oggi a pranzo, in un ristorante non proprio dai prezzi popolari, e che di domenica credo facesse tutt’altro che calmierare il listino; ma si sa, uscendo con amici è necessario venire a compromessi con le proprie abitudini… fast forward per un attimo al conto: dividendo la somma finale per 5 persone (il metodo della romana approssimativo, come lo chiamo io, in quanto pagare alla romana significa dividere esattamente in base ai reali “consumi” di ognuno) ed avendo io ordinato una bistecca ed un piatto di cicoria all’agro, oltre all’equivalente di meno di metà di antipasto misto (a tavola c’era solo mezzo litro di anonimo vino rosso, per i -soliti- beoni della combriccola), ho pagato 23 euro; c’è da dire che oltre ai due “antipasti ricchi” da dividere tra tutti, gli altri hanno ordinato solo un primo, ed alcuni hanno preso un dolce, a conti fatti ho anche diluito la mia parte con gli altri. Altrove puoi mangiare primo, secondo e contorno pagando 10 euro, e qualcuno ti offre pure il caffè.

Insomma, cos’è che mi chiedevo oggi a pranzo? Proprio quello che si legge nel titolo.

Appena entrato nella sala del ristorante non ho potuto non sorprendermi di come quasi tutti i tavoli fossero pieni; dapprima questo è stato un ingannevole indizio della politicità dei prezzi (“se c’è così tanta gente, significa che si paga relativamente poco nonostante il posto”), ma sono stato stordito smentito una volta aperto il menu.

Come se non bastasse, piatti di pesce fioccavano dovunque (la carne è improvvisamente diventata “out”? contiene pure più proteine del pesce!), e bambini piccoli lasciavano quasi per intero le loro portate che inesorabilmente tornavano indietro pressoché illese; per intenderci, una scena generalizzata di pingue e pantagruelica abbuffata di pietanze relativamente costose.

Allora mi chiedo, ma ‘sta crisi dove sta? Esiste una folta e imprevedibile classe di benestanti nascosti nel sottobosco della società, che durante il finesettimana si riversa nei locali “in”, oppure (con la dovuta esclusione di chi davvero non ha i mezzi per far durare 30 giorni lo stipendo) c’è solo una massa di persone che spende e spande in ristoranti, sigarette, discoteche, macchine nuove fiammanti, vacanze invernali ai tropici, e sceglie di non potersi invece finanziare servizi di base indiscutibilmente più utili? (ogni riferimento a fatti o persone riguardanti il sottoscritto è puramente intenzionale)

Come direbbe Dervis Fontecedro, disgustorama!

This article has been Digiproved

reCAPTCHA manca lo scopo, che sia un bypass o un crack lo spam passa

Mi piace(va) l’idea dietro reCAPTCHA, bloccare lo spam mentre si aiuta la digitalizzazione dei libri, e diciamocelo, le immagini di reCAPTCHA sono più leggibili all’occhio umano rispetto ai codici alfanumerici deformati prodotti dai normali codici antispam.

Tuttavia, anche se ho il plugin Akismet attivo, siccome i commenti sono dietro captcha immaginavo che non avrei ricevuto alcuno spam, di certo non da bot, ed invece ne è sempre arrivato, soprattutto nell’ultimo periodo in grande quantità e per messaggi tutti uguali tra loro; stava succedendo anche sul forum punbb del mio sito professionale, dove era in azione un plugin recaptcha, e capite come trovarsi a sorpresa un post pieno di link a siti a luci rosse, con tanto di immaginette oscene, sia controproducente per la mia immagine.

Come mai succede tutto questo? Forse un inquinamento del database di reCAPTCHA con tecniche particolari di spamming per cui alcune parole chiave vengono sempre riconosciute come corrette, oppure tecniche di OCR avanzate, o infine il disoccupato della porta accanto pagato qualche millicent per ogni captcha risolto. Non me ne importa poi tanto, quello che conta è che lo spam continua a passare.

Indiragionpercui ho deciso di abbandonare del tutto reCAPTCHA e passare ai cari vecchi captcha generati tramite PHP, vedremo cosa succederà, su questo sito ora è in azione il plugin SI Captcha (immagino derivi da Secure Image, riconosco lo stile).

This article has been Digiproved