<?xml version="1.0" encoding="utf-8" ?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:syn="http://purl.org/rss/1.0/modules/syndication/" xmlns="http://purl.org/rss/1.0/">




    



<channel rdf:about="http://blog.redturtle.it/aspetti-tecnici/RSS">
  <title>Aspetti tecnici</title>
  <link>http://blog.redturtle.it</link>

  <description>
    
      
    
  </description>

  

  
            <syn:updatePeriod>daily</syn:updatePeriod>
            <syn:updateFrequency>1</syn:updateFrequency>
            <syn:updateBase>2012-05-08T16:02:35Z</syn:updateBase>
        

  

  <image rdf:resource="http://blog.redturtle.it/logo.png"/>

  <items>
    <rdf:Seq>
      
        <rdf:li rdf:resource="http://blog.redturtle.it/webhelpers-piccoli-aiuti-web-migliore"/>
      
      
        <rdf:li rdf:resource="http://blog.redturtle.it/web-apps-debug-remoto-android-chrome-devtools"/>
      
      
        <rdf:li rdf:resource="http://blog.redturtle.it/sunburst-css-dtml"/>
      
      
        <rdf:li rdf:resource="http://blog.redturtle.it/gallerie-slider-immagini-sito-web-20-esempi"/>
      
      
        <rdf:li rdf:resource="http://blog.redturtle.it/pudb-ovvero-come-ho-imparato-velocizzare-mio-debug"/>
      
      
        <rdf:li rdf:resource="http://blog.redturtle.it/funkload-simple-buildout-to-run-your-test"/>
      
      
        <rdf:li rdf:resource="http://blog.redturtle.it/rt.atmigrator-pensioniamo-vecchi-tipi-con-un-click"/>
      
      
        <rdf:li rdf:resource="http://blog.redturtle.it/quando-la-sicurezza-in-plone-e-importante-reindexobjectsecurity"/>
      
      
        <rdf:li rdf:resource="http://blog.redturtle.it/e-uscito-il-buildout-2.0-posso-rilanciare-il-mio-buildout"/>
      
      
        <rdf:li rdf:resource="http://blog.redturtle.it/creazione-plugin-gestire-gruppi-virtuali-plone"/>
      
      
        <rdf:li rdf:resource="http://blog.redturtle.it/semplici-regole-finire-casella-spam-gmail"/>
      
      
        <rdf:li rdf:resource="http://blog.redturtle.it/sviluppo-front-end-ottimizzare-prestazioni"/>
      
      
        <rdf:li rdf:resource="http://blog.redturtle.it/migrazione-plone-4-tips-and-tricks"/>
      
      
        <rdf:li rdf:resource="http://blog.redturtle.it/come-gestire-e-distribuire-i-vostri-prodotti-plone"/>
      
      
        <rdf:li rdf:resource="http://blog.redturtle.it/come-utilizzare-online-id-login-plone"/>
      
    </rdf:Seq>
  </items>

</channel>


  <item rdf:about="http://blog.redturtle.it/webhelpers-piccoli-aiuti-web-migliore">
    <title>WebHelpers, tanti piccoli aiuti per un web migliore</title>
    <link>http://blog.redturtle.it/webhelpers-piccoli-aiuti-web-migliore</link>
    <description>A volte si devono utilizzare finezze per avere un prodotto più gradevole o facilitarne lo sviluppo. Gli strumenti giusti per fare velocemente il lavoro sono fondamentali</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Lavorando a un progetto <strong><a class="external-link" href="http://www.pylonsproject.org/" target="_self" title="The Pylons Project">Pyramid</a><strong> </strong></strong>mi sono imbattuto in un pacchetto decisamente interessante: webhelpers.</p>
<a name="anchor-breaktext"></a><div class="breakText"><strong><a class="external-link" href="http://pypi.python.org/pypi/WebHelpers/1.3">Webhelpers</a> </strong> è una libreria di helper che facilita la creazione di applicazioni web; è stata sviluppata principalmente per <a class="external-link" href="http://www.pylonsproject.org/" target="_self" title="The Pylons Project"><strong>Pylons</strong></a> e <a class="external-link" href="http://turbogears.org/" target="_self" title="TurboGears2"><strong>TurboGears2</strong></a> anche se può essere usata in qualsiasi web framework <strong>python</strong>! Tutta la documentazione si trova <a class="external-link" href="http://sluggo.scrapping.cc/python/WebHelpers/" target="_self"><strong>qui</strong></a>, ma voglio illustrare alcuni degli helper che ho apprezzato di più, per mostrare quanto può essere utile una libreria come questa quando si lavora.</div>
<h2 class=" ">Lavorare con le date</h2>
<blockquote class="pullquote">Visualizzazione dei periodi di tempo in stile social!</blockquote>
<p><strong>distance_of_time_in_words </strong>è una funzione che restituisce la distanza di tempo fra due interi o due oggetti datetime in formato human readable. I parametri accettati sono <em>from_time</em>, <em>to_time</em>, <em>granularity </em>e <em>round </em>i quali permettono di ottenere velocemente stringhe come quelle nel seguente esempio:</p>
<pre><br />&gt;&gt;&gt; from webhelpers.date import *
&gt;&gt;&gt; from datetime import datetime<br />&gt;&gt;&gt;
&gt;&gt;&gt; distance_of_time_in_words(1)    
'1 second'<br />&gt;&gt;&gt;
&gt;&gt;&gt; distance_of_time_in_words(0,90)
'1 minute and 30 seconds<br />&gt;&gt;&gt;  
&gt;&gt;&gt; distance_of_time_in_words(0, 90, granularity='minute', round=True)
'1 minute'<br />&gt;&gt;&gt;
&gt;&gt;&gt; distance_of_time_in_words(0, 91, granularity='minute', round=True)
'2 minutes'<br />&gt;&gt;&gt;
&gt;&gt;&gt; distance_of_time_in_words(0,100000000000, granularity='second')
'31 centuries, 6 decades, 8 years, 10 months, 15 days, 8 hours, <br />    46 minutes and 40 seconds'<br />&gt;&gt;&gt; d1 = datetime(2013,11,04)<br />&gt;&gt;&gt; d2 = datetime(2013,2,15)
&gt;&gt;&gt; distance_of_time_in_words(d1, d2, granularity='second', round=False)
'8 months and 17 days'<br />
</pre>
<p>Per comodità è stata introdotta anche la funzione <strong>time_ago_in_words </strong>che si comporta esattamente come la precedente, ma il cui end-point è fisso a datetime.now().</p>
<h2 class=" ">Conversione del testo</h2>
<blockquote class="pullquote">Conversione da linguaggi di Markup semplici ad HTML</blockquote>
<p><strong>WebHelpers</strong> contiene degli helper per la conversione di testo. Una funzione messa a disposizione è <strong>markdown,</strong><strong> </strong>che permette di trasformare in HTML un testo scritto nell'omonimo <a class="external-link" href="http://daringfireball.net/projects/markdown/" target="_self" title="Markdown"><strong>Formato</strong></a>. Questa ci permetterà di fare cose come la seguente:</p>
<pre><br />&gt;&gt;&gt; from webhelpers.html.converters import markdown<br />&gt;&gt;&gt; text = """
... A first level header
... ====================
... 
... A second level header
... ---------------------
... 
... ###A third level header
... """
&gt;&gt;&gt; print markdown(text)<br />&lt;h1&gt;A first level header&lt;/h1&gt;<br /><br />&lt;h2&gt;A second level header&lt;/h2&gt;<br /><br />&lt;h3&gt;A third level header&lt;/h3&gt;

</pre>
<p>Dal momento che esistono diverse implementazioni di questo linguaggio di markup, la funzione accetta, oltre al testo da convertire, un parametro tramite cui si può passare il modulo con l'implementazione che si intende utilizzare; alternativamente verrà utilizzata un'implementazione fornita con webhelpers stesso.</p>
<p>Altre funzioni messe a disposizione dal modulo delle conversioni sono <strong>textilize, </strong>per la conversione in HTML di testo <strong><a class="external-link" href="http://textile.sitemonks.com/">textile</a>,</strong> <strong>format_paragraphs</strong> per la conversione in paragrafi HTML del testo passato e <strong>nl2br</strong> per inserire dei &lt;br/&gt; in corrispondenza dei "new line" nel testo.</p>
<h2 class=" ">Creare tag</h2>
<blockquote class="pullquote">Creazione di tag HTML in modo programmatico</blockquote>
<p>Il modulo tags contiene un insieme di funzioni utili alla creazione di tag HTML in modo programmatico; queste funzioni, oltre ai parametri specifici, accettano un ulteriore parametro, <i>attrs</i>, utile per specificare altri attributi HTML. Vediamone alcuni esempi (la lista completa la si può vedere nella <a class="external-link" href="http://sluggo.scrapping.cc/python/WebHelpers/modules/html/tags.html" target="_self" title="WebHelpers: tag helpers"><strong>documentazione</strong></a>):</p>
<pre><br />&gt;&gt;&gt; from webhelpers.html.tags import checkbox<br />&gt;&gt;&gt; checkbox('programming_lang', value='python', checked=True, label='Python')
literal(u'&lt;label&gt;&lt;input checked="checked" id="programming_lang" <br />       name="programming_lang" type="checkbox" value="python" /&gt;Python&lt;/label&gt;')<br />
</pre>
<p>oppure:</p>
<pre><br />&gt;&gt;&gt; from webhelpers.html.tags import link_to<br />&gt;&gt;&gt; link_to('Google', 'http://www.google.it', title="Google")
literal(u'&lt;a href="http://www.google.it" title="Google"&gt;Google&lt;/a&gt;')<br />
&gt;&gt;&gt; link_to('RedTurtle', 'mailto:info@redturtle.it', title="Mail to RedTurtle")
literal(u'&lt;a href="mailto:info@redturtle.it" title="Mail to RedTurtle"&gt;<br />         RedTurtle&lt;/a&gt;')
&gt;&gt;&gt;<br /> </pre>
<p>Oltre a tutte le funzioni utilizzate per generare tag, ce ne sono alcune più complesse che servono a elaborare i testi per inserire tag al loro interno. Avremo ad esempio <strong>auto_link</strong> che, dato un testo, converte le occorrenze riconosciute come link nel tag corrispondente:</p>
<pre><br />&gt;&gt;&gt; from webhelpers.html.tool import auto_link<br />&gt;&gt;&gt; auto_link("Visita il nostro sito: http://www.redturtle.it, <br />               il nostro blog: http://blog.redturtle.it, oppure <br />               scrivici all'indirizzo info@redturtle.it")<br /> 
literal(u'Visita il nostro sito: <i>&lt;a href="http://www.redturtle.it"&gt;<br />          http://www.redturtle.it&lt;/a&gt;</i>, il nostro blog:<br />         <i>&lt;a href="http://blog.redturtle.it"&gt;http://blog.redturtle.it&lt;/a&gt;</i>,<br />         oppure scrivici all&amp;#39;indirizzo <br />         <i>&lt;a href="mailto:info@redturtle.it"&gt;info@redturtle.it&lt;/a&gt;</i>')<br />
</pre>
<h2>Email facilities</h2>
<blockquote class="pullquote">Creare facilmente link per l'invio di mail precompilate</blockquote>
<p>Interessante è anche la possibilità di creare link predisposti per facilitare l'invio di mail, fornendo una precompilazione dei campi del client di invio:</p>
<pre><br />&gt;&gt;&gt; from webhelpers.html.tools import mail_to
&gt;&gt;&gt; mail_to('luca.bellenghi@redturtle.it',<br />...         'Scrivi a RedTurtle',<br />...         cc="info@redturtle.it",<br />...         subject="Mail di esempio",<br />...         body=u"non stampare questa mail")
literal(u'&lt;a href="mailto:info@redturtle.it?cc=info%40redturtle.it&amp;amp;subject=Mail%20di%20esempio&amp;amp;body=non%20stampare%20questa%20mail"&gt;Scrivi a RedTurtle&lt;/a&gt;')<br />
</pre>
<p>Fra l'altro, è possibile anche offuscare gli indirizzi email per rendere la vita più complicata agli spider dei motori di ricerca:</p>
<pre><br />&gt;&gt;&gt; mail_to('info@redturtle.it',<br />...         'Scrivi a RedTurtle',<br />...         cc="info@redturtle.it",<br />...         subject="Mail di esempio",<br />...         body=u"non stampare questa mail",<br />...         encode="hex")
literal(u'&lt;a href="&amp;#109;&amp;#97;&amp;#105;&amp;#108;&amp;#116;&amp;#111;&amp;#58;%69%6e%66%6f@%72%65%64%74%75%72%74%6c%65.%69%74?cc=info%40redturtle.it&amp;amp;subject=Mail%20di%20esempio&amp;amp;body=non%20stampare%20questa%20mail"&gt;Scrivi a RedTurtle&lt;/a&gt;')
&gt;&gt;&gt;<br />
</pre>
<h2>Elaborazione numerica</h2>
<blockquote class="pullquote">Formattazione ed elaborazione statistica dei numeri</blockquote>
<p>Fra le varie funzioni di elaborazione numerica, la più comoda che questo modulo mette a disposizione è quella per la formattazione, tramite la quale possiamo decidere come visualizzare un numero:</p>
<pre><br />&gt;&gt;&gt; from webhelpers.number import format_number
&gt;&gt;&gt; format_number(1936.27, '.', ',')
'1.936,27'<br />
</pre>
<p>E' un'ottima alternativa (basata sulle regex) ad un altro <a class="external-link" href="http://docs.python.org/2/library/decimal.html#recipes"><strong>metodo</strong></a> che ho trovato nella documentazione ufficiale di python e avevo usato diverse volte per formattare stringhe che dovevano rappresentare una valuta.</p>
<p>Altre <a class="external-link" href="http://sluggo.scrapping.cc/python/WebHelpers/modules/number.html"><strong>funzioni</strong></a> che questo modulo mette a disposizione sono ben più analitiche: abbiamo funzioni per il calcolo della <i>media</i>, della <i>mediana</i>, <i>deviazione standard</i>, <i>percentuale</i>, e tutta una serie di statistiche su una lista di numeri.</p>
<h2>Controllo dei predicati</h2>
<blockquote class="pullquote">Verifica della veridicità dei predicati</blockquote>
<p>Sono state sviluppate nel pacchetto una serie di funzioni di controllo dei predicati: data una lista di elementi si può effettuare delle verifiche di verità rispetto ad un predicato passato come parametro:</p>
<pre><br />&gt;&gt;&gt; from webhelpers.misc import all, any
&gt;&gt;&gt; seq = [2,3,4,5]
&gt;&gt;&gt; all(seq, lambda x: x &gt; 1)
True
&gt;&gt;&gt; all(seq, lambda x: x &gt; 2)
False
&gt;&gt;&gt; any(seq, lambda x: x &gt; 6)
False
&gt;&gt;&gt; any(seq, lambda x: x &gt; 4)
True<br />
</pre>
<p>Oltre ad <strong>all </strong>ed<strong> any</strong> che controllano se il predicato è vero per ogni o almeno un elemento nella lista,<strong> </strong>esistono anche <strong>no</strong> - che controlla se tutti gli elementi sono falsi rispetto al predicato - e <strong>count_true </strong>- che verifica quanti elementi della sequenza sono veri rispetto al predicato in oggetto.</p>
<h2>In definitiva</h2>
<p>Queste, oltre ad altre funzioni che per brevità non ho elencato, hanno permesso a questo pacchetto di entrare in una mia personale libreria di utilities da tenere sempre a portata di mano. Occorre sempre utilizzare piccoli accorgimenti per far rendere al meglio il risultato del proprio lavoro, ed è importante poterlo fare velocemente. Questa per me è una buona raccolta di funzionalità da tenere a mente. L'unico neo che ho potuto trovare al momento è la mancanza di traduzioni i18n.</p>
<p><span class="discreet">L'immagine di testata è di <strong><a class="external-link" href="http://www.flickr.com/photos/roberts87/" id="yui_3_7_3_3_1368954044156_1224">®DS</a></strong></span></p>
<p><span class="discreet">L'immagine per facebook è di <a class="external-link" href="http://www.flickr.com/photos/ajc1/"><strong>AJC1</strong></a></span></p>]]></content:encoded>
    <dc:publisher>No publisher</dc:publisher>
    <dc:creator>Luca Bellenghi</dc:creator>
    <dc:rights></dc:rights>
    
      <dc:subject>python</dc:subject>
    
    
      <dc:subject>tutorials</dc:subject>
    
    
      <dc:subject>web</dc:subject>
    
    <dc:date>2013-05-24T12:05:00Z</dc:date>
    <dc:type>Weblog Entry</dc:type>
  </item>


  <item rdf:about="http://blog.redturtle.it/web-apps-debug-remoto-android-chrome-devtools">
    <title>Web apps: debug remoto con Android e Chrome Developer Tools</title>
    <link>http://blog.redturtle.it/web-apps-debug-remoto-android-chrome-devtools</link>
    <description>Breve guida all'installazione e configurazione di Google Chrome Developer Tools e Android per il debug remoto di applicazioni web mobile</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Attualmente la maggior parte dei browser web disponibili per <strong>desktop </strong><strong>-</strong><strong> </strong>come per esempio <i>Chrome</i>, <i>Internet Explorer</i>, <i>Opera</i>...<i> -</i> dispone nativamente, o quanto meno permette l'installazione, di strumenti divenuti ormai indispensabili per lo sviluppo web, dei quali sarebbe impensabile fare a meno.</p>
