Windows 10, le novità. Beh, quasi.

Il 29 luglio Microsoft rilascerà la nuova versione di Windows. Su questo blog la cosa è probabile che interessi poco, ma ci tenevo ad elencare le novità giusto per non perdere d’occhio in che direzione sta andando il mondo desktop.

Commento le novità seguendole una per una alla pagina ufficiale MS.

  • Windows 10 avrà il menù start, del tutto simile a quello che c’era fino a Windows 7. Cioè, in pratica, lo hanno tolto da Windows 8 per poi poterlo presentare come novità di Windows 10.
  • Windows 10 manderà (finalmente) in pensione Internet Explorer e con lui i peggiori spettri del medioevo informatico come ActiveX e BHO. Internet Explorer sarà sostituito da Microsoft Edge, un browser nuovo di zecca basato sugli standards (speriamo). Per i nostalgici comunque Internet Explorer 11 potrà ancora funzionare su Windows 10 (o forse per tutti quelli a cui MS Edge non funzionerà…). Detta in breve, Windows 10 ti permetterà di navigare su internet (forse).
  • Windows 10 permetterà di avere fino a QUATTRO finestre aperte contemporaneamente. Se non ricordo male su Windows 8 erano solo due. E, sempre se non ricordo male, fino a Windows 7 erano illimitate quindi la cosa non veniva neppure pubblicizzata… non è importante cosa vendi, l’importante è saperlo vendere.
  • Windows 10 ha uno store fornitissimo di app, musica, giochi e quant’altro. C’era già su Windows 8. E, a dirla tutta, non è che se ne sentisse la necessità.
  • Windows 10 include Cortana, ovvero un desktop semantico che si fa gli affari tuoi convinto di sapere meglio di te cosa in effetti stai cercando. De gustibus. Gli altri sistemi operativi ce l’hanno da circa una decade e da circa nove anni e 364 giorni gli utenti hanno imparato a disabilitarlo.
  • Windows 10 ha il supporto per periferiche di input diverse dal mouse, come schermi touch con dito o penna apposita. Wow.
  • Windows 10 funziona con schermi di varie dimensioni e risoluzioni, ovvero non ti obbliga ad avere un monitor che supporti la risoluzione 800×600 come Windows 3.1, ricordate?
  • XBox sta per arrivare su Windows. Beh questa onestamente non la capisco… non era Windows che era arrivato su XBox, fin dal giorno in cui hanno inventato la Xbox?

Comunque, anche se non capisco l’ultima, mi sembra che l’elenco di novità sia già talmente lungo ed interessante da voler assolutamente aggiornare alla nuova versione di Windows appena possibile… ma non prima che qualcuno mi dica che fine ha fatto Windows 9.

Considerazioni da chi la pensa diversamente

Faccio alcune noiose, ma necessarie, premesse.

Una volta, da giovane, sentii dire da un prete che il cristiano non si ferma, ma è in continua ricerca della verità, in continua ricerca di Dio. Da allora mi sono sempre sentito legittimato a mettere in dubbio le mie convinzioni (e di conseguenza quelle degli altri) per il piacere di sapere, di scoprire e di fare un passo in più in questa ricerca della verità e di Dio: non so se il prete intendesse proprio questo, ma questa interpretazione a me calzava a pennello.

Come sapete mi piace fare l’avvocato del diavolo, ma lo faccio sempre e solo per scoprire il perché delle cose, per darmi una spiegazione a ciò che non so spiegare, non per il gusto di infastidire gli altri. Spero con questo di non infastidire nessuno, sappiate che non ho cattive intenzioni, cerco solo di capire da che parte sta la verità.

Una cosa che mi mette sempre in discussione è il fatto che, allo stesso modo in cui io cerco di capire, senza avere cattive intenzioni, anche tutto il resto del mondo cerca di capire. Lo fanno in buona fede i cattolici (di cui faccio orgogliosamente parte) e lo fanno in buona fede i protestanti. A loro modo forse un po’ invadente, ma lo fanno in buona fede anche i testimoni di Geova e tutti gli appartenenti ad altre religioni, financo gli atei e gli agnostici. Lo fanno in buona fede anche i cattolici che la pensano al 100% da cattolici. Allo stesso modo in cui io credo nelle mie convinzioni, allo stesso modo in cui io penso di aver raggiunto conclusioni sensate ed allo stesso modo in cui io penso di essere nel giusto, così anche i protestanti, i testimoni di Geova, gli atei pensano di essere nel giusto. Gli stessi cattolici più aderenti alla dottrina romana pensano sinceramente di essere nel giusto. Peccato che molti punti dei rispettivi pensieri siano diametralmente opposti fra loro ed inconciliabili, per cui qualcuno di noi sbaglia per forza. Chi lo dice che a sbagliare non potrei essere io? In fondo tutti gli altri pensano in buona fede di essere nel giusto esattamente come me, quindi non c’è nulla che conferisca alle mie convinzioni maggiori probabilità di corrispondere alla realtà.

Fatte queste premesse, incollo qui sotto il contenuto di una pagina trovata in giro per internet, scritta da un gruppo di credenti di varie provenienze, ma non cattolici. Stranamente, io sono cattolico, ma mi trovo d’accordo con quanto scritto da questi protestanti. Ancor più stranamente, partecipo periodicamente agli incontri locali dell’ADMA, e mi piace parteciparvi. Non sento mia il tipo di preghiera che si fa in quegli incontri, ma sento molto mia la comunità cristiana che mi accoglie e mi permette di partecipare a quegli incontri. È soprattutto per loro che ho scritto questo post, perché sono cose su cui ho tentato di chiedere lumi a loro, sono punti di vista che sento miei, ma non ho le basi teologiche per poterli esprimere, per sostenere la dialettica. Alla prima risposta che mi danno mi rendo conto di non avere nulla da ribattere, ma, cionondimeno, la risposta che mi danno non risponde ai miei perché.

Questa pagina esprime bene il mio punto di vista, perché non parla di teologia e filosofia, ma di pratica, anche se forse tende ad essere un po’ troppo critica nei confronti dei cattolici, da una parte perché fa di tutte l’erbe un fascio, dall’altra perché alla fine anche noi siamo persone con i nostri dubbi e le nostre debolezze, non siamo così arroccati e scontrosi come sembra descriverci l’autore o, almeno, io non lo sono e conosco altri cattolici che non lo sono. Il punto comunque non è chi ha ragione e chi no, ma è trovare assieme la verità o, quantomeno, cercare di avvicinarcisi il più possibile.

Cari amici dell’ADMA, io sono qui a chiedervi di spiegarmi il vostro punto di vista, che, a dire il vero, dovrebbe essere anche il mio, ma come sapete, per ora non è. Vi chiederei però, nel leggere le righe qui sotto, di non dare per scontato di essere per forza voi dalla parte del giusto, ma di mettervi in discussione, così come sto facendo io, che sono arrivato a pormi queste domande, proprio perché negli anni mi sono messo in discussione. Se, nonostante la buona volontà di confronto e di mettersi in discussione, sentite di avere le risposte giuste da darmi, vi prego di darmele, sarò ben felice di cercare di capirle per poterle fare mie in futuro.

Domanda: “L’adorazione dei santi o di Maria è biblica?”

