follow me on Twitter

    DualHead e Gnome workarounds

    Questa settimana mi sono cimentato involontariamente nella configurazione del DualHead sulla mia GNU/Linux Box ;-)

    Il DualHead è una modalità di funzionamento dell’interfaccia grafica coadiuvato dalla capacità della scheda video di gestire più periferiche di output contemporaneamente (ad esempio l’ LCD e l’uscita VGA di un portatile).

    Precedentemente questa modalità di funzionamento era supportata da XWindows mediante un estensione chiamata Xinerama.

    Ultimamente la funzionalità di DualHead è invece integrata nel modulo XRandr che è in grado di selezionare al volo la risoluzione grafica delle schede video e anche di attivare le schede video secondarie senza necessità di riavvio di XWindows (necessaria invece con Xinerama essendo configurata staticamente nel file di configurazione di Xorg)

    XRandr, con la possibilità di riconfigurazione live, è un grande passo in avanti per Xorg… ma come tutte le cose nuove introduce anche nuovi problemi :-D

    La modalità DualHead è sicuramente utile per lavorare su più applicazioni contemporaneamente ma è ancora più utile durante presentazioni e seminari, permettendo di eseguire su uno schermo (il proiettore agganciato all’uscita VGA) la presentazione e sull’altro (l’LCD del portatile) la scaletta/mindmap della presentazione, magari con le note riguardanti i dettagli importanti da non dimenticare :-)

    Ho provato ultimamente a configurare il DualHead in una modalità diversa dalla modalità mirror (che semplicemente clona i due output mostrando su entrambi il medesimo desktop) e ho avuto qualche problemino dovuto probabilmente alla non completa integrazione del nuovo sistema XRandr nella applicazioni e desktop environment (nel mio caso GNOME).

    Nel cercare dei workaround a questi problemi ne ho comunque tratto una conoscienza migliore dei meccanismi e delle tecnologie coinvolte e ho deciso quindi di lasciare queste 4 righe di traccia a beneficio di chi potrebbe incontrare i miei stessi problemi ;-)

    Le ultime versioni Ubuntu (e quindi molto probabilmente anche molte altre distribuzioni) integrano un sistema guidato di riconfigurazione degli output video:

    • gnome-display-properties (compreso nel pacchetto gnome-control-center

    Tra l’altro ci deve fare piacere il fatto che tra i contributor c’e’ un cittadino di adozione leccese ;-) (Alberto Milone) che ha contribuito, tra le altre cose, all’integrazione con X-Kit (di cui ne è autore) per automatizzare quelle procedure che richiedono ancora la configurazione di Xorg attraverso il suo file di configurazione statico.

    Ad esempio una configurazione che fa a finire nel file di configurazione /etc/X11/xorg.conf è la risoluzione virtuale totale (cioè la superficie virtuale che verrà spezzettata tra i vari output reali):

    Section "Screen" 
      Identifier "Default Screen" 
      Device "Intel Corporation Mobile 915GM/GMS/910GML Express Graphics Controller" 
      Monitor "LVDS" 
      DefaultDepth 24 
      SubSection "Display" 
        Depth 24 
        Modes "1280x768" "1024x768" "800x600" "640x480" 
        Virtual 1280 1536 
      EndSubSection 
    EndSection 
    

    Queste modifiche verranno effettuate in maniera completamente trasparente grazie alla collaborazione tra gnome-display-properties, screen-resoluzion-extras, X-Kit e PolicyKit

    Il lavoro di fino degli ultimi anni di freedesktop e dei team di sviluppo di gnome e delle varie distribuzioni stanno finalmente dando i loro primi frutti ;-)

    BUG

    Tutto ha funzionato perfettamente… o quasi… di ritorno dal suspend il tool gnome-display-properties fallisce silenziosamente e non ho avuto ancora la possibilità di approfondire il problema :-(

    Beh… poco male… in ogni caso xrandr è sempre li pronto a servirci attraverso la nostra linea di comando :-D

    Ma rimane comunque un problema troppo fastidioso per essere ignorato:

    i pannelli gnome finiscono nel primo monitor… che per qualche oscuro motivo (almeno sul mio laptop, un Latitude X1) non è l’LCD del laptop ma il monitor esterno…

    … perfetto… il mio obiettivo era ottenere esattamente il comportamento contrario :-(

    Use the Zen: circoscrivere il problema

    In questo caso mi è sembrato naturale pensare che il problema non poteva che risiedere dentro gnome… così prima di andare a guardare i sorgenti o pensato fosse il caso di dare una sbirciata alle chiavi di configurazione GConf con gconf-editor

    Ed eccolo li… è bastato cercare tutte le chiavi di configurazioni contenenti il termine monitor per identificare una chiave interessante /apps/panel/toplevels/panel_0/monitor

    Un rapito test al volo ha dimostrato che semplicemente cambiando la chiave (al volo visto che viene automaticamente ridefinita in caso di assenza del monitor VGA) sposta il pannello sul monitor che preferiamo :-PPPPP

    WORKAROUND

    Dopo aver circoscritto il problema è bastato impacchettare il workaround in un mini-script bash:

    xrandr --output VGA --mode 1024x768 --pos 0x0 --output LVDS  --mode 1280x768 --pos 0x768
    
    gconftool --type int --set /apps/panel/toplevels/panel_0/monitor "1"
    gconftool --type int --set /apps/panel/toplevels/panel_1/monitor "1"
    

    Ohhh… now it’s work!!!

    Happy dualhead, rpl

    geekevening 0x12

    Domani l'appuntamento a ZEI che ha come argomento il wiimote scripting in ambiente GNU/Linux in compagnia mia e del buon fabio ;-)

    geekevening 0x12: wii && GNU/Linux

    Lo sapevate? Il wiimote è molto di più di un joystick per la Nintendo Wii... e potreste utilizzarlo come telecomando, trasformarlo in un strumento musicale o nell'accelleratore di una moto virtuale!!! Come? Vi aspettiamo Mercoledì 19 Novembre alle 21.00 per scoprire insieme come comunicare con questo fantastico dispositivo con la sola imposizione delle mani e due manciate di Software Libero :-D Sapevatelo su geekevening 0x12 :-P

    Just4Fun: Python Wiimote Control

    Just For Fun: Python Wiimote Control

    From SaLUG’s LinuxDay2008… … powered by “Just4Fun (TM)”

    Python Wiimote Control

    Intro

    In principio c’era il declino inesorabile della Nintendo nel panorama delle console per videogame, la quale lasciava il passo alla muscolosa Sony con la sua PlayStation… ed infine a Microsoft che con la sua XBox sottocosto (che in realta’ paghiamo tutti noi con le licenze di Windows che siamo costretti a comprare insieme ai nostri PC) intende rompere le balle alla Sony… buon per noi :-P

    La Nintendo in questa lotta a due (tra PlayStation e XBox) ha deciso di non immischiarsi e ha scelto la strada dell’innovazione anziche’ quella dei muscoli… evidentemente hanno assunto qualche dirigente piu’ sveglio e rinfrescato il settore Ricerca e Sviluppo.

    Questi fatti apparentemente banali e senza alcun interesse “scientifico” hanno generato pero’ un importante cambiamento nel campo dell’intrattenimento casalingo:

    nuove possibilita'/modalita' di interazione uomo-macchina

    Quanti anni sono passati da quando abbiamo cominciato ad usare tastiere, joystick, joypad e mouse… … e’ arrivato il momento di cambiare… ed era anche ora!!!! :-)

    Sono veramente poche le tecnologie rimaste cosi’ statiche quanto quelle di interazione uomo-macchina.

    E questo non riguarda solo il settore ludico o dell’intrattenimento.

    Wiimote

    Questo e’ il Wiimote (il telecomando/joystick bluetooth della Nintendo Wii) una periferica di interazione totalmente nuova, le cui possibilita’ sono solo in minima parte conosciute e sfruttate a pieno dai giochi della Wii.

    Probabilmente neanche chi lo ha inventato sapeva realmente quanti campi di applicazione gli avrebbero trovato in breve tempo gli hacker di tutto il mondo:

    Ma come fanno?!?!?!?

    Cosa c’e’ di tanto magico in un Wiimote da renderlo cosi’ poliedrico?!?!

    Beh si fa presto a dirlo :-P

    Oltre a vari pulsanti, pulsantini e freccette (comuni in altri joystick/joypad) ci sono 2 importanti novita’:

    • un accellerometro… che misura, indovinate un po’… l’accellerazione
    • una videocamera che (attraverso varie elaborazioni dei segnali fatte all’interno del wiimote stesso) calcola la posizione di 4 sorgenti luminose infrarosse all’interno del suo campo visivo

    … oooooh! (fate un’espressione stupita… dai! :-P)

    Grazie all’accellerometro possiamo conoscere gli spostamenti del wiimote sui 3 assi e cosi’ come alcuni degli angoli di orientamento (in particolare pitch e roll)…

    … pero’ non e’ possibile calcolare lo yaws

    e che c…to e’ lo yaws direte voi…

    Per riuscire a calcolare lo yaws i ricercatori della Nintendo hanno pensato di piazzare una barra dotata di 4 led (la Sensor Bar) con la console e di utilizzare una telecamerina nel Wiimote per identificare l’orientamento del Wiimote sul piano orizzontale quando la Sensor Bar si trova all’interno del suo campo visivo…

    e avete ragione… e’ quello che ho pensato anche io… non si capisce un… ma dato che una illustrazione vale piu’ di mille parole ecco a voi:

    grafico degli assi applicati ad un wiimote

    Ora dopo aver ringraziato tutti quelli che hanno reversato, documentato e scritto librerie ed applicazioni per questa stupenda periferica (e molte sue estensioni ;-)):

    potete andare a divertirvi anche voi un po’ ;-)

    Just For Fun: Python Wiimote Control

    Da vero geek non sono riuscito a vedere tutta sta gente divertirsi come i matti e non poter partecipare :-D

    Quindi ho deciso di farmi un regalo e comprarmi un bel Wiimote… si solo la periferica ;-)

    Ho cominciato a giocarci un po’ attraverso la libreria cwiid e in particolare utilizzando il binding in python.

    I primi timidi tentativi si sono concretizzati nell’emissione di rumori di vario genere da parte di un sintetizzatore (ZynAddSubFX) a cui inviavo messaggi MIDI basati (malamente) sull’accellerazione del Wiimote…

    avevo proprio bisogno di leggere un paio di righe di documentazione in piu’ … http://www.wiili.org/index.php/Motion_analysis

    Dopo aver letto un po’ di documentazione l’emissione di rumori e’ diventata l’emissione di 3 note diverse con velocita’ (nel senso midi del termine) proporzionale all’accellerazione del wiimote opportunamente riscalata (sarebbe piu’ corretto dire empiricamente riscalata :-P)

    Volendo mi sarei anche accontentato… se non fosse stato per la gradita visita di due altri geek locali (Fabio “valvola” Viola e Enrico “Bongy” Tramacere) che con domande, valutazioni e nuove periferiche (il Nunchuk :-P) mi hanno costretto a continuare :-PPPPP

    Come potevo non provare a far diventare il Nunchuk il plettro della mia “chitarra elettrica” bluetooth? Come potevo resistere all’irresistibile voglia di utilizzare i due accellerometri presenti in Wiimote e Nunchuk di concerto per simulare le due bacchette di una batteria?

    Non potevo… ma soprattutto non volevo resistere :-P

    Quindi una variante dopo l’altra mi sono trovato con 3 scriptini in python:

    • wiiguitar: per simulare una chitarra elettrica con wiimote e zynaddsubfx
    • wiidrums: per simulare una batteria con wiimote e hydrogen
    • wiidesktop: per controllare desktop e applicazioni con il wiimote durante le presentazioni

    LinuxDAY2008

    Un hack cosi’ divertente non poteva mancare al linuxday del GLUG piu’ bello del mondo :-D

    Pero’ sai che palle riavviare lo script e rieffettuare il detect del wiimote per passare da uno modalita’ all’altra?!?!?

    Gia immaginavo Francesco “haku” Palermo esclamare: “che pizza… ma devi scrivere tutte ‘ste cose ogni volta?!?!?”

    Allora ho pensato che sarebbe stato carino fondere di nuovo insieme i 3 script e studiare un modo per passare da una modalita’ ad un’altra con la pressione di un tasto del Wiimote (il tasto home in particolare).

    Visto che fondamentalmente le differenze tra quegli script si limitavano alla fase di inizializzazione e all’interpretazione dei messaggi provenienti, il refactoring e’ consistito nel trasformare gli script in moduli da caricare e scrivere un nuovo script che inizializzi tutti i moduli e nella propria callback intercetti un tasto di cambio modalita’ per poi passare il controllo alle callback dei moduli attivi…

    … si si… e’ piu’ facile da scrivere in python che a spiegarlo in italiano :-P

    Get the sources

    Essendo un piccolo hack non c’e’ ovviamente ne binario ne risoluzione automatica delle dipendenze :-)

    C’e’ un repository di codice GPLv3 da scaricare, studiare e modificare a proprio piacimento … esercitate liberamente le vostre 4 liberta’ :-P

    Nel README ci sono anche due note sulle dipendenze ma in ogni caso invito chi decidesse di cimentarsi nel tentativo di utilizzarlo sulla propria macchina o di utilizzarlo come base per qualche proprio esperimento di scrivermi le proprie idee e/o problemi su questo piccolo pezzo di “cera pongo” :-) all’indirizzo “rpl AT salug.it”

    Per eventuali flame, troll, insulti etc. scrivetemi pure… saranno tutti ridirezionati su /dev/null :-D

    beh… bando alle ciance ora…

    Happy Hacking, rpl

    Mozilla, Ubiquity e DBUS

    La scorsa settimana mi sono imbattuto in una estensione per mozilla molto interessante: mozjs_dbus

    Credo che Ubuntu dovrebbe seriamente valutare la possibilità di compilare e installare questa estensione di default per migliorare l’integrazione del browser con il resto dell’ambiente desktop.

    In pratica la funzione dell’estensione è quella di esporre all’interno di chrome (inteso come la componente privilegiata del broser e non il broser di google) dei servizi che consentano di accedere e fornire servizi dbus.

    Il tutto è condito da un’API Javascript che consente di colloquiare agevolmente con dbus, che all’interno del panorama delle tecnologie Desktop libere costituisce l’analogo di COM, CORBA o XPCOM.

    Visto che la compilazione dell’estensione (che necessita dei sorgenti di mozilla) non è risultata troppo complessa (come unico imprevisto ho dovuto aggiornare il file install.rdf del’estensione per estenderne la compatibilità a Firefox 3.0.3)

    Volevo fare una prova… così ho pensato che poteva essere una buona scusa per provare a scrivere il primo comando per Ubiquity, estensione che aggiunge a firefox una commandline con cui colloquiare con il browser un po’ come faccio con emacs :-)

    Mediante dbus-viewer è possibile navigare le interfacce dbus messe a disposizione dalle applicazioni attualmente attive… tra tutte ho individuato Tomboy.

    Tomboy è un’applicazione gnome per conservare delle note ed esporta un interfaccia dbus particolarmente completa in quanto consente di effettuare tutte le operazioni CRUD sulle note.

    Ho creato quindi 2 nuovi comandi per ubiquity:

    • tomboy-list: che restituisce in preview l’elenco puntato dei titoli delle note
    • tomboy-view: che restituisce in preview l’elenco puntato di titolo e contenuto delle note che contengono la stringa passata come parametro

    iNvida CSS bomb

    Se avete un amico sborone che vi costringe ad apprezzare la superficie satinata del suo portatile XPS ed ammirare le fantastiche performance della scheda Nvidia con cui è equipaggiato… non disperate…

    Se il pomeriggio è particolarmente noioso e piovoso e volete divertirvi con poco potete vedere impazzire il vostro caro amico sborone e sfruttare una fantastica feature della sua scheda NVidia ;-)

    vi basterà creare una pagina con tanti bei div e span colorati e sparare nel css un bel:

    body {
      opacity: .99;
    }
    

    … BOOOOOOOOM: 100% CPU

    vallo a capire ora che il bug non è in Firefox… non è in X.org… … non è nel kernel Linux… ma nel fantastico driver NVidia :-D

    iNdivia bombarda anche tu un tuo amico sborone ;-)

    Svegliatemi da questo incubo...

    MozREPL e Firefox 3: access unsafe properties from chrome

    Ci sono dei tool senza i quali mi sentirei disarmato… come farebbe il muratore senza la “cardarina” o la “livella” :-DDDD

    Nello sviluppo in Javascript il tool a cui non riesco assolutamente a rinunciare è MozREPL!!!

    La sensazione di controllo che mi da potermi collegare in telnet (comodamente dal mio emacs) dentro il browser a navigare nella mia applicazione e relativo codice Javascript è ineguagliabile.

    Certo c’e’ Firebug… ma vuoi mettere… ssh con vnc? :-D

    non c’e’ confronto :-P

    Purtroppo le notevoli rivoluzioni avvenute tra Firefox 2 a Firefox 3 hanno introdotto tutta una serie di policy aggiuntive di sicurezza che hanno reso il porting faticoso (o meglio fastidioso :-P) per lo sviluppatore del progetto.

    Per la gioia di tutti bard ha preso la volpe per le corna (:-PPP) e bypassato tutta una serie di complicazioni introdotte da queste nuove policy, ridandoci MozREPL in tutto il suo splendore anche su Firefox 3.

    Colpo di scena

    Giocavo un po’ con ExtJS come passatempo domenicale e ad un certo punto ho avuto bisogno di vedere alcuni dettagli da più vicino … attivo MozREPL!

    Navigando nel DOM mi accorgo di qualcosa di strano:

      repl> repl.enter(content)
      [object XPCWrappedNative [object Window]] ...
      repl> repl.look()
      ...
      this.Ext= undefined
      ...
      ...
      repl>
    

    uhm… strano… l’object che dovrebbe contenere tutti gli oggetti di ExtJS è presente nell’elenco delle proprietà di window ma risulta undefined.

    uhm… dopo averne discusso brevemente con bard l’occhio salta improvvisamente qualche riga sopra:

      repl> repl.enter(content)
      [obejct XPCWrappedNative [object Window]] ...
    

    Azz… window risulta wrapped… in altre parole per evitare di accedere inavvertitamente a codice insicuro Firefox 3 ricopre gli oggetti provenienti dal content con una interfaccia di protezione quando ci accediamo da chrome :-(

    e ora?!?!?!

    WebSurfing

    Non bisogna mai disperare… chi cerca trova:

    Secondo quanto scritto nella documentazione mozilla:

     If unsafe access to a property is required for some reason, this can 
     be accomplished via the wrappedJSObject property of the wrapper.

    bene bene bene… quindi:

    Workaround

      repl> repl.enter(content.wrappedJSObject)
      [object Window] ...
    

    perfetto!!! ora le proprietà sono nuovamente accessibili :-D

    Soluzione

    Beh che c’e’ di meglio per una domenica pomeriggio dell’eliminare un workaround :-D

    Il codice di MozREPL è veramente pulitissimo, di conseguenza sono bastati pochi minuti per identificare il punto in cui intervenire ed introdurre la modifica:

     // CONTEXT NAVIGATION
     // ----------------------------------------------------------------------
     
    -function enter(context) {
    +function enter(context, wrapped) {
    +    if (wrapped != true && context.wrappedJSObject != undefined) 
    +      context = context.wrappedJSObject;
    +
         this._contextHistory.push(this._workContext);
     
         if(isTopLevel(context))
    

    Ohhh ora tutto è tornato come prima e ho di nuovo la mia “livella” :-D

    Git it a try

    Era un po’ che mi ci imbattevo… all’inizio raramente… poi sempre piu’ spesso… GIT

    Fino ad ora mi ero sempre limitato a ”‘clonare”’ repository di progetti che avevo intenzione di compilare dai sorgenti e di qualche nuovo plugin per Rails.

    Ma con la semplice operazione di clonazione non ero ancora riuscito a visualizzare analogie e differenze con altri sistemi di controllo delle revisioni decentralizzato DVCS che mi sono trovato ad utilizzare in precedenza, ed in particolare con il sistema che sino ad adesso ho utilizzato per revisionare i sorgenti e documenti su cui lavoro, Bazaar.

    In realtà non mi sono mai trovato così male con bazaar da motivarmi sufficientemente alla ricerca di un alternativa, per cui l’aumento esponenziale della popolarità e diffusione di GIT mi è diciamo scivolata addosso :-D

    Certo GitHub aveva l’aria di essere una gran figata… ma… non lo so… per quale motivo provare git?

    Just for fun, naturalmente :-)

    La molla

    La molla che ha fatto partire l’interesse e la successiva fase di studio e test è stato un articolo trovato per caso durante una recente sessione di websurfing:

    Git is the next unix
    http://www.advogato.org/person/apenwarr/diary/371.html

    L’articolo non è particolarmente approfondito ma dipinge GIT da un altro interessante punto di vista:

    git is a totally new way to operate on data

    […]

    With git, we’ve invented a new world where revision history, checksums, and branches don’t make your filesystem slower: they make it faster.

    They don’t make your data bigger: they make it smaller.

    They don’t risk your data integrity; they guarantee integrity.

    They don’t centralize your data in a big database; they distribute it peer to peer.

    La goccia

    La goccia poi che ha fatto traboccare il vaso e spinto di fatto a interessarmi alla questione è stata la scoperta di un piccolo progetto chiamato etckeeper.

    Questo piccolo insieme di script bash utilizza un sistema di revisione (git di default ma con supporto anche di bazaar o darcs) allo scopo di tenere in revisioning i file di configurazione di un sistema (/etc per intenderci) consentendoci quindi di tracciarne meglio la vita e di poter riportare tutti o alcuni file ad una versione precedente senza nessun problema.

    E così ho deciso che era decisamente il momento di approfondire git, il suo funzionamento, le differenze e le analogie con gli altri sistemi simili, i vantaggi e gli svantaggi.

    WebSurfing about GIT

    E così è partito il websurfing di approfondimento:

    Goosh - a command line on google

    Dato che mi sembra che il post precedente abbia occupato per troppo tempo questa prima pagina... talmente tanto che gli annunci di google qui accanto cominciano a propormi roba del tipo "11 esami in 10 mesi" :-P e visto oltretutto che a parte il dovuto sfogo ho altro a cui pensare e con cui divertirmi ;-)
    ma soprattutto dato che il compagno Domenico continua a punzacchiarmi su questa cosa...
    ho deciso di dedicargli questo micropost :-D
    Goosh è una "interfaccia CLI non ufficiale" per effettuare ricerche su google.
    In pratica è una piccola applicazione XHTML+Javascript che implementa una interfaccia in linea di comando (del tutto simile ad una shell) la quale comunica in AJAX con i servizi google mediante le loro API.
    E' un hack molto simpatico e anche particolarmente piacevole per chi come noi adora usare il terminale a caratteri ;-)
    Happy gooshing

    Geekevening 0x0E

    Non sono sicuro di riuscire pienamente a descrivere la sensazione provata ieri sera al geekevening-0x0E "Jamendo"...

    Quest'ultimo geekevening aveva (come è facile intuire dal titolo) come argomento l'accesso ai servizi offerti dal progetto Jamendo e in particolare lo sviluppo da parte di due giovani quanto promettenti geek del nostro amato LUG di 2 plugin per integrare le risorse audio CC disponibili su Jamendo nei loro player audio preferiti (EMMS e Audacious).

    Il numero di partecipanti superava di poco la decina, numero comunque elevato visto l'argomento molto tecnico (elisp e C), ma la cosa più bella a mio avviso era il clima che si respirava:
    hackmeeting

    Incredibile ma vero... eravamo a Lecce... nello Spazio Sociale ZEI... ma la sensazione che ho provato era quella di trovarmi ad uno dei seminari dell'hackit:

    Curiosità... entusiasmo...e una sufficiente dose di tecnicismi mista a quella classica (quanto fastidiosa per i !geek) ironia geek :-D

    Ho seguito con estremo interesse l'esposizione di entrambi (valvola e sydro), e probabilmente sono stato fastidioso come una zanzara d'estate (spero di non aver esagerato ;-P) ma che ci posso fare... ero preso troppo bene e non riuscivo a trattenermi dal partecipare attivamente... forse trooooppo attivamente :-D

    Siete autorizzati a imbavagliarmi la prossima volta :-P

    In conclusione... grazie ragazzi (lacrimuccia :°D)... a tutti coloro che hanno realizzato uno o più geekevening e a tutti coloro che vi hanno partecipato... sono andato a casa con un sorriso ebete di soddisfazione stampato in faccia ieri sera...

    ...ho sognato questo giorno dal momento in cui ho cominciato a capire il perchè avevo diviso il mio disco a metà per fare posto a GNU/Linux:

    il giorno in cui avrei potuto guardare una pagina come questa:
    http://salug.it/wiki/index.php/LaNotteFaLoHacker
    e dire questo succede a Lecce... e lo abbiamo fatto succedere noi ;-)

    Al prossimo geekevening allora...

    Use the Profiler, Luke

    Una delle fisse (una delle tante) che ci ritroviamo come programmatori è quella dell'ottimizzazione.

    Come ogni fissa, sono diverse le scuole di pensiero: c'è chi ritiene di dover scrivere tutto in C o meglio ancora in assembler, chi ritiene si debbano evitare i linguaggi di scripting puramente interpretati a vantaggio di quelli basati su bytecode, chi di dover evitare questo o quel framework e che sia meglio riscriversi le funzionalità da zero invece che affidarsi a libreria di uso più generico... etc. etc. etc.

    Ma il problema IMHO è che l'ottimizzazione è un problema che trascende il linguaggio di programmazione, il sistema operativo, la virtual machine, il framework e qualsiasi altra discriminante tecnologica.

    Tra le cose lette e la mia modesta esperienza a riguardo credo di poter affermare di essere pienamente daccordo con Martin Fowler (http://martinfowler.com/ieeeSoftware/yetOptimization.pdf):

    La prima domanda che ci dovremmo porre e a cui dovremmo dare risposta (alla Marzulliana maniera) è:

    Ottimizzare COSA?!?!?

    Inutile ottimizzare un software che non è stato ancora scritto

    Inutile ottimizzare qualcosa che non si è ancora misurato... anche perchè se non lo abbiamo misurato... come facciamo a essere sicuri che quella che abbiamo intavolato è una ottimizzazione?

    "If you make an optimization and don’t measure to confirm the performance increase, all you know for certain is that you’ve made your code harder to read." (Martin Flowler)

    Quindi? Personalmente seguo gli insegnamenti di Obi-Wan :-)

    "Use the Profiler, Luke"

    Ultimamente mi sono trovato insieme ai miei altri Alca-compagni nella situazione di voler identificare quale parte di una nostra applicazione Javascript introduce un ritardo non proprio trascurabile per valutare se e cosa ottimizzare.

    Le soluzioni che abbiamo trovato e provato per Javascript sono 3: Il primo si è rivelato molto efficace per effettuare il profiling del codice javascript privilegiato (quello nella zona chrome di mozilla):

    Il secondo si è rivelato più comodo per il profiling di codice javascript contenuto nelle pagine HTML (quello nella zona content nella terminologia mozilla):

    L'ultimo di è rivelato utile per misurare velocemente il profiling di una singola funzione o di punti particolari di una stessa funzione Javascript:

    Provare per credere ;-)

    "Use the Profiler, Luke... Use the Profiler"

    ExtJS: myContainer.items.items.items.items... :-D

    E chi l'avrebbe mai detto?!?!?!

    ExtJS è un gran bel toolkit... un vero è proprio UI toolkit (come Gtk, Qt, Swing etc. etc.) per Javascript multibrowser.

    Sono ormai un bel po' di mesi che lo usiamo passando dalla versione 1.1.1 alla nuova 2.0.

    Siamo molto soddisfatti della pulizia e flessibilità del framework e la composizione lazy in JSON dell'interfaccia è un vera manna... non mancano ovviamente le sorprese... ma in fondo è questo il bello dell'usare nuove tecnologie fresche fresche... la continua scoperta :-)

    Una delle cose a cui non riuscivamo assolutamente a rassegnarci era quello di non riuscire a scorrere gli item di un Ext.Container mediante l'attributo items:
    
    >> console.log(myContainer.items)
    [ undefined, undefined, undefined ]
    
    
    tradotto da Javascript in italiano: "la lunghezza dell'array è giusta... mah dove c....o stanno i nostri oggetti Ext.Component?!?!?!?"

    ancora più strano visto che con il metodo find si ottiene un array di Ext.Component:
    
    >> console.log(myContainer.find())
    [Object initialConfig=Object id=contact-info xtype=panel, 
     Object initialConfig=Object id=operator-notes xtype=form, 
     Object initialConfig=Object xtype=textarea]
    
    non è sopportabile la sensazione di essere preso per il c..o da un pezzo di codice Javascript!!!!

    beh... grazie ad un po' di debugging e con l'aiuto dei watch di Firebug il mistero è svelato: items.items... i maledetti!!!!!!

    e c'è anche un motivo, anche se puo' sembrare assurdo: items è una istanza di Ext.util.MixedCollection che ha a sua volta un attributo items contenente l'array di istanze di Ext.Component :-(

    Questa si chiama proprio cieca deformazione professionale :-P

    items.items non si può proprio sentire... beh almeno ora sappiamo perchè ;-)

    Localize your XUL

    Ho scritto questo breve howto per non dimenticare la procedura di esternalizzazione delle stringhe e di conversione in formato po/pot allo scopo di usufruire dei tool di internazionalizzazione che supportano questo formato. L'articolo si trova su XULIT all'url: Link utili

    OpenWRT snapshot by night

    Dovendo ricondizionare ( :-P ) una fonera per un amico ho deciso di provare questo famigerato tool "AP51 Easy Flash" che automatizza completamente la procedura (rootfs, kernel):
    
    rpl@ubik:~/Works/fon2200$ sudo ./ap51-flash-fonera-1.0-38 eth0 \
     openwrt-atheros-2.6-root.jffs2-64k openwrt-atheros-2.6-vmlinux.lzma
    Reading rootfs file openwrt-atheros-2.6-root.jffs2-64k with 1835008 bytes...
    Reading kernel file openwrt-atheros-2.6-vmlinux.lzma with 786432 bytes...
    rootfs(0x006e0000) + kernel(0x000c0000) + nvram(0x00000000) sums up to 0x007a0000 bytes
    Non arp received. Make sure, the device is connected directly!
    Peer MAC: 00:18:84:81:5d:9c
    Peer IP : 192.168.1.1
    Your MAC: 00:ba:be:ca:ff:ee
    Your IP : 192.168.1.0
    Setting IP address...
    Loading rootfs...
    Sending rootfs, 3584 blocks...
    Initializing partitions...
    Rootfs partition size now 0x006f0000
    Flashing rootfs...
    Loading kernel...
    Sending kernel, 1536 blocks...
    Flashing kernel...
    Setting boot_script_data...
    Done. Restarting device...
    
    Miiiii che noia fa praticamente tutto lui :-(

    Vi toglie tutta l'emozione e il divertimento... come vedere un film conoscendone già il finale :-(((

    tra l'altro la seconda revisione della fonera (FON2200) ha già redboot attivo e quindi non è nemmeno necessario utilizzare hack per aprire ssh, cambiare kernel etc. etc. :-'(

    Se è la vostra "prima volta" vi consiglio caldamente la procedura manuale (http://wiki.ninux.org/LaFoneraDallaScatolaAOpenWrt), molto più divertente :-D

    beh... cosa vedo li sulla porta 80? webif installato di default... diamogli un occhiata, mai provato prima...
    ...
    http://192.168.1.1/
    ...
    Network
    ...
    Host
    ... SBAM
    
    /bin/sh: nvram: not found
    /bin/sh: nvram: not found
    /bin/sh: nvram: not found
    /bin/sh: nvram: not found
    /bin/sh: nvram: not found
    /bin/sh: nvram: not found
    /bin/sh: nvram: not found
    /bin/sh: nvram: not found
    /bin/sh: nvram: not found
    /bin/sh: nvram: not found
    Content-Type: text/html; charset=UTF-8
    Pragma: no-cache
    
    ...
    
    <div class="warning">WARNING: This page has not been updated or
    checked for correct functionality under Kamikaze.</div>
    ...
    
    Miiii... funziona bene ;-)
    al secondo menù ho già beccato una pagina non funzionante?

    aggiorniamo? aggiorniamo!
    magari prima dovremmo correggere i repository?!?!??!
    st'immagine fa proprio... beh il "bello" degli snapshot è l'emozione ;-)
    
    #src snapshots http://downloads.openwrt.org/snapshots/atheros-2.6/packages
    src snapshots src snapshots http://ipkg.k1k2.de/packages/
    src packages http://downloads.openwrt.org/kamikaze/packages/mips
    dest root /
    dest ram /tmp
    src X-Wrt http://downloads.x-wrt.org/xwrt/kamikaze/snapshots/atheros-2.6/packages
    
    ORA aggiorniamo:
    
    root@OpenWrt:/etc# ipkg update
    Downloading http://ipkg.k1k2.de/packages//Packages
    Updated list of available packages in /usr/lib/ipkg/lists/snapshots
    Downloading http://downloads.openwrt.org/kamikaze/packages/mips/Packages
    Updated list of available packages in /usr/lib/ipkg/lists/packages
    Downloading http://downloads.x-wrt.org/xwrt/kamikaze/snapshots/atheros-2.6/packages/Packages
    Updated list of available packages in /usr/lib/ipkg/lists/X-Wrt
    Done.
    root@OpenWrt:/etc# ipkg upgrade
    Upgrading busybox on root from 1.4.2-3 to 1.8.2-1...
    Downloading http://downloads.x-wrt.org/xwrt/kamikaze/snapshots/atheros-2.6/packages/./busybox_1.8.2-1_mips.ipk
    ipkg: fork failed: Cannot allocate memory
    
    scusa scusa... faccio fuori qualcosa?... httpd?
    
    root@OpenWrt:/etc# /etc/init.d/httpd stop
    Terminated 
    insisti insisti che alla fine ce la farà...
    
    root@OpenWrt:/etc# ipkg upgrade
    ....
    root@OpenWrt:/etc# ipkg upgrade
    ....
    root@OpenWrt:/etc# ipkg upgrade webif
    
    
    ohhh.... facciamo ripartire httpd:
    
    root@OpenWrt:/etc# /etc/init.d/httpd start
    /etc/rc.common: eval: line 1: uci_set_default: not found
    
    ti piacerebbe!!!
    googla di qua e googla di la mi sa che il nuovo webif fa uso di funzionalità inserite nei nuovi uci e base-files (https://dev.openwrt.org/changeset/10086)...

    Aggiorniamo?.... beh...
    
    root@OpenWrt:~# ipkg upgrade uci
    Installing uci (0.3.0-1) to root...
    Downloading http://downloads.x-wrt.org/xwrt/kamikaze/snapshots/atheros-2.6/packages/./uci_0.3.0-1_mips.ipk
    Installing libuci (0.3.0-1) to root...
    Downloading http://downloads.x-wrt.org/xwrt/kamikaze/snapshots/atheros-2.6/packages/./libuci_0.3.0-1_mips.ipk
    Configuring libuci
    Done.
    Collected errors:
    Package uci wants to install file /lib/config/uci.sh
           But that file is already provided by package base-files-atheros-2.6
    
    prego prego sovrascrivi:
    
    root@OpenWrt:~# ipkg upgrade uci -force-overwrite 
    Installing uci (0.3.0-1) to root...
    Downloading http://downloads.x-wrt.org/xwrt/kamikaze/snapshots/atheros-2.6/packages/./uci_0.3.0-1_mips.ipk
    Configuring uci
    Done.
    root@OpenWrt:~#
    
    e ora il passo delicato (della serie "attento a cosa sovrascrivi e fare un diff non fa mai male"):
    
    root@OpenWrt:~# ipkg install base-files-atheros -force-overwrite
    ....
       Configuration file '/etc/passwd'
       ==> File on system created by you or by a script.
       ==> File also in package provided by package maintainer.
          What would you like to do about it ?  Your options are:
           Y or I  : install the package maintainer's version
           N or O  : keep your currently-installed version
             D     : show the differences between the versions (if diff is installed)
        The default action is to keep your current version.
       *** passwd (Y/I/N/O/D) [default=N] ?n
    
    
    ed ora?
    
    root@OpenWrt:~# /etc/init.d/httpd start
    root@OpenWrt:~# 
    
    ohhhh... riproviamo:
    ...
    http://192.168.1.1/
    ...
    Network
    ...
    Host
    ...
    NOW IT'S WORK ;-)

    ISO e OOXML

    Pare che l'OOXML abbia ottenuto i voti necessari alla sua approvazione come standard: Il formato OOXML, proposto da microsoft, (ISO/IEC 29500) is a standard for word-processing documents, presentations and spreadsheets that is intended to be implemented by multiple applications on multiple platforms...

    e l'Open Document Format (standardizzato proprio dall'ISO nel 2006) cos'era?

    Caliamo un velo pietoso :-(

    Prim, AIR e Silverlight: 3 visioni dell'integrazione del web con il desktop

    Unlike Adobe AIR and Microsoft Silverlight, we’re not building a 
    proprietary platform to replace the web. We think the web is a 
    powerful and open platform for this sort of innovation, so our 
    goal is to identify and facilitate the development of enhancements 
    that bring the advantages of desktop apps to the web platform.
    ...
    MS says "Write a web application using Silverlight and you can get 
    desktop integration". 
    Adobe says "Write a web application using AIR and you can get desktop 
    integration". 
    Mozilla says "write a website *without* doing anything special, and 
    *we* will take care of desktop integration".
    
    Come ho accennato anche io in qualche passato post, si sta preparando un nuovo profondo cambiamento dei nostri sistemi desktop:
         il web che si fonde con il desktop
    

    Davanti a noi si presentano al momento 3 visioni (e relative possibilità):
    • in una il nostro desktop e il web si riempiono di file .exe e .dll e relativa sbrillucicosa tecnologia proprietaria (.NET)
    • in un'altra il nostro desktop si riempie di file .swf (il web purtroppo ne è già pieno :-P) e relativa sbrilluccicosa tecnologia proprietaria (AIR, Flex e compagnia bella)
    • nell'ultima (che poi era la prima ;-)) il nostro totalmente non standardizzato desktop verrà in contatto con quelli che sono gli standard aperti della rete (W3C, ECMAScript etc.)

    Ora... a noi la scelta! :-D

    Links

    GoogleGears: select * from javascript

    Google Gears (come molti sapranno) è uno dei software rilasciati da Google, in particolare sotto licenza BSD... ma che cos'è?

    La maggiore complessità dei compiti demandati al lato client delle applicazioni web con l'avvento di AJAX (sempre più simili a vere e proprie applicazioni desktop) oramai fa sentire l'esigenza di uno storage per i dati degno di questo nome.

    E ovviamente per "storage degno di questo nome" intendiamo quello che inizia per S e finisce per QL :-)

    Google non è la sola ad aver portato SQL su un web client (o più semplicemente browser), anche Mozilla e Adobe hanno fatto altrettanto: A voler essere proprio pignoli Firefox ha un SQL Engine accessibile al "codice Javascript privilegiato" già dalla versione 2 ;-)

    Da notare comunque che in tutti e tre i casi l'engine non è altro che SQLite... ovviamente... perchè reinventare qualcosa che c'e' già ?!?!

    La cosa interessante di Google Gears è che viene distribuito come plugin per il vostro normale browser (Firefox e IE al momento) e porta quindi SQL sulle normali applicazioni Web (cioe' non codice privilegiato come nel caso di Mozilla e AIR), oltre ad altri interessanti possibilità: caching offline delle risorse web e un working pool per le sincronizzazioni dati.
    
    <script type="text/javascript" src="gears_init.js"></script>
    <script type="text/javascript">
    var db = google.gears.factory.create('beta.database');
    db.open('database-test');
    db.execute('create table if not exists "YourFirstTable" ("id" integer not null primary key, "info" text)');
    var rs = db.execute('selet * from sqlite_master');
    
    while (rs.isValidRow()) {
    alert(rs.field(0) + ' - ' + rs.field(1));
    rs.next();
    }
    rs.close();
    </script>
    
    And now "select * from javascript"

    Link utili

    Javascript Array Iteration... la tentazione del for... in...

    la tentazione è forte...
    
    my_array = [2,3,4];
    
    for (var i in my_array) {
    print(i);
    }
    
    purtroppo... non avevate considerato questo... ;-)
    
    >>> Array.prototype.remove = function (B) {
     var A = this.indexOf(B);
     if (A != -1) {
         this.splice(A, 1);
     }
     return this;
    }
    >>> my_array.remove
    function()
    >>> for (var i in my_array) { console.log(i) }
    0
    1
    2
    remove
    
    dopo aver aggiunto un metodo al prototype di Array ce lo ritroveremo in tutte le istanze di Array:
    DOH!!!!
    ehhhh! non vi lamentate troppo pero'... il manuale parlava chiaro ;-)
    
    (From "Core JavaScript 1.5 Reference:Statements:for...in")
    Although it may be tempting to use this as a way to iterate over an Array,
    this is a bad idea.
    The for...in statement iterates over user-defined properties in addition
    to the array elements, so if you modify the array's non-integer or non-positive
    properties (e.g. by adding a "foo" property to it or even by adding a method or
    property to Array.prototype), the for...in statement will return the name of
    your user-defined properties in addition to the numeric indexes.
    Also, because order of iteration is arbitrary, iterating over an array may not
    visit elements in numeric order.
    Thus it is better to use a traditional for loop with a numeric index when
    iterating over arrays.
    
    Quindi scartate for e for each come metodi di iterazioni sugli Array Javascript... toglietevelo dalla testa ;-) (sono più utili per fare reflection sugli oggetti... Array compresi).
    Il modo corretto di iterare un array sino a Javascript 1.6 era il ciclo for con indice numerico (alla plain C maniera) mentre ora è possibile usare il metodo forEach:
    
    >>> my_array.forEach(function(e) { console.log(e); });
    2
    3
    4
    >>> Array.forEach(my_array,function(e) { console.log(e); });
    2
    3
    4
    
    Ma attenzione a quello che scrivete nella closure che passate a forEach:
    
    >>> obj = { itera: function(a) { console.log(this); a.forEach(function(e) { console.log(this); }) } }
    Object
    >>> obj.itera([1,2,3]);
    Object
    Window
    Window
    Window
    
    come è possibile verificare nel proprio Firebug this fuori dalla closure punta all'Object obj, mentre il this nella closure punta a Window (il contesto globale). Un'ulteriore conferma di questo comportamento possiamo ottenerla con uno spidermonkey in linea di comando:
    
    rpl@ubik:~$ js
    js> obj = { itera: function(a) { print(this); a.forEach(function(e) { print(this); }) } }
    [object Object]
    js> obj.itera([1,2,3])
    [object Object]
    [object global]
    [object global]
    [object global]
    
    Questo comportamento è un po' spiazzante (con un for o un for each non avremmo avuto un cambio di contesto del genere). Personalmente risolvevo definendo come workaround una variabile self raggiungibile dalla closure per ricordare il contesto da cui ho avviato il forEach:
    
    >>> obj = {
     prova: function(a) {
       var self = this;
       console.log(this);
       a.forEach(function(e) { console.log(self); })
     }
    }
    Object
    >>> obj.prova([1,2,3])
    Object
    Object
    Object
    Object
    
    Ma ancora una volta facendo riferimento al manuale (RTFM RTFM RTFM RTFM!!!): si può verificare che forEach accetta un secondo parametro allo scopo di selezionare il contesto (this) nel quale la closure sarà eseguita, che se non definito o nullo sarà associato al contesto globale (come verificato con gli snippet precedenti). Detto in codice diventa:
    
    >>> obj = {
      itera: function(a) {
          console.log(this);
          a.forEach(function(e) { console.log(this); },this)
      }
    }
    Object
    >>> obj.itera([1,2,3])
    Object
    Object
    Object
    Object
    
    Quindi la Soluzione (quella con la S maiuscola) è quella di passare this come secondo parametro della forEach.
    Quante cose si imparano leggendo un manuale, no? ;-)

    Javascript Code Coverage

    Sentivo la mancanza di qualcosa... ma non riuscivo ad identificare cosa...
         il code coverage
    
    con ruby sfruttavo rcov per capire di tutto il codice scritto quale è in uso e quale no, utile nel refactoring per fare fuori il codice inutile (o quanto meno evitare di riscriverlo) e nel testing per capire quanto del codice i test ricoprono già. Da rapida google-ata sono emerse alcune soluzioni: non le ho ancora provare, ma sapere che esistono soluzioni del genere è già qualcosa ;-)
    P.S. il codice coverage non è mai sicuro al 100% (nel senso che non da una misura completamente affidabile su quanto è completo il testing), ma è utile per coadiuvare il lavoro "umano" necessario.

    Javascript Object Composition

    Nella programmazione ad oggetti spesso si sente l'esigenza di comporre gli oggetti anziche creare complesse gerarchie di codice e per questo sono state introdotte tutta usa serie di tecniche oltre a nuove caratteristiche dei linguaggi stessi. Ad esempio se avessi voluto"Mescolare" del codice in Ruby per ottenere un nuovo oggetto con le caratteristiche risultati (e senza dover usare un foglio A3 per disegnarne l'albero genealogico ;-)) avrei avuto a mia disposizione i Mixin, qualcosa del tipo:
    
    module InutilityModule
    def important_method
      @obj_var = 5
    end
    end
    
    class TClass
    include InutilityModule
    
    def initialize
      @obj_var2 = 2
    end
    
    def add
       return @obj_var2+@obj_var
    end
    end
    
    Le istanze della classe TClass avranno il metodo important_method oltre ai propri. In JavaScript le cose vanno un po' diversamente in quanto non ci sono classi ma oggetti prototipo, e inoltre gli oggetti altro non sono se non Hash tables. Se vogliamo aggiungere un metodo ad un oggetto JavaScript ci basta definirne la nuova proprietà:
    
    var myobj = {
    method1: function() {
      this._var1 = 5;
    }
    };
    
    myobj.method2 = function() {
    this._var2 = 3;
    }
    
    myobj["method3"] = function() {
    alert(this._var1+this._var2);
    }
    
    alle volte pero' mi e' capitato di doverne aggiungere un gruppo e quindi per pulizia ciclo su tutti gli attributi dell'oggetto sorgente:
    
    var codetomix = {
    method2: function() {
      alert("method2");
    },
    
    method3: function() {
      alert("method3");
    }
    }
    
    for (var property_name in codetomix) {
    myobj[property_name] = codetomix[property_name];
    }
    
    volendo (come fanno molti framework javascript) si puo' incapsulare la funzionalita' in una funzione di comodo:
    
    function apply(src, dst) {
    for (var prop in src) {
      dst[prop] = src[prop];
    }
    }
    
    apply(codetomix,myobj);
    
    chiaramente questa versione di "apply" è moooolto minimale ma nella sua minimalita' puo' essere molto utile quando non si vuole ricorrere all'implementazione di un particolare framework (che introduce in genere una maggiore complessita' avendo come obiettivo quello di realizzare l'ereditarietà alla maniera classica) IMHO la cosa simpatica di snippet come questo è che rendono evidente la propensione a scheme del design di JavaScript ;-)

    si ma... il backtrace?

    Oggi come al solito iteravo tra lo scrivere il codice e lo scrivere gli spec test Javascript (con il test framework accennato precedentemente) e ad un certo punto un test fallisce... DOH! ...il che è normale mentre stai facendo refactoring o stai aggiungendo feature, ma questa volta il problema si trovava in una callback javascript che veniva richiamata in molti punti (e ricorsivamente tra l'altro). Dato che il suddetto test framework (JSSpec) esegue il catch delle eccezioni, per mostrarne un breve log nel report html che genera, in FireBug l'eccezione non arriva proprio e non è in grado di mostrarmi il backtrace (per capire "chi chiama chi e passandogli quali parametri" ;-) ) Ora... daccordo (con me stesso :-P) che la cosa dovrebbe essere risolta nel sorgente di JSSpec, avevo comunque bisogno di poter vedere quel backtrace... e lo volevo vedere SUBITO! Dal sito di documentazione per gli sviluppatori del progetto mozilla è possibile verificare che Mozilla aggiunge un attributo fuori standard all'oggetto globale Error che ritorna il backtrace di dell'eccezione "catch-ata". Quindi in codice:
    
    try {
    // il vostro pericolosissimo codice
    }
    catch (e) {
    console.log(e)
    console.log(e.backtrace)
    [...]
    }
    
    Il risultato visibile nella console di FireBug: non è il massimo... ma per ora può bastare ;-) Grazie Mozilla Developer Network :-D

    [Spec] Testing Your Code

    Un anno fa circa ho cambiato il mio approccio al testing del codice passando dal classico Unit Testing allo Spec Testing (e di fatto puntanto alla metodologia BDD anzichè TDD). Inizialmente ho introdotto lo spec testing nello sviluppo di applicazioni ruby/ruby on rails attraverso RSpec. RSpec è un framework di testing BDD implementato attraverso la definizione di un DSL interno per Ruby, consentendomi di scrivere gli spec-test in una sorta di pseudolinguaggio molto gradevole e leggibile:
    
    # mycode_spec.rb
    require 'mycode'
    
    describe MyCode do
    before(:each) do
    @myvar = MyCode.new
    end
    
    it "should work as i want ;-)" do
    ret = @myvar.set_something(45)
    ret.should == true
    end
    end
    
    Oltre ad essere molto gradevole la sintassi del codice, lo è ancora di più il report html che puo' essere generato a valle dell'esecuzione dei test. Ma dato che ora come ora sono intento a scrivere per lo più Javascript sentivo l'esigenza di avere qualcosa di analogo... non sto tranquillo se non ho i test a supporto... durante i refactoring mi tremano le mani ;-) Beh... non ho dovuto cercare molto: c'è JSSpec! La sintassi è molto simile a quella di RSpec, ed è altrettando gradevole ed autoesplicativa:
    
    describe('XPath helpers (snapshot, iter, any)', {
    'before_all': function() {
     // get test xml data
     xhr = new XMLHttpRequest();
     xhr.open("GET","data/test.xml",false);
     xhr.send(null);
    
     // init testing data objects
     xml_dom_obj = xhr.responseXML;
    },
    
    'should create a snapshot from an xpath expression and a dom node': function() {
     var xp_res = $XP_snap(xml_dom_obj, "//*");
     value_of(xp_res.resultType).should_be(XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
     value_of().should_fail("TODO: CHECK RESULT CONTENT");
    },
    
    'should create an interator for the xpath expression and a dom node': function() {
     var xp_res = $XP_iter(xml_dom_obj, "//*");
     value_of(xp_res.resultType).should_be(XPathResult.ORDERED_NODE_ITERATOR_TYPE);
     value_of().should_fail("TODO: CHECK RESULT CONTENT");
    },
    })
    
    Tra l'altro lo sviluppatore è un coreano molto molto cordiale (e sicuramente molto geek ;-): gli ho inviato una patch di poche righe per visualizzare il codice dei test eseguiti nei div html dei singoli test, che ho inserito nella mia copia di JSSpec per aiutarmi nel debugging dei test che falliscono e per valutare la sintassi dell'API dai test che scrivo, e l'ha integrata dopo due giorni nel trunk e dopo avermi inviato una mail di ringraziamento e un per avvisarmi dell'integrazione :-DDD Ed erano solo 2 righe ;-) Chissa se scrivessi una "intera funzione"! magari mi manda un thé coreano :-PPPPP Sono un fanatico del thé... quasi quasi gli propongo il baratto :-D Comunque a conferma (a volte cerco conferme di questo tipo ;-)) che non sono pazzo con il mio flash sui test ecco il post di un altro personaggio che ha fatto più o meno il mio stesso percorso e offre anche qualche altro spunto interessante (lo spec-testing javascript browser-less): Happy Hacking

    Live in the Shell #1: ripetere un comando su una lista di file

    Spesso mi è capitato durante la normale manutenzione della mia home, delle directory di building o durante interventi sistemistici vari, di dover ripetere un task su una lista di file. Di solito utilizzo spontaneamente l'approccio da coder:
    
    rpl@ubik:~$  LIST=`find -iname "*~"`
    rpl@ubik:~$  for i in $LIST; echo $i; done
    [...]
    
    
    Il che non è sbagliato... funziona... Ma il bello del lavorare in team è lo scambio di abitudini e conoscenze continuo e naturale, e oggi Domenico M. mi ha fatto notare che c'e' un modo più compatto e sistemistico per svolgere lo stessa operazione:
    
    rpl@ubik:~$  find -iname "*~" -exec echo '{}' \;
    
    
    Ma il bello è che ce ne sarebbe ancora un'altra (e chissa quante altre):
    
    rpl@ubik:~$ find -iname "*~" | xargs echo
    
    
    e allora quale usare? beh... de gustibus. Il primo metodo è un for vero e proprio e si puo' utilizzare in generale con ogni stringa che contenga un elenco di elementi separati da spazi, gli altri sono sicuramente più manegevoli quando la lista andrebbe comunque generata con un find ;-)

    GML: Sostituzione di una variabile GData nell'attibuto di un tag xml

    Quest'oggi ho provato per la prima volta Blogger.com e ho potuto giocare con il sistema di template di google. Ad un certo punto mi sono chiesto... ma per sostituire una variabile GData in un attributo? Eccovi la risposta

    Web Aided Web Design

    Dovendo manipolare immagini, scegliere colori e generare blocchi dai bordi arrotondati, puo' essere utile trovare una mano sul web stesso:
    • http://www.picnik.com/
    • http://kuler.adobe.com/
    • http://web2.0stores.com/blog/archives/googles-rounded-corner-generator/
    • http://www.cssjuice.com/25-rounded-corners-techniques-with-css/
    • http://www.roundedcornr.com/beta/
    • http://www.getroundedbox.com/
    • http://tools.sitepoint.com/spanky/index.php
    View Luca Greco"s profile on LinkedIn

    Rpl

    La mia foto
    Lecce, Italy
    Fulltime Coder and *nix BOFH