<p style="text-align: center; "><img class="image-inline" src="http://blog.redturtle.it/uploads/browsericons.png/@@images/620b1e8e-9035-4d5b-86f3-82221f9c70fb.png" /></p>
<p>Stiamo parlando infatti di tool molto potenti e raffinati, veri e propri "<i>attrezzi del mestiere</i>" di web developer e designer. <br /><a class="external-link" href="http://getfirebug.com/">Firebug</a>, <a class="external-link" href="https://developers.google.com/chrome-developer-tools/">Chrome Developer Tools</a>, <a class="external-link" href="http://www.opera.com/dragonfly/">Opera Dragonfly</a> sono sicuramente tra i più diffusi e conosciuti, e offrono sofisticate funzionalità tra cui:</p>
<ul>
<li>debugger</li>
<li>console JavaScript</li>
<li>ispezione degli elementi DOM</li>
<li>analisi dei log.</li>
</ul>
<h2 style="text-align: left; ">Problema</h2>
<a name="anchor-breaktext"></a><div class="breakText">In ambiente <i>mobile</i>, nello sviluppo di applicazioni <strong>HTML5 </strong>(web app) le cose non sono diverse,<img class="image-right" src="http://blog.redturtle.it/uploads/lookbehindyou.png" /> nel senso che le esigenze sono le stesse dello sviluppo web tradizionale; a cambiare, però, sono gli strumenti disposizione.</div>
<p>I browser per <i>mobile</i> non hanno infatti le caratteristiche dei fratelli maggiori, lasciando così sviluppatori e designer sprovvisti di un vero e proprio "banco di lavoro" per le loro applicazioni.</p>
<h2>Soluzione</h2>
<p>Fortunatamente a venirci in soccorso sono proprio gli stessi ambienti di sviluppo desktop.mobile.<br /> Negli ultimi anni infatti, alcuni di questi si sono evoluti aggiungendo funzionalità di <i>remote debugging, </i>come ha fatto per esempio Google per <i>Chrome Developer Tools</i>.</p>
<p>Il debug remoto permette di connettersi con il browser in utilizzo sul computer direttamente alla sessione attiva sul browser del dispositivo <i>mobile</i> e rende possibile interagire con essa in tempo reale.</p>
<p><strong>Niente male, direi</strong>! Vediamo come si configura.</p>
<h2 style="text-align: left; ">Installazione</h2>
<p>Nativamente disponibile nella versione desktop di Chrome (F12 da tastiera), <i>Chrome Developer Tools</i> necessita di qualche componente aggiuntivo per l'utilizzo remoto.</p>
<h3>Requisiti</h3>
<ul>
<li>un dispositivo <i>mobile</i> Android</li>
<li>l'ambiente di sviluppo Android (SDK)</li>
<li><i>Chrome for mobile</i> installato sul dispositivo</li>
<li>un cavo USB</li>
</ul>
<p>L'installazione dell'<strong>Android SDK</strong> non presenta grosse difficoltà in quanto Goolge fornisce direttamente l'installer per iOS, Linux e Windows. Una volta scaricato, vi basta seguire le indicazioni di configurazione fornite a schermo. Per maggiori informazioni trovate tutto <a class="external-link" href="http://developer.android.com/sdk/index.html">qui</a>.</p>
<p><strong>Android SDK</strong> viene tipicamente usato per lo sviluppo di applicazioni native, ma è necessario anche nello sviluppo di <strong>applicazioni web <i>mobile</i></strong>: infatti mette a disposizione <strong>adb </strong>(Android Debug Bridge) che permette la comunicazione tra il browser <i>mobile</i> attivo sul dispositivo e <i>Chrome Developer Tools</i> su desktop.</p>
<h3><strong>Chrome for mobile</strong></h3>
<p><i>Chrome for mobile</i> è il browser di Google per <i>mobile</i> scaricabile <strong>free</strong> direttamente da<a class="external-link" href="https://play.google.com/store?hl=en"> Google Play</a>. Attenzione ai requisiti minimi di installazione su <i>Android</i>: richiede infatti una versione 4 o superiore.</p>
<h2 style="text-align: left; ">Configurazione</h2>
<p>Finita la fase di installazione si può procedere con la configurazione, che in linea di massima dovrebbe essere molto veloce; bastano due flag selezionati nei punti giusti.</p>
<p>Ecco cosa fare: connettere il telefono al computer attraverso il cavo USB e, nell'ordine, abilitare il <strong>debugger usb </strong>in <i>Android</i> e il <strong>debugger web <i>mobile</i></strong> in <i>Chrome for mobile </i>come mostrato di seguito:</p>
<p style="text-align: center; "><img class="image-inline" src="http://blog.redturtle.it/uploads/copy2_of_usb.png" style="text-align: center; " /> <img class="image-inline" src="http://blog.redturtle.it/uploads/copy_of_web.png" /></p>
<p>Lanciare ora il comando <strong>adb</strong> direttamente da console per attivare la sincronizzazione tra desktop e dispositivo <i>mobile</i>:</p>
<pre>adb forward tcp:9222 localabstract:chrome_devtools_remote</pre>
<p>Fatto!</p>
<h2>Utilizzo</h2>
<p>Arrivati a questo punto abbiamo tutto il necessario per iniziare una nuova sessione di sviluppo. Digitare quindi nella barra degli indirizzi di Chrome l'indirizzo <i>localhost:9222</i></p>
<p style="text-align: center; "><img class="image-inline" src="http://blog.redturtle.it/uploads/copy_of_image_7.png" /></p>
<p>Se tutto è andato a buon fine, quando si inizia la navigazione da cellulare dovrebbero comparire le pagine navigate in <i>Google Chrome, </i>come mostrato nell'esempio sopra, dove si vedono tre pagine da me aperte in quel momento. Ora potete scegliete quale ispezionare semplicemente cliccandoci sopra. Il sorgente sarà immediatamente disponibile in <i>Chrome Developer Tools</i> sul vostro computer, esattamente come fareste con le applicazioni per desktop:</p>
<p style="text-align: center; "><img class="image-inline" src="http://blog.redturtle.it/uploads/inspection.png" /></p>
<h2 style="text-align: left; ">Conclusioni</h2>
<p>Nel difficile compito di ricerca delle performance, disporre di strumenti adeguati è molto importante specialmente per il <i>mobile</i> dove le risorse a disposizione sono (ancora) ridotte.<br /><i>Chrome Deveveloper tools</i> è uno di questi; di certo non può garantire che le vostre applicazioni siano di successo, ma è di grande aiuto affinché possano diventarlo.</p>
<div>
<div></div>
<div id="_mcePaste"></div>
</div>]]></content:encoded>
    <dc:publisher>No publisher</dc:publisher>
    <dc:creator>Nicola Senno</dc:creator>
    <dc:rights></dc:rights>
    
      <dc:subject>web</dc:subject>
    
    
      <dc:subject>Chrome</dc:subject>
    
    
      <dc:subject>HTML5</dc:subject>
    
    
      <dc:subject>Android</dc:subject>
    
    
      <dc:subject>Remote debug</dc:subject>
    
    <dc:date>2013-05-14T07:40:00Z</dc:date>
    <dc:type>Weblog Entry</dc:type>
  </item>


  <item rdf:about="http://blog.redturtle.it/sunburst-css-dtml">
    <title>Sunburst e i css + dtml: se li conosci NON li eviti</title>
    <link>http://blog.redturtle.it/sunburst-css-dtml</link>
    <description>Sviluppare un tema basato su Sunburst e cambiargli abito in 5 minuti si può: i dtml non sono ancora morti e aspettano solo di essere riportati in vita!</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Alzi la mano chi, almeno una volta, ha maledetto Sunburst (il tema integrato nelle versioni di Plone 4.x) per averci privato di un preziosissimo supporto nello sviluppo dei temi grafici: <a class="external-link" href="http://plone.org/documentation/glossary/dtml" target="_blank">la sintassi DTML</a>.</p>
<p>Alzi la mano chi ha sul muro dell'ufficio i segni inequivocabili di tazze, portapenne, robottini e cancelleria varia scagliati contro la personificazione di quel public.css di Sunburst che porta scolpito il blu <span>#205C90 nei più reconditi recessi delle proprie righe.</span></p>
<p></p>
<a name="anchor-breaktext"></a><div class="breakText"></div>
<p>Proprio così: il formato DTML è stato ufficialmente abbandonato e relegato alle versioni di Plone &lt;= 3.x.</p>
<p>Attenzione: abbandonato non vuol dire "non supportato". Nei nostri temi basati su Sunburst possiamo tranquillamente introdurre file .dtml.<br />Allora non ci resta che prendere esempio dagli sceneggiatori di Beautiful e riportarli alla vita con un bel "<i>coup de theatre</i>".</p>
<p>Lo scopo di questo post non è di spiegarne l'uso, la sintassi o elencarne pregi o difetti. E' una scelta individuale e organizzativa che può essere o meno condivisibile. Ma per tutti i "<i>plone-skinner</i>" che la pensano come me, metto a disposizione la mia personale panacea:</p>
<ul>
<li>il buon vecchio <strong><a href="http://blog.redturtle.it/uploads/base_properties.props" class="internal-link">base_properties.props</a></strong>, ampliato con ulteriori personalizzazioni (stili per la descrizione, bordo inferiore sui link, colore di hover sui link...)</li>
<li>un file <strong><a href="http://blog.redturtle.it/uploads/sunburst_public.css.dtml" class="internal-link">sunburst_public.css.dtml</a></strong> (da aggiungere al proprio tema) che fa uso del <i>base_properties.props</i> per ridefinire tutti gli stili (e solo quelli) del <i>public.css</i> di <strong>Sunburst</strong> in cui sia possibile sostituire un valore statico con una variabile dtml.</li>
</ul>
<p>Entrambi i files vanno inseriti nella cartella "skins/miotema_styles" del proprio pacchetto. Il file sunburst_public.css.dtml dovrà essere registrato in profiles/default/cssregistry.xml con la classica direttiva:</p>
<pre>&lt;stylesheet id="sunburst_public.css" <br />            media="screen" rel="stylesheet" <br />            rendering="link"<br />            cacheable="True"<br />            compression="safe"<br />            cookable="True"<br />            enabled="1"<br />            expression=""/&gt;</pre>
<p>Consiglio di registrarlo <strong>prima</strong> del file css specifico del tema (esempio <i>miotema.css</i>).</p>
<h3><strong>Vantaggi?</strong></h3>
<p>Molteplici:</p>
<ul>
<li>cambiare faccia a Sunburst in 5 minuti </li>
<li>evitare di sovrascrivere l'intero <i>public.css </i></li>
<li>ridurre gli episodi di ipertensione e nervosismo</li>
<li>preservare il candore del muro del proprio ufficio.</li>
</ul>
<h3><strong>Svantaggi?</strong></h3>
<p>Onestamente non ne vedo nessuno, salvo il fatto che il giorno in cui i dtml verranno definitivamente deprecati si dovrà necessariamente rivedere il proprio codice... ma in una simile circostanza si starà senz'altro procedendo con una migrazione di versione "<i>major</i>" e potreste sfruttare l'occasione per proporre un bel restyling del sito ;-)</p>
<p><i>Avvertenze e modalità d'uso: </i>l'uso del prodotto può creare dipendenza e assuefazione. Assumere a piccole dosi e intervallare con la somministrazione di un tema <strong>Diazo</strong> per equilibrare i valori di "<i>cssemia"</i>.</p>]]></content:encoded>
    <dc:publisher>No publisher</dc:publisher>
    <dc:creator>Irene Capatti</dc:creator>
    <dc:rights></dc:rights>
    
      <dc:subject>Plone 4</dc:subject>
    
    
      <dc:subject>plone.it</dc:subject>
    
    
      <dc:subject>css</dc:subject>
    
    <dc:date>2013-04-23T07:00:00Z</dc:date>
    <dc:type>Weblog Entry</dc:type>
  </item>


  <item rdf:about="http://blog.redturtle.it/gallerie-slider-immagini-sito-web-20-esempi">
    <title>Gallerie e Slider di immagini per il tuo sito web: eccone 20 esempi! </title>
    <link>http://blog.redturtle.it/gallerie-slider-immagini-sito-web-20-esempi</link>
    <description>Durante le mie ricerche ho raccolto tutti i riferimenti agli slider che mi hanno più incuriosito. Scopri anche tu come mostrare le immagini del tuo sito in modo originale!</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p class="p1">La maggior parte dei clienti chiede una <strong>gallery</strong> o uno <strong>slider</strong> nel proprio sito. In effetti, un carousel di immagini può fare una grande differenza e dare quel tocco <i>cool</i> al portale.</p>