Risposta: La Bibbia è assolutamente chiara sul fatto che dobbiamo adorare soltanto Dio. Nella Bibbia, gli unici esempi di qualcun altro che non sia Dio a ricevere adorazione sono i falsi dèi, che sono Satana e i suoi demòni. Tutti i seguaci del Signore Iddio rifiutano l’adorazione. Pietro e gli apostoli rifiutarono di essere adorati (Atti 10:25-26; 14:13-14). Gli angeli santi rifiutano di essere adorati (Apocalisse 19:10; 22:9). La risposta è sempre la stessa: “Adora Dio!”.

I cattolici romani tentano di “aggirare” questi chiari princìpi scritturali affermando che essi non “adorano” Maria o i santi, ma piuttosto che li “venerano” soltanto. Utilizzare una parola diversa non cambia l’essenza di ciò che si fa. Una definizione di “venerare” è “guardare con rispetto o riverenza”. Mai nella Bibbia ci viene detto di riverire qualcun altro che non sia soltanto Dio. Non c’è nulla di sbagliato nel rispettare quei cristiani fedeli che ci hanno preceduti (cfr. Ebrei 11). Non c’è niente di sbagliato nell’onorare Maria come madre terrena di Gesù. La Bibbia descrive Maria come “grandemente favorita” da Dio (Luca 1:28, ND). Allo stesso tempo, non c’è alcun insegnamento nella Bibbia di riverire quanti sono andati in cielo. Dobbiamo certamente seguirne l’esempio, ma non adorarli, riverirli o venerarli!

Quando sono costretti ad ammettere che essi, in realtà, adorano Maria, i cattolici affermano che essi adorano Dio attraverso di lei, lodando la creatura meravigliosa che Egli ha fatta. Maria, secondo loro, è la creatura più bella e meravigliosa di Dio e, lodandola, essi ne stanno lodando il Creatore. Per i cattolici, questo è analogo al rivolgere lodi a un artista lodandone la scultura o il dipinto. Il problema di questo è che Dio comanda esplicitamente di non adorarLo attraverso cose create. Noi non dobbiamo prostrarci e adorare alcuna delle cose che sono lassù nel cielo o quaggiù sulla terra (Esodo 20:4-5). Romani 1:25 non potrebbe essere più chiaro: “Essi, che hanno mutato la verità di Dio in menzogna e hanno adorato e servito la creatura invece del Creatore, che è benedetto in eterno. Amen”. Certo, Dio ha creato cose meravigliose e sorprendenti. Certo, Maria fu una donna santa che merita il nostro rispetto. No, noi non dobbiamo assolutamente adorare Dio “indirettamente” lodando cose (o persone) che Egli ha create. Far questo è apertamente idolatrico.

Il modo principale in cui i cattolici “venerano” Maria e i santi è pregandoli. Come mostra l’articolo successivo, pregare chiunque altro che non sia soltanto Dio è antibiblico: pregare i santi e Maria. Sia che Maria e/o i santi siano pregati sia che se ne chiedano le preghiere, nessuna di queste due pratiche è biblica. Pregare è un atto di adorazione. Quando preghiamo Dio, stiamo ammettendo che abbiamo bisogno del Suo aiuto. Rivolgere le nostre preghiere a qualcun altro che non sia Dio significa derubarLo della gloria che spetta soltanto a Lui.

Un altro modo in cui i cattolici “venerano” Maria e i santi è facendone statue e immagini. Molti cattolici usano le immagini di Maria e/o dei santi come “portafortuna”. Qualunque lettura veloce della Bibbia rivelerà che questa pratica è apertamente idolatrica (Esodo 20:4-6; 1 Corinzi 12:12; 1 Giovanni 5:21). Sfregare i grani del rosario è idolatrico. Accendere candele davanti a una statua o a un ritratto di un santo è idolatrico. Sotterrare un’immagine di san Giuseppe nella speranza di vendere la casa (e innumerevoli altre pratiche cattoliche) è idolatrico.

Il problema non sta nella terminologia. Che la pratica sia descritta come “adorazione” o “venerazione” o con qualunque altro termine, il problema non cambia. Ogniqualvolta attribuiamo qualcosa che appartiene a Dio a qualcun altro, questa è idolatria. La Bibbia non c’insegna mai a riverire, pregare, affidarci o “idoleggiare” nessun altro che Dio. Dobbiamo adorare soltanto Dio. La gloria, la lode e l’onore appartengono soltanto a Dio. Solo Dio è degno “…di ricevere la gloria, l’onore e la potenza…” (Apocalisse 4:11). Soltanto Dio è degno di ricevere il nostro culto, la nostra adorazione e la nostra lode (Neemia 9:6; Apocalisse 15:4).

Omeopatia ed ignoranza

