La premessa era promettente: tecnici, dottori di
ricerca, portavoce delle telco e politici che parlano di internet, della sua
liberta' innata, e di come conciliarla in una societa' dove le misure di
sicurezza aumentano costantemente, e
come tali contrastano con un mondo virtuale senza barriere di sorta. Inoltre,
e' un'arena virtuale in cui tutto puo' essere gratuito, non solo le informazioni, e le persone ci
si stanno abituando.
Il primo intervento e' stato tenuto dal prof. Kenneth Carter, direttamente dalla
Columbia University, e ha fatto da ampia introduzione alle tematiche esplorate
(e talvolta ripetute) durante la giornata. In breve, la grande domanda e': gli
ISP possono offrire diversi gradi di performance su diversi siti (o far pagare
per performance migliori), permettere/bloccare/sovraccaricare l'accesso a certi
siti o da certi dispositivi?
Filtrare l'accesso ai servizi di rete e' una pratica comune su internet,
come lo e' filtrare i contenuti, e non necessariamente cattiva: pensate ai
filtri antispam per prevenire UCE e ai filtri dei
NAP per prevenire e mitigare attacchi DDOS, o ai sistemi antivirus/IDS. Anche i piani di
servizio differenziati, dove ottieni latenza piu' bassa o maggiore banda in
upload pagando di piu', sono accettabili, perche' la “qualita' del
servizio” non e' un valore assoluto: dipende dal tipo di servizi che
l'utente usa. E nella maggior parte dei casi, l'utente non coglie (e nemmeno
ha bisogno di cogliere) i concetti che ci stanno dietro.
Questo e' il mio resoconto del primo facebook developer garage
italiano, tenutosi a Milano il 23 aprile 2009,
e ospitato da mikamai. La mattina e' stata
dedicata alle sessioni per sviluppatori, il pomeriggio a quelle di marketing
& comunicazione. Alcuni video dell'evento sono disponibili qui.
Piu' tardi ho avuto occasione di chiedere a James se
FB fosse incline o meno ad adottare OpenID
come metodo di autenticazione: ha detto che connect e OpenID permettono
entrambi agli utenti di avere credenziali di login uniche per accedere a piu'
siti, ma connect permette anche di sfruttare la potenza del social graph di
Facebook per consentire agli utenti di comunicare e condividere informazioni.
Quindi, la risposta breve e' “no”. Allora gli ho proposto di
implementare OpenID su FB stesso, cosi' che connect potesse diventare davvero
un superset di OpenID, ma ha risposto che “come azienda, queste sono
decisioni difficili e non posso dare una risposta adesso”. Comprensibile
:).
AGGIORNAMENTO: il 27
aprile 2009, TechCrunch riporta di aver sentito che Facebook abbraccera'
OpenID come mezzo per autenticare gli utenti. Ottime notizie, in attesa di
una dichiarazione ufficiale da Facebook! :)
Il secondo talk e' stato tenuto da Vincenzo
Acinapura, che ha descritto gli strumenti di base per creare
un'applicazione sulla piattaforma Facebook. Ha esplorato le tecnologie che ci
stanno dietro (XFBML, FQL, FBJS), i principali punti
di integrazione all'interno della piattaforma (notifiche, publisher, ...) e
ha mostrato codice d'esempio per implementare alcuni dei tag FBML piu' usati (fb:comments,
fb:share, fb:feed, e cosi' via).
Infine ha ricordato l'importanza di automatizzare il deploy delle applicazioni,
e ha suggerito di usare capistrano per
farlo.
Sto cercando un nuovo animale domestico. Noi abbiamo
gia’ due gatti adorabili, ma dopo aver sentito
quanto puo’ essere viva una casa con tanti animali (dopo una bella serata al
maniero de il
quadrato),
sto pensando di prenderne un altro da crescere e amare.
Ma che razza di geek sarei, se non ci aggiungessi un tocco nerd? Quindi, dopo
l’interfaccia cervello-twitter di
cui si e’ parlato
tantonegli
ultimi
giorni,
stasera un pensiero abbastanza casuale e divertente mi e’ balenato in testa:
che ne dite di prendere un pappagallo
cenerino, crescerlo,
insegnargli a parlare, e lasciarlo… be’, twittare le sue parole usando un
sistema di riconoscimento vocale piazzato accanto alla sua gabbia e collegato a
un account twitter? Quanto sarebbe assurdo? :D
A pensarci bene, la cosa piu’ strana e’ che nel 2009, un pappagallo che twitta
mi fa pensare a un “pappagallo con accesso a twitter”… e non a un uccello
che emette il suo verso naturale. Sono troppo sovraccaricato da questa storia
dei social media? Dovrei prendermi una vacanza?
Subject: Notice to all employees
Date: Tue, 24 Feb 2009 13:06:14 -0500
Dear employees,
Due to the current financial situation caused by the slowdown
of the economy, Management has decided to implement a scheme
to put workers of 40 years of age and above on early retirement.
This scheme will be known as RAPE (Retire Aged People Early).
Persons selected to be RAPED can apply to management to be eligible
for the SHAFT scheme (Special Help After Forced Termination).
Persons who have been RAPED and SHAFTED will be reviewed under the
SCREW programme (Scheme Covering Retired Early Workers). A person
may be RAPED once, SHAFTED twice and SCREWED as many times as
Management deems appropriate.
Persons who have been RAPED can only get AIDS (Additional Income
for Dependents & Spouse) or HERPES (Half Earnings for Retired
Personnel Early Severance).
Obviously, persons who have AIDS or HERPES will not be SHAFTED or
SCREWED any further by Management.
Persons who are not RAPED and are staying on will receive as much
SHIT (Special High-Intensity Training) as possible. Management
has always prided itself on the amount of SHIT it gives employees.
Sincerely,
The Management
(Spero vi siate divertiti :D C’e’ anche una versione USAF del 1997).
Su VisitaCSA stiamo usando
facebox di
defunkt per mostrare le immagini dei
luoghi in grande.
Facebox e’ un ottimo lightbox generico, perche’ e’ veloce, stabile, si basa su
jQuery e ha un’API davvero pulita.
Ma avevamo bisogno di qualcosa in piu’ di un semplice lightbox di
visualizzazione, perche’ volevamo che i nostri utenti potessero navigare
facilmente tra tutte le immagini, possibilmente senza modificare facebox. La
soluzione si e’ rivelata piuttosto semplice, grazie anche al plugin
will_paginate che stavamo
gia’ usando. In sostanza si tratta di avere:
Un model Photo, attrezzato con il metodo has_attachment
Route per le risorse photos (map.resources :photos, :only => :show in
config/routes.rb)
Un metodo show nel controller PhotosController che chiama .paginate
con un argomento :per_page di 1
Una vista HTML per la risorsa photo, con i controlli di paginazione usando
l’helper will_paginate
Del codice jQuery che si aggancia ai link di paginazione e fa caricare al
browser via AJAX la foto successiva direttamente nel facebox.
Ecco il codice rilevante, semplificato rispetto a quello effettivamente
online, perche’ il model photo e’ in realta’ polimorfico (usa STI) e diverse
collezioni sono gestite dal photos controller (foto, volantini, ecc.) per
diversi model, con miniature diverse :P.
Model [app/models/photo.rb]
classPhoto<ActiveRecord::Base has_attachment :storage=>:file_system, :path_prefix=>'public/photos',
:processor=>'ImageScience', :thumbs=> { :thumb=>'600x800' }
end
Per me sembra una melodia contorta, o una poesia complicata. E’ ingegneria
malvagia, lo so. Ma mentre lo scrivevo, provavo esattamente la stessa
sensazione di quando scrivevo versi in rima. Le parole di
_why sono assolutamente pertinenti qui:
finche’ i programmatori non smetteranno di comportarsi come se l’offuscamento
fosse moralmente pericoloso, non saranno artisti, solo ragazzini che non
vogliono che il loro cibo si tocchi.
Puoi vedere il codice con l’evidenziazione della sintassi su
github, oppure con la funzione “Visualizza
sorgente” del tuo browser mentre sei sul sito
segfault. :)
Attualmente mantengo il mirror italiano del
sito web della Open Source Initiative, e oggi mi sono
reso conto che lo script che avevo scritto qualche mese fa non stava facendo
bene il suo lavoro… perche’ i file CSS non venivano scaricati affatto,
causando un rendering del sito piuttosto sgradevole.
Per fare il mirror di opensource.org sto usando il caro vecchio GNU
Wget con -r –mirror e compagnia bella.
Mentre il buon vecchio wget scarica tutti i prerequisiti di ogni pagina
definiti nel sorgente HTML, non supporta le regole CSS @import e non scarica le
immagini referenziate nei CSS con le regole url().
Comunque, niente che non si possa risolvere con un po’ di regex-fu: ecco
perche’ condivido lo script che sto usando
attualmente per fare il mirror del sito opensource.org, sperando che generi un
nuovo mirror o qualche spunto su come fare meglio questo lavoro :).
Un altro spin-off dal sito www.visitacsa.it: un
miglioramento a
permalink_fu che
permette permalink dinamici. Lo so che è un
ossimoro, perché i permalink dovrebbero
essere… beh… permanenti! E siccome i motori di
ricerca li indicizzano, non dovrebbero
mai cambiare. Ma cosa succede quando pubblichi qualcosa, il tuo permalink
viene generato con permalink_fu usando il titolo del tuo post, e dopo un
paio di giorni vuoi cambiare il titolo, e anche il permalink sotto il quale il
post è accessibile?
Seguendo la
specifica, la tua
applicazione dovrebbe inviare uno status HTTP 301 moved permanently quando si
accede al vecchio permalink e fare redirect del client verso il nuovo Uniform
Resource Locator. Questo è più o meno quello che fa la mia modifica a
permalink_fu: ogni volta che gli attributi del tuo post vengono modificati, il
permalink precedente e quello nuovo vengono salvati nel database, e puoi
abilitare il tuo controller a generare redirect 302 moved temporarily quando
necessario. In altre parole, controlla se l’URL richiesto è un vecchio
permalink e reindirizza automagicamente il client verso quello nuovo.
Tutto avviene dietro le quinte, e il plugin ha anche dei comodi task rake per
impostare il model Redirect e le migration associate. E puoi anche cambiarne
il nome, ovviamente! :)
Di recente ho scritto un plug-in jQuery che
permette l’upload di file via AJAX senza usare un pulsante file input
fisso. Raggiunge il suo scopo installando un handler OnMouseMove sugli elementi
selezionati e spostando il pulsante input sotto il cursore del mouse.
La citazione che ha ispirato questo codice e’: “Se Maometto non va alla
montagna, la montagna va da Maometto”, il contrario del proverbio piu'
noto :).
// ~ JavaScript Kung-FU, with an excess chunky bacon dose! ~
// This plugin allows seamless ajax file uploads without having
// a fixed file input button. It achieves this by installing an
// OnMouseMove handler over the interested elements, and moving
// the input button under the cursor. <<If Muhammad won't go to
// the the mountain, the mountain will come to Muhammad.>> :-).
//
// This approach is needed on the majority of browser, except
// Safari, on which the coder is allowed to trigger a "click"
// event onto an input type=file element. On other browsers,
// you can not, that's why the complicated mousemove approach
// was chosen.
//
// Either way, when the value of the input type=file changes,
// handlers are disabled, and a user-provided callback is then
// called (passed via the "upload" option). Handlers are then
// re-enabled again when the upload succeeds or fails.
//
// IE has additional problems, because, quite unexplicably,
// when submitting a form that causes a page load, the change
// event on the file input is triggered AGAIN, thus triggering
// a new file upload. To circumvent this, you can pass a "linked"
// option, that contains the jQuery selector of the form, and
// whenever an input under this form is hovered, ajax upload
// handlers are temporarily cleared and thus the spurious form
// submission.
//
// The jquery Form plugin is a perfect companion of this one,
// because of its .ajaxSubmit method. Have a look at its home
// page: http://malsup.com/jquery/form/.
//
// Have fun!
// - vjt@openssl.it
//
$.fn.ajaxFormUpload=function(options) {
varpositioning= { top:0, left:0,
position:'absolute', cursor:'pointer', 'z-index':2 };
varform=$(options.form||'#ajax_upload');
form.css(positioning)
varinput=form.find('input[type=file]');
input.css($.extend(positioning, { width:'10px', opacity:0, 'font-size':'0px' }));
varhovering_element=null;
varelements=$(this);
varhandler, event_;
if ($.browser.safari) {
event_='click', handler=function() {
hovering_element=$(this);
input.click();
};
} else {
event_='mousemove', handler=function(event) {
hovering_element=$(this);
form.css({ left:event.pageX-10, top:event.pageY-5 });
};
}
functionenable() { $(elements).bind(event_, handler); }
functiondisable() { $(elements).unbind(event_, handler); }
input.change(function() {
varelement=hovering_element;
if (!element) return;
disable();
options.upload(element, form);
enable();
});
enable();
if (options.linked) {
$(document).ready(function() {
$(options.linked).find('input').mouseover(function() { hovering_element=null; });
});
}
};