<p class="p1">E' per questo che spesso mi piace perdermi alla ricerca di qualcosa di nuovo da proporre. Qui sotto ho elencato una serie di slider e gallery costituiti principalmente da <strong>JQuery plugin</strong> e <strong>CSS3</strong>.</p>
<h2 class="p1"><a class="external-link" href="http://buildinternet.com/project/supersized/">supersized! JQuery plugin</a></h2>
<h3 class="p1" style="text-align: left; ">Supersized è un fullscreen background slideshow costruito utilizzando la libreria jQuery.</h3>
<p class="p1" style="text-align: right; "><strong><a class="external-link" href="http://buildinternet.com/project/supersized/slideshow/3.2/demo.html">DEMO &gt;&gt;</a></strong></p>
<p class="p2"><a class="external-link" href="http://buildinternet.com/project/supersized/"><img class="image-inline" src="http://blog.redturtle.it/uploads/supersized.png/@@images/2c14dd26-c534-42b7-85ad-b2fe0b2e1d48.png" /></a></p>
<p class="p2"><span class="s1"><br /></span></p>
<p> </p>
<p></p>
<a name="anchor-breaktext"></a><div class="breakText"></div>
<h2 class="external-link"><a class="external-link" href="http://manos.malihu.gr/sideways-jquery-fullscreen-image-gallery/">SIDEWAYS</a></h2>
<h3 class="p1">Una galleria fullscreen di immagini creata con la libreria jQuery e CSS. La galleria presenta le immagini a schermo intero in diverse modalità e con barre di scorrimento personalizzate.</h3>
<p style="text-align: right; "><strong><a class="external-link" href="http://manos.malihu.gr/tuts/sideways_jquery_fullscreen_image_gallery.html">DEMO &gt;&gt;</a></strong></p>
<p class="p1"><img class="image-inline" src="http://blog.redturtle.it/uploads/sideways.png/@@images/8bad9c57-9c3e-4e29-b8dd-3aac1f6ea453.png" /></p>
<p class="p1"> </p>
<p> </p>
<h2 class="breakText"><a class="external-link" href="http://www.webstuffshare.com/2012/07/flyout-image-slider-using-jquery-css3/">Flyout Image Slider Using jQuery &amp; CSS3</a></h2>
<h3>Uno slider costituito da una pila di immagini, che funziona facendo “volare” l'immagine selezionata davanti alla pila. Usa le transizioni CSS3, animazione e jQuery.</h3>
<p style="text-align: right; "><strong><a class="external-link" href="http://webstuffshare.com/demo/FlyoutSlider/index.html">DEMO &gt;&gt;</a></strong></p>
<p><img class="image-inline" src="http://blog.redturtle.it/uploads/FlyoutSlider.png/@@images/d918e5af-688f-4566-98fb-c3624603f8b5.png" /></p>
<p class="p3"> </p>
<h2 class="p3"><a class="external-link" href="http://www.egrappler.com/full-screen-responsive-jquery-image-and-content-sliderrslider/">Rslider</a></h2>
<h3>Uno slider jQuery di immagini e contenuti, fullscreen e responsive.</h3>
<p style="text-align: right; "><strong><a class="external-link" href="http://www.egrappler.com/responsive-image-content-slider/index.htm">DEMO &gt;&gt;</a></strong></p>
<p><img class="image-inline" src="http://blog.redturtle.it/uploads/responsiveimagecontentslider.png/@@images/a42eecfc-1038-4402-a29d-31ee15bc5f1a.png" /></p>
<p class="p1"> </p>
<h2 class="external-link"><a class="external-link" href="http://www.webstuffshare.com/2012/07/portfolio-flipping-slider-using-jquery-css3/">Portfolio Flipping Slider Using jQuery &amp; CSS3</a></h2>
<h3>Uno slider per visualizzare il proprio portfolio con un effetto "flipping" per l'impaginazione. Usa jQuery e trasformazioni CSS3.</h3>
<p style="text-align: right; "><strong><a class="external-link" href="http://webstuffshare.com/demo/FlippingSlider/index.html">DEMO &gt;&gt;</a></strong></p>
<p><img class="image-inline" src="http://blog.redturtle.it/uploads/FlippingSlider.png/@@images/3e35fcac-0ae4-40a9-b9be-489f8b32910a.png" /></p>
<p class="p2"> </p>
<h2 class="p3"><a class="external-link" href="http://www.sequencejs.com/themes/category/free/">Sequence</a></h2>
<h3>Uno slider responsive che usa transizioni CSS3 avanzate.</h3>
<p><img class="image-left" src="http://blog.redturtle.it/uploads/slidinghorizontalparallax.png/@@images/3cd4d953-429f-4c6c-82e4-d622e715515a.png" /></p>
<blockquote class="pullquote">Sliding Horizontal Parallax Theme</blockquote>
<p><strong><a class="external-link" href="http://www.sequencejs.com/themes/sliding-horizontal-parallax/">DEMO &gt;&gt;</a></strong></p>
<div class="visualClear"></div>
<p><img class="image-left" src="http://blog.redturtle.it/uploads/modernslidein.png/@@images/2bedee8e-399d-4df9-b8db-4bd3b7c723c1.png" /></p>
<blockquote class="pullquote">Apple iPhone4 Style Theme</blockquote>
<p class="p1"><strong><a class="external-link" href="http://www.sequencejs.com/themes/apple-style/">DEMO &gt;&gt;</a></strong></p>
<div class="visualClear"></div>
<p style="text-align: center; "><img class="image-left" src="http://blog.redturtle.it/uploads/applestyle.png/@@images/b5f91b3f-a0e5-4258-b191-a93770e8e287.png" /></p>
<blockquote class="pullquote">Minimalist Horizontal Sliding Theme</blockquote>
<p class="p1"><strong><a class="external-link" href="http://www.sequencejs.com/themes/modern-slide-in/">DEMO &gt;&gt;</a></strong></p>
<div class="visualClear"></div>
<p class="p1"> </p>
<h2 class="external-link"><a class="external-link" href="http://tympanus.net/codrops/2012/08/02/animated-responsive-image-grid/">Animated Responsive Image Grid</a></h2>
<h3>Un plugin jQuery per la creazione di una griglia di immagini responsive che cambia automaticamente le immagini con animazioni e tempi diversi.</h3>
<p style="text-align: right; "><strong><a class="external-link" href="http://tympanus.net/Development/AnimatedResponsiveImageGrid/">DEMO &gt;&gt;</a></strong></p>
<p><img class="image-inline" src="http://blog.redturtle.it/uploads/copy_of_animatedresponsiveimagegrid.png/@@images/348f122e-362e-4417-938f-7861fefc1dc3.png" /></p>
<p class="p2"> </p>
<h2 class="p3"><a class="external-link" href="http://www.webstuffshare.com/2012/05/showing-image-with-bounce-effect/">Showing Image With Bounce Effect</a></h2>
<h3>Un effetto di rimbalzo quando viene mostrata un'immagine, creato utilizzando trasformazioni CSS3 e animazione.</h3>
<p style="text-align: right; "><strong><a class="external-link" href="http://webstuffshare.com/demo/BounceEffect/index.html">DEMO &gt;&gt;</a></strong></p>
<p><img class="image-inline" src="http://blog.redturtle.it/uploads/BounceEffect.png/@@images/71356b40-9b2f-4a3d-b36c-657205268c6c.png" /></p>
<p class="p2"> </p>
<h2 class="p3"><a class="external-link" href="http://tympanus.net/codrops/2012/08/16/triple-panel-image-slider/">Triple Panel Image Slider</a></h2>
<h3>Uno slider jQuery di immagini a pannello triplo con un look 3D.</h3>
<p style="text-align: right; "><strong><a class="external-link" href="http://tympanus.net/Tutorials/TriplePanelImageSlider/">DEMO &gt;&gt;</a></strong></p>
<p><img class="image-inline" src="http://blog.redturtle.it/uploads/TriplePanelImageSlider.png/@@images/0f241448-985f-404a-8fa8-d0effc738e9c.png" /></p>
<p class="p1"> </p>
<h2 class="p3"><a class="external-link" href="http://www.minimit.com/works/minimit-gallery-plugin">Minimit</a></h2>
<h3 class="p1">Minimit Gallery è un plugin slider che supporta transizioni e trasformazioni CSS3, trascinamento, scroller, e interazioni touch.</h3>
<p style="text-align: right; "><strong><a class="external-link" href="http://www.minimit.com/mg/demo.html">DEMO &gt;&gt;</a></strong></p>
<p><img class="image-left" src="http://blog.redturtle.it/uploads/minimit.png/@@images/50f37580-65b9-40d3-9e42-5c5c22103649.png" /></p>
<h3 class="p1"><img class="image-inline" src="http://blog.redturtle.it/uploads/minimit1.png/@@images/8a20f79b-f6c0-489e-b4bd-72ededbf2a37.png" /></h3>
<p><img class="image-inline" src="http://blog.redturtle.it/uploads/minimit2.png/@@images/e11216c2-8e2d-4388-8d13-ba9f00156839.png" /></p>
<p class="p1"> </p>
<p class="p1"> </p>
<h2 class="p3"><a class="external-link" href="http://www.script-tutorials.com/css3-parallax-scrolling-slider/">CSS3 Parallax scrolling slider</a></h2>
<h3>Uno slider verticale che usa solamente proprietà CSS3.</h3>
<p style="text-align: right; "><strong><a class="external-link" href="http://www.script-tutorials.com/demos/273/index.html">DEMO &gt;&gt;</a></strong></p>
<p><img class="image-inline" src="http://blog.redturtle.it/uploads/CSS3Parallaxscrollingslider.png/@@images/0090ba95-3722-40d0-8eff-b2a2ad7e4866.png" /></p>
<p class="p2"> </p>
<h2 class="p3"><a class="external-link" href="http://tympanus.net/codrops/2012/06/06/image-accordion-with-css3/">Image Accordion with CSS3</a></h2>
<h3>Un accordion di immagini che espande un elemento al click.</h3>
<p style="text-align: right; "><strong><a class="external-link" href="http://tympanus.net/Tutorials/CSS3ImageAccordion/">DEMO &gt;&gt;</a></strong></p>
<p><img class="image-inline" src="http://blog.redturtle.it/uploads/CSS3ImageAccordion.png/@@images/656ed21d-0886-4e81-9446-cc1c69aeb88f.png" /></p>
<p class="p2"> </p>
<h2 class="p3"><a class="external-link" href="http://vegas.jaysalvat.com/">Vegas</a>, Background jQuery Plugin</h2>
<h3>Uno slider di diversi background.</h3>
<p style="text-align: right; "><strong><a class="external-link" href="http://vegas.jaysalvat.com/demo/">DEMO &gt;&gt;</a></strong></p>
<p><img class="image-inline" src="http://blog.redturtle.it/uploads/vegas.png/@@images/ed27a5db-d0b8-4680-9309-eb2fe635a6f9.png" /></p>
<p class="p3"> </p>
<h2 class="p3"><a class="external-link" href="http://tympanus.net/codrops/2011/09/12/elastislide-responsive-carousel/">Elastislide</a></h2>
<h3>Carousel responsive di immagini che si adatterà in modo fluido a un layout. Si tratta di un plugin per jQuery che può essere disposto in orizzontale o in verticale.</h3>
<p style="text-align: right; "><strong><a class="external-link" href="http://tympanus.net/Development/Elastislide/">DEMO &gt;&gt;</a></strong></p>
<p style="text-align: center; "><img class="image-inline" src="http://blog.redturtle.it/uploads/Elastislide.png/@@images/683f37ad-76f5-4572-a091-302bb81ff8dd.png" /></p>
<p style="text-align: center; "> </p>
<h2 class="external-link"><a class="external-link" href="http://www.zurb.com/playground/orbit-jquery-image-slider">Orbit</a>, A Slick jQuery Image Slider Plugin</h2>
<h3>Un plugin jQuery per un slider di immagini.</h3>
<p style="text-align: right; "><strong><a class="external-link" href="http://www.zurb.com/playground/orbit-jquery-image-slider">DEMO &gt;&gt;</a></strong></p>
<p><img class="image-inline" src="http://blog.redturtle.it/uploads/orbit.png/@@images/4e0b38d4-341c-4589-8f49-ab84ca9d41b5.png" /></p>
<p> </p>
<h2 class="external-link"><a class="external-link" href="http://tympanus.net/codrops/2012/06/12/css-only-responsive-layout-with-smooth-transitions/">CSS-Only Responsive Layout with Smooth Transitions</a></h2>
<h3>Un layout con effetto a “scorrimento fluido” creato solamente attraverso CSS.</h3>
<p style="text-align: right; "><strong><a class="external-link" href="http://tympanus.net/Tutorials/SmoothTransitionsResponsiveLayout/">DEMO &gt;&gt;</a></strong></p>
<p><img class="image-inline" src="http://blog.redturtle.it/uploads/SmoothTransitionsResponsiveLayout.png/@@images/3fce5e9f-7969-4f21-8263-9872e33e254f.png" /></p>
<p class="p2"> </p>
<h2 class="external-link"><a class="external-link" href="http://glisse.victorcoulon.fr/">Glisse.js</a></h2>
<h3>Un photo viewer jQuery, responsive e completamente personalizzabile.</h3>
<p style="text-align: right; "><strong><a class="external-link" href="http://glisse.victorcoulon.fr/example-1/">DEMO &gt;&gt;</a></strong></p>
<p><img class="image-inline" src="http://blog.redturtle.it/uploads/glisse2.png/@@images/d96d4820-65f3-4202-b410-01c5558681ed.png" /></p>
<p class="p2"> </p>
<h2 class="external-link"><a class="external-link" href="http://www.iosscripts.com/iosslider/">iosSlider</a>, Touch Enabled jQuery Horizontal Slider Plugin</h2>
<h3>Un plugin jQuery progettato per essere usato come un dispositivo di scorrimento del contenuto, un carousel, un banner di scorrimento o una galleria di immagini.</h3>
<p style="text-align: right; "><strong><a class="external-link" href="http://www.iosscripts.com/iosslider/">DEMO &gt;&gt;</a></strong></p>
<p><img class="image-inline" src="http://blog.redturtle.it/uploads/iosslider.png/@@images/d4bd7d87-c3e5-415d-84e7-33a6820868e1.png" /></p>
<p class="p3"> </p>
<h2 class="external-link"><a class="external-link" href="http://tympanus.net/codrops/2011/11/21/elastic-image-slideshow-with-thumbnail-preview/">Elastic Image Slideshow with Thumbnail Preview</a></h2>
<h3>Uno slideshow "elastico" che usa miniature per le anteprime. La presentazione si regolerà automaticamente al suo contenitore.</h3>
<p style="text-align: right; "><strong><a class="external-link" href="http://tympanus.net/Tutorials/ElasticSlideshow/">DEMO &gt;&gt;</a></strong></p>
<p><img class="image-inline" src="http://blog.redturtle.it/uploads/ElasticSlideshow.png/@@images/ebac87e8-7a2f-4165-bf76-403926fa6d95.png" /></p>
<p class="p3"> </p>
<h2 class="p3"><a class="external-link" href="http://wowslider.com/">WOW Slider</a></h2>
<h3>Uno slider jQuery di immagini, responsive e con vari effetti di visualizzazione.</h3>
<p style="text-align: right; "><strong><a class="external-link" href="http://wowslider.com/demo.html">DEMO &gt;&gt;</a></strong></p>
<p><img class="image-inline" src="http://blog.redturtle.it/uploads/wowslider.com.png/@@images/282b0560-de26-4fb8-91b0-c16a2bc844fb.png" /></p>
<p> </p>
<p>Come vedete, le possibilità per mostrare le vostre immagini sono davvero molte; e queste sono solo alcune delle tante proposte!</p>
<p>Ci si potrebbe chiedere: "quale scegliere"? Ma a questa domanda non è possibile dare un risposta che vada bene per tutti. Alcuni di questi plugin richiedono funzionalità estremamente avanzate, non ancora disponibili per tutti i browser, e questo non è un aspetto che si possa trascurare. In altri casi potreste avere bisogno di una soluzione <strong>accessibile</strong>, e allora sarà vostro compito testare l'utilizzo della tastiera.</p>
<p>Una sola cosa credo sia chiara: le funzionalità che ad oggi <strong>CSS3</strong> e <strong>HTML5</strong> ci offrono, hanno reso più semplice la creazione di questi strumenti, e questo ci fa ben sperare per il futuro.</p>
<p>Spero che abbiate trovato in uno di questi slider una soluzione alla vostra specifica esigenza!</p>
<p><span class="discreet">La foto in testata è di <a class="external-link" href="http://www.flickr.com/photos/widerbergs/">Widerbergs</a>.</span></p>]]></content:encoded>
    <dc:publisher>No publisher</dc:publisher>
    <dc:creator>Federica D'Elia</dc:creator>
    <dc:rights></dc:rights>
    
      <dc:subject>jQuery</dc:subject>
    
    
      <dc:subject>web</dc:subject>
    
    
      <dc:subject>plone.it</dc:subject>
    
    
      <dc:subject>HTML5</dc:subject>
    
    
      <dc:subject>css</dc:subject>
    
    <dc:date>2013-04-08T08:15:00Z</dc:date>
    <dc:type>Weblog Entry</dc:type>
  </item>


  <item rdf:about="http://blog.redturtle.it/pudb-ovvero-come-ho-imparato-velocizzare-mio-debug">
    <title>PuDB, ovvero: come ho imparato a velocizzare il mio debug</title>
    <link>http://blog.redturtle.it/pudb-ovvero-come-ho-imparato-velocizzare-mio-debug</link>
    <description>Quando si fa debug di codice poco "docile" è importante avere gli strumenti giusti per non impazzire sprecando tempo prezioso nel trovare il problema</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p style="float:right; "><img class="image-inline" src="uploads/wtf.png/@@images/7c8b7077-5383-4f56-a234-73a3e78d2709.png" /></p>