Il titolo dice già tutto, ma non basta a spiegare il mio punto di vista, che, a dispetto del titolo, credo non sia condiviso da molti, nè fra quelli che ritengono che l’omeopatia sia solo un buon affare, nè fra quelli che pensano invece che sia la medicina del futuro.
Partiamo dal dato inattaccabile che i cosiddetti rimedi omeopatici non contengono assolutamente nulla, per quel che ne sappiamo. Quando dico nulla, intendo nulla di curativo. Se ingerite dei globuli di qualsivoglia rimedio omeopatico, sate mangiando pastigliette di puro e semplice zucchero.
Chi difende l’omeopatia vi dirà che quei globuli non contengono nulla di osservabile con gli strumenti che oggi abbiamo, ma che in realtà quello zucchero, grazie al modo in cui viene preparato, ha delle proprietà curative potentissime che, se vogliamo parlare di scienza, agiscono a livello subatomico, quindi non sono osservabili sistematicamente. È inutile che prepariate un vetrino con i globuli di un rimedio omeopatico e lo passiate al microscopio elettronico (lo so, non serve un classico vetrino per quel microscopio): non ci troverete null’altro che zucchero, questo ve lo dice anche chi difende l’omeopatia. È pure inutile mettere una pastiglietta dentro l’acceleratore del CERN, perché qualsiasi cosa osserveremo, sarà il risultato di una perturbazione tale del sistema che non corrisponderà minimamente alla pastiglietta, prima che fosse messa nell’acceleratore (lo so, non ci si mette una pastiglietta a centrifugare nell’acceleratore, per fortuna non mi chiamo Mariastella…).
I detrattori dell’omeopatia e difensori dei metodi della medicina ufficiale vi diranno invece che qualsiasi cosa contengano i rimedi omeopatici, pur assumendo che contengano qualcosa di non osservabile in quanto subatomico, nella pratica non funziona, perché al test doppio cieco i rimedi omeopatici totalizzano lo stesso punteggio del placebo (cioè le pastigliette di zucchero vere e proprie, non quelle omeopatiche, ma quelle preparate senza alcun procedimento particolare). In altre parole, la loro tesi è che se guarisci con l’omeopatia, saresti guarito comunque non prendendo nulla.
Infine ci sono io e quelli come me che l’omeopatia l’hanno provata, su sé stessi e sui propri figli ed hanno provato anche la medicina ufficiale, sempre su sé stessi e sui propri figli. Io costituisco un campione assolutamente parziale, troppo piccolo e troppo coinvolto nell’esperimento per poter essere considerato affidabile, quindi qualsiasi cosa io dica, dal punto di vista scientifico, e soprattutto medico, non ha alcun valore: chi legge lo tenga presente. Ha però un valore dal punto di vista culturale, dell’esperienza fatta e comunicata. Fin che si può comunicare, approfittiamone.
Mia figlia, a 3 anni, ha avuto sei tonsilliti nell’arco di un anno. Significa che ha subìto cinque cicli di antibiotici nell’arco di un anno. La pediatra, all’ultimo ciclo prescritto, che avrebbe dovuto essere il sesto, ci ha detto che quello sarebbe stato l’ultimo e che se si fosse ripresentata la tonsillite, l’unica soluzione sarebbe stata la tonsillectomia, cioè l’asportazione chirurgica delle tonsille.
Su consiglio di un amico, abbiamo provato, sotto la nostra responsabilità, a non darle l’ultimo ciclo di antibiotici prescritto ed a darle invece una fiala di Echinacea Compositum ed una di Limphomyosot al giorno, non diluite, a stomaco vuoto. La tonsillite è passata e non si è più ripresentata per un anno e mezzo. Dopo un anno e mezzo abbiamo ripetuto la cura omeopatica e la tonsillite è di nuovo passata, questa volta per sempre. Ora mia figlia ha dodici anni ed entrambe le tonsille al loro posto.
Cosa ha fatto guarire mia figlia? Non lo so, ma mi sono fatto una mia idea.
L’idea è che l’omeopatia serva, ma non dal punto di vista chimico o subatomico. Mi spiego. Gli antibiotici sono utili nel breve termine, ma inutili nel medio termine e dannosi nel lungo, ragion per cui se si lascia che il sistema immunitario lavori per conto proprio si ottengono risultati più lenti (il mal di gola passa in quattro giorni invece che due), ma più stabili (il mal di gola non torna il mese successivo). Naturalmente se si lascia che sia il sistema immunitario a lavorare da solo, si hanno meno garanzie che la malattia si risolva: potrebbe invece aggravarsi. Veramente lo stesso potrebbe accadere anche dando l’antibiotico, ma il rapporto rischio beneficio sembra essere a favore del farmaco, e sicuramente lo è nel breve termine (pochi giorni).
Il problema è che se si ha un figlio con il mal di gola ed il mondo scientifico ti dice che per curarlo devi dargli un antibiotico, se tu non gli dai l’antibiotico vieni visto come uno che non si occupa della salute dei propri figli, con possibili conseguenze anche penali. D’altra parte anche tu come genitore sei tranquillo se sai di aver fatto il possibile ed anche qualcosa in più per curare i tuoi figli: non è pensabile vedere un figlio che soffre e non fare nulla, sarebbe innaturale, nessun genitore sano di mente si sentirebbe a posto ignorando la sofferenza dei propri figli. Qualcosa devi fare per vivere serenamente, per non portare il peso della responsabilità di un eventuale peggioramento della salute. Ecco dove l’omeopatia entra in gioco. In realtà con i rimedi omeopatici non facciamo assolutamente nulla (per quel che ne sappiamo dal punto di vista scientifico), ma c’è la possibilità teorica che effettivamente i rimedi omeopatici abbiano un efficacia oggi non dimostrabile con il metodo scientifico, in quanto il test del doppio cieco, se l’omeopatia funziona veramente così come io ipotizzo, inquinerebbe esso stesso il procedimento e sarebbe esso stesso un test non adatto a verificare l’efficacia dei rimedi omeopatici.
La mia ipotesi quindi è che l’omeopatia agisca a livello psicofisico meglio del placebo quando usata all’interno di un gruppo di persone in relazione affettiva di qualche tipo. Il nostro sistema immunitario è suscettibile allo stress, questo credo che sia condiviso anche dal mondo della medicina ufficiale. Se io papà “curo” mia figlia, indipendentemente da cosa uso per curarla, ma so che sto facendo il meglio che posso fare per lei, creo attorno a lei, in famiglia, un ambiente tranquillo e sereno. Mia moglie, che magari nel frattempo non si è occupata molto di interazioni subatomiche, ma si è comunque preoccupata di trovare qualcosa che funzionasse meglio degli antibiotici e che non portasse al tavolo del chirurgo, allo stesso modo sa che sta facendo il possibile e qualcosa in più. Non siamo certi che la cura funzionerà, ma siamo certi che gli antibiotici, sul lungo termine, non hanno funzionato e sappiamo quindi che stiamo facendo del nostro meglio per trovare una soluzione più efficace. Mi rendo conto che il tutto può sembrare un colossale arrampicamento sui vetri, ma non è così: è solo la condivisione di un’esperienza, alla ricerca della verità. E spero che serva ad altri.

2014. Cento di questi anni.

Tempo di crisi, ditte che chiudono, progetti che si sbriciolano fra le dita prima ancora di nascere o, peggio, dopo averli maneggiati con cura e tenuti in caldo fra le mani per mesi. Eppure il 2014 per me è stato l’anno dei cambiamenti, delle novità e delle esperienze indimenticabili.
Il mio lavoro? Una tragedia in tre atti. Siamo alle porte del 2015 e le mie prospettive sono spaventose. Tuttavia se mi proponessero altri 100 di questi anni, tutti entusiasmanti come è stato per me questo 2014, metterei la firma subito.
La prima cosa che mi viene in mente pensando al 2014 è l’estate. Dal punto di vista meteorologico, è stata un’estate bruttina, molto piovosa, quasi assente. Per me è stata la migliore estate da non so più quando (anche perché non amo particolarmente il caldo, mentre al freddo mi ci trovo bene).
Il 4 luglio ho scelto di diventare vegetariano. Non l’ho fatto per ragioni etiche, ma per la salute. Il 18 luglio sono andato al concerto degli Oronero a Gravellona. Grazie mille a mio fratello e mia cognata per avermi portato con loro, il ricordo di quella serata resterà sempre dentro di me. È un peccato che non si possa far rivivere il passato, perché la realtà spesso non è all’altezza dei ricordi, ma se il genio della lampada mi concedesse i tre desideri, rivivere quelle emozioni sarebbe uno dei tre.
Sì gli animali uccisi mi fanno pena, ma non è una novità del 4 luglio, né la scelta di essere vegetariano potrebbe in alcun modo essere coerente con le ragioni etiche. Sono cambiate tante cose dentro di me fra il 20 giugno ed il 4 luglio. Queste cose mi hanno portato a rispettare me stesso, il mio corpo, più di quanto non stessi facendo prima. E dal 4 luglio al 4 ottobre ho perso 15 chili. Altri 3 li ho persi dal 4 ottobre al 10 dicembre (ieri nel momento in cui scrivo).
No, essere vegetariani di per sé non fa dimagrire. Imparare a rispettare il proprio corpo sì, se avete chili di troppo. E se imparate a rispettare il vostro corpo, probabilmente diventerete anche voi vegetariani, infatti anche per me il diventare vegetariano è stata una conseguenza dell’avere cura di me stesso.
Molte altre cose sono cambiate quest’anno. Sono troppe per scriverle su un blog. Sono troppo belle per raccontarvele, perché vedete, sono mie e ne sono geloso. Inoltre coinvolgono persone a me molto care, che so bene che non vorrebbero vedersi proiettate su un blog. Ho scritto queste perché volevo solo far sapere a tutti quelli che mi chiedono come ho fatto a dimagrire, che tutto parte dalla testa e dalle emozioni. Non esiste dieta che possa funzionare se non ci mettete il cuore e la testa. Molte diete potranno farvi perdere dei chili, ma finita la dieta, li riacquisterete tutti. Far dieta non deve essere una sofferenza, altrimenti non è sostenibile. Deve essere una soddisfazione, uno stile di vita, un modo di essere ed un innato amore per sé stessi.
Sappiate però che per me ha funzionato, perché quello che vi ho raccontato qui è solo una piccola parte delle emozioni che ho vissuto e che vivo tutt’ora.
E ringrazio tutte le persone a me care che tutti i giorni continuano a farmi vivere queste emozioni.

