<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><!-- generator="wordpress/2.1.3" --><rss 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:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Roberto M. Oliva</title>
	<link>http://www.robertooliva.com</link>
	<description>The Gold Bug</description>
	<pubDate>Fri, 23 Oct 2009 16:17:35 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.1.3</generator>
	<language>en</language>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/RobertoOliva" /><feedburner:info uri="robertooliva" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:browserFriendly></feedburner:browserFriendly><item>
		<title>En Drupal un administrador de usuarios es superpoderoso</title>
		<link>http://www.robertooliva.com/2009/10/23/en-drupal-un-administrador-de-usuarios-es-superpoderoso/</link>
		<comments>http://www.robertooliva.com/2009/10/23/en-drupal-un-administrador-de-usuarios-es-superpoderoso/#comments</comments>
		<pubDate>Fri, 23 Oct 2009 16:17:35 +0000</pubDate>
		<dc:creator>Roberto M. Oliva</dc:creator>
		
		<category><![CDATA[Drupal]]></category>

		<guid isPermaLink="false">http://www.robertooliva.com/2009/10/23/en-drupal-un-administrador-de-usuarios-es-superpoderoso/</guid>
		<description><![CDATA[En Drupal, inicialmente, hay tres tipos de usuarios: Anónimos, autenticados y el usuario con ID 1. A este usario 1 yo le denomino usuario root por su analogía con el mundo Linux. El usuario con ID 1 tiene, por defecto, permiso para todo. Drupal, cuando comprueba que el ID del usuario es 1, ya no [...]]]></description>
			<content:encoded><![CDATA[<p>En Drupal, inicialmente, hay tres tipos de usuarios: Anónimos, autenticados y el usuario con ID 1. A este usario 1 yo le denomino usuario <em>root</em> por su analogía con el mundo Linux. El usuario con ID 1 tiene, por defecto, permiso para todo. Drupal, cuando comprueba que el ID del usuario es 1, ya no comprueba nada más le concede permiso directamente.</p>
<p>Nosotros montamos una versión personalizada de Drupal. Lo cual, siguiendo con la analogía Linux, lo podríamos considerar como una distribución propia de Drupal. En pocos minutos tenemos una web totalmente configurada y preparada con la funcionalidad establecida para que nuestro cliente se ponga manos a la obra, para él creamos un rol denominado administrador, de tal manera que introducimos un nuevo tipo de usuario entre medias. Él no accede a Drupal, accede directamente a un gestor de contenidos donde mantener y categorizar noticias, enlaces imágenes, etc&#8230; y usuarios! y aquí es donde aparece la discordia.</p>
<p>Un administrador de una de estas webs tiene que poder administrar usuarios y al administrar usuarios lo hace también del usuario <em>root</em> 8/. Por lo que puede, perfectamente, cambiarle la contraseña y acceder como él. Existen muchos comentarios sobre este asunto (<a href="http://drupal.org/node/39636">Security: The &#8220;administer users&#8221; permission exposes user/1</a>), pero para mí claramente es una brecha de seguridad. El usuario <em>root</em> debería de estar por encima de cualquier administrador y nadie (y menos un &#8220;simple&#8221; administrador de usuarios) debería de poder modificar sus datos.</p>
<p>Por otro lado, evidentemente, esto es software libre (nunca daremos suficientes gracias a la comunidad que hay detrás) y podemos modificarlo a nuestro gusto. No es que me guste modificar el <em>core</em> de Drupal, de hecho es una de las mejores características de Drupal: no es necesario tocar el núcleo para conseguir la funcionalidad buscada, basta con añadir los módulos necesarios. Pero en este caso no hay más remedio y, teniendo en cuenta que mi prioridad es modificar lo menos posible, implementé la siguiente modificación (<a href="http://api.drupal.org/api/function/user_save/6">modules/user/user.module</a>):</p>
<pre class="brush: php">
&lt; ?php
function user_save($account, $array = array(), $category = &#039;account&#039;) {
  global $user;
  if($account-&gt;uid==1 &amp;&amp; $user-&gt;uid != 1) {
     drupal_set_message(t(&quot;Only root user can change its user information&quot;), &quot;error&quot;);
     return user_load($account-&gt;uid);
  }

  // Dynamically compose a SQL query:
  $user_fields = user_fields();
   ...
}
</pre>
<p>Reconozco que no es muy elegante, pero cumple su función: Por mucho que asigne administración de usuarios a cualquier usuario ninguno podrá acceder como root al sitio y, además modifico mínimamente el core de Drupal.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.robertooliva.com/2009/10/23/en-drupal-un-administrador-de-usuarios-es-superpoderoso/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Un WTF para variar</title>
		<link>http://www.robertooliva.com/2009/08/24/un-wtf-para-variar/</link>
		<comments>http://www.robertooliva.com/2009/08/24/un-wtf-para-variar/#comments</comments>
		<pubDate>Sun, 23 Aug 2009 23:42:30 +0000</pubDate>
		<dc:creator>Roberto M. Oliva</dc:creator>
		
		<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://www.robertooliva.com/2009/08/24/un-wtf-para-variar/</guid>
		<description><![CDATA[Os pongo aquí un WTF que encontré personalmente en un centro Carrefour (no voy a poner cual de ellos). Tiene ya tiempo, porque lo vi en enero de este 2009, pero me la he encontrado haciendo limpieza de fotos y he pensado que merecería la pena ponerla aquí:

]]></description>
			<content:encoded><![CDATA[<p>Os pongo aquí un WTF que encontré personalmente en un centro <a href="http://www.carrefour.es">Carrefour</a> (no voy a poner cual de ellos). Tiene ya tiempo, porque lo vi en enero de este 2009, pero me la he encontrado haciendo limpieza de fotos y he pensado que merecería la pena ponerla aquí:</p>
<p><img src="http://www.robertooliva.com/images/02012009.jpg" alt="Un WTF en Carrefour" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.robertooliva.com/2009/08/24/un-wtf-para-variar/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Testeo paranóico de JSON con Cucumber</title>
		<link>http://www.robertooliva.com/2009/07/30/testeo-paranoico-de-json-con-cucumber/</link>
		<comments>http://www.robertooliva.com/2009/07/30/testeo-paranoico-de-json-con-cucumber/#comments</comments>
		<pubDate>Thu, 30 Jul 2009 16:18:11 +0000</pubDate>
		<dc:creator>Roberto M. Oliva</dc:creator>
		
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.robertooliva.com/2009/07/30/testeo-paranoico-de-json-con-cucumber/</guid>
		<description><![CDATA[Estoy aprendiendo Cucumber y se que no esta pensado directamente para lo que aquí voy a exponer pero me resultó muy gratificante ver como de una manera muy sencilla se puede testear cualquier JSON devuelto por nuestros servicios REST. Se puede testear, con una sintáxis muy efectiva y clara hasta la última entrada de datos. [...]]]></description>
			<content:encoded><![CDATA[<p>Estoy aprendiendo <a href="http://github.com/aslakhellesoy/cucumber/tree/master">Cucumber</a> y se que no esta pensado directamente para lo que aquí voy a exponer pero me resultó muy gratificante ver como de una manera muy sencilla se puede testear cualquier <a href="http://en.wikipedia.org/wiki/Json">JSON</a> devuelto por nuestros servicios <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">REST</a>. Se puede testear, con una sintáxis muy efectiva y clara hasta la última entrada de datos. </p>
<p>Por ejemplo, de manera muy sencilla, quiero testear un servicio que me devuelve una lista de registros de una tabla denominada <em>&#8216;datos&#8217;</em> que contiene dos campos:<em> &#8216;id&#8217; </em>y <em>&#8216;nombre&#8217;</em>. Si metemos dos registros el servicio REST de listarlos nos va a devolver un JSON como el siguiente:</p>
<pre class="brush: javascript">
[
{datos:{nombre:&quot;Prueba1&quot;,id:&quot;1&quot;},
{datos:{nombre:&quot;Prueba2&quot;,id:&quot;2&quot;},
]
</pre>
<p>No tiene mucho misterio, es un array con dos elementos. Pero lo que sí es sorprendente, si nos lo montamos bien, es lo claro que puede llegar a ser la definición de la <em>feature</em> de Cucumber:</p>
<pre class="brush: sh">
	Scenario: Listing elements of type Datos
		Given a data with name &quot;Prueba1&quot;
		And a data with name &quot;Prueba2&quot;
		When I list &quot;datos&quot;
		Given the json reponse
			Then the json must contain &quot;2&quot; elements
			Given the &quot;1&quot; element of the json array
				Then the json element should contain the &quot;datos&quot; key
				Given the &quot;datos&quot; key of the json hash
					Then the json element should contain the keys: &quot;id, nombre&quot;
					And the json element should contain the key &quot;id&quot; with value &quot;1&quot;
					And the json element should contain the key &quot;nombre&quot; with value &quot;Prueba1&quot;
		Given the json reponse
			And the &quot;2&quot; element of the json array
				Then the json element should contain the &quot;datos&quot; key
				Given the &quot;datos&quot; key of the json hash
					Then the json element should contain the keys: &quot;id, nombre&quot;
					And the json element should contain the key &quot;id&quot; with value &quot;2&quot;
					And the json element should contain the key &quot;nombre&quot; with value &quot;Prueba2&quot;
</pre>
<p>Lo único que se puede advertir aquí es que no tiene mucho sentido testear los id&#8217;s ya que van a cambiar seguro de testeo a testeo, pero lo dejo como ejemplo de que se pueden testear más campos.<br />
Como se ve queda un <em>feature</em> totalmente legible y que testea completamente el JSON devuelto.</p>
<p>La clave de todo esto está en los <em>steps</em> definidos para testear el JSON. De manera genérica un JSON contiene sólo arrays y hashes. Los primeros contienen elementos y los segundos claves de elementos. Los elementos a su vez pueden ser arrays o hashes también y así indefinidamente. Por lo tanto los pasos se reducen a:<br />
- Seleccionar un elemento de un array o de un hash.<br />
- Contar cuantos elementos tiene un array o un hash.<br />
- Ver si un hash tiene una clave determinada.<br />
- Ver el valor de la clave del hash.</p>
<p>Un ejemplo de dichos steps es el código siguiente:</p>
<pre class="brush: ruby">
Given /^the json reponse$/ do
  @json_sel_element = ActiveSupport::JSON.decode(@response.body)
end

Given /^the &quot;([^&quot;]*)&quot; key of the json hash$/ do |key|
  @json_sel_element = @json_sel_element[key]
end

Then /^the json must contain &quot;([^&quot;]*)&quot; elements$/ do |num_elements|
  @json_sel_element.size.should == num_elements.to_i
end

Given /^the &quot;([^&quot;]*)&quot; element of the json array$/ do |num_element|
  @json_sel_element = @json_sel_element[num_element.to_i-1]
end

Then /^the json element should contain the &quot;([^&quot;]*)&quot; key$/ do |key|
  @json_sel_element.keys.should include(key)
end

Then /^the json element should contain the key &quot;([^&quot;]*)&quot; with value &quot;([^&quot;]*)&quot;$/ do |key, value|
  @json_sel_element[key].should == value
end

Then /^the json element should contain the key &quot;([^&quot;]*)&quot; with a null value$/ do |key|
  @json_sel_element[key].should be_nil
end

Then /^the json element should contain the key &quot;([^&quot;]*)&quot; with a not null value$/ do |key|
  @json_sel_element[key].should_not be_nil
end

Then /^the json element should contain the keys: &quot;([^&quot;]*)&quot;$/ do |keys|
  k = keys.split(&quot;,&quot;)
  k.each do |key|
    And %{the json element should contain the &quot;#{key.strip}&quot; key}
  end
end
</pre>
<p>Al final he escrito esto un poco rápido (me cuesta encontrar un hueco) lo remataré en breve. Pero para abrir boca no está nada mal&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.robertooliva.com/2009/07/30/testeo-paranoico-de-json-con-cucumber/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Document-oriented Databases</title>
		<link>http://www.robertooliva.com/2009/07/09/document-oriented-databases/</link>
		<comments>http://www.robertooliva.com/2009/07/09/document-oriented-databases/#comments</comments>
		<pubDate>Thu, 09 Jul 2009 15:21:03 +0000</pubDate>
		<dc:creator>Roberto M. Oliva</dc:creator>
		
		<category><![CDATA[Document-oriented Databases]]></category>

		<guid isPermaLink="false">http://www.robertooliva.com/2009/07/09/document-oriented-databases/</guid>
		<description><![CDATA[Voy a empezar a escribir esta entrada y no la voy a terminar, en breve, ya que la voy a utilizar como herramienta de investigación e irá creciendo a la par que voy adentrándome en el mundo de los Document-oriented Database.
Las Document-oriented Databases suponen un enfoque distinto de almacenamiento de datos al que proponen las [...]]]></description>
			<content:encoded><![CDATA[<p>Voy a empezar a escribir esta entrada y no la voy a terminar, en breve, ya que la voy a utilizar como herramienta de investigación e irá creciendo a la par que voy adentrándome en el mundo de los Document-oriented Database.</p>
<p>Las Document-oriented Databases suponen un enfoque distinto de almacenamiento de datos al que proponen las tradicionales <a href="http://es.wikipedia.org/wiki/Sistema_administrador_de_bases_de_datos_relacionales">RDBMS</a> (Relational Data Base Management System). No pretenden suplantar a éstas, sino más bien presentar una solución diferente a una serie de problemas comunes en el tratamiento de datos como puedan ser los cambios constantes de estructura, la tolerancia a fallos o la clusterización, por decir algunos.</p>
<p>Las diferencias básicas entre ambos tipos de bases de datos se pueden ver en la siguiente tabla (Obtenida de <a href="http://damienkatznet.net/files/What_is_CouchDB.pdf">What_is_Couch</a>):</p>
<p>SQL -> CouchDB<br />
Esquema explícito predefinido -> Esquema implícito dinámico<br />
Tablas de datos uniformes  -> Coleccion de documentos con estructura variable<br />
Normalizado. Los objetos se expanden en varias tablas. Dulicacioón reducida -> Desnormalizado. Los documentos se autocontienen. Los datos suelen estar duplicados.<br />
Se debe de conocer el esquema antes de escribir o leer un objeto completo -> Solo es necesario conocer el nombre del documento.<br />
Consultas dinámicas de esquemas estáticos -> Consultas estáticas de esquemas dinámicos.</p>
<p>Me ha gustado mucho el siguiente enlace: <a href="http://www.readwriteweb.com/enterprise/2009/02/is-the-relational-database-doomed.php">Is the Relational Database Doomed?</a>. En él, el autor, expone los siguientes apuntes:<br />
- Las bases de datos RDBMS han cumplido de manera eficaz las mayor parte de las necesidades de las aplicaciones. Simplicidad, seguridad, flexibilidad, rendimiento, escalabilidad y compatibilidad han sido sus vritudes generales, siendo algunas mejores en algunos puntos que en otros. Lo que ha ocurrido es que, a día de hoy, una de estas necesidades ha adquirido un protagonismo mucho más critico que el de todas las demás. Concretamente el de la escalabilidad.<br />
- Los beneficios principales de una base de datos orientada a documento son los siguientes: Muy adecuado para funcionar en la nube y encaja de una manera más natural con el código.<br />
- Por contra, los inconvenientes son los siguientes: El modelado del código no recae en la base de datos, sino en la aplicación (capa de negocios) y limitaciones en las consultas.<br />
- Por último, recomienda usar estas bases de datos cuando: Los datos estén muy orientados a documento (obviamente), el entorno de desarrollo sea muy orientado a objetos, el almacen de datos sea &#8220;barato&#8221; y este bien integrado en el servicio de hosting y, por último, que la mayor preocupación se centre en ofrecer una aplicación altamente disponible y con gran velocidad de acceso a datos.</p>
<p>También es interesante la comparación de herramientas que realiza la siguiente entrada: <a href="http://www.metabrew.com/article/anti-rdbms-a-list-of-distributed-key-value-stores/">Anti-RDBMS: A list of distributed key-value stores</a>. Aparte de que la introducción es graciosa (pero con sustancia). Motivos por los cuales elegir una base de datos orientada a documento:<br />
   1. Sufres de Aplicación-en-la-nubemanía.<br />
   2. Necesitas una excusa para utilizar <a href="http://www.google.es/url?sa=t&#038;source=web&#038;ct=res&#038;cd=2&#038;url=http%3A%2F%2Fes.wikipedia.org%2Fwiki%2FErlang&#038;ei=ywVWSrydGMbs-AbCmKi-Dw&#038;usg=AFQjCNGqh6PRiPFIJ0FG46vaGLzbvgvaHQ&#038;sig2=vnWNx0-lRnbuN_mSeOfsyw">Erlang</a> (Varias de estas DB&#8217;s están desarrolladas utilizando Erlang).<br />
   3. Has oido que CouchDB mola.<br />
   4. Odias MySQL y, aunque PostgreSQL está mucho mejor, no tiene ningún mecanismo de replicación decente y no hay posibilidad de comprar las licencias de Oracle.<br />
   5. Tus datos se almacenan y se obtienen, casi siempre, a través de su clave primaria y sin utilizar consultas complejas.<br />
   6. Tienes una cantidad de datos nada trivial y te da miedo manejar estructuras de RDBMS con sistemas de replicación y tolerancia a fallos.</p>
<p>Garcias a estas dos páginas y a alguna más, he encontrado la siguiente lista de bases de datos orientadas a documentos:</p>
<p><a href="http://code.google.com/p/thrudb/">ThruDB</a><br />
<a href="http://project-voldemort.com/">Project Volemort</a><br />
<a href="http://monetdb.cwi.nl/">MonetDB</a><br />
<a href="http://www.openneptune.com/">Neptune</a><br />
<a href="http://code.google.com/p/redis/">Redis</a><br />
<a href="http://tokyocabinet.sourceforge.net/tyrantdoc/">Tokyo Tyran</a> + <a href="http://tokyocabinet.sourceforge.net/">Tokyo Cabinet</a><br />
<a href="http://hadoop.apache.org/hbase/">HBase</a><br />
<a href="http://github.com/cliffmoon/dynomite/tree/master">Dynomite</a><br />
<a href="http://code.google.com/p/scalaris/">Scalaris</a><br />
<a href="http://github.com/tuulos/ringo/tree/master">Ringo</a><br />
<a href="http://couchdb.apache.org/">CouchDB</a><br />
<a href="http://www.mongodb.org/display/DOCS/Home">MongoDB</a><br />
<a href="http://code.google.com/p/the-cassandra-project/">Cassandra</a></p>
<p>También ha bvisto otros sistemas de BD&#8217;s a tener en cuenta:<br />
<a href="http://virtuoso.openlinksw.com/">Virtuoso</a><br />
<a href="http://en.wikipedia.org/wiki/Zope_Object_Database">Zope Object Database</a><br />
<a href="http://code.google.com/p/schemafree/">Schemafree (MySQL Addon)</a><br />
<a href="http://neo4j.org/">neo4j</a><br />
<a href="http://www.vertica.com/">Vertica</a><br />
<a href="https://launchpad.net/drizzle">Drizzle</a></p>
<p>Como primer resúmen (dado desde la visión superficial que tengo actualmente) se podría decir que si las necesidades de la aplicación pasan por ser muy rápida y muy escalable (considerando si se va a trabajar con ingentes cantidades de registros) y si la estructura va a variar bastante a costa de necesitar una mayor inversión en desarrollo del modelo (aquí me gustaría incidir en que, si los testeos ya de por si son importantes, aquí lo son más aún) este tipo de bases de datos es una muy buena opción. Lo que esta claro es que cada tipo de base de datos tiene su lugar y hay que aprender a diferencia cuando conviene un tipo sobre otro.</p>
<p>A través de este blog y, siempre que el tiempo me lo permita, iré añadiendo datos sobre mis pesquisas sobre este mundo que está resurgiendo poco a poco y que es, cuando menos, bastante interesante.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.robertooliva.com/2009/07/09/document-oriented-databases/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Sobreescribir menu links del core de Drupal 6</title>
		<link>http://www.robertooliva.com/2009/02/26/sobreescribir-menu-links-del-core-de-drupal-6/</link>
		<comments>http://www.robertooliva.com/2009/02/26/sobreescribir-menu-links-del-core-de-drupal-6/#comments</comments>
		<pubDate>Thu, 26 Feb 2009 20:19:33 +0000</pubDate>
		<dc:creator>Roberto M. Oliva</dc:creator>
		
		<category><![CDATA[Drupal]]></category>

		<guid isPermaLink="false">http://www.robertooliva.com/2009/02/26/sobreescribir-menu-links-del-core-de-drupal-6/</guid>
		<description><![CDATA[Esto es más un apunte para que no se me olvide la próxima vez. Si además le viene bien a alguien, pues mejor  
Cuando creamos un módulo podemos hacer que atienda él mismo las peticiones que se harían al core si no estuviese. Dicho de otra manera: Nuestro módulo va a interceptar ciertas llamadas [...]]]></description>
			<content:encoded><![CDATA[<p>Esto es más un apunte para que no se me olvide la próxima vez. Si además le viene bien a alguien, pues mejor <img src='http://www.robertooliva.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Cuando creamos un módulo podemos hacer que atienda él mismo las peticiones que se harían al <em>core</em> si no estuviese. Dicho de otra manera: Nuestro módulo va a interceptar ciertas llamadas que se harían al <em>core</em> de Drupal para proporcionar un comportamiento diferente al de por defecto y no romper el sistema de enlaces propuesto por Drupal. </p>
<p>Por ejemplo, he desarrollado un modulo que muestra los elementos de una taxonomía de manera distinta a como lo hace Drupal. Para ello hemos redigido la llamada de menú: <em>taxonomy/term/%</em> (atendida por el <em>core</em> en el modulo <em>Taxomony</em>) a una función de nuestro módulo.</p>
<p>Al motor de enlaces le va a llegar dos entradas de menu que tienen la misma url, pero que apuntan a dos funciones distintas. Cómo hace Drupal para escoger la que va a atender? Pues muy sencillo, por el peso del módulo que atiende a las peticiones. </p>
<p>Todos los módulos se instalan con un peso por defecto, si a nuestro módulo le ponemos un peso mayor que el del módulo <em>Taxonomy</em> del core (la lista de llamadas se hace sobreescribiendo las anteriores y <strong>Drupal recorre los modulos, al generar el menú, de menor a mayor peso</strong>) la sobreescribirá con la entrada de menu de nuestro módulo.</p>
<p>Para cambiar el peso de un módulo, basta con actualizar el valor del campo <em>weight</em> de la table <em>{system}</em> de la base de datos de nuestro sitio. Para más información: <a href="http://drupal.org/node/110238">How to update a module&#8217;s weight</a>.</p>
<p>Por último recordar que el menú del sitio se encuentra cacheado en la base de datos. No basta con actualizar nuestro código para que queden disponibles los enlaces implementados en nuestro módulo. Hay que recargar la tabla <em>{menu_links}</em>. Esto es facil de hacer guardando la lista de módulos del sitio, sin tocar nada.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.robertooliva.com/2009/02/26/sobreescribir-menu-links-del-core-de-drupal-6/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Otra manera de calcular la media ponderada en Ruby</title>
		<link>http://www.robertooliva.com/2009/02/16/otra-manera-de-calcular-la-media-ponderada-en-ruby/</link>
		<comments>http://www.robertooliva.com/2009/02/16/otra-manera-de-calcular-la-media-ponderada-en-ruby/#comments</comments>
		<pubDate>Mon, 16 Feb 2009 15:30:48 +0000</pubDate>
		<dc:creator>Roberto M. Oliva</dc:creator>
		
		<category><![CDATA[Personal]]></category>

		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.robertooliva.com/2009/02/16/otra-manera-de-calcular-la-media-ponderada-en-ruby/</guid>
		<description><![CDATA[Esto que escribo es un poco chorra, lo sé, pero llevo tanto tiempo sin escribir que me parece que puede ser gracioso poner esto aquí.
Hoy me he enfrentado al &#8220;terrible y dificil&#8221; reto de calcular una media ponderada de datos, más concretamente las notas de los alumnos en una asignatura.
Partimos de tener un hash en [...]]]></description>
			<content:encoded><![CDATA[<p>Esto que escribo es un poco chorra, lo sé, pero llevo tanto tiempo sin escribir que me parece que puede ser gracioso poner esto aquí.<br />
Hoy me he enfrentado al &#8220;terrible y dificil&#8221; reto de calcular una <a href="http://es.wikipedia.org/wiki/Media_ponderada">media ponderada</a> de datos, más concretamente las notas de los alumnos en una asignatura.<br />
Partimos de tener un hash en el que se define, para cada nota, los alumnos que la han obtenido. Por ejemplo (No han sacado muy buenas notas, la verdad):</p>
<p><code>{4.0=>7, 3.0=>3, 6.0=>3, 9.0=>1, 7.0=>5, 10.0=>1, 5.0=>2, 2.0=>2, 8.0=>1}</code></p>
<p>Según la definición del calculo, deberíamos acumular, por un lado, la nota multiplicada por el número de alumnos que la han obtenido y por otro el número de alumnos totales que han cursado la asignatura.<br />
Una manera estándar de hacer esto seria:</p>
<p><code><br />
total_peso = hash.inject(0){|result, e| result += e[0]*e[1]}<br />
total_alumnos = hash.inject(0){|result, e| result += e[1]}<br />
media = total_peso/total_alumnos<br />
</code></p>
<p>Hay que reconocer que ruby tiene cosas muy interesantes y que, usadas con imaginación, pueden ayudarnos a mejorar mucho el código. Y una de ellas, que es la que comento aqui, es la posibilidad de multiplicar un array por un valor. Si a cada elemento del hash multiplicamos la nota convertida en array por el número de alumnos que han obtenido esa nota obtendremos un array con todas las notas de todos los alumnos. A partir de ahí basta aplicar el método <em>avg</em> del Array para que Ruby calcule la media. Esto es lo mismo que antes, pero reduciendo enormemente el código:</p>
<p><code><br />
 hash.map{|k,v| [k] * v}.flatten.avg<br />
</code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.robertooliva.com/2009/02/16/otra-manera-de-calcular-la-media-ponderada-en-ruby/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Hook_theme en Drupal 6</title>
		<link>http://www.robertooliva.com/2008/10/10/hook_theme-en-drupal-6/</link>
		<comments>http://www.robertooliva.com/2008/10/10/hook_theme-en-drupal-6/#comments</comments>
		<pubDate>Fri, 10 Oct 2008 12:42:27 +0000</pubDate>
		<dc:creator>Roberto M. Oliva</dc:creator>
		
		<category><![CDATA[Drupal]]></category>

		<guid isPermaLink="false">http://www.robertooliva.com/2008/10/10/hook_theme-en-drupal-6/</guid>
		<description><![CDATA[Estamos empezando el desarrollo de una serie de sitios basados en Drupal 6, por lo que nos hemos puesto a crear temas nuevos y nos hemos encontrado con cosas curiosas. Aquí voy a explicar la que me ha dado más dolores de cabeza en estos días que llevo con Drupal 6 y, si bien, al [...]]]></description>
			<content:encoded><![CDATA[<p>Estamos empezando el desarrollo de una serie de sitios basados en Drupal 6, por lo que nos hemos puesto a crear temas nuevos y nos hemos encontrado con cosas curiosas. Aquí voy a explicar la que me ha dado más dolores de cabeza en estos días que llevo con Drupal 6 y, si bien, al final es algo bastante sencillo, hay que aprenderlo.</p>
<p>Todo parte de la necesidad de renderizar los <em>Primary Links</em> con una plantilla que no sea la estándar. Se puede renderizar con la plantilla <em>links</em>:</p>
<p><code>< ?php  print theme('links', $primary_links ); ?></code></p>
<p>O como menu_tree:</p>
<p><code>< ?php print menu_tree($menu_name = 'primary-links'); ?></code></p>
<p>Y luego trabajar con el CSS, pero queremos ir un poco más allá: queremos definir exactamente el HTML que nos de la gana. Nuestra llamada va a ser:</p>
<p><code>< ?php  print theme('primary_links', $primary_links ); ?></code></p>
<p>Y, aparte, tener definido un fichero de plantilla: <strong>primary_links.tpl.php</strong> donde especificamos el comportamiento de la renderización del array de enlaces.</p>
<p>En Drupal 5 la manera de descubrir plantillas de temas es automática, nos hubiera bastado con tener algo de lo siguiente definido, por orden de importancia:<br />
- Fichero de plantilla (<strong>primary_links.tpl.php</strong>) para que lo hubiera utilizado.<br />
- Funcion propia de tema (<strong>nombretema_primary_links.tpl.php</strong>) dentro del template.php.<br />
- Funcion propia del motor del tema (<strong>phptemplate_primary_links.tpl.php</strong>) dentro del template.php.</p>
<p>En Drupal 6 no es automático. Hay que indicárselo al motor, el cual cacheará las llamadas para hacer el proceso más eficiente.<br />
Habría que implementar la funcion <em>hook_theme</em> dentro del tema (dentro de <em>template.php</em>) o dentro del módulo que necesite el template. Esta funcion debe devolver un array que defina como se comportan cada uno de los temas. Por ejemplo:</p>
<p><code>function nombretema_theme() {<br />
  return array(<br />
    'primary_links' => array(<br />
      'arguments' => array(<br />
        'links' => NULL<br />
      ),<br />
	  'template' => 'primary_links'<br />
    ),<br />
  );<br />
}<br />
</code></p>
<p>Hace básicamente lo que buscamos: Relacionar <em>theme(hook, &#8230;)</em> con el fichero: <em>hook.tml.php</em>.<br />
Pero también podemos definir como queremos que se comporte ese hook, por ejemplo renderizando como una función del tema (comportamiento por defecto):</p>
<p><code><br />
/**<br />
* Implementation of hook_theme().<br />
*/<br />
function maristas_silvia_theme() {<br />
  return array(<br />
    'primary_links' => array(<br />
      'arguments' => array(<br />
        'links' => NULL<br />
      ),<br />
    ),<br />
  );<br />
}</p>
<p>function nombretema_primary_links($links = array()) {<br />
	return "Renderizamos los enlaces primarios"; // Salida de ejemplo<br />
}<br />
</code></p>
<p>En el ejemplo anterior la renderización encargada del hook la realizará una función del <em>template.php</em>.</p>
<p>Por nomenclatura se suele traducir los guiones bajos del nombre del hook (primary_links) a guiones simples al nombre del template asociado (primary-links.tpl.php).</p>
<p>Si se cambia la estructura de los hooks, hay que reiniciar la cache, esto se puede hacer con cualquiera de los siguientes métodos:<br />
- En la página &#8220;Administer > Site configuration > Performance&#8221; hacer click en el botón: &#8220;Clear cached data&#8221;.<br />
- Con el módulo <a href="http://drupal.org/project/devel">devel</a>, hacer clieck en el enlace: &#8220;Empty cache&#8221; link.<br />
- Con la función: <a href="http://api.drupal.org/api/function/drupal_rebuild_theme_registry/6">drupal_rebuild_theme_registry</a> de la API.</p>
<p>Más información en:</p>
<p>- <a href="http://api.drupal.org/api/function/hook_theme/6">hook_theme : Drupal 6 API</a><br />
- <a href="http://drupal.org/theme-guide">Theme guide (Drupal 6)</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.robertooliva.com/2008/10/10/hook_theme-en-drupal-6/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Flex: Atendiendo a la finalizacion de comandos</title>
		<link>http://www.robertooliva.com/2008/07/22/flex-atendiendo-a-la-finalizacion-de-comandos/</link>
		<comments>http://www.robertooliva.com/2008/07/22/flex-atendiendo-a-la-finalizacion-de-comandos/#comments</comments>
		<pubDate>Tue, 22 Jul 2008 13:24:46 +0000</pubDate>
		<dc:creator>Roberto M. Oliva</dc:creator>
		
		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Cairngorm]]></category>

		<guid isPermaLink="false">http://www.robertooliva.com/2008/07/22/flex-atendiendo-a-la-finalizacion-de-comandos/</guid>
		<description><![CDATA[Una dificultad en el desarrollo de clientes en Flex es su carecter totalmente asíncrono.
Nosotros utilizamos Cairngorm  para el desarrollo en Flex y nos suponía un problema añadido el que no hay control sobre la finalización de un comando asíncrono. Hay veces que es necesario realizar una operación concreta nada más haber recibido una serie [...]]]></description>
			<content:encoded><![CDATA[<p>Una dificultad en el desarrollo de clientes en Flex es su carecter totalmente asíncrono.<br />
Nosotros utilizamos <a href="http://www.google.es/url?sa=t&#038;ct=res&#038;cd=3&#038;url=http%3A%2F%2Flabs.adobe.com%2Fwiki%2Findex.php%2FCairngorm&#038;ei=cd2FSKXqJom00gT3i9nhBA&#038;usg=AFQjCNEvKWilkRZ2ICxY1G7-JRNGqvDGqg&#038;sig2=DMkCQt6NHuNBxRTz7qXGxw">Cairngorm</a>  para el desarrollo en Flex y nos suponía un problema añadido el que no hay control sobre la finalización de un comando asíncrono. Hay veces que es necesario realizar una operación concreta nada más haber recibido una serie de datos, por ejemplo. </p>
<p>Esto, dentro de Cairngorm, puede hacerse en la función result del Comando (implementa la interfaz <em>IResponder</em>) que ha lanzado la petición. El problema de esta técnica estriba en que el comando, que es parte del Controlador, no conoce nada acerca de la Vista ni del Modelo. En realidad debería de poder acceder al Modelo, según el patrón MVC.</p>
<p>También se puede hacer utilizando observers que controlan cuando los datos pedidos han sido recibidos y por tanto se puede realizar la operación subsiguiente. Pero complica bastante el código y lo hace muy frágil.</p>
<p>Al final, estamos utilizando una técnica que parece bastante lógica y flexible y, gracias a Dios, es fácil de implementar. La inspiración ha venido a raíz del siguiente enlace: <a href="http://www.thomasburleson.biz/2007/06/cairngorm_view_notifications.html">Cairngorm View Notifications</a>.</p>
<p>Simplemente se basa en pasar al evento un parámetro adicional con la función que será llamada cuando el evento finalice.</p>
<p>La función result pasaría a ser algo así:</p>
<p><code><br />
override public function result(event:Object) : void {<br />
  var eventR : ResultEvent = event as ResultEvent;<br />
  if (_event.function_result != null)<br />
    _event.function_result.call(this, eventR);<br />
}<br />
</code></p>
<p>Me encantan las pequeñas ideas que ofrecen grandes soluciones.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.robertooliva.com/2008/07/22/flex-atendiendo-a-la-finalizacion-de-comandos/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Desplegando Rails</title>
		<link>http://www.robertooliva.com/2008/04/16/desplegando-rails/</link>
		<comments>http://www.robertooliva.com/2008/04/16/desplegando-rails/#comments</comments>
		<pubDate>Wed, 16 Apr 2008 14:27:21 +0000</pubDate>
		<dc:creator>Roberto M. Oliva</dc:creator>
		
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.robertooliva.com/2008/04/16/desplegando-rails/</guid>
		<description><![CDATA[Llevamos  más de año y medio metidos en un mega-proyecto basado en Ruby On Rails. Después de tanto tiempo tenemos una visión muy clara de las ventajas e inconvenientes de utilizar esta plataforma. Ya hay muchos sitios en los que se habla de estas consideraciones y de muchas otras, pero yo quiero exponer aquí [...]]]></description>
			<content:encoded><![CDATA[<p>Llevamos  más de año y medio metidos en un mega-proyecto basado en Ruby On Rails. Después de tanto tiempo tenemos una visión muy clara de las ventajas e inconvenientes de utilizar esta plataforma. Ya hay muchos sitios en los que se habla de estas consideraciones y de muchas otras, pero yo quiero exponer aquí el que probablemente haya sido el mayor problema con el que nos hemos encontrado: El despliegue.</p>
<p>Siguiendo en paralelo esta <a href="http://codemonkey.ravelry.com/2008/03/10/load-balancing/">entrada</a>  hemos pasado por todos las arquitecturas posibles de aplicaciones Rails, bueno nos saltamos el FastCGI:</p>
<ul>
<li>Apache con mod_balancer</li>
<li>Nginx con fair</li>
<li>Mongrel</li>
<li>Thin</li>
</ul>
<p>Muchas, muchas horas invertidas con problemas de estabilidad, rendimiento, conexión a la base de datos defectuosa, etc, etc.<br />
No hemos llegado todavia al paso de implementar HAProxy, aunque todo de andará. Pero con un nginx con fair, un stack de 10 thines y una buena máquina sirviendo el MySql, parece que nos hemos ganado un poco de tranquilidad.</p>
<p>Tenemos en plan crear dos máquinas virtualizadas con un stack de mongreles en cada una y el nginx que balancee a ambas. Esta arquitectura tiene que escalar hasta dos máquinas con cuatro stack de thines virtualizados cada una, lo que nos dará 80 thines dispuestos en paralelo, mejor balanceo de carga y una mayor tolerancia a fallos. Posiblemente tendremos que replicar la base de datos porque seguramente pasaremos el cuello de botella a ese extremo.</p>
<p>Por si sirven los siguientes datos, sacados de varios sitios web, entre ellos el de: <a href="http://brainspl.at/">Ezra Zygmuntowicz</a>. Teniendo en cuenta:<br />
- reqs: Request per second. Son el número de peticiones que se harán por segundo.<br />
- tm: Tiempo medio de respuesta de cada petición.</p>
<p>El número de mongreles necesarios serán: reqs * tm. A su vez, se recomienda 8 mongreles por núcleo de CPU, con esto también nos permite obtener cuantos servidores necesitamos.<br />
Por ejemplo: Si necesitamos servir 100 request por segundo y cada request toma una media de 0,5 segundos en ser enviada, necesitaríamos 50 mongreles. Una máquina QuadCore podría tener 32 mongreles, con lo que necesitaríamos 2 máquinas. Esto sin contar con el consumo de memoria RAM de la máquina. Si un mongrel consume unos 60Mb de RAM, para 32 mongreles necesitaríamos algo menos de 2Gb de RAM en la máquina.</p>
<p>Después de toda esta disquisición, voy a comentar en este y en sucesivos posts un nuevo chico en la ciudad (como se suele decir en inglés), se denomina: <a href="http://www.modrails.com/">Phusion Passenger</a>. Como todos los que comienzan promete todo: Gran velocidad, estabilidad, mucha documentación. Pero esta solución promete algo mejor y es virtual hosting de Rails con configuración cero.</p>
<p>Para desplegar un sitio Rails, aparte de saber programar ;), había que saber desplegar toda la arquitectura, vamos, lo que he comentado antes (nginx, mongreles, etc). Con modrail esto se acaba: Subes los ficheros de la aplicación Rails al directorio que atiende el virtual host y ya está funcionando. </p>
<p>He estado instalándolo en un servidor en el que tenemos varias aplicaciones Rails. La instalación ha sido bastante fácil: Una gema, un script de configuración y unas variables en el <em>apache2.conf</em>. Después de esto y, como por arte de magia, tenemos una aplicación rails corriendo en un virtual host sin tener que preouparnos por los mongreles ni por los balanceos de carga.</p>
<p>Cuando viene algo nuevo, suelo ser bastante excépctico. Todavía queda mucho camino por recorrer: A Ruby (<a href="http://rubini.us/">Rubinius</a> por ejemplo), a Rails y, en este caso, a modrails.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.robertooliva.com/2008/04/16/desplegando-rails/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Retomando…</title>
		<link>http://www.robertooliva.com/2008/04/01/retomando/</link>
		<comments>http://www.robertooliva.com/2008/04/01/retomando/#comments</comments>
		<pubDate>Tue, 01 Apr 2008 13:16:20 +0000</pubDate>
		<dc:creator>Roberto M. Oliva</dc:creator>
		
		<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://www.robertooliva.com/2008/04/01/retomando/</guid>
		<description><![CDATA[Llevo más tiempo sin escribir aquí del que pensaba. Estoy dispuesto a ponerme las pilas de nuevo, porque quiero comprometerme a mantener este blog lo más actualizado posible.
No obstante todo ha sido por un motivo, el de siempre: El trabajo (no me importaría que fuese otro). Pero también he de decir que este blog se [...]]]></description>
			<content:encoded><![CDATA[<p>Llevo más tiempo sin escribir aquí del que pensaba. Estoy dispuesto a ponerme las pilas de nuevo, porque quiero comprometerme a mantener este blog lo más actualizado posible.<br />
No obstante todo ha sido por un motivo, el de siempre: El trabajo (no me importaría que fuese otro). Pero también he de decir que este blog se alimenta del mismo trabajo. Y durante este lapso de tiempo he trabajado mucho y muy intensamente. Sirva de introducción esta entrada de blog a las tecnologías en las que he estado profundamente involucrado estos últimos meses y de las que tengo que dar más cumplida cuenta por aquí:</p>
<p>Por supuesto:<br />
- <a href="http://www.rubyonrails.org/">Ruby on Rails<br />
</a>- <a href="http://www.adobe.com/products/flex/">Adobe Flex</a></p>
<p>Entran en la lista:<br />
- <a href="http://www.drupal.org">Drupal</a>. He montado un gran portal social sobre esta plataforma, lo que me ha dado una gran oportunidad para aprender y valorar sus grandes virtudes, que son muchas.<br />
- <a href="http://extjs.com/">Ext Js. </a>. Mi fuerte no es el javascript, lo reconozco, pero esta librería permite desarrollar interfaces de usuario web muy potentes.<br />
- <a href="http://wiki.codemongers.com/Main">Nginx</a>. Un servidor web ruso, muy liviano y muy rápido.<br />
- <a href="http://code.macournoyer.com/thin/">Thin</a>. Un nuevo servidor de aplicaciones para Ruby on Rails, con bastante mejor respuesta que el Mongrel, pero con la estabilidad como duda.<br />
- <a href="http://en.wikipedia.org/wiki/Memcached">Memcached</a>. Un servidor de cache en memoria.<br />
- <a href="http://www.ja-sig.org/products/cas/">CAS</a>. Una propuesta de Single Sign On.<br />
- <a href="http://openid.net/">OpenID</a>. Un nuevo sistema de autentificación web.<br />
- <a href="http://www.citrixxenserver.com/Pages/default.aspx">Xen</a>. Sistema de virtualización para sistemas Linux.<br />
- <a href="http://www.tildeslash.com/monit/">Monit</a>. Software de monitorización de servicios y recursos sobre Linux.<br />
- <a href="http://en.wikipedia.org/wiki/Action_Message_Format">AMF</a>. Protocolo de intercambio de información entre un servidor y una aplicación ActionScript.<br />
- <a href="http://merbivore.com/">Merb</a>. Un framework de desarrollo web, similar a Rails, pero más orientado a rendimiento.<br />
- <a href="http://www.microsoft.com/sharepoint/default.mspx">Microsoft Sharepoint</a>. Hay que reconocer que es el mejor software para Intranet disponible actualmente.</p>
<p>Fuera del trabajo:<br />
- <a href="http://mediatomb.cc/">Mediatomb</a></p>
<p>Por ahora las listo, para que me sirva de una guía de temas de los que tengo ganas de hablar por si alguien puede estar interesado en escucharme&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.robertooliva.com/2008/04/01/retomando/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