<p>Nella vita di ogni sviluppatore arriva il giorno in cui si incrocia la propria tastiera con codice incomprensibile, dai risultati inspiegabili e che, ovviamente, bisogna correggere. Avere gli <strong>strumenti adatti per il debugging</strong> è fondamentale.</p>
<p>Come programmatore python ho avuto modo di utilizzare diversi tipi di debugger, dal semplice pdb a una versione più completa: <a class="external-link" href="https://pypi.python.org/pypi/pdbpp/"><strong>pdb++</strong></a>. Esistono debugger integrati nei vari IDE di sviluppo, di cui però non ho mai approfondito troppo l'uso dal momento che li ho sempre trovato ambienti un po' pesanti. Da amante della shell, divido il mio tempo di sviluppo fra vim e un editor di testo molto semplice come <a class="external-link" href="http://www.sublimetext.com/"><strong>sublime</strong></a>.</p>
<p></p>
<a name="anchor-breaktext"></a><div class="breakText">Ed è da amante della shell che sono rimasto piacevolmente colpito da un debugger di cui non conoscevo l'esistenza, e di cui mi ha raccontato qualche giorno fa un uccellino azzurro: <a class="external-link" href="https://pypi.python.org/pypi/pudb"><strong>puDB</strong></a>!</div>
<p>PuDB è un debugger visuale basato su <strong><a class="external-link" href="https://pypi.python.org/pypi/urwid">Urwid</a></strong>. Quando ho visto la sua prima immagine ho pensato che fosse qualcosa per nostalgici: sono riaffiorati parecchi ricordi delle schermate che mi hanno accompagnato quando muovevo i primi passi con TurboPascal.</p>
<p>Ma questo effetto <a class="external-link" href="http://it.wikipedia.org/wiki/Stile_retr%C3%B2"><strong>retrò</strong></a> è passato rapidamente in secondo piano: mi sono reso conto di avere sotto mano <strong>tutto quello che mi serviva per debuggare il problema su cui stavo lavorando</strong>.</p>
<h2>Installazione e uso</h2>
<p>L'installazione è semplice: è necessario utilizzare un interprete che vada almeno dalla versione 2.4 in poi, dopodiché, che si usi buildout, easy_install o pip per l'installazione è indifferente e in un attimo si è pronti all'uso del pacchetto; nel codice che si vuole debuggare basta inserire:</p>
<p class="callout">import <strong>pudb</strong>;<strong>pudb</strong>.set_trace()</p>
<p>e al momento dell'esecuzione, in shell ci si trova nel debugger:</p>
<p><img class="image-inline" src="uploads/pudb.png/@@images/c36746db-0a5c-4e45-b213-802cb5bad61a.png" /></p>
<p>Una sola immagine è già in grado di mostrare che si ha molto per le mani: un'intera pagina di codice sulla sinistra e 3 box sulla destra - il primo con le variabili dello scope, il secondo in cui viene mostrato lo stack e il terzo in cui si trova la lista dei breakpoint.</p>
<h2>Caratteristiche principali</h2>
<p>Il funzionamento base è come quello del pdb: <strong>'n'</strong> per proseguire nel debug, <strong>'s'</strong> per entrare in un metodo e così via. Ma vediamo quali sono le caratteristiche principali di questo debugger e perché, secondo me, rende più veloce il debug.</p>
<blockquote class="pullquote">Navigazione da tastiera tramite le frecce o Shift+[V/S/B] per passare ai box di variabili, stack e breakpoint</blockquote>
<p>Prima di tutto, abbiamo un'ottima navigazione da tastiera: per chi è abituato a vim, si tratta di ricordare qualche combinazione o tasto in più, ma una volta memorizzati i comandi principali si va veramente veloci. Per una lista di tutti i comandi, si può fare riferimento alla guida inserita nel debugger stesso, attivabile premendo <strong>'SHIFT+?'</strong>.</p>
<p>In secondo luogo, si vede una porzione molto ampia di codice; non è una regola, ma cerco di scrivere metodi non troppo lunghi (dove possibile) e con puDB diventa facile visualizzare l'intero metodo di cui si sta facendo debug.</p>
<blockquote class="pullquote">Visualizzazione differenziata per le variabili (tipo, repr, str) ed espandibile nel caso di variabili complesse</blockquote>
<p>Altra caratteristica che reputo importantissima (assieme alla visione completa del codice) è la presenza nei box di destra di tutte le variabili che vengono definite nello scope e aggiornate durante l'esecuzione. Quello che preferisco è il fatto che si possa agire in diversi modi sulle variabili: in caso di variabili complesse, queste si possano espandere come vediamo nell'immagine sotto (premendo <strong>'\'</strong>):</p>
<p style="text-align: center; "><img src="http://blog.redturtle.it/uploads/variables.png" style="text-align: center; " title="" class="image-inline" alt="" /></p>
<p>Inoltre si può scegliere il tipo di visualizzazione per ogni singola variabile, mostrandola per tipo (<strong>'t'</strong>), mostrandone la __repr__ (<strong>'r'</strong>), la __str__ (<strong>'s'</strong>) oppure utilizzando una rappresentazione personalizzata (<strong>'c'</strong>).</p>
<blockquote class="pullquote">Stack delle chiamate navigabile</blockquote>
<p>Per quello che riguarda lo stack, la possibilità di scorrerlo e di navigare nei metodi elencati al suo interno è molto utile, dal momento che si è in grado (senza dover aprire altre finestre o senza riavviare la sessione di debug) di visualizzare il codice chiamante dei metodi che stiamo analizzando. Una volta entrati in un altro metodo dello stack, cambierà lo scope e anche le variabili visualizzate saranno aggiornate; l'esecuzione del debug riprenderà da quel nuovo punto.</p>
<p>Ovviamente, nel caso fosse necessario utilizzare la linea di comando, la possibilità c'è: è sufficiente premere <strong>'!'</strong> per fare switch su una shell python contestualizzata nello scope corrente ('<strong>Ctrl-d'</strong> per uscirne).</p>
<p>Non c'è molto altro da aggiungere; la cosa migliore da fare è mettersi alla tastiera e iniziare a utilizzare questo debugger!</p>
<p><span class="discreet">Immagine nel body: <a href="http://www.flickr.com/photos/smitty/2245445147/">http://www.flickr.com/photos/smitty/2245445147/</a></span></p>
<p><span class="discreet">Immagine in testata: </span><a href="http://www.flickr.com/photos/28208534@N07/4047355843">http://www.flickr.com/photos/28208534@N07/4047355843</a></p>]]></content:encoded>
    <dc:publisher>No publisher</dc:publisher>
    <dc:creator>Luca Bellenghi</dc:creator>
    <dc:rights></dc:rights>
    
      <dc:subject>python</dc:subject>
    
    
      <dc:subject>tutorials</dc:subject>
    
    <dc:date>2013-04-03T08:50:00Z</dc:date>
    <dc:type>Weblog Entry</dc:type>
  </item>


  <item rdf:about="http://blog.redturtle.it/funkload-simple-buildout-to-run-your-test">
    <title>Funkload: a simple buildout to spread and run your test!</title>
    <link>http://blog.redturtle.it/funkload-simple-buildout-to-run-your-test</link>
    <description>Load testing can be one of the key for a successful website deployment. Moreover it can help to solve many situations. Let's see a way to spread your tests!</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Recently we faced a performance issue on a <strong>Plone </strong>site, which has been reported to be slower than expected.</p>
<p>The application, after a migration to a new hardware, has shown to be a bit lazy compared to the expectations.</p>
<p>Because of the weird behaviour and confident on our <strong>Plone </strong>installation, we assumed a hardware misconfiguration.<br /> But without evidence (numbers in this case), a claim is merely an opinion.</p>
<p>So, to get ride of the problem, we decided to perform multiple load test on different servers, and then compare the results.</p>
<p> </p>
<p></p>
<a name="anchor-breaktext"></a><div class="breakText">The easiest and fast way to get the job done has been achieved with a simple <i>buildout</i> used to spread <strong>Funkload</strong> on many other servers with the same hardware requirements, each one running a Plone site clone. Of course, in order to compare the performance, every server has to meet the same hardware requirements.</div>
<p> </p>
<h3>Funkload</h3>
<div><a class="external-link" href="http://funkload.nuxeo.org/">Funkload</a> is a powerful functional and load web tester, easy to install and well documented. I'm not going deep on details of all its functionality in this post, because in our case the two standard commands <strong>fl-run-bench</strong> and <strong>fl-build-report</strong> have been enough for the purpose, but if you are interested there are many guides online that can help you:</div>
<div></div>
<div><a href="http://funkload.nuxeo.org/">http://funkload.nuxeo.org/</a></div>
<p><a href="http://funkload.nuxeo.org/"></a><a href="http://ziade.org/2011/07/27/how-to-stress-test-your-app-using-funkload-part-1/">http://ziade.org/2011/07/27/how-to-stress-test-your-app-using-funkload-part-1</a></p>
<p>So, let's see how to set a Funkload test within a <i>buildout.</i></p>
<div>As usual the starting point is the <a class="external-link" href="https://pypi.python.org/pypi/virtualenv">virtualenv</a> environment:</div>
<pre>git clone https://github.com/nicolasenno/funkload.buildout
cd funkload.buildout<br />virtualenv --no-site-packages .<br />. bin/activate
</pre>
<p>Then the buildout.cfg (<a class="external-link" href="https://github.com/nicolasenno/funkload.buildout">download</a> from github):</p>
<div></div>
<pre>[buildout]
parts = 
    bench-tools
    gnuplot
    versions = versions<br />
[bench-tools]
recipe = zc.recipe.egg:scripts
eggs =
    docutils
    funkload 
    tcpwatch
initialization =
import os
os.environ['TCPWATCH'] = "${buildout:bin-directory}/tcpwatch"

[gnuplot]
recipe = zc.recipe.cmmi
url = http://sourceforge.net/projects/gnuplot/files/gnuplot/4.6.2/gnuplot-4.6.2.tar.gz/download
configure-options = --bindir=${buildout:directory}/bin<br />
[versions]
funkload = 1.16.1<br /> </pre>
<p><strong>Gnuplot</strong> can be installed directly from buildout, as suggested by  Alessandro Pisa on his <a class="external-link" href="http://blog.redturtle.it/fix-funkload-report-generation-problems-by-upgrading-gnuplot">blog post.</a></p>
<div>Finally, once Funkload is ready, we can create a test:</div>
<pre>import unittest
from random import random
from funkload.FunkLoadTestCase import FunkLoadTestCase

PAGES = (('Homepage', ''),
         ('path1', 'contacts'),
         ('path2', 'media'),
         )

class Site(FunkLoadTestCase):
    """This test use a configuration file Site.conf."""

    def setUp(self):
        """Setting up test."""
        self.server_url = self.conf_get('main', 'url')

    def test_app(self):
        ''' site path
        '''
        server_url = self.server_url

        for title, page in PAGES:
            url = "/".join((server_url, page))
            self.get(url, description='Get %s' % title)
</pre>
<p>Then we can use a Makefile to automate the launch process:</p>
<pre>LOG_HOME := var/funkload/log
REPORT_HOME := var/funkload/data

ifdef URL
    FLOPS = -u $(URL) $(EXT)
else
    FLOPS = $(EXT)
endif

ifdef REPORT_HOME
    REPORT = $(REPORT_HOME)
else
    REPORT = report
endif

all: test

test: start test-app

bench: start bench-app

start:
    mkdir -p $(REPORT)  $(LOG_HOME)

test-app:
    fl-run-test -d --debug-level=3 --simple-fetch site_test.py Site.test_app $(FLOPS)

bench-app:
    fl-run-bench --simple-fetch site_test.py Site.test_app -c 1:5:10:15:20:30:40:50 -D 45 -m 0.1 -M .5 -s 1 $(FLOPS)
    fl-build-report $(LOG_HOME)/site-bench.xml --html -o $(REPORT)

clean:</pre>
<p>If you prefer, as an improvement, you can generate this file within the <i>buildout</i> itself.<br />Take a look to <a class="external-link" href="https://pypi.python.org/pypi/collective.recipe.template">collective.recipe.template</a> for more information.</p>
<p>Here we are!<br /> A couple of shell commands and you will be ready to run the test.</p>
<p>From your <i>buildout</i> directory, type:</p>
<pre>make test
make test URL=http://override-url/
make bench
</pre>
<p>At this point a full report will be ready in "{buildout dir}/var/funkload/data" (path depends on your configuration).</p>
<h3>Conclusion</h3>
<p>As you can see install and run a <strong>Funkload</strong> load test it's just matter of few steps. <br /> Thanks to it, we have been able to prove our thesis with numbers.</p>
<p>I think it's not a bad idea add it into my checklist of things to do for every site deployment. It could become useful in many other cases.</p>
<h3>Recommended reading</h3>
<p><a href="http://blog.redturtle.it/how-to-write-funkload-test-in-few-minutes">http://blog.redturtle.it/how-to-write-funkload-test-in-few-minutes</a></p>
<p><a href="http://www.martinaspeli.net/articles/tools-for-a-successful-plone-project">http://www.martinaspeli.net/articles/tools-for-a-successful-plone-project</a></p>]]></content:encoded>
    <dc:publisher>No publisher</dc:publisher>
    <dc:creator>Nicola Senno</dc:creator>
    <dc:rights></dc:rights>
    
      <dc:subject>web</dc:subject>
    
    
      <dc:subject>funkload</dc:subject>
    
    
      <dc:subject>Monitoring</dc:subject>
    
    
      <dc:subject>python</dc:subject>
    
    
      <dc:subject>Plone</dc:subject>
    
    <dc:date>2013-03-26T08:10:00Z</dc:date>
    <dc:type>Weblog Entry</dc:type>
  </item>


  <item rdf:about="http://blog.redturtle.it/rt.atmigrator-pensioniamo-vecchi-tipi-con-un-click">
    <title>rt.atmigrator: pensioniamo i vecchi tipi con un click</title>
    <link>http://blog.redturtle.it/rt.atmigrator-pensioniamo-vecchi-tipi-con-un-click</link>
    <description>Archetype che non servono più e contenuti da migrare in un altro tipo? Un prodotto ci può aiutare a concedere loro il meritato riposo in modo facile ed intuitivo</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<blockquote class="pullquote">Di cosa potrei parlare? Cosa ho fatto ultimamente di interessante da poter condividere?</blockquote>
<p>Quando sto per scrivere un nuovo post per il blog, il problema è sempre il solito: trovare un argomento interessante da proporre.</p>
<p>Sfortunatamente per voi, la risposta è sempre la stessa: <strong>migrazioni!</strong></p>
<a name="anchor-breaktext"></a><div class="breakText">Ormai le migrazioni sono diventate il mio pane quotidiano. Il lavoro dell'ultimo anno è stato prevalentemente quello di prendere per mano <strong>vecchi e appesantiti portali Plone</strong> e dargli nuova vita <strong>migrandoli alla versione più aggiornata</strong>.</div>
<p>Come già detto in un precedente <a href="http://blog.redturtle.it/content-type-products-contentmigration" class="internal-link">articolo</a>, spesso le migrazioni sono anche il momento ideale in cui fare un'analisi del portale e individuare eventuali <strong>archetypes creati ad hoc</strong> che, col tempo, sono <strong>diventati inutili o addirittura da eliminare</strong>, perché mai utilizzati correttamente.</p>
<p><img src="http://blog.redturtle.it/topic_images/recycle_logo.gif/@@images/dfcdee5f-a6c5-429b-979c-93a4cf9672dd.jpeg" alt="recycle" class="image-right" title="recycle" />Se quei contenuti li vogliamo proprio eliminare, li cancelliamo direttamente dal portale e non ci si pensa più.<br />Discorso diverso, invece, se questi vanno <strong>mantenuti e</strong> magari <strong>"<i>convertiti</i>" in qualcosa di più standard</strong>, come ad esempio i contenuti base di Plone.</p>
<p>Ultimamente ho dovuto pensare proprio a come migrare 4-5 vecchi Archetypes ormai inutilizzati e farli diventare dei tipi base di Plone (Cartelle, Pagine ed Eventi).</p>
<p>La prima idea è stata quella di creare una serie di procedure come descritto nell'articolo di cui parlavo prima, ma poi mi sono chiesto se non esistesse un modo per rendere parametrizzabile questa operazione senza dover scrivere ogni volta 200 metodi uguali.</p>
<p>Visto che la migrazione che mi interessava era molto base e non avevo bisogno di eseguire nessuna operazione intermedia, ho deciso di creare un piccolo prodottino che mi aiutasse: <a class="external-link" href="https://pypi.python.org/pypi/rt.atmigrator">rt.atmigrator</a>.</p>
<p>Si tratta di un pacchetto che <strong>va inserito nel buildout e non ha bisogno di essere installato</strong>.</p>
<p>Fornisce una semplice vista (<i>http://url-del-sito/@@migrate-types</i>) che non fa altro che chiedere all'utente 2 cose:</p>
<ul>
<li>Il <strong>tipo di partenza</strong> (selezionabile tra i tipi aggiungibili nel portale)</li>
<li>Il <strong>tipo di destinazione</strong> (selezionabile tra i tipi aggiungibili nel portale).</li>
</ul>
<p><img src="http://blog.redturtle.it/topic_images/atmigrator.png" alt="atmigrator" class="image-inline" title="atmigrator" /></p>
<p>Una volta confermato, viene lanciato un metodo come quelli già descritti, che esegue la migrazione con <a class="external-link" href="https://pypi.python.org/pypi/Products.contentmigration">Products.contentmigration</a> utilizzando come parametri i 2 tipi impostati nel form.</p>
<p>Completata la migrazione, <strong>nel log c'è una descrizione completa delle operazioni svolte</strong> (ed eventualmente il traceback degli errori) e l'utente viene informato di quanti elementi sono stati aggiornati.</p>
<p>Il prodotto di per sé è molto semplice, dato che esegue una migrazione base da un tipo ad un altro.<br />Nulla vieta però di prevedere, in futuro, anche delle evoluzioni e supportare, ad esempio, una gestione di filtri per determinare i contenuti da migrare (oltre al solo tipo, magari anche un percorso o lo stato di pubblicazione), oppure delle operazioni pre e post migrazione per determinati tipi.</p>
<p>Il sorgente è disponibile su <a class="external-link" href="https://github.com/RedTurtle/rt.atmigrator">github</a>, quindi si può consultare ed eventualmente modificare in un attimo.</p>]]></content:encoded>
    <dc:publisher>No publisher</dc:publisher>
    <dc:creator>Andrea Cecchi</dc:creator>
    <dc:rights></dc:rights>
    
      <dc:subject>migration</dc:subject>
    
    
      <dc:subject>Archetypes</dc:subject>
    
    
      <dc:subject>Plone</dc:subject>
    
    <dc:date>2013-03-20T08:00:00Z</dc:date>
    <dc:type>Weblog Entry</dc:type>
  </item>


  <item rdf:about="http://blog.redturtle.it/quando-la-sicurezza-in-plone-e-importante-reindexobjectsecurity">
    <title>Quando la sicurezza in Plone è importante: reindexObjectSecurity</title>
    <link>http://blog.redturtle.it/quando-la-sicurezza-in-plone-e-importante-reindexobjectsecurity</link>
    <description>Quando gli indici introdotti da prodotti aggiuntivi hanno a che fare con la sicurezza del sito, è meglio prendere alcune precauzioni per evitare problemi</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Per chiunque sviluppi con Plone, diventa presto chiara l'importanza del catalogo e, contemporaneamente, la necessità di <strong>mantenere il catalogo del sito aggiornato</strong>.</p>
<p>L'API principale a cui si fa riferimento per aggiornare lo stato di un contenuto nel catalogo Plone è la chiamata a <strong>reindexObject</strong>:</p>
<pre>&gt;&gt;&gt; context.setTitle('Nuovo titolo')<br />&gt;&gt;&gt; context.reindexObject()<br />&gt;&gt;&gt; context.title()<br />'Nuovo titolo'</pre>
<p>Fin qui, nulla di nuovo.</p>
<a name="anchor-breaktext"></a><div class="breakText"></div>
<p>In alcuni casi è possibile limitare gli indici aggiornati a un sottoinsieme di quelli esistenti.</p>
<pre>&gt;&gt;&gt; context.setTitle('Nuovo titolo')<br />&gt;&gt;&gt; context.reindexObject(idxs['Title', 'sortable_title', 'SearchableText'])<br />&gt;&gt;&gt; context.title()<br />'Nuovo titolo'</pre>
<p>In base all'attributo modificato, vale la pena aggiornare tutti gli indici che lo riguardano.</p>
<h2>Quando la sicurezza incontra la ricerca</h2>
<p><img src="http://blog.redturtle.it/topic_images/MorePaperPeople.jpg/@@images/118a359e-7d62-465d-9cec-9f5f418c1cf4.jpeg" alt="Meeting" class="image-right" title="Meeting" />Un fatto meno noto: <strong>il catalogo di Plone è usato anche nella gestione della sicurezza</strong>.<br />In particolare esiste un indice dal nome <strong>allowedRolesAndUsers</strong> esplicitamente usato per una verifica di sicurezza: capire se un utente ha accesso a un contenuto (in pratica viene memorizzato nel catalogo se gli utenti hanno il permesso di "<strong>View</strong>" sul contenuto).</p>
<p>Perché tutto questo? L'alternativa sarebbe disastrosa in termini di prestazioni: caricare tutti i documenti risultanti dalla ricerca e verificare il controllo di sicurezza direttamente su questi.<br />Tale operazione può diventare molto lenta e dispendiosa, se pensiamo che una semplice ricerca testuale può portare a migliaia di risultati in un sito mediamente popolato.</p>
<p>E' quindi importante che <strong>questo indice sia sempre aggiornato</strong>. Per questo motivo, ogni volta che viene effettuata un'operazione che comporta un cambio di sicurezza di un contenuto (principalmente modifiche nella pagina di condivisione), l'indice viene aggiornato automaticamente.</p>
<p>Dato che una semplice chiamata al metodo <i>reindexObject</i> può essere relativamente dispendiosa (tenete sempre presente che Plone potrebbe indicizzare anche i file allegati e che l'operazione di re-indicizzazione di un file può essere piuttosto lenta), esiste un altro metodo che viene utilizzata al suo posto: <strong>reindexObjectSecurity</strong>.<br />Nel funzionamento base di Plone, questa chiamata si occupa di aggiornare solo l'indice <i>allowedRolesAndUsers</i> introdotto sopra.</p>
<h2>Sicurezze alternative</h2>
<p><img src="http://blog.redturtle.it/topic_images/5894290438_493dd4802c_o.jpg/@@images/81948fc8-a18a-43f3-8235-cc9a7468adf6.jpeg" alt="Security cams" class="image-right" title="Security cams" />Ma è vero che l'unico indice legato alla sicurezza sia allowedRolesAndUsers?<br />Nell'uso quotidiano di Plone sì, ma esistono alternative.</p>
<p>Vi porto due esempi.</p>
<h3>collective.portlet.truereview</h3>
<p>Sto parlando di un prodotto poco noto e di qualche anno fa: <a class="external-link" href="https://pypi.python.org/pypi/collective.portlet.truereview/">collective.portlet.truereview</a>.</p>
<p>Questo prodotto applica lo stesso principio utilizzato col permesso "<i>View</i>" dall'indice <i>allowedRolesAndUsers</i> per un nuovo permesso legato all'attività di revisione dei contenuti: "<i>Review portal content</i>".<br />Per fare questo viene creato un nuovo indice: <i>reviewerRolesAndUsers</i>.</p>
<p>Lo scopo del prodotto è fornire una portlet di revisione alternativa per Plone che, a differenza di quella ufficiale, non richieda il caricamento del contenuto.<br /><i>NB</i>: il prodotto è fermo dal 2009, non sono certo che funzioni ancora ma lo trovo piuttosto didattico.</p>
<h3>collective.localrolesdatatables</h3>
<p>Il secondo esempio è legato al più recente <a class="external-link" href="http://plone.org/products/collective.localrolesdatatables/">collective.localrolesdatatables</a>.</p>
<p>Questo prodotto vuole fornire una vista che permetta di ispezionare lo stato della sicurezza e delle condivisioni in un sito Plone.<br />Per fare questo è necessario capire su quali contenuti ci siano effettivamente delle personalizzazioni locali della sicurezza, ovviamente senza caricare i contenuti per non ricadere nel solito problema di prestazioni (ormai ci siamo capiti, vero?!).<br />L'approccio usato è quello di creare un nuovo indice "<strong>hasLocalRoles</strong>", un valore booleano che indica se un contenuto ha ruoli locali impostati o meno.</p>
<h2>Espandere il funzionamento di reindexObjectSecurity</h2>
<p><img src="http://blog.redturtle.it/topic_images/bingbang.jpg/@@images/35839ef6-0211-4940-b28f-61007cbbed77.jpeg" alt="Universe expanding" class="image-left" title="Universe expanding" />E' stato proprio utilizzando di recente <i>collective.localrolesdatatables</i> che mi sono imbattuto in un bug (di cui sono certo soffra anche <i>collective.portlet.truereview</i>):<br />il prodotto funziona a dovere, ma se la sicurezza di un contenuto viene aggiornata, l'indice "hasLocalRoles" non viene modificato a sua volta, almeno non fin quando l'intero documento verrà modificato (e quindi completamente reindicizzato).</p>
<p>Qual è il problema? Il metodo <strong><i>reindexObjectSecurity</i> "non sa" che anche questo indice fa parte della sicurezza del sito</strong>.</p>
<p>Come risolvere?</p>
<p>Se andiamo ad analizzare l'implementazione di <i>reindexObjectSecurity</i>, troviamo questa riga di codice:</p>
<pre>catalog.reindexObject(ob, idxs=self._cmf_security_indexes,<br />                      update_metadata=0, uid=brain_path)</pre>
<p>Viene quindi chiesto di reindicizzare nel catalogo il documento (<i>ob</i>) e di limitarsi agli indici definiti nella tupla <i>self._cmf_security_indexes</i> (quindi non tutti gli indici).<strong> </strong></p>
<p><strong>_cmf_security_indexes</strong> è un attributo di classe definito per <strong>CatalogAware</strong>, nel pacchetto <i>Products.CMFCore</i>. La sua definizione è la seguente:</p>
<pre>_cmf_security_indexes = ('allowedRolesAndUsers',)</pre>
<p>La soluzione è molto semplice: estendere la lista di indici registrati in questo attributo (<a class="external-link" href="https://github.com/collective/collective.localrolesdatatables/blob/8319deb4aef3d8db1803f1823071052130b28ce4/collective/localrolesdatatables/__init__.py">qui</a> come ho modificato <i>collective.localrolesdatatables</i>):</p>
<pre>from Products.CMFCore.CMFCatalogAware import CatalogAware<br /><br />CatalogAware._cmf_security_indexes += ('mioNuovoSecurityIndex',)</pre>
<h3>Problemi?</h3>
<p>Questo tipo di intervento ha un effetto collaterale: modifica l'attributo <strong>a livello di classe</strong> e si rispecchia quindi su <i>tutti</i> i siti Plone presenti nell'installazione. Potreste anche trovarvi nella situazione in cui il prodotto che necessita di questa modifica sia installato su un solo sito Plone, quindi il nuovo indice non sia presente in altri, eppure la modifica sia comunque applicata.</p>
<p>E' un problema? Per fortuna no!<br />Il catalogo Plone è molto tollerante: se viene chiesta la reindicizzazione di un indice non esistente, questo fallisce l'operazione senza sollevare eccezioni.</p>
<p><span class="discreet">L'immagine di testata è di <a class="external-link" href="http://www.flickr.com/photos/adulau/">Alexandre Dulaunoy</a>.</span></p>]]></content:encoded>
    <dc:publisher>No publisher</dc:publisher>
    <dc:creator>Luca Fabbri</dc:creator>
    <dc:rights></dc:rights>
    
      <dc:subject>products</dc:subject>
    
    
      <dc:subject>Plone</dc:subject>
    
    
      <dc:subject>Archetypes</dc:subject>
    
    
      <dc:subject>plone.it</dc:subject>
    
    <dc:date>2013-03-12T08:00:00Z</dc:date>
    <dc:type>Weblog Entry</dc:type>
  </item>


  <item rdf:about="http://blog.redturtle.it/e-uscito-il-buildout-2.0-posso-rilanciare-il-mio-buildout">
    <title>E' uscito il Buildout 2.0! Posso rilanciare il mio buildout?</title>
    <link>http://blog.redturtle.it/e-uscito-il-buildout-2.0-posso-rilanciare-il-mio-buildout</link>
    <description>Viene rilasciata una nuova versione di un pacchetto, e per molti Plonisiti è il caos. Vediamo come usare (o non usare) il Buildout 2.0</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Non è molto che è uscita la versione <strong>2.0</strong> di <a class="external-link" href="https://pypi.python.org/pypi/zc.buildout/2.0.1">zc.buildout</a> e, come spesso accade, i buildout, soprattutto quelli un po’ più vecchi, non prendono di buon grado l’aggiornamento.<br />Nel caso di questo pacchetto, le cause sono alcuni import che sono cambiati o sono stati spostati.</p>
<p>Il <strong>Buildout 2.0</strong> fa un taglio netto con il passato che, con le versioni 1.6 e 1.7, aveva come obiettivo principale quello di isolare il più possibile il buildout dalla componente <strong>Python</strong>. Ma il compito si è rivelato troppo difficile da implementare, e quindi si è scelto di abbandonare questa strada e lasciare all’utilizzatore di decidere tramite l'utilizzo di <i>virtualenv</i>.</p>
<p>Non è però in questo articolo che voglio analizzare le modifiche apportate a questo componente (che potete comunque trovare <a class="external-link" href="https://pypi.python.org/pypi/zc.buildout/2.0.1#id4">qui</a>). Oggi vediamo cosa fare per far funzionare i <i>nostri</i> bulidout.</p>
<a name="anchor-breaktext"></a><div class="breakText"></div>
<h2>Rimanere ancorati al passato.</h2>
<blockquote class="pullquote">Tutto dipende dal bootstrap.py presente nel vostro buildout.</blockquote>
<p>Se vi interessa rimanere sulle versioni <strong>1.x</strong><strong>,</strong><strong> </strong>allora potete usare questo <strong>bootstrap.py</strong>: contiene una restrizione sulla versione di <i>zc.buildout</i> che deve essere minore di 2.0 - <a class="external-link" href="http://downloads.buildout.org/1/bootstrap.py">http://downloads.buildout.org/1/bootstrap.py</a>.</p>
<p>Ma se non vi sentite troppo sicuri nel sostituire il <i>bootstrap.py</i> del vostro buildout, c’è una seconda soluzione, suggerita in risposta a <a class="external-link" href="http://stackoverflow.com/questions/14801416/zc-buildout-stopped-working-importerror-no-module-named-apport-fileutils">questo bug report</a> su stack overflow. <br />Dovrete semplicemente rilanciare il bootstrap del vostro buildout  forzando la versione di <i>zc.buildout</i> in questo modo:</p>
<pre><br />     python bootstrap.py -v 1.7.1<br /> </pre>
<p>Tuttavia, con versioni molto vecchie del <i>bootstrap.py</i>, potreste ritrovarvi nel caso in cui non sia possibile forzare la versione; allora dovrete per forza aggiornare il file con la versione di cui sopra, per poi eseguire il comando forzando <i>zc.buildout</i> all’ultima versione precedente alla 2.0; al momento, questa: <a class="external-link" href="https://pypi.python.org/pypi/zc.buildout/1.7.1">https://pypi.python.org/pypi/zc.buildout/1.7.1</a>.</p>
<h2>Il nuovo che avanza.</h2>
<p>Per usare la versione <strong>2.0</strong> di <i>zc.buildout</i> vi consiglio di utilizzare questa versione del bootstrap: <a class="external-link" href="http://downloads.buildout.org/2/bootstrap.py">http://downloads.buildout.org/2/bootstrap.py</a>.</p>
<p>In questo caso, però, vi potreste trovare nella situazione inversa, ovvero: dopo aver lanciato il solito comando "<i>./bin/buildout -N"</i>, non trovate la nuova versione di <i>zc.buildout</i>.</p>
<p>La causa è da attribuire alla presenza di <strong>buildout.dumppickedversions</strong> che ha fatto il pin di alcune versioni e, quindi, lanciando il buildout con il <i>“-N”</i> (pratica più che corretta!), la nuova versione per <i>zc.buildout</i> non è stata presa in considerazione. <br />Magari avete specificato il <i>dumppickedversions</i> nelle <i>extensions</i> nel vostro <i>buildout.cfg</i> e state pensando di rimuoverlo; ma nelle ultime versioni del buildout è automaticamente incluso. <br />La soluzione, consigliata da Reinout van Rees nel suo <a class="external-link" href="http://reinout.vanrees.org/weblog/2013/02/12/prevent-buildout-problems.html">post</a>, è molto semplice: fate il pin di questi due prodotti nel<i> [versions]</i> del vostro file di configurazione e avrete il vostro pacchetto aggiornato :)</p>
<pre><br />    [versions]
    zc.buildout = 2.0.1
    zc.recipe.egg = 2.0.0a3<br /> </pre>]]></content:encoded>
    <dc:publisher>No publisher</dc:publisher>
    <dc:creator>Mirco Angelini</dc:creator>
    <dc:rights></dc:rights>
    
      <dc:subject>Plone 4</dc:subject>
    
    
      <dc:subject>buildout</dc:subject>
    
    
      <dc:subject>Plone</dc:subject>
    
    <dc:date>2013-03-11T10:55:00Z</dc:date>
    <dc:type>Weblog Entry</dc:type>
  </item>


  <item rdf:about="http://blog.redturtle.it/creazione-plugin-gestire-gruppi-virtuali-plone">
    <title>Creazione di plugin per gestire gruppi virtuali in Plone</title>
    <link>http://blog.redturtle.it/creazione-plugin-gestire-gruppi-virtuali-plone</link>
    <description>Una funzionalità Plone che sfrutto pochissimo è il meccanismo dei gruppi virtuali, quello che sta dietro al gruppo "Authenticated User". Analizziamolo!</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Poche sono state le volte in cui ho avuto bisogno di sfruttare il gruppo che in Plone è chiamato <strong>"Authenticated Users"</strong>. Si tratta di un gruppo virtuale creato in modo tale per cui ogni utente autenticato risulta appartenere, fra gli altri, a questo gruppo in modo automatico.</p>