AutoCloseable EntityManager

Sembra che io non sia l’unico a chiederselo e sembra anche che le risposte date non siano necessariamente soddisfacenti. Non sarebbe bello poter usare il try-with-resources con gli EntityManager?
Pare che il motivo per cui EntityManager non implementa AutoCloseable sia che se lo facesse, potrebbe solo fare la close() di sè stesso, ma non la rollback() dell’eventuale transazione. Questo renderebbe l’intero sforzo inutile, dovendo comunque gestire la transazione attraverso la finally come al solito. Oppure illuderebbe l’utente che l’EntityManager, essendo AutoCloseable, faccia cose che in realtà non fa (la rollback() appunto). Onestamente mi sfugge il motivo per cui l’EntityManager non possa tenere traccia della EntityTransaction, così come fa il mio codice qui sotto, ma è probabile che sia un problema di specifiche e di ricerca della purezza a tutti costi, per venire incontro a qualche possibile implementazione di JPA proveniente da Marte o altri pianeti più lontani…

Ad ogni modo il mio codice funziona, o almeno funziona per me e per il mio stile di programmazione. Può darsi che in realtà non sia sufficientemente generico e che in altri casi non funzioni… se capita a voi fatemi sapere, grazie.

Notate che il fatto che io abbia aggiunto AutoCloseable è una conseguenza di un bug che avevo lasciato in un mio software per cui un EntityManager non veniva chiuso. Per scoprire quale fosse, ho dovuto aggiungere tutto il monitoraggio attraverso JConsole ed interfaccia MBean. Ora quindi avete una classe che vi permette di ottenere un EntityManager (in realtà lo dovete usare per quel che è, ovvero EMWrapper) che nel frattempo è anche monitorabile attraverso JConsole. A voi il codice.

/*
Copyright © 2014 Lucio Crusca <lucio@sulweb.org>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
*/

package com.virtual_bit.salix.web.persistence;

import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.metamodel.Metamodel;

public class PersistenceManager
{
  private static final PersistenceManager singleton = new PersistenceManager();

  private HashMap<String, EntityManagerFactory> emfs;
  
  private static final String mainUnitName = "my-unit";
  
  private static final String[] databases = {
    "some-unit",
    "other-unit"
  };
  
  public static interface EMapMBean extends Map<String, List<EMWrapper>>
  {
    
  }
  
  public static class EMap extends HashMap<String, List<EMWrapper>> implements EMapMBean
  {
    
  }
  
  public static interface EntityMapMXBean
  {
    EMap getMap();
    String[] getOverview();
    String[] getDetails();
  }

  private static EMap activeWrappers;
  
  public static class EntityMap implements EntityMapMXBean
  {
    @Override
    public EMap getMap()
    {
      return activeWrappers;
    }
    
    public String[] getOverview()
    {
      List<String> result = new ArrayList<>();
      synchronized(activeWrappers)
      {
        Set<String> keys = activeWrappers.keySet();
        for (String s: keys)
          result.add(s + " -> " + activeWrappers.get(s).size());
      }
      String[] ares = new String[result.size()];
      return result.toArray(ares);
    }

    @Override
    public String[] getDetails()
    {
      List<String> lresult = new LinkedList<>();
      synchronized(activeWrappers)
      {
        Set<String> keys = activeWrappers.keySet();
        int ki = 0;
        for (String s: keys)
        {
          List<EMWrapper> wrappers = activeWrappers.get(s);
          String[][] traces = new String[wrappers.size()][];
          int i = 0;
          for (EMWrapper emw: wrappers)
            traces[i++] = emw.getStackStrace();
          lresult.add(flatten(traces));
        }
      }
      String[] result = new String[lresult.size()];
      return lresult.toArray(result);
    }

    private String flatten(String[][] traces)
    {
      StringBuilder sb = new StringBuilder();
      for (String[] key: traces)
        for (String values: key)
          sb.append(values).append("\n");
      return sb.toString();
    }

  }

  private PersistenceManager()
  {
  }
  
  private static void initMBean()
  {
    synchronized(PersistenceManager.class)
    {
      if (activeWrappers != null)
        return;
      
      try
      {
        activeWrappers = new EMap();
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();  
        EntityMap map = new EntityMap();
        ObjectName name = new ObjectName(map.getClass().getPackage().getName() + ":type=" + map.getClass().getSimpleName());
        mbs.registerMBean(map, name);
      }
      catch (InstanceAlreadyExistsException | MBeanRegistrationException | MalformedObjectNameException | NotCompliantMBeanException ex)
      {
        Logger.getLogger(PersistenceManager.class.getName()).log(Level.SEVERE, null, ex);
      }    
    }
  }

  private static PersistenceManager getInstance()
  {
    return singleton;
  }

  private EMWrapper createEntityManager(String jndiName)
  {
    EntityManagerFactory emf = _getFactory(jndiName);
    EMWrapper result = new EMWrapper(emf.createEntityManager(), jndiName);
    return result;
  }
  
  private EntityManagerFactory _getFactory(String jndiName)
  {
    if (emfs == null)
      emfs = new HashMap<>();
    if (!emfs.containsKey(jndiName))
      emfs.put(jndiName, Persistence.createEntityManagerFactory(jndiName));
    return emfs.get(jndiName);
  }

  public void closeFactories()
  {
    if (emfs == null)
      return;
    for (EntityManagerFactory emf: emfs.values())
      emf.close();
    emfs.clear();
    emfs = null;
  }
  
  public static EMWrapper getEM()
  {
    return getInstance().createEntityManager(nameEM());
  }
  
  private static String suffix()
  {
    Thread current = Thread.currentThread();
    if (current.isDaemon())
      return "-bg";
    return "";
            
  }

  public static String nameEM()
  {
    return mainUnitName + suffix();
  }
  
  
  public static String nameSomeEM()
  {
    return databases[0] + suffix();
  }
  
  public static String nameOtherEM()
  {
    return databases[1] + suffix();
  }
  
  
  public static EMWrapper getSomeEM()
  {
    return getInstance().createEntityManager(nameSomeEM());
  }
  
  public static EMWrapper getOtherEM()
  {
    return getInstance().createEntityManager(nameOtherEM());
  }
  
  public static EMWrapper getEM(String unitname)
  {
    return getInstance().createEntityManager(unitname);
  }

  public static Iterable<String> nameDatabases()
  {
    ArrayList<String> dbs = new ArrayList<>();
    for (String d: databases)
      dbs.add(d + suffix());
    return dbs;
  }

  public static interface EMWrapperMBean extends EntityManager
  {
    
  };
  
  public static class EMWrapper implements EMWrapperMBean, AutoCloseable
  {
    private final EntityManager wrapped;
    private final String jndiName;
    private StackTraceElement[] ste;
    
    private EMWrapper(EntityManager wrapped, String jndiName)
    {
      this.wrapped = wrapped;
      this.jndiName = jndiName;
      this.ste = Thread.currentThread().getStackTrace();
      initMBean();
      synchronized(activeWrappers)
      {
        List<EMWrapper> active = activeWrappers.get(jndiName);
        if (active == null)
          active = new LinkedList<>();
        active.add(this);
        activeWrappers.put(jndiName, active);
      }
    }

