<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>BeOSmAn&#039;s Blooog &#187; Informática</title>
	<atom:link href="http://beosman.org/archivo/category/informatica/feed" rel="self" type="application/rss+xml" />
	<link>http://beosman.org</link>
	<description>Breaking with the past to build the future</description>
	<lastBuildDate>Fri, 18 May 2012 14:47:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>El porqué de los menús globales y su falta de usabilidad</title>
		<link>http://beosman.org/archivo/2012/informatica/el-porque-de-los-menus-globales-y-su-falta-de-usabilidad.html</link>
		<comments>http://beosman.org/archivo/2012/informatica/el-porque-de-los-menus-globales-y-su-falta-de-usabilidad.html#comments</comments>
		<pubDate>Thu, 10 May 2012 18:12:20 +0000</pubDate>
		<dc:creator>Diego</dc:creator>
				<category><![CDATA[Informática]]></category>
		<category><![CDATA[Opinión]]></category>

		<guid isPermaLink="false">http://beosman.org/?p=6191</guid>
		<description><![CDATA[Lo que fueron un par de comentarios en Menéame sobre la usabilidad de Unity —los menús globales en general— en un artículo que nada tiene que ver, lo he convertido en una entrada que llevaba tiempo queriendo escribir, aunque algo menos densa. El caso es que todo empezó con que las últimas versiones de Ubuntu [...]]]></description>
			<content:encoded><![CDATA[<p>Lo que fueron un <a href="http://www.meneame.net/story/5-pc-tendran-instalado-ubuntu-proximo-ano-canonical-confia-200/00043">par</a> de <a href="http://www.meneame.net/story/5-pc-tendran-instalado-ubuntu-proximo-ano-canonical-confia-200/00061">comentarios</a> en Menéame sobre la usabilidad de <a href="http://es.wikipedia.org/wiki/Unity_(entorno_de_escritorio)">Unity</a> —los menús globales en general— en <a href="http://www.meneame.net/story/5-pc-tendran-instalado-ubuntu-proximo-ano-canonical-confia-200">un artículo que nada tiene que ver</a>, lo he convertido en una entrada que llevaba tiempo queriendo escribir, aunque algo menos densa.</p>
<p>El caso es que todo empezó con que las últimas versiones de <a href="http://es.wikipedia.org/wiki/Ubuntu">Ubuntu</a> cuentan con un nuevo entorno de escritorio llamado Unity, que se asemeja más al de <a href="http://es.wikipedia.org/wiki/Mac_OS_X">Mac OS X</a> que a la forma antigua —más tirando a entornos <a href="http://es.wikipedia.org/wiki/Windows">Windows</a>— y por ello cuenta con una barra de aplicaciones en el lateral izquierdo y un menú de aplicación global en el borde superior de la pantalla.</p>
<p>Son precisamente estos cambios lo que provocan las quejas de no pocos usuarios, pero no por el hecho de cambiar la interfaz, sino porque dichos cambios, precisamente, hacen de este software algo <em>inusable</em>. Aunque bueno, por ser un poco menos radicales lo dejaremos en <em>&#8220;poco usable&#8221;</em>. Y es poco usable porque ha sido pensado para pantallas pequeñas y para ejecutar aplicaciones a pantalla completa dejando muy de lado las pantallas grandes (de 20 pulgadas en adelante) con aplicaciones con ventanas pequeñas distribuidas a lo largo y ancho de todo el escritorio. Además de que es muy poco configurable y personalizable (si no es con software de terceros).</p>
<p>¿Qué es lo que nos lleva a decir que es poco usable? Empecemos por un par de pequeñas historias. La primera: Mac OS X, allá por sus inicios, justificó su menú global superior argumentando que ubicándolo de esta forma no te sales con el ratón, es decir, por muy rápido que vayas hacia un menú, el borde de la pantalla evitará que te salgas y la probabilidad de acierto de clic en el menú correspondiente es muy alta. Esto no ocurre, por ejemplo, con los menús en Windows, que suelen estar por debajo de la barra de título y puede que, si no eres hábil con el ratón, en lugar de hacer clic en dicho menú lo hagas en la barra. En Mac OS X puedes hacer clic en el menú equivocado, pero por arriba nunca te saldrás, mientra que en Windows tienes los cuatro costados para fallar en la acción.</p>
<p>La segunda historia es algo más moderna, exactamente de <a href="http://es.wikipedia.org/wiki/Google_Chrome">Google Chrome</a>: la idea detrás de la ubicación de las pestañas en Google Chrome con la ventana maximizada es la misma que la del menú global. A la hora de cambiar de pestaña haciendo clic con el ratón, por mucho que avances o muy rápido que vayas, no te saldrás de la pantalla y siempre darás en una pestaña. Que puede que falles, sí, pero la probabilidad de acierto es mucho más alta que si las pestañas estuvieran como en el antiguo <a href="http://es.wikipedia.org/wiki/Firefox">Firefox</a>, justo por debajo del menú y este por debajo de la barra de título. Por cierto, en Firefox ya se puede hacer lo mismo con las pestañas arriba del todo ocultando el menú.</p>
<p>Con estas dos historias en mente, tenemos que usar un menú global impide que se usen las pestañas de la forma para lo que han sido diseñadas. En Mac OS X y en Unity, por ejemplo, toda esta funcionalidad de Chrome se pierde, como se puede ver en la imagen siguiente:</p>
<p><a href="/uploads/2012/05/pestañas-parte-superior.jpg"><img src="http://beosman.org/uploads/2012/05/pestañas-parte-superior-650x406.jpg" alt="Pestañas de Chrome en Ubuntu con Unity" title="Pestañas de Chrome en Ubuntu con Unity" width="650" height="406" class="alignnone size-large wp-image-6200" /></a></p>
<p>Y no sólo eso, un usuario experimentado ¿cuántas veces usa los menús? En general, los usuarios experimentados usan el ratón, usan las barras de herramientas, usan los menús contextuales y, sobre todo, usan las teclas de acceso rápido. Incluso en, por ejemplo, <a href="http://es.wikipedia.org/wiki/Photoshop">Photoshop</a>, que es un software complejo con muchas opciones, muchos menús, muchas herramientas… el usuario experimentado rara vez usará los menús ya que está totalmente habituado a usar las teclas y el menú contextual.</p>
<p>Como decía antes, en un navegador, ¿para qué sirve el menú? ¿Cuántas veces se usa? La primera vez para configurarlo. Y ya. Si te fijas, Chrome desde un principio ya lo ha sustituido por un sólo botón donde sale un menú contextual. Firefox, con la configuración compacta, ha hecho exactamente lo mismo con su botón naranja. El explorador de Windows (el de los archivos, no el navegador) tampoco tiene menú —que se activa presionando la tecla Alt—. Microsoft Office lo ha sustituido por <a href="http://en.wikipedia.org/wiki/Ribbon_(computing)" title="Menú «Ribbon» de Microsoft Office">una barra de herramientas y un botón con menú contextual</a>. Y así con mucho otro software… Pero no es que sea una moda, es que <a href="/archivo/2011/informatica/mejorando-el-explorador-de-windows-o-no-y-otros-menesteres.html">hay estudios</a> que dicen que un menú es poco usable y hay alternativas mucho mejores, entre ellas, las ya nombradas teclas de acceso rápido los gestos en el <em><a href="http://es.wikipedia.org/wiki/Trackpad">trackpad</a></em> que Mac OS X usa con destreza.</p>
<p>Además, otra de las cosas criticables de los menús globales es que, en el caso de querer usar el menú —porque se siguen usando, obviamente, aunque su uso se reduzca con las nuevas interfaces gráficas—, si tenemos una aplicación con ventana pequeña ubicada en el lugar más cómodo de uso para nosotros, puede que sea bastante tedioso usar dicho menú. Por ejemplo, la calculadora:</p>
<p><a href="/uploads/2012/05/cambiar-modo-calculadora.jpg"><img src="http://beosman.org/uploads/2012/05/cambiar-modo-calculadora-650x406.jpg" alt="Cambiar el modo de la calculadora en Unity" title="Cambiar el modo de la calculadora en Unity" width="650" height="406" class="alignnone size-large wp-image-6203" /></a></p>
<p>En caso de querer cambiar el modo, funcionalidad sólo accesible a través de menús, tendremos que recorrer toda la pantalla para acceder al mismo y luego volver para hacer uso de la calculadora.</p>
<p>Aún podemos seguir con esta falta de usabilidad de Unity: ¿por qué si hay una aplicación maximizada y otra en ventana normal delante, el menú que se muestra en el menú global es el de la aplicación que tiene el foco, <strong>excepto</strong> cuando haces clic, que es el menú de la aplicación maximizada trayendo esta al frente? Es decir, el menú de arriba es el de la ventana que tiene el foco excepto cuando haces clic en él, que se convierte por arte de magia en el menú de la ventana maximizada. Muy coherente todo, sí.</p>
<p>Pero, venga, no nos quedemos aquí. Unity también tiene cosas buenas. O casi…</p>
<p>La barra y lanzador de aplicaciones a la izquierda está muy bien. Es muy usable porque no te sales hacia la izquierda (el mismo principio que usa el menú global) porque a la izquierda de las aplicaciones no hay ningún control… bueno, eso no es cierto del todo. En Unity los botones de minimizar, maximizar y cerrar ventana están, ¡oh, sorpresa!, a la izquierda. Cuando vas a cerrar una ventana es muy fácil que te salgas hacia la barra de aplicaciones. Una solución es cambiar los botones a la derecha de la ventana.</p>
<p>O también, ¿qué pasaría si la pudiéramos poner el lanzador a la derecha? Digo &#8220;pudiéramos&#8221; porque Unity no lo permite (de ahí mis quejas por la falta de configuración). En caso de poderse, alguien podría pensar que ahí interfiere con la barra de desplazamiento… pero no. ¿Todavía queda alguien que no use la rueda del ratón? La única queja es el <em>trackpad</em> de los portátiles, pero hoy en día la mayoría soporta <em lang="en">scroll</em> don dos dedos o cualquier forma similar.</p>
<p>En conclusión, y ya para terminar este <em>ladrillo</em>, se podría decir, en mi opinión, que la mejor configuración para un lanzador de aplicaciones, menú principal y bandeja del sistema en una <a href="http://es.wikipedia.org/wiki/Interfaz_gr%C3%A1fica_de_usuario">interfaz gráfica de usuario</a> es en la parte inferior —donde lo tienen Windows, KDE y Gnome 2.x— ya que no interfiere con ningún control de la ventana; o también en los laterales, siempre y cuando los controles de la ventana no estén en el mismo lado.</p>
<p>Como nota respecto a esta ubicación de elementos y a mi conocida afición por el sistema operativo <a href="http://es.wikipedia.org/wiki/BeOS">BeOS</a>/<a href="http://es.wikipedia.org/wiki/Haiku_(sistema_operativo)">Haiku</a>, tengo que decir que allá por el año 1990, BeOS ya contaba con una interfaz gráfica de usuario donde el lanzador y la lista de aplicaciones abiertas estaba en la parte superior derecha del escritorio, y los controles de las ventanas estaban a la izquierda de la barra de título —teniendo en cuenta que esta barra de título no ocupaba todo el ancho de la ventana sino sólo lo que ocupaba el texto, de forma similar a solapas—, tónica de diseño de interfaces que ha tardado veinte años en llegar al gran público.</p>
<p>Si has llegado a este punto (vaya ganas que tenías de leer <img src='http://beosman.org/wp-includes/images/smilies/tongue.gif' alt=':tongue:' class='wp-smiley' />  ), que quede claro que esta es mi opinión y sólo mía, totalmente criticable por supuesto, pero que luego cada uno usará lo que quiera siempre y cuando esté a su gusto.</p>
]]></content:encoded>
			<wfw:commentRss>http://beosman.org/archivo/2012/informatica/el-porque-de-los-menus-globales-y-su-falta-de-usabilidad.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Galaxy Nexus</title>
		<link>http://beosman.org/archivo/2012/tecnologia/galaxy-nexus.html</link>
		<comments>http://beosman.org/archivo/2012/tecnologia/galaxy-nexus.html#comments</comments>
		<pubDate>Thu, 05 Apr 2012 11:53:25 +0000</pubDate>
		<dc:creator>Diego</dc:creator>
				<category><![CDATA[Chismes]]></category>
		<category><![CDATA[Informática]]></category>
		<category><![CDATA[Tecnología]]></category>

		<guid isPermaLink="false">http://beosman.org/?p=5956</guid>
		<description><![CDATA[Después de dos años y medio de mi primer Android en un HTC Magic, ha llegado la hora de cambiarlo, exactamente por un Galaxy Nexus. Porque, la verdad, que un teléfono de estos, teniendo en cuenta la obsolescencia programada, dure dos años y medio es todo un logro. Pero ya empezaba a fallar, sobre todo [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.google.com/nexus/"><img class="floatright" src="/uploads/2012/04/galaxy-nexus.jpg" alt="" title="Galaxy Nexus" width="269" height="489" /></a></p>
<p>Después de dos años y medio de <a href="/archivo/2009/tecnologia/mi-nuevo-android-dentro-de-un-htc-magic.html">mi primer Android en un HTC Magic</a>, ha llegado la hora de cambiarlo, exactamente por un <a href="http://es.wikipedia.org/wiki/Galaxy_Nexus">Galaxy Nexus</a>. Porque, la verdad, que un teléfono de estos, teniendo en cuenta la <a href="http://es.wikipedia.org/wiki/Obsolescencia_programada">obsolescencia programada</a>, dure dos años y medio es todo un logro. Pero ya empezaba a fallar, sobre todo la batería —que no llegaba ya al 100 % de carga— y porque cada vez que salía de la aplicación de <a title="Aplicación de Twitter para Android en Google Play" href="https://play.google.com/store/apps/details?id=com.twitter.android&#038;feature=search_result#?t=W251bGwsMSwyLDEsImNvbS50d2l0dGVyLmFuZHJvaWQiXQ..">Twitter</a> tardaba un minuto en mostrarme el escritorio… 528 MHz de procesador y 192 MB de RAM ya dan para poco con las nuevas aplicaciones, a parte de seguir con Android 2.2.</p>
<p>El Galaxy Nexus lo compré a través de <a href="http://vodafone.es">Vodafone</a> mediante su programa de puntos. En total, 1000 puntos y 239 € con una oferta de 120 € de descuento. Teniendo en cuenta que libre cuesta más de 500 € no está nada mal. Eso sí, 24 meses de permanencia. ¿Mucho tiempo? Bueno, sería mucho si no estuviera contento con ellos pero, hasta el momento, sólo tengo una queja que quizá comente otro día.</p>
<p>En cuanto al terminal, me quejaba con el Magic que era un poco grande con 3,2 pulgadas de pantalla… y he pasado a este con ¡4,65 pulgadas! Esperemos que no supere la medida estándar del bolsillo de mis pantalones.</p>
<p>En cuanto al hardware, poco hay que decir. Que si un buen procesador, que si mucha memoria, que si bastante memoria de almacenamiento… ¡ah! ¿Que soy poco preciso? Vaya, Apple hace lo mismo y no os quejáis tanto… <img src='http://beosman.org/wp-includes/images/smilies/trollface.gif' alt=':troll:' class='wp-smiley' /> . Bueno, venga: procesador <a href="http://es.wikipedia.org/wiki/ARM">ARM</a> <a href="http://es.wikipedia.org/wiki/Cortex">Cortex</a>-A9 a 1,2 GHz, 1 GB de memoria RAM y 16 GB de memoria de almacenamiento. ¿Así mejor?</p>
<p>La pega. La gran pega de <strong>todos</strong> los <em>smartphones</em>: la batería. Todavía no he hecho un cálculo <em>preciso</em> de cuanto podría llegar a durar, pero dudo mucho que pase de un día o día y medio con un uso <em>normal</em> <sup><a href="#uso-normal">1</a></sup>.</p>
<p>Pero lo más importante de este cambio de terminal, lejos de todo eso de los megaherzios y gigabytes, es <strong>el software</strong>. El Galaxy Nexus llega con <a href="http://en.wikipedia.org/wiki/Android_version_history#v4.x_Ice_Cream_Sandwich">Android 4.0</a> <abbr title="Ice Cream Sandwich">ICS</abbr>, que es la evolución del nunca lanzado Android 3.0 para <em>tablets</em>. Y esto es lo que hace bueno a un dispositivo, con todas las mejoras de dos años de evolución y la <a href="/archivo/2010/informatica/%C2%BFmejoras-en-la-interfaz-de-android.html">ya comentada por aquí</a> actuación de Matias Duarte en cuanto a la interfaz gráfica.</p>
<p>A partir de ahora esperemos que dure, como mínimo, lo mismo que el HTC Magic —que sigue vivo, pero un cajón—. Y a disfrutar <img src='http://beosman.org/wp-includes/images/smilies/grin.gif' alt=':grin:' class='wp-smiley' /> .</p>
<p class="postdata">
<sup id="uso-normal">1</sup> El uso normal podría ser diariamente un par de llamadas de 10 minutos, la sincronización total (correo y calendario), media hora de Twitter y otra media hora de navegación. ¿Sería más o menos así? ¿Cambiamos algo?</p>
]]></content:encoded>
			<wfw:commentRss>http://beosman.org/archivo/2012/tecnologia/galaxy-nexus.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Script en BASH para mostrar las entradas de GRUB2 tal y como salen en el menú</title>
		<link>http://beosman.org/archivo/2012/informatica/script-en-bash-para-mostrar-las-entradas-de-grub2-tal-y-como-salen-en-el-menu.html</link>
		<comments>http://beosman.org/archivo/2012/informatica/script-en-bash-para-mostrar-las-entradas-de-grub2-tal-y-como-salen-en-el-menu.html#comments</comments>
		<pubDate>Mon, 02 Apr 2012 18:04:49 +0000</pubDate>
		<dc:creator>Diego</dc:creator>
				<category><![CDATA[Informática]]></category>
		<category><![CDATA[Sistemas Operativos]]></category>

		<guid isPermaLink="false">http://beosman.org/?p=5946</guid>
		<description><![CDATA[¿No os ha pasado alguna vez que actualizáis un sistema Linux y, después de reiniciar, queréis quitar los kernels antiguos pero no sabéis cuáles son? La solución más rápida era buscar el archivo /boot/grub/grub.cfg de GRUB 2 y mirar en la zona de abajo cuáles eran las entradas que había y cuáles sobraban. Y luego, [...]]]></description>
			<content:encoded><![CDATA[<p>¿No os ha pasado alguna vez que actualizáis un sistema Linux y, después de reiniciar, queréis quitar los <a href="http://es.wikipedia.org/wiki/N%C3%BAcleo_(inform%C3%A1tica)"><em>kernels</em></a> antiguos pero no sabéis cuáles son?</p>
<p>La solución más rápida era buscar el archivo <code>/boot/grub/grub.cfg</code> de <a href="http://es.wikipedia.org/wiki/GNU_GRUB">GRUB</a> 2 y mirar en la zona de abajo cuáles eran las entradas que había y cuáles sobraban. Y luego, ya, desinstalarlas con <code>apt-get purge</code>.</p>
<p>Pero como al hacer un <code>cat</code> sobre <code>grub.cfg</code> se muestra mucha información que cuesta descifrar de un sólo vistazo, he hecho un <em>script</em> (ya sabéis, prefiero hacer un <em>script</em> que hacer las cosas a mano <img src='http://beosman.org/wp-includes/images/smilies/grin.gif' alt=':grin:' class='wp-smiley' /> ) que muestra las entradas de GRUB tal y como salen en el menú de inicio con el fin de identificarlas igual de rápido que al iniciar el sistema.</p>
<pre>
#!/bin/bash

FILE=/boot/grub/grub.cfg
PATTERN='menuentry'

cat $FILE | grep $PATTERN | while read; do
	LINE=${REPLY:11}
	PROCESSED=`echo $LINE | rev | cut -s -d"'" -f2 | rev`
	if [ "$PROCESSED" == "" ]; then
		PROCESSED=`echo $LINE | rev | cut -s -d'"' -f2 | rev`
	fi
	echo $PROCESSED
done
</pre>
<p>Si tampoco tenéis ganas de copiarlo y pegarlo, también <a href="/uploads/2012/04/grub-list-menu-entries.txt">lo podéis descargar</a>. No os olvidéis de quitarle la extensión <code>.txt</code> (si queréis) para que se parezca más a un comando de Linux y de darle permisos de ejecución con <code>chmod 755</code> <img src='http://beosman.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  .</p>
]]></content:encoded>
			<wfw:commentRss>http://beosman.org/archivo/2012/informatica/script-en-bash-para-mostrar-las-entradas-de-grub2-tal-y-como-salen-en-el-menu.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hacer copia de seguridad de tus tweets</title>
		<link>http://beosman.org/archivo/2012/informatica/hacer-copia-de-seguridad-de-tus-tweets.html</link>
		<comments>http://beosman.org/archivo/2012/informatica/hacer-copia-de-seguridad-de-tus-tweets.html#comments</comments>
		<pubDate>Tue, 20 Mar 2012 12:56:36 +0000</pubDate>
		<dc:creator>Diego</dc:creator>
				<category><![CDATA[Informática]]></category>
		<category><![CDATA[Internet]]></category>

		<guid isPermaLink="false">http://beosman.org/?p=5907</guid>
		<description><![CDATA[Twitter es ese sistema de microblogging que ahora es tan famoso, pero no por lo que puedas escribir, sino por lo que te puedan contestar. De ahí lo de red social. Uno de los problemas carencias de este servicio, aunque creo que hay más, es que no queda constancia de lo que escribes más allá [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://es.wikipedia.org/wiki/Twitter">Twitter</a> es ese sistema de microblogging que ahora es tan famoso, pero no por lo que puedas escribir, sino por lo que te puedan contestar. De ahí lo de red <strong>social</strong>.</p>
<p>Uno de los <del>problemas</del> carencias de este servicio, <a href="/archivo/2011/informatica/11-caracteristicas-que-twitter-deberia-tener.html">aunque creo que hay más</a>, es que no queda constancia de lo que escribes más allá de sus servidores y ¿qué pasa si quieres hacer copia de seguridad?</p>
<p>Pues tienes dos opciones: o usar una de las múltiples aplicaciones que hay para ello (una búsqueda en Internet dará con muchas de ellas aunque, eso sí, la mayoría tienen características de pago) o usar las aplicaciones necesarias para descargarlos por ti mismo. Más concretamente, usar <code><a href="http://es.wikipedia.org/wiki/CURL">cURL</a></code>.</p>
<p>Antes de nada, debes tener en cuenta que, como máximo, <a href="https://dev.twitter.com/discussions/276">sólo se pueden recuperar los últimos 3200 tweets</a>. Esto es debido a una restricción en el <a href="http://es.wikipedia.org/wiki/API"><acronym title="Application Programming Interface" lang="en">API</acronym></a> de Twitter. ¿Por qué? Ni idea, pero ahí está.</p>
<p>Y luego hay que tener en cuenta que sólo se pueden recuperar 100 tweets en cada petición, por lo que se harán 32 peticiones. Después de esto y de revisar un poco <a href="https://dev.twitter.com/docs/api/1/get/statuses/user_timeline">su API</a>, ya podemos recuperar nuestros 3200 últimos <em>tweets</em> mediante este comando (que se puede ejecutar en Linux o Windows siempre que se use la aplicación cURL):</p>
<p class="terminal nowrap">
$ curl -s &#45;&#45;user-agent &quot;Mozilla&quot; &#45;&#45;insecure &quot;https://twitter.com/statuses/user_timeline/<em>beoxman</em>.xml?count=100&amp;page=[1-32]&quot; &gt; <em>beoxman</em>@twitter.com.2012-03-20.xml
</p>
<p>Obviamente hay que sustituir el nombre de usuario (<em>beoxman</em> en este caso) por el vuestro. Después de esto, tendréis en el archivo de salida vuestros últimos 3200 <em>tweets</em> en formato <a href="http://es.wikipedia.org/wiki/XML">XML</a>.</p>
<p>El siguiente paso es buscar la forma de descargarse, también en formato XML, todos los <em>retweets</em> que hemos hecho (que no están incluidos en el <abbr title="Timeline" lang="en">TL</abbr>) y luego, ya para rematar, descargar todas las menciones y <em>retweets</em> que nos han hecho. Pero bueno, eso ya lo preparamos para otro día después de <a href="https://dev.twitter.com/docs/api">revisar el API de descargas</a> <img src='http://beosman.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  .</p>
]]></content:encoded>
			<wfw:commentRss>http://beosman.org/archivo/2012/informatica/hacer-copia-de-seguridad-de-tus-tweets.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Algoritmo de cálculo de la sucesión de Fibonacci en C++</title>
		<link>http://beosman.org/archivo/2012/informatica/algoritmo-de-calculo-de-la-sucesion-de-fibonacci-en-cpp.html</link>
		<comments>http://beosman.org/archivo/2012/informatica/algoritmo-de-calculo-de-la-sucesion-de-fibonacci-en-cpp.html#comments</comments>
		<pubDate>Thu, 08 Mar 2012 14:38:44 +0000</pubDate>
		<dc:creator>Diego</dc:creator>
				<category><![CDATA[Informática]]></category>
		<category><![CDATA[Lenguajes]]></category>

		<guid isPermaLink="false">http://beosman.org/?p=5838</guid>
		<description><![CDATA[Seguro que todos los que habéis tenido matemáticas en el instituto o universidad conocéis la sucesión de Fibonacci. Y seguro que todos los que habéis hecho algún curso, módulo o carrera de informática la habéis tenido que implementar alguna vez, ¿verdad? Lo más fácil era seguir las instrucciones del profesor e implementar, sin salirse del [...]]]></description>
			<content:encoded><![CDATA[<p>Seguro que todos los que habéis tenido matemáticas en el instituto o universidad conocéis la <a href="http://es.wikipedia.org/wiki/Sucesi%C3%B3n_de_Fibonacci">sucesión de Fibonacci</a>. Y seguro que todos los que habéis hecho algún curso, módulo o carrera de informática la habéis tenido que implementar alguna vez, ¿verdad?</p>
<p>Lo más fácil era seguir las instrucciones del profesor e implementar, sin salirse del guión, la definición matemática de esta sucesión:</p>
<blockquote class="small"><p>
<em>f<sub>0</sub> = 0<br />
f<sub>1</sub> = 1<br />
f<sub>n</sub> = f<sub>n-1</sub> + f<sub>n-2</sub> para todo n = 2, 3, 4&#8230;</em>
</p></blockquote>
<p>Siguiendo esto estrictamente, en C++ os quedaría:</p>
<pre>

unsigned long long
fibonacci(int value) {
  if(value == 0) {
    return 0;
  } else if(value == 1) {
    return 1;
  } else {
    return fibonacci(value - 1) + fibonacci(value - 2);
  }
}
</pre>
<p>Este algoritmo, como podréis observar, es <a href="http://es.wikipedia.org/wiki/Recursividad">recursivo</a>, es decir, se llama a sí mismo con parámetros diferentes a los que se pasa inicialmente para calcular la solución.</p>
<p>Pero este algoritmo tiene un problema bastante más grave que el de la recursividad (que, dependiendo del número de llamadas recursivas, corremos el riesgo de desbordar la pila) y es el de la duplicidad de llamadas a la función con el mismo valor del parámetro. Es decir, ¿te has parado a pensar cuántas veces se llama a la función <code>fibonacci(int)</code> con el mismo parámetro? Pues te lo digo yo: para un valor inicial de 8, esta función se llama 13 veces con el 0, 21 veces con el 1, 13 veces con el 2, 8 veces con el 3, 5 veces con el 4, 3 veces con el 5, 2 veces con el 6 y 1 vez con el 7. En total 66 veces. 66 veces cuando el valor a calcular es 8. Si tenemos que calcular con el 20, la función se llama un total de ¡<span class="nowrap">21 890</span> veces!</p>
<p>Digamos que esta función, implementada directamente como se define matemáticamente, es totalmente ineficiente. Probad, si queréis, a calcular el tiempo de cálculo para 20, 40, 50… si tenéis tiempo, claro.</p>
<p>¿Y cómo solucionarlo? Pues mediante <a href="http://es.wikipedia.org/wiki/Programaci%C3%B3n_din%C3%A1mica">programación dinámica</a>. Resumiendo, se trata de reducir el problema principal en problemas más pequeños, calcular la solución para cada problema pequeño y, finalmente, aplicar las soluciones de estos problemas pequeños para solucionar el problema grande.</p>
<p>Para la sucesión de Fibonacci específicamente, de lo que se trata es de no tener que calcular el mismo valor cada vez que se llama a la función, sino de tener una tabla donde están los valores previamente calculados. Si, cuando se llama a esta función el valor no está calculado, se calcula, pero si lo está, se recoge directamente de la tabla evitando toda esa recursividad y cálculos innecesarios.</p>
<p>Una posible implementación en C++ podría quedar así:</p>
<pre>

unsigned long long
fibonacci_alt(int value) {
	// Variables estáticas con la tabla de valores precalculados.
	static unsigned long long* prev_values = new unsigned long long[value];
	static bool init = true;
	if(init) {
		// Inicializamos sólo una vez.
		for(int i = 0; i &lt; value; i++) {
			prev_values[i] = -1;
		}
		init = false;
	}

	// Implementación de Fibonacci comprobando si hay algún valor precalculado.
	if(value == 0) {
		return 0;
	} else if(value == 1) {
		return 1;
	} else if(prev_values[value - 1] != -1 || prev_values[value - 2] != -1) {
		prev_values[value] = prev_values[value - 1] + prev_values[value - 2];
		return prev_values[value];
	} else {
		if(prev_values[value-1] == -1) {
			prev_values[value-1] = fibonacci_alt(value-1);
		}
		if(prev_values[value-2] == -1) {
			prev_values[value-2] = fibonacci_alt(value-2);
		}
		prev_values[value] = prev_values[value-1] + prev_values[value-2];
		return prev_values[value];
	}
}
</pre>
<p>Usando esta función, ésta sólo se ejecuta el número de veces indicado en el valor. Cierto es que usa más memoria, pero la reducción de tiempo es tan impresionante que merece la pena. De hecho, con este algoritmo, podréis calcular sin problemas la sucesión de Fibonacci para valores mayores de 200. Probad con el algoritmo anterior…</p>
<p>Y, ya de estar, <a href="/uploads/misc/fibonacci.cpp">aquí tenéis</a> un programa para probar estos dos algoritmos con alguna funcionalidad extra, como la de la presentación de estadísticas de llamadas a las funciones y demás. Y con un fallo: con el argumento “2” produce una <a href="http://es.wikipedia.org/wiki/Violaci%C3%B3n_de_segmento">violación de segmento</a>. Pero en general funciona.</p>
<p>Para compilarlo podéis usar el comando:</p>
<p class="terminal">
$ g++ -o fibonacci fibonacci.cpp
</p>
<p>Y para usarlo podéis hacerlo así (o usando el comando <code>time</code> para calcular cuánto tarda con cada método):</p>
<p class="terminal">
$ ./fibonacci<br />
fibonacci &lt;number&gt; [-a|-v|-av]<br />
Opciones:<br />
&nbsp;&nbsp;-a&nbsp;&nbsp;&nbsp;Usa el algoritmo alternativo.<br />
&nbsp;&nbsp;-v&nbsp;&nbsp;&nbsp;Muestra más información en pantalla.<br />
&nbsp;&nbsp;-av&nbsp;&nbsp;Usa el algoritmo alternativo mostrando más información.<br />
$ ./fibonacci 20<br />
6765<br />
$</p>
]]></content:encoded>
			<wfw:commentRss>http://beosman.org/archivo/2012/informatica/algoritmo-de-calculo-de-la-sucesion-de-fibonacci-en-cpp.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Funciones de comprobación de tipos de datos en C++</title>
		<link>http://beosman.org/archivo/2012/informatica/funciones-de-comprobacion-de-tipos-de-datos-en-c.html</link>
		<comments>http://beosman.org/archivo/2012/informatica/funciones-de-comprobacion-de-tipos-de-datos-en-c.html#comments</comments>
		<pubDate>Tue, 06 Mar 2012 18:59:04 +0000</pubDate>
		<dc:creator>Diego</dc:creator>
				<category><![CDATA[Informática]]></category>
		<category><![CDATA[Lenguajes]]></category>

		<guid isPermaLink="false">http://beosman.org/?p=5823</guid>
		<description><![CDATA[Haciendo uso de la STL de C++ y viendo que no tiene ninguna función &#8220;sencilla&#8221; de comprobación de tipos de datos, he implementado estas funciones para uso y disfrute de todo aquel que las quiera y las necesite. Con sus comentarios y todo. Por resumir, tenemos la función T StringTo&#60;T&#62;(string,T) (con sus diferentes variantes) para [...]]]></description>
			<content:encoded><![CDATA[<p>Haciendo uso de la <a href="http://en.wikipedia.org/wiki/Standard_Template_Library"><abbr title="Standard Template Library">STL</abbr></a> de <a href="http://es.wikipedia.org/wiki/C%2B%2B">C++</a> y viendo que no tiene ninguna función <em>&#8220;sencilla&#8221;</em> de comprobación de tipos de datos, he implementado estas funciones para uso y disfrute de todo aquel que las quiera y las necesite. Con sus comentarios y todo.</p>
<p>Por resumir, tenemos la función <code>T StringTo&lt;T&gt;(string,T)</code> (con sus diferentes variantes) para convertir una cadena al tipo determinado en la plantilla. Por ejemplo:</p>
<pre>

int i = StringTo&lt;int&gt;("42",0);  // i valdrá 42

bool error;
int a = StringTo&lt;int&gt;("42a",-1,error);  // a valdrá -1 y error será true

float f = StringTo&lt;float&gt;("123.45",-1);  // f valdrá 123.45
</pre>
<p>También está la función <code>bool StringIs&lt;T&gt;(string)</code> (también con sus variantes sobrecargadas) que comprueba si el valor pasado en la cadena como parámetro es del tipo indicado en la plantilla:</p>
<pre>

cout &lt;&lt; boolalpha &lt;&lt; StringIs&lt;int&gt;("42") &lt;&lt; endl;  // la salida será true
cout &lt;&lt; boolalpha &lt;&lt; StringIs&lt;int&gt;("42a") &lt;&lt; endl;  // la salida será false
cout &lt;&lt; boolalpha &lt;&lt; StringIs&lt;float&gt;("42") &lt;&lt; endl;  // la salida será true
cout &lt;&lt; boolalpha &lt;&lt; StringIs&lt;float&gt;("123.45") &lt;&lt; endl;  // la salida será true
</pre>
<p>Finalmente tenemos la función <code>string StringFrom&lt;T&gt;(T)</code> que devuelve una cadena con el valor pasado como parámetro convertido:</p>
<pre>

string value = StringFrom&lt;int&gt;(42);  // "value" contendrá la cadena "42"
string bvalue = StringFrom&lt;bool&gt;(true,boolapha);  // "bvalue" contendrá la cadena "true"
</pre>
<p>Y, ahora ya sí, la implementación:</p>
<pre>

#include &lt;string&gt;
#include &lt;sstream&gt;

using std::string;
using std::ios_base;
using std::stringstream;

/**
 * Convierte una cadena en el tipo dado en la plantilla.
 *
 * @param string value Valor a convertir.
 * @param T defaultValue Valor por defecto en caso de error.
 * @param bool&#038; error Esta variable se fija a true si hay error, a false si
 * todo_ está correcto.
 * @param ios_base f Si son números, se puede especificar una base de
 * conversión.
 * @return T Valor devuelto según la cadena pasada.
 */
template &lt;typename T&gt;
T
StringTo(const string value, T defaultValue, bool&#038; error, ios_base&#038; (*f)(ios_base&#038;) = NULL) {
	stringstream iss(value);
	T result;
	if(f == NULL) {
		iss &gt;&gt; result;
	} else {
		iss &gt;&gt; f &gt;&gt; result;
	}
	error = iss.fail() || iss.rdbuf()-&gt;in_avail() &gt; 0;
	return (iss.fail() || iss.rdbuf()-&gt;in_avail() &gt; 0 ? defaultValue : result);
}

/**
 * Función sobrecargada de la anterior donde se omite el parámetro "error".
 * @see template &lt;typename T&gt; T StringTo(const string, T, bool&#038;, ios_base&#038; (*)(ios_base&#038;));
 */
template &lt;typename T&gt;
T
StringTo(const string value, T defaultValue, ios_base&#038; (*f)(ios_base&#038;) = NULL) {
	bool result;
	return StringTo&lt;T&gt;(value, defaultValue, result, f);
}

/**
 * Función sobrecargada de la anterior con un "const char*" en lugar de
 * un string.
 *
 * @param const char* value Valor a convertir.
 * @param T defaultValue Valor por defecto.
 * @param ios_base&#038; f En caso de que sea un número y haya una base de
 * conversión.
 * @return T Tipo de dato a partir de la cadena.
 */
template &lt;typename T&gt;
T
StringTo(const char* value, T defaultValue, ios_base&#038; (*f)(ios_base&#038;) = NULL) {
	return StringTo&lt;T&gt;(string(value),defaultValue,f);
}

/**
 * Devuelve si una cadena contiene el tipo de dato indicado en la plantilla.
 *
 * @param string value Valor a controlar.
 * @param ios_base&#038; f En caso de que sea un número, la base de conversión.
 * @return bool True si la cadena es del tipo indicado, false en otro caso.
 */
template &lt;typename T&gt;
bool
StringIs(const string value, ios_base&#038; (*f)(ios_base&#038;) = NULL) {
	stringstream iss(value);
	T result;
	if(f == NULL) {
		iss &gt;&gt; result;
	} else {
		iss &gt;&gt; f &gt;&gt; result;
	}
	return !iss.fail() &#038;&#038; iss.rdbuf()-&gt;in_avail() &lt;= 0;
}

/**
 * Convierte un valor del tipo indicado en la plantilla a cadena de caracters.
 *
 * @param T value Valor.
 * @param ios_base&#038; f En caso de que sea numérico se puede especificar la base
 * de conversión.
 * @return string Cadena con el valor convertido.
 */
template &lt;typename T&gt;
string
StringFrom(const T value, ios_base&#038; (*f)(ios_base&#038;) = NULL) {
	stringstream result;
	if(f != NULL) {
		result &lt;&lt; f;
	}
	result &lt;&lt; (T)value;
	return result.str();
}
</pre>
<p><strong>Actualización 2012-03-07</strong>: Releyendo un poco el código y habiendo leído algo de documentación adicional, creo que quedaría más elegante si llamamos a las funciones de otra manera (con la misma implementación), por eso de simplificar. Más o menos así:</p>
<pre>

namespace string {

template &lt;typename T&gt; T to(const string) {…}

template &lt;typename T&gt; T is(const string) {…}

template &lt;typename T&gt; const string from(T value) {…}

}
</pre>
<p>Con lo que los ejemplos quedarían:</p>
<pre>

int i = string::to&lt;int&gt;("42");  // 42
bool isint = string::is&lt;int&gt;("42");  // true
string value = string::from&lt;float&gt;(123.45);  // "123.45"
</pre>
<p>Por simple elegancia <img src='http://beosman.org/wp-includes/images/smilies/grin.gif' alt=':grin:' class='wp-smiley' /> , ya que la funcionalidad es la misma. Pues quizás lo implemente&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://beosman.org/archivo/2012/informatica/funciones-de-comprobacion-de-tipos-de-datos-en-c.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Generar diccionarios de palabras en texto plano</title>
		<link>http://beosman.org/archivo/2012/informatica/generar-diccionarios-de-palabras-en-texto-plano.html</link>
		<comments>http://beosman.org/archivo/2012/informatica/generar-diccionarios-de-palabras-en-texto-plano.html#comments</comments>
		<pubDate>Fri, 17 Feb 2012 19:05:56 +0000</pubDate>
		<dc:creator>Diego</dc:creator>
				<category><![CDATA[Informática]]></category>
		<category><![CDATA[Lenguajes]]></category>
		<category><![CDATA[Sistemas Operativos]]></category>

		<guid isPermaLink="false">http://beosman.org/?p=5733</guid>
		<description><![CDATA[Un diccionario, en la jerga informática, es un archivo de palabras en texto plano —es decir, sin formato— donde generalmente hay una palabra por línea. Este tipo de diccionarios tiene muchos usos, entre ellos la de actuar como base de correctores ortográficos como, por ejemplo, el diccionario de Mozilla Firefox. En Linux existe un paquete [...]]]></description>
			<content:encoded><![CDATA[<p>Un diccionario, en la jerga informática, es un archivo de palabras en texto plano —es decir, sin formato— donde generalmente hay una palabra por línea. Este tipo de diccionarios tiene muchos usos, entre ellos la de actuar como base de correctores ortográficos como, por ejemplo, el <a href="https://addons.mozilla.org/es-es/firefox/language-tools/">diccionario de Mozilla Firefox</a>.</p>
<p>En Linux existe un paquete de software llamado <a href="http://en.wikipedia.org/wiki/Aspell">Aspell</a> que es la base de la mayoría de correctores ortográficos que se usan en este sistema operativo. Y, Aspell, obviamente, también tiene muchas palabras de diferentes idiomas que usa para su cometido, sólo que los tiene en su formato interno.</p>
<p>Pero, ¿qué pasa cuando queremos obtener un diccionario para nuestros propios fines? Por ejemplo, para instalarlo como corrector ortográfico de <a href="http://www.eclipse.org">Eclipse</a>. Pues para ello, haremos uso, en Linux, del nombrado paquete Aspell en su forma de comando de consola. El famoso comando, que luego explicaré, es este:</p>
<p class="terminal nowrap">
$ aspell &#45;&#45;lang=es dump master | aspell &#45;&#45;lang=es expand | tr &#8216; &#8216; &#8216;\n&#8217; &gt; spanish-dict.txt
</p>
<p>Este gran comando, en realidad son cuatro (separados por &#8216;|&#8217; y el último por &#8216;&gt;&#8217;):</p>
<ol>
<li><code>aspell &#45;&#45;lang=es dump master</code>: Vuelca todas las palabras del diccionario interno de Aspell a formato de texto plano y una por línea, con la salvedad de que dichas palabras tienen códigos específicos para poder expandirlas (por ejemplo, poder expandir el infinitivo de un verbo en todas sus formas).</li>
<li><code>aspell &#45;&#45;lang=es expand</code>: Dada una entrada (que en el comando es la salida del comando anterior), expande cada palabra de cada línea en todas las que puede generar. Por ejemplo, lo que he comentado antes, un verbo en todas sus formas. Esta expansión se hace en la misma línea, es decir, todas las formas verbales, por ejemplo, aparecerán en la misma línea separadas por espacios.</li>
<li><code>tr ' ' '\n'</code>: La entrada de este comando es la salida del anterior, transformando todos los espacios en retornos de carro. Con esto se consigue que, ahora sí, cada palabra esté en una línea.</li>
<li><code>&gt; spanish-dict.txt</code>: Finalmente, la salida del comando anterior se redirige a un archivo cuyo nombre es &#8220;spanish-dict.txt&#8221;.</li>
</ol>
<p>Ahora, en el archivo <code>spanish-dict.txt</code> tenemos <span class="nowrap">1 250 789</span> palabras, una por línea, que podremos usar para lo que queramos.</p>
<p class="postdata">
P.D.: Llegados a este punto, os podéis preguntar para qué sirven, además, estos diccionarios, porque sólo como corrector ortográfico podría parecer poco, ¿no? Pues lleváis razón. Una de las cosas donde más se utilizan estos diccionarios, a parte de corregirnos las faltas, es para <em>crackear</em> contraseñas. El método se llama <a href="http://es.wikipedia.org/wiki/Ataque_de_diccionario">ataque de diccionario</a> y consiste en coger cada una de las palabras del archivo e ir probando si coinciden con la contraseña. Y, como <a href="http://www.meneame.net/story/hackean-email-presidente-sirio-password-12345">la mayoría de las contraseñas que usamos son débiles</a>, pues suele ser bastante rápido el descifrado.</p>
]]></content:encoded>
			<wfw:commentRss>http://beosman.org/archivo/2012/informatica/generar-diccionarios-de-palabras-en-texto-plano.html/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Sesión remota gráfica en Linux</title>
		<link>http://beosman.org/archivo/2012/informatica/sesion-remota-grafica-en-linux.html</link>
		<comments>http://beosman.org/archivo/2012/informatica/sesion-remota-grafica-en-linux.html#comments</comments>
		<pubDate>Tue, 07 Feb 2012 18:54:49 +0000</pubDate>
		<dc:creator>Diego</dc:creator>
				<category><![CDATA[Informática]]></category>
		<category><![CDATA[Sistemas Operativos]]></category>

		<guid isPermaLink="false">http://beosman.org/?p=5618</guid>
		<description><![CDATA[Cuando accedemos a un ordenador, generalmente lo hacemos en modo consola, es decir, estamos delante de la pantalla, el teclado y el ratón y todo lo que hagamos mediante la interfaz lo hacemos en la máquina que tenemos delante. Pero ¿qué pasa cuando queremos trabajar en otro ordenador pero sin movernos del nuestro? Bien porque [...]]]></description>
			<content:encoded><![CDATA[<p>Cuando accedemos a un ordenador, generalmente lo hacemos en modo consola, es decir, estamos delante de la pantalla, el teclado y el ratón y todo lo que hagamos mediante la interfaz lo hacemos en la máquina que tenemos delante.</p>
<p>Pero ¿qué pasa cuando queremos trabajar en otro ordenador pero sin movernos del nuestro? Bien porque está lejos, bien porque somos unos vagos… <img src='http://beosman.org/wp-includes/images/smilies/grin.gif' alt=':grin:' class='wp-smiley' /> </p>
<p><img src="/uploads/2012/02/conexion-escritorio-remoto-200x123.png" alt="" title="Conexión a Escritorio Remoto" width="200" height="123" class="floatright" /></p>
<p>En <a href="http://es.wikipedia.org/wiki/Windows">Windows</a> es de sobra conocido el <a href="http://es.wikipedia.org/wiki/Remote_Desktop_Protocol">Protocolo de Escritorio Remoto</a>, donde nos conectamos a cualquier ordenador con Windows cuyo equipo esté compartido (que acepte conexiones remotas) y tenemos, en una ventana o en pantalla completa, el escritorio completo del ordenador remoto con el que podemos trabajar como si estuviéramos delante.</p>
<p>Y, en Linux, ¿podemos hacer algo similar? La respuesta corta es: por supuesto. La respuesta larga incluye la siguiente explicación:</p>
<p>El sistema operativo <a href="http://es.wikipedia.org/wiki/GNU/Linux">GNU/Linux</a> cuenta con un servidor gráfico (la aplicación que gestiona la <a href="http://es.wikipedia.org/wiki/Interfaz_gr%C3%A1fica_de_usuario">interfaz gráfica de usuario</a>) llamado <a href="http://es.wikipedia.org/wiki/X.Org_Server">X.org</a>, que es una implementación del sistema <a lang="en" href="http://es.wikipedia.org/wiki/X_Window_System">X Window System</a>. Este servidor es el programa encargado de gestionar las pantallas, las ventanas y, también, las conexiones remotas a otros equipos para tener interfaz gráfica remota. El protocolo usado para estas conexiones remotas, que es lo que nos interesa, se llama <acronym lang="en" title="X Display Manager Control Protocol"><a href="http://es.wikipedia.org/wiki/XDMCP">XDMCP</a></acronym>.</p>
<p>Este servidor gráfico se apoya en otra aplicación, llamada <em>Display Manager</em>, encargada de iniciar dicho servidor gráfico a la vez que muestra la pantalla de acceso, es decir, donde se pone el usuario y la contraseña. Y seguro que los usuarios de Linux conocéis más de un gestor de pantalla: <a href="http://es.wikipedia.org/wiki/XDM"><acronym title="X Display Manager" lang="en">xdm</acronym></a>, <a href="http://es.wikipedia.org/wiki/GDM"><acronym title="Gnome Display Manager" lang="en">gdm</acronym></a>, <a href="http://es.wikipedia.org/wiki/KDM"><acronym title="KDE Display Manager" lang="en">kdm</acronym></a>, <a href="http://es.wikipedia.org/wiki/LightDM"><acronym title="Light Display Manager" lang="en">lightdm</acronym></a>…</p>
<p>A partir de este punto donde ya sabemos, más o menos, cómo funciona esto de la gestión de la interfaz gráfica, lo que nos queda para habilitar el acceso remoto en Linux es configurar el gestor de pantalla (<em>display manager</em>) del ordenador remoto al que queremos acceder para que tenga activado el protocolo <acronym lang="en" title="X Display Manager Control Protocol">XDMCP</acronym>.</p>
<p>Hay que tener en cuenta que cada gestor usado (como hemos dicho: gdm, kdm, lightdm&#8230;) tiene su propia configuración, pero para el más moderno y usado en la última versión de Ubuntu, <code>lightdm</code>, la configuración está en el archivo <code>/etc/lightdm/lightdm.conf</code> (para el resto se puede ver su configuración usando el manual o, en una consola, con el comando <code>man <em>&lt;dm&gt;</em></code>). En este archivo de configuración hay que activar el protocolo <acronym lang="en" title="X Display Manager Control Protocol">XDMCP</acronym> añadiendo las siguientes líneas en dicho archivo:</p>
<div class="source">
<p>[XDMCPServer]<br />
enable=true</p>
</div>
<p>Y luego reiniciar el servidor <code>lightdm</code> —teniendo en cuenta que se cerrarán todas las sesiones— con el comando:</p>
<p class="terminal">
$ sudo service lightdm restart
</p>
<p>Ya tenemos nuestro servidor funcionando y aceptando conexiones remotas. Y, ahora, para acceder a él, lo podemos hacer de dos formas:</p>
<p>La primera es usando el programa <code>Xnest</code> que se instala escribiendo el comando <code>sudo apt-get install xnest</code>. Luego, para lanzar la sesión remota hay que lanzar el comando:</p>
<p class="terminal">
$ Xnest :1 -query remote.server
</p>
<p>En el caso de que tengáis en vuestro equipo más de una sesión gráfica iniciada, hay que cambiar el <code>:1</code> por un número de pantalla que no está usado. Además, <code>remote.server</code> puede ser tanto el nombre de un servidor como su IP.</p>
<p>Con este comando se nos abrirá una ventana donde aparecerá la pantalla de acceso a nuestro servidor remoto como si estuviéramos delante de él.</p>
<p><a href="/uploads/2012/02/xnest.jpg"><img src="/uploads/2012/02/xnest-650x494.jpg" alt="Ventana de Xnest" title="Ventana de Xnest" width="650" height="494" class="alignnone size-large wp-image-5637 image" /></a></p>
<p>La segunda opción es lanzar directamente las X (otra instancia del servidor X.org) desde un terminal mediante el comando: </p>
<p class="terminal">
$ X :1 -query remote.server
</p>
<p>Hay que tener en cuenta lo mismo sobre el número de pantalla (<code>:1</code>) y el nombre del servidor que con <code>Xnest</code>.</p>
<p>Con este comando, en lugar de abrir una ventana, lo que hará será cambiar de <a href="http://en.wikipedia.org/wiki/Virtual_terminal">terminal virtual  (<abbr title="Virtual Terminal" lang="en">VT</abbr>)</a> —de forma similar a cuando cambiamos entre la interfaz gráfica y una consola con las teclas Ctrl+Alt+F1/F7— a, generalmente, el número 8 (Ctrl+Alt+F8) mostrándonos la pantalla de acceso al sistema remoto.</p>
<p>Con el segundo método realmente parece que estamos delante de la máquina remota ya que no hay ventanas de por medio que aparenten estar en un sistema virtualizado. Además, con las combinaciones de teclas Ctrl+Alt+F<em>x</em> bastará para cambiar entre equipos de forma muy cómoda y muy rápida, teniendo tanto la sesión local como la sesión remota totalmente activas y funcionales.</p>
<p>Y realmente es muy cómodo no tener que desplazarse para trabajar en otros equipos cuando necesitas la interfaz gráfica. Aunque, bueno, ya sabéis que para administrar sistemas no hay nada mejor ni más rápido que una consola en modo texto, por supuesto <img src='http://beosman.org/wp-includes/images/smilies/grin.gif' alt=':grin:' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://beosman.org/archivo/2012/informatica/sesion-remota-grafica-en-linux.html/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Implementación de la clase de sincronización Semaphore con la librería boost (y alguna cosa más)</title>
		<link>http://beosman.org/archivo/2012/informatica/implementacion-de-la-clase-de-sincronizacion-semaphore-con-la-libreria-boost-y-alguna-cosa-mas.html</link>
		<comments>http://beosman.org/archivo/2012/informatica/implementacion-de-la-clase-de-sincronizacion-semaphore-con-la-libreria-boost-y-alguna-cosa-mas.html#comments</comments>
		<pubDate>Thu, 02 Feb 2012 19:21:19 +0000</pubDate>
		<dc:creator>Diego</dc:creator>
				<category><![CDATA[Informática]]></category>

		<guid isPermaLink="false">http://beosman.org/?p=5583</guid>
		<description><![CDATA[Una de las primitivas clásicas de la sincronización de procesos e hilos —hablando de informática— es el semáforo. La diferencia entre este y el mutex es que el semáforo se puede bloquear y liberar desde diferentes hilos/procesos mientras que el mutex no; es para proteger una zona de código (el acceso a variables por un [...]]]></description>
			<content:encoded><![CDATA[<p>Una de las primitivas clásicas de la sincronización de <a href="http://es.wikipedia.org/wiki/Proceso_(inform%C3%A1tica)">procesos</a> e <a href="http://es.wikipedia.org/wiki/Hilo_de_ejecuci%C3%B3n">hilos</a> —hablando de informática— es el <a href="http://es.wikipedia.org/wiki/Sem%C3%A1foro_(programaci%C3%B3n)">semáforo</a>. La diferencia entre este y el <em><a href="http://es.wikipedia.org/wiki/Mutex">mutex</a></em> es que el semáforo se puede bloquear y liberar desde diferentes hilos/procesos mientras que el <em>mutex</em> no; es para proteger una zona de código (el acceso a variables por un sólo hilo).</p>
<p>La librería <a href="http://www.boost.org/"><code>boost</code></a> —una de las mejores librerías generalistas para C++ que hay, por no decir la mejor— no hay un semáforo de este tipo propiamente dicho, sino que se usan <a href="http://en.wikipedia.org/wiki/Condition_variable">variables de condición</a> para implementarlo; o semáforos con nombre, aunque estos son más específicos para sincronización entre procesos en lugar de entre hilos. Esta implementación se basa mucho en el estándar <acronym title="Portable Operating System Interface (UNIX)" lang="en"><a href="http://es.wikipedia.org/wiki/POSIX">POSIX</a></acronym> de hilos (<code><a href="http://en.wikipedia.org/wiki/Pthreads">pthreads</a></code>) pero orientándolo a objetos.</p>
<p>Es por esto que, para no tener que usar un variable de condición, un <code>mutex</code> y un contador cada vez que se quiere implementar un semáforo, se puede usar esta clase:</p>
<pre>
#include &lt;boost/thread.hpp&gt;
#include &lt;boost/thread/condition_variable.hpp&gt;
#include &lt;boost/thread/mutex.hpp&gt;

class Semaphore {
	private:
    	mutable boost::mutex fMutex;
	    boost::condition_variable fCondVar;
    	unsigned long fCounter;

	public:
    	Semaphore(unsigned long counter)
          : fMutex(),
            fCondVar(),
            fCounter(counter)
        {
    	}

	    void post() {
    	    boost::mutex::scoped_lock lock(fMutex);
    	    ++fCounter;
    	    fCondVar.notify_one();
	    }

    	void wait() {
    	    boost::mutex::scoped_lock lock(fMutex);
    	    while(fCounter &lt;= 0)
    	        fCondVar.wait(lock);
    	    --fCounter;
    	}

    	bool isLocked() const {
    		return fCounter == 0;
    	}
};
</pre>
<p>Un buen ejemplo de uso de un semáforo es implementar una cola de datos usada para el famoso <a href="http://en.wikipedia.org/wiki/Producer-consumer_problem">problema del productor/consumidor</a>, es decir, tenemos dos procesos, uno que produce datos y los mete en la cola, y otro que los consume sacándolos de dicha cola teniendo en cuenta que, cuando la cola está vacía, el consumidor está bloqueado esperando a que haya más valores.</p>
<p>Para ello, la implementación de la cola podría ser la siguiente:</p>
<pre>
#include &lt;deque.hpp&gt;

using std::deque;

template &lt;typename T&gt;
class Queue {
	private:
		deque&lt;T&gt; fQueue;
		mutable boost::mutex fAccessLock;
		mutable Semaphore fSem;

	public:
		Queue() : fQueue(), fAccessLock(), fSem(0) {}

		virtual ~Queue() {}

		virtual void push(T elem) {
			fSem.post();
			boost::mutex::scoped_lock lock(fAccessLock);
			fQueue.push_front(elem);
		}

		virtual T pop() {
			fSem.wait();
			boost::mutex::scoped_lock lock(fAccessLock);
			T elem = fQueue.back();
			fQueue.pop_back();
			return elem;
		}
};
</pre>
<p>Y el programa de prueba implementando dos funciones, una el productor y otra el consumidor, y usando <a href="http://www.boost.org/doc/libs/1_48_0/doc/html/thread.html">hilos de <code>boost</code></a> sería:</p>
<pre>
#include &lt;boost/ref.hpp&gt;
#include &lt;boost/date_time.hpp&gt;
#include &lt;iostream&gt;

template &lt;typename T&gt;
void
producer(Queue&lt;T&gt;&#038; q) {
	int counter = 0;
	int times = 5;
	while(!boost::this_thread::interruption_requested() &#038;&#038; times-- &gt; 0) {
		for(int i = 0; i &lt; 5; i++) {
			cout &lt;&lt; "producer: inserting " &lt;&lt; counter &lt;&lt; endl;
			q.push(counter++);
		}
		sleep(4);
	}
}

template &lt;typename T&gt;
void
consumer(Queue&lt;T&gt;&#038; q) {
	while(!boost::this_thread::interruption_requested()) {
		cout &lt;&lt; "consumer: extracting " &lt;&lt; q.pop() &lt;&lt; endl;
		boost::this_thread::sleep(boost::posix_time::milliseconds(100));
	}
}

int
main() {
	Queue&lt;int&gt; q(7);

	boost::thread p(producer,boost::ref(q));
	sleep(1);
	boost::thread c(consumer,boost::ref(q));

	p.join();
	c.join();

	return 0;
}
</pre>
<p>En este ejemplo, el hilo productor inserta cinco números cada 4 segundos (a ráfagas) mientras que el productor saca un número cada 100 milisegundos. Cuando la cola está vacía, gracias al semáforo el hilo consumidor espera hasta que el productor inserte más números, y así sucesivamente.</p>
<p>Pues sí, pues vale, muy bonito, pero ¿para qué se usa esta cola y el productor/consumidor? Pues, en informática, en multitud de software. Por ejemplo, en el reproductor multimedia que usáis todos los días. El hilo productor es el que hilo que lee del disco duro la música insertando los datos leídos en un <em>buffer</em> (en la cola), y el consumidor es el hilo que saca los datos de ese <em>buffer</em>, los decodifica y los envía a la tarjeta de sonido. Y con el vídeo funciona igual (aparte, claro, de los mecanismos de sincronización entre sonido y vídeo).</p>
<p>Pero en esta implementación hay una cosa que falta: el productor debería parar de insertar elementos cuando la cola esta llena hasta que el consumidor saque algún elemento. Pero esa implementación será para el próximo programa <img src='http://beosman.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  .</p>
]]></content:encoded>
			<wfw:commentRss>http://beosman.org/archivo/2012/informatica/implementacion-de-la-clase-de-sincronizacion-semaphore-con-la-libreria-boost-y-alguna-cosa-mas.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>11 características que Twitter debería tener</title>
		<link>http://beosman.org/archivo/2011/informatica/11-caracteristicas-que-twitter-deberia-tener.html</link>
		<comments>http://beosman.org/archivo/2011/informatica/11-caracteristicas-que-twitter-deberia-tener.html#comments</comments>
		<pubDate>Fri, 09 Dec 2011 14:59:32 +0000</pubDate>
		<dc:creator>Diego</dc:creator>
				<category><![CDATA[Informática]]></category>
		<category><![CDATA[Opinión]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://beosman.org/?p=5412</guid>
		<description><![CDATA[Mucha gente usa Twitter, esa red social tan &#8220;rara&#8221; que sólo permite 140 caracteres en cada mensaje. Y quizás sea por eso su gran éxito a pesar de que sus características técnicas no han cambiado desde&#8230; bueno, casi desde que se creó. Por eso creo que, desde el punto de vista de un usuario (no [...]]]></description>
			<content:encoded><![CDATA[<p>Mucha gente usa <a href="http://es.wikipedia.org/wiki/Twitter">Twitter</a>, esa <a href="http://es.wikipedia.org/wiki/Red_social">red social</a> tan <em>&#8220;rara&#8221;</em> que sólo permite 140 caracteres en cada mensaje. Y quizás sea por eso su gran éxito a pesar de que sus características técnicas no han cambiado desde&#8230; bueno, casi desde que se creó. Por eso creo que, desde el punto de vista de un usuario (no de un desarrollador), Twitter necesita, al menos, que se implementen estas 11 características:</p>
<ol>
<li><strong>Edición de tuits</strong>: Sería bueno poder editar los tuits, al menos durante un tiempo después de la publicación, para corregir, por ejemplo, faltas de ortografía. No sería bueno poder editarlos siempre ya que con la sucesivas ediciones podrías hacer totalmente incoherente la conversión con el resto de usuarios.</li>
<li><strong>Bloqueo de usuarios sin necesidad de dejar de seguirlos</strong>: ¿Sabéis eso de &#8220;te sigo por compromiso&#8221;? Pues eso. Además, he visto algunos tuits donde ya se demanda esta característica.</li>
<li><strong>Omisión de tuits en el <em>timeline</em> que contengan un determinado <em>hashtag</em></strong>: No estaría demás que se pudiera, en el <acronym title="Timeline" lang="en">TL</acronym> principal, omitir de forma automática los tuits que contengan algún <em><a href="http://es.wikipedia.org/wiki/Hashtag">hashtag</a></em> determinado, por eso de ser, en ocasiones, bastante cansinos.</li>
<li><strong>Poder recuperar todos tus tuits</strong>: En caso de tener un cliente de Twitter que no sea el de Web (y creo que con el de Web también), sólo podrás recuperar tus 3000 últimos tuits. Aunque el resto siguen en la base de datos, su API no soporta recuperar más de esta cantidad.</li>
<li><strong>Posibilidad de copia de seguridad de tus tuits</strong>: No hay ninguna forma de recuperar todos tus tuits si no es con aplicaciones externas. Y a esto hay que aplicarle el límite del punto anterior. Twitter debería implementar una forma de hacer copia de seguridad de tus tuits.</li>
<li><strong>Respuesta pública</strong>: Posibilidad de responder a un tuit de forma pública (que lo vean todos los usuarios que te siguen en lugar de los usuarios que te siguen y los que siguen al que respondes) para así no tener que poner un carácter antes del nombre de quien estás respondiendo y tener que desaprovecharlo.</li>
<li><strong>Implementación de un sistema para <em>&#8220;leer más tarde&#8221;</em></strong>: Yo, al menos, uso los favoritos como marcadores para leer luego. No tengo ningún tuit favorito, simplemente en mi cliente del móvil los marco (los que tienen imágenes, alguna <acronym title="Uniform Resource Locator" lang="en">URL</acronym>&#8230;) para leer cuando esté en un ordenador o <em>tablet</em>. Recordemos las limitaciones de las pantallas pequeñas y, sobre todo, las limitaciones de las conexiones <a href="http://es.wikipedia.org/wiki/3G">3G</a>.</li>
<li><strong>Formato del texto</strong>: Esta quizás sería la más rompedora con la filosofía de Twitter, pero ayudaría mucho a expresar justamente lo que queremos decir —<em>&#8220;emociones&#8221;</em> incluidas— con, al menos, negrita, cursiva y tachado.</li>
<li><strong>Enlaces contextualizados</strong>: Los enlaces deberían ir como en HTML, enlazando un texto en lugar de que vaya la <acronym title="Uniform Resource Locator" lang="en">URL</acronym> directamente. El contexto es muy importante en la Web y Twitter está haciendo un esfuerzo enorme —entiendo que inconscientemente— para eliminarlo. Lo mismo que los acortadores <acronym title="Uniform Resource Locator" lang="en">URL</acronym>, donde se pierde toda la semántica de las <a href="http://es.wikipedia.org/wiki/URL_sem%C3%A1ntica"><acronym title="Uniform Resource Locator" lang="en">URL</acronym>s amigables</a>. Pero ese es otro tema.</li>
<li><strong>Estadísticas</strong>: Sería buena idea que se proporcionaran estadísticas —principalmente informativas— de uso de Twitter, tanto de los usuarios (tuits por día, horarios de tuiteo, retuits…) como generales (tuis diarios, tuits diarios por países, usuarios activos en tiempo real…).</li>
<li><strong>Avance automático en el cliente Web</strong>: En el cliente Web, cuando sale el aviso de que hay nuevos tuits, al hacer clic, la página debería avanzar automáticamente hasta el último que has leído. Además, en la nueva interfaz, se debería marcar de alguna forma el último tuit que has leído (en la antigua se hacía).</li>
</ol>
<p>Y una característica extra, la duodécima: más caracteres. Aquí hay muchísima controversia. Quizás, como he dicho antes, el éxito de Twitter sea precisamente el de tener un número de caracteres limitados. Pero, al menos a mi, muchas más veces de las que me gustaría se me quedan muy cortos para escribir lo que quiero decir. Y a veces no soy capaz de hacerle caso al famoso mensaje <em>&#8220;Tu Tweet contiene mas de 140 caracteres. Tendrás que ser más ingenioso.&#8221;</em>.</p>
<p>No estoy diciendo que se ponga un número ilimitado (o muy grande) de caracteres como ocurre con <a href="http://es.wikipedia.org/wiki/Google%2B">Google+</a> o <a href="http://es.wikipedia.org/wiki/Facebook">Facebook</a>, pero sí alguno más, por ejemplo —por aventurarme con un número— 200; o, mejor, 256 (2<sup>8</sup>, por eso de ser friki <img src='http://beosman.org/wp-includes/images/smilies/tongue.gif' alt=':tongue:' class='wp-smiley' /> ). Por ejemplo, las <a href="http://www.meneame.net/notame/">notas de Menéame</a> tienen 1000 caracteres y creo que la mayoría de ellas no pasan ni de los 500, pero cuando hay algo más largo que decir, se puede hacer sin ningún problema.</p>
<p>Pero bueno, esta es sólo mi opinión. Y vosotros ¿qué opináis de estas 11 características que Twitter debería tener? ¿Alguna más? ¿Alguna menos?</p>
]]></content:encoded>
			<wfw:commentRss>http://beosman.org/archivo/2011/informatica/11-caracteristicas-que-twitter-deberia-tener.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>¿Pagarías por usar tu distribución de Linux favorita?</title>
		<link>http://beosman.org/archivo/2011/informatica/%c2%bfpagarias-por-usar-tu-distribucion-de-linux-favorita.html</link>
		<comments>http://beosman.org/archivo/2011/informatica/%c2%bfpagarias-por-usar-tu-distribucion-de-linux-favorita.html#comments</comments>
		<pubDate>Mon, 05 Dec 2011 22:09:05 +0000</pubDate>
		<dc:creator>Diego</dc:creator>
				<category><![CDATA[Informática]]></category>
		<category><![CDATA[Opinión]]></category>

		<guid isPermaLink="false">http://beosman.org/?p=5399</guid>
		<description><![CDATA[Me ha llamado mucho la atención esta encuesta del blog Usemos Linux: &#8220;¿Pagarías por usar tu distribución favorita de Linux?&#8221;. Mi respuesta corta: No. Mi respuesta larga: No porque todas las distribuciones usan el mismo software. Todas. Todas usan X Window System (de momento Wayland está en desarrollo). Todas usan Gnome o KDE con alguna [...]]]></description>
			<content:encoded><![CDATA[<p>Me ha llamado mucho la atención <a href="http://usemoslinux.blogspot.com/2011/12/pagarias-por-usar-tu-distro-linux.html">esta encuesta</a> del blog <a href="http://usemoslinux.blogspot.com/">Usemos Linux</a>: <em>&#8220;¿Pagarías por usar tu distribución favorita de Linux?&#8221;</em>.</p>
<p>Mi respuesta corta: <strong>No</strong>.</p>
<p>Mi respuesta larga: No porque <strong>todas</strong> las distribuciones <strong>usan el mismo software</strong>. Todas. Todas usan <a href="http://es.wikipedia.org/wiki/X_Window_System">X Window System</a> (de momento <a href="http://es.wikipedia.org/wiki/Wayland_(servidor_gr%C3%A1fico)">Wayland</a> está en desarrollo). Todas usan <a href="http://es.wikipedia.org/wiki/Gnome">Gnome</a> o <a href="http://es.wikipedia.org/wiki/KDE">KDE</a> con alguna disidente que usa <a href="http://es.wikipedia.org/wiki/Xfce">Xfce</a>, <a href="http://es.wikipedia.org/wiki/LXDE">LXDE</a> o similares. Todas tienen las mismas librerías. Todas tienen la misma arquitectura multimedia. Y, como no, todas usan, en esencia, el mismo <a href="http://es.wikipedia.org/wiki/N%C3%BAcleo_Linux">Kernel</a>.</p>
<p>¿Por qué pagar por algo que haga una empresa cuando cualquier otra empresa o particular lo puede hacer sin ningún coste? Incluso, si eres un poco aficionado al tema, te puedes hacer tu propia distribución sin más coste que tu tiempo. Y, ojo, que no estamos hablando del servicio técnico.</p>
<p>Yo, personalmente, pagaría por tener algo diferente (y mejor, se entiende). Algo que haya hecho una empresa para mejorar lo que hay en lugar de ser una mera agrupación de distintos elementos de software, todo con el mismo Kernel, y ponerle un nombre rimbombante.</p>
<p>Si Windows no es de mi agrado a nivel técnico (y lo uso como usuario), Linux tampoco lo es (y también lo uso como usuario). Ya sabéis que yo soy más de <a href="http://es.wikipedia.org/wiki/BeOS">BeOS</a>/<a href="http://es.wikipedia.org/wiki/Haiku_(sistema_operativo)">Haiku</a> <img src='http://beosman.org/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://beosman.org/archivo/2011/informatica/%c2%bfpagarias-por-usar-tu-distribucion-de-linux-favorita.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>C#</title>
		<link>http://beosman.org/archivo/2011/informatica/c-sharp.html</link>
		<comments>http://beosman.org/archivo/2011/informatica/c-sharp.html#comments</comments>
		<pubDate>Thu, 01 Dec 2011 18:54:20 +0000</pubDate>
		<dc:creator>Diego</dc:creator>
				<category><![CDATA[Informática]]></category>
		<category><![CDATA[Lenguajes]]></category>

		<guid isPermaLink="false">http://beosman.org/?p=5299</guid>
		<description><![CDATA[Por necesidades del servicio voy a empezar a programar en C#, así que me he leído un par de manuales y he practicado un poco con ello. Y, la verdad, no me ha convencido demasiado. Así que, por petición popular (si por una persona se le puede llamar &#8220;popular&#8221;), estas son algunas de las conclusiones [...]]]></description>
			<content:encoded><![CDATA[<p>Por <em>necesidades del servicio</em> voy a empezar a programar en <a href="http://es.wikipedia.org/wiki/C_Sharp">C#</a>, así que me he leído un par de manuales y he practicado un poco con ello. Y, la verdad, <a href="https://twitter.com/#!/beoxman/status/139403030180274177">no me ha convencido demasiado</a>. Así que, por <a href="https://twitter.com/#!/albfernandez/status/139419504382967808">petición popular</a> (si por una persona se le puede llamar <em>&#8220;popular&#8221;</em>), estas son algunas de las conclusiones que he sacado, aunque si eres muy fan de C# quizás no deberías seguir leyendo <img src='http://beosman.org/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> :</p>
<h3>Declaración de tipos</h3>
<p>Extrañamemente se usan formas diferentes para declarar lo mismo. Porque declarar una variable o un nuevo tipo de dato debería ser consistente. Por ejemplo, para declarar una variable se usa <code>&lt;tipo de dato&gt; <strong>&lt;identificador&gt;</strong>;</code>. En cambio, para declarar un alias de un tipo de dato (no hay nuevos tipos) se usa <code>using <strong>&lt;identificador&gt;</strong> = &lt;tipo de dato&gt;;</code>. Y, ya para rematar, para declarar un <code><a href="">delegate</a></code> se usa <code>delegate &lt;valor devuelto&gt; <strong>&lt;identificador&gt;</strong> (&lt;parámetros&gt;);</code>.</p>
<p>¿No sería más sencillo y consistente tener una sintaxis común? Por ejemplo: <code>&lt;tipo de dato&gt; &lt;descripción&gt; <strong>&lt;identificador&gt;</strong>;</code>, con lo que la declaración quedaría:</p>
<pre>
// Variable:
int i;

// Tipo de dato:
typedef int MyInt;

// Usando 'using' (sin introducir ninguna palabra reservada adicional):
using int as MyInt;

// Delegate:
delegate void(int) MyDelegate;
</pre>
<p>Con esto la sintaxis siempre es consistente. Tenemos a la izquierda los tipos y a la derecha, siempre, el nombre tanto de la variable como del tipo nuevo como del delegate (que no deja de ser un tipo nuevo).</p>
<h3>Nuevos tipos de datos</h3>
<p>En C#, al igual que en C++, no se pueden declarar nuevos tipos de datos. Sí, en serio. Lo que estáis pensando ahora mismo es que con typedef sí se puede&#8230; pues no. En realidad es un alias del tipo básico. En C++, este código:</p>
<pre>
typedef int myint_t;
void overloaded_function(int value);
void overloaded_function(myint_t value);  // Error de compilación.
</pre>
<p>Daría error de compilación porque las dos funciones son iguales. <code>myint_t</code> no es un tipo de datos nuevo, sino un alias de <code>int</code>. En C# ocurre lo mismo, sólo que en lugar de declarar los <em>nuevos</em> tipos con <code>typedef</code> (que no tiene esa palabra reservada) se usa <code>using</code>:</p>
<pre>
using myint_t = int;

class Main {
  void overloaded_funcion(int value) {...}
  void overloaded_funcion(myint_t value) {...}  // Error de compilación.
}
</pre>
<p>También se puede hacer alguna triquiñuela, como hacer una clase <code>MyInt</code> que herede de <code>System.Int32</code>. Pero ya habría que implementar ciertas cosas para que funcionase.</p>
<h3>Los métodos y su tipo de acceso</h3>
<p>Es bastante enrevesado el uso de <code>virtual</code>, <code>override</code> y <code>new</code> para controlar el polimorfismo de las clases. Por ejemplo, en el código:</p>
<pre>
class A {
	public virtual void Who() { Console.WriteLine("A"); }
}

class B : A {
	public override void Who() { Console.WriteLine("B"); }
}

class C : B {
	public new virtual void Who() { Console.WriteLine("C"); }
}

class D : C {
	public override void Who() { Console.WriteLine("D"); }
}

C c = new D();
c.Who();	// Escribe "D"; lógico ¿no?

A a = new D();
a.Who();	// ¡Escribe "B"! ¿Dónde está la lógica de funciones virtuales aquí?
</pre>
<p>Es obligatorio que en todos los métodos que se podrán sobreescribir en clases derivadas se ponga <code>virtual</code>; que en todos los métodos que sobreescriben se ponga <code>override</code>; y que si un método oculta a otro se ponga <code>new</code>.</p>
<p>¿No sería más sencillo que todos los métodos fuesen virtuales por defecto (porque cuando haces clases, lo más probable es que las vayas a heredar)? ¿No sería más lógico que cuando declaras un método con el mismo nombre en la clase base, automáticamente se sobreescriba el de la base y, en caso de querer llamar al método de la base, uses <code>super</code>, <code>base</code> o similar?</p>
<p>Por cierto, decidme un caso <strong>real</strong> donde se use esta funcionalidad.</p>
<h3>El problema de la clase base frágil</h3>
<p>En <a href="http://ssw.jku.at/Teaching/Lectures/CSharp/Tutorial/Part2.pdf">este manual se menciona el problema de la clase base frágil</a>, que habla de que en Java podría suceder esto, teniendo en principio estas clases:</p>
<pre>
class BaseClass {
	public void CleanUp() {
		System.out.println("BaseClass.CleanUp()");
	}
}

class DerivedClass extends BaseClass {
	public void Delete() {
		System.out.println("DerivedClass.Delete()");
	}
	public void CleanUp() {
		Delete();
	}
}

public class Test {
	public static void main(String[] args) {
		BaseClass k = new DerivedClass();
		k.CleanUp();
	}
}
</pre>
<p>La salida de este programa sería:</p>
<p class="terminal">
$ javac Test.java &#038;&#038; java Test<br />
DerivedClass.Delete();<br />
$
</p>
<p>Si luego implementamos el método <code>Delete()</code> en la clase base de esta forma:</p>
<pre>
class BaseClass {
	public void CleanUp() {
		System.out.println("BaseClass.CleanUp()");
	}
	public void Delete() {
		System.out.println("Delete all the world!");
	}
}
</pre>
<p>Según el manual, ¡podríamos borrar el mundo!</p>
<p>Esto sería un verdadero problema&#8230; si existiese. Pero es muy fácil comprobar que no se produce. La salida con la clase modificada es la misma que sin ella. Sólo usando <code>super.Delete()</code> se podría borrar el mundo.</p>
<h3>Ámbito global o local</h3>
<p>En C#, si una clase oculta un espacio de nombres, para acceder a dicho espacio introduce una nueva palabra que no está reservada, pero que hay que recordar: <code>global</code>. Por ejemplo:</p>
<pre>
class Main {

  public class System {}

  static void Main(string[] args) {
    System.Console.WriteLine("¡Hola mundo!");  // Error: la clase 'System' oculta
                                               // el espacio de nombres 'System'.
    global::System.Console.WriteLine("Esto sí funciona.");
  }
}
</pre>
<p>¿No sería más sencillo, en lugar de introducir otro identificador nuevo, usar sólo el operador <code>::</code>, como hace C++ o, incluso, usar el operador <code>.</code>?</p>
<h3>Comportamientos extraños de las variables</h3>
<p>Resulta que si declaras una variable de tipo <code>delegate</code>, esta se comporta como una <strong>lista</strong> de delegates que se llaman todos seguidos:</p>
<pre>

class Test {
	void Notify1(string text) {
		System.Console.WriteLine("Hello " + text);
	}
	void Notfiy2(string text) {
		System.Console.WriteLine("Goodbye " + text);
	}
}

Test test = new Test();

delegate void Notifier(string text);

Notifier notifier;
notifier = new Notifier(test.Notify1);
notifier += new Notifier(test.Notify2);

notifier("Manolito");

// La salida será:
// Hello Manolito
// Goodbye Manolito
</pre>
<p>¿Nos aclaramos? ¿<code>Notifier</code> es una variable o es una lista de variables? Y si todos los <code>delegate</code>s asignados devuelven algún valor, sólo se devuelve el último ejecutado. ¿Y el resto?</p>
<h3>Recorriendo listas</h3>
<p>C# añade el <code>foreach</code>, que no es más que lo que se conoce como <em><a href="http://en.wikipedia.org/wiki/Syntactic_sugar">syntactic sugar</a></em> para el bucle <code>for</code> de toda la vida evitando que el programador use variables índice:</p>
<pre>

string[] stringArray = new string[] { /* Inicialización */ };

foreach(var s in stringArray) {
  System.Console.WriteLn(s);
}
</pre>
<p>Pero no estoy criticando ese <em>syntactic sugar</em>, todo lo contrario, eso me parece muy bien. Cuanto menos código se escriba y haga más cosas, mejor.</p>
<p>Lo que ya no me parece tan bien es que en ese bucle <code>foreach</code> sólo se tenga acceso a los valores de la lista a recorrer y no se tenga acceso al índice de dicha lista. Sí, simplemente a la famosa <code>i</code> que se omite para que el programador escriba menos código.</p>
<p>Y por culpa de esto, en caso de necesitarla, pues tienes que declararla fuera e incrementarla manualmente. Vamos, con en un bucle <code>for</code>.</p>
<h3>Anidamiento</h3>
<p>No se permiten métodos anidados, es decir, declaración e implementación de métodos dentro de otros métodos. Sí, venga, vale, se puede “solucionar” mediante el uso de <code>delegates</code>, pero eso no es permitir métodos anidados, eso es una chapuza.</p>
<p>Y además, ya para rematar, tampoco se permite declarar estructuras ni clases dentro de métodos. Como está orientado a objetos, pues toda declaración adicional tiene que ir dentro de la clase.</p>
<p><strong>Actualización 2011-12-05</strong>: C y C++ tampoco permiten métodos anidados <a href="http://beosman.org/archivo/2011/informatica/c-sharp.html#comment-22891">como me indican en un comentario</a>. Esto lo puse porque yo los he usado para resolver algún problema, sólo que no recuerdo ni el lenguaje ni el proyecto en el que lo hice. ¿Pascal quizás?</p>
<h3>Atributos</h3>
<p>Los atributos del lenguaje también son otra cosa que está muy bien dentro de un lenguaje. Permiten extender la funcionalidad del compilador, por ejemplo, para hacer compilación condicional, controlar entre diferentes versiones o arquitecturas, marcar elementos como obsoletos… pero, me pregunto, ¿por qué la sintaxis no es coherente con el resto del lenguaje y hay que añadir triquiñuelas del estilo <code>[Conditional("Debug")]</code> al código?</p>
<h3>Conclusión</h3>
<p>Después de despotricar un poco toca una pequeña conclusión:</p>
<p>Si Microsoft tuvo la oportunidad de crear un nuevo lenguaje de programación desde cero, para ellos solos, sin que nadie se pueda meter, sin que nadie le diera lecciones, con la posibilidad de innovar, de mejorar lo que había hasta el momento ¿por qué lo ha hecho tan retorcido e incoherente? Porque sí, en serio, es retorcido. Hasta C++ —que mira que a <a href="http://es.wikipedia.org/wiki/Bjarne_Stroustrup">Bjarne Stroustrup</a> se le fue la olla cuando lo diseñó— es más consistente y coherente que C#. C# parece un batiburrilo de Java, C++ y alguna funcionalidad adicional como los <code>delegates</code> que más que ser un lenguaje nuevo es lo mismo de siempre con otro nombre. Y propietario, claro.</p>
<p>Y, bueno, de la compilación a código intermedio en lugar de a código máquina directamente ya no hablamos. Eso es una decisión que han tomado pero que tampoco es que importe demasiado. Recordemos que esta generación de código es una de las fases de compilación que se puede cambiar sin afectar a la sintaxis.</p>
<p>Concluyendo, a mi, personalmente, no me convence en absoluto. Pero claro, si quieres hacer un proyecto decente para sistemas Windows, no queda otra que hacerlo en C# o pelearte con los punteros en C++.</p>
<p>O usar <a href="http://es.wikipedia.org/wiki/Pascal_(lenguaje_de_programaci%C3%B3n)">Pascal</a> <img src='http://beosman.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  .</p>
<p class="postdata">
<abbr title="Postdata">P.D.</abbr>: Yo, en realidad, soy más del <a href="http://www.d-programming-language.org">lenguaje de programación D</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://beosman.org/archivo/2011/informatica/c-sharp.html/feed</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Representar un número en binario en C++</title>
		<link>http://beosman.org/archivo/2011/informatica/representar-un-numero-en-binario-en-cpp.html</link>
		<comments>http://beosman.org/archivo/2011/informatica/representar-un-numero-en-binario-en-cpp.html#comments</comments>
		<pubDate>Wed, 16 Nov 2011 19:01:20 +0000</pubDate>
		<dc:creator>Diego</dc:creator>
				<category><![CDATA[Informática]]></category>
		<category><![CDATA[Lenguajes]]></category>

		<guid isPermaLink="false">http://beosman.org/?p=5247</guid>
		<description><![CDATA[Puede que alguna vez en tu vida como desarrollador de software te veas en la necesidad de representar números en su forma binaria. Hay infinidad de algoritmos para ello, por eso no me voy a enrollar mucho. Aquí te muestro tres en C++: La forma sencilla e intuitiva template &#60;typename T&#62; char* ValueToBits(T value) { [...]]]></description>
			<content:encoded><![CDATA[<p>Puede que alguna vez en tu vida como desarrollador de software te veas en la necesidad de representar números en su forma binaria. Hay infinidad de algoritmos para ello, por eso no me voy a enrollar mucho. Aquí te muestro tres en <a href="http://es.wikipedia.org/wiki/C%2B%2B">C++</a>:</p>
<h3>La forma sencilla e intuitiva</h3>
<pre>
template &lt;typename T&gt;
char*
ValueToBits(T value) {
	int length = sizeof(T)*8;
	char* result = new char[length];
	result[length] = '\0';
	for(int i = 0; i &lt; length; i++) {
		result[length-1-i] = (value &#038; (1 &lt;&lt; i) ? '1' : '0');
	}
	return result;
}
</pre>
<p>Este algoritmo es fácilmente adaptable a <a href="http://es.wikipedia.org/wiki/C_(lenguaje_de_programaci%C3%B3n)">C estándar</a>. Basta con quitar la plantilla, sobrecargar esta función con más versiones, una por cada tipo de dato que se quiera convertir, y usar <code><a href="http://en.wikipedia.org/wiki/C_dynamic_memory_allocation">malloc()</a></code> en lugar de <code>new</code>. Y, por supuesto, no hay que olvidarse de liberar la memoria del valor devuelto, o bien con <code>delete[]</code> si usas <code>new</code>, o bien con <code>free()</code> si usas <code>malloc()</code>.</p>
<h3>Usando <code>std::string</code>s</h3>
<p>Este algoritmo es similar al anterior pero usando <code>std::string</code>s, con lo que evitamos el uso de <code>char*</code> y la reserva manual de memoria.</p>
<pre>
#include &lt;string&gt;

using std::string;

template &lt;typename T&gt;
const string
ValueToBits(T value) {
	string result;
	for(int i = 0; i &lt; sizeof(T)*8; i++) {
		result = (value &#038; (1 &lt;&lt; i) ? "1" : "0") + result;
	}
	return result;
}
</pre>
<h3>La forma elegante</h3>
<p>Y ya que estamos en C++, ¿por qué no usar toda la potencia que nos proporciona la <abbr title="Standard Template Library" lang="en"><a href="http://en.wikipedia.org/wiki/Standard_Template_Library">STL</a></abbr>?</p>
<pre>
#include &lt;bitset&gt;

using std::bitset;

template &lt;typename T&gt;
const string
ValueToBits(T value) {
	return bitset&lt;sizeof(T)*8&gt;(value).to_string();
}
</pre>
<p>No me digáis que esta forma no es <strong>muy</strong> elegante <img src='http://beosman.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://beosman.org/archivo/2011/informatica/representar-un-numero-en-binario-en-cpp.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>¿Qué significan los iconos de inicio de HaikuOS?</title>
		<link>http://beosman.org/archivo/2011/informatica/que-significan-los-iconos-de-inicio-de-haikuos.html</link>
		<comments>http://beosman.org/archivo/2011/informatica/que-significan-los-iconos-de-inicio-de-haikuos.html#comments</comments>
		<pubDate>Fri, 11 Nov 2011 15:03:23 +0000</pubDate>
		<dc:creator>Diego</dc:creator>
				<category><![CDATA[Informática]]></category>
		<category><![CDATA[Sistemas Operativos]]></category>

		<guid isPermaLink="false">http://beosman.org/?p=5207</guid>
		<description><![CDATA[Cuando se inicia el sistema operativo Haiku se presentan una serie de iconos para indicar en qué estado del inicio nos encontramos. Estos iconos significan lo siguiente: Inicializa los módulos del kernel. Monta el sistema de archivos principal en / (rootfs) y monta el sistema de archivos de los dispositivos en /dev (devfs). Inicializa el [...]]]></description>
			<content:encoded><![CDATA[<p class="aligncenter">
<img class="image" src="/uploads/2011/11/haiku-boot-icons.png" alt="Iconos de inicio de HaikuOS" title="Iconos de inicio de HaikuOS" width="650" height="154" />
</p>
<p>Cuando se inicia el <a href="http://haiku-os.org">sistema operativo Haiku</a> se presentan una serie de iconos para indicar en qué estado del inicio nos encontramos. Estos iconos significan lo siguiente:</p>
<ul style="list-style-type: none;list-style-image: none;">
<li style="overflow:auto;"><img style="margin:0 5px 5px 0;" class="floatleft" src="/uploads/2011/11/haiku-boot-atom.png" alt="Haiku boot: Atom" title="Haiku boot: Atom" width="40" height="40" /> Inicializa los módulos del kernel.</li>
<li style="overflow:auto;"><img style="margin:0 5px 5px 0;" class="floatleft" src="/uploads/2011/11/haiku-boot-disk-glass.png" alt="Haiku boot: Disk with magnifier glass" title="Haiku boot: Disk with magnifier glass" width="40" height="40" /> Monta el sistema de archivos principal en <code>/</code> (<code>rootfs</code>) y monta el sistema de archivos de los dispositivos en <code>/dev</code> (<code>devfs</code>).</li>
<li style="overflow:auto;"><img style="margin:0 5px 5px 0;" class="floatleft" src="/uploads/2011/11/haiku-boot-plug-in-card.png" alt="Haiku boot: Plug-in card" title="Haiku boot: Plug-in card" width="40" height="40" /> Inicializa el gestor de dispositivos.</li>
<li style="overflow:auto;"><img style="margin:0 5px 5px 0;" class="floatleft" src="/uploads/2011/11/haiku-boot-disk-leaf.png" alt="Haiku boot: Disk with leaf" title="Haiku boot: Disk with leaf" width="40" height="40" /> Monta el disco del sistema (<code>/boot</code>).</li>
<li style="overflow:auto;"><img style="margin:0 5px 5px 0;" class="floatleft" src="/uploads/2011/11/haiku-boot-chip.png" alt="Haiku boot: Chip" title="Haiku boot: Chip" width="40" height="40" /> Activa los módulos para controlar las características específicas de la CPU.</li>
<li style="overflow:auto;"><img style="margin:0 5px 5px 0;" class="floatleft" src="/uploads/2011/11/haiku-boot-folder.png" alt="Haiku boot: Folder" title="Haiku boot: Folder" width="40" height="40" /> Finalización del inicio de los subsistemas (que cargan módulos del disco principal en <code>/boot</code>).</li>
<li style="overflow:auto;"><img style="margin:0 5px 5px 0;" class="floatleft" src="http://beosman.org/uploads/2011/11/haiku-boot-rocket.png" alt="Haiku boot: Rocket" title="Haiku boot: Rocket" width="40" height="40" /> Carga en memoria e inicia el <em>script</em> (<code>BootScript</code>) que carga los servidores de inicio como el <code>app_server</code> o el <code>input_server</code>.</li>
</ul>
<p>En una máquina virtual con <a href="http://es.wikipedia.org/wiki/VirtualBox">VirtualBox</a> (en un equipo moderno, todo hay que decirlo) tarda algo menos de 10 segundos en iniciar el sistema. Supongo que en hardware real tardará menos <img src='http://beosman.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://beosman.org/archivo/2011/informatica/que-significan-los-iconos-de-inicio-de-haikuos.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Las tres leyes del software</title>
		<link>http://beosman.org/archivo/2011/citas/las-tres-leyes-del-software.html</link>
		<comments>http://beosman.org/archivo/2011/citas/las-tres-leyes-del-software.html#comments</comments>
		<pubDate>Mon, 07 Nov 2011 19:07:25 +0000</pubDate>
		<dc:creator>Diego</dc:creator>
				<category><![CDATA[Citas y frases]]></category>
		<category><![CDATA[Humor]]></category>
		<category><![CDATA[Informática]]></category>

		<guid isPermaLink="false">http://beosman.org/?p=5180</guid>
		<description><![CDATA[Ningún programa se arrancará sin ser necesario y sin ser requerido por el usuario. Ningún programa recopilará, enviará o buscará datos por la jeta, sin ser parte de una tarea solicitada por el usuario. Todo programa (o componente de software) debe poder desinstalarse sin dejar rastro a la voz de ya. Propuestas por Supermon, como [...]]]></description>
			<content:encoded><![CDATA[<blockquote class="small">
<ol>
<li>Ningún programa se arrancará sin ser necesario y sin ser requerido por el usuario.</li>
<li>Ningún programa recopilará, enviará o buscará datos por la jeta, sin ser parte de una tarea solicitada por el usuario.</li>
<li>Todo programa (o componente de software) debe poder desinstalarse sin dejar rastro a la voz de ya.</li>
</ol>
</blockquote>
<p class="alignright">
<a href="http://halondisparado.com/?p=3874">Propuestas por Supermon</a>, como homólogas a <a href="/archivo/2010/citas/las-tres-leyes-de-la-robotica.html">las tres leyes de la robótica</a>, en <a href="http://halondisparado.com">Halón Disparado</a>.
</p>
<p class="alignright">
Y con las que estoy totalmente de acuerdo. Además, se podría añadir la de <em>«Todo programa será software libre y su código liberado»</em>, <a href="http://www.meneame.net/story/pardillo-de-asimov/00011">como comentan en Menéame</a>, aunque esa quizás ya sería para nota <img src='http://beosman.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://beosman.org/archivo/2011/citas/las-tres-leyes-del-software.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hal o Win</title>
		<link>http://beosman.org/archivo/2011/informatica/hal-o-win.html</link>
		<comments>http://beosman.org/archivo/2011/informatica/hal-o-win.html#comments</comments>
		<pubDate>Mon, 31 Oct 2011 13:20:01 +0000</pubDate>
		<dc:creator>Diego</dc:creator>
				<category><![CDATA[Geek/Friki]]></category>
		<category><![CDATA[Humor]]></category>
		<category><![CDATA[Informática]]></category>

		<guid isPermaLink="false">http://beosman.org/?p=5151</guid>
		<description><![CDATA[Hoy es Halloween; y qué mejor que esta imagen que nada tiene que ver con ello pero que tiene un juego de palabras de los mejores que he visto últimamente. Grande, muy grande. Desde Neoon. P.D.: Por cierto, la fiesta de Halloween es una fiesta que tiene su origen en la fiesta celta del Samhain [...]]]></description>
			<content:encoded><![CDATA[<p class="aligncenter">
<a href="http://www.neoon.es/halowin/"><img class="image" src="http://beosman.org/uploads/2011/10/hal_o_win-650x466.jpg" alt="Hal o Win" title="Hal o Win" width="650" height="466" /></a>
</p>
<p>Hoy es <a href="http://es.wikipedia.org/wiki/Halloween"><em>Halloween</em></a>; y qué mejor que esta imagen que nada tiene que ver con ello pero que tiene un juego de palabras de los mejores que he visto últimamente. Grande, muy grande. <a href="http://www.neoon.es/halowin/">Desde Neoon</a>.</p>
<p class="postdata">
<acronym title="Postdata">P.D.</acronym>: Por cierto, la fiesta de <em>Halloween</em> es una fiesta que tiene su origen en la fiesta celta del <a href="http://es.wikipedia.org/wiki/Samhain">Samhain</a> y en la fiesta cristiana de <a href="http://es.wikipedia.org/wiki/D%C3%ADa_de_todos_los_santos">Todos los Santos</a>. Por si a alguno se le ocurre decir a estas alturas esto de <em>&#8220;yo no celebraré ninguna fiesta traída de EE.UU.&#8221;</em>. Por favor, señores, que cada uno celebre lo que quiera <img src='http://beosman.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://beosman.org/archivo/2011/informatica/hal-o-win.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

