joe di castrohttp://joedicastro.com2011-06-30T01:21:00+02:00Pelican - Configuración y personalización2011-06-30T01:21:00+02:00joe di castrohttp://joedicastro.com/pelican-configuracion-y-personalizacion.html<p>Con este articulo cierro la serie que le he dedicado a <a href="http://joedicastro.com/tag/pelican.html">Pelican</a> como
herramienta idónea para crear blogs estáticos con mantenimiento cero. Aquí voy a
tratar de la parte más compleja de Pelican, la que nos permite personalizarlo y
adaptarlo a nuestros gustos y necesidades. El primer nivel de personalización se
obtiene a través del fichero de configuración (aunque no es necesario, es
recomendable emplearlo). El segundo nivel vendría mediante la personalización del
tema empleado, bien creando uno nuevo o bien modificando el que viene por
defecto. El último nivel vendría de modificar el propio Pelican. Todos son
posibles y están a nuestro alcance, gracias a que es Software Libre. </p>
<p>Si bien yo he personalizado mi sitio con respecto al sitio por defecto, y aún
quedan ciertas cosas que aún quiero cambiar, no he necesitado de momento más que
modificar el fichero de configuración y el tema que viene por defecto. En
Pelican no he tocado nada exceptuando el activar por defecto <strong>Markdown Extra</strong>,
algo que Alexis tuvo como gentileza <a href="https://github.com/ametaireau/pelican/pull/138">aceptar como modificación</a> a Pelican. Es
posible que en el futuro algunas de las cosas que tengo en mente me lleven a
modificarlo, y espero poder así contribuir en alguna medida a su desarrollo. </p>
<h2 id="configuraci+n">Configuración</h2>
<p>La configuración se hace a través de un fichero python, que en el ejemplo por
defecto se llama <code>pelican.conf.py</code> y en nuestro ejemplo estaría en
<em>myblog.com/site/pelican.conf.py</em>. Para llamar al fichero de configuración se
utiliza la opción <code>-s</code> y en nuestro ejemplo sería:</p>
<div class="codehilite"><pre><span class="gp">$</span> pelican -s ./site/pelican.conf.py
</pre></div>
<p>Este es un tema que está muy bien resuelto en la <a href="http://docs.notmyidea.org/alexis/pelican/settings.html">documentación</a>. De todos
modos voy a hablar de unos cuantos campos interesantes y alguno no incluido
dentro de la documentación. Entre paréntesis indico los valores por defecto.</p>
<ul>
<li>
<p><strong>OUTPUT_PATH</strong> (<code>'output/'</code>) y <strong>PATH</strong> (<code>None</code>)</p>
<p>Empleando estos dos valores, conseguimos que solo tengamos que especificar el
fichero de configuración en la linea de comandos empleada para llamar a Pelican.
El primero define el directorio de salida donde queremos que se genere nuestro
sitio y el segundo el directorio origen de nuestro contenido. </p>
</li>
<li>
<p><strong>SITESUBTITLE</strong> (<code>u''</code>)</p>
<p>Un subtitulo que se puede poner al blog, e.g. un lema. No aparece documentado.</p>
</li>
<li>
<p><strong>JINJA_EXTENSIONS</strong> (<code>[]</code>)</p>
<p>Puede ser necesario habilitar ciertas extensiones de Jinja2 para personalizar
el tema que vamos a emplear. Por ejemplo, para mostrar la nube de etiquetas
con las etiquetas ordenadas alfabéticamente, he habilitado una extensión que
necesitaba para el proceso de esta manera:</p>
<div class="codehilite"><pre><span class="n">JINJA_EXTENSIONS</span> <span class="o">=</span> <span class="p">[</span><span class="s">'jinja2.ext.do'</span><span class="p">]</span>
</pre></div>
</li>
<li>
<p><strong>STATIC_PATHS</strong> (<code>['images',]</code>)</p>
<p>Te permite especificar los contenidos estáticos que quieres añadir a tu blog
y que acabaran colgando de la carpeta <em>static</em>. Yo por ejemplo lo empleo
para alojar las imágenes en <em>static/pictures</em> y el mapa flash que utilizo en
el articulo <a href="http://joedicastro.com/combatir-el-spam-en-drupal.html">Combatir el spam en Drupal</a> en <em>static/ammap</em> así:</p>
<div class="codehilite"><pre><span class="n">STATIC_PATHS</span> <span class="o">=</span> <span class="p">[</span><span class="s">"pictures"</span><span class="p">,</span> <span class="s">"ammap"</span><span class="p">,</span> <span class="p">]</span>
</pre></div>
</li>
<li>
<p><strong>TAG_FEED</strong> (<code>None</code>) y <strong>TAG_FEED_RSS</strong> (<code>None</code>)</p>
<p>Te permiten establecer fuentes Atom y RSS por etiqueta, que es una opción
muy interesante para quienes solo les interesa un tema de los que trates o
para formar parte de un <a href="http://es.wikipedia.org/wiki/Planeta_%28agregador%29">Planet</a> sin mezclar temas. Eso si, lo lógico es
modificar luego el tema para que aparezcan disponibles. </p>
</li>
<li>
<p><strong>DIRECT_TEMPLATES</strong> (<code>('index', 'tags', 'categories', 'archives')</code>)</p>
<p>Estas son las plantillas del tema que generan una página por si mismas. No
viene documentada, pero yo he cambiado los valores por defecto para añadir
una página personalizada a la que redirijo los errores 404 (Página no
encontrada) de esta manera:</p>
<div class="codehilite"><pre><span class="n">DIRECT_TEMPLATES</span> <span class="o">=</span> <span class="p">(</span><span class="s">'index'</span><span class="p">,</span> <span class="s">'tags'</span><span class="p">,</span> <span class="s">'categories'</span><span class="p">,</span> <span class="s">'archives'</span><span class="p">,</span> <span class="s">'notfound'</span><span class="p">)</span>
</pre></div>
</li>
<li>
<p><strong>PIWIK_URL</strong> y <strong>PIWIK_SITE_ID</strong></p>
<p>Te permiten configurar tu sitio para emplear el magnifico sistema de
analíticas web <a href="http://piwik.org/">Piwik</a>. Yo hace unos dos años que lo empleo en mis sitios,
porque tiene la ventaja de que no dependes de un script de un dominio externo.
Esto te ahorra consultas DNS y que la página se quede esperando a cargar
completamente cuando estos fallan. De esta manera tienes el control total
sobre las estadísticas de tu web sin tener que renunciar a la calidad de
otros servicios externos.</p>
</li>
<li>
<p><strong>FILES_TO_COPY</strong> (<code>()</code>)</p>
<p>Básica si queremos emplear ficheros como <em>.htaccess</em> o <em>robots.txt</em>. No está
documentada tampoco. El uso de la misma consiste en una tupla de tuplas con
los valores de las rutas del fichero origen y su destino. En este sitio por
ejemplo:</p>
<div class="codehilite"><pre><span class="n">FILES_TO_COPY</span> <span class="o">=</span> <span class="p">((</span><span class="s">'extra/robots.txt'</span><span class="p">,</span> <span class="s">'robots.txt'</span><span class="p">),</span>
<span class="p">(</span><span class="s">'extra/favicon.ico'</span><span class="p">,</span> <span class="s">'favicon.ico'</span><span class="p">),</span>
<span class="p">(</span><span class="s">'extra/.htaccess'</span><span class="p">,</span> <span class="s">'.htaccess'</span><span class="p">),)</span>
</pre></div>
</li>
</ul>
<h2 id="personalizaci+n">Personalización</h2>
<p>Pero si realmente queremos personalizar el sitio, tanto en funcionalidad básica
como en su aspecto, nos toca modificar el tema por defecto. Aquí podemos optar por
tres vías: Crear el nuestro propio, empezar un tema casi desde cero,
eligiendo el tema por defecto <code>simple</code> (solo texto) o partir de la base del tema
por defecto <code>notmyidea</code>. Este último es el que hemos estado empleado en nuestro
ejemplo y el que yo modifiqué hasta llegar donde lo tengo ahora. </p>
<p>Para comprender de que consta un tema y como podemos personalizarlo, lo mejor es
analizar el tema <code>notmyidea</code>.</p>
<div class="codehilite"><pre><span class="go">notmyidea/</span>
<span class="go">├── static</span>
<span class="go">│ ├── css</span>
<span class="go">│ │ ├── main.css</span>
<span class="go">│ │ ├── pygment.css</span>
<span class="go">│ │ ├── reset.css</span>
<span class="go">│ │ └── wide.css</span>
<span class="go">│ └── images</span>
<span class="go">│ └── icons</span>
<span class="go">│ ├── delicious.png</span>
<span class="go">│ ├── lastfm.png</span>
<span class="go">│ ├── linkedin.png</span>
<span class="go">│ ├── rss.png</span>
<span class="go">│ └── twitter.png</span>
<span class="go">└── templates</span>
<span class="go"> ├── analytics.html</span>
<span class="go"> ├── archives.html</span>
<span class="go"> ├── article.html</span>
<span class="go"> ├── article_infos.html</span>
<span class="go"> ├── base.html</span>
<span class="go"> ├── categories.html</span>
<span class="go"> ├── category.html</span>
<span class="go"> ├── comments.html</span>
<span class="go"> ├── disqus_script.html</span>
<span class="go"> ├── github.html</span>
<span class="go"> ├── index.html</span>
<span class="go"> ├── page.html</span>
<span class="go"> ├── pagination.html</span>
<span class="go"> ├── piwik.html</span>
<span class="go"> ├── skribit_tab_script.html</span>
<span class="go"> ├── skribit_widget_script.html</span>
<span class="go"> ├── tag.html</span>
<span class="go"> ├── taglist.html</span>
<span class="go"> ├── tags.html</span>
<span class="go"> ├── translations.html</span>
<span class="go"> └── twitter.html</span>
</pre></div>
<ul>
<li>
<p><strong><em>static/css</em></strong></p>
<p>Aquí es donde se guardan las <a href="http://es.wikipedia.org/wiki/CSS">Hojas de estilo en cascada (CSS)</a> que emplea el
tema. Aunque la el fichero <em>wide.css</em> no es empleado por el tema, solo para la
versión wide del mismo. Yo la eliminé como primera medida. Luego tenemos
<em>main.css</em> que es la hoja de estilo principal, <em>pygment.css</em> que es la que emplea
Pygments para el resaltado de sintaxis y <em>reset.css</em> para resetear los navegadores
a unos valores comunes por defecto. </p>
<p>Si lo que queremos es tener un sitio con un buen rendimiento, deberíamos dar
como mínimo dos pasos, consolidar todas la hojas de estilo en una sola y
minimizar el tamaño de esta. Consolidarla en este caso es realmente sencillo,
simplemente debemos insertar el contenido de <em>reset.css</em> al principio del
fichero <em>main.css</em> y <em>pygment.css</em> al final del mismo. Depués hay que
eliminar los imports de estas hojas en <em>main.css</em>*. Luego para minimizar
su tamaño eliminar comentarios y lineas en blanco y poner una regla por línea. </p>
<p>Otro paso que dí para mejorar el rendimiento es no usar las web fonts
externas (ni internas), que aunque le dan un aspecto inmejorable, hay que
reconocerlo, requieren cargar otro recurso externo, desde mi punto de vista
innecesario.</p>
<p>Lo mejor en estos casos es seguir siempre las recomendaciones de estas dos
magnificas herramientas: <a href="http://developer.yahoo.com/yslow/">YSlow</a> de <strong>Yahoo</strong> y <a href="http://code.google.com/speed/page-speed/">Page Speed</a> de
<strong>Google</strong>. Afortunadamente hay sitios web como <a href="http://gtmetrix.com/">GTmetrix</a> o
<a href="http://www.webpagetest.org/">WebPagetest</a> que nos permiten ver los resultados de ambas herramientas
en nuestro sitio web sin necesidad de instalarlas (aunque para el desarrollo
es más que recomendable). Si por ejemplo emplearamos <strong>GTmetrix</strong> los valores
que arroja un sitio con el tema por defecto son:</p>
<table>
<thead>
<tr>
<th>Page Speed (tema por defecto)</th>
<th>YSlow (tema por defecto)</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>B (80%)</strong></td>
<td><strong>B (85%)</strong></td>
</tr>
</tbody>
</table>
<p>Valores bastante mejorables. Los valores actuales para este sitio, una vez
personalizado el tema y configurado correctamente el <em>.htaccess</em> son:</p>
<table>
<thead>
<tr>
<th>Page Speed (tema personalizado)</th>
<th>YSlow (tema personalizado)</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>A (91%)</strong></td>
<td><strong>A (95%)</strong></td>
</tr>
</tbody>
</table>
<p>Y si nos fijamos en <a href="http://gtmetrix.com/reports/joedicastro.com/BeFSzvAa">los resultados</a>, las penalizaciones de rendimiento
vienen de los scrips externos de Piwik y Disqus, principalmente de este
último. Sin emplear estos scripts los valores suben a:</p>
<table>
<thead>
<tr>
<th>Page Speed (sin scripts)</th>
<th>YSlow (sin scripts)</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>A (100%)</strong></td>
<td><strong>A (98%)</strong></td>
</tr>
</tbody>
</table>
<p>En resumen, una optimización más que correcta, solo hay que ver los valores
de las páginas del Top 1000 que ofrecen en GTmetrix. Obtener una optimización
como esta con un CMS no es imposible (había conseguido unos valores solo un
poquito peores con Drupal) pero si bastante más complicado. La experiencia
del usuario depende mucho de estos valores, hay que contar con que no todo
el mundo dispone de buenos accesos a Internet.</p>
<p>Evidentemente, después cada uno retocara el fichero CSS resultante a su
gusto para personalizar el aspecto del sitio. En este caso estoy empleando
CSS 3 y valida correctamente. </p>
</li>
</ul>
<p style="text-align:center;">
<a href="http://jigsaw.w3.org/css-validator/validator?uri=http%3A%2F%2Fjoedicastro.com%2F&profile=css3&usermedium=all&warning=1&vextwarning=&lang=es">
<img style="border:0;width:88px;height:31px"
src="pictures/valid-css3.png"
alt="¡CSS 3 Válido!" title="¡CSS 3 Válido!" />
</a>
</p>
<ul>
<li>
<p><strong>static/images/icons</strong></p>
<p>Son los iconos empleados por la hoja de estilo para los enlaces sociales de
la parte inferior de la página. Yo no los empleo. ¿Entonces como se ven?
Bueno lo primero que hice fue crear un <a href="http://www.w3schools.com/css/css_image_sprites.asp">sprite</a> para cargar una sola
imagen en lugar de 6, es decir menos solicitudes al servidor. Después
incorporé esta imagen <a href="http://www.websiteoptimization.com/speed/tweak/inline-images/">dentro del propio fichero CSS con un Data URL</a>, y
gracias a haberla optimizado hasta ocupar solamente ~3k, me compensaba
hacerlo. Una consulta menos al servidor. Lo mismo hice después con el
logotipo (1K) y al final no se carga ninguna imagen por defecto en el blog,
0 consultas. Los navegadores modernos soportan esto sin problemas, los que
no lo hacen, no muestran la imagen, solo el enlace, que tampoco es un ningún
problema.</p>
<p>Así es como queda en <em>main.css</em> la imagen que da vida a los iconos de los
enlaces a la redes sociales:</p>
<div class="codehilite"><pre><span class="nf">#extras</span> <span class="nt">div</span><span class="o">[</span><span class="nt">class</span><span class="o">=</span><span class="s1">'social'</span><span class="o">]</span> <span class="nt">a</span><span class="p">{</span><span class="k">background-repeat</span><span class="o">:</span><span class="k">no-repeat</span><span class="p">;</span><span class="k">background-image</span><span class="o">:</span><span class="sx">url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAACSCAMAAAB7VbqAAAAAwFBMVEWQBQCWFxU5VpedVy+tUE5LZaBPZZZDabDdYSpke75vfZBkfbJZgc+heztshKvldjBgld91j9+Uj4p5ksZ/lLzthzLqhz+MmrAcvuaDofihpYRzq/D4mDeUp9KetkSirsnQpKWpvV/qqHvHsJjnqY/3qWK1ubbIun2jwLHEu7xm1O+6xoOtv++7wte0yNzxwH563e/3xJjK06ya5vXY3p7U2+3e3tbm6IT63cLn7czr7fbZ9Prz7+r8+O/3+fb9//z6WVfkAAADNElEQVRIx9WV4XqiPBCFoyu4aVjQBrW2ImBX3aJYdQERIbn/u9qTRKzd7/n+b88jxHlnMswEY4hIGYUcLZYKklLbtixqNBymhNl2yG/2lBFqu1LKKjD2dEioxfIKKOfaVgA+HkoptsoGoDxPA8orKZTtEIdyNWE4zXEbUgVokAq4p1JuqQHIX8G9lYK2EdOpkNuhlJxec+TTrcxpJVENAOK3iK9oLkOLEmbqGQZ4dMAtRlJj617QZErQvqpHiVLVvvhL/y6oFx40HhktaqJt9X2mtSDwHg7L1p6NAJZY9eZwB8aHsgF61zaAnr8spXxX9piMR8umxAQQZBp5ZDTSOZYgzXjkKTCbvTeKNPLgKaCTK/dCNldQlu9wL0aNHH9XADnK2UGWXil/GoDJyFx6P69gNlPPWy698cIDWOj68DzvO+Qt0D7MsXcV2v86by55+qSEPP3+pKf/ARfxF5Dy8gH2+/0N7Pc3oCUMSJIWyESBRANxgX4nyQ1cEiMDEkR8BheT4jYl2bdJW5DsdczlA9z09N/2v86bw1Vs4vl8c6xbcI7ncQxkCBFFPM8a0QAfDTjOM70453lc630bx2ezXJt5oUARx40BmQF3EfFroXJs5gaU30inF+G3vombBnuu7JFer9OJ1JQMZcQ/SK8WEekRVRYqjb+RSMq60yHF8VzXRVHAWUsV0TZVIEekctzafEPKTnS/o+qog7z361FHkfhK/5ZV0MrnPAgqEvBWYZoGPCSt6aujLGScuC5j+LAdNkAVALCrUuVndwARvhoJs3C3WSXUFB8HjtW1LFxCvz3WtQC03Bw5fOsDdEPl794BPMW9Ap3DAMuyCc5nJQ2sO2AB+BgYCU1dCkwwhjjnfNUO8ycTl/lf6pxTtzzfQXl1BduXAQ5/7jiDl50CgcMnq6Ku69WEOQHAgD8+Pq5WbysMLle78tdq8jDR4oMc4HzKsuPuBRoMLKHB6+spG2hgrwCydQZpQH0NTmsgB/4BTVe1AphyNCBXoMk2p9MvB7bT1xEitB+eFXCch3WhSl/Z/T6dcMddr581KAD6fdd9fnyoTbdvrN93+v2uXbTt17sQyvV6/AE7UZJYs2UOngAAAABJRU5ErkJggg==")</span><span class="p">;</span><span class="k">padding-left</span><span class="o">:</span><span class="m">25px</span><span class="p">;}</span>
<span class="nc">.social</span> <span class="nt">a</span><span class="o">[</span><span class="nt">href</span><span class="o">*=</span><span class="s1">'atom.xml'</span><span class="o">]</span><span class="p">{</span><span class="k">background-position</span><span class="o">:</span><span class="m">3px</span> <span class="m">6px</span><span class="p">;}</span>
<span class="nc">.social</span> <span class="nt">a</span><span class="o">[</span><span class="nt">href</span><span class="o">*=</span><span class="s1">'rss.xml'</span><span class="o">]</span><span class="p">{</span><span class="k">background-position</span><span class="o">:</span><span class="m">3px</span> <span class="m">-20px</span><span class="p">;}</span>
<span class="nc">.social</span> <span class="nt">a</span><span class="o">[</span><span class="nt">href</span><span class="o">*=</span><span class="s1">'twitter.com'</span><span class="o">]</span><span class="p">{</span><span class="k">background-position</span><span class="o">:</span><span class="m">3px</span> <span class="m">-46px</span><span class="p">;}</span>
<span class="nc">.social</span> <span class="nt">a</span><span class="o">[</span><span class="nt">href</span><span class="o">*=</span><span class="s1">'identi.ca'</span><span class="o">]</span><span class="p">{</span><span class="k">background-position</span><span class="o">:</span><span class="m">3px</span> <span class="m">-72px</span><span class="p">;}</span>
<span class="nc">.social</span> <span class="nt">a</span><span class="o">[</span><span class="nt">href</span><span class="o">*=</span><span class="s1">'facebook.com'</span><span class="o">]</span><span class="p">{</span><span class="k">background-position</span><span class="o">:</span><span class="m">3px</span> <span class="m">-98px</span><span class="p">;}</span>
<span class="nc">.social</span> <span class="nt">a</span><span class="o">[</span><span class="nt">href</span><span class="o">*=</span><span class="s1">'bitbucket.org'</span><span class="o">]</span><span class="p">{</span><span class="k">background-position</span><span class="o">:</span><span class="m">3px</span> <span class="m">-124px</span><span class="p">;}</span>
</pre></div>
</li>
<li>
<p><strong>static/templates</strong></p>
<p>Estas son las plantillas que dan vida al tema y emplean Jinja2. Los nombres
son bastante descriptivos de la función que realiza cada una de ellas. En mi
caso hay una serie de ellas que no empleo, como son: <em>analytics.html</em>,
<em>article_infos.html</em>, <em>github.html</em>, <em>skribit_tab_script.html</em>,
<em>skribit_widget_script.html</em>, <em>translations.html</em> y <em>twitter.html</em>. He
realizado bastantes modificaciones en las plantillas y me extendería demasiado
explicándolo, además sigo realizando cambios. Aún no lo tengo todo como yo
lo quiero, y aún voy a personalizar y optimizar más cosas. Cuando lo tenga
todo listo, pienso publicar un repositorio con el contenido que genera este
blog, tanto a efectos de copia de seguridad, como de que le pueda servir a
alguien como guía para montar el suyo propio. </p>
<p>De todos modos si puedo decir que he añadido una que no existía,
<em>notfound.html</em> para los errores 404 y pienso crear una nueva para los
errores 403. Además he creado los enlaces para los feeds RSS y Atom de las
etiquetas y eliminado el bloque de información que aparecía en cada articulo.
Además en la plantilla <em>tags.html</em> que por defecto viene vacía, he creado lo
necesario para generar la nube de etiquetas. <em>tags.html</em> queda entonces así:</p>
<div class="codehilite"><pre><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"base.html"</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}</span>
<span class="nt"><section</span> <span class="na">id=</span><span class="s">"content"</span> <span class="na">class=</span><span class="s">"body"</span><span class="nt">></span>
<span class="nt"><h1></span>etiquetas<span class="nt"></h1></span>
<span class="nt"><ul</span> <span class="na">id=</span><span class="s">"cloud"</span><span class="nt">></span>
<span class="cp">{%</span>- <span class="k">set</span> <span class="nv">all_tags</span> <span class="o">=</span> <span class="o">{}</span> -<span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">ctag</span> <span class="k">in</span> <span class="nv">tag_cloud</span> -<span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">do</span> <span class="nv">all_tags.update</span><span class="o">({</span><span class="nv">ctag.0</span><span class="o">:</span><span class="nv">ctag.1</span><span class="o">})</span> <span class="cp">%}</span>
<span class="cp">{%</span>- <span class="k">endfor</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">tag</span> <span class="k">in</span> <span class="nv">all_tags</span><span class="o">|</span><span class="nf">sort</span> <span class="cp">%}</span>
<span class="nt"><li</span> <span class="na">class=</span><span class="s">"tag-</span><span class="cp">{{</span> <span class="nv">all_tags</span><span class="o">[</span><span class="nv">tag</span><span class="o">]</span> <span class="cp">}}</span><span class="s">"</span><span class="nt">><a</span> <span class="na">href=</span><span class="s">"tag/</span><span class="cp">{{</span> <span class="nv">tag</span><span class="o">|</span><span class="nf">replace</span><span class="o">(</span><span class="s2">" "</span><span class="o">,</span> <span class="s2">"%20"</span><span class="o">)</span> <span class="cp">}}</span><span class="s">.html"</span><span class="nt">></span><span class="cp">{{</span> <span class="nv">tag</span> <span class="cp">}}</span><span class="nt"></a></li></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="nt"></ul></span>
<span class="nt"></section></span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
</pre></div>
<p>También he realizado las modificaciones pertinentes para que el contenido
validara perfectamente en HTML 5. </p>
</li>
</ul>
<p style="text-align:center;">
<a href="http://validator.w3.org/check?uri=http%3A%2F%2Fjoedicastro.com%2F">
<img style="border:0;width:88px;height:31px"
src="pictures/valid-html5.png"
alt="¡HTML 5 Válido!" title="¡HTML 5 Válido!" />
</a>
</p>
<p>Pero como ya he dicho es un proceso que aún no he finalizado. Cuando lo
termine y publique el repositorio, actualizaré también este articulo.</p>Pelican - Publicación y automatización2011-06-28T23:54:00+02:00joe di castrohttp://joedicastro.com/pelican-publicacion-y-automatizacion.html<p>Una vez que sabemos como <a href="http://joedicastro.com/pelican-introduccion-e-instalacion.html">instalar Pelican</a> y <a href="http://joedicastro.com/pelican-creacion-de-contenido.html">crear contenido</a> con él, es
hora de saber como convertir ese contenido en un blog real disponible en
internet. Es decir, saber como publicar ese contenido. Como hemos visto hasta
ahora, al constar básicamente de simples ficheros HTML, un servidor de archivos
es más que suficiente para servir el blog. Esto nos abre un gran abanico de
posibilidades, desde emplear un potente (y barato) servidor de ficheros en la
<em>nube</em> como <strong>Amazon S3</strong>, pasando por las páginas web estáticas que nos
permiten repositorios como <strong>Bitbucket</strong> o <strong>GitHub</strong>, por los tradiciones
hostings compartidos (e.g. este blog), hasta un servidor casero sencillo
montado sobre un <a href="http://es.wikipedia.org/wiki/Network-attached_storage">NAS</a>. </p>
<p>Aún cuando es posible emplear un simple servidor de archivos para alojar el blog,
siempre es mejor contar con un servidor web detrás (Apache, nginx, lighttpd,
...) que nos permita hacer redirecciones para nuestras antiguas páginas si ya
disponíamos de un blog anterior o manejar los errores HTTP <a href="http://es.wikipedia.org/wiki/Error_404">404</a> o <a href="http://es.wikipedia.org/wiki/Anexo:C%C3%B3digos_de_estado_HTTP">403</a>
de forma personalizada. </p>
<h2 id="publicar_el_contenido">Publicar el contenido</h2>
<p>Publicar el contenido de una web es tan sencillo como volcar el contenido del
directorio que nos genera Pelican (en nuestro ejemplo sería
<em>myblog.com/site/output/*</em>) en el directorio destino de nuestro servidor web.
Dependiendo del método que hayamos elegido para alojar nuestro blog, puede ser
tan sencillo como una copia de archivos o emplear FTP (SFTP) ó <a href="http://es.wikipedia.org/wiki/SSH">SSH</a> (<a href="http://es.wikipedia.org/wiki/SCP">SCP</a>,
<a href="http://en.wikipedia.org/wiki/Unison_%28file_synchronizer%29">Unison</a> ó <a href="http://es.wikipedia.org/wiki/Rsync">rsync</a>). Aquí el tema radica no en la primera vez que
vayamos a subir el contenido al servidor, si no en las sucesivas, a medida que
vayamos creando contenido nuevo. No tendría ningún sentido volver a subir todo
el contenido cada vez, si no solamente el nuevo o el que haya cambiado. Para eso
necesitamos sincronizar los dos directorios. </p>
<p>Si solamente disponemos de acceso FTP (o SFTP) a nuestro servidor, entonces
tendremos que emplear una herramienta que nos permita la sincronización sobre
FTP, como puede ser <strong>lftp</strong>. Y el proceso se puede automatizar con un script
como el que describo en <a href="http://joedicastro.com/sincronizar-una-carpeta-local-y-una-remota-a-traves-de-ftp-lftp-mirror.html">Sincronizar una carpeta local y una remota a través de
FTP: lftp-mirror</a>. Si disponemos de acceso a través de SSH, entonces la
elección es clarisima, <strong>rsync</strong>. Más adelante explico una manera de emplearlo
de forma automática.</p>
<p>Cualquiera de ambas soluciones nos permite subir el contenido en apenas segundos,
(sobre todo en el caso de rsync) cuando se trata de añadir un articulo nuevo,
por ejemplo. Y lo mismo a la hora de hacer una rectificación, es tan inmediato
como lo pueden ser plataformas como Wordpress, Drupal y similares. Además, con
las potentes herramientas que existen para hacer cambios múltiples en varios
ficheros de texto a la vez, se pueden realizar tareas casi imposibles con una
plataforma de blogs tradicional sin recurrir a consultas SQL en la BDD o a
plugins externos. Una de estas herramientas, sin recurrir a <code>find</code>, <code>grep</code>,
<code>awk</code> y <code>sed</code>, puede ser <a href="http://regexxer.sourceforge.net/">regexxer</a>.</p>
<h2 id="generar_el_contenido_en_el_propio_servidor">Generar el contenido en el propio servidor</h2>
<p>Si el alojamiento que hemos escogido nos permite instalar programas python,
entonces tenemos la posibilidad de instalar Pelican en el servidor remoto. De
esta formar podríamos subir únicamente los archivos markdown o reStructuredText
al servidor y generar allí mismo el contenido web. De este modo la cantidad de
datos a subir sería ridícula y un simple comando FTP nos serviría. Luego bien
podríamos lanzar Pelican a través de una consola SSH o bien dependiendo del
servidor, tener un <a href="http://es.wikipedia.org/wiki/Demonio_%28inform%C3%A1tica%29">demonio</a> corriendo que cuando detectara un cambio en el
sistema de ficheros lanzará un script que generara el contenido con Pelican. </p>
<p>Otra posibilidad que me convence más, es de la poder instalar un repositorio en
el servidor con un software de control de versiones, como Git o Mercurial. La
idea sería tener un repositorio local, y al hacer un push hacia el repositorio
remoto, a través de un <em>hook</em> activar la generación de la página con Pelican.
Esto nos permitiría además poder tener varias copias del repositorio (por
ejemplo en GitHub o Bitbucket) y por lo tanto de la web, haciendo "innecesarias"
las copias de seguridad. </p>
<h2 id="automatizar_todos_los_procesos">Automatizar todos los procesos</h2>
<p>Pero lo ideal es poder automatizar todas las tareas que hemos visto hasta ahora,
empleando unos pocos comandos para realizarlas sin esfuerzo alguno (bueno,
a menos que tengas tú <a href="http://es.wikipedia.org/wiki/Negro_%28escritor%29">ghostwriter</a> particular, me temo que los artículos los
seguirás teniendo que escribir tú). Para poder realizar esto disponemos de la
fantástica y potente herramienta <a href="http://fabfile.org">Fabric</a> (el <a href="http://en.wikipedia.org/wiki/Capistrano">Capistrano</a> para Python)
que nos permite ejecutar comandos locales o remotos en múltiples servidores. Esto
nos permite hacer despliegues de software sin apenas esfuerzo en distintas
máquinas, copiar ficheros o ejecutar tareas repetitivas empleado una corta
serie de comandos. Una grandísima herramienta para administradores de sistema y
desarrolladores.</p>
<p>Lo único que necesitamos es instalar <strong>fabric</strong> y crear un fichero llamado
<code>fabfile.py</code> donde especificaremos las tareas que queremos programar. Para
instalar la última versión estable de fabric, lo mejor es emplear <code>easy_install</code>
o <code>pip</code></p>
<div class="codehilite"><pre><span class="gp">$</span> pip install fabric
</pre></div>
<p>Una vez creado el fichero <code>fabfile.py</code>, lo único que tendremos que hacer para
ejecutar una tarea del mismo, sería escribir el comando <code>fab</code> seguido del nombre
que le hayamos dado a la tarea (este sería el funcionamiento básico). Y la tarea
se ejecutaría inmediatamente. </p>
<p>Para comprender mejor como funciona Fabric, muestro aquí el contenido actual de
mi fichero <code>fabfile.py</code><br />
</p>
<div class="codehilite"><pre><span class="c">#!/usr/bin/env python</span>
<span class="c"># -*- coding: utf8 -*-</span>
<span class="sd">"""</span>
<span class="sd"> fabfile.py: A fabric script for generate my personal blog</span>
<span class="sd">"""</span>
<span class="n">__author__</span> <span class="o">=</span> <span class="s">"joe di castro <joe@joedicastro.com>"</span>
<span class="n">__license__</span> <span class="o">=</span> <span class="s">"GNU General Public License version 3"</span>
<span class="n">__date__</span> <span class="o">=</span> <span class="s">"28/06/2011"</span>
<span class="n">__version__</span> <span class="o">=</span> <span class="s">"0.2"</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">from</span> <span class="nn">fabric.api</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">fabric.contrib.project</span> <span class="kn">import</span> <span class="n">rsync_project</span>
<span class="kn">from</span> <span class="nn">fabric.contrib.console</span> <span class="kn">import</span> <span class="n">confirm</span>
<span class="n">PELICAN_REPOSITORY</span> <span class="o">=</span> <span class="s">"git://github.com/ametaireau/pelican.git"</span>
<span class="n">PROD</span> <span class="o">=</span> <span class="s">"joedicastro.com"</span>
<span class="n">PROD_PATH</span> <span class="o">=</span> <span class="s">"/home/joedicastro/webapps/joedicastro"</span>
<span class="n">LOCAL_WEB</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s">"~/www"</span><span class="p">,</span> <span class="n">PROD</span><span class="p">)</span>
<span class="n">ROOT_PATH</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">__file__</span><span class="p">))</span>
<span class="n">ENV_PATH</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">ROOT_PATH</span><span class="p">,</span> <span class="s">"env"</span><span class="p">)</span>
<span class="n">PELICAN</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">ROOT_PATH</span><span class="p">,</span> <span class="s">"pelican"</span><span class="p">)</span>
<span class="n">CONFIG_FILE</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">ROOT_PATH</span><span class="p">,</span> <span class="s">"site/pelican.conf.py"</span><span class="p">)</span>
<span class="n">OUTPUT</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">ROOT_PATH</span><span class="p">,</span> <span class="s">"site/output"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_valid_HTML</span><span class="p">():</span>
<span class="sd">"""Remove the obsolete rel="" and rev="" links in footnotes."""</span>
<span class="k">for</span> <span class="n">path</span><span class="p">,</span> <span class="n">dirs</span><span class="p">,</span> <span class="n">files</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="n">OUTPUT</span><span class="p">):</span>
<span class="k">for</span> <span class="n">fil</span> <span class="ow">in</span> <span class="n">files</span><span class="p">:</span>
<span class="k">if</span> <span class="n">fil</span><span class="p">[</span><span class="o">-</span><span class="mi">5</span><span class="p">:]</span> <span class="o">==</span> <span class="s">".html"</span><span class="p">:</span>
<span class="n">local</span><span class="p">(</span><span class="s">"sed -i {0} -r -e 's/re[l|v]=</span><span class="se">\"</span><span class="s">footnote</span><span class="se">\"</span><span class="s">//g' {0}"</span><span class="o">.</span>
<span class="n">format</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">fil</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">" "</span><span class="p">,</span> <span class="s">r"\ "</span><span class="p">))))</span>
<span class="k">def</span> <span class="nf">_make_env</span><span class="p">():</span>
<span class="sd">"""Make a virtual enviroment"""</span>
<span class="n">local</span><span class="p">(</span><span class="s">"virtualenv {0}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">ENV_PATH</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">_del_env</span><span class="p">():</span>
<span class="sd">"""Delete a virtual enviroment."""</span>
<span class="n">local</span><span class="p">(</span><span class="s">"rm -rf {0}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">ENV_PATH</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">_clone_pelican</span><span class="p">():</span>
<span class="sd">"""Clone Pelican from repository."""</span>
<span class="n">local</span><span class="p">(</span><span class="s">"git clone {0}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">PELICAN_REPOSITORY</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">_install</span><span class="p">():</span>
<span class="sd">"""Install Pelican in the virtual enviroment."""</span>
<span class="k">with</span> <span class="n">lcd</span><span class="p">(</span><span class="n">PELICAN</span><span class="p">):</span>
<span class="n">local</span><span class="p">(</span><span class="s">"{0}/bin/python setup.py install"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">ENV_PATH</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">_browse</span><span class="p">():</span>
<span class="sd">"""Browse the local Apache site."""</span>
<span class="n">local</span><span class="p">(</span><span class="s">"firefox -new-window http://localhost/joedicastro.com 2>/dev/null &"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_gen</span><span class="p">(</span><span class="n">autoreload</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
<span class="sd">"""Generate the site from source."""</span>
<span class="n">local</span><span class="p">(</span><span class="s">"{0}/bin/pelican {2} -s {1}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">ENV_PATH</span><span class="p">,</span> <span class="n">CONFIG_FILE</span><span class="p">,</span>
<span class="s">"-r"</span> <span class="k">if</span> <span class="n">autoreload</span> <span class="k">else</span> <span class="s">""</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">_clean</span><span class="p">():</span>
<span class="s">"Remove the output folder."</span>
<span class="n">local</span><span class="p">(</span><span class="s">"rm -rf {0}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">OUTPUT</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">_local_deploy</span><span class="p">():</span>
<span class="sd">"""Deploy to the local apache web server."""</span>
<span class="n">local</span><span class="p">(</span><span class="s">"rm -rf {0}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">LOCAL_WEB</span><span class="p">))</span>
<span class="n">local</span><span class="p">(</span><span class="s">"cp -r {0} {1}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">OUTPUT</span><span class="p">,</span> <span class="n">LOCAL_WEB</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">pull_pelican</span><span class="p">():</span>
<span class="sd">"""Update Pelican to last revision from repository."""</span>
<span class="k">with</span> <span class="n">lcd</span><span class="p">(</span><span class="n">PELICAN</span><span class="p">):</span>
<span class="n">local</span><span class="p">(</span><span class="s">"git pull"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">bootstrap</span><span class="p">():</span>
<span class="sd">"""Get Pelican and install it in a virtual enviroment."""</span>
<span class="k">with</span> <span class="n">settings</span><span class="p">(</span><span class="n">warn_only</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="n">_del_env</span><span class="p">()</span>
<span class="n">_make_env</span><span class="p">()</span>
<span class="k">with</span> <span class="n">settings</span><span class="p">(</span><span class="n">warn_only</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="n">_clone_pelican</span><span class="p">()</span>
<span class="n">_install</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">regen</span><span class="p">():</span>
<span class="sd">"""Regenerate the site from source."""</span>
<span class="n">_clean</span><span class="p">()</span>
<span class="n">_gen</span><span class="p">()</span>
<span class="n">_valid_HTML</span><span class="p">()</span>
<span class="n">_local_deploy</span><span class="p">()</span>
<span class="nd">@hosts</span><span class="p">(</span><span class="s">"my_user@"</span> <span class="o">+</span> <span class="n">PROD</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">publish</span><span class="p">():</span>
<span class="sd">"""Publish into remote web server with rsync."""</span>
<span class="n">regen</span><span class="p">()</span>
<span class="n">_browse</span><span class="p">()</span>
<span class="k">if</span> <span class="n">confirm</span><span class="p">(</span><span class="s">"¿Estas seguro de querer publicarlo?"</span><span class="p">):</span>
<span class="n">rsync_project</span><span class="p">(</span><span class="n">PROD_PATH</span><span class="p">,</span> <span class="n">OUTPUT</span> <span class="o">+</span> <span class="s">"/"</span><span class="p">,</span> <span class="n">delete</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">new</span><span class="p">(</span><span class="n">title</span><span class="p">):</span>
<span class="sd">"""Create a new blog article."""</span>
<span class="n">local</span><span class="p">(</span><span class="s">"gedit --new-window {0}/site/source/blog/{1}.md 2>/dev/null &"</span><span class="o">.</span>
<span class="n">format</span><span class="p">(</span><span class="n">ROOT_PATH</span><span class="p">,</span> <span class="n">title</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">" "</span><span class="p">,</span> <span class="s">"\ "</span><span class="p">)))</span>
<span class="n">local</span><span class="p">(</span><span class="s">"firefox --new-window {0}/index.html &"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">OUTPUT</span><span class="p">))</span>
<span class="n">_gen</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">img4web</span><span class="p">(</span><span class="n">delete</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">source</span><span class="o">=</span><span class="s">""</span><span class="p">):</span>
<span class="sd">"""Optimize .jpg & .png images and copy them into source pictures dir."""</span>
<span class="n">local</span><span class="p">(</span><span class="s">"./img4web.py -d {0} {1} {2}"</span><span class="o">.</span>
<span class="n">format</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">ROOT_PATH</span><span class="p">,</span> <span class="s">"site/source/pictures"</span><span class="p">),</span>
<span class="s">"--delete"</span> <span class="k">if</span> <span class="n">delete</span> <span class="k">else</span> <span class="s">""</span><span class="p">,</span>
<span class="s">"-s {0}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">source</span><span class="p">)</span> <span class="k">if</span> <span class="n">source</span> <span class="k">else</span> <span class="s">""</span><span class="p">))</span>
</pre></div>
<p>Ahora, veremos el funcionamiento básico que nos permite este script. Primero
vemos las tareas que tenemos disponibles:</p>
<div class="codehilite"><pre><span class="gp">$</span> fab -l
<span class="go"> fabfile.py: A fabric script for generate my personal blog</span>
<span class="go">Available commands:</span>
<span class="go"> bootstrap Get Pelican and install it in a virtual enviroment.</span>
<span class="go"> img4web Optimize .jpg & .png images and copy them into source pict...</span>
<span class="go"> new Create a new blog article.</span>
<span class="go"> publish Publish into remote server with rsync.</span>
<span class="go"> pull_pelican Update Pelican to last revision from repository.</span>
<span class="go"> regen Regenerate the site from source.</span>
</pre></div>
<p>Veamos que hacen cada una de ellas:</p>
<ul>
<li>
<p><strong><em>bootstrap</em></strong> Si observamos el código, veremos que lo hace es, en este orden:
eliminar cualquier entorno virtual previo, crear un entorno virtual nuevo,
descargar Pelican desde el repositorio (si no lo hemos hecho anteriormente) e
instalar Pelican dentro de este entorno virtual. Y todo esto en un solo paso, casi
todos los comandos que explicaba en <a href="http://joedicastro.com/pelican-introduccion-e-instalacion.html">Pelican - Introducción e Instalación</a> con
solo teclear <code>fab bootstrap</code>. Así de fácil. Con este comando podemos tanto crear
una instalación de Pelican desde cero, como actualizar la instalación de Pelican
después de actualizar este a la última versión con <strong><em>pull-pelican</em></strong>. Siguiendo
con nuestro ejemplo, lo que haría este comando es crear los directorios <em>env</em> y
<em>pelican</em> dentro de <em>myblog.com</em> con el entorno virtual creado y pelican
instalado.</p>
<div class="codehilite"><pre><span class="gp">$</span> fab bootstrap
</pre></div>
</li>
<li>
<p><strong><em>img4web</em></strong> Este comando hace uso del script que describía en <a href="http://joedicastro.com/optimizar-imagenes-para-la-web.html">Optimizar
imágenes para la web</a> para hacer precisamente eso, reducir el peso de las
imágenes que empleo en los artículos. Lo que hago es a medida que voy escribiendo
el articulo es ir guardando las imágenes en el directorio raíz (en nuestro
ejemplo, <em>myblog.com/</em>) y cuando lo termino, simplemente ejecuto el comando
<code>fab img4web</code> y este me optimiza las imágenes, me guarda las optimizadas en el
directorio de imágenes del contenido (<em>myblog.com/site/source/pictures/</em>) y me
elimina las imágenes originales del directorio raíz. Cuando termina me muestra un
resumen con la cantidad de imágenes procesadas y el ahorro en espacio conseguido.
Espacio en disco ahorrado que se resume en menos ancho de banda consumido y en
páginas web que se cargan más rápido.</p>
<div class="codehilite"><pre><span class="gp">$</span> fab img4web
</pre></div>
</li>
<li>
<p><strong><em>new</em></strong> Con este creo o edito los artículos del blog. Realiza
tres funciones: me abre una venta de Gedit con el articulo que le indico con la
extensión <code>.md</code>, me abre una ventana de Firefox que me muestra el fichero
<em>index.html</em> del directorio del sitio generado por Pelican
(<em>myblog.com/site/output/index.html</em>) y finalmente me activa Pelican con la
opción <code>autoreload</code>. Luego empleando el plugin <strong>Grid</strong> de Compiz, divido la
pantalla en dos mitades y coloco a la izquierda Gedit y a la derecha Firefox.
Esto me permite, como explicaba en <a href="http://joedicastro.com/de-drupal-a-pelican.html">De Drupal a Pelican</a> editar el contenido
y previsualizar el resultado casi en tiempo real, disponiendo al mismo tiempo de
un buen corrector ortográfico. </p>
<div class="codehilite"><pre><span class="gp">$</span> fab new:<span class="s2">"Articulo de prueba"</span>
</pre></div>
</li>
<li>
<p><strong><em>publish</em></strong> El más importante, el que sube los artículos al servidor web.
Publicar el contenido de la web es tan sencillo como ejecutar este comando. Lo
que hace es regenerar el contenido (por si hubiera algún cambio sin guardar) y
luego mostrarme el resultado en firefox. Pero el resultado que me muestra no es
el del directorio de salida de Pelican, si no de una copia que tengo en un
servidor Apache local. Esto me permite ver los cambios de manera más fiel a la
versión web, puesto que hace uso del fichero .htaccess y de las reglas que tengo
establecidas en él. Finalmente me pregunta si realmente deseo publicar el
contenido, por si se me hubiera escapado algo. Si le digo que no, aborta la
publicación, pero si le digo que si, me sincroniza el contenido de la carpeta
local con la remota empleando <strong>rsync</strong>. De esta manera solo se transmiten los
ficheros nuevos, se borran los que se hayan eliminado en local y <strong>solo transmite
la parte que haya cambiado de los archivos modificados</strong>. Gracias a esto,
modificar o añadir contenido es cuestión de segundos. Y sencillisimo.</p>
<div class="codehilite"><pre><span class="gp">$</span> fab publish
</pre></div>
</li>
<li>
<p><strong><em>pull_pelican</em></strong> Nos sirve para actualizar Pelican a la última revisión
disponible en el repositorio oficial. Si después de ejecutarlo, queremos instalar
la nueva versión en nuestro entorno virtual para poder emplearla, simplemente
tenemos que volver a ejecutar <code>fab bootstrap</code> y todo se realizará de forma
automática.</p>
<div class="codehilite"><pre><span class="gp">$</span> fab pull_pelican
</pre></div>
</li>
<li>
<p><strong><em>regen</em></strong> El proceso principal, es el que le pide a Pelican que genere el
sitio web a partir de nuestro directorio de origen. También realiza varios
procesos: primero eliminar el directorio de salida actual (para tener una copia
fresca), genera el nuevo contenido, luego procesa los archivos para que
validen en HTML5 y finalmente hace una copia del directorio de salida a mi
servidor local Apache. El procesar los archivos para validar en HTML5 se debe a
que markdown crea unos enlaces <code>rel = "footnote"</code> y <code>rev = "footnote"</code> en las notas
al pie que se han quedado obsoletos y no son necesarios. De momento es un
post-procesado, pero puede que finalmente modifique Pelican para que se haga en
tiempo de generación del sitio. Aunque creo que el rendimiento de esta manera
sería menor que emplear el comando <code>sed</code> que ejecuta este proceso, será cuestión
de probarlo. También se podría modificar markdown.</p>
</li>
</ul>
<p>Con solo <strong>6</strong> comandos tengo automatizadas todas las tareas básicas para
administrar y crear contenido en mi blog. Ni siquiera el potente y buenísimo
<a href="http://drupal.org/project/drush">drush</a> de Drupal me permitía este nivel de automatización (aunque se
acercaba bastante). De esta manera solo me tengo que preocupar de crear
artículos y de las posibles personalizaciones que le quiera realizar al tema del
sitio. Me olvido de todo lo demás, de todo lo que conlleva un CMS. Solo hay una
manera de bloguear más cómoda para los que a estos les parezca algo complejo,
servicios como Tumblr. Aunque si quieres tener el control sobre tu sitio, no
conozco manera más cómoda y con más ventajas que esta. </p>Pelican - Creación de contenido2011-06-27T18:27:00+02:00joe di castrohttp://joedicastro.com/pelican-creacion-de-contenido.html<p>Crear contenido con <strong>Pelican</strong> es lo más sencillo que uno pueda imaginarse. Por
ejemplo, crear este articulo, se puede hacer del siguiente modo. Abrimos un
editor de textos cualquiera (por ejemplo vi o gedit) y creamos un archivo nuevo
llamado Pelican, con la extensión <em>.md</em> si queremos emplear Markdown o <em>.rst</em> si
queremos emplear reStructuredText. Vemos como lo haría, para este blog en
concreto. Este sería el texto para crearlo en formato reStructuredText:</p>
<div class="codehilite"><pre><span class="gh">Pelican - Creación de contenido</span>
<span class="gh">###############################</span>
<span class="nc">:tags:</span> <span class="nf">Pelican, python, markdown, reStructuredText, blog, HTML.</span>
Crear contenido con <span class="gs">**Pelican**</span> es lo más sencillo que uno pueda imaginarse. Por
ejemplo, crear este articulo, se puede hacer del siguiente modo. Abrimos un
editor de textos cualquiera (por ejemplo vi o gedit) y creamos un archivo nuevo
llamado Pelican, con la extensión <span class="ge">*.md*</span> si queremos emplear Markdown o <span class="ge">*.rst*</span> si
queremos emplear reStructuredText.
</pre></div>
<p>Y este el que usaría para crearlo en markdown, que es el que yo empleo:</p>
<div class="codehilite"><pre>title: Pelican - Creación de contenido
tags: Pelican, python, markdown, reStructuredText, blog, HTML, Piwik, Disqus.
Crear contenido con **Pelican** es lo más sencillo que uno pueda imaginarse. Por
ejemplo, crear este articulo, se puede hacer del siguiente modo. Abrimos un
editor de textos cualquiera (por ejemplo vi o gedit) y creamos un archivo nuevo
llamado Pelican, con la extensión *.md* si queremos emplear Markdown o *.rst* si
queremos emplear reStructuredText. Vemos como lo haría, para este blog en
concreto.
</pre></div>
<p>Ahora solo tendríamos que guardar este fichero en la carpeta raíz de nuestro
contenido y ejecutar Pelican para generar la página web resultante. Así de
sencillo. Por ejemplo, creamos una carpeta <em>prueba</em> dentro de la estructura de
ficheros que habíamos creado en el <a href="http://joedicastro.com/pelican-introduccion-e-instalacion.html">articulo anterior</a> (<em>myblog.com/</em>) y
guardamos allí este fichero. Ahora ejecutamos pelican dentro del entorno virtual
y nos creara una carpeta <em>output</em> donde como resultado tendremos un blog por
defecto creado como por arte de magia. Es decir, hacemos esto:</p>
<div class="codehilite"><pre><span class="gp">$</span> mkdir prueba
<span class="gp">$</span> vi prueba/pelican.md
<span class="gp">$</span> <span class="nb">source </span>env/bin/activate
<span class="gp">$</span> pelican prueba/
<span class="gp">$</span> ls
<span class="go">env output pelican prueba site temp</span>
<span class="gp">$</span> firefox output/index.html
</pre></div>
<p>y obtenemos esto:</p>
<p style="text-align:center;"><img src="pictures/sample_article.png"
alt="pelican sample article" title="pelican sample article" width=700
height=465 /></p>
<h2 id="estructura_del_articulo">Estructura del articulo</h2>
<p>En el ejemplo anterior lo único que varía entre ambos formatos (aparte de la
sintaxis) es la cabecera del mismo. En la cabecera se incluye el titulo del
mismo (no tiene porque coincidir con el nombre del fichero) y los metadatos. El
titulo en reStructuredText va subrayado con símbolos <code>#</code> y en markdown es un
metadato más. Excepto el título, todos los metadatos son opcionales. Los
metadatos en <em>.rst</em> van precedidos de dos puntos <code>:</code>. Después de los metadatos
es suficiente con dejar una linea en blanco para comenzar a redactar el
contenido de nuestro articulo. </p>
<p>Los metadatos que se pueden incorporar son los siguientes:</p>
<ul>
<li>
<p><strong>title</strong> (solo como metadato en markdown): Es el titulo del artículo o página.</p>
</li>
<li>
<p><strong>date</strong>: Es la fecha y hora de publicación. Si no se indica, tomara como tal
los valores del propio fichero de texto. El formato es el siguiente:
año-mes-dia hora:minutos, es decir, <code>%Y-%m-%d %H:%M</code></p>
</li>
<li>
<p><strong>category</strong>: La categoría en la que queremos englobar el articulo. Si no se
especifica, puede coger la categoría por defecto que se haya especificado en el
fichero de configuración si así se ha establecido (por defecto es <em>misc</em>). Otra
forma aún más simple, es crear un directorio dentro de nuestro directorio de
contenido y colgar los archivos dentro de él. Todos los que se encuentren dentro
de ese directorio caerán en la categoría que coincida con el nombre del mismo.
Así es como yo lo hago, con un directorio llamado blog, es idoneo para organizar
el contenido. </p>
<p>En el tema por defecto, las categorías se añaden como una entrada al menú
superior que al ser seleccionada, muestra todos los artículos englobados dentro
de ella.</p>
</li>
<li>
<p><strong>author / authors</strong>: El autor(es) del articulo. Si se omite, escoge por
defecto el que se haya establecido en el fichero de configuración. Yo lo omito,
pero puede ser muy útil para blogs escritos por varios autores.</p>
</li>
<li>
<p><strong>tags</strong>: Las etiquetas con las que etiquetamos a nuestro articulo. El tema
por defecto solo nos permite seleccionar una y ver todos los artículos
etiquetados de igual modo, pero es bastante sencillo crear una nube de etiquetas
como la que empleo en este blog.</p>
</li>
<li>
<p><strong>summary</strong>: Es el resumen que queremos que se vea del articulo cuando se
emplea la paginación. Por defecto, si no se especifica este campo, los artículos
se resumen con las primeras 50 palabras del mismo.</p>
</li>
<li>
<p><strong>slug</strong>: Esta es uno de los campos más curiosos, pero al mismo tiempo más
geniales. Este campo es el nexo que nos permite enlazar varias versiones del
mismo articulo en distintos idiomas. En el tema por defecto, nos muestra las
distintas traducciones de un articulo, si es que existen.</p>
</li>
<li>
<p><strong>status</strong>: Esta es un campo especial que solo admite dos valores, <code>draft</code>
(borrador) y <code>published</code> (publicado). Cualquier otro valor es ignorado. Si el
valor es <code>draft</code>, el articulo o pagina no aparece publicado ni referenciado de
algún modo al generar el contenido, y solo está disponible si accedemos a él a
través del directorio <em>drafts/</em>. Esto es una ayuda para evitar que por un
descuido subamos a la web un articulo sin terminar. Yo no lo empleo, ya veremos
cuando hable de le automatización, como he resuelto este posible problema de
otro modo. Si lo empleamos, deberíamos añadir el directorio <em>drafts/</em> a nuestro
fichero <em>robots.txt</em> como <code>Disallow</code> para que no fuera indexado por los
buscadores (de poco importaría ocultar el el borrador si lo haces accesible a
través del buscador). </p>
</li>
</ul>
<p>Para comprender el resto de opciones disponibles para crear el contenido, voy a
centrarme en el sitio de ejemplo que viene por defecto con Pelican. Empezaremos
eliminando las pruebas que acabamos de realizar.</p>
<div class="codehilite"><pre><span class="gp">$</span> rm -r output/
<span class="gp">$</span> rm -r prueba/
<span class="gp">$</span> ls
<span class="go">env pelican site</span>
</pre></div>
<h2 id="estructura_del_contenido_del_ejemplo">Estructura del contenido del ejemplo</h2>
<p>Ahora, en el directorio de contenido del sitio de ejemplo, tenemos la siguiente
estructura de ficheros:</p>
<div class="codehilite"><pre><span class="gp">$</span> <span class="nb">cd </span>site/
<span class="gp">$</span> tree <span class="nb">source</span>/
<span class="go">source/</span>
<span class="go">├── another_super_article-fr.rst</span>
<span class="go">├── another_super_article.rst</span>
<span class="go">├── cat1</span>
<span class="go">│ ├── article1.rst</span>
<span class="go">│ ├── article2.rst</span>
<span class="go">│ ├── article3.rst</span>
<span class="go">│ └── markdown-article.md</span>
<span class="go">├── draft_article.rst</span>
<span class="go">├── extra</span>
<span class="go">│ └── robots.txt</span>
<span class="go">├── pages</span>
<span class="go">│ └── test_page.rst</span>
<span class="go">├── pictures</span>
<span class="go">│ ├── Fat_Cat.jpg</span>
<span class="go">│ ├── Sushi.jpg</span>
<span class="go">│ └── Sushi_Macro.jpg</span>
<span class="go">├── super_article.rst</span>
<span class="go">├── unbelievable.rst</span>
<span class="go">└── unwanted_file</span>
</pre></div>
<p>Donde:</p>
<ul>
<li>
<p><strong><em>another_super_article-fr.rst</em></strong> y <strong><em>another_super_article.rst</em></strong> son dos
versiones del mismo articulo en inglés y francés. Aunque cuelgan del directorio
raíz, ambos están englobados dentro del sitio en la categoría <em>bar</em> a través del
metadato <strong>category</strong> y enlazados traducciones mediante el metadato <strong>slug</strong>
<code>:slug: oh-yeah</code></p>
</li>
<li>
<p><strong><em>draft_article.rst</em></strong> es un articulo que no aparece publicado en el sitio
de ejemplo al estar marcado como borrador con el metadato <strong>status</strong>, pero al
que podemos acceder igualmente a través de
<code>myblog.com/site/source/drafts/a-draft-article.html</code></p>
</li>
<li>
<p><strong><em>super_article.rst</em></strong> y <strong><em>unbelievable.rst</em></strong> son ejemplos de uso de
metadados. El primero es un articulo que cuelga de la categoría <em>yeah</em> y
que sirve como ejemplo del empleo de <strong>summary</strong> y del uso de imágenes y
código. El segundo es un ejemplo de articulo sin más metadatos que la
fecha del mismo y de como cae en la categoría <strong>misc</strong> por defecto.</p>
</li>
<li>
<p><strong><em>unwanted_file</em></strong> es un articulo que no se procesa de ningún modo por
carecer de extensión que lo identifique como markdown o reStructuredText. Como
consecuencia este fichero ni siquiera se copia al sitio web generado. Puede ser
un truco útil para emplearlo como fichero de notas personales de cualquier tipo,
por ejemplo un recordatorio de como hemos definido la estructura de archivos,
una chuleta como usar marcado o reStructuredText, artículos pendientes, ...</p>
</li>
<li>
<p><strong><em>cat1</em></strong> Este directorio es un ejemplo de como todos los artículos que
cuelgan de él son englobados dentro de la categoría <em>cat1</em> de forma automática.
Esto nos evita escribir el metadato <strong>category</strong> en cada uno de ellos y nos
ayuda a clasificarlos en el directorio. Y nos muestra como se pueden mezclar
archivos markdown y reStructuredText sin ningún tipo de problemas.</p>
</li>
<li>
<p><strong><em>extra</em></strong> En esta carpeta (puede ser otra, es configurable) englobamos
archivos que queremos incluir en el sitio, pero que no han de ser procesados.
Como por ejemplo: .htaccess, .robots.txt,
<a href="http://humanstxt.org/ES">.humans.txt</a>, ... Esto puede cambiarse en el
fichero de configuración, especificando el origen dentro del directorio de
nuestro contenido y la ruta en la que queremos que esté en el sitio web. En
este caso, sería así en el fichero de configuración <code>pelican.conf.py</code></p>
<div class="codehilite"><pre><span class="n">FILES_TO_COPY</span> <span class="o">=</span> <span class="p">((</span><span class="s">'extra/robots.txt'</span><span class="p">,</span> <span class="s">'robots.txt'</span><span class="p">),)</span>
</pre></div>
</li>
<li>
<p><strong><em>pages</em></strong> Serían las páginas estáticas del sitio, lo que no son artículos.
Este nombre de directorio está reservado para esta función por defecto. Por
ejemplo la página <a href="http://joedicastro.com/pages/markdown.html"><em>markdown</em></a> que
empleo en este blog, sería una de estas páginas estáticas. En estas páginas
no están disponibles los comentarios. Si se especifica en el fichero de
configuración, estas páginas aparecerán como entradas en el menú principal
del tema por defecto. </p>
</li>
<li>
<p><strong><em>pictures</em></strong> Este es uno de los directorios que se pueden emplear para
albergar contenido estático como son las imágenes. Esto es configurable en el
fichero de configuración. En este caso lo que se guardan en el son las imágenes
empleadas en los artículos. Estas acabaran dentro del directorio
<code>static/pictures/</code> de nuestro sitio. </p>
</li>
</ul>
<p>Y ya está, es una estructura muy sencilla y que genera un resultado bastante
decente, comparado con los cientos de archivos que emplea (a parte de la BDD)
cualquier CMS como Wordpress o Drupal.</p>
<p>Si partiéramos de un blog ya creado, Pelican proporciona una herramienta, que
en nuestro caso estaría en <em>/myblog.com/pelican/tools/importer.py</em> y que nos
permite importar artículos desde Wordpress o desde un fichero RSS y que nos
genera los contenidos en reStructuredText. Si quisiéramos emplear markdown,
existe una herramienta externa, <a href="http://www.codefu.org/wiki/Main/Html2markdown"><strong>html2markdown</strong></a> que nos permite obtener
un texto en markdown desde una página web. Otra herramienta similar a esta
última sería <a href="http://www.aaronsw.com/2002/html2text/">html2text</a>.</p>
<p>No tiene más secreto que este, crear ficheros de texto plano en formato <em>.md</em> o
<em>.rst</em>, guardarlos en el directorio que empleamos para albergar el contenido
y generar el blog.</p>Pelican - Introducción e Instalación2011-06-27T10:21:00+02:00joe di castrohttp://joedicastro.com/pelican-introduccion-e-instalacion.html<p><a href="http://docs.notmyidea.org/alexis/pelican/">Pelican</a> es un generador de sitios web con contenido estático. Está orientado
originalmente a la creación de blogs. <strong>Pelican</strong> (Pelicano) es una anagrama de
la palabra francesa <em>Calepin</em> que significa en español "cuaderno de notas"
(blog). Su creador y desarrollador principal es el programador francés
<a href="http://blog.notmyidea.org/">Alexis Métaireau</a>. Y es la aplicación que genera el contenido para este
blog. Personalmente le veo muchas ventajas frente a una plataforma de blogs
convencional como Wordpress o Drupal, como ya comentaba en mi <a href="http://joedicastro.com/de-drupal-a-pelican.html">anterior articulo</a>. </p>
<p>Pelican genera este contenido estático (páginas HTML) a partir de ficheros de
texto plano formateados en un lenguaje de marcado ligero como <a href="http://es.wikipedia.org/wiki/Markdown">Markdown</a> o
<a href="http://es.wikipedia.org/wiki/ReStructuredText">reStructuredText</a>. También crea fuentes RSS y Atom de los artículos. Y
dependiendo del tema empleado se pueden tener un archivo de los artículos
publicados, clasificación por categorías, nube de etiquetas, un <a href="http://es.wikipedia.org/wiki/Blogroll">blogroll</a>,
enlaces a redes sociales, botón para tweeter, paginación, traducciones, etc.
Aunque viene un tema completo por defecto y están disponibles <a href="https://github.com/ametaireau/pelican-themes">algunos más</a>,
se puede crear uno completamente personalizado desde cero. La creación de
estos temas se basa en el sistema de plantillas <a href="http://jinja.pocoo.org/">jinja2</a>, lo que nos
permite una gran flexibilidad. También disponemos de varios scripts que nos
proporcionan soporte para comentarios con <a href="http://disqus.com">Disqus</a> y de analíticas con
<a href="http://www.google.com/intl/es/analytics/">Google Analytics</a> ó <a href="http://piwik.org/">Piwik</a>. También nos permite generar ficheros PDFs de
los artículos automáticamente y mostrar los enlaces a ellos, siempre que los
artículos se hayan creado con reStructuredText.</p>
<p>Es un software muy joven, el primer commit en <a href="https://github.com/ametaireau/pelican">GitHub</a> data del 13 de Agosto de
2010, pero que ha evolucionado bastante rápido y que aún sigue desarrollándose a
un buen ritmo. Es posible que por esto aún tenga alguna carencia o algún que
otro fallo, pero su autor es muy receptivo y acepta de buena gana las sugerencias,
informes de errores y colaboraciones de desarrollo. Cuenta con una documentación
bastante decente y actualizada. Alguno que otra cosa no está documentada, pero
lo veo normal dado el ritmo de desarrollo y de a quien va orientado un software
como este. Es muy sencilla su instalación y su utilización cuando se ha leído
esta, pero será mejor que lo explique con un ejemplo sobre la marcha.</p>
<h2 id="instalaci+n_para_linux">Instalación (para Linux)</h2>
<p>La instalación del mismo es relativamente sencilla si no queremos complicarnos
la vida, siempre tenemos la última versión disponible en el <a href="http://pypi.python.org/pypi/pelican/2.7.2">PyPi</a>. Así que
instalarlo podría ser tan sencillo como esto:</p>
<div class="codehilite"><pre><span class="gp">$</span> easy_install pelican
</pre></div>
<p>Aunque recomiendo emplear <a href="http://www.pip-installer.org/en/latest/index.html"><code>pip</code></a> en lugar de <code>easy_install</code>, de este modo:</p>
<div class="codehilite"><pre><span class="gp">$</span> pip install pelican
</pre></div>
<p>De todos modos desaconsejo emplear este método, me parece mejor solución, dada
la velocidad de desarrollo del software, emplear un entorno virtual para su
instalación. Un <a href="http://www.virtualenv.org/en/latest/index.html">entorno virtual</a> nos permite tener una versión de Python
independiente de la del resto del sistema, con sus propias librerías y con el
software instalado que nosotros deseemos. Todo esto solo estará disponible cuando
nos encontremos dentro de este entorno virtual, sin afectar al resto del
sistema. Y podemos eliminarlo o des/activarlo cuando deseemos. Es bastante más
sencillo de utilizar de lo que parece y es realmente potente. </p>
<p>Veamos, paso a paso, la forma en que yo lo instalaría.</p>
<p>Creamos una carpeta que contendrá Pelican, el entorno virtual y el sitio que
crearemos. Yo le daría el nombre de la URL del blog, por ejemplo, <em>myblog.com</em></p>
<div class="codehilite"><pre><span class="gp">$</span> mdkir myblog.com
<span class="gp">$</span> <span class="nb">cd </span>myblog.com
</pre></div>
<p>Descargamos la revisión actual del repositorio de Pelican en GitHub. Esto nos
creara una carpeta llamada <em>pelican</em> que contendrá una copia del repositorio en
local (lo cual nos será muy útil en el futuro para actualizarlo). </p>
<div class="codehilite"><pre><span class="gp">$</span> git clone git://github.com/ametaireau/pelican.git
<span class="go">Cloning into pelican...</span>
<span class="go">remote: Counting objects: 2603, done.</span>
<span class="go">remote: Compressing objects: 100% (1143/1143), done.</span>
<span class="go">remote: Total 2603 (delta 1541), reused 2420 (delta 1374)</span>
<span class="go">Receiving objects: 100% (2603/2603), 687.30 KiB | 397 KiB/s, done.</span>
<span class="go">Resolving deltas: 100% (1541/1541), done.</span>
</pre></div>
<p>Ahora vamos a crear nuestro entorno virtual. En caso de no tener instalado <code>pip</code>
o <code>virtualenv</code>, es rematadamente sencillo:</p>
<div class="codehilite"><pre><span class="gp">$</span> easy_install pip
<span class="gp">$</span> pip install virtualenv
</pre></div>
<p>Voy a llamar <em>env</em> a nuestro entorno virtual. Lo creamos así.</p>
<div class="codehilite"><pre><span class="gp">$</span> virtualenv env
<span class="go">New python executable in env/bin/python</span>
<span class="go">Installing distribute...........................................................</span>
<span class="go">................................................................................</span>
<span class="go">.......................................done.</span>
<span class="gp">$</span> ls
<span class="go">env pelican</span>
</pre></div>
<p>Ahora activaremos nuestro entorno virtual para "sumergirnos" dentro de él. </p>
<div class="codehilite"><pre><span class="gp">$</span> <span class="nb">source </span>env/bin/activate
<span class="gp">(env)$</span>
</pre></div>
<p>Vemos que aparece el nombre del entorno virtual entre paréntesis antes de la
línea del <a href="http://es.wikipedia.org/wiki/Prompt">prompt</a>. Eso quiere decir que
nos encontramos dentro de este entorno virtual. Ahora procederemos a instalar
Pelican. </p>
<div class="codehilite"><pre><span class="gp">$</span> <span class="nb">cd </span>pelican/
<span class="gp">$</span> python setup.py install
</pre></div>
<p>Ahora tenemos ya instalado Pelican, <strong>solo dentro de nuestro entorno virtual</strong>.
Si probamos a llamar al programa fuera de él, veremos que no está disponible,
luego necesitaremos activar este entorno cada vez que queramos emplearlo.</p>
<div class="codehilite"><pre><span class="gp">$</span> pelican
<span class="go">CRITICAL: you need to specify a path containing the content (see pelican --help for </span>
<span class="go">more information)</span>
</pre></div>
<p>Nos da un error porque no le hemos pasado los parámetros necesarios. Ahora
desactivamos el entorno y volvemos a llamar al programa y nos dice que no
existe.</p>
<div class="codehilite"><pre><span class="gp">$</span> deactivate
<span class="gp">$</span> pelican
<span class="go">pelican: orden no encontrada</span>
</pre></div>
<p>Tenemos ahora dentro de <em>myblog.com/</em> dos directorios, <em>env</em> y <em>pelican</em>.
Podríamos borrar ahora el directorio <em>pelican</em> porque ya lo tenemos instalado
dentro del entorno virtual, pero sería bueno conservarlo para poder actualizarlo
en el futuro mediante <code>git pull</code>. Yo crearía una tercer directorio, <em>site</em> donde
se alojaría nuestro sitio, organizado a su vez en tres subdirectorios: </p>
<ul>
<li>
<p><strong>source</strong>: sería la carpeta donde alojaríamos los archivos de texto de
nuestro blog y todo aquello que quisiéramos que formara parte de nuestro sitio:
imágenes, fichero <a href="http://es.wikipedia.org/wiki/Htaccess">.htacess</a>, fichero <a href="http://es.wikipedia.org/wiki/Robots.txt">robots.txt</a>, páginas
personalizadas...</p>
</li>
<li>
<p><strong>output</strong>: El resultado del procesamiento de Pelican, es decir, nuestro blog.</p>
</li>
<li><strong>theme</strong> : Sería el tema que usariamos para crear nuestro blog, en el
estarían las plantillas <strong>jinja2</strong>, las hojas de estilo .css, el contenido
estático (iconos, imágenes), ...</li>
</ul>
<p>Luego, lo haríamos así:</p>
<div class="codehilite"><pre><span class="gp">$</span> <span class="nb">cd</span> ..
<span class="gp">$</span> mkdir -p site/source
<span class="gp">$</span> mkdir site/output
<span class="gp">$</span> mkdir site/theme
<span class="gp">$</span> ls site/
<span class="go">output source theme</span>
</pre></div>
<p>Ya está, tenemos instalado Pelican y creada nuestra estructura para empezar a
trabajar con él. Para eso nada mejor que crear un primer sitio de ejemplo.
Entramos en el entorno virtual y creamos el sitio que viene de ejemplo con
Pelican:</p>
<div class="codehilite"><pre><span class="gp">$</span> <span class="nb">source </span>env/bin/activate
<span class="gp">$</span> pelican pelican/samples/content/ -o site/output -s pelican/samples/pelican.conf.py
</pre></div>
<p>Y ahora si abrimos el fichero <code>myblog.com/site/output/index.html</code> en un
navegador, veremos algo como esto (en la imagen se ve la categoría cat1
seleccionada):</p>
<p style="text-align:center;"><img src="pictures/sample_blog.png"
alt="pelican sample blog" title="pelican sample blog" width=453 height=700 /></p>
<p>Es así de fácil de emplear Pelican, simplemente especificarle el directorio donde
está el origen del contenido, el directorio destino y el fichero de configuración.
Aunque con el fichero de configuración correctamente creado, solo será necesario
indicarle la ubicación del mismo. Para comprender mejor la estructura y como
funciona Pelican, sería buena idea copiar el tema, el fichero de configuración y
el contenido que han generado este sitio de ejemplo a la carpeta <em>site</em> para no
empezar nuestro blog desde cero.</p>
<div class="codehilite"><pre><span class="gp">$</span> cp -r pelican/samples/content/* site/source
<span class="gp">$</span> cp -r pelican/pelican/themes/notmyidea/* site/theme/
<span class="gp">$</span> cp pelican/samples/pelican.conf.py site/
</pre></div>
<p>En próximos artículos veremos como crear artículos, publicar el sitio,
personalizar el tema y automatizar todos estos procesos para hacerlo todo mucho
más sencillo. </p>De Drupal a Pelican2011-06-22T02:10:00+02:00joe di castrohttp://joedicastro.com/de-drupal-a-pelican.html<p>Este blog no está realizado con ningún <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr>, ni siquiera utiliza <abbr title="Base de datos">BDD</abbr> alguna, es
simplemente HTML + CSS y nada más. Es decir, es contenido estático, no dinámico.
Hasta hace 3 días estaba funcionando con el mejor <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> <a href="http://es.wikipedia.org/wiki/PHP">PHP</a> que conozco,
<a href="http://drupal.org">Drupal</a>. Pero persiguiendo el camino hacia el minimalismo y la productividad
(fiel al espíritu <a href="http://es.wikipedia.org/wiki/Principio_KISS"><abbr title="Keep It Simple, Stupid (en español, "Mantenlo simple, estúpido"). Ver enlace"><abbr title="Keep It Simple, Stupid (en español, "Mantenlo simple, estúpido"). Ver enlace">KISS</abbr></abbr></a>) que ya inicie cuando <a href="http://joedicastro.com/markdown-la-mejor-opcion-para-crear-contenidos-web.html">comencé a escribir todos mis
artículos en Drupal con Markdown</a>, el siguiente paso era evidente. La pregunta
era muy sencilla, si un blog consta de contenidos que rara vez cambian
(exceptuando los comentarios) ¿para que necesito un gestor de contenidos
dinámicos?</p>
<p>La respuesta es fácil, para nada. Actualmente, gracias a servicios como los de
<a href="http://disqus.com">Disqus</a>, <a href="http://livefyre.com/">Livefyre</a>, <a href="http://intensedebate.com/">IntenseDebate</a> ó <a href="http://www.aboutecho.com/commenting">Echo</a> es posible
externalizar el único contenido dinámico básico de un blog, los comentarios.
Todo lo demás puede ser contenido puramente estático, solo HTML y CSS, sin
renunciar a prácticamente nada de lo que nos ofrece un blog basado en un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr>
como Wordpress o Drupal. Se pueden emplear scripts externos en javascript si se
desea, o insertarlos dentro del HTML. Lo que nos permite implementar lo mismo
que en un blog normal. Además se puede disponer también de feeds RSS y Atom.<br />
</p>
<h2 id="elegir_un_generador_de_contenido_est+tico">Elegir un generador de contenido estático</h2>
<p>Evidentemente la idea no es crear las paginas HTML a mano, ni de broma, lo lógico
era seguir empleando la misma estrategia que ya había iniciado con Drupal,
emplear solo ficheros de texto en formato Markdown que nos generarán el HTML
necesario de forma automática. Entonces lo que tenía que encontrar era un
software que me permitiera hacer lo mismo que Drupal, pero sin toda la
parafernalia que rodea a un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr>. Un generador de sitios web estáticos (a partir
de markdown) y que a ser posible estuviera escrito en <strong>Python</strong>, mi lenguaje
favorito. Como ya adelante en el <a href="http://joedicastro.com/markdown-la-mejor-opcion-para-crear-contenidos-web.html">artículo sobre Markdown</a>, existen varias opciones:</p>
<ul>
<li><a href="http://docs.notmyidea.org/alexis/pelican/">Pelican</a> de Alexis Métaireau, que emplea en su propio <a href="http://blog.notmyidea.org/">blog</a></li>
<li><a href="http://www.blogofile.com/">Blogofile</a> de Ryan McGuire que también lo usa en su <a href="http://www.enigmacurry.com/">blog</a></li>
<li><a href="http://hyde.github.com/">Hyde</a> de Lakshmi Vyas. Su <a href="http://ringce.com/blog/">blog</a> con Hyde también.</li>
<li><a href="https://github.com/mitsuhiko/rstblog">rstblog</a> de Armin Ronacher. Solo permite reStructuredText, con él crea su
<a href="http://lucumr.pocoo.org/">blog</a>, un ejemplo de elegancia y calidad.</li>
</ul>
<p>Bueno, tenía varias posibilidades, solo tenía que elegir una que se adaptara
mejor a mis necesidades. De entrada descarté <strong>rstblog</strong> porque no permitía el
empleo de markdown, cuando los otros permitían tanto .rst como .md como formatos
de entrada. Solo me quedaban 3 candidatos. Así que lo primero que hice antes de
nada, fue buscar blogs creados con cada uno de ellos, para ver que posibilidades
reales ofrecían. Encontré ejemplos de blogs de mucha calidad de todos ellos.
Aunque enseguida me di cuenta de una cosa, en dos de ellos los mejores blogs lo
eran porque tenían una elevada personalización detrás (artículos de sus autores
contándolo). Y curiosamente con el tercero, casi todos preferían quedarse con la
configuración estándar, sin tocar prácticamente nada, y la verdad es que el
resultado era bastante decente. Luego miré que cargaba cada uno de ellos en la
página de entrada, y volvía a repetirse la misma tendencia. En los dos primeros
vi demasiadas hojas de estilo, imágenes y demasiados scripts javascript, en el
tercero, nuevamente se cargaban menos elementos. Finalmente comparé
características, modo de funcionamiento y le eché un vistazo rápido al código.
La impresión era otra vez la misma, dos de ellos, <strong>Hyde</strong> y <strong>Blogofile</strong> aunque
aparentemente potentes, los veía innecesariamente complejos, en cambió
<strong>Pelican</strong> era bastante más sencillo. Otra forma de determinar su repercusión
era contar el número de descargas de cada una de las aplicaciones desde PyPi.
Los números son los siguientes (a 27 de Junio de 2011), obtenidos con
<a href="https://github.com/aclark4life/vanity">Vanity</a> o <a href="http://pythonpackages.com/">pythonpackages.com</a>:</p>
<table>
<thead>
<tr>
<th>Paquete</th>
<th>Descargas</th>
<th>Descargas (2-12-2011)</th>
<th>Descargas (7-4-2012)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Blogofile</td>
<td>2.419</td>
<td>3.854</td>
<td>5.276</td>
</tr>
<tr>
<td>Hyde</td>
<td>1.945</td>
<td>4.518</td>
<td>7.644</td>
</tr>
<tr>
<td>Pelican</td>
<td>3.919</td>
<td>6.138</td>
<td>10.126</td>
</tr>
</tbody>
</table>
<p>La elección final era Pelican y no me arrepiento en absoluto, la prueba es que
esté blog está funcionando gracias a él (Gracias Alexis!). Aunque las otras dos
son también muy buenas opciones, y seguramente serían la primera opción para más
de uno. Y siempre podría cambiar fácilmente, porque el contenido seguiría estando
guardado en ficheros de texto con marcado markdown. </p>
<blockquote>
<p><strong>Actualización</strong> (2-12-2011): </p>
<p>La estructura de Pelican es tan sencilla y eficaz, que <a href="http://www.solberg.is/">Jökull Sólberg</a>
ha creado a partir de una versión hospedada del mismo (y modificada) una de las
plataformas de blogs más simples de utilizar que existen, <a href="http://calepin.co/">calepin.co</a>.
Publicar articulos es tán fácil como crear un archivo markdown y guardarlo en tu
cuenta de <a href="http://www.dropbox.com/">Dropbox</a>. Así de sencillo.</p>
</blockquote>
<p>No entraré en detalles ahora de como instalar y emplear <strong>Pelican</strong>, eso lo dejo
para otro próximo articulo, <a href="http://joedicastro.com/pelican-introduccion-e-instalacion.html">Pelican</a>. Pero si voy a hacer un repaso de los
pros y los contras de emplear Pelican frente a un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> como Drupal para crear un
blog.</p>
<h2 id="ventajas_de_pelican_vs_cms">Ventajas de Pelican vs <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr></h2>
<h3 id="solo_ficheros_de_texto_no_bdd">Solo ficheros de texto, No <abbr title="Base de datos">BDD</abbr></h3>
<p>Simplemente te tienes que preocupar de eso, ficheros de texto, es donde guardas
el contenido que creas. Todo lo demás lo genera Pelican por ti. Nada de crear y
gestiónar bases de datos, ni copias de seguridad de la misma y un montón de
espacio y recursos desaprovechado solamente para generar dinámicamente el mismo
contenido que te genera Pelican.</p>
<h3 id="mejor_rendimiento_carga_de_p+gina_m+s_r+pida">Mejor rendimiento, carga de página más rápida</h3>
<p>Generar contenido dinámico es más caro en recursos y es más lento (consultas a
la <abbr title="Base de datos">BDD</abbr>). Sobre todo a medida que llenas tu <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> de personalizaciones y plugins.
¿Que hacen prácticamente todos los sistemas de caché?, generar contenido
estático para luego servirlo más rápidamente. ¿No es un poco estúpido crear
contenido que apenas cambia en el tiempo, en un sistema dinámico que genera ese
contenido cada vez y que para mejorar su rendimiento lo convierte en estático?
Y ya no hablemos de las múltiples hojas CSS, scripts javascript y enlaces a
contenido externo que cargan la mayoría de los <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> por defecto. Cada plugin que
añadimos pone su granito de arena y optimizar todo esto requiere dedicación y
esfuerzo (o seguir sumando aún más plugins en el mejor de los casos). Con
Pelican ya tienes directamente el contenido estático y menos recursos que
descargar. En este blog, sin contar con los ficheros javascript de Disqus y
Piwik, lo único que se descarga es un fichero HTML, una hoja CSS y las imágenes
que se incluyen en los artículos (cuando las hay). Es decir sirves el mismo
contenido pero generando menos tráfico desde tu servidor. </p>
<h3 id="soporta_mejor_el_tr+fico">Soporta mejor el tráfico</h3>
<p>Cuando un sitio web soporta mucho tráfico, emplear un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> requiere de mucha
optimización y generalmente de mucha maquina o complejas instalaciones. Y la
base principal siempre es un sistema de caché que sirva contenido lo más
estático posible. Se cachea todo lo que se puede, y si es en memoria mejor. Las
<abbr title="Base de datos">BDD</abbr> son un problema aparte, desde soluciones NoSQL a clusters o <abbr title="Base de datos">BDD</abbr> distribuidas.
Con contenido estático no te tienes que preocupar de optimizar los accesos a la
<abbr title="Base de datos">BDD</abbr>, solo de tener un buen servidor web y si quieres, cachear en memoria o
ampliar máquina. Pero poco más.</p>
<h3 id="seguridad">Seguridad</h3>
<p>Olvídate de problemas de seguridad, los únicos agujeros de seguridad de un sitio
con contenido estático están del lado del servidor web, de todo lo demás, te
olvidas. Establece bien los permisos en el sistema de ficheros y punto. El único
contenido dinámico del sitio (javascript) ni siquiera es algo que deba
preocuparte, es algo externo que le concierne a <strong>Disqus</strong> o al sistema de
analíticas web que elijas (Google Analytics o Piwik).</p>
<h3 id="olvidarse_de_gestionar_un_cms_mantenimiento_mucho_m+s_sencillo_nulo">Olvidarse de gestionar un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr>. Mantenimiento mucho más sencillo (nulo)</h3>
<p>Instalar el <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr>, crear la <abbr title="Base de datos">BDD</abbr>, encontrar, instalar y probar los plugins que
necesitas, actualizaciones, actualizaciones de seguridad, personalizaciones,
temas... Todo lo que rodea a cualquier <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr>. Y ya no digamos si hablamos de un
<abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> potente y complejo como Drupal, con cientos de posibilidades. Y sin olvidar
toda la basura que se va acumulando en las <abbr title="Base de datos">BDD</abbr> tras varias actualizaciones y
múltiples pruebas de plugins, con Pelican siempre tienes un sistema limpio.
Todo eso lo olvidas con Pelican, lo instalas, personalizas y automatizas una
sola vez, luego te olvidas de todo lo que no sea escribir (si quieres, nada te
impide seguir cambiándolo y mejorándolo). Emplea tú tiempo en crear contenido.</p>
<h3 id="backups_m+s_sencillos">Backups más sencillos</h3>
<p>Con un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> <abbr title="No hacerlas es una decisión nefasta">deberías hacer Backups</abbr> del servidor web tanto del sistema de ficheros
como de la <abbr title="Base de datos">BDD</abbr>. Y sería aconsejable tener un servidor web local montado para
probar los cambios que vayas a hacer en el <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> sin miedo a romper nada. Con
Pelican ni siquiera necesitas hacer Backups del servidor ni del contenido web.
Todo lo que necesitas para generarlo ya está en tu ordenador en esos ficheros de
texto. Incluso si empleas un tema propio, también está en tu equipo. Así que las
copias de seguridad de tu sitio web no son distintas a las que
<abbr title="No me digas que aún no las haces, ¿estas de broma?">regularmente ya haces</abbr> de tu ordenador personal.</p>
<h3 id="hosting_en_cualquier_sitio">Hosting en cualquier sitio</h3>
<p>Solo tienes que alojar contenido estático, no necesitas <abbr title="Base de datos">BDD</abbr> ni soporte para
ningún lenguaje o librería en particular. Puedes hasta utilizar recursos
gratuitos como las páginas de <a href="https://github.com/">GitHub</a> o <a href="http://bitbucket.org/">BitBucket</a> o un sistema
de ficheros en la nube económico como <a href="http://aws.amazon.com/es/s3/">Amazon S3</a> (o
<a href="http://aws.amazon.com/es/cloudfront/">Amazon CloudFront</a>). Solo necesitas eso, servir ficheros, nada más. Hasta
el hosting más económico te sirve. </p>
<h3 id="emplear_un_cvs_para_gestionarlo">Emplear un <abbr title="Control Version System (en español, "Sistema de Control de Versiones")">CVS</abbr> para gestionarlo</h3>
<p>Poder emplear Git o Mercurial o cualquier otro <abbr title="Control Version System (en español, "Sistema de Control de Versiones")">CVS</abbr> para gestionar los cambios
del blog no tiene precio. Ningún sistema de revisiones de <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> es tan potente.
Además tienes la posibilidad de crear un <em>hook</em> para que al enviar un commit
después de crear un articulo (o realizar un cambio) se suba el contenido
automáticamente al servidor. Con esto realizar cualquier cambio o revertir un
error es algo trivial. Además te permite subir una copia a un sitio como GitHub
o BitBucket y tenerlo siempre disponible en cualquier sitio con conexión a la
red. Como maravillosa opción, esto permite que el contenido de un blog, incluso
de un mismo articulo, sea editado por más de una persona de manera bastante más
sencilla, potente y menos propensa a errores que con un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr>. </p>
<h3 id="crear_los_articulos_off-line">Crear los articulos off-line</h3>
<p>Eso te permite ir creando los artículos al ritmo que te de la gana, cuando
quieras y en cualquier sitio con un portátil. No necesitas estar conectado a la
red. Esto también puede hacerse con un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr>, pero suele ser más complejo
(exceptuando emplear cortar y pegar) e inseguro (si se habilita el envío remoto
de artículos). Yo lo había logrado en Drupal empleando markdown, pero seguía
necesitando un segundo paso on-line para personalizar las etiquetas. </p>
<h3 id="edici+n_de_art+culos_m+s_c+moda">Edición de artículos más cómoda</h3>
<p>Puede parecer que un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> con su editor WYSIWYG es más cómodo, pero todo lo
contrario. Ya lo comentaba en el <a href="http://joedicastro.com/markdown-la-mejor-opcion-para-crear-contenidos-web.html">artículo sobre markdown</a>. Pero es que
además me proporciona una mejor experiencia de edición y más potente. Explico
como redacto yo los artículos para que se entienda mejor. Divido la pantalla en
dos mitades, a la izquierda el editor de textos y a la derecha el navegador.
Como editor de textos empleo Gedit, que tiene resaltado de texto para markdown y
un corrector ortográfico (por esto no uso vim para esto) bastante mejor que el
de Firefox (que solo examina el texto hasta cierto número de casos dudosos).
Además Pelican tiene una maravillosa opción, <code>autoreload</code> que lo hace correr en
segundo plano y cuando detecta un cambio en uno de los ficheros, vuelve a generar
el contenido. Entonces en gedit le digo que autoguarde el contenido cada 3
minutos (o a voluntad, manualmente) y cuando Pelican lo detecta, automáticamente
regenera los ficheros HTML. Como navegador empleo Firefox y tengo, abierto en
una pestaña, el fichero <code>index.html</code> que genera Pelican y empleando la extensión
<a href="https://addons.mozilla.org/es-ES/firefox/addon/auto-reload/?src=api">Auto Reload</a> el contenido de la página (en local) se actualiza
automáticamente al detectar un cambio en el fichero. Es decir, como en la
primera página se puede ver el contenido completo del último articulo, lo que
estoy viendo es una previsualización automática del contenido en la página cada
3 minutos. Y todo esto en off-line, sin estar conectado a internet. Esto si es
un verdadero editor WYSIWYG, y no los otros. Además, que demonios, los
navegadores no se diseñaron para crear texto, cualquier editor de texto es más
potente.</p>
<h3 id="control_del_spam">Control del Spam</h3>
<p>El Spam, esa lacra que azota toda la web. En Pelican, ese problema, lo tiene que
gestionar Disqus, no tú. Tú solo tienes que gestionar el poco que se le escape.
Pero el buscar un plugin, configurarlo y que funcione bien, es algo de lo que no
tienes que preocuparte. En Drupal tenía este asunto solucionado, pero fue cosa
de probar varios plugins, hasta que al final <a href="http://joedicastro.com/combatir-el-spam-en-drupal.html">di con uno que me lo solucionaba de
verdad</a>. </p>
<h3 id="recursos_de_cpu_y_ram">Recursos de CPU y RAM</h3>
<p>El contenido dinámico consume mucha más memoria RAM y CPU en el servidor que
servir contenido estático. Al fin y al cabo, en el caso del contenido estático,
es poco más complejo que servir ficheros. Si tienes que compartir el servidor
con más proyectos, agradecerás no tener que emplear un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> para servir el blog.</p>
<h3 id="resaltado_de_sintaxis_incorporada_con_pygments">Resaltado de Sintaxis incorporada con Pygments</h3>
<p>Mientras en la mayoría de <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> necesitas un plugin para habilitar el resaltado de
sintaxis para código fuente, en Pelican esto viene por defecto empleando el
excelente <a href="http://pygments.org/">Pygments</a></p>
<h3 id="cumplimiento_de_est+ndares_web">Cumplimiento de Estándares Web</h3>
<p>Con Pelican es relativamente sencillo configurar el tema para que cumpla los
estándares web y genere contenido valido. Y una vez que lo haces, es para
siempre, a no ser que modifiques algo en el tema, todo el contenido que generes
cumplirá con los estándares (a no ser que incluyas HTML dentro que no lo sea).
De este modo, este sitio valida HTML5, CSS3 y genera feeds RSS y Atom validos.
Conseguir esto con un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> y empleando editores WYSIWYG es bastante más complejo
y doloroso. Aunque yo lo había conseguido con Drupal y markdown, tuve que
modificar un tema casi por completo, casi como crearlo desde cero. </p>
<h2 id="inconvenientes_de_pelican_vs_cms">Inconvenientes de Pelican vs <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr></h2>
<h3 id="comentarios_sin_resaltado_de_sintaxis">Comentarios sin resaltado de sintaxis</h3>
<p>Algo que me permitía Drupal y no me permite Disqus (por ahora) era emplear
markdown en los comentarios y resaltado de sintaxis para el código fuente. Es el
mayor inconveniente que he encontrado hasta ahora. Pero bueno, tampoco es algo
imprescindible y esperemos que Disqus lo soporte en un futuro.</p>
<h3 id="sitemap">Sitemap</h3>
<p>Tampoco Pelican genera sitemaps en xml para los buscadores. Aunque tampoco es
algo imprescindible y Drupal tampoco lo soporta por defecto, si no a través de
un módulo. El autor lo tiene como tarea pendiente, y si tarda mucho, a lo mejor
me animo y lo creo yo mismo.</p>
<h3 id="personalizaci+n_m+s_sencilla_para_non_geeks">Personalización más sencilla para non geeks</h3>
<p>Esta es la parte que menos me afecta, pero es el gran inconveniente para la gran
mayoría sin conocimientos avanzados. Aunque Pelican no es difícil de instalar y
configurar, si queremos personalizarlo bastante, la cosa cambia. Los <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> son
mucho más sencillos en ese sentido, pero el coste a pagar por otro lado no me
compensa. </p>
<h3 id="no_tiene_b+squeda_incorporada">No tiene búsqueda incorporada</h3>
<p>Es otro pequeño inconveniente que puede suplirse empleando la de Google AdSense
en el sitio, por ejemplo. Personalmente no me importa demasiado, teniendo
disponibles en el sitio recursos como el archivo de todos los artículos
publicados o la nube de etiquetas.</p>
<h3 id="no_puedes_personalizar_el_contenido_din+micamente">No puedes personalizar el contenido dinámicamente</h3>
<p>Con un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> puedes hacer cosas como mostrar un contenido o un tema distinto según
el perfil del usuario, o según la carga del servidor, etc. Con contenido
estático lógicamente no puedes hacer esto. A mi me da igual, no lo necesito, es
solo un blog.</p>
<br />
<p>Llevo varios años empleando Drupal en varios sitios y me sigue pareciendo un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr>
excelente y una buenísima opción para generar contenido dinámico para no
desarrollladores (de otro modo prefiero un framework como Django). Pero
actualmente, para crear blogs, si se tienen conocimientos suficientes, emplear
un <abbr title="Content Management System (en español, "Sistema de gestión de contenidos")">CMS</abbr> me parece una decisión poco acertada, es matar moscas a cañonazos. Hoy en
día hay soluciones como Pelican y las mencionadas arriba (y otras alternativas
en otros lenguajes) que te permiten crear blogs con facilidad, centrándote
únicamente en crear los artículos y automatizar todo lo demás. ¿Acaso esa no es
la razón principal del grandisimo éxito de <a href="http://twitter.com/">twitter</a> o <a href="http://www.tumblr.com/">tumblr</a>?
La inmediatez de los resultados y la delegación de la gestión a terceros, tú
solo escribes. Pelican te permite lo mismo, solo requiere la personalización
inicial y listo, con la ventaja añadida de que puedes personalizarlo a tu gusto
y hasta donde te dé la gana o seas capaz.</p>Markdown, la mejor opción para crear contenidos web2011-04-02T20:29:00+02:00joe di castrohttp://joedicastro.com/markdown-la-mejor-opcion-para-crear-contenidos-web.html<p>Normalmente cuando se crea contenido en un blog o CMS, como Wordpress, Blogger,
Drupal, Joomla, Plone, Typo, etc, se hace a través de un editor visual (<abbr title="What You See Is What You Get (en inglés, "lo que ves es lo que obtienes")">WYSIWYG</abbr>).
Algunos editores de este tipo son <a href="http://tinymce.moxiecode.com/">TinyMCE</a>, <a href="http://ckeditor.com/">CKeditor</a>, <a href="http://nicedit.com/">NicEdit</a>,
<a href="http://www.wymeditor.org/">WYMEditor</a>, <a href="http://markitup.jaysalvat.com/home/">markItUP!</a>, <a href="http://www.openwebware.com/">openWYSIWYG</a>, etc.</p>
<p>Yo mismo he empleado varios de ellos durante años, en varias plataformas como
Blogger, Wordpress, Joomla, Drupal, etc. Y si, hay que reconocerlo, te hacen la
vida muy fácil, sobre todo para aquellos que no quieran preocuparse más que de
añadir contenido en su página. E incluso usuarios más avanzados como
administradores o diseñadores web, lo suelen emplear por comodidad frente a un
área de texto plano. Y si, es cómodo, muy cómodo, a corto plazo. A largo plazo...
a largo plazo es cuando empiezas a verle los peros y los problemas, que los
tienen, y bastantes. Veamos cuales son esos problemas y la alternativa, que para
mi personalmente, es la solución.</p>
<h2 id="los_problemas_de_los_editores_wysiwyg">Los problemas de los editores <abbr title="What You See Is What You Get (en inglés, "lo que ves es lo que obtienes")">WYSIWYG</abbr></h2>
<p>Los editores visuales están pensados para que de una forma muy fácil, se pueda
editar el contenido de forma visualmente atractiva, sin tenerse que andar
preocupando del HTML que se genera a partir de él, esto es, no es necesario
conocer nada de HTML para usar un editor <abbr title="What You See Is What You Get (en inglés, "lo que ves es lo que obtienes")">WYSIWYG</abbr>. Puedes añadir negritas,
cursivas, alinear el texto, cambiar el tamaño, el color, crear tablas, etc, sin
conocimiento alguno de HTML o CSS. Se supone que el editor genera HTML valido
correctamente por ti. Y aquí es donde empiezan los problemas:</p>
<ul>
<li>
<p>Los editores visuales generalmente crean el formato con <strong>CSS embebido dentro
del HTMl</strong>, es decir mezclando el contenido y el estilo de la página. Algunos
incluso te permiten incluir tus propias hojas de estilo para que el contenido
se ajuste al estilo actual de tu web.</p>
<p>¿Pero que ocurre cuando al cabo de un tiempo, con decenas o más de artículos
generados quieres cambiar el estilo de tú página? Pues dependiendo de como
haya realizado el trabajo tu editor <abbr title="What You See Is What You Get (en inglés, "lo que ves es lo que obtienes")">WYSIWYG</abbr>, te puedes encontrar con el
desagradable problema de que todo queda desencajado o no se ajusta al estilo
actual. Yo me he tenido que enfrentar con este problema en el pasado al
actualizar una versión de Drupal y cambiar completamente el tema, y no fue
nada cómodo de solucionar, o al importar contenido de un CMS a otro.</p>
</li>
<li>
<p>Los editores visuales <strong>se crearon inicialmente para impresión en papel</strong>, no
para HTML. Y HTML se emplea en multitud de dispositivos (desde móviles hasta
ereaders) y bien empleado proporciona una flexibilidad que se rompe al mezclar
la estructura del documento (HTML) con el estilo del mismo (CSS) en el mismo
archivo. Así que a la hora de crear versiones para dispositivos móviles, con
todas esas etiquetas CSS embebidas, puede ser un verdadero quebradero de cabeza.</p>
</li>
<li>
<p>Se supone que <strong>tienen que generar HTML válido</strong>, pero durante mucho tiempo
<strong>esto no ha sido siempre así</strong>, sobre todo si el editor no está bien
configurado o tiene algún plug-in que no respeta este tema. Además, generan
HTML valido ahora, ¿que pasa en el futuro? Es decir, si quieres pasar
contenido antiguo para por ejemplo pasar de HTML 2.0 a HTML 4.0 o incluso 5
y eliminar etiquetas obsoletas y generar HTML que cumpla con el estándar,
prepárate, porque te espera una ardua tarea. Por no decir que muchos de estos
editores tienen errores en su propio código javascript, lo que lleva a
frecuentes actualizaciones de los mismos.</p>
</li>
<li>
<p>Pueden <strong>generar cantidades absurdas de HTML</strong>, sobre todo si no están
correctamente configurados. Algunos editores (a veces con la configuración por
defecto hacen esto, y tienes que ser tú quien lo ajuste para que no ocurra)
crean toneladas de <code><div></code>,<code><p></code> y <code><span></code> sin sentido y totalmente superfluos.
Cuando no emplean tablas para formatear algunas presentaciones complejas. Y ni
que decir tiene de aquellos editores visuales que te dejan pegar contenido
desde un procesador de textos como Word, el HTML generado en estos casos,
bueno, hay que verlo para creerlo, un absoluto despropósito.</p>
</li>
<li>
<p>Es incluso factible que un usuario inexperto pueda <strong>romper el diseño de una
página a través de un editor <abbr title="What You See Is What You Get (en inglés, "lo que ves es lo que obtienes")"><abbr title="What You See Is What You Get (en inglés, "lo que ves es lo que obtienes")">WYSIWYG</abbr></abbr></strong>, creando párrafos o <code><div></code> de forma
inadecuada. Incluso al reescribir un texto es posible que se mezclen estilos
CSS embebidos antiguos con nuevos, generando unos embrollos inmensos a nivel de
HTML. Y ya no digo nada de los que rompen el estilo visual de un tema abusando
de colores en las fuentes, tamaños, etc</p>
</li>
<li>
<p>El <strong>contenido</strong> que se guarda <strong>en la base de datos</strong> esta <strong>mezclado con</strong>
las etiquetas <strong>HTML y CSS</strong>, todo junto, vamos que no se parece en nada a lo
que has introducido en tu editor. Todo esto en principio carece de importancia,
pero puede suponer hasta el 20% del tamaño de las páginas de tu sitio, espacio
absurdamente desperdiciado en tu BDD. De hecho el contenido XHTML se genera por
lo normal cada vez que se visualiza la página de forma dinámica. Si te preocupa
el rendimiento, tranquilo, los sistemas de cache están ahí para echarte una
mano y que te dejes de preocupar por eso.</p>
</li>
<li>
<p><strong>Distraen la atención</strong>, el problema de absolutamente todos los editores
visuales, incluidos procesadores de texto, el centrarse en el formato y no en
el contenido. Una gran mayoría de usuarios desperdicia un tiempo notable
preocupándose por más el aspecto visual del documento, que por el contenido del
mismo. Que si esto en negrita, que si mejor con esta fuente, que si mejor con
la otra... Se desvía la atención de lo importante, el contenido. Mal amigo de
la productividad, se tarda bastante más en general, por esta razón, en generar
el mismo contenido en un editor <abbr title="What You See Is What You Get (en inglés, "lo que ves es lo que obtienes")">WYSIWYG</abbr>.</p>
</li>
<li>
<p><strong>Son bastante poco flexibles</strong>, si quieres introducir tu propio HTMl en el
contenido (e.g. para tener un control más fino sobre las tablas, yo lo hago en
este articulo) puede que te encuentres que lo genera como lo tiene
preestablecido, eliminado la estructura que tu quieras darle. Y embeber
contenido multimedia o scripts también es frecuentemente un problema, siendo
hasta habitual que existan plugins para estos editores para insertar contenidos
de sitios como YouTube.</p>
</li>
<li>
<p>Todos los editores <abbr title="What You See Is What You Get (en inglés, "lo que ves es lo que obtienes")">WYSIWYG</abbr> <strong>aumentan el peso por página y disminuyen la
velocidad de carga</strong>, al necesitar pesado código javascipt que necesita tanto
ser descargado como ejecutado por tu navegador. Ya de por si los CMS suelen
emplear bastante código javascript, como para encima añadirle un editor visual.
Además realizan bastantes llamadas HTTP, ralentizando aún más la velocidad de
carga. Ejemplo: tienes un articulo de 80 lineas de texto cuyo contenido XHTML
puede pesar tranquilamente de 10 á 20 veces menos que el javascript del editor,
¿no es un poco ridículo?. Aunque muy pocos editores web se preocupan de esto,
la verdad, es que hay que pensar que no todo el mundo disfruta de buenas
conexiones a la red.</p>
</li>
<li>
<p>Por último y no menos importante, <strong>no cuidan la accesibilidad</strong>. El HTML
valido que cumpla con los estándares, es esencial para crear páginas con una
buena accesibilidad, pensando en aquellos que no lo tienen tan fácil para
navegar por nuestros sitios web. Deberían tenerse al menos en cuenta un mínimo
de puntos sobre este tema al crear contenidos en la web.</p>
</li>
</ul>
<p>En conclusión, que los editores <abbr title="What You See Is What You Get (en inglés, "lo que ves es lo que obtienes")">WYSIWYG</abbr> pueden no dar problemas hasta que tus
necesidades cambian, entonces pueden darte más de un quebradero de cabeza.</p>
<br />
<h2 id="mark">Texto plano y Markdown</h2>
<p>¿Cual sería entonces la solución para esquivar estos problemas? Texto plano,
nada más, que se transforme automáticamente en HTML valido respetando el formato
que nosotros queramos darle. Esto existe, y es posible gracias a los lenguajes
de marcado ligero, entre los que se encuentra <a href="http://daringfireball.net/projects/markdown/">Markdown</a>. Nada mejor que
empezar demostrándolo con un ejemplo:</p>
<div>
<table>
<thead><tr><th style="width: 50%;">Markdown</th><th>Resultado</th></tr></thead>
<tbody><tr>
<td><pre class="no_mrkdwn">
<p>Documento de ejemplo
====================</p><p>Lorem ipsum [dolor sit amet](#mark), consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum **semper adipiscing leo** et blandit.</p><p>Sed nibh quam, hendrerit _sit amet aliquam_ vel, pulvinar molestie augue.</p><p>> Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</p><p>Lista numerada (ordenada)</p><p>1. Este es el primer elemento
2. Este es el segundo elemento
* Una lista de puntos anidada
* Se llama también desordenada
* Tercer nivel de anidamiento
3. Este es el tercer elemento</p><p></p><p>### Cabecera ###</p><p>- - -</p><p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p><p>
| | solo texto | HTML Limpio |
| -------------- | -- | ------- |
| Markdown | Si | Si |
| Editor WYSISWG | X | A veces |</p><p>
:::python
import lifetime
for each_day in lifetime.days():
carpe_diem()</p><p>Suspendisse posuere velit et velit vehicula at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis.</p><p>Esto es un texto con nota al pie [^prima] y esta es otra nota [^secunda]</p><p>
*[vehicula]: automobila
[^prima]: Esto es una nota al pie.
[^secunda]: Esto es la segunda nota.</p></pre>
</td>
<td>
<h1>Documento de ejemplo</h1>
<p>Lorem ipsum <a href="#mark">dolor sit amet</a>, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum <strong>semper adipiscing leo</strong> et blandit.</p>
<p>Sed nibh quam, hendrerit <em>sit amet aliquam</em> vel, pulvinar molestie augue.</p>
<blockquote>
<p>Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</p>
</blockquote>
<p>Lista numerada (ordenada)</p>
<ol><li>Este es el primer elemento</li>
<li>Este es el segundo elemento
<ul><li>Una lista de puntos anidada</li>
<li>Se llama también desordenada
<ul><li>Tercer nivel de anidamiento</li>
</ul></li>
</ul></li>
<li>Este es el tercer elemento</li>
</ol><p><img src="pictures/avatar.png" alt="avatar" /></p>
<h3>Cabecera</h3>
<p><hr /><p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p></p>
<table><thead><tr><th></th>
<th>solo texto</th>
<th>HTML Limpio</th>
</tr></thead><tbody><tr><td>Markdown</td>
<td>Si</td>
<td>Si</td>
</tr><tr><td>Editor WYSISWG</td>
<td>X</td>
<td>A veces</td>
</tr></tbody></table>
<div class="codehilite"><pre><span class="kn">import</span> <span class="nn">lifetime</span>
<p><span class="k">for</span> <span class="n">each_day</span> <span class="ow">in</span> <span class="n">lifetime</span><span class="o">.</span><span class="n">days</span><span class="p">():</span>
<span class="n"> carpe_diem</span><span class="p">()</span></pre></div>
<p>Suspendisse posuere velit et velit <abbr title="automobila">vehicula</abbr> at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis.</p></p>
<p>Esto es un texto con nota al pie <sup id="fnref:prima"><a href="#fn:prima" rel="footnote">1</a></sup> y esta es otra nota <sup id="fnref:secunda"><a href="#fn:secunda" rel="footnote">2</a></sup></p>
<div class="footnotes">
<hr /><ol><li id="fn:prima">
<p>Esto es una nota al pie. <a href="#fnref:prima" rev="footnote">↩</a></p>
</li>
<li id="fn:secunda">
<p>Esto es la segunda nota. <a href="#fnref:secunda" rev="footnote">↩</a></p>
</li>
<p></ol>
</td>
</tr>
</tbody></table>
</div></p>
<p>Es así de sencillo, el texto plano que se escribe en la columna de la izquierda
genera el HTML que se puede ver representado en la derecha. Es además HTML
valido, sin CSS embebido (exceptuando el código con resaltado de sintaxis, pero
esto es necesario y tampoco es generado por <strong>Markdown</strong> si no por
<a href="http://qbnz.com/highlighter/">GeSHi</a> anteriormente y ahora por <a href="http://pygments.org/">Pygments</a>) y empleando el
mínimo necesario, siendo lo más limpio posible.
Pero el contenido que se guarda en la base de datos y el que tú editas es el de
la izquierda. Este contenido generará HTML valido hoy y mañana, es totalmente
independiente del estilo que emplees en tu página y puedes migrarlo de un CMS a
otro sin problema alguno. Todo son ventajas, el único inconveniente es que tienes
que aprender a usar <strong>Markdown</strong>, algo que es sumamente sencillo, a la par que
incrementa la legibilidad del texto plano.</p>
<p>La legibilidad del texto es uno de los pilares fundamentales de <strong>Markdown</strong>, tal
y como el mismo autor, <a href="http://en.wikipedia.org/wiki/John_Gruber">John Gruber</a>, lo cuenta<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup>:</p>
<blockquote>
<p>El objetivo fundamental de diseño para la sintaxis de Markdown es hacerlo tan
legible como sea posible. La idea es que un documento formateado con Markdown
debería poder ser publicado tal y como está, como texto plano, sin que parezca
que ha sido marcado con etiquetas o instrucciones de formateado. Mientras que la
sintaxis de Markdown ha sido influenciada por muchos filtros texto-a-HTML
existentes, la principal fuente de inspiración es el formato de los correos
electronicos en texto plano.</p>
</blockquote>
<p>No voy ahora, en este articulo, a enseñarte a emplear <strong>Markdown</strong>, pero tienes
una guía de prácticamente todas las posibilidades que te brinda en
<a href="http://joedicastro.com/pages/markdown.html">Markdown & Pygments Lexers Cheat Sheet</a>.
Además, si somos así de vagos, podemos emplear también algunos editores visuales
que generan y emplean markdown, como <a href="http://markitup.jaysalvat.com/home/">markItUP!</a> o el conocido <a href="http://code.google.com/p/wmd/">WMD</a> que
empleamos en <a href="http://python.majibu.org">python majibu</a>. Aunque ambos editores
solo soportan Markdown estándar, cuando en este sitio también soporto las
capacidades adicionales de <a href="http://michelf.com/projects/php-markdown/extra/">Markdown Extra</a>.</p>
<p>Todo el contenido de este sitio (exceptuando el automático, como las búsquedas,
etiquetas, acerca de, ...) está generado empleando <strong>Markdown</strong> y todo está en
HTML 5 valido. Un ejemplo del HTML que genera Markdown sería el siguiente:</p>
<table>
<thead>
<tr>
<th style="width: 50%;">Markdown</th><th>HTML</th>
</tr>
<tbody>
<tr>
<td>
<pre class="no_mrkdwn">
Documento de ejemplo
====================
Lorem ipsum [dolor sit amet](#mark), consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum **semper adipiscing leo** et blandit.
Sed nibh quam, hendrerit _sit amet aliquam_ vel, pulvinar molestie augue.
</pre>
</td>
<td>
<pre class="no_mrkdwn">
<h1>Documento de ejemplo</h1>
<p>Lorem ipsum <a href="#mark">dolor sit amet</a>, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum <strong>semper adipiscing leo</strong> et blandit.</p>
<p>Sed nibh quam, hendrerit <em>sit amet aliquam</em> vel, pulvinar molestie augue.</p>
</pre>
</td>
</tr>
</tbody>
</table>
<p>Como se puede ver es el HTMl justo, limpio y cumpliendo estándares, ni más ni
menos. Este es un ejemplo muy sencillo, y posiblemente cualquier editor <abbr title="What You See Is What You Get (en inglés, "lo que ves es lo que obtienes")">WYSIWYG</abbr>
sea capaz de dar el mismo resultado, el problema aparece con documentos más
complejos, con sucesivas re-ediciones del texto y con editores mal configurados.
Eso si, lo que se almacena en la BDD con <strong>Markdown</strong> es texto plano, con los
otros editores, el texto, las etiquetas HTML y CSS embebido.</p>
<h2 id="+porque_markdown_y_no_otros">¿Porque Markdown y no otros?</h2>
<p>Evidentemente <strong>Markdown</strong> no es el único <a href="http://es.wikipedia.org/wiki/Lenguajes_de_marcas_ligeros">lenguaje de marcado ligero</a>,
existen otros también conocidos y extendidos como <a href="http://textile.thresholdstate.com/">Textile</a>, <a href="http://www.bbcode.org/">BBCode</a>,
<a href="http://docutils.sourceforge.net/rst.html">reStructuredText</a>, <a href="http://texy.info/en/">Texy!</a>, <a href="http://txt2tags.org/">Txt2tags</a> o los empleados en los Wikis
como <a href="http://www.wikicreole.org/">Creole</a> o el de <a href="http://www.mediawiki.org/wiki/Help:Formatting">MediaWiki</a>.</p>
<p>En primer lugar <strong>Markdown</strong> es uno de los que más características soporta, uno
de los que más salidas puede generar (no solo HTML, también LaTeX, RTF, PDF,
EPUB, ...) y además es probablemente el más extendido y soportado de todos
(exceptuando BBCode y los de los Wikis, empleados en sus nichos particulares).
Pero también es uno de los más fáciles de emplear (saliendo del formato básico
como negritas, etc) y que produce un texto plano más vistoso y legible.</p>
<h3 id="comparativa">Comparativa</h3>
<p>Como no, lo mejor, es ver una comparativa con un ejemplo del mismo documento y
el texto empleado por cada uno de los lenguajes para generarlo. Para ello he
creado un articulo aparte para mostrarla.</p>
<p><a href="http://joedicastro.com/comparativa-de-lenguajes-de-marcado-ligero.html">Comparativa</a></p>
<h2 id="+qui+n_emplea_markdown">¿Quién emplea Markdown?</h2>
<p>Una de las razones para emplear <strong>Markdown</strong> es porque es uno de los más
extendidos, sobre todo en el mundo de la programación. Por ejemplo,
<a href="http://stackoverflow.com/">Stack Overflow</a> y todos los sitios de <a href="http://stackexchange.com/">Stack Exchange</a> emplean una
variante de Markdown para la entrada de texto. Repositorios de código como
<a href="https://github.com/">GitHub</a> y <a href="https://bitbucket.org/">Bitbucket</a> también lo emplean para ciertas funciones.
También lo emplea el sistema de seguimiento de incidencias <a href="http://lighthouseapp.com/">LightHouse</a>.</p>
<p>Fuera del ámbito de la programación, sitios tan conocidos como <a href="http://www.reddit.com/">Reddit</a> lo
emplean. Plataformas para la educación online como <a href="http://moodle.org/">Moodle</a> o
<a href="http://podmedics.heroku.com/">Podmedics</a> también hacen uso de él. Un Wiki como <a href="http://www.instiki.org/">Instiki</a> permite
emplear Markdown. Plataformas de blogs y contenidos como <a href="https://posterous.com/">Posterous</a>,
<a href="http://www.tumblr.com/">Tumblr</a> y <a href="http://www.squarespace.com/">Squarespace</a> lo ofrecen como opción. Y seguro que me estoy
dejando en el tintero muchos más lugares donde es empleado habitualmente.</p>
<p>Hay que tener en cuenta de que aquí no he hablado de software CMS que lo soporta,
eso lo contemplo en el próximo punto, si no más bien de organizaciones/compañías.</p>
<h2 id="excusas_para_no_emplearlo">Excusas para no emplearlo</h2>
<p>La primera que dice todo el mundo, es un incordio usarlo y aprenderlo, la
pregunta es: ¿Has intentado emplearlo? Créeme se aprende en nada, sobre la
marcha, y una vez que te acostumbras a él, lo elegirás frente a los editores
<abbr title="What You See Is What You Get (en inglés, "lo que ves es lo que obtienes")">WYSIWYG</abbr>, casi con toda seguridad. Una vez aprendido no tienes que separar los
dedos de tu teclado, no necesitas para nada el ratón para crear tu contenido.
Ganarás mucho tiempo para ti mismo y lo agredeceras, créeme.</p>
<p>La segunda, no puedo usarlo en mi CMS o blog. ¿Seguro? A continuación te detallo
las opciones que conozco para publicar contenidos empleando <strong>Markdown</strong>.</p>
<h3 id="cms_y_blogs">CMS y Blogs:</h3>
<ul>
<li>Por defecto, como opción o nativamente:<ul>
<li><a href="http://nestacms.com/">Nesta</a></li>
<li><a href="http://kohanut.com/">Kohanut</a></li>
<li><a href="http://www.movabletype.org/">MovableType</a></li>
<li><a href="http://fdv.github.com/typo/">Typo</a></li>
</ul>
</li>
<li>Con añadidos:<ul>
<li><a href="http://drupal.org/">Drupal</a> A través de un modulo, <a href="http://drupal.org/project/markdown">Markdown Filter</a></li>
<li><a href="http://wordpress.org/">Wordpress</a> Hay varios plugins disponibles para emplearlo.</li>
<li><a href="http://djangoproject.com/">Django</a> Hay varias formas de soportarlo.</li>
<li><a href="http://plone.org">Plone</a> Se puede habilitar a través de un modulo.</li>
<li><a href="http://blogger.com">Blogger</a> A través de algunos proyectos externos, <a href="http://code.google.com/p/blogger-markdown-editor/">Blogger-markdown-editor</a></li>
<li><a href="http://expressionengine.com/">ExpressionEngine</a> A través de un plugin.</li>
<li><a href="http://www.joomla.org/">Joomla</a> A través de una extensión, <a href="http://extensions.joomla.org/extensions/edition/code-display/8391">jMarkdown</a></li>
</ul>
</li>
</ul>
<h3 id="generadores_de_sitios_con_contenido_est+tico_html">Generadores de sitios con contenido estático (HTML):</h3>
<ul>
<li><a href="https://github.com/ametaireau/pelican/">Pelican</a></li>
<li><a href="http://ringce.com/hyde">hyde</a></li>
<li><a href="http://www.blogofile.com/">Blogofile</a></li>
<li><a href="https://bitbucket.org/obensonne/poole/src">Poole</a></li>
<li><a href="https://github.com/xfire/growl/tree">Growl</a></li>
<li><a href="http://markdoc.org/">Markdoc</a></li>
<li><a href="http://webgen.rubyforge.org/">Webgen</a></li>
<li><a href="http://nanoc.stoneship.org/">nanoc</a></li>
<li><a href="http://jekyllrb.com/">jekyll</a></li>
<li><a href="http://jaspervdj.be/hakyll/">Hakyll</a></li>
<li><a href="http://webby.rubyforge.org/">Webby</a></li>
<li><a href="http://cloudhead.io/toto">toto</a></li>
<li><a href="http://rote.rubyforge.org/">Rote</a></li>
</ul>
<h3 id="plataforma_de_blogs_con_contenido_est+tico_html">Plataforma de Blogs con contenido estático (HTML):</h3>
<ul>
<li><a href="http://calepin.co/">Calepin.co</a> es un <strong>Pelican</strong> hospedado, que lee ficheros
markdown desde <strong>DropBox</strong></li>
</ul>
<h3 id="wiki">Wiki:</h3>
<ul>
<li>Por defecto, como opción o nativamente:<ul>
<li><a href="http://instiki.org">Instiki</a></li>
<li><a href="http://ikiwiki.info/">ikiwiki</a></li>
<li><a href="http://sputnik.freewisdom.org/">sputnik</a></li>
<li><a href="http://alt.textdrive.com/nanoki/">nanoki</a></li>
<li><a href="https://github.com/jgm/gitit">gitit</a></li>
</ul>
</li>
<li>Con añadidos:<ul>
<li><a href="http://moinmo.in/">MoinMoin</a> con una <a href="http://moinmo.in/ParserMarket/Markdown">extensión</a></li>
<li><a href="http://www.mediawiki.org">MediaWiki</a> con una <a href="http://www.mediawiki.org/wiki/Extension:MarkdownSyntax">extensión</a></li>
<li><a href="http://www.dokuwiki.org/">DokuWiki</a></li>
<li><a href="http://oddmuse.org/">Oddmuse</a></li>
<li><a href="http://www.pmwiki.org/">PmWiki</a></li>
</ul>
</li>
</ul>
<h3 id="foros">Foros:</h3>
<ul>
<li><a href="http://www.phpbb.com/">phpBB</a> A través de un
<a href="http://www.phpbb.com/community/viewtopic.php?f=70&t=2093183">MOD</a></li>
</ul>
<h3 id="conversor_markdown_desdea_otros_formatos">Conversor Markdown desde/a otros formatos:</h3>
<ul>
<li><a href="http://johnmacfarlane.net/pandoc/try">Pandoc</a></li>
</ul>
<h3 id="editores_de_texto_que_lo_soportan_marcado_de_sintaxis">Editores de Texto que lo soportan (marcado de sintaxis):</h3>
<ul>
<li><a href="http://www.vim.org/">Vim</a> con <a href="https://github.com/plasticboy/vim-markdown">Vim-Markdown</a></li>
<li><a href="http://www.gnu.org/software/emacs/">Emacs</a> con <a href="http://jblevins.org/projects/markdown-mode/">markdown-mode</a></li>
<li><a href="http://projects.gnome.org/gedit/">Gedit</a> con <a href="http://live.gnome.org/Gedit/MarkdownSupport">gedit-markdown</a></li>
<li><a href="http://www.eclipse.org/">Eclipse</a> con el experimental <a href="http://www.winterwell.com/software/markdown-editor.php">markdown editor</a></li>
<li><a href="http://macromates.com/">TextMate</a></li>
<li><a href="http://www.codingmonkeys.de/subethaedit/">SubEthaEdit</a></li>
<li><a href="http://ecto.kung-foo.tv/">Ecto</a></li>
<li><a href="http://www.red-sweater.com/marsedit/">MarsEdit</a></li>
</ul>
<h3 id="editor_markdown">Editor Markdown:</h3>
<ul>
<li><a href="http://sourceforge.net/p/retext/home/">ReText</a></li>
<li><a href="http://markdownpad.com/">Markdown Pad</a></li>
<li><a href="http://bywordapp.com/">Byword</a></li>
</ul>
<h3 id="editor_offline_para_blogs">Editor Offline para blogs:</h3>
<ul>
<li><a href="http://qtm.blogistan.co.uk/">QTM</a></li>
</ul>
<h3 id="editores_online_para_probar_markdown">Editores Online para probar Markdown:</h3>
<ul>
<li><a href="http://daringfireball.net/projects/markdown/dingus">Dingus</a> por <a href="http://daringfireball.net/">John Gruber</a></li>
<li><a href="http://michelf.com/projects/php-markdown/dingus/">Dingus PHP</a> por Michel Fortin</li>
<li><a href="http://anthonybush.com/markdown_extra_geshi/">Markdown Extra + GeShi</a> por Anthony Bush</li>
<li><a href="http://dillinger.io/">Dillinger</a> es una aplicación en HTML 5 por Joe McCann</li>
<li><a href="http://babelmark.bobtfish.net/?markdown=*This+**is+a+test*.&normalize=on">Babelmark</a> para comparar las distintas implementaciones de Markdown</li>
<li><a href="http://joncom.be/experiments/markdown-editor/edit/">Markdown Editor</a> por John Combe</li>
<li><a href="http://softwaremaniacs.org/playground/showdown-highlight/">Showdown</a></li>
<li><a href="http://markdownr.com/">Markdownr</a></li>
</ul>
<p>Y si eres desarrollador, tienes disponibles distintas implementaciones de Markdown:</p>
<table>
<thead>
<tr>
<th>Lenguaje</th>
<th>Implementaciones</th>
</tr>
</thead>
<tbody>
<tr>
<td>Python</td>
<td><a href="http://www.freewisdom.org/projects/python-markdown/">Python-markdown</a></td>
</tr>
<tr>
<td>PHP</td>
<td><a href="http://michelf.com/projects/php-markdown/">PHP Markdown y PHP Markdown Extra</a></td>
</tr>
<tr>
<td>Perl</td>
<td><a href="http://daringfireball.net/projects/markdown/">Original</a> y <a href="https://github.com/fletcher/MultiMarkdown">MultiMarkdown</a></td>
</tr>
<tr>
<td>Ruby</td>
<td><a href="http://deveiate.org/projects/BlueCloth">BlueCloth</a>, <a href="https://github.com/nex3/maruku">Maruku</a> y <a href="http://kramdown.rubyforge.org/">Kramdown</a></td>
</tr>
<tr>
<td>C#</td>
<td><a href="http://aspnetresources.com/blog/markdown_announced">Markdown.NET</a></td>
</tr>
<tr>
<td>C</td>
<td><a href="http://www.pell.portland.or.us/~orc/Code/markdown/">Discount</a> y <a href="https://github.com/jgm/peg-markdown">Peg-Markdown</a></td>
</tr>
<tr>
<td>C++</td>
<td><a href="http://cpp-markdown.sourceforge.net/">Cpp-markdown</a></td>
</tr>
<tr>
<td>Java</td>
<td><a href="http://sourceforge.net/projects/markdownj/">MarkdownJ</a></td>
</tr>
<tr>
<td>Javascript</td>
<td><a href="https://github.com/coreyti/showdown">Showdown</a></td>
</tr>
<tr>
<td>Lua</td>
<td><a href="http://www.frykholm.se/files/markdown.lua">markdown.lua</a></td>
</tr>
<tr>
<td>Haskell</td>
<td><a href="http://johnmacfarlane.net/pandoc/">Pandoc</a></td>
</tr>
<tr>
<td>Common Lisp</td>
<td><a href="http://common-lisp.net/project/cl-markdown/">CL-Markdown</a></td>
</tr>
<tr>
<td>Scala</td>
<td><a href="http://tristanhunt.com/projects/knockoff/">Knockoff</a> y <a href="http://henkelmann.eu/projects/actuarius/">Actuarius</a></td>
</tr>
</tbody>
</table>
<p>Entonces, habiendo tantas opciones, ¿por qué no lo pruebas?</p>
<p>Y si hay más excusas, pues la verdad, no las conozco, dímelas tú.</p>
<div class="footnote">
<hr />
<ol>
<li id="fn:1">
<p>The overriding design goal for Markdown’s formatting syntax is to make
it as readable as possible. The idea is that a Markdown-formatted document
should be publishable as-is, as plain text, without looking like it’s been
marked up with tags or formatting instructions. While Markdown’s syntax has
been influenced by several existing text-to-HTML filters, the single biggest
source of inspiration for Markdown’s syntax is the format of plain text
email. <a href="http://daringfireball.net/projects/markdown/">fuente</a> <a href="#fnref:1" rev="footnote" title="Jump back to footnote 1 in the text">↩</a></p>
</li>
</ol>
</div>Comparativa de Lenguajes de marcado ligero2011-04-02T20:29:00+02:00joe di castrohttp://joedicastro.com/comparativa-de-lenguajes-de-marcado-ligero.html<p>Esta es una comparativa de los lenguajes de marcado ligero más empleados de los
disponibles actualmente. Dicha comparativa surge a partir de este articulo,
<a href="http://joedicastro.com/markdown-la-mejor-opcion-para-crear-contenidos-web.html">Markdown, la mejor opción para crear contenidos web</a>, donde defiendo la
idoneidad de markdown para crear contenidos web.</p>
<p>En esta comparativa se verá como emplear cada uno de los lenguajes de marcado
disponibles para crear un contenido web similar. Tomo como referencia a markdown,
aunque no todos los lenguajes soportan todas o las mismas características que
este.</p>
<h2 id="documento_de_ejemplo_realizado_con_markdown">Documento de ejemplo realizado con Markdown</h2>
<div>
<table>
<thead>
<tr>
<th style="width: 50%;">Markdown</th><th>Resultado</th>
</tr>
<tbody>
<tr>
<td>
<pre class="no_mrkdwn">
<p>Documento de ejemplo
====================</p><p>Lorem ipsum [dolor sit amet](#mark), consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum **semper adipiscing leo** et blandit.</p><p>Sed nibh quam, hendrerit _sit amet aliquam_ vel, pulvinar molestie augue.</p><p>> Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</p><p>Lenguajes de marcado ligero</p><p> * **Markdown**
* Textile
* reStructuredText
* Texy!
* Txt2tags
* Marcado Wiki
1. Creole
2. MediaWiki</p><p></p><p>### Cabecera H3 ###</p><p>- - -</p><p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p><p>| | solo texto | HTML Limpio |
| -------------- | -- | ------- |
| Markdown | Si | Si |
| Editor WYSISWG | X | A veces |</p>_Ejemplo de código_</p><p> import lifetime
for each_day in lifetime.days():
carpe_diem()</p><p>Suspendisse posuere velit et velit vehicula at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis.</p><p>Esto es un texto con nota al pie [^ejemplo] y esta es otra nota [^segunda]</p><p>
*[vehicula]: automobila
[^ejemplo]: Esto es una nota al pie.
[^segunda]: Esto es la segunda nota.</p></pre>
</td>
<td>
<h1>Documento de ejemplo</h1>
<p>Lorem ipsum <a href="#mark">dolor sit amet</a>, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum <strong>semper adipiscing leo</strong> et blandit.</p>
<p>Sed nibh quam, hendrerit <em>sit amet aliquam</em> vel, pulvinar molestie augue.</p>
<blockquote>
<p>Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</p>
</blockquote>
<p>Lenguajes de marcado ligero</p>
<ul>
<li><strong>Markdown</strong></li>
<li>Textile</li>
<li>reStructuredText</li>
<li>Texy!</li>
<li>Txt2tags</li>
<li>Marcado Wiki
<ol>
<li>Creole</li>
<li>MediaWiki</li>
</ol></li>
</ul>
<p><img src="pictures/no_wysiwyg.png" alt="avatar" /></p>
<h3>Cabecera H3</h3>
<hr />
<p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p>
<table>
<thead>
<tr>
<th></th>
<th>solo texto</th>
<th>HTML Limpio</th>
</tr>
</thead>
<tbody>
<tr>
<td>Markdown</td>
<td>Si</td>
<td>Si</td>
</tr>
<tr>
<td>Editor WYSISWG</td>
<td>X</td>
<td>A veces</td>
</tr>
</tbody>
</table>
<p><em>Ejemplo de código</em></p>
<pre class="txt" style="font-family:monospace;">import lifetime
for each_day in lifetime.days():
carpe_diem()</pre>
<p>Suspendisse posuere velit et velit <abbr title="automobila">vehicula</abbr> at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis.</p>
<p>Esto es un texto con nota al pie <sup id="fnref:ejemplo"><a href="#fn:ejemplo" rel="footnote">1</a></sup> y esta es otra nota <sup id="fnref:segunda"><a href="#fn:segunda" rel="footnote">2</a></sup></p>
<div class="footnotes">
<hr />
<ol>
<li id="fn:ejemplo">
<p>Esto es una nota al pie. <a href="#fnref:ejemplo" rev="footnote">↩</a></p>
</li>
<li id="fn:segunda">
<p>Esto es la segunda nota. <a href="#fnref:segunda" rev="footnote">↩</a></p>
</li>
<p></ol>
</div>
</td>
</tr>
</tbody>
</table>
</div></p>
<hr />
<h2 id="textile">Textile</h2>
<p>Es una buena alternativa a Markdown y bastante extendido, aunque quizás menos
que Markdown. Tiene algunas posibilidades que no tiene Markdown como emplear
colores, poder alinear el texto o emplear superindice y subindice. También tiene
carencias como el no poder dibujar líneas horizontales o el poder emplear
acronimos solo con mayusculas y tener que declararlos en cada una de las partes
del texto que aparezcan. Pero quiźas para mi la mayor desventaja es la menor
legibilidad del texto, es menos evidente a un vistazo que markdown.</p>
<table>
<thead>
<tr>
<th style="width: 50%;">Textile</th><th>Resultado</th>
</tr>
<tbody>
<tr>
<td>
<pre class="no_mrkdwn">
h1. Documento de ejemplo
Lorem ipsum "dolor sit amet":#mark, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum **semper adipiscing leo** et blandit.
Sed nibh quam, hendrerit _sit amet aliquam_ vel, pulvinar molestie augue.
bq. Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.
Lenguajes de marcado ligero
* **Markdown**
* Textile
* reStructuredText
* Texy!
* Txt2tags
* Marcado Wiki
## Creole
## MediaWiki
!pictures/no_wysiwyg.png (avatar)!
h3. Cabecera H3
Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.
|_. @@|_. solo texto|_. HTML Limpio|
|Markdown|Si|Si|
|Editor WYSISWG|X|A veces|
_Ejemplo de código_
bc.. import lifetime
for each_day in lifetime.days():
carpe_diem()
p. Suspendisse posuere velit et velit VEHICULA(automobila) at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis.
Esto es un texto con nota al pie[1] y esta es otra nota[2]
fn1. Esto es una nota al pie.
fn2. Esto es la segunda nota.
</pre>
</td>
<td>
<h1>Documento de ejemplo</h1>
<p>Lorem ipsum <a href="#mark">dolor sit amet</a>, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum <b>semper adipiscing leo</b> et blandit.</p>
<p>Sed nibh quam, hendrerit <em>sit amet aliquam</em> vel, pulvinar molestie augue.</p>
<blockquote>
<p>Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</p>
</blockquote>
<p>Lenguajes de marcado ligero </p>
<ul>
<li><b>Markdown</b></li>
<li>Textile</li>
<li>reStructuredText</li>
<li>Texy!</li>
<li>Txt2tags</li>
<li>Marcado Wiki
<ol>
<li>Creole</li>
<li>MediaWiki</li>
</ol></li>
</ul>
<p><img src="pictures/no_wysiwyg.png" title="avatar" alt="avatar" /></p>
<h3>Cabecera H3</h3>
<p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p>
<table>
<tr>
<th></th>
<th>solo texto</th>
<th><span class="caps"><span class="caps">HTML</span></span> Limpio</th>
</tr>
<tr>
<td>Markdown</td>
<td>Si</td>
<td>Si</td>
</tr>
<tr>
<td>Editor <span class="caps"><span class="caps">WYSISWG</span></span></td>
<td>X</td>
<td>A veces</td>
</tr>
</table>
<p><em>Ejemplo de código</em></p>
<pre>
import lifetime
for each_day in lifetime.days():
carpe_diem()
</pre>
<p>Suspendisse posuere velit et velit <acronym title="automobila"><span class="caps">VEHICULA</span></acronym> at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis.</p>
<p>Esto es un texto con nota al pie<sup class="footnote"><a href="#fn8701048694d94660b0d4d4">1</a></sup> y esta es otra nota<sup class="footnote"><a href="#fn13831162204d94660b122f5">2</a></sup></p>
<p id="fn8701048694d94660b0d4d4" class="footnote"><sup>1</sup> Esto es una nota al pie.</p>
<p id="fn13831162204d94660b122f5" class="footnote"><sup>2</sup> Esto es la segunda nota.</p>
<p></td>
</tr>
</tbody>
</table></p>
<hr />
<h2 id="bbcode">BBCode</h2>
<p>Es uno de los más extendido porque es ampliamente usado en foros por toda la red.
Nació para ser empleado en foros y es prácticamente el único ámbito en el que se
emplea. Es también muy limitado porque no soporta muchas de las características
de los otros lenguajes y además hay múltiples variantes que no ayudan a crear un
estándar. Por ejemplo las listas y las tablas no son contempladas en algunas de
esas variantes.</p>
<table>
<thead>
<tr>
<th style="width: 50%;">BBCode</th><th>Resultado</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<pre class="no_mrkdwn">
Documento de ejemplo
Lorem ipsum [url=http://joedicastro.com]dolor sit amet[/url], consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum [b]semper adipiscing leo[/b] et blandit.
Sed nibh quam, hendrerit [i]sit amet aliquam[/i] vel, pulvinar molestie augue.
[quote]Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.[/quote]
[img]http://joedicastro/files/
imagenes/no_wysiwyg.png[/img]
Cabecera H3
Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.
[i]Ejemplo de codigo[/i]
[code]
import lifetime
for each_day in lifetime.days():
carpe_diem()
[/code]
</pre>
</td>
<td><div>
<p>
Documento de ejemplo<br />
</p>
<p>
Lorem ipsum <a href="http://joedicastro.com" target="_new">dolor sit amet</a>, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum <strong>semper adipiscing leo</strong> et blandit.
</p>
<p>
Sed nibh quam, hendrerit <em>sit amet aliquam</em> vel, pulvinar molestie augue.
</p>
<blockquote>
<p>
Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.
</p>
</blockquote>
<p><img src="pictures/no_wysiwyg.png" alt="" /></p>
<p>Cabecera H3</p>
<p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p>
<em>Ejemplo de codigo</em>
<pre class="code">
import lifetime
for each_day in lifetime.days():
carpe_diem()
</pre></div>
</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="restructuredtext">reStructuredText</h2>
<p>Fue creado para crear documentación, en concreto documentación para lenguajes de
programación como Python. Tiene algunas carencias al no estar orientado a HTML,
pero también tiene posibilidades de las que carece Markdown. Es muy potente,
bastante legible, pero un poco incomodo para según que cosas, a mi modo de ver. </p>
<table>
<thead>
<tr>
<th style="width: 53%;">reStructuredText</th><th>Resultado</th>
</tr>
<tbody>
<tr>
<td>
<pre class="no_mrkdwn">
Documento de ejemplo
====================
Lorem ipsum `dolor sit amet <#mark>`_, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum **semper adipiscing leo** et blandit.
Sed nibh quam, hendrerit *sit amet aliquam* vel, pulvinar molestie augue.
Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.
Lenguajes de marcado ligero
* **Markdown**
* Textile
* reStructuredText
* Texy!
* Txt2tags
* Marcado Wiki
1. Creole
2. MediaWiki
.. image:: pictures/no_wysiwyg.png
:alt: avatar
---------------
Cabecera H3
^^^^^^^^^^^
Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.
============== ========== ===========
\ solo texto HTML Limpio
============== ========== ===========
Markdown Si Si
Editor WYSISWG X A veces
============== ========== ===========
*Ejemplo de código*::
import lifetime
for each_day in lifetime.days():
carpe_diem()
Suspendisse posuere velit et velit vehicula at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis.
Esto es un texto con nota al pie [1]_ y esta es otra nota [2]_
.. [1] Esto es una nota al pie.
.. [2] Esto es la segunda nota.
</pre>
</td>
<td>
<h1 id="documento-de-ejemplo">Documento de ejemplo</h1>
<p>Lorem ipsum <a href="#mark">dolor sit amet</a>, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum <strong>semper adipiscing leo</strong> et blandit.</p>
<p>Sed nibh quam, hendrerit <em>sit amet aliquam</em> vel, pulvinar molestie augue.</p>
<blockquote>
<p>Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</p>
</blockquote>
<p>Lenguajes de marcado ligero</p>
<ul>
<li><strong>Markdown</strong></li>
<li>Textile</li>
<li>reStructuredText</li>
<li>Texy!</li>
<li>Txt2tags</li>
<li>Marcado Wiki
<ol style="list-style-type: decimal">
<li>Creole</li>
<li>MediaWiki</li>
</ol></li>
</ul><p />
<img src="pictures/no_wysiwyg.png" alt="avatar" />
<hr />
<h2 id="cabecera-h3">Cabecera H3</h2>
<p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p>
<table>
<thead>
<tr class="header">
<th align="left"> </th>
<th align="left">solo texto</th>
<th align="left">HTML Limpio</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left">Markdown</td>
<td align="left">Si</td>
<td align="left">Si</td>
</tr>
<tr class="even">
<td align="left">Editor WYSISWG</td>
<td align="left">X</td>
<td align="left">A veces</td>
</tr>
</tbody>
</table>
<p><em>Ejemplo de código</em>:</p>
<pre>import lifetime
<p>for each_day in lifetime.days():
carpe_diem()
</pre>
<p>Suspendisse posuere velit et velit vehicula at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis.</p>
<p>Esto es un texto con nota al pie <sup><a href="#fn1" class="footnoteRef" id="fnref1">1</a></sup> y esta es otra nota <sup><a href="#fn2" class="footnoteRef" id="fnref2">2</a></sup></p>
<div class="footnotes">
<hr />
<ol>
<li id="fn1"><p>Esto es una nota al pie. <a href="#fnref1" class="footnoteBackLink" title="Jump back to footnote 1">↩</a></p></li>
<li id="fn2"><p>Esto es la segunda nota. <a href="#fnref2" class="footnoteBackLink" title="Jump back to footnote 2">↩</a></p></li>
</ol>
</div>
</td>
</tr>
</tbody>
</table></p>
<hr />
<h2 id="texy">Texy!</h2>
<p>Fue específicamente diseñado para crear documentos XHTML, por ello es bastante
completo, pero no está muy extendido. Es legible, pero también tiene carece de
soporte para ciertos tags de HTML.</p>
<table>
<thead>
<tr>
<th style="width: 53%;">Texy!</th><th>Resultado</th>
</tr>
<tbody>
<tr>
<td>
<pre class="no_mrkdwn">
Documento de ejemplo
====================
Lorem ipsum [dolor sit amet | http://joedicastro.com], consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum **semper adipiscing leo** et blandit.
Sed nibh quam, hendrerit *sit amet aliquam* vel, pulvinar molestie augue.
> Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.
Lenguajes de marcado ligero
- **Markdown**
- Textile
- reStructuredText
- Texy!
- Txt2tags
- Marcado Wiki
1) Creole
2) MediaWiki
[* pictures/no_wysiwyg.png .(alt text)[avatar] *]
### Cabecera H3 ###
-----
Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.
|------------------------------
| | solo texto | HTML Limpio
|------------------------------
| Markdown | Si | Si
| Editor WYSISWG | X | A veces
*Ejemplo de código*
/---code
import lifetime
for each_day in lifetime.days():
carpe_diem()
\---
Suspendisse posuere velit et velit "vehicula"((automobila)) at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis.
</pre>
</td>
<td>
<h1 id="toc-documento-de-ejemplo">Documento de ejemplo</h1>
<p>Lorem ipsum <a href="http://joedicastro.com">dolor sit amet</a>, consectetur
adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id
rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula.
Vestibulum <strong>semper adipiscing leo</strong> et blandit.</p>
<p>Sed nibh quam, hendrerit <em>sit amet aliquam</em> vel, pulvinar
molestie augue.</p>
<blockquote>
<p>Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel
convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis,
ultrices pharetra nunc.</p>
</blockquote>
<p>Lenguajes de marcado ligero</p>
<ul>
<li><strong>Markdown</strong></li>
<li>Textile</li>
<li>reStructuredText</li>
<li>Texy!</li>
<li>Txt2tags</li>
<li>Marcado Wiki
<ol>
<li>Creole</li>
<li>MediaWiki</li>
</ol>
</li>
</ul>
<div><img src="pictures/no_wysiwyg.png" class="avatar"
alt="alt text"></div>
<h1 id="toc-cabecera-h3">Cabecera H3</h1>
<hr>
<p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce
dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui
fermentum vitae blandit risus aliquet.</p>
<table>
<thead>
<tr>
<th> </th>
<th>solo texto</th>
<th>HTML Limpio</th>
</tr>
</thead>
<tbody>
<tr>
<td>Markdown</td>
<td>Si</td>
<td>Si</td>
</tr>
<tr>
<td>Editor WYSISWG</td>
<td>X</td>
<td>A veces</td>
</tr>
</tbody>
</table>
<p><em>Ejemplo de código</em></p>
<pre>import lifetime
for each_day in lifetime.days():
carpe_diem()</pre>
<p>Suspendisse posuere velit et velit <acronym
title="automobila">vehicula</acronym> at scelerisque orci suscipit. Nulla
facilisis lorem eu sem viverra varius nec ut felis.</p>
<p></td>
</tr>
</tbody>
</table></p>
<hr />
<h2 id="txt2tags">txt2tags</h2>
<p>Está escrito en Python y es muy potente, al igual que RestructuredText,
permitiendo macros. Permite la salida en muchos formatos, incluido el XHTML.
Es muy legible y muy fácil de emplear, es una pena que no esté más extendido y
soportado. Aunque aún tiene algunas carencias como las notas al pie o las
abreviaturas, que pueden ser soportadas con macros, también tiene un desarrollo
muy activo. En la futura versión 3.0 serán soportados directamente las notas al
pie. Es una alternativa con muy buen futuro.</p>
<table>
<thead>
<tr>
<th style="width: 53%;">txt2tags</th><th>Resultado</th>
</tr>
<tbody>
<tr>
<td>
<pre class="no_mrkdwn">
=Documento de ejemplo=
Lorem ipsum [dolor sit amet #mark], consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum **semper adipiscing leo** et blandit.
Sed nibh quam, hendrerit //sit amet aliquam// vel, pulvinar molestie augue.
<tab>Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.
Lenguajes de marcado ligero
- **Markdown**
- Textile
- reStructuredText
- Texy!
- Txt2tags
- Marcado Wiki
+ Creole
+ MediaWiki
[pictures/no_wysiwyg.png]
===Cabecera H3===
--------------------
Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.
|| | solo texto | HTML Limpio
| Markdown | Si | Si |
| Editor WYSISWG | X | A veces |
//Ejemplo de codigo//
```
import lifetime
for each_day in lifetime.days():
carpe_diem()
```
</pre>
</td>
<td>
<h1>Documento de ejemplo</h1>
<p>
Lorem ipsum <a href="#mark">dolor sit amet</a>, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum <b>semper adipiscing leo</b> et blandit.
</p>
<p>
Sed nibh quam, hendrerit <i>sit amet aliquam</i> vel, pulvinar molestie augue.
</p>
<blockquote><p>
Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</p>
</blockquote>
<p>
Lenguajes de marcado ligero
</p>
<ul>
<li><b>Markdown</b>
<li>Textile
<li>reStructuredText
<li>Texy!
<li>Txt2tags
<li>Marcado Wiki
<ol>
<li>Creole
<li>MediaWiki
</ol>
</ul>
<p>
<img src="pictures/no_wysiwyg.png" alt="">
</p>
<h3>Cabecera H3</h3>
<hr />
<p>
Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.
</p>
<table cellpadding="4">
<tr>
<th></th>
<th>solo texto</th>
<th>HTML Limpio</th>
</tr>
<tr>
<td>Markdown</td>
<td align="center">Si</td>
<td align="center">Si</td>
</tr>
<tr>
<td>Editor WYSISWG</td>
<td align="center">X</td>
<td align="center">A veces</td>
</tr>
</table>
<p>
<i>Ejemplo de codigo</i>
</p>
<pre>
import lifetime
for each_day in lifetime.days():
carpe_diem()
</pre>
</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="creole">Creole</h2>
<p>Creado a partir de los lenguajes más empleados en los Wikis y usado
fundamentalmente en Wikis, por lo que también tiene ciertas carencias.</p>
<table>
<thead>
<tr>
<th style="width: 50%;">Creole</th><th>Resultado</th>
</tr>
<tbody>
<tr>
<td>
<pre class="no_mrkdwn">
== Documento de ejemplo ==
Lorem ipsum [[#mark|dolor sit amet]], consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum **semper adipiscing leo** et blandit.
Sed nibh quam, hendrerit //sit amet aliquam// vel, pulvinar molestie augue.
> Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.
Lenguajes de marcado ligero
* **Markdown**
* Textile
* reStructuredText
* Texy!
* Txt2tags
* Marcado Wiki
## Creole
## MediaWiki
{{pictures/no_wysiwyg.png|avatar}}
==== Cabecera H3 ====
-----
Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.
|= |= solo texto |= HTML Limpio |
| Markdown | Si | Si |
| Editor WYSISWG | X | A veces |
//Ejemplo de código//
{{{
import lifetime
for each_day in lifetime.days():
carpe_diem()
}}}
</pre>
</td>
<td>
<h1>Documento de ejemplo</h1>
<p>Lorem ipsum <a href="#mark">dolor sit amet</a>, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum <strong>semper adipiscing leo</strong> et blandit.</p>
<p>Sed nibh quam, hendrerit <em>sit amet aliquam</em> vel, pulvinar molestie augue.</p>
<blockquote><p>Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</p>
</blockquote>
<p>Lenguajes de marcado ligero </p>
<ul><li><strong>Markdown</strong>
</li><li>Textile
</li><li>reStructuredText
</li><li>Texy!
</li><li>Txt2tags
</li><li>Marcado Wiki
<ol><li>Creole
</li><li>MediaWiki
</li></ol></li></ul>
<p><img src="pictures/no_wysiwyg.png" alt="avatar" title="avatar" /></p>
<h3>Cabecera H3</h3>
<p>-----</p>
<p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p>
<table><tr><th></th><th>solo texto</th><th>HTML Limpio</th></tr>
<tr><td>Markdown</td><td>Si</td><td>Si</td></tr>
<tr><td>Editor WYSISWG</td><td>X</td><td>A veces</td></tr>
</table>
<p><em>Ejemplo de código</em></p>
<pre>
import lifetime
<p>for each_day in lifetime.days():
carpe_diem()
</pre></p>
<p></td>
</tr>
</tbody>
</table></p>
<hr />
<h2 id="mediawiki">MediaWiki</h2>
<p>Quizás el más extendido, no en vano MediaWiki es el Wiki empleado por la
Wikipedia. Igual que Creole, tiene ciertas limitaciones que suple con plugins y
etiquetas HTML. No me acaba de gustar. La manera que tiene de crear tablas -
por ejemplo - aunque potente, no me parece nada legible en texto plano.<br />
</p>
<table>
<thead>
<tr>
<th style="width: 53%;">MediaWiki</th><th>Resultado</th>
</tr>
<tbody>
<tr>
<td>
<pre class="no_mrkdwn">
==Documento de ejemplo==
Lorem ipsum [http://joedicastro.com dolor sit amet], consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum '''semper adipiscing leo''' et blandit.
Sed nibh quam, hendrerit ''sit amet aliquam'' vel, pulvinar molestie augue.
<blockquote>Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</blockquote>
Lenguajes de marcado ligero
* '''Markdown'''
* Textile
* reStructuredText
* Texy!
* Txt2tags
* Marcado Wiki
*# Creole
*# MediaWiki
[[File:pictures/no_wysiwyg.png|caption]]
=== Cabecera H3 ===
----
Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.
{|
!
! solo texto
! HTML Limpio
|-
|Markdown
|Si
|Si
|-
|Editor WYSISWG
|X
|A veces
|}
''Ejemplo de código''
import lifetime
for each_day in lifetime.days():
carpe_diem()
Suspendisse posuere velit et velit <span title="automobila">vehicula</span> at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis.
Esto es un texto con nota al pie <ref name="ejemplo">Esto es una nota al pie.</ref> y esta es otra nota <ref name="segunda"> Esto es la segunda nota.</ref>
{{reflist}}
</pre>
</td>
<td>
<h2><span class="mw-headline" id="Documento_de_ejemplo">Documento de ejemplo</span></h2>
<p>Lorem ipsum <a href="http://joedicastro.com" class="external text" rel="nofollow">dolor sit amet</a>, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum <b>semper adipiscing leo</b> et blandit.</p>
<p>Sed nibh quam, hendrerit <i>sit amet aliquam</i> vel, pulvinar molestie augue.</p>
<blockquote>
<p>Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</p>
</blockquote>
<p>Lenguajes de marcado ligero</p>
<ul>
<li><b>Markdown</b></li>
<li>Textile</li>
<li>reStructuredText</li>
<li>Texy!</li>
<li>Txt2tags</li>
<li>Marcado Wiki
<ol>
<li>Creole</li>
<li>MediaWiki</li>
</ol>
</li>
</ul>
<p><img src="pictures/no_wysiwyg.png" alt="" /></p>
<h3><span class="mw-headline" id="Cabecera_H3">Cabecera H3</span></h3>
<hr />
<p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p>
<table>
<tr>
<th></th>
<th>solo texto</th>
<th>HTML Limpio</th>
</tr>
<tr>
<td>Markdown</td>
<td>Si</td>
<td>Si</td>
</tr>
<tr>
<td>Editor WYSISWG</td>
<td>X</td>
<td>A veces</td>
</tr>
</table>
<p><i>Ejemplo de código</i></p>
<pre>
import lifetime
<p>for each_day in lifetime.days():
carpe_diem()</p>
<p></pre>
<p>Suspendisse posuere velit et velit <span title="automobila">vehicula</span> at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis.</p></p>
<p>Esto es un texto con nota al pie <sup id="cite_ref-ejemplo_0-0" class="reference"><a href="#cite_note-ejemplo-0"><span>[</span>1<span>]</span></a></sup> y esta es otra nota <sup id="cite_ref-segunda_1-0" class="reference"><a href="#cite_note-segunda-1"><span>[</span>2<span>]</span></a></sup></p>
<div class="reflist" style="list-style-type: decimal;">
<ol class="references">
<li id="cite_note-ejemplo-0"><b><a href="#cite_ref-ejemplo_0-0">^</a></b> Esto es una nota al pie.</li>
<li id="cite_note-segunda-1"><b><a href="#cite_ref-segunda_1-0">^</a></b> Esto es la segunda nota.</li>
<p></ol>
</td>
</tr>
</tbody>
</table></p>