    @Override
    public void persist(Object entity)
    {
      wrapped.persist(entity);
    }

    @Override
    public <T> T merge(T entity)
    {
      return wrapped.<T>merge(entity);
    }

    @Override
    public void remove(Object entity)
    {
      wrapped.remove(entity);
    }

    @Override
    public <T> T find(Class<T> entityClass, Object primaryKey)
    {
      return wrapped.<T>find(entityClass, primaryKey);
    }

    @Override
    public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties)
    {
      return wrapped.<T>find(entityClass, primaryKey, properties);
    }

    @Override
    public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode)
    {
      return wrapped.<T>find(entityClass, primaryKey, lockMode);
    }

    @Override
    public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties)
    {
      return wrapped.<T>find(entityClass, primaryKey, lockMode, properties);
    }

    @Override
    public <T> T getReference(Class<T> entityClass, Object primaryKey)
    {
      return wrapped.<T>getReference(entityClass, primaryKey);
    }

    @Override
    public void flush()
    {
      wrapped.flush();
    }

    @Override
    public void setFlushMode(FlushModeType flushMode)
    {
      wrapped.setFlushMode(flushMode);
    }

    @Override
    public FlushModeType getFlushMode()
    {
      return wrapped.getFlushMode();
    }

    @Override
    public void lock(Object entity, LockModeType lockMode)
    {
      wrapped.lock(entity, lockMode);
    }

    @Override
    public void lock(Object entity, LockModeType lockMode, Map<String, Object> properties)
    {
      wrapped.lock(entity, lockMode, properties);
    }

    @Override
    public void refresh(Object entity)
    {
      wrapped.refresh(entity);
    }

    @Override
    public void refresh(Object entity, Map<String, Object> properties)
    {
      wrapped.refresh(entity, properties);
    }

    @Override
    public void refresh(Object entity, LockModeType lockMode)
    {
      wrapped.refresh(entity, lockMode);
    }

    @Override
    public void refresh(Object entity, LockModeType lockMode, Map<String, Object> properties)
    {
      wrapped.refresh(entity, lockMode, properties);
    }

    @Override
    public void clear()
    {
      wrapped.clear();
    }

    @Override
    public void detach(Object entity)
    {
      wrapped.detach(entity);
    }

    @Override
    public boolean contains(Object entity)
    {
      return wrapped.contains(entity);
    }

    @Override
    public LockModeType getLockMode(Object entity)
    {
      return wrapped.getLockMode(entity);
    }

    @Override
    public void setProperty(String propertyName, Object value)
    {
      wrapped.setProperty(propertyName, value);
    }

    @Override
    public Map<String, Object> getProperties()
    {
      return wrapped.getProperties();
    }

    @Override
    public Query createQuery(String qlString)
    {
      return wrapped.createQuery(qlString);
    }

    @Override
    public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery)
    {
      return wrapped.<T>createQuery(criteriaQuery);
    }

    @Override
    public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass)
    {
      return wrapped.<T>createNamedQuery(qlString, resultClass);
    }

    @Override
    public Query createNamedQuery(String name)
    {
      return wrapped.createNamedQuery(name);
    }

    @Override
    public <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass)
    {
      return wrapped.<T>createNamedQuery(name, resultClass);
    }

    @Override
    public Query createNativeQuery(String sqlString)
    {
      return wrapped.createNativeQuery(sqlString);
    }

    @Override
    public Query createNativeQuery(String sqlString, Class resultClass)
    {
      return wrapped.createNativeQuery(sqlString, resultClass);
    }

    @Override
    public Query createNativeQuery(String sqlString, String resultSetMapping)
    {
      return wrapped.createNativeQuery(sqlString, resultSetMapping);
    }

    @Override
    public void joinTransaction()
    {
      wrapped.joinTransaction();         
    }

    @Override
    public <T> T unwrap(Class<T> cls)
    {
      return wrapped.<T>unwrap(cls);
    }

    @Override
    public Object getDelegate()
    {
      return wrapped.getDelegate();
    }
    
    private EntityTransaction transaction;
    
    @Override
    public void close()
    {
      if (transaction != null)
        if (transaction.isActive())
          transaction.rollback();
       
      wrapped.close();
      this.ste = null;
      synchronized(activeWrappers)
      {
        List<EMWrapper> active = activeWrappers.get(jndiName);
        active.remove(this);
        activeWrappers.put(jndiName, active);
      }
    }

    @Override
    public boolean isOpen()
    {
      return wrapped.isOpen();
    }

    @Override
    public EntityTransaction getTransaction()
    {
      transaction = wrapped.getTransaction();
      return transaction;
    }

    @Override
    public EntityManagerFactory getEntityManagerFactory()
    {
      return wrapped.getEntityManagerFactory();
    }

    @Override
    public CriteriaBuilder getCriteriaBuilder()
    {
      return wrapped.getCriteriaBuilder();
    }

    @Override
    public Metamodel getMetamodel()
    {
      return wrapped.getMetamodel();
    }
    
    public static HashMap<String, List<EMWrapper>> getWrappers()
    {
      return activeWrappers;
    }
    
    public String[] getStackStrace()
    {
      if (ste == null)
        return null;
      String[] result = new String[ste.length];
      int i = 0;
      for (StackTraceElement s: ste)
        result[i++] = s.getClassName() + "#" + s.getMethodName() + ":" + s.getLineNumber();
      return result;
    } 
  }
}

Il vero problema.

Nessuno se lo aspettava, neppure Renzi. M5S ha perso, e di brutto, e il PD ha vinto, alla grande. Io ho votato orgogliosamente M5S e per una volta nella vita pensavo che avrei votato coloro che poi avrebbero vinto. Mi sbagliavo.
Ora chi ha orgogliosamente votato PD sarà felice e fa bene, lo sarei anch’io se avesse vinto M5S. Anche chi ha votato PD non tanto perché convinto, ma perché il programma elettorale di M5S è troppo antieuropeo, fa bene ad essere felice, io stesso ho dei dubbi sulle concrete possibilità di uscire dall’euro. Soprattutto, ho dei dubbi sulla reale forza contrattuale italiana: la guerra l’abbiamo persa e le conseguenze economiche ci sono ancora oggi, ma non credo che il vero motivo della scarsa forza contrattuale italiana sia quello. In fondo anche la Germania ha perso la guerra, ma oggi può dire la sua. Il problema più grave è che i debiti li abbiamo non solo con gli USA, ma anche con il resto d’europa, e sono tanti, e non possiamo giocare a braccio di ferro con nessuno. Quindi anche quelle persone che hanno votato PD in considerazione della condizione economica italiana possono ritenersi soddisfatte del risultato elettorale, in fondo hanno espresso un voto ponderato, anche se forse lo hanno fatto turandosi il naso.

Il vero problema sono i restanti elettori, probabilmente la maggioranza, che ancora nel 2014, dopo 20 anni di alternanza PD e FI, passati entrambi per vari nomi ma sempre con le stesse facce, hanno votato PD perché «Berlusconi no», convinti ed il PD sia la sinistra. Il vero problema sono quelli che non si sono informati, che hanno votato sulla base di quel che hanno visto in TV. Il vero problema sono io che non ho fatto tutto quel che potevo per informarli, non per convincerli a votare M5S, ma solo per informarli. Potevo fare di più: una volta consci di quel che facevano, era poi giusto che votassero PD se volevano, sapendo quel che stavano facendo.

