<?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>Scipion Strikes Back</title>
	<atom:link href="http://scipion.es/feed/" rel="self" type="application/rss+xml" />
	<link>http://scipion.es</link>
	<description>Scipion Strikes Back. Padawan de la web2.0 metido a desarrollador web.</description>
	<lastBuildDate>Sat, 11 Feb 2012 19:28:57 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
		<item>
		<title>Fuciones publicas vs privilegiadas</title>
		<link>http://scipion.es/2012/02/fuciones-publicas-vs-privilegiadas/</link>
		<comments>http://scipion.es/2012/02/fuciones-publicas-vs-privilegiadas/#comments</comments>
		<pubDate>Sat, 11 Feb 2012 19:28:57 +0000</pubDate>
		<dc:creator>Scipion</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Programación]]></category>

		<guid isPermaLink="false">http://scipion.es/?p=230</guid>
		<description><![CDATA[Hace tiempo que encontré este texto de Douglas Crockford sobre las funciones privadas en JavaScript. En el explica como crear funciones privadas de un objeto. Estas son declaradas en el constructor pero no se le asignan al objeto this. De esta manera solo las funciones dentro del mismo ámbito (el del constructor) tienen el privilegio [...]]]></description>
			<content:encoded><![CDATA[<p>Hace tiempo que encontré este <a href="http://javascript.crockford.com/private.html" target="_blank">texto de Douglas Crockford</a> sobre las funciones privadas en JavaScript. En el explica como crear funciones privadas de un objeto. Estas son declaradas en el constructor pero no se le asignan al objeto <em>this</em>. De esta manera solo las funciones dentro del mismo ámbito (el del constructor) tienen el privilegio de acceder a ellas.</p>
<pre class="brush:js">function myKlass(){
   var privateValue=0;
   function privateFunction(){
      return ++privateValue;
   }
   //Esta funcion tiene el privilegio de acceder a privateFunction
   this.pivileged=function(){
      return "Ejecución nº "+ privateFunction();
   }
}
var obj = new myKlass();
obj.pivileged();//Ejeción nº 1
obj.pivileged();//Ejeción nº 2
obj.pivileged();//Ejeción nº 3</pre>
<p>Si extendemos el prototipo de la función myKlass podemos obtener una clase más rica, con muchas más funciones publicas que estarán en todos los objetos creados con la sentencia <em>new</em>.<br />
Hasta aquí nada nuevo, porque esto es posible en javascript ya desde hace mucho. Pero el diferenciar entre Publica y Privilegiada es algo que no me acaba de gustar.</p>
<h3>Toda función puede tener ciertos privilegios.</h3>
<p>Las funciones creadas dentro del constructor tienen acceso a todas las funciones dentro del mismo ámbito. Sí, esto es un privilegio, pero estas funciones no tienen acceso a, por ejemplo, terceras funciones internas a otra funcion privilegiada (o publica).<br />
Así que en realidad solo tiene privilegio a un ámbito, que casualmente es el del constructor. Es muy sencillo crear otro ábito y declarar alli una gran cantidad de funciones privadas y asignarselas al prototipo. En este nuevo ámbito podriamos tener otras funciones privilegiadas que solo tuviesen acceso a este ámbito. Veamoslo:</p>
<pre class="brush:js">myKlass.prototype.otherPrivileged=(function(){
   var otherVariable=0;
   function otherExecution(){
      return otherVariable+=100;
   }
   return function(){
      return "Aqui vamos a "+otherExecution();
   }
})();
obj.otherPrivileged();//Aqui vamos a 100
obj.otherPrivileged();//Aqui vamos a 200</pre>
<p>Aqí tenemos una función que también tiene ciertos privilegios. No tiene acceso a <em>privateValue</em> o a <em>privateFunction</em>, pero solo ella tiene acceso a <em>otherVariable</em> y <em>otherExecution</em>.</p>
<p>Para una función está muy bien. Pero ¿y si queremos un grupo de funciones &#8216;privilegiadas&#8217;?. Pues nuestro ámbito de privilegios debe devolver no una sola función, sino un objeto con las funciones que deseemos y extender el prototipo de nuestra ya muy nutrida clase con ellos.</p>
<pre class="brush:js">var superFunctions=(function(){
   var v1=0,v2=2000,v3=775;//...
   function fprivate1(){/*...*/}
   function fprivate2(){/*...*/}
   function fprivate3(){/*...*/}

   function fpublic1(){/*...*/}
   function fpublic2(){/*...*/}
   function fpublic3(){/*...*/}
   return {
      fpublic1: fpublic1,
      fpublic2: fpublic2,
      x: fpublic3
   }
})();

for(fun in superFunctions){
    myKlass.prototype[fun]=superFunctions[fun];
}

new myKlass();
/* Cuidado con los nombres de las funciones, serán los del objeto devuelto
x	fpublic3()
fpublic1	fpublic1()
fpublic2	fpublic2()
otherPrivileged	function()
pivileged	function()
*/</pre>
<p>Con una funcion para extender prototypos de funciones se habría quedado un código más legible, pero en definitiva esto es lo que se debe hacer.</p>
<p>Sea como sea, podemos hacer que cualquier función publica sea en cierta medida privilegiada. Por eso prefiero no hacer distinción entre las funciones de un objeto. Cada una puede implementar su funcionalidad con acceso a otros métodos o no, eso no importa.</p>
]]></content:encoded>
			<wfw:commentRss>http://scipion.es/2012/02/fuciones-publicas-vs-privilegiadas/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Más pixels aleatorios, esta vez con Canvas</title>
		<link>http://scipion.es/2011/12/mas-pixels-aleatorios-esta-vez-con-canvas/</link>
		<comments>http://scipion.es/2011/12/mas-pixels-aleatorios-esta-vez-con-canvas/#comments</comments>
		<pubDate>Fri, 23 Dec 2011 16:32:58 +0000</pubDate>
		<dc:creator>Scipion</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[canvas]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[pixel]]></category>
		<category><![CDATA[random]]></category>

		<guid isPermaLink="false">http://scipion.es/?p=208</guid>
		<description><![CDATA[Hace tiempo escribí un post acerca de los pixels aleatorios. Dibujaba una imagen en java para probar que no ser repetían patrones en la funcion random. Para hacer lo propio en javascript ahora gracias al html5 podemos usar la etiqueta canvas y pintar dentro de ella. Nos declaramos un canvas del tamaño que queramos, por [...]]]></description>
			<content:encoded><![CDATA[<p>Hace tiempo escribí un post acerca de los pixels aleatorios. Dibujaba una imagen en java para probar que no ser repetían patrones en la funcion random. Para hacer lo propio en javascript ahora gracias al html5 podemos usar la etiqueta canvas y pintar dentro de ella. Nos declaramos un canvas del tamaño que queramos, por ejemplo de 300 x 300</p>
<pre class="brush:html">&lt;canvas height="300" width="300" id="mycanvas"&gt;&lt;/canvas&gt;</pre>
<p>Antes de dibujar en nuestro lienzo tenemos que usar el contexto, en este caso en 2d.</p>
<p>Para dibujar pixel a pixel solo tienes que dibujar cuadrados de un pixel de tamaño. Empezamos por la cordenada (0,0) hasta la (299,299). En realidad puedes dibujar fuera del canvas, pero por supuesto no esperes que se vea.</p>
<pre class="brush:js">function drawRandom(id){
	var canvas = document.getElementById(id);
	var ctx = canvas.getContext('2d');

	for(var j=0;j&lt;300; j++){
		for(var i=0;i&lt;300; i++){
			ctx.fillStyle = getRandColor();
			ctx.fillRect(i, j,i+1, j+1);
		}
	}
}

function getRandColor(){
	//Si quieres puedes usar solo blanco y negro para verlo más claro
	//var blanco="rgb(255,255,255)";
	//var negro="rgb(0,0,0)";
	return ("rgb("+(parseInt( (Math.random()*1000) % 256))+","
		+(parseInt( (Math.random()*1000) % 256))+","
		+(parseInt( (Math.random()*1000) % 256))+")");
}

drawRandom("mycanvas");</pre>
<p>Puede que tarde un rato, o incluso que el navegador piense que tienes un bucle infinito en ejecución. Después te pintará una imagen tan &#8220;bonita&#8221; como esta:</p>
<div id="attachment_216" class="wp-caption aligncenter" style="width: 310px"><a href="http://scipion.es/wp-content/uploads/2011/12/canvas.png"><img class="size-full wp-image-216" title="canvas" src="http://scipion.es/wp-content/uploads/2011/12/canvas.png" alt="canvas con pixels de colores aleatorios" width="300" height="300" /></a><p class="wp-caption-text">canvas con pixels de colores aleatorios</p></div>
<p>Para este ejemplo sencillo vemos que la funcion <em>Math.random( )</em> se comporta bastante bien en cuanto al grado de aleatoriedad. Pero si quieres profundizar en hacer dibujos con canvas puedes ver más cosas <a href="https://developer.mozilla.org/en/Canvas_tutorial/Drawing_shapes" target="_blank">aquí</a>. Si ya lo has hecho en otros lenguajes (no como yo) no te resultará complicado hacerlo en javascript.</p>
]]></content:encoded>
			<wfw:commentRss>http://scipion.es/2011/12/mas-pixels-aleatorios-esta-vez-con-canvas/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Visión general de un SQLInjection</title>
		<link>http://scipion.es/2011/08/vision-general-de-un-sqlinjection/</link>
		<comments>http://scipion.es/2011/08/vision-general-de-un-sqlinjection/#comments</comments>
		<pubDate>Sat, 27 Aug 2011 18:34:50 +0000</pubDate>
		<dc:creator>Scipion</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programación Web]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[seguridad]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[sqlinjection]]></category>

		<guid isPermaLink="false">http://scipion.es/?p=194</guid>
		<description><![CDATA[Me ha parecido muy completa esta presentación de SQL injection. Toca un poco de Doctrine y Propel para dar ejemplos de buenas practicas. Da un dato interesante, entre el 40-60% de los casos de acceso a datos no autorizados son por fallos de injecciones de SQL en el código de una web. Un error muy [...]]]></description>
			<content:encoded><![CDATA[<p>Me ha parecido muy completa esta presentación de SQL injection. Toca un poco de Doctrine y Propel para dar ejemplos de buenas practicas.<br />
Da un dato interesante, entre el 40-60% de los casos de acceso a datos no autorizados son por fallos de injecciones de SQL en el código de una web. Un error muy común por lo visto.<br />
Las transparencias son de Krzysztof Kotowicz un experto en seguridad en e-comerce y web 2.0. Solo echarle un ojo a <a href="http://blog.kotowicz.net/" target="_blank">su blog</a> ya es algo muy recomendable apara estar al día en seguridad para la web.</p>
<div id="__ss_3459190" style="width: 510px;"><object id="__sse3459190" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="510" height="426" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowScriptAccess" value="always" /><param name="src" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=owasp-sql-injection-en-100317143725-phpapp02&amp;stripped_title=sql-injection-complete-walktrough-not-only-for-php-developers&amp;userName=kkotowicz" /><param name="name" value="__sse3459190" /><param name="allowfullscreen" value="true" /><embed id="__sse3459190" type="application/x-shockwave-flash" width="510" height="426" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=owasp-sql-injection-en-100317143725-phpapp02&amp;stripped_title=sql-injection-complete-walktrough-not-only-for-php-developers&amp;userName=kkotowicz" name="__sse3459190" allowscriptaccess="always" allowfullscreen="true"></embed></object></div>
]]></content:encoded>
			<wfw:commentRss>http://scipion.es/2011/08/vision-general-de-un-sqlinjection/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Two ways to create custom objects</title>
		<link>http://scipion.es/2011/05/two-ways-to-create-custom-objects/</link>
		<comments>http://scipion.es/2011/05/two-ways-to-create-custom-objects/#comments</comments>
		<pubDate>Sun, 08 May 2011 11:22:01 +0000</pubDate>
		<dc:creator>Scipion</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jsapi]]></category>
		<category><![CDATA[spidermonkey]]></category>

		<guid isPermaLink="false">http://scipion.es/?p=170</guid>
		<description><![CDATA[Visto en JSAPI User Guide una tan sencilla como complicada segunda opción Hay dos formas de crear objetos personalizados que el JS engine puede utilizar: Escribir un script JS que crea un objeto, sus propiedades, métodos, y el constructor, y luego pasa la secuencia de comandos para el motor de JS en tiempo de ejecución. Insertar el código de la aplicación que define las propiedades del objeto y los métodos, llame al motor para inicializar un objeto nuevo, a continuación, establezcalas propiedades del objeto a través de llamadas adicionales al motor. Una ventaja de estemétodo es que su aplicación puede contener métodos nativos que manipulen [...]]]></description>
			<content:encoded><![CDATA[<p>Visto en <a title="JSAPI User Guide" href="https://developer.mozilla.org/en/JavaScript_C_Engine_Embedder's_Guide" target="_blank">JSAPI User Guide</a> una tan sencilla como complicada segunda opción</p>
<blockquote><p>Hay dos formas de crear objetos personalizados que el JS engine puede utilizar:</p>
<ul>
<li>Escribir un script JS que crea un objeto, sus propiedades, métodos, y el constructor, y luego pasa la secuencia de comandos para el motor de JS en tiempo de ejecución.</li>
<li>Insertar el código de la aplicación que define las propiedades del objeto y los métodos, llame al motor para inicializar un objeto nuevo, a continuación, establezcalas propiedades del objeto a través de llamadas adicionales al motor. Una ventaja de estemétodo es que su aplicación puede contener métodos nativos que manipulen directamente la incrustación de objetos.</li>
</ul>
</blockquote>
<p>La desventaja del segundo método es que para escribir algo en javascript tienes que escribirlo en C++. Sencillez vs rendimiento.</p>
<p>Hace tiempo leí una cita sobre Unix que decía algo así como:  &#8221;UNIX es sencillo, solo que hace falta un genio para apreciar su sencillez&#8221;. Creo que no solo le pasa a Unix.</p>
]]></content:encoded>
			<wfw:commentRss>http://scipion.es/2011/05/two-ways-to-create-custom-objects/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Timsort. Porqué no había versión JavaScript</title>
		<link>http://scipion.es/2011/05/timsort-porque-no-habia-version-javascript/</link>
		<comments>http://scipion.es/2011/05/timsort-porque-no-habia-version-javascript/#comments</comments>
		<pubDate>Fri, 06 May 2011 15:53:31 +0000</pubDate>
		<dc:creator>Scipion</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[array]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[mergesort]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[quicksort]]></category>
		<category><![CDATA[timsort]]></category>
		<category><![CDATA[vector]]></category>

		<guid isPermaLink="false">http://scipion.es/?p=174</guid>
		<description><![CDATA[La ordenación de vectores es algo que se imparte desde los primeros años de carrera en informática con el método de la burbuja, inserción directa y alguno más con complejidad O(n^2). Más tarde cuando se profundiza en la algoritmia un poco llegamos a algoritmos más complejos de complejidad O(nLogn) se concluye que no hay nada [...]]]></description>
			<content:encoded><![CDATA[<p>La ordenación de vectores es algo que se imparte desde los primeros años de carrera en informática con el método de la burbuja, inserción directa y alguno más con complejidad O(n^2). Más tarde cuando se profundiza en la algoritmia un poco llegamos a algoritmos más complejos de complejidad O(nLogn) se concluye que no hay nada mejor en la ordenación de vectores, y esas innovaciones son ya de hace bastante tiempo.</p>
<p><strong>Métodos de ordenación de vectores</strong></p>
<p>QuickSort,  MergeSort, HeapSort &#8230; hay muchos Sort&#8217;s por el mundo y todos tienen ventaja frente a otros. Los que he mencionado son de los más conocidos con complejidades de O(nLogn). Por lo que he estado viendo, el <strong>MergeSort </strong>es el que se suele utilizar más por su baja cantidad de operaciones de computo. Es muy sencillo, ya que mezclar listas ordenadas de elementos tiene complejidad lineal y no tiene mucha historia. Su principal desventaja, la gran cantidad de memoria temporal utilizada, tiene cada vez menos importancia gracias a que la memoria se va abaratando cada vez más. Pero&#8230;</p>
<p>¿Que pasa en los dispositivos que no tienen mucha memoria? Lo primero que viene a la mente es que siempre hay alguien que tiene un equipo en el que la memoria se mide en K&#8217;s, pero no van por ahí los tiros. Los smartphones y tablets son cada vez más populares, y por ahora lo que se considera normal en estos dispositivos es lo que se tenía en escritorio hace ya bastante tiempo.</p>
<p><strong>TimSort</strong></p>
<p>En esta visión del ahorro de memoria + mergeSort es donde surge el algoritmo TimSort. Lo ideó Tim Peters para la ordenacion en Python (donde se pueden programar librerias nativas en C) y lo bautizó con su propio nombre, como el dice: &#8220;eh, me lo he ganado&#8221;.</p>
<p>El TimSort no mejora en complejidad a su padre, el MergeSort, pero si que tiene ciertas optimizaciones que lo hacen que ahorre mucha memoria en los casos medios. Cuando una parte del vector está &#8220;bastante&#8221; ordenada no sigue dividiendo el vector en partes hasta llegar a una lista de un elemento, sino que utiliza la inserción directa para ordenar todo ese trozo. Aunque la inserción directa sea de complejidad O(n^2) para listas muy pequeñas de elementos es muy rápido gracias a su sencillez.</p>
<p>Si un tramo del vector que estamos intentado ordenar de mayor a menor por ejemplo, se encuentra ordenado de menor a mayor, el algoritmo invierte este tramo y continua.</p>
<p>Con esto y ajustando los vectores temporales al mínimo requerido timsort consigue un ahorro de memoria y de rendimiento respecto de MergeSort en vectores parcialmente ordenados o con muchos repetidos.</p>
<p style="text-align: center;"><img class="aligncenter" title="Ejemplo de ordenación con Timsort" src="http://upload.wikimedia.org/wikipedia/en/6/69/Timsort-edited.png" alt="Ejemplo de ordenación con Timsort" width="1106" height="368" /></p>
<p><strong>TimSort en C (Python) y en Java</strong></p>
<p>Es por estas pequeñas cosas que el TimSort ha sido seleccionado para ser el tipo de ordenación de vectores por defecto en Java 7 (lanzamiento estimado en Julio de 2001) y en la plataforma para móviles Android (que se puede decir que es Java también)</p>
<p>También es la ordenación por defecto en Python, bastante lógico cuando el algoritmo se ideó en principio para este lenguaje. Esta implementación es nativa de Python, por eso está escrito en C (no todo lo nativo de Python está escrito en C pero sí es aconsejable para aumentar el rendimiento).</p>
<p>El TimSort de Tim lo puedes encontrar aquí (<a href="http://svn.python.org/projects/python/trunk/Objects/listobject.c" target="_blank">timsort.c</a>) y una <a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt" target="_blank">explicación</a> de sus pruebas de rendimiento.</p>
<p>Otra <a href="http://www.google.com/codesearch/p?hl=es#ih5hvYJNSIA/src/share/classes/java/util/TimSort.java&amp;q=timsort&amp;sa=N&amp;cd=1&amp;ct=rc" target="_blank">implementación en java</a> Josh Bloch con bastantes menos lineas de código.</p>
<p><strong>Y &#8230; en JavaScript</strong></p>
<p>Siendo un obsesionado del JavaScript me pregunté, ¿y no hay implementación en JavaScript?. En javascipt ya se pueden ordenar vecteres con el metodo nativo del Array <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort" target="_blank">sort</a>(funcionDeComparacion) pero cada maquina viertual de JS utiliza la ordenación que más le conviene. Bueno en realidad la que han decidido sus desarrolladores. Pero de todas maneras, si los desarrolladores de una maquina virtual de JS decidieran implementarlo usarían el código ya existente si implementan en C/C++ como son el SpiderMonkey y el V8, o la versión Java para Rhino.</p>
<p>Utilizar una versión JavaScript para ordenar vectores en JavaScript sería una perdida de rendimiento, al menos en gran cantidad de los casos.</p>
<p><strong>Mi pequeña contribución</strong></p>
<p>Si aun así no te fias y quieres hacer tus propias pruebas de rendimiento he portado la versión Java del algoritmo a JavaScript (<a href="https://github.com/Scipion/interesting-javascript-codes/blob/master/timsort.js" target="_blank">TimSort JavaScript</a>), con algunas optimizaciones propias del lenguaje; intentando utilizar el mayor numero de métodos nativos del lenguaje, aunque estoy seguro de que se puede optimizar algo más hasta equipararse en rendimiento 1 a 1 al sort nativo (que puede que en cada implementación sea un algoritmo distinto). Actualmente solo supera en rendimiento al nativo en muy pocas ocasiones, cuando el vector tiene muy poca entropía; y en casos muy malos llega a duplicar el tiempo de computo de la versión nativa.</p>
<p>No he buscado mucho y no sé que algoritmos utilizan las maquinas virtuales de los navegadores de hoy en día así que indagaré un poco pero eso es otro post.</p>
]]></content:encoded>
			<wfw:commentRss>http://scipion.es/2011/05/timsort-porque-no-habia-version-javascript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dibujando rutas en Google Maps</title>
		<link>http://scipion.es/2011/03/dibujando-rutas-en-google-maps/</link>
		<comments>http://scipion.es/2011/03/dibujando-rutas-en-google-maps/#comments</comments>
		<pubDate>Mon, 14 Mar 2011 20:26:00 +0000</pubDate>
		<dc:creator>Scipion</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Programación Web]]></category>
		<category><![CDATA[directionsDisplay]]></category>
		<category><![CDATA[directionsService]]></category>
		<category><![CDATA[Google Maps]]></category>
		<category><![CDATA[Google Maps Api 3]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Manual]]></category>

		<guid isPermaLink="false">http://scipion.es/?p=152</guid>
		<description><![CDATA[Dibujando rutas Puedes consultar las partes anteriores del manual de Google Maps Api 3: Primera parte del manual Segunda parte del manual Tercera parte del manual Este servicio es interesante, a demás podemos usar coordenadas o direcciones directamente, ya que el servicio las traducirá por sí solo. Las clases principales son: google.maps.DirectionsService que es la [...]]]></description>
			<content:encoded><![CDATA[<h3>Dibujando rutas</h3>
<p>Puedes consultar las partes anteriores del manual de Google Maps Api 3:<br />
<a title="Primera parte manual Google Maps" href="http://scipion.es/2011/03/introduccion-a…gle-maps-api-3/" target="_blank">Primera parte del manual</a></p>
<p><a title="Segunda parte del manual de Google Maps Api 3" href="http://scipion.es/2011/03/google-maps-geocoder/ " target="_blank">Segunda parte del manual</a></p>
<p><a title="Tercera parte del manual de Google Maps" href="http://scipion.es/2011/03/dibujar-marcas-en-un-mapa/" target="_blank">Tercera parte del manual</a></p>
<p>Este servicio es interesante, a demás podemos usar coordenadas o direcciones directamente, ya que el servicio las traducirá por sí solo.<br />
Las clases principales son: <em>google.maps.DirectionsService</em> que es la que ejecuta la peticion del servicio al servidor y nos devuelve los datos, y <em>google.maps.DirectionsRenderer</em> que es la encargada de mostrar la ruta en nuestro mapa.<br />
El ejempo básico de inicialización es el siguiente:</p>
<pre class="brush:js">directionsService = new google.maps.DirectionsService();
directionsDisplay = new google.maps.DirectionsRenderer();

directionsDisplay.setMap(map);</pre>
<p>La llamada a route tiene el formato “<em>directionsService.route(request, function(result, status)</em>”. Hay que generar un objeto request primero(DirectionRequest) que solo es necesario rellenar los campos que no sinteresan. Despues la funcion de callback es la que a partir del status tratamos los reultados.</p>
<pre class="brush:js">var request = {
  origin:start,
  destination:end,
  travelMode: google.maps.DirectionsTravelMode.DRIVING
};</pre>
<p>La llamada y el tratamiento del objeto result. Comprobamos que el status es OK, si no no hay nada que hacer, salvo mostrar el tipo de error.</p>
<pre class="brush:js">directionsService.route(request, function(result, status) {
  if (status == google.maps.DirectionsStatus.OK) {
    directionsDisplay.setMap(map);
    var mystr="";
    for(var i in result.routes){
      var mylegs=result.routes[i].legs
      for(var j in mylegs){
        mystr += mylegs[j].distance.text;
        mystr += " " + mylegs[j].duration.text+ " &lt;br/&gt;";
      }
      mystr+="&lt;br/&gt;";
      $(“#infoRecorrido).html(mystr);
    }
    directionsDisplay.setDirections(result);
  }
});</pre>
<p>Lo que realmente dibuja el mapa es ‘<em>directionsDisplay.setDirections(result)</em>’ ¿y todo lo demas? pues bien, google nos envia un objeto con bastante información. Los margenes en que se visualizará el mapa, las coordenadas de los puntos de incio y fin, y otras cosas entre ellas la distancia y tiempo de recorrido.<br />
La distancia se encuentra en “<em>result.routes[0..n-1].legs[0..n-1].duration</em>”. Se puede visualizar en texto en tiempo ya tranformado en horas:minutos:segundos con ‘<em>.text</em>’ o directamente en el numero de segundos con ‘<em>.value</em>’.<br />
La respuesta contiene bastante información y se le puede sacar mucho partido (ver: <a href="http://code.google.com/intl/es/apis/maps/documentation/directions/">http://code.google.com/intl/es/apis/maps/documentation/directions/</a> )</p>
<pre class="brush:js">bounds = new google.maps.LatLngBounds();
for(var l in markers){
  bounds.extend( markers[l].getPosition() );
}
map.fitBounds(bounds);</pre>
<p>visto en: <a href="http://blog.shamess.info/2009/09/29/zoom-to-fit-all-markers-on-google-maps-api-v3/">http://blog.shamess.info/2009/09/29/zoom-to-fit-all-markers-on-google-maps-api-v3/</a></p>
<p>Finalmente y por experiencia propia recomiendo re posicionar los margenes con cierto retardo con una función como esta:</p>
<pre class="brush:js">function rebounds(){
  setTimeout(recReBounds,250,(6));
}

function recReBounds(veces)
  if(!veces){
    return false;
  }
  try{
    bounds = new google.maps.LatLngBounds();
    for(var l in markers){
    bounds.extend( markers[l].getPosition() );
  }
  map.fitBounds(bounds);
  }
  catch(e){
    setTimeout(recReBounds,250,(veces-1));
  }
}

rebounds();</pre>
<p>A veces la velocidad del navegador que esté utilizando el cliente no carga las imágenes del mapa con mucha velocidad. Si ejecutamos el reajuste de margenes una vez recogidos los datos puede que se reajusten los margenes antes de pintar el mapa, con lo cual el reajuste no tiene efecto. Con un retardo de un cuarto de segundo el usuario siente interacción de la web y el reajuste tiene efecto.</p>
]]></content:encoded>
			<wfw:commentRss>http://scipion.es/2011/03/dibujando-rutas-en-google-maps/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dibujar marcas en un mapa</title>
		<link>http://scipion.es/2011/03/dibujar-marcas-en-un-mapa/</link>
		<comments>http://scipion.es/2011/03/dibujar-marcas-en-un-mapa/#comments</comments>
		<pubDate>Fri, 11 Mar 2011 20:10:52 +0000</pubDate>
		<dc:creator>Scipion</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Programación Web]]></category>
		<category><![CDATA[Google Maps]]></category>
		<category><![CDATA[Google Maps Api 3]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Manual]]></category>
		<category><![CDATA[Markers]]></category>

		<guid isPermaLink="false">http://scipion.es/?p=149</guid>
		<description><![CDATA[Trabajando con los markers Puedes consultar las partes anteriores del manual de Google Maps Api 3 primera parte del manual segunda parte del manual Para empezar vamos a trabajar con un vector de marcas que va a ser una variable global markers. Tan sencillo como: var markers={}; setMarker hace algo más que posicionar un marker [...]]]></description>
			<content:encoded><![CDATA[<h3>Trabajando con los markers</h3>
<p>Puedes consultar las partes anteriores del manual de Google Maps Api 3</p>
<p><a title="Primera parte manual Google Maps" href="http://scipion.es/2011/03/introduccion-a…gle-maps-api-3/" target="_blank">primera parte del manual</a></p>
<p><a title="Segunda parte del manual de Google Maps Api 3" href="http://scipion.es/2011/03/google-maps-geocoder/ " target="_blank">segunda parte del manual</a></p>
<p>Para empezar vamos a trabajar con un vector de marcas que va a ser una variable global markers. Tan sencillo como:</p>
<pre class="brush:js">var markers={};</pre>
<p>setMarker hace algo más que posicionar un marker en el mapa. Seleciona el campo donde tenemos la localidad (o direccion), esto lo hace con la funcion dollar de jquery. Esta direccion la traduce a coordenadas LatLng con el servicio geocoder.<br />
Despues invoca al método marker que es el que realmente inserta el marcador en el punto correcto del mapa.</p>
<pre class="brush:js">function setMarker(id,addid){
  var dir = $("#"+id).val();
  geocoder.geocode( { 'address': dir}, function(results, status) {
    if (status == google.maps.GeocoderStatus.OK) {
      marker(id, results[0].geometry.location);
    } else {
      marker(id,null);
    }
  });
}</pre>
<p>Marker en realidad es una funcion muy sencilla. Si existe el marcador añade una nueva posición, si no existe lo crea indicandole el mapa y la posicion donde irá.<br />
La unica complejidad en cuanto a configuracion del maker es indicarle que no sea arrastrable (draggable) ni que se pueda pinchar (clickable).</p>
<pre class="brush:js">function marker(id, location){
  if(markers[id]){
    markers[id].setPosition(location);
  }
  else{
    markers[id] = new google.maps.Marker({
      map: map
      ,position: location
      ,markerOptions:{
        draggable:false
        ,clickable:false
      }
    });
  }

  map.setZoom(10);
}</pre>
<p>Otras opciones posibles son hacer zoom y centrar el mapa en el marcador (en este caso está comentado) pero son opciones del mapa, no del marcador.</p>
<h3>Borrar un marker</h3>
<p>Para borrar un marker es tan sencillo como añadirle una posicion nula. Como en nuestro caso tenemos un objeto global donde están todos nuestros markers nos podemos hacer las funciones hideMarker y hideAllMarkers:</p>
<pre class="brush:js">function hideAllMarkers(){
  for(var m in markers){
    markers[m].setPosition(null);
  }
}

function hideMarker(id){
  if(id &amp;&amp; id != "" &amp;&amp; markers[id]){
    markers[id].setPosition(null);
    return true;
  }
  return false;
}</pre>
<p>*Cuidado si se usan otras propiedades de los markers como el texto que despliegan al clickarlos. Si volvemos a ponerle una posicion al marker esas propiedaden persisten. Suponemos que en esta aplicacion no añadimos informacion extra y que los markers no son clickables. En otro caso para más seguridad hay que hacer un new cada vez para chafar las propiedades anteriores, o cambiarlas una por una.</p>
]]></content:encoded>
			<wfw:commentRss>http://scipion.es/2011/03/dibujar-marcas-en-un-mapa/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google Maps Geocoder</title>
		<link>http://scipion.es/2011/03/google-maps-geocoder/</link>
		<comments>http://scipion.es/2011/03/google-maps-geocoder/#comments</comments>
		<pubDate>Wed, 09 Mar 2011 10:27:55 +0000</pubDate>
		<dc:creator>Scipion</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Programación Web]]></category>
		<category><![CDATA[Geocoder]]></category>
		<category><![CDATA[Google Maps]]></category>
		<category><![CDATA[Google Maps Api 3]]></category>
		<category><![CDATA[Manual]]></category>

		<guid isPermaLink="false">http://scipion.es/?p=146</guid>
		<description><![CDATA[De dirección a coordenada Puedes consultar la primera parte del manual de Google Maps Api 3 El objeto Geocoder se usa para traducir coordenadas a direcciones y viceversa. Si nos fijamos en las indicaciones de uso de google nos encontramos que si usameos el servico Geocoder tenemos que incluir obligatoriamente un mapa de google en [...]]]></description>
			<content:encoded><![CDATA[<h3>De dirección a coordenada</h3>
<p>Puedes consultar la <a title="Primera parte manual Google Maps" href="http://scipion.es/2011/03/introduccion-a…gle-maps-api-3/" target="_blank">primera parte del manual</a> de Google Maps Api 3</p>
<p>El objeto <strong>Geocoder </strong>se usa para traducir coordenadas a direcciones y viceversa. Si nos fijamos en las indicaciones de uso de google nos encontramos que si usameos el servico Geocoder tenemos que incluir obligatoriamente un mapa de google en nuestra web.<br />
Bueno en realidad es lo logico al traducir direcciones a coordenadas, pero si estabas pensando dar un servicio de otro tipo que no sea visualizado, siento decirte que te caparán el servicio</p>
<p>Este ejemplo traduce una dirección (de un input text) a unas coordenadas y centra el mapa en esas coordenadas y crea un marker.</p>
<pre class="brush:js">&lt;script type="text/javascript"&gt;
var geocoder;
var map;
function initialize() {
  geocoder = new google.maps.Geocoder();
  var latlng = new google.maps.LatLng(-34.397, 150.644);
  var myOptions = {
    zoom: 8,
    center: latlng,
    mapTypeId: google.maps.MapTypeId.ROADMAP
  }
  map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
}

function codeAddress() {
  var address = document.getElementById("address").value;
  geocoder.geocode( { 'address': address}, function(results, status) {
    if (status == google.maps.GeocoderStatus.OK) {
      map.setCenter(results[0].geometry.location);
      var marker = new google.maps.Marker({
        map: map,
        position: results[0].geometry.location
      });
    } else {
      alert("Geocode was not successful for the following reason: " + status);
    }
  });
}
&lt;/script&gt;</pre>
<p>más info: <a href="http://code.google.com/intl/es/apis/maps/documentation/javascript/services.html#Geocoding">http://code.google.com/intl/es/apis/maps/documentation/javascript/services.html#Geocoding</a></p>
<p>una consulta correcta devuelve un json tal que así:</p>
<pre class="brush:js">{
"status": "OK",
"results": [ {
  "types": [ "locality", "political" ],
  "formatted_address": "Winnetka, IL, USA",
  "address_components": [ {
  "long_name": "Winnetka",
  "short_name": "Winnetka",
  "types": [ "locality", "political" ]
  }, {
  "long_name": "Illinois",
  "short_name": "IL",
  "types": [ "administrative_area_level_1", "political" ]
  }, {
  "long_name": "United States",
  "short_name": "US",
  "types": [ "country", "political" ]
  } ],
"geometry": {
  "location": {
    "lat": 42.1083080,
    "lng": -87.7417070
  },
"location_type": "APPROXIMATE",
  "viewport": {
    "southwest": {
      "lat": 42.0917501,
      "lng": -87.7737218
    },
    "northeast": {
      "lat": 42.1248616,
      "lng": -87.7096922
    }
  },
  "bounds": {
    "southwest": {
      "lat": 42.0885320,
      "lng": -87.7715480
    },
    "northeast": {
      "lat": 42.1284090,
      "lng": -87.7110160
    }
  }
}
} ]
}</pre>
<p>Accediendo al objeto <em>results[0].geometry.location</em> obtenemos un objeto lonLat, objeto propio de google.maps, que contiene la coordenada. ya podemos hacer lo que queramos con ella.</p>
]]></content:encoded>
			<wfw:commentRss>http://scipion.es/2011/03/google-maps-geocoder/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Introducción a Google Maps Api 3</title>
		<link>http://scipion.es/2011/03/introduccion-a-google-maps-api-3/</link>
		<comments>http://scipion.es/2011/03/introduccion-a-google-maps-api-3/#comments</comments>
		<pubDate>Sat, 05 Mar 2011 20:26:27 +0000</pubDate>
		<dc:creator>Scipion</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Programación Web]]></category>
		<category><![CDATA[Google Maps]]></category>
		<category><![CDATA[Google Maps Api 3]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Manual]]></category>

		<guid isPermaLink="false">http://scipion.es/?p=141</guid>
		<description><![CDATA[Google Maps api3 con ejemplos Esta es la primera parte de un manual sobre el Api 3 de google maps. Simplemente es una primera guia para cómo, a partir de pocas lineas de código, poder implementar una aplicación interesante en tu web. Aportar información geolocalizada está hoy a la orden del día, yo voy a [...]]]></description>
			<content:encoded><![CDATA[<h3>Google Maps api3 con ejemplos</h3>
<p>Esta es la primera parte de un manual sobre el Api 3 de google maps. Simplemente es una primera guia para cómo, a partir de pocas lineas de código, poder implementar una aplicación interesante en tu web.</p>
<p>Aportar información geolocalizada está hoy a la orden del día, yo voy a basarme en los ejemplos que proporciona google añadiendo variaciones que amplian su funcionamiento. Para hacerlo de forma más comoda voy a utilizar jQuery 1.4.2 en algunos casos.</p>
<p>Ejemplo ligeramente modificado con jquery:<br />
-muestra un mapa. se puede insertar longitud y latitud numerica y actualizar el mapa. Despues una lista de las propiedades de google.maps</p>
<pre class="brush:js">&lt;html&gt;
&lt;head&gt;
&lt;meta name="viewport" content="initial-scale=1.0, user-scalable=no" /&gt;
&lt;script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="./jquery.1.4.2.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var myOptions, latlng, map;

function initialize() {
  latlng = new google.maps.LatLng(-34.397, 150.644);
  myOptions = {
    zoom: 8,
    center: latlng,
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };
  map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
}

$(document).ready(function(){
  $("#buttonver").click(function(){
    var latVar,lonVar;
    latVar = $("#lat").val();
    lonVar = $("#lon").val();
    latlng = new google.maps.LatLng(latVar, lonVar);
    myOptions.center=latlng;
    map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
  });
});
&lt;/script&gt;
&lt;/head&gt;
&lt;body onload="initialize()"&gt;
&lt;div id="map_canvas" style="width:400px; height:400px"&gt;&lt;/div&gt;
&lt;label for="lat"&gt;latitud&lt;/label&gt;&lt;input type="text" id="lat" name="lat" value="38.5"/&gt;
&lt;label for="lon"&gt;longitud&lt;/label&gt;&lt;input type="text" id="lon" name="lon" value="-0.5"/&gt;
&lt;input type="button" id="buttonver" value="ver" /&gt;</pre>
<pre class="brush:js">&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Añadimos evento cuando haga <strong>click </strong>para que muestre la <strong>longitud y latitud</strong>:<br />
*MEJORA: no hacemos un new Map cuando cambiamos las coordenadas. Usamos el método map.setCenter(latlng)</p>
<pre class="brush:js">&lt;html&gt;
&lt;head&gt;
&lt;meta name="viewport" content="initial-scale=1.0, user-scalable=no" /&gt;
&lt;script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="./jquery.1.4.2.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var myOptions, latlng, map;

function initialize() {
  latlng = new google.maps.LatLng(-34.397, 150.644);
  myOptions = {
    zoom: 8,
    center: latlng,
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };
  map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
  google.maps.event.addListener(map, 'click', function(event) {
    alert(event.latLng);
  });
}

$(document).ready(function(){
  $("#buttonver").click(function(){
    var latVar,lonVar;
    latVar = $("#lat").val();
    lonVar = $("#lon").val();
    latlng = new google.maps.LatLng(latVar, lonVar);
    myOptions.center=latlng;
    map.setCenter(latlng);
  });
});
&lt;/script&gt;
&lt;/head&gt;
&lt;body onload="initialize()"&gt;
&lt;div id="map_canvas" style="width:400px; height:400px"&gt;&lt;/div&gt;
&lt;label for="lat"&gt;latitud&lt;/label&gt;&lt;input type="text" id="lat" name="lat" value="38.5"/&gt;
&lt;label for="lon"&gt;longitud&lt;/label&gt;&lt;input type="text" id="lon" name="lon" value="-0.5"/&gt;
&lt;input type="button" id="buttonver" value="ver" /&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Reseña sobre los eventos posibles:</p>
<p>- ‘click’<br />
- ‘dblclick’<br />
- ‘mouseup’ -&gt; no me va<br />
- ‘mousedown’ -&gt; no me va<br />
- ‘mouseover’<br />
- ’mouseout’</p>
<p>En estos eventos se les pasa un event a la funcion calback que contiene una variable latLng.</p>
<p>- ‘zoom_change’ -&gt; el callback no recibe parámetros<br />
- ‘bounds_changed’<br />
- ‘center_changed’</p>
<p><strong>Enlaces de referencia:</strong></p>
<p>-Tutorial:<br />
<a href="http://code.google.com/intl/es/apis/maps/documentation/javascript/tutorial.html">http://code.google.com/intl/es/apis/maps/documentation/javascript/tutorial.html</a></p>
<p>-Referencia:<br />
<a href="http://code.google.com/intl/es/apis/maps/documentation/javascript/reference.html">http://code.google.com/intl/es/apis/maps/documentation/javascript/reference.html</a></p>
<p>-Ejemplos:<br />
<a href="http://code.google.com/intl/es/apis/maps/documentation/javascript/examples/">http://code.google.com/intl/es/apis/maps/documentation/javascript/examples/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://scipion.es/2011/03/introduccion-a-google-maps-api-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mozilla t-shirt</title>
		<link>http://scipion.es/2011/02/mozilla-t-shirt/</link>
		<comments>http://scipion.es/2011/02/mozilla-t-shirt/#comments</comments>
		<pubDate>Sat, 26 Feb 2011 15:30:32 +0000</pubDate>
		<dc:creator>Scipion</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[MDN]]></category>
		<category><![CDATA[mozilla]]></category>
		<category><![CDATA[t-shirt]]></category>

		<guid isPermaLink="false">http://scipion.es/?p=133</guid>
		<description><![CDATA[Hace un tiempo me encontre este post: llamamiento: http://hacks.mozilla.org/2011/01/write-some-docs-get-an-mdn-t-shirt/ La gente de mozilla iba a hacer un sprint de generar documentación en developer.mozilla.org y buscaban colaboradores. Explicaban que si querias colaborar te podias meter en el canal de chat de irc de desarrolladores (que es #mozdev) y que si colaborabas te podias ganar una camiseta [...]]]></description>
			<content:encoded><![CDATA[<p>Hace un tiempo me encontre este post:</p>
<p>llamamiento: <a href="http://hacks.mozilla.org/2011/01/write-some-docs-get-an-mdn-t-shirt/">http://hacks.mozilla.org/2011/01/write-some-docs-get-an-mdn-t-shirt/</a></p>
<p>La gente de mozilla iba a hacer un sprint de generar documentación en developer.mozilla.org y buscaban colaboradores. Explicaban que si querias colaborar te podias meter en el canal de chat de irc de desarrolladores (que es #mozdev) y que si colaborabas te podias ganar una camiseta de mozilla.</p>
<p>Pues bien, esa documentación que tanto me ha dado y tan poco le he dado yo. La verdad es que la mayoría está en ingles. Yo tampoco es que conozca el código fuente de firefox como la palma de mi mano, pero si que acostumbro a leer la documentación de distintos sitios para aprender, tanto en ingles como en español, y el wiki de la documentación de mozilla es uno de mis sitios de referencia importantes.</p>
<p>Pues bien, el citado día del sprint me presencié en el canal de chat. Allí me preguntaron que si estaba por el sprint doc day y contesté que sí. &#8220;¿En que apartado te gustaría trabajar Scipion?&#8221; &#8211; me preguntó Janet Swisher, que trabaja en la documentación de mozilla y era una de las coordinadoras del spint. &#8211; &#8220;En la traducción al español&#8221;. &#8211; le contesté &#8211; &#8220;Excelente, tenemos personas trabajando en la traducción al francés y al portugués pero nadie trabajando en español. Enviame tus datos para que te mandemos una camisera&#8221;.</p>
<p>Ese día traduje unos cuantos artículos y revisé algún otro, pero queda muchísimo que hacer en la parte hispana de la documentación.</p>
<p>&#8230; y los chicos de mozilla me mandaron la camiseta.</p>
<p style="text-align: center;"><a title="MDN t-shirt front by scipion50, on Flickr" href="http://www.flickr.com/photos/44983884@N04/5462732004/"><img class="aligncenter" src="http://farm6.static.flickr.com/5013/5462732004_55765ff7c9.jpg" alt="MDN t-shirt front" width="350" height="263" /></a></p>
<p style="text-align: center;"><a title="MDN t-shirt back by scipion50, on Flickr" href="http://www.flickr.com/photos/44983884@N04/5462731934/"><img class="aligncenter" src="http://farm6.static.flickr.com/5215/5462731934_9904c4eff3.jpg" alt="MDN t-shirt back" width="350" height="263" /></a></p>
<p>No he dejado de contribuir el tiempo que puedo en la docu de mozilla y seguiré cuando tenga un rato, porque muchas cosas que no son novedosas siguen estando solo en inglés.</p>
<p>Por lo visto fue bastante bien la cosa <a href="http://hacks.mozilla.org/2011/01/mdn-doc-sprint-was-a-huge-success/" target="_blank">según explican</a>. Normalmente la comunidad produce documentación a un ritmo bastante lento. La comunidad hispana no es una excepción, es más, somos de los que más lentos vamos. Por eso os animo a subiros al carro. Estad pendientes del próximo sprint y ¡¡¡Ganad una camiseta!!!</p>
]]></content:encoded>
			<wfw:commentRss>http://scipion.es/2011/02/mozilla-t-shirt/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