<a name="anchor-breaktext"></a><div class="breakText">E' utile sapere come creare questi gruppi per poterli sfruttare quando si presentano casi d'uso in cui una buona profilazione degli utenti passa per un determinato raggruppamento, soprattutto perché possiamo fare in modo che questo raggruppamento sia automatizzato.</div>
<a name="anchor-breaktext"></a><div class="breakText"></div>
<h3>Il caso</h3>
<blockquote class="pullquote">Come fa Plone a gestire<br /> i gruppi virtuali??</blockquote>
<p>Partiamo da un caso concreto, al quale sto lavorando in questi giorni. Ci sono degli user che, tramite un sistema di autenticazione federato, si collegano al sito. Quando questi si collegano per la prima volta, viene creato un utente vero e proprio nel sito Plone a cui viene impostata una proprietà (supponiamo sia "caratteristica_x=True"). Devo fare in modo di raggrupparli automaticamente.</p>
<p>In Plone tutto questo si fa con <a class="external-link" href="https://pypi.python.org/pypi/Products.PluggableAuthService/"><strong>PAS</strong></a> e i suoi plugin in <a class="external-link" href="https://pypi.python.org/pypi/Products.PlonePAS/"><strong>PlonePAS</strong></a> (si può vedere della documentazione <a class="external-link" href="http://plone.org/documentation/manual/developer-manual/users-and-security/pluggable-authentication-service"><strong>qui</strong></a>). E proprio in quest'ultimo troviamo il <a class="external-link" href="https://github.com/plone/Products.PlonePAS/tree/master/Products/PlonePAS"><strong>codice</strong></a> che ci mostra come creare e gestire il gruppo degli "Authenticated User"; codice che si trova nei seguenti file:</p>
<ul>
<li>plugins/autogroup.py</li>
<li>__init__.py</li>
<li>Extensions/Install.py</li>
</ul>
<p>Negli ultimi due moduli c'è il codice per registrare il plugin e installarlo. Si tratta di operazioni banali, e ci tornerò sopra più avanti quando mostrerò come creare un nuovo plugin. Nel primo modulo, invece, c'è tutta la logica che riguarda il funzionamento del plugin, ed è questo che mi interessa analizzare.</p>
<h3>Analisi del plugin</h3>
<p>Il plugin è generato tramite la classe <strong>AutoGroup</strong>. I meccanismi di PAS si basano sull'implementazione di interfacce tramite cui la classe si impegna a fornire un set di metodi; nella classe in analisi troviamo:</p>
<blockquote class="pullquote">Tramite l'implementazione di interfacce, un plugin fornisce dei metodi e "promette" dei comportamenti</blockquote>
<ul>
<li><strong>IGroupEnumerationPlugin</strong>: fornisce metodi per l'enumerazione e la ricerca di gruppi</li>
<li><strong>IGroupsPlugin</strong>: fornisce un metodo tramite il quale, dato un principal (utente o gruppo) si ritornano tutti i gruppi a cui questo principal appartiene</li>
<li><strong>IGroupIntrospection</strong>: fornisce metodi per ottenere da un plugin gruppi e utenti dei gruppi</li>
<li><strong>IPropertiesPlugin</strong>: fornisce un metodo per ottenere le proprietà (titolo e descrizione) di un gruppo.</li>
</ul>
<p>Per il nostro use case, è tutto corretto e l'unico comportamento che ci interessa modificare è quella fornito da <strong>IGroupsPlugin</strong>, tramite cui decidiamo se uno user è nel gruppo oppure no.</p>
<h3>Creiamo un nuovo plugin</h3>
<p>Per farlo, percorriamo i passi già citati sopra:</p>
<ul>
<li>si crea un plugin</li>
<li>si registra</li>
<li>lo si installa nel sistema.</li>
</ul>
<p>Come detto, modifichiamo una sola funzionalita, data dal metodo <strong>getGroupsForPrincipal</strong>:</p>
<pre><br />from App.class_init import InitializeClass
from Products.PlonePAS.plugins.autogroup import AutoGroup<br />from Products.PageTemplates.PageTemplateFile import PageTemplateFile

manage_addCustomGroupForm = PageTemplateFile("./zmi/CustomUsersGroupForm",
                                           globals())<br /><br />
def manage_addCustomGroup(self,
                          id,
                          title='',
                          group='',
                          description='',
                          RESPONSE=None):
    """Add an Auto Group plugin."""

    plugin = CustomUsersGroup(id, title, group, description)
    self._setObject(id, plugin)

    red_to = "%s/manage_workspace?manage_tabs_message=Custom+Users+Group+plugin+added"
    if RESPONSE is not None:
        return RESPONSE.redirect(red_to % self.absolute_url())<br /><br />
class CustomUsersGroup(AutoGroup):
    meta_type = "Custom users group"

    # IGroupsPlugin implementation.
    def getGroupsForPrincipal(self, principal, request=None):
        if principal.getProperty('caratteristica_x'):
            return (self.group,)<br />        return ()

InitializeClass(CustomUsersGroup)<br /> </pre>
<p>Gli altri metodi nel codice sopra, <strong>manage_addCustomGroup</strong> e <strong>manage_addCustomGroupForm</strong>, sono utilizzati per l'aggiunta e la gestione del plugin in <strong>ZMI</strong> dentro la <strong>acl_users</strong> del sito: dobbiamo infatti creare un'istanza del plugin per avere il nuovo gruppo a disposizione.</p>
<p>Una volta scritto il codice del plugin lo dobbiamo registrare nell'inizializzazione del pacchetto:</p>
<pre><br />from Products.PluggableAuthService import registerMultiPlugin<br /><br />try:
    registerMultiPlugin(CustomUsersGroup.meta_type)
except RuntimeError:
    # Don't explode upon re-registering the plugin:
    pass

def initialize(context):
    context.registerClass(CustomUsersGroup,
                           permission=add_user_folders,
                           constructors=(manage_addCustomGroupForm,
                                         manage_addCustomGroup),
                           visibility=None
                           )