Il vero problema non è chi ha votato PD, il vero problema siamo noi elettori M5S che non siamo stati in grado di informare abbastanza. Il vero problema parte da Beppe Grillo, che invece di informare continua a fare il comico. Un grazie a Beppe Grillo che ha creato il MoVimento, ma è tempo che si faccia da parte. Gente come Di Battista al suo posto avrebbe raccolto voti invece di perderne. E le parolacce, anche se io capisco che sono solo un mezzo per far arrivare la comunicazione, non pagano, ma sono un ostacolo nel momento in cui io cerco di far capire lo spirito del MoVimento agli altri.

Grazie comunque a tutti per la partecipazione.

LibGDX: BestFitViewport

Today’s post is in english, because software development and code distribution know only one language: english.

While trying to solve this problem I wrote a new Viewport class (and solved said problem). You are encouraged to read that thread first.

Its name is BestFitViewport and it makes sense only on mobile devices in poorly designed apps that force the user to rotate the device between screens. I know, the right solution would be a good user interface design, but chances are you have no choice because someone else badly designed the app and they pay you to code that crap.

Assuming you end up in such a situation, this class may help you in that:
1. it offers cross platform screen orientation (Android and IOs only, desktop and web app developers DO NOT WANT TO USE THIS, unless they want to force users of a 23 inch. CRT display to physically rotate it now and then…). Please note that I tested this thing only on two Android devices (SGS GT I9000 and SGS GT I9505), however it does not make use of any esoteric features, only two common libgdx classes (Viewport and Camera), so I expect it to work more or less everywhere.
2. It’s way faster than setRequestedOrientation()
3. It works where setRequestedOrientation() was failing (SGS GT I9505), maybe my fault, but I couldn’t spot it

Enough bla bla bla, here is the code:

package org.sulweb.bestfitviewport;

/*
* Copyright © 2014 Lucio Crusca <lucio@sulweb.org>
* Based on LibGDX OrthographicCamera.java source code, nightly 2014-04-20.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/


import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;

public class BestFitCamera extends Camera
{
  public float zoom = 1, stretchFactorX = 1, stretchFactorY = 1;
  public boolean rotated;

  public BestFitCamera()
  {
    this.near = 0;
  }

  public BestFitCamera(float viewportWidth, float viewportHeight)
  {
    this.viewportWidth = viewportWidth;
    this.viewportHeight = viewportHeight;
    this.near = 0;
    update();
  }

  private final Vector3 tmp = new Vector3();

  @Override
  public void update()
  {
    update(true);
  }

  @Override
  public void update(boolean updateFrustum)
  {
    float left = zoom * stretchFactorX * -(viewportWidth / 2);
    float right = zoom * stretchFactorX * (viewportWidth / 2);
    float top = zoom * stretchFactorY * -(viewportHeight / 2);
    float bottom = zoom * stretchFactorY * viewportHeight / 2;
    if (rotated)
    {
      float tmp = left;
      left = top;
      top = tmp;
      tmp = right;
      right = bottom;
      bottom = tmp;
    }
    projection.setToOrtho(left, right, top, bottom, near, far);
    view.setToLookAt(position, tmp.set(position).add(direction), up);
    combined.set(projection);
    Matrix4.mul(combined.val, view.val);

    if (updateFrustum)
    {
      invProjectionView.set(combined);
      Matrix4.inv(invProjectionView.val);
      frustum.update(invProjectionView);
    }
  }

  /**
   * Sets this camera to an orthographic projection using a viewport fitting the screen resolution,
   * centered at (Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight()/2), with the y-axis pointing
   * up or down.
   * 
   * @param yDown
   *          whether y should be pointing down
   */
  public void setToOrtho(boolean yDown)
  {
    setToOrtho(yDown, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
  }

  /**
   * Sets this camera to an orthographic projection, centered at (viewportWidth/2,
   * viewportHeight/2), with the y-axis pointing up or down.
   * 
   * @param yDown
   *          whether y should be pointing down.
   * @param viewportWidth
   * @param viewportHeight
   */
  public void setToOrtho(boolean yDown, float viewportWidth,
      float viewportHeight)
  {
    if (yDown)
    {
      up.set(0, -1, 0);
      direction.set(0, 0, 1);
    }
    else
    {
      up.set(0, 1, 0);
      direction.set(0, 0, -1);
    }
    position
        .set(zoom * viewportWidth / 2.0f, zoom * viewportHeight / 2.0f, 0);
    this.viewportWidth = viewportWidth;
    this.viewportHeight = viewportHeight;
    update();
  }

  /**
   * Rotates the camera by the given angle around the direction vector. The direction and up vector
   * will not be orthogonalized.
   * 
   * @param angle
   */
  public void rotate(float angle)
  {
    rotate(direction, angle);
  }

  /**
   * Moves the camera by the given amount on each axis.
   * 
   * @param x
   *          the displacement on the x-axis
   * @param y
   *          the displacement on the y-axis
   */
  public void translate(float x, float y)
  {
    translate(x, y, 0);
  }

  /**
   * Moves the camera by the given vector.
   * 
   * @param vec
   *          the displacement vector
   */
  public void translate(Vector2 vec)
  {
    translate(vec.x, vec.y, 0);
  }

}
package org.sulweb.bestfitviewport;

/*
* Copyright © 2014 Lucio Crusca <lucio@sulweb.org>
* Based on LibGDX FitViewport.java and ScalingViewport.java source code, nightly 2014-04-20.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Scaling;
import com.badlogic.gdx.utils.viewport.Viewport;

/**
 * This class behaves more or less like a FitViewport; it behaves different
 * when the world units orientation does not match the current display (or
 * window) orientation. This class may be useful only on mobile devices.
 * 
 * You may find this viewport useful only if all the following things hold
 * true for your mobile app:
 * 1. The app has at least one fixed portrait screen
 * 2. The app has at least one fixed landscape screen
 * 3. You agree that 1+2 above is bad user interface design, but your boss does not
 * want to change that
 * 4. You want portable code, i.e. you don't want to call setRequestedOrientation()
 *  because that's Android specific
 * 5. You want a fast orientation switch between screens
 * 6. You're fed up with Android Activity lifecycle and do not want to call setRequestedOrientation()
 * also to avoid a recreate()
 * 7. Your world units are "sane" enough, i.e. the long edge is actually longer, in numbers, 
 * than the short one. If this is not the case for you, it should be reasonably easy to patch
 * my code to support a 800x300 portrait world...
 * 8. Your Activity has a fixed orientation, e.g. the user cannot choose to rotate his device
 * and make the screen layout differently
 * 
 * How to use this class. You basically get the same as a FitViewport that fits the best 
 * fitting orientation, based on world coordinates you pass in and assuming world units
 * are squares.
 * 
 *   stage.setViewport(new BestFitViewport(1000,800));
 *   
 * such a viewport will force landscape orientation and fit the landscape display.
 * 
 *   stage.setViewport(new BestFitViewport(750,1030));
 *   
 * and this one will force portrait orientation and fit the portrait display.
 * 
 * @author Lucio Crusca
 *
 */