</pre>
<p>Fatto questo, possiamo considerare l'attività di sviluppo terminata. Se vogliamo istanziare il plugin con l'installazione del pacchetto, dobbiamo creare un <strong>import step</strong> dentro il quale fare qualcosa di questo tipo:</p>
<pre> 
    ....
    portal = context.getSite()
    acl_users = getToolByName(portal, 'acl_users')
    plugins = acl_users.plugins
    if not 'custom_users_group' in acl_users.objectIds():
        manage_addCustomGroup(acl_users,
                            "custom_users_group",
                            "Custom users (Virtual Group)",
                            "CustomUsersGroup",
                            "Automatic Custom Group Provider")
        for interface in [IGroupsPlugin,
                          IPropertiesPlugin,
                          IGroupEnumerationPlugin,
                          IGroupIntrospection]:
            plugins.activatePlugin(interface, "custom_users_group"<br />    ....<br />
</pre>
<p>In questo modo si aggiunge il plugin alla acl_users del sito e si attivano le interfacce per le funzionalità che il plugin dovrà gestire.</p>
<h3>Conclusioni</h3>
<p>Finito! Come possiamo vedere a questo punto nella gestione gruppi del sito, abbiamo un gruppo in più, che si comporta esattamente come il gruppo "Authenticated Users", tranne che per la condizione di appartenenza al gruppo; tale gruppo è disponibile anche nello sharing.</p>
<p>Per testarne il funzionamento, possiamo accedere al sito con un utente e verificare che non abbia permessi di nessun tipo. Dalla gestione gruppi possiamo assegnare il ruolo di Manager al gruppo appena creato e tornare a verificare con l'utente di cui sopra, che ora ha permessi da Manager nel portale.</p>
<p><span class="discreet">L'immagine in testata è di <a class="external-link" href="http://www.flickr.com/photos/denisemccooeyphoto/">evildan2</a></span></p>]]></content:encoded>
    <dc:publisher>No publisher</dc:publisher>
    <dc:creator>Luca Bellenghi</dc:creator>
    <dc:rights></dc:rights>
    
      <dc:subject>PAS</dc:subject>
    
    
      <dc:subject>Plone</dc:subject>
    
    
      <dc:subject>plone.it</dc:subject>
    
    <dc:date>2013-02-26T09:55:00Z</dc:date>
    <dc:type>Weblog Entry</dc:type>
  </item>


  <item rdf:about="http://blog.redturtle.it/semplici-regole-finire-casella-spam-gmail">
    <title>Semplici regole per finire... dritti nella casella di spam di Gmail!</title>
    <link>http://blog.redturtle.it/semplici-regole-finire-casella-spam-gmail</link>
    <description>Breve introduzione all'invio massivo di posta elettronica da applicativo, con riferimento alle linee guida di Google</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>L'invio massivo di posta da applicazioni web può rivelarsi un grattacapo, in particolare se il vostro target è composto per la maggior parte da utenti <strong>Google.</strong> Ma la questione può essere risolta facilmente; in realtà dipende dal risultato che si vuole ottenere.</p>
<p>Nel caso in cui l'obbiettivo sia quello di far arrivare l'email da voi inviata <img src="http://blog.redturtle.it/uploads/bers.png" alt="" class="image-right" title="" /><br />dritta nello <i>spam</i> di Gmail, basta seguire due semplici regole:</p>
<ul>
<li>sottovalutare l'attività di invio email</li>
<li>ignorare le linee guida fornite dal provider.</li>
</ul>
<p> </p>
<p>Facile, no?</p>
<p>Vorrei evitare di dire che lo <i>spam</i> è un grosso problema per la maggior parte degli utilizzatori di internet, ma ormai l'ho detto e allora, già che ci sono, aggiungo anche che <strong>Gmail </strong>in tal senso ha la guardia ben alzata.</p>
<a name="anchor-breaktext"></a><div class="breakText">Ahimè nella realtà, contrariamente da quanto espresso nel titolo del mio post, si vuole raggiungere la casella <i>inbox</i> e non quella dedicata allo <i>spam</i>, quindi il problema da risolvere è di altro livello e le due "regoline" indicate sopra non vanno più bene. Serve maggiore attenzione.</div>
<p>Quindi, invertendo il loro significato, si ottiene che la prima regola è rassegnarsi al fatto che l'attività di invio messaggi di posta (parlo ovviamente di invio massivo), va gestita con un certo criterio e va seguita con altrettanta attenzione.</p>
<p>Non basta, per esempio, prendere una delle tante librerie disponibili per il vostro framework preferito e iniziare a spedire messaggi a tutto il mondo, perché le email verranno probabilmente inviate ma in molti casi non raggiungeranno mai la casella <i>inbox</i>.</p>
<p>La seconda regola impone di seguire le linee guida fornite dai provider, nel nostro caso quelle fornite da Google.</p>
<p>E' chiaro, a questo punto, che bisogna prendersi un po' di tempo e studiare il problema.</p>
<h2>Concetti base</h2>
<p>Da marzo 2012, <strong>Google</strong> aggiunge in cima a ogni email marcata come <i>spam</i>, un messaggio che indica il motivo per cui è stata classificata come tale, come nell'esempio qui sotto:</p>
<p><img src="http://blog.redturtle.it/uploads/copy_of_message.png" alt="" class="image-inline" title="" /></p>
<p>Ci sono due principali motivi per cui un messaggio viene marcato come <i>spam</i>.</p>
<h3>Primo</h3>
<p><strong>Google</strong> considera la vostra email un potenziale falso o un tentativo di "<i>phishing"</i>, marca il messaggio come <i>spam</i> e aggiunge una delle seguenti diciture:</p>
<ul>
<li>Our systems couldn't verify that this message was really sent by yyy.com</li>
<li>This message may not have been sent by xxx@yyy.com</li>
<li>Similar messages were used to steal people's personal information.<br />Unless you trust the sender, don't click links or reply with personal information.</li>
</ul>
<h3>Secondo</h3>
<p><strong>Google</strong> considera il messaggio semplicemente <i>spam</i>, lo marca come tale e aggiunge qualcosa del tipo:</p>
<ul>
<li>It contains content that's typically used in <i>spam</i> messages</li>
<li>It's similar to messages that were detected by our <i>spam</i> filters</li>
<li>You previously marked messages from xxx@yyy.com as <i>spam</i>.</li>
</ul>
<p> </p>
<p>E' importante capire la differenza tra questi due diversi motivi, perché nel primo caso si risolve in modo relativamente facile - probabilmente si tratta solo di un problema di configurazione.<br />Nel secondo caso, invece, la questione è più complessa, perché <strong>Google</strong> decide cosa è <i>spam</i> secondo parametri e criteri non del tutto trasparenti.</p>
<p>Per quanto riguarda i contenuti, inizialmente Google come altri provider, cercava di separare il legittimo dall'illegittimo basandosi sull'analisi del testo alla ricerca di parole chiave sospette; ma questa strategia è stata abbandonata a favore di un'altra.</p>
<p>Negli ultimi anni la tendenza è di filtrare i messaggi in base al comportamento osservato nei destinatari stessi. Mi spiego meglio: se le email inviate per esempio da un indirizzo specifico vengono marcate come posta non desiderata<i> </i>o scartate dalla maggior parte degli utenti, Google assume che quell'indirizzo invia messaggi non graditi, e quindi diventa <i>spam.</i></p>
<p>Il meccanismo è complesso, ma a grandi linee funziona come un sistema di rating alimentato dai destinatari, che in questo modo determinano quello che non vogliono ricevere.</p>
<p>Un primo spunto per risolvere il problema può venire dalla guida ufficiale <a class="external-link" href="http://support.google.com/mail/bin/answer.py?hl=en&amp;answer=81126">Bulk Senders Guidelines</a> di Google, della quale riporto alcune sezioni tradotte e interpretate.</p>
<h2></h2>
<h2>Le linee guida</h2>
<a name="anchor-breaktext"></a><div class="breakText"></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div>Google suddivide l'argomento in sette sezioni:</div>
<div id="_mcePaste">
<ul>
<li>Autenticazione e identificazione</li>
<li>Sottoscrizione</li>
<li>Cancellazione</li>
<li>Formato</li>
<li>Consegna</li>
<li>Third-Party Senders</li>
<li>Affiliate Marketing Programs.</li>
</ul>
</div>
<div>
<h2>Autenticazione e identificazione</h2>
</div>
<div id="_mcePaste"><img src="http://blog.redturtle.it/uploads/mascherasmall.jpg" alt="" class="image-right" title="" />Con autenticazione e identificazione si descrive la capacità da parte di chi fornisce il servizio di posta (provider) di riconoscere il mittente del messaggio per cercare di prevenire il fenomeno conosciuto come <a class="external-link" href="http://en.wikipedia.org/wiki/Email_spoofing">email spoofing</a>.</div>
<div><br /> Le tecniche di autenticazione e identificazione maggiormente utilizzate prevedono:</div>
<div id="_mcePaste">
<ul>
<li>evitare il più possibile l'invio di email per lo stesso servizio da IP diversi</li>
<li>mantenere un <a class="external-link" href="http://it.wikipedia.org/wiki/Risoluzione_DNS_inversa">reverse DNS</a> dell'indirizzo utilizzato per l'invio; inoltre, il rDNS deve puntare al dominio di invio</li>
<li>utilizzare sempre lo stesso indirizzo email nel campo "From" in tutte le email mandate dalla stessa applicazione</li>
<li>utilizzare il protocollo <a class="external-link" href="http://it.wikipedia.org/wiki/Sender_Policy_Framework">SPF </a>applicato al DNS del dominio di invio, che permette di definire da dove vengono inviate le email</li>
<li>autenticazione con <a class="external-link" href="http://en.wikipedia.org/wiki/DomainKeys_Identified_Mail">DKIM</a>.</li>
</ul>
</div>
<div id="_mcePaste"></div>
<h2 id="_mcePaste"></h2>
<h2>Sottoscrizione</h2>
<div id="_mcePaste">Per sottoscrizione si intende la modalità con cui l'utente viene iscritto o aggiunto alla lista dei destinatari di posta.</div>
<div id="_mcePaste">Gmail fa riferimento per questo punto alle mailing-list, ma è un concetto che può essere applicato anche per applicazioni che offrono un altro tipo di sevizio. La guida suggerisce di usare un approccio nel quale sia l'utente stesso a esprimere esplicitamente la volontà di volersi iscrivere nelle seguenti modalità:</div>
<div>
<ul>
<li>utilizzando un apposito form web</li>
<li>in risposta a una mail di richiesta.</li>
</ul>
</div>
<div></div>
<div id="_mcePaste"></div>
<h2 id="_mcePaste"></h2>
<h2>Cancellazione</h2>
<div></div>
<div id="_mcePaste">La cancellazione, come la sottoscrizione, deve garantire che l'utente possa scegliere se ricevere o meno messaggi dalla nostra applicazione/mailing-list: se si è fornito un sistema di iscrizione o qual si voglia sistema di inserimento del nominativo in una lista utilizzata per l'invio, deve essere fornita anche la possibilità di cancellarlo (ragionevole, direi!).</div>
<div></div>
<div></div>
<div id="_mcePaste"></div>
<div>E' consigliato quindi:</div>
<div>
<ul>
<li>inserire un link ben visibile nel corpo del messaggio che permetta la cancellazione automatica dell'utente</li>
<li>consentire di rimuovere il proprio nominativo dalla lista o al sevizio rispondendo direttamente alla mail ricevuta con un opportuno campo "oggetto"</li>
<li>nel caso si tratti di una mailing-list, fornire un "List-Unsubscribe" header che punti all'email o all'indirizzo web (URL) per la cancellazione.</li>
</ul>
</div>
<p>Inoltre è suggerito di:</p>
<div>
<ul>
<li>inviare periodicamente un messaggio di richiesta di conferma</li>
<li>indicare nella mail con quale indirizzo sono iscritti gli utenti all'applicazione o alla mailing-list.</li>
</ul>
</div>
<div id="_mcePaste"></div>
<h2 id="_mcePaste"></h2>
<h2>Formato<img src="http://blog.redturtle.it/uploads/w3c.jpg" alt="" class="image-right" title="" /></h2>
<div id="_mcePaste">
<div id="_mcePaste">In fase di valutazione del messaggio da parte del software anti-spam, anche il formato viene preso in considerazione. Bisogna quindi rispettare alcune semplici regole:</div>
<div>
<ul>
<li>tutti i messaggi devono essere redatti in accordo con lo standard <i>RFC 2822 SMTP4</i> e, se si tratta di messaggi che fanno uso di HTML, questo deve aderire allo standard <a class="external-link" href="http://www.w3.org">w3c.org</a></li>
<li>l'oggetto specificato nella mail deve avere rilevanza per il contenuto della mail, quindi è consigliato evitare di scrivere l'oggetto con un significato forviante.</li>
</ul>
</div>
</div>
<h2></h2>
<h2>Consegna</h2>
<p>Sulla consegna Google ci tiene a sottolineare che non è in grado di garantire che la posta inviata raggiunga correttamente il destinatario.<br />Riporta in ogni caso due fattori determinanti:</p>
<ul>
<li>l'utente destinatario dovrebbe avere l'indirizzo contenuto nel campo "form" tra i propri contatti</li>
<li>il destinatario, quando riceve il messaggio, deve indicare a Gmail (attraverso l'apposito tasto) che chi ha inviato il messaggio da quell'indirizzo non è da considerare come <i>spam</i> (aumenta il rating associato all'indirizzo).</li>
</ul>
<p>Questo è uno dei punti critici del sistema, perché sono i destinatari dei nostri messaggi a decidere la sorte delle email che inviamo. <strong>Google</strong> consiglia per questo motivo di utilizzare due indirizzi diversi a seconda dello scopo, per esempio: supporto e promozione.</p>
<p>E' molto probabile infatti che i messaggi di tipo promozionale finiscano nel cestino o marcati come <i>spam</i> dall'utente, con la conseguenza di abbassare il rating generale dell'indirizzo di invio; mentre i messaggi di supporto probabilmente non verranno marcati come <i>spam</i>.</p>
<p> </p>
<h2>Conclusioni<img src="http://blog.redturtle.it/uploads/martello.jpg" alt="" class="image-right" title="" /></h2>
<p>In conclusione si può dire che l'ultima parola spetta ovviamente ai provider (<strong>Google</strong> in questo caso), i quali hanno pieno potere sulla gestione delle email. Seguire le linee giuda aiuta notevolmente, tuttavia il risultato non è garantito. E' chiaro che l'argomento "posta" non va preso sottogamba: spedire è semplice, ma fare in modo che arrivi al destinatario non è un risultato scontato.</p>
<h2></h2>
<h2></h2>
<h2></h2>]]></content:encoded>
    <dc:publisher>No publisher</dc:publisher>
    <dc:creator>Nicola Senno</dc:creator>
    <dc:rights></dc:rights>
    
      <dc:subject>mail</dc:subject>
    
    
      <dc:subject>newsletter</dc:subject>
    
    
      <dc:subject>web</dc:subject>
    
    
      <dc:subject>spam</dc:subject>
    
    <dc:date>2013-02-22T10:00:00Z</dc:date>
    <dc:type>Weblog Entry</dc:type>
  </item>


  <item rdf:about="http://blog.redturtle.it/sviluppo-front-end-ottimizzare-prestazioni">
    <title>Sviluppo Front-End: ottimizzare le prestazioni</title>
    <link>http://blog.redturtle.it/sviluppo-front-end-ottimizzare-prestazioni</link>
    <description>Alcuni trucchi e consigli per migliorare la velocità dei siti web</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Per quanto riguarda lo sviluppo front-end, c'è sempre più attenzione alle <i>performances</i>, dato che favorendo la velocità dell'esperienza utente c'è un ritorno diretto in termini di soddisfazione da parte di chi fruisce il progetto web.</p>
<p>E' uscito da poco un articolo molto curato sull'argomento che ha attratto la mia attenzione:</p>
<p><strong><a class="external-link" href="http://csswizardry.com/2013/01/front-end-performance-for-web-designers-and-front-end-developers/">Front-end performance for web designers and front-end developers</a> </strong><strong>di  <a href="http://twitter.com/csswizardry" style="text-decoration: underline; ">Harry Roberts</a>.</strong></p>
<p>Nell'articolo vengono illustrati e sintetizzati molti degli argomenti relativi all'ottimizzazione dello sviluppo front-end.</p>
<p></p>
<a name="anchor-breaktext"></a><div class="breakText"></div>
<p class="callout">Si parte dalle regole basilari: gli <strong>stili css devono essere chiamati all'inizio della pagina mentre i file javascript in fondo ad essa</strong>. Questo è un punto essenziale, dato che i browser eseguono il render della pagina progressivamente e prima hanno a disposizione il css, prima ne possono iniziare il render sulla pagina, evitando di bloccarla graficamente.</p>
<p>Al contrario le chiamate javascript, bloccando i browser nel processo di download parallelo delle varie risorse, devono essere posizionate in fondo alla pagina. La loro natura bloccante deriva anche dal fatto che ogni singola risorsa js deve essere caricata nell'esatta sequenza.</p>
<p>In generale è bene <strong>fare il minor numero di chiamate possibili a risorse</strong>, cioè scaricare il minor numero di elementi effettuando così poche HTTP Request. Ogni chiamata tecnicamente può incorrere in un "DNS lookup", in un redirect o in un errore 404 di risorsa non trovata; per questo ridurle contribuisce sensibilmente ad ottimizzare l'esecuzione.</p>
<p>Idealmente si dovrebbe <strong>massimizzare il parallelismo nell'ottenere risorse</strong> da domini diversi. Dato che un browser può al massimo trattare due risorse alla volta da uno stesso dominio, possiamo moltiplicare questo numero per il numero di domini dal quale possiamo servire le risorse.</p>
<p>Molti siti conosciuti fanno uso di domini "statici" solo per questo motivo, ottenere le risorse da più domini. In abbinamento alla tecnologia CDN (Content Delivery Network), ciò consente di diminuire ulteriormente la latenza di tempo ottenendo così le risorse anche da più luoghi dislocati fisicamente nel mondo.</p>
<p>Le <strong>richieste HTTP e il tempo per la risoluzione dei nomi DNS </strong>possono quindi rappresentare uno dei principali colli di bottiglia nelle prestazioni di front-end dato il limite nello scaricamento di risorse in parallelo imposto dai browsers. D'altro canto, la tecnica dell'utilizzo di sottodomini per aumentare le possibilità parallele introduce ad ogni nuovo dominio il tempo di latenza della risoluzione del nuovo nome DNS, quindi va valutato accuratamente caso per caso se sia possibile farsi carico di questo ulteriore tempo nel progetto web di cui ci si sta occupando.</p>
<p><span>Nel caso in cui servano nuovi nomi di dominio, è utile utilizzare la tecnica del </span><span><strong>DNS prefetching</strong></span><span> attraverso la quale semplicemente si comunica in anticipo al browser il nuovo dns dal quale, poco dopo, sarà necessaria una risorsa; facendo così si riescono a evitare i tempi di attesa per la risoluzione del nuovo dominio.</span></p>
<pre>&lt;head&gt;<br />&lt;link rel="dns-prefetch" href="//widget.foo.com" /&gt;<br />&lt;/head&gt;</pre>
<p>In realtà questo introduce il concetto di prefetching generale delle risorse; oltre ai DNS, anche le altre risorse come i web fonts o le immagini chiamate dai fogli di stile possono essere chiamate in anticipo in modo da iniziarne il download leggermente prima del loro effettivo utilizzo.</p>
<p>Per fare questo esistono due vie: <br />- una sporca e sicura, che prevede di celare in un &lt;div&gt; nascosto le immagini per averle a disposizione nell'html della pagina molto in anticipo<br />- una più pulita ai puristi del codice, che è sostanzialmente sempre il link prefetching già visto per i DNS.</p>
<pre>&lt;link rel="prefetch" href="sprite.png" /&gt;<br />&lt;link rel="prefetch" href="webfont.woff" /&gt;</pre>
<p>Invece, per quanto riguarda l'<strong>ottimizzazione</strong><strong> delle chiamate css</strong><strong> </strong><strong>è fondamentale sapere che</strong><strong> </strong>non devono mai essere fatte da un un altro dns, data la loro natura bloccante sulla resa grafica della pagina; così facendo infatti si incorrerebbe nel DNS lookup, ovvero nel tempo ulteriore necessario alla risoluzione del nuovo dominio.</p>
<p>Oltre a servire il css il prima possibile nella pagina, bisogna <strong>concatenarli, ridurli al minimo rimuovendo commenti e spazi e comprimerli</strong> per diminuire il lavoro da parte del browser e dei vari sistemi di caching. I software di editing css contemporanei hanno tutti funzioni per controllare anche questi aspetti; in aggiunta, se si usano linguaggi di preprocessing dei css come sass si hanno a disposizione potenti strumenti per curare nei dettagli tali operazioni.</p>
<p>Senza entrare troppo nel dettaglio della compressione possibile usando gzip su server attraverso Apache, passiamo all'ottimizzazione delle immagini.</p>
<p>Si parte dalla ben nota tecnica di <strong>spriting delle immagini</strong>, ovvero del raggruppare in un'unica immagine tutte quelle che possono servire nel file css, in modo da ridurre al minimo il numero di http Request a questo tipo di risorsa. Anche se non tutte le immagini possono essere messe in uno sprite - ad esempio quelle da usare come sfondo, che vanno ripetute e che spesso vengono messe negli sprite con molti pixel vuoti attorno in modo da poter ottenere la ripetizione necessaria. Ma i pixel vuoti, non necessari, sono un problema nella velocità di esecuzione. L'articolo suggerisce di usare il classico "elemento di spriting", solitamente &lt;i&gt;, che ha il solo scopo di rimanere vuoto e portare l'immagine di sprite come sfondo. Ecco l'esempio di utilizzo più comune:</p>
<pre>&lt;li&gt;<br />   &lt;a href="/profile/"&gt;<br />      &lt;i class="icon icon--person"&gt;&lt;/i&gt; Profile<br />   &lt;/a&gt;<br /><br />&lt;/li&gt;<br /> 
</pre>
<p>L'articolo di Harry Roberts tocca anche il caso delle<strong> immagini Retina</strong> solitamente usate per i dispositivi mobile, in modo da garantire ad essi che hanno capacità di memoria inferiori, esperienze estetiche superiori, ma in generale l'autore ritiene che vadano scelte oculatamente. Tutto sommato esistono anche valide alternative alle immagini bitmap, come svg o font di icone.</p>
<p>Infine, l'ultimo argomento dell'articolo: <strong>le immagini JPG progressive</strong>.</p>
<p>Riguarda più che altro la velocità percepita nell'esecuzione, infatti a differenza dei JPG che si caricano per blocchi successivi, i jpg progressivi sono caricati interamente fin dall'inizio ma pixelati e solo progressivamente aumentano di dettaglio, un po' come accadeva per le vecchie gif. Ciò contribuisce molto alla percezione di rapidità visiva che avrà l'utente.</p>
<p>L'articolo portato alla vostra attenzione è ricco di approfondimenti come <a class="external-link" href="http://calendar.perfplanet.com/2012/progressive-jpegs-a-new-best-practice/">questo</a> sui jpg progressivi: il mio invito è di tornare a ricercare ogni singolo approfondimento direttamente alla fonte.</p>
<p class="discreet">Image by courtesy of: <a href="http://www.flickr.com/photos/silviacesari/" target="_blank">Silvia Cesari</a></p>]]></content:encoded>
    <dc:publisher>No publisher</dc:publisher>
    <dc:creator>Riccardo Petracchini</dc:creator>
    <dc:rights></dc:rights>
    
      <dc:subject>web</dc:subject>
    
    
      <dc:subject>javascript</dc:subject>
    
    
      <dc:subject>HTML5</dc:subject>
    
    
      <dc:subject>speed</dc:subject>
    
    
      <dc:subject>Plone</dc:subject>
    
    
      <dc:subject>css</dc:subject>
    
    <dc:date>2013-02-18T13:00:00Z</dc:date>
    <dc:type>Weblog Entry</dc:type>
  </item>


  <item rdf:about="http://blog.redturtle.it/migrazione-plone-4-tips-and-tricks">
    <title>Migrazione a Plone 4: alcuni utili tips and tricks</title>
    <link>http://blog.redturtle.it/migrazione-plone-4-tips-and-tricks</link>
    <description>Devi migrare un sito a Plone 4? Hai paura di non riuscirci? Ecco una breve guida che può aiutarti a uscire (quasi) indenne da questa avventura</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Con l’uscita di versioni aggiornate di un software (<strong>Plone</strong> nel nostro caso), ci si ritrova spesso a dover aggiornare le vecchie installazioni per tenerle al passo con le ultime versioni rilasciate e godere delle migliorie apportate e delle nuove funzionalità.</p>
<p>Negli ultimi mesi, il mio lavoro è stato principalmente quello di “<i>aggiornare</i>” dei vecchi siti e migrarli da Plone 3 a Plone 4 (lo so, in ritardo di un paio d'anni).</p>
<p>Esistono sostanzialmente due modalità per migrare un sito Plone:</p>
<ul>
<li>esportazione dei soli contenuti dal vecchio sito (per esempio con strumenti come transmogrifier) e importazione di questi in un nuovo ambiente immacolato.</li>
<li>migrazione del portale così com'è mediante il tool interno fornito da Plone stesso.</li>
</ul>
<p>La migrazione con transmogrifier, di cui abbiamo già <a class="external-link" href="http://blog.redturtle.it/2012/05/04/la-nobile-arte-della-migrazione-transmogrifier">parlato</a> precedentemente, in linea di massima è consigliata in quei casi in cui il vecchio portale potrebbe avere diverso “<i>sporco</i>” al suo interno, dovuto a svariati motivi (errori di gioventù dei programmatori, prodotti installati e mai utilizzati o mal rimossi, ecc.), oppure se si decide che parte dei contenuti attuali non servono più e si vuole portare dietro solo alcune sezioni.</p>
<p>Nel nostro caso avevamo degli ambienti abbastanza controllati, dove conoscevamo bene i prodotti installati (in parte sviluppati da noi e in parte trovati su pypi ma utilizzati da tempo) e il livello di sporcizia era minimo, ma soprattutto i portali dovevano essere migrati per intero.</p>
<a name="anchor-breaktext"></a><div class="breakText"></div>
<p class="breakText">Per questo motivo abbiamo deciso di utilizzare il tool di migrazione nativo di Plone.<br />L’utilizzo del tool è molto semplice, basta un click e fa tutto da solo, però il difficile è stato “<i>preparare</i>” i vari portali alla migrazione.<br />Il nostro problema era che dovevamo migrare una ventina di portali in sequenza e il rischio era di rimanere impantanati nelle varie procedure.<br />Dopo diverse prove e migrazioni fallite, abbiamo trovato una serie di linee guida che ci hanno aiutato a sopravvivere e che sono tornate utili anche in successive migrazioni.</p>
<h3 class="mceContentBody documentContent"><img src="http://blog.redturtle.it/topic_images/sherlock.jpg/@@images/d23a81c6-df41-48b7-9a33-56c56aa27959.jpeg" alt="sherlock" class="image-right" title="sherlock" />Analisi della situazione</h3>
<p>Come prima cosa, bisogna fare un’analisi approfondita dell’utilizzo del portale, dei prodotti installati e dei contenuti creati.<br />In questo modo si può avere una panoramica su quanti e quali contenuti sono stati effettivamente creati, quali prodotti sono veramente utilizzati e bisogna portarsi dietro, e quali sono inutilizzati e si possono rimuovere per ottimizzare ulteriormente il portale.</p>
<h3>Compatibilità dei prodotti su Plone 4</h3>
<p>Dopo l’analisi preliminare, è utile testare il corretto funzionamento dei prodotti da mantenere, su un buildout Plone 4.<br />Per quelli di terze parti scaricati da pypi, di solito non c’è bisogno di fare molto: basta una veloce ricerca su <a class="external-link" href="http://pypi.python.org/pypi">pypi</a> o su <a class="external-link" href="http://plone.org/products/">plone.org</a> e il gioco è fatto. Se poi non sono compatibili, vuol dire che o sono stati superati da altri prodotti più evoluti (e forse è meglio informarsi meglio sull'eventualità di sostituirli), oppure possiamo sempre aggiornarli noi, in modo da dare un utile contributo alla comunità.<br />I prodotti sviluppati appositamente per i clienti, invece, vanno per forza sistemati. In generale, se non si deve fare un refactoring pesante ma solo un aggiornamento, un buon inizio è quello di controllare se presi e messi su un Plone 4 girano correttamente, ed eventualmente correggere a mano a mano gli errori che si riscontrano.<br />Molto probabilmente diversi template o importazioni si romperanno, perché alcune cose in Plone 4 sono cambiate; nessun problema, visto che sul sito di plone.org c'è una guida dedicata: <a class="external-link" href="http://plone.org/documentation/manual/upgrade-guide">http://plone.org/documentation/manual/upgrade-guide</a> - in alternativa, Google o le varie mailing-list tornano sempre utili.</p>
<h3>Rimozione dei prodotti inutilizzati</h3>
<p>Il passo successivo consiste nella rimozione dei prodotti vecchi e/o inutilizzati.<br />E’ un passo importante, poiché non è consigliato portarsi dietro dei prodotti che non vengono utilizzati, o che già sappiamo non essere compatibili su Plone 4. Per questo vanno rimossi prima di effettuare una migrazione.</p>
<blockquote class="pullquote">Promemoria: fare sempre i profili di disinstallazione!</blockquote>
<p>Se un prodotto non è dotato di un profilo di disinstallazione fatto correttamente (e per esperienza posso dire che purtroppo molti sono così), potrebbe lasciare dei “<i>residui</i>” indesiderati nel nostro Data.fs.<br />Questi possono generare dei semplici warning  nel nuovo sito, come per esempio dei CSS o Javascript registrati e non più disponibili, ma nella maggior parte dei casi il problema riguarda adapter o persistent utilities che non vengono rimossi correttamente e rischiano di vanificare la migrazione.<br />Come per l’aggiornamento dei prodotti, se questi sono stati scaricati da pypi, una buona prassi è quella di sistemare i profili di disinstallazione dando un contributo alla comunità.<br /><img src="http://blog.redturtle.it/topic_images/cleanuptheworld.jpg/@@images/df582867-7747-42ba-8d31-f9bf63d5b63c.jpeg" alt="clean" class="image-right" title="clean" />Di solito le risorse che sono registrate e non vengono disinstallate correttamente sono quelle gestite con i profili di GenericSetup, come per esempio dei CSS o javascript, ma anche controlpanel e skin layers. Per avere degli esempi di come eseguire una corretta disinstallazione, basta cercare diversi prodotti nella collective (ad esempio <a class="external-link" href="https://github.com/RedTurtle/redturtle.smartlink.git">redturtle.smartlink</a>).<br />Se malauguratamente il prodotto non mette a disposizione il repository con i sorgenti (e può capitare), o sistemare il profilo di disinstallazione risulta troppo complicato, si riescono a rimuovere parecchie risorse anche manualmente.<br />Tutte quelle relative a GenericSetup si possono rimuovere da ZMI nei vari tool, ma i nostri nemici più agguerriti sono state le <strong>persistent-utilities</strong>, che sono persistenti ma non si riescono a visualizzare da ZMI.<br />Nessun problema, ci sono venute in aiuto due preziose risorse:</p>
<ul>
<li><a class="external-link" href="http://pypi.python.org/pypi/wildcard.fixpersistentutilities">wildacard.fixpersistentutilities</a>, un prodotto che aiuta a riconoscere e rimuovere da interfaccia utente eventuali persistent-utilities presenti nel sito</li>
<li>un'utilissima <a class="external-link" href="http://plone.org/documentation/kb/manually-removing-local-persistent-utilities/">guida</a> di Nathan Van Gheem che spiega come rimuovere manualmente adapters, utility e subscribers.</li>
</ul>
<h3>Blob Blob Blob</h3>
<p>Su Plone 4 è diventato di default il supporto ai blob, per ovvi motivi di miglioramento delle prestazioni e di separazione di file e immagini dal Data.fs vero e proprio.<br />Per questo motivo, la migrazione di Plone 4 include uno step apposito che provvede in autonomia a migrare i contenuti di tipo file e immagine presenti nel sito ai blob.<br />Se i vostri prodotti prevedono contenuti che contengono immagini o file, è buona norma dotarli del supporto ai blob (procedura spiegata in un paragrafo della <a class="external-link" href="http://plone.org/documentation/manual/upgrade-guide/version/upgrading-plone-3-x-to-4.0/updating-add-on-products-for-plone-4.0/use-plone.app.blob-based-blob-storage">guida</a> alla migrazione precedente) e di una procedura che permetta di migrare a blob i contenuti già presenti nel sito (ovviamente post-migrazione a Plone 4). Un buon esempio è fornito da <a class="external-link" href="https://github.com/RedTurtle/redturtle.smartlink/blob/master/redturtle/smartlink/browser/migrate.py">redturtle.smartlink</a>.</p>
<h3>E per finire... la migrazione</h3>
<p>Arrivati a questo punto, dopo aver verificato che tutti i prodotti siano compatibili con Plone 4 e aver ripulito il nostro Data.fs, possiamo procedere alla migrazione vera e propria.<br />Non serve altro che copiare i nostri dati nel nuovo buildout, farlo partire e andare nella ZMI del sito da migrare: un testo avvertirà che il sito è obsoleto e va aggiornato. Seguendo il link si avrà la possibilità di eseguire la migrazione in due modi:</p>
<ul>
<li>dry-run, cioè eseguendo tutti i passi della migrazione, ma non committando le modifiche alla fine: serve se si vogliono prima fare delle prove</li>
<li>migrazione vera e propria: esegue tutti i passi e, una volta terminati, committa le modifiche e le scrive nel db.</li>
</ul>
<p><img src="http://blog.redturtle.it/uploads/laptop7.jpg/@@images/7c73daa5-2fe1-4faa-a041-181bbe6cd788.jpeg" alt="laptop" class="image-right" title="laptop" />Ovviamente il tempo impiegato dipende da molti fattori, come per esempio la potenza della macchina, la dimensione del Data.fs e il fatto di avere già i file sui blob.<br />Non sempre la migrazione andrà a buon fine al <strong>primo colpo</strong>. Fortunatamente quasi sempre il traceback dei fallimenti ci dà buone informazioni su cosa è andato storto, in modo da poterlo sistemare e ritentare. Nella mia esperienza, spesso i problemi erano proprio con utility mal rimosse o classi non più trovate.</p>
<p>Alla fine di tutto il procedimento, quando avremo un sito aggiornato e funzionante, prima di effettuare i vari test è buona norma fare un giro nel pannello di gestione dei prodotti aggiuntivi, in modo da vedere se ci sono degli upgrade-step da lanciare per sistemare alcuni prodotti. Altra operazione importante da fare è il pack del db, perché consente di guadagnare diverso spazio, visto lo spostamento all’esterno di file e immagini.</p>
<h3>Conclusioni</h3>
<p>In conclusione, se si prepara per bene il db da migrare, rimuovendo correttamente tutti i componenti inutilizzati, il tool di migrazione<strong> funziona discretamente bene</strong>.</p>
<p>Abbiamo solo avuto alcuni problemi durante la migrazione dei blob di un sito, come riportato anche da Ross Patterson in un suo <a class="external-link" href="http://rpatterson.net/blog/poskeyerror-during-commit">post</a>. Dopo una lunga analisi, abbiamo notato che il poskey Error veniva lanciato durante il commit finale, ma non siamo riusciti (come l'autore) a risalire all'origine del problema. La soluzione è stata quella di effettuare dei commit intermedi alla fine della migrazione dei file e alla fine delle immagini, anziché alla fine di tutta la procedura.</p>
<p>Seguendo questa sorta di check-list, siamo riusciti a migrare abbastanza agilmente una ventina di siti, e l'abbiamo riutilizzata anche per successivi lavori.</p>]]></content:encoded>
    <dc:publisher>No publisher</dc:publisher>
    <dc:creator>Andrea Cecchi</dc:creator>
    <dc:rights></dc:rights>
    
      <dc:subject>tutorials</dc:subject>
    
    
      <dc:subject>Plone 4</dc:subject>
    
    
      <dc:subject>migration</dc:subject>
    
    <dc:date>2013-02-12T10:00:00Z</dc:date>
    <dc:type>Weblog Entry</dc:type>
  </item>


  <item rdf:about="http://blog.redturtle.it/come-gestire-e-distribuire-i-vostri-prodotti-plone">
    <title>Come gestire e distribuire i vostri prodotti Plone?</title>
    <link>http://blog.redturtle.it/come-gestire-e-distribuire-i-vostri-prodotti-plone</link>
    <description>Un'esplorazione di tutti i (bizzarri) metodi con cui ho visto gestire il codice Plone (ma non solo), alla ricerca di una soluzione per ogni problema
</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Come gestire e distribuire i vostri prodotti Plone?</p>
<p>Sarà perché nella mia esperienza ho affrontato vari corsi di formazione per sviluppatori Plone, sarà perché non tutto il codice è sempre pronto per essere rilasciato, una cosa è certa: il rapporto tra il neofita e il codice da lui sviluppato è piuttosto combattuto.</p>
<p>Partiamo con una carrellata di quello che potete fare (ma in gran parte non dovete) fino ad arrivare alla soluzione dei casi più delicati.</p>
<p></p>
<a name="anchor-breaktext"></a><div class="breakText"></div>
<h2>Sviluppo old-style</h2>
<p>Nell'uso quotidiano di Plone, il nostro amico buildout ci ha abituati per anni all'uso della directory di <strong>develop</strong> (di solito, la directory <i>src</i>):</p>
<pre>[buildout]<br />...<br />develop =<br />    src/my.package<br />    ...</pre>
<p><img alt="Papyrus" class="image-right" src="http://blog.redturtle.it/topic_images/papyrus.jpg/@@images/5bc9c800-3a14-47cd-99e0-d0c0c6299621.jpeg" title="Papyrus" />Sebbene questo metodo oggi sia largamente superato (vedi <a class="external-link" href="http://pypi.python.org/pypi/mr.developer">mr.developer</a>), la comunità Plone lo ha utilizzato per anni e c'è ancora tanta documentazione in giro che ne parla.</p>
<p>Per molti utenti che non hanno dimestichezza con l'installazione di mr.developer (prima che questo diventasse parte dei template di buildout Plone rilasciati) questo modo è quello "più semplice".</p>
<p class="callout">Semplicemente: funziona!</p>
<h2>Versiona-che?</h2>
<p>Ammettiamo che vi troviate nella situazione di cui sopra: qual è la cosa peggiore che potreste trovare in un buildout?<br />Semplice! L'<strong>assenza del versionamento</strong> del codice.</p>
<p>Mi è capitato diverse volte di trovarmi in questa situazione: il <i>Cliente X</i> chiama per mettere mano a un buildout in cui erano presenti prodotti legacy proprio all'interno della cartella <i>src</i>.<br />Nei casi peggiori, si tratta di codice non versionato. Eppure ci viene chiesto di mettergli mano e di apportare un qualche tipo di modifica!</p>
<p>A volte può capitare di accorgersi che nemmeno la configurazione del buildout sia sotto controllo di versione...</p>
<p>Spesso il cliente si sente sufficientemente al sicuro sapendo che ha "<i>una copia da qualche parte</i>" (quando va bene), eppure è difficile fargli capire che la soluzione "backup" non è tutto.</p>
<p>Probabilmente siamo passati tutti per questa fase (detta anche fase del "<i>ero giovane, avevo bisogno di lavorare</i>"), ma spero per voi l'abbiate abbandonata abbastanza in fretta.</p>
<h2>Externals SVN</h2>
<p>Prima dell'esplosione di popolarità di <a class="external-link" href="http://git-scm.com/">Git</a>/<a class="external-link" href="https://github.com/">Github</a>, il software di versionamento del codice più in voga tra gli sviluppatori Plone è stato <a class="external-link" href="http://subversion.apache.org/">SVN</a>.<br />Ne è riprova il fatto che, ancora oggi, la <a class="external-link" href="http://svn.plone.org/svn/collective/">collective SVN</a> è un repository piuttosto utilizzato, anche se la <a class="external-link" href="https://github.com/collective/">nuova collective</a>, ospitata su GitHub, sta rapidamente prendendo piede.</p>
<p>Una delle caratteristiche di SVN era la possibilità di definire il contenuto di una directory sotto controllo di versione tramite la definizione di externals (<a class="external-link" href="http://svnbook.red-bean.com/en/1.0/ch07s03.html">svn:externals</a>), ossia permettere di caricare nella directory una serie di altri sorgenti provenienti (volendo) anche da altri repository.</p>
<p>Una volta compresa l'importanza del versionamento, il <i>Cliente X</i> potrebbe davvero apprezzare il fatto di sapere che il suo buildout è stato versionato, e che il contenuto della directory <i>src</i> contenente il suo codice è controllato da <i>svn:externals</i>, così che il sorgente di ogni prodotto venga scaricato dal repository stesso del prodotto.</p>
<p>Un esempio del formato che questa proprietà dovrebbe avere per due ipotetici prodotti Plone:</p>
<pre>my.package https://my.repository/svn/my.package/trunk<br />your.package https://your.repository/svn/your.package/trunk</pre>
<p>Il tutto ora è piuttosto robusto. L'unico problema riguarda l'utilizzo del <strong>trunk</strong> dei prodotti.<br />Questo tipo di configurazione può andare bene per un ambiente di sviluppo, ma come possiamo configurare l'ambiente di produzione?</p>
<p>Il <i>trunk</i> è per definizione una versione instabile o comunque sempre aggiornata di un prodotto; la possibilità che, aggiornando l'installazione o effettuandone una replica su un nuovo server (magari in seguito ad un disaster-recovery del sistema), il codice possa cambiare o aggiornarsi in qualche modo, è piuttosto pericolosa.</p>
<p>Per mantenere le cose stabili, si dovrebbe quindi riferirsi ai tag dei vari prodotti:</p>
<pre>my.package https://my.repository/svn/my.package/tags/1.2<br />your.package https://your.repository/svn/your.package/tags/1.4.1</pre>
<p>Il problema ora diventa degli sviluppatori, che sarebbero obbligati a gestire manualmente il cambio di repository da tag a trunk.</p>
<p>Come soluzione, per un certo periodo, abbiamo sperimentato l'uso di un doppia directory dei sorgenti, una per i tag di produzione e una per lo sviluppo.</p>
<p>Diciamo quindi di avere un buildout con un <i>production.cfg</i> in questa forma:</p>
<pre>[buildout]<br />...<br />develop =<br />    prod-src/my.package<br />    prod-src/your.package<br />    ...</pre>
<p>...e un development.cfg così:</p>
<pre>[buildout]<br /><br />extends = production.cfg<br />...<br />develop +=<br />    src/my.package<br />    src/your.package<br />    ...</pre>
<p>Le due directory <strong>prod-src</strong> e <strong>src</strong> venivano quindi configurate con due <i>svn:externals</i> differenti: uno che puntava ai tag (versioni stabili e di produzione) e l'altro alle versioni di sviluppo.</p>
<p>La situazione è solida, ma in presenza di molti prodotti personalizzati (10, 20, ...) questo sistema risente di lentezza in fase di aggiornamento.</p>
<p>Ci sono modi migliori: andiamo avanti.</p>
<h2>infrae.subversion</h2>
<p>L'approccio dell'uso di <i>svn:externals</i> aveva anche un altro aspetto negativo: i puristi (diciamo pure: i maniaci) di buildout amano controllare <i>tutto</i> nei propri file <i>.cfg</i>; nell'esempio al caso precedente viene lasciata un'importante parte della configurazione (quali sorgenti scaricare) a SVN.<br />In pratica, aprendo il file di configurazione buildout.cfg non siamo in grado di vedere dove e quali versioni dei prodotti stiamo utilizzando.</p>
<p>La recipe <a class="external-link" href="http://pypi.python.org/pypi/infrae.subversion">infrae.subversion</a> faceva esattamente questo e per un breve periodo ha risentito di una certa popolarità: che cosa scaricare usando SVN veniva configurato in un file .cfg!</p>
<pre>[svneggs]<br />recipe = infrae.subversion<br />location = src<br />urls =<br />    https://my.repository/svn/my.package/tags/1.2 my.repository<br />    ...</pre>
<p>La cosa non è andata avanti per molto, per vari aspetti negativi dell'approccio tra cui la lentezza (maggiore che usando <i>svn:externals</i>) e la fragilità (spesso gli aggiornamenti non andavano a buon fine).</p>
<p>Dimentichiamoci quindi anche di questo approccio.</p>
<h2>Habemus egg</h2>
<p>Torniamo al principio:<br />L'uso della sezione <i>develop</i> del nostro buildout è stata prevista per lo sviluppo.</p>
<p>Rendiamoci conto che tutti questi problemi si hanno solo in presenza di codice non pubblicamente rilasciato e rilasciabile: un qualunque prodotto <i>pubblico</i> viene scaricato automaticamente dal <a class="external-link" href="http://pypi.python.org/">Python Package Index</a> e ci dobbiamo preoccupare del suo sorgente solo se intendiamo mettergli mano per svilupparlo.</p>
<p>La soluzione migliore, da tempo documentata, è:</p>
<ul>
<li>poter utilizzare un server pypi privato (aziendale o del cliente)</li>
<li>rilasciare i prodotti nel formato standard python (gli egg per l'appunto).</li>
</ul>
<p>Il primo caso è in realtà piuttosto semplice: un <i>pypi server</i> non è altro che una directory di file accessibile via Web/HTTP.</p>
<p>Ammettendo di avere una directory su un server privato e che questa directory contenga tutti i nostri egg, questo semplice comando Python lanciato sul server permetterebbe di avere un repository di egg compatibile con buildout:</p>
<pre>$ cd pypi-archive<br />$ python -m SimpleHTTPServer 9000</pre>
<p>A questo punto va indicato al buildout che esiste questa possibilità:</p>
<pre>[buildout]<br />...<br />find-links =<br />    http://dist.plone.org/release/4.2.4<br />    http://dist.plone.org/thirdparty<br />    http://the.server:9000/</pre>
<p>Ovviamente un modo più robusto sarebbe quello di configurare un vero web server, come Apache.</p>
<p>Il problema in questo caso è che l'egg, una volta generato, andrebbe copiato manualmente in questa directory, mentre l'uso del Python Package Index ci ha abituati a un automatismo a cui è difficile rinunciare.<br />Presto detto: se volete ottenere un <strong>server in stile pypi perfettamente funzionante</strong>, potete usare Plone stesso e il prodotto <a class="external-link" href="http://plone.org/products/plonesoftwarecenter">PloneSoftwareCenter</a> (che supporta le <strong>Python Package Index API</strong>).</p>
<p><img alt="Egg" class="image-left" src="http://blog.redturtle.it/topic_images/egg.jpg/@@images/76541d7b-236c-45c6-9c87-41e965133fc6.jpeg" title="Egg" />Ora il secondo problema: com'è fatto un egg? Come posso generarlo e rilasciarlo?</p>
<p>Se per anni il rilascio di egg (pubblico o privato che fosse) necessitava di conoscere almeno i rudimenti di <a class="external-link" href="http://docs.python.org/2/distutils/index.html#distutils-index">distutils</a>, oggi ci sono fantastiche utility che nascondono tutta la complessità. In questo stesso blog potete leggere una <a class="internal-link" href="http://blog.redturtle.it/come-rilasciare-un-pacchetto-senza-piu-pensieri-zest.releaser">dettagliata descrizione del migliore di questi: zest.releaser</a>.</p>
<p>Come potete leggere dall'articolo, <strong>zest.releaser</strong> si occupa di tutte quelle operazioni di versionamento del codice necessarie al momento di una nuova release (aggiornamento, tag della versione, ...) e lo fa per varie tecnologie di versionamento (SVN, Git, Mercurial, ...).</p>
<p>Sembrerebbe quindi che abbiamo trovato la soluzione migliore per i nostri prodotti proprietari:</p>
<ul>
<li>codice versionato</li>
<li>buildout che usa mr.developer</li>
<li>server pypi riservato</li>
<li>uso di zest.releaser.</li>
</ul>
<h2>Ambienti poco amichevoli</h2>
<p><img alt="Endor" class="image-left" src="http://blog.redturtle.it/topic_images/endor.jpg/@@images/183fb037-52ba-43d8-92ff-5f554cd1bc23.jpeg" title="Endor" />Non abbiamo però definito che cosa si intende per "<i>server pypi riservato</i>". Questo può essere:</p>
<ul>
<li>un servizio pubblicamente accessibile ma protetto da autenticazione</li>
<li>un servizio senza autenticazione, ma posto su rete interna del cliente o dell'azienda.</li>
</ul>
<p>Nel primo caso, l'autenticazione può essere un problema: configurare buildout/Python perché richieda autenticazione non è esattamente triviale e può dare vari grattacapi.</p>
<p>Nel secondo caso tutto torna ad essere molto semplice, ma cosa succede se il servizio è nella rete interna del cliente e siete voi il fornitore che deve mettere mano al codice per poi rilasciare nuove versioni?<br />A meno di non possedere una VPN, la cosa non sta in piedi.</p>
<p>In più: ci sono situazioni in cui l'accesso alla rete dall'esterno (e a volte anche verso l'esterno) è fortemente limitato da policy di sicurezza e regole di firewall che farebbero impallidire lo scudo sulla luna boscosa di Endor.</p>
<p class="callout">La difficoltà di poter avere un repository di egg condiviso tra voi e il cliente può non essere banale.</p>
<p>Ci sono però alcuni prerequisiti su cui non si transige: i sistemisti avranno dovuto accettare per forza di cose che "<i>Plone non viene distribuito con un CD ma viene installato accedendo alla Rete</i>" e che "<i>Il buildout usa un sistema di versionamento a cui gli sviluppatori devono poter accedere</i>".</p>
<p>In questi casi limite, noi in RedTurtle abbiamo iniziato a usare un metodo forse non troppo pulito, ma semplice e senza controindicazioni.</p>
<h2>Pypi-local!</h2>
<p>L'idea è semplice:</p>
<ul>
<li>generare gli egg senza rilasciarli (ci piace rilasciare codice, ma non sempre si può)</li>
<li>inserire gli egg nel buildout, in una directory</li>
<li>versionare anche i sorgenti dell'egg.</li>
</ul>
<p>"<i>pypi-local</i>" è stato il primo nome dato alla directory atta ad ospitare gli "egg locali", e da allora non è più cambiato (se in RedTurtle qualcuno dice "<i>...è nella pypi-local</i>" tutti capiscono!).</p>
<p>Tenendo fede a questo nome, ecco come configurare il buildout:</p>
<pre>[buildout]<br />...<br />find-links =<br />    ./pypi-local<br />    http://dist.plone.org/release/4.2.4<br />    http://dist.plone.org/thirdparty</pre>
<p>In pratica, nella radice del buildout deve esistere questa directory.</p>
<p>Prima di impallidire per la poca eleganza di questo approccio, sappiate che questo ci ha aiutato in molte situazioni, non ultimo il caso seguente: dare un prodotto (sempre non rilasciato pubblicamente, a volte per mere questioni di "<i>non saprei se va bene per pypi</i>") a un cliente con un livello tecnico minimo, limitato solo al "<i>so lanciare un buildout</i>".<br />Come? Si manda l'egg per e-mail, con due righe di istruzioni e il gioco è fatto.</p>
<h2>rt.zestreleaser.pypilocal</h2>
<p>Fermo restando che nessuno vuole abbandonare l'uso di <i>zest.releaser</i>, l'uso della directory locale richiede la perdita di un automatismo e una copia manuale dell'egg generato nella directory:</p>
<pre>...<br />Register and upload to pypi (y/N)? <br />Register and upload to plone.org (Y/n)? n<br />Register and upload to redturtle (Y/n)? n<br />...<br />INFO: Finished full release.<br />INFO: Reminder: tag checkout is in /private/var/folders/Ka/Ka7qqP8VFb8dZJO8sohbrE+++TI/-Tmp-/...</pre>
<p><i>zest.releaser</i> esegue una serie di operazioni automatiche per rilasciare gli egg su tutti i server configurati, ma alla fine ci dice dove possiamo trovare la copia temporanea usata per queste operazioni ("<i>Reminder: tag checkout is in...</i>").</p>
<p>Ci basta andare cercare il nostro egg dentro a quella directory (nella sottodirectory <i>dist</i>).</p>
<p>Semplice? Sì, ma rimangono due considerazioni:</p>
<ul>
<li>la programmazione fa l'uomo pigro</li>
<li><i>zest.releaser</i> è maledettamente ben fatto, ed è <strong>pluggabile.</strong></li>
</ul>
<p>Per questo motivo (sì, esatto, solo per non dover copiare manualmente l'egg) abbiamo reso disponibile un <strong>plugin per zest.releaser</strong> che permette di copiare automaticamente l'egg nella directory "pypi-local" (o in qualunque directory vogliate): <a class="external-link" href="http://pypi.python.org/pypi/rt.zestreleaser.pypilocal/">rt.zestreleaser.pypilocal</a>.</p>
<p>La sua configurazione è molto semplice: vi basta modificare il vostro file <i>.pypirc</i> nel seguente modo:</p>
<pre>[distutils]<br />index-servers =<br /> pypi<br /> plone.org<br /> ...<br /><br />[rt.zestreleaser.pypilocal]<br />pypi-local = ../../pypi-local<br />global = /opt/global-pypi</pre>
<p>Nella sezione "<i>rt.zestreleaser.pypilocal</i>" dovete andare a specificare la directory (volendo anche più di una) che <i>zest.releaser</i> cercherà prima di chiedervi se intendete copiare lì i file.</p>
<p>L'esempio "<strong>../../pypi-local</strong>" non è casuale: se state usando un struttura di directory standard nel vostro buildout, quando lancerete i comandi di zest.releaser vi troverete dentro alla directory del vostro prodotto (solitamente qualcosa nella forma <i>buildout-root/src/my.package</i>). Il percorso relativo fornito rispecchia esattamente l'idea che la directory <i>pypi-local</i> sia nella radice del buildout.</p>
<p>L'output di <i>zest.releaser</i> cambierà in questo modo:</p>
<pre>...<br />Register and upload to pypi (y/N)? <br />Register and upload to plone.org (Y/n)? n<br />Register and upload to redturtle (Y/n)? n<br />Copy egg to folder ../../pypi-local (Y/n)? <br />Copy egg to folder /opt/global-pypi (Y/n)? n<br />...<br />INFO: Finished full release.<br />INFO: Reminder: tag checkout is in /private/var/folders/Ka/Ka7qqP8VFb8dZJO8sohbrE+++TI/-Tmp-/...</pre>
<h2>Conclusione</h2>
<p>Tra tutti i metodi descritti, spero ne abbiate trovato almeno uno che si adatti alle vostre esigenze.</p>
<p>Gli strumenti per fare le cose nel modo giusto e per evitare il caos nella gestione dei vostri add-on Plone ci sono tutti, e sono semplici da usare!</p>
<p><span class="discreet">L'immagine in testata è di <a class="external-link" href="http://www.flickr.com/photos/fifthconspiracy/">fifthconspiracy</a>.</span></p>]]></content:encoded>
    <dc:publisher>No publisher</dc:publisher>
    <dc:creator>Luca Fabbri</dc:creator>
    <dc:rights></dc:rights>
    
      <dc:subject>buildout</dc:subject>
    
    
      <dc:subject>python</dc:subject>
    
    
      <dc:subject>riuso</dc:subject>
    
    
      <dc:subject>plone.it</dc:subject>
    
    
      <dc:subject>tutorials</dc:subject>
    
    <dc:date>2013-02-08T10:55:00Z</dc:date>
    <dc:type>Weblog Entry</dc:type>
  </item>


  <item rdf:about="http://blog.redturtle.it/come-utilizzare-online-id-login-plone">
    <title>Come utilizzare gli Online ID per il login Plone</title>
    <link>http://blog.redturtle.it/come-utilizzare-online-id-login-plone</link>
    <description>Facebook, Twitter, Google. Ma anche OpenID, Foursquare, LinkedIN e molti altri. Vediamo come sfruttare il servizio di RPX/Janrain per autenticarsi in Plone</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Oggi giorno se un sito istituzionale, un portale web o anche il più semplice dei siti richiede una registrazione con utente e password che poi dovranno essere in qualche modo memorizzati, le persone mal volentieri compileranno il form in questione.</p>
<p>Il perché è ovvio: ogni persona ha come minimo 50 registrazioni a siti vari e, soprattutto, ogni <i>internauta</i> di oggi ha un profilo su più <strong>social network</strong>.<br />Da qui la brillante idea di permettere di accedere ai siti direttamente con un altro account che fornisca l'identità.</p>
<p class="breakText">Plone non poteva certo rimanere indietro su questo fronte e quindi ecco <strong><a class="external-link" href="http://pypi.python.org/pypi/plonesocial.auth.rpx/0.815">plonesocial.auth.rpx</a></strong>: un pacchetto che utilizza i servizi di autenticazione <strong>RPX</strong> offerti <strong>Janrain</strong>.</p>
<p></p>
<a name="anchor-breaktext"></a><div class="breakText"></div>
<h3>Una nostra personalizzazione</h3>
<p>Il plugin di <a class="external-link" href="http://comlounge.net/">COM.lounge</a> non rispondeva però appieno alle necessità di un nostro cliente, il quale non voleva l'autenticazione automatica indiscriminata da parte di tutti ma un secondo step di registrazione in cui richiedere alcuni dati aggiuntivi.<br />Abbiamo quindi deciso di estendere il prodotto originale sviluppandone una <a class="external-link" href="https://github.com/RedTurtle/plonesocial.auth.rpx/tree/plone4_compatible">nostra versione</a> in cui:</p>
<ul>
<li>abbiamo aggiunto un campo <i>"telefono"</i> al profilo utente</li>
<li>abbiamo aggiunto un form obbligatorio per effettuare la registrazione al portale</li>
<li>abbiamo modificato il plugin di autenticazione in modo da lasciare anonimi tutti gli utenti che non hanno completato il form.</li>
</ul>
<p class="breakText"> </p>
<h2>Configuriamo il sistema</h2>
<p> </p>
<p><img alt="RPX sing-up" class="image-right" src="http://blog.redturtle.it/uploads/RPX_singup.png/@@images/cad635c6-6223-47f3-b923-26bf8fd11c23.png" style="text-align: center; " title="RPX sing-up" /></p>
<p> </p>
<p> </p>
<p> </p>
<p>La prima cosa da configurare è <a class="external-link" href="https://rpxnow.com">Janrain</a> stesso che, in linea con la politica di questo sistema, non fornisce la possibilità di una registrazione diretta al sistema ma solo tramite un account preesistente.</p>
<p style="text-align: center; "> </p>
<p style="text-align: center; "> </p>
<p style="text-align: center; "> </p>
<div><img alt="RPX create application" class="image-left" src="http://blog.redturtle.it/uploads/RPX_createapplication.png/@@images/e3d502bd-627b-407f-b114-bd46d65ba31b.png" title="RPX create application" />
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p>Dopo aver confermato le informazioni del proprio account, bisogna scegliere un nome per la propria applicazione.</p>
<p style="text-align: center; "> </p>
<p style="text-align: center; "> </p>
<p style="text-align: center; "> </p>
<p> </p>
<p><img alt="RPX plone conf" class="image-right" src="http://blog.redturtle.it/uploads/RPX_PloneConf.png/@@images/a7a6cf20-0664-42df-8489-5a7d72a9e042.png" title="RPX plone conf" /></p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p>Il dominio RPX, basato sul nome che avete scelto per la vostra applicazione, insieme ad alcune altre chiavi vanno a comporre le informazioni di configurazione. Queste sono necessarie a configurare il nostro pacchetto Plone.</p>
<p style="text-align: center; "> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p>A questo punto la configurazione <i>“Plone to RPX”</i> è completa, ma ora bisogna configurare RPX perché si colleghi ai vari provider di Online ID per i quali si vuole garantire l’accesso sul nostro portale Plone.</p>
<p>La home dell’applicazione presenta alcune informazioni sugli accessi, limitate se si sta utilizzando la versione gratuita, molto più complete se avete acquistato una versione plus, pro o enterprise. <br />Dei vari menù e quick links disponibili quello che ci interessa è il menu <i>“Development -&gt; Provider Configuration”</i>.</p>
<p style="text-align: center; "><img alt="RPX global configuration" class="image-inline" src="http://blog.redturtle.it/uploads/RPX_configureprovider.png/@@images/6f5acd0c-7b72-472e-b71a-13344f67d430.png" title="RPX global configuration" /></p>
<p>Nell’immagine qui sopra si può vedere che, al momento, la mia applicazione è configurata per gestire l’accesso tramite Facebook e Google; l’altro dettaglio visibile è che molte delle opzioni sono disponibili solo per le versioni a pagamento.</p>
<p> </p>
<p>Ora vediamo come configurare RPX per connettersi ad uno degli <strong>Online ID </strong>disponibili e prendiamo come esempio la configurazione per <a class="external-link" href="http://twitter.com/">Twitter</a>.</p>
<p>Cliccando sul pulsante <i>“Configure”</i> parte un <strong>wizard</strong> che fa compiere tutti i passi necessari.</p>
<p style="text-align: center; "><img alt="RPX wizard twitter" class="image-inline" src="http://blog.redturtle.it/uploads/RPX_wizardtwitter.png/@@images/8ebcbad8-5bd6-4bd7-b530-f0c0abd16737.png" title="RPX wizard twitter" /></p>
<p>Per collegare Twitter, ma anche Facebook tra quelli che ho avuto modo di provare, occorre attivare il proprio account come <strong>“Developers”</strong>. Nulla di particolarmente difficile, sul web si trovano tutte le informazioni necessarie, ma è un’ulteriore passaggio da fare.</p>
<p>Una volta effettuato l’accesso, bisogna creare la propria applicazione tramite la compilazione di un semplice form dove è necessario inserire i parametri indicati nella seconda schermata del wizard.</p>
<p style="text-align: center; "><img alt="RPX twitter create application" class="image-inline" src="http://blog.redturtle.it/uploads/RPX_twitterapp.png/@@images/3baabc82-6ce9-48b1-b6b0-a2737f0addff.png" title="RPX twitter create application" /></p>
<p>La terza schermata dice di impostare il permesso di “lettura e scrittura” da parte della vostra applicazione su Twitter, mentre l’ultimo passaggio da fare è impostare in <i>RPX</i> i parametri di <i>“customer Key”</i> e <i>“Customer Secret”</i> per effettuare il collegamento tra i due sistemi.</p>
<p>I <i>wizard</i> di configurazione non sono tutti uguali, perché ogni provider necessita di configurazioni particolari, ma si concludono tutti con la richiesta dei parametri per il collegamento tra i sistemi.</p>
<p>Per concludere la configurazione di RPX, bisogna andare a impostare il <strong>widget di Sign-in</strong> che verrà mostrato nel proprio sito scegliendo i tipi di account che sono stati precedentemente configurati.</p>
<p style="text-align: center; "><img alt="RPX widget di sing-in" class="image-inline" src="http://blog.redturtle.it/uploads/RPX_widgetsingin.png/@@images/27366202-b281-4b91-9b65-b928d50bfa33.png" style="text-align: center; " title="RPX widget di sing-in" /></p>
<p> </p>
<p>A questo punto tutto è pronto per effettuare l’accesso con Online ID in Plone; buon login!</p>
<p style="text-align: center; "><img alt="RPX login plone" class="image-inline" src="http://blog.redturtle.it/uploads/RPX_logininplone.png/@@images/9c061453-8468-479b-9fbc-d1e2836487d3.png" title="RPX login plone" /></p>
</div>]]></content:encoded>
    <dc:publisher>No publisher</dc:publisher>
    <dc:creator>Mirco Angelini</dc:creator>
    <dc:rights></dc:rights>
    
      <dc:subject>Plone 4</dc:subject>
    
    
      <dc:subject>plone.it</dc:subject>
    
    
      <dc:subject>products</dc:subject>
    
    
      <dc:subject>tutorials</dc:subject>
    
    
      <dc:subject>Facebook</dc:subject>
    
    
      <dc:subject>login</dc:subject>
    
    
      <dc:subject>Plone</dc:subject>
    
    <dc:date>2013-02-01T09:15:00Z</dc:date>
    <dc:type>Weblog Entry</dc:type>
  </item>





</rdf:RDF>