public class BestFitViewport extends Viewport
{
  private Scaling scaling;
  private boolean rotated;
  private int screen_width, screen_height;
  private float currentRotation;
  
  public BestFitViewport(float wwidth, float wheight)
  {
    super();
    this.scaling = Scaling.fit;
    this.worldWidth = wwidth;
    this.worldHeight = wheight;
    this.camera = new BestFitCamera();  
  }
  
  private void updateRotationState(int screenW, int screenH)
  {
    this.screen_width = screenW;
    this.screen_height = screenH;
    rotated = (worldWidth > worldHeight && screenW < screenH) || 
              (worldWidth < worldHeight && screenW > screenH);
  }

  @Override
  public void setWorldHeight(float worldHeight)
  {
    setWorldSize(getWorldWidth(), worldHeight);
  }

  @Override
  public void setWorldSize(float worldWidth, float worldHeight)
  {
    this.worldWidth = worldWidth;
    this.worldHeight = worldHeight;
    updateRotationState(screen_width, screen_height);
  }

  @Override
  public void setWorldWidth(float worldWidth)
  {
    setWorldSize(worldWidth, getWorldHeight());
  }

  @Override
  public void update(int screenWidth, int screenHeight, boolean centerCamera)
  {
    if (screenHeight != 0 && screenWidth != 0 &&
        (screenHeight != this.screen_height || screenWidth != this.screen_width)
       )
    {
      updateRotationState(screenWidth, screenHeight);
      Vector2 scaled;
      if (rotated)
      {
        scaled = scaling.apply(worldWidth, worldHeight, screenHeight, screenWidth);
        viewportWidth = Math.round(scaled.y);
        viewportHeight = Math.round(scaled.x);
      }
      else
      {
        scaled = scaling.apply(worldWidth, worldHeight, screenWidth, screenHeight);
        viewportWidth = Math.round(scaled.x);
        viewportHeight = Math.round(scaled.y);
      }
      
      // center the viewport in the middle of the screen
      viewportX = (screenWidth - viewportWidth) / 2;
      viewportY = (screenHeight - viewportHeight) / 2;

      Gdx.gl.glViewport(viewportY, viewportX, viewportWidth, viewportHeight);
      camera.viewportWidth = worldWidth;
      camera.viewportHeight = worldHeight;
      if (centerCamera) 
        camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0); 
  
      float previousRotation = currentRotation;
      currentRotation = rotated ? 270 : 0;
      camera.rotate(currentRotation - previousRotation, 0, 0, 1);
      if (rotated)
      {
        ((BestFitCamera)camera).stretchFactorX = (worldHeight / viewportWidth) / (worldWidth / viewportHeight);
        ((BestFitCamera)camera).stretchFactorY = 1 / ((BestFitCamera)camera).stretchFactorX; 
      }
      ((BestFitCamera)camera).rotated = rotated;      
    }
    camera.update(); 
  }
}

No jars provided, if you want to use it, just copy the code over into your project.

Il gender ed il medioevo

Ricevo oggi via email questo opuscolo. Riporto qui la mia risposta agli amici del gruppo famiglie (che peraltro frequento volentieri) da cui l’ho ricevuto.

EDIT: il gruppo famiglie che frequento è un gruppo di persone cattoliche che nulla ha a che vedere con il forum delle associazioni familiari dell’Umbria (ovvero con gli autori del volantino). Ho ricevuto il volantino in quanto mi è stato girato da qualcuno del gruppo che a sua volta lo ha ricevuto da qualcuno di RnS. Dopo aver scritto questo post mi sono informato sull’identità degli autori: una lista politica, che, ovviamente, fa della lotta al gender uno strumento di propaganda elettorale. Nessuna pretesa di indicare un cammino educativo quindi da parte degli autori, ma solo una pretesa di moralità, strumentalizzata ai fini elettorali. Resta viva più che mai la necessità di verificare con attenzione le fonti e di non diffondere qualsiasi cartigienica solo perché sembra ricalcare certi ideali. E mi riferisco a RnS.

Posto che non sono ancora riuscito a farmi un’opinione in merito, perché le basi scientifiche mancano da ambo le parti e quelle filosofiche/religiose sono sostanzialmente legate alle convinzioni personali (almeno per quello che è la mia conoscenza della materia), per cui uno può ritenere corretto il pensiero di un filosofo o l’insegnamento di un particolare credo, mentre altri possono avere idee diametralmente opposte e ciò nonostante avere buone motivazioni a sostegno, resta il fatto che, pur dando per scontato, per partito preso, che l’ideologia cattolica sia quella corretta, questo modo di agire non può che danneggiare i nostri figli.

Mi spiego: chiudere i figli sotto una campana di vetro per evitare che sentano le idee che a noi non piacciono (tipo tenerli a casa da scuola durante eventuali lezioni sul gender tenute da gente che non la pensa come noi), è un atteggiamento bigotto, dannoso e diseducativo. Folle per dirla in una parola. Invitare altri genitori a seguire una pratica tanto ottusa quanto medioevale in nome di una religione che dovrebbe renderci liberi non ha prezzo, ma verso il basso. Capisco che spesso si compiano delle azioni sulla scia delle mode, senza stare a pensarci troppo e fidandosi della valutazione che altri a noi
vicini hanno dato di tali azioni, ma ritengo doveroso usare anche il proprio cervello quando gli argomenti di cui si parla sono tanto delicati.

Se i nostri figli la teoria del gender non la sentono a scuola, la sentiranno comunque in tv. Se spegniamo la tv, la leggeranno su internet. Se stacchiamo internet, la sentiranno dagli amici. Gli impediamo di vedere gli amici?

Si lo so cosa mi direte, la scuola ha un ruolo diverso dagli amici o dalla tv. Bene, anche noi genitori abbiamo un ruolo diverso ed è nostro preciso compito, prima ancora che un compito della scuola, educare i nostri figli. Mettersi a fare una crociata contro le idee degli altri, invece di mettersi a tavolino a discuterne, è diseducativo. Se abbiamo paura che le idee degli altri possano inquinare i nostri figli, significa che non crediamo abbastanza nelle nostre. Significa che dentro di noi pensiamo di avere armi spuntate. E significa quindi che dovremmo metterci in discussione.

Il modo migliore di reagire alla teoria del gender, sempre dando per scontato che sia da combattere, è proporre incontri sulla visione cattolica, non cercare di oscurare quelli sulla teoria del gender. Abbiamo forse paura di dire come la pensiamo? O forse il problema è che non siamo abbastanza preparati sulla nostra religione da essere in grado di sostenere le nostre idee? E se così fosse (ovvero so che così è), come possiamo sostenere le nostre idee se nemmeno noi sappiamo perché le abbiamo?

No, non terrò a casa i miei figli da scuola e non manderò raccomandate ai dirigenti scolastici intimando di tornare nel medioevo. Cercherò piuttosto di dare ai miei figli le basi per farsi una loro opinione, qualunque essa sia, purché sia un’opinione che si sono fatti loro, con il loro cervello e non con il cervello preso in prestito da altri, siano “altri” i docenti o siano gli amici.

Con immutata stima verso tutti voi.

Lucio.

Il doposcuola Villar. Grazie.

“Il Doposcuola Villar” cresce. Lo fa in silenzio, e per questo è una grande gratificazione. È un piacere vedere che i volontari, che ringrazio sentitamente, dedicano il loro tempo ai bambini anche se tutto ciò non fa guadagnare loro neppure un po’ di popolarità fra i loro amici. Lo fanno per passione. Lo fanno per i bambini. Non cercano alcun tornaconto materiale. Non voglio nominare qui i volontari, loro sanno che io li ringrazio e sanno che i bambini li ringraziano. La scuola, pur nel suo intrinseco immobilismo calato dall’alto, tipico di quando la si pensa come un’istituzione, è fatta di persone: i docenti sono persone che hanno a cuore i nostri bambini ed anche loro ringraziano i volontari del doposcuola. Lo so che lo fanno, so anche che i docenti considerano il doposcuola un’iniziativa importante: lo so perché me l’hanno detto, forse senza accorgersene, ma me l’hanno detto. In particolare me lo hanno detto ieri, al telefono, mentre mi chiedevano se ci fosse la possibilità di inserire nel progetto doposcuola un nuovo bambino di prima elementare: il modo migliore di dire grazie, anche se fosse un grazie inconsapevole, è chiederci di continuare e di aumentare la nostra attività.

Noi vogliamo raccogliere questa sfida, la crescita. Speriamo di aiutare i bambini a crescere e nel frattempo impariamo a crescere anche noi. Il doposcuola cresce non grazie alla pubblicità, che non facciamo, non grazie ai soldi, che non abbiamo, né grazie al tornaconto, che non c’è.

Il doposcuola cresce grazie alla sua utilità, che si pubblicizza da sola, grazie alla qualità del servizio, che non ha bisogno di soldi e grazie, soprattutto, al tempo che i volontari dedicano ai bambini.

Aiutaci a crescere. Aiutati a crescere. Aiutali a crescere. Dedica un po’ del tuo tempo al doposcuola. C’è un bambino, di prima elementare, che ha bisogno di un aiuto per imparare l’alfabeto ed i numeri. È il motivo per cui scrivo, il motivo per cui ieri ho ricevuto la telefonata dalla scuola di Villar. Se hai letto fino a qui, sicuramente sei in grado di aiutarlo. Contattami, ti darò tutti i dettagli.

Grazie a tutti quelli che hanno letto, grazie ai volontari, grazie al Comune di Villar Perosa, grazie alla scuola, grazie ai genitori dei bambini che si fidano di noi.

Grazie a te che hai appena deciso di far parte di questo piccolo grande progetto.

Sviluppo di applicazioni web in team

Le pagine di un sito dinamico che ha sia una forte componente di business logic, sia dei precisi requisiti estetici e comunicativi, devono necessariamente essere sviluppate da più persone, ognuna nel proprio ambito di competenza.

Lo sviluppo contemporaneo dei due aspetti, comunicativo e funzionale, è però problematico, indipendentemente da quale linguaggio usino i programmatori e da quale software di authoring usino i web designers.

I web designers devono poter scrivere (o far scrivere dal loro software preferito) il codice HTML ed il codice CSS e devono anche poterlo modificare all’occorrenza fino a raggiungere il risultato desiderato dal cliente. I programmatori devono, d’altro canto, modificare il codice HTML creato dai web designers, per aggiungere la caratteristica di generazione dinamica dei dati a tali pagine. Le modifiche apportate dai programmatori tipicamente non vengono interpretate nel modo corretto dal software utilizzato dai web designer, il quale smette di riconoscere e di renderizzare l’intera pagina modificata dal programmatore, oppure ignora le parti che non capisce, ma, in questo caso, non risalva le modifiche in modo corretto dopo che il designer ha cambiato qualcosa puramente estetico all’interno della pagina. Tutto ciò ovviamente supponendo che il web designer non usi solamente un semplice editor di testi, cosa piuttosto rara.

Molti framework e linguaggi di sviluppo software, inoltre, semplificano la vita al programmatore, permettendogli di spezzare la pagina HTML in files più piccoli e più facilmente gestibili, per poi ottenere la pagina finale attraverso una procedura automatica di ricomoposizione delle parti, che avviene al volo durante la generazione dinamica delle pagine stesse. Se da una parte questo semplifica la vita al programmatore, dall’altra la complica infinitamente al web designer, il quale ora si trova con tanti pezzetti di files HTML, apparentemente sparsi senza filo logico (il filo logico è scritto nel codice del linguaggio usato dal programmatore, ovvero in un modo incomprensibile al web designer).

A seconda dei casi specifici, dipendenti dai software e framework usati, dalla composizione del team e dalle competenze di ognuno, ci possono essere varie soluzioni più o meno efficaci a questi problemi, ma l’unica soluzione trasversale ed applicabile indipendentemente da tutti i fattori citati ci arriva dall’oriente: «Modo migliore di evitare pugno… è di non essere li». Tradotto, il modo migliore è evitare la sovrapposizione fra il lavoro dei web designers e quello degli sviluppatori software.
Per poterla evitare, è necessario che i web designers terminino il loro lavoro prima che gli sviluppatori inizino a lavorare sull’interfaccia utente. Per potersi permettere questo lusso, è necessario prevedere i due step di sviluppo, chiarire il problema al committente e chiedergli di approvare la grafica del sito prima che questo vada online, ovvero spiegargli che da quando lui approva la grafica a quando andrà online passerà un tempo maggiore di zero, durante il quale gli sviluppatori creeranno l’interfaccia utente e durante il quale nessuna modifica all’asspetto grafica sarà più possibile. Nella realtà dei fatti poi si cerca di non essere così rigidi, ma è importante far passare il messaggio a priori.

La metodologia di sviluppo del team deve tenere conto del fatto che lo sviluppo delle pagine HTML non deve sovrapporsi, in linea temporale, allo sviluppo dell’interfaccia utente dinamica, ma deve precederla.

I web designers sviluppano quindi prima la struttura HTML delle pagine, utilizzando dati statici e fittizi per le parti che saranno in futuro generate dinamicamente. Contemporaneamente, sul lato sviluppo software, gli sviluppatori partono dal backend (come fra l’altro è normale che sia) e solo in un secondo momento, quando l’aspetto estetico è ormai stabile e deciso, lo si congela e si procede allo sviluppo della parte software che si occuperà dell’interfaccia utente.

Dopo il congelamento dell’aspetto estetico, sarà ancora possibile, per i web designers, apportare qualsiasi modifica essi vogliano ai files CSS, ma non sarà più possibile per loro modificare autonomamente i files HTML. Qualsiasi modifica ai files HTML, dopo il congelamento, dovrà essere fatta dal team di sviluppo software su indicazione dei designers e, in caso di modifiche strutturali, potrebbe comportare il rifacimento di parte del lavoro di sviluppo software per l’interfaccia utente eventualmente già svolto.

Tutto questo deve essere tenuto in debita considerazione nel pianificare i lavori, nel prevedere le date di consegna, nell’anticipare al cliente gli step di produzione del sito ed in generale nel costruire un diagramma di Gantt il più possibile fedele al progetto che si sta facendo.

Va bene, direte voi, ma in che modo questa soluzione sarebbe migliore di altre? Beh, il meglio ed il peggio sono concetti soggettivi, ma a favore di questa soluzione c’è una minor dipendenza da variabili aleatorie che, per quanto aleatorie, giocano sempre a nostro sfavore, e fanno immancabilmente slittare in avanti la data di consegna. In pratica questa soluzione ha il grande vantaggio di permetterci di dire subito al cliente una data di consegna che più probabilmente riusciremo a rispettare. Cliente soddisfatto.