tag:blogger.com,1999:blog-56445922008-05-24T20:09:01.612+02:00pséjavi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comBlogger383125tag:blogger.com,1999:blog-5644592.post-27172346760942208372008-05-22T20:53:00.004+02:002008-05-22T21:43:29.747+02:00Manual rápido de programación con GPSHace tiempo que tenía ganas de poner un post de este tipo, así que vamos allá. Pongamos que no sabes lo que es GPS y quieres hacer una aplicación que necesite saber donde estás, estás en el sitio correcto, voy a tratar de enumerar lo que necesitas saber de forma clara y concisa:<br /><br />- Qué es <a href="http://es.wikipedia.org/wiki/DGPS">GPS</a>: es un sistema que permite saber en qué posición del globo estás situado<br />- En qué se basa: Hay una serie de satélites orbitando que emiten señales, el receptor las interpreta y gracias a triangulación determina tu posición<br />- Necesito saber triangular: no, el receptor hace todo por tí, olvida a doppler, trigonometría, etc :)<br />- qué información da el GPS: te da la posición gracias a la latitud y longitud, esto es, lo hace en <a href="http://es.wikipedia.org/wiki/Coordenadas_polares">coordenadas polares</a>. Además el GPS da mucho más información...<br />- Cómo me da la información el GPS: usa <a href="http://es.wikipedia.org/wiki/NMEA">NMEA</a>, un protocolo de texto separado por comas donde viene la información bien clarita.<br />- Cómo recojo la información del GPS: pues normalmente a través de puerto serie... "pero mi receptor GPS es bluetooth", no te preocupes, tu bluetooth se comportará como un <a href="http://es.wikipedia.org/wiki/Puerto_serie">puerto serie</a>.<br />- Cómo uso la información desde mi aplicación: abres el puerto y vas leyendo linea a linea los datos NMEA, extraes la información y la usas, por ejemplo, para poner un punto en un mapa.<br />- Las coordenadas polares no son útiles para mi: lógico, estamos acostumbrados a trabajar en <a href="http://es.wikipedia.org/wiki/Coordenadas_cartesianas">coordenadas cartesianas</a> (el plano XY de toda la vida). <a href="http://es.wikipedia.org/wiki/Gerardus_Mercator">Alguien </a> ya pensó en eso e inventó UTM, que no es más que un sistema para proyectar latitud y longitud a nuestro querido plano castesiano. En resumen, al final tendremos X e Y y con eso es muy fácil empezar a trabajar<br /><br />- Ya, dicho así es fácil, pero cómo lo hago en la realidad?. Lo primero es tener un GPS, <a href="http://www.activagps.com/GPS-Cable_25.htm">por ejemplo </a>, como mi pc no tiene puerto serie uso un <a href="http://www.activagps.com/_Adaptador-USB-PS2-Hembra_235.htm">conversor USB->serie</a>. De esta forma ya puedo acceder al GPS... cómo? pues con python y los siguientes pasos:<br /><br />- <a href="http://www.python.org/download/">instalo python </a><br />- instalo <a href="http://downloads.sourceforge.net/pywin32/pywin32-210.win32-py2.5.exe?modtime=1159009392&big_mirror=0">Python for Windows</a> extensions si estoy en windows<br />- instalo <a href="http://pyserial.sourceforge.net/">pyserial</a> que nos da acceso al pueto serie.<br />- instalo <a href="http://pygps.org">pygps</a>: este hará el trabajo de interpretar NMEA y proyectar a UTM por nosotros<br /><br />- abro el editor y programo: <br /><br /><br /><font color="#cd5c5c">import</font>&nbsp;serial;<br /><font color="#cd5c5c">from</font>&nbsp;threading <font color="#cd5c5c">import</font>&nbsp;Thread;<br /><font color="#cd5c5c">from</font>&nbsp;NMEA <font color="#cd5c5c">import</font>&nbsp;NMEA;<br /><font color="#cd5c5c">from</font>&nbsp;LatLongUTMconversion <font color="#cd5c5c">import</font>&nbsp;LLtoUTM;<br /><br /><font color="#f0e68c"><b>class</b></font>&nbsp;<font color="#98fb98">GPSPosition</font>(Thread):<br />&nbsp;&nbsp;&nbsp;&nbsp;<font color="#f0e68c"><b>def</b></font>&nbsp;<font color="#98fb98">__init__</font>(self, callback):<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.__init__(self);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#87ceeb">#serial conf</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s = serial.Serial()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.baudrate = 4800<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.port = <span style="background-color: #333333"><font color="#ffffff">&quot;</font></span><font color="#ffa0a0">COM1</font><span style="background-color: #333333"><font color="#ffffff">&quot;</font></span>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.open();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.serial = s<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.nmea = NMEA();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.callback = callback<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self._run = 1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.start();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<font color="#f0e68c"><b>def</b></font>&nbsp;<font color="#98fb98">end</font>(self):<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self._run = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;<font color="#f0e68c"><b>def</b></font>&nbsp;<font color="#98fb98">run</font>(self):&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#f0e68c"><b>while</b></font>&nbsp;self._run:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nmea_data = self.serial.readline();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.nmea.handle_line(nmea_data);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zone, easting, northing = LLtoUTM(23, self.nmea.lat, self.nmea.lon)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.pos = (easting, northing);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.callback(self.nmea.lat,&nbsp;&nbsp;self.nmea.lon, self.pos, self.nmea.mode &gt; 0);<br /><br /><font color="#f0e68c"><b>if</b></font>&nbsp;__name__ == <span style="background-color: #333333"><font color="#ffffff">'</font></span><font color="#ffa0a0">__main__</font><span style="background-color: #333333"><font color="#ffffff">'</font></span>:<br />&nbsp;&nbsp;&nbsp;&nbsp;<font color="#f0e68c"><b>def</b></font>&nbsp;<font color="#98fb98">position</font>(lat, lon, pos, valid_pos):<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#f0e68c"><b>if</b></font>(valid_pos):<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#f0e68c"><b>print</b></font>&nbsp;<span style="background-color: #333333"><font color="#ffffff">&quot;</font></span><font color="#ffa0a0">current position</font><span style="background-color: #333333"><font color="#ffffff">&quot;</font></span>, pos, <span style="background-color: #333333"><font color="#ffffff">&quot;</font></span><font color="#ffa0a0">lat: </font><span style="background-color: #333333"><font color="#ffffff">&quot;</font></span>, lat, <span style="background-color: #333333"><font color="#ffffff">&quot;</font></span><font color="#ffa0a0">&nbsp;lon:</font><span style="background-color: #333333"><font color="#ffffff">&quot;</font></span>, lon;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#f0e68c"><b>else</b></font>:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#f0e68c"><b>print</b></font>&nbsp;<span style="background-color: #333333"><font color="#ffffff">&quot;</font></span><font color="#ffa0a0">invalid position</font><br />&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;gps = GPSPosition(position);<br />&nbsp;&nbsp;&nbsp;&nbsp; <br /><br /><br />ejecuto:<br /><blockquote><br />C:\temp>c:\Python25\python gps.py<br />invalid position<br />invalid position<br />current position: 314418.53, 4575413.58 lat: 41.31 lon: -5.22<br />current position: 314418.53, 4575413.58 lat: 41.31 lon: -5.22<br />current position: 314418.80, 4575413.20 lat: 41.31 lon: -5.22<br /></blockquote><br /><br />- qué es posición inválida? Pues resulta que un GPS no sabe su posición nada más conectarse, necesita un tiempo (que depende de muchas cosas) para tener una posición válida.<br />- Lo hago y no me funciona: sal a la calle porque en casa el GPS no es capaz de coger señal de satélite dentro de casa!!<br />- No me da bien la posición: Lo habitual son 10 metros de error como mucho, normalmente está entre los 2 o 3 metros.<br />- Lo hago pero me oscilan las posiciones: en GPS es bueno pero milagros no hace.<br /><br />Fin, espero no haberme dejado nada.javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-62438464095967289782008-05-21T20:20:00.009+02:002008-05-21T20:46:36.042+02:00falta de profesionalidadTodos los días empresas nos prestan una serie de servicios a cambio de un dinero, sea de forma directa, voy a un bar, pido un café y pago al camarero, o de forma indirecta, voy por una autovía que se financia con los impuestos que pago. Detrás de esas empresas y servicios hay gente, personas y el trabajo de esas personas es lo que al final te llega: el camarero me sirve el café, el ingeniero diseña la carretera y el operario la cubre con asfalto, etc.<br /><br />El problema es que en una empresa hay gente profesional y gente que no lo es y es es la diferencia entre que no te enteres de que te están prestando un servicio a estar quemado e indefenso.<br /><br />Para mi un profesional _no_ es una persona que tenga mucha experiencia o conocimientos en un área o que haga muy bien tal o cual cosa, para mi ser un profesional es ser serio en el trabajo, cumplir con los plazos, tratar de mejorar cada día, hacer frente a los problemas y, sobretodo, hacerse responsable cuando las cosas no se hacen bien. <br /><br />Últimamente veo como la profesionalidad cada vez es menor: los servicios técnicos pasan de ti cuando hay un problema, el fontanero tarda 4 días en venir a repararte el agua caliente, acuerdas un plazo y luego no se cumple, etc, etc... y lo peor, cobran con un verdadero profesional. Estoy harto de ver gente que está en su trabajo viendo pasar el tiempo para que lleguen las 3 de la tarde y saliendo del paso como pueden y con el menor esfuerzo posible, lo veo cada día. <br /><br />Da gusto ver a una persona que es profesional, que le gusta su trabajo y que se preocupa, y aunque me cobre más, lo pago con gusto, solo por el hecho de que sé que ese dinero va para alguien que lo merece y por otro lado porque así estoy participando en una "selección natural". <br /><br />No me extraña que las empresas cada vez busquen gente con "perfiles horizontales", ser serio es algo básico y la carencia de esa característa es mucho más problemática que la de conocimientos técnicos. Sabes que una persona profesional que tiene una responsabilidad va a esforzarse (o apechugar) para sacarlo, independientemente de si sus conocimientos sean bajos en esa materia. Saber J2EE, hibernate, structs, blablabla tiene un precio, poder confiar en que alguien va a tener algo en la fecha, sea lo que sea, no.javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-66682620377801489242008-05-18T00:54:00.003+02:002008-05-18T01:16:36.870+02:00intento de augmented reality"Para quien tiene un martillo todo son clavos".<br /><br />Esta mañana me he levantado pronto y como no tenía sueño y nada que hacer productivo en todo el día, he pensado en hacer algo con mi webcam (tranquilos, no salgo en ningún momento :). Hace unos días vi como con un gps, una webcam y una brújula gracias a google earth conseguían poner una <a href="http://www.navigadget.com/index.php/2008/04/16/enkin-for-android/">capa por encima de la realidad con información la ubicación de diferentes cosas</a>. El proyecto estaba hecho sobre android, en el enlace hay un video muy interesante. Tambien hace relativamente poco vi como un navegador proyectaba información sobre el parabrisas que indicaba qué calle debías coger (no encuentro el link). Con lo cual me planteé por qué no podría hacer lo mismo para agroguía, que el agricultor mirase la cámara y viese por donde había ya pasado superpuesto con la realidad.<br /><br />En esta mañana he hecho un prototipo de <a href="http://en.wikipedia.org/wiki/Augmented_reality">augmented reality </a> de forma que en la pantalla del PC se mostrase información de por donde ya había pasado mostrando la visión en ese momento del conductor unido a un capa generada que se lo indicase.<br /><br />He cogido la webcam, un GPS, python y opengl y he preparado un prototipo. He colocado la webcam arriba en el coche (ver foto) junto al GPS de forma que a medida que el GPS me da información de posición con OpenGL renderizo las zonas por las que ya se ha pasado justo con la cámara en ese lugar. <br /><br /><a href="http://picasaweb.google.es/qualopec/Agroguia02/photo#5201414865598897682"><img src="http://lh4.ggpht.com/qualopec/SC8jQxF1XhI/AAAAAAAAA5o/o7rg5LxHkKk/s800/100_4933.JPG" /></a><br /><br /><br />La prueba no ha quedado demasiado mal teniendo en cuenta que es un prototipo rápido, un video:<br /><br /><object width="425" height="355"><param name="movie" value="http://www.youtube.com/v/8UEhSo6ouCs&hl=en"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/8UEhSo6ouCs&hl=en" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"></embed></object><br /><br />Problemas:<br />- La resolución de la cámara es malísima.<br />- El GPS lleva retardo, de ahí que no estén sincronizados<br />- No he calibrado la cámara adecuadamente, la he puesto a ojo, un fov e inclinación más o menos parecida a la de la webcam<br /><br />Mañana voy a probar con un GPS de 5hz y con menos retardo, además intentaré ajustar mejor la cámara.javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-47747765783118562092008-05-11T19:41:00.003+02:002008-05-11T19:44:44.279+02:00Cube modeling challengeEste fin de semana están haciendo un <a href="http://blenderartists.org/forum/showthread.php?t=124116">concurso de modelado solo con cubos</a>. A priori parece que con pocos cubos no se puede hacer demasiado, sin embargo merece la pena entrar y ver las imágenes. <br /><br />Por mi parte me he animado y he hecho una (lo primero que "modelo" en mi vida)<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_XzuP3e63Ok8/SCcwMxF1XfI/AAAAAAAAA5A/PO9r8g-HNWo/s1600-h/1.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_XzuP3e63Ok8/SCcwMxF1XfI/AAAAAAAAA5A/PO9r8g-HNWo/s320/1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5199177290716896754" /></a><br /><br />si, es triste y oscura.javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-90343125143816215692008-05-04T20:36:00.005+02:002008-05-04T20:54:36.006+02:00cosas que pasan: MGS mobileMe bajo metal gear acid mobile, la versión 3D para probarla en mi móvil y así saber si los shots que había visto hace ya meses eran verdad y el juego prometía tanto, lo paso al móvil y después de defraudarme miserablemente (por ahora, no me gustan los juegos por turnos) me dispongo a decompilarlo para ver un poco qué hacían.<br /><br />ejecuto: <br />"""<br />C:\temp\metal_gear_acid_mobile_3d_n70\src>java -cp jode.jar;C:\WTK22\lib\cldcapi10.jar;C:\WTK22\lib\midpapi20.jar;C:\SonyEricsson\JavaME_SDK_CLDC\PC_Emulation\WTK2\lib\mobile3d.jar;C:\WTK22\lib\mmapi.jar jode.decompiler.Main --dest src meta l_gear_acid_mobile_3d_n70.jar<br />"""<br /><br />y cual es mi sorpresa que no está ofuscado!. Ahí está, el código del juego completito, salvo métodos que están, parece ofuscados, todo el resto de cosas se pueden ver perfectamente. Ahi está, todo el código de 3D, su A* (ver AStarSearchpor ejemplo), la animación a la antigua usanza (quake2 style pero sin interpolar) de Snake (ver JSR184_LoadSnake).<br /><br />Soy fan de decompilar juegos para móvil, es divertidísimo intentar saber qué están haciendo sin ver ni una sola variable (normalmente todo se llama 'a') o ver los formatos de fichero que usan o como cargan las imágenes. Por ahora lo que más he visto ha sido lo de empaquetar recursos y "xorear" parte de los datos, "swapear" el comienzo y fin del fichero (ves cosas como "GNP" de la cabecera de los png)... aunque luego tienes casos como gameloft del cual aún no he conseguido ver como lo hacen, es demasiado difícil de descifrar para un rato.<br /><br />Si algo bueno tiene java (de lo poco) es que se puede decompilar y mirar dentro.javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-20525092065258600042008-05-02T21:38:00.005+02:002008-05-02T23:55:58.065+02:00KML y la privacidadEste post pretender ser dos cosas: primero un pequeño manual de como hacer un servidor de KML con python y <a href="http://www.cherrypy.org/">cherrypy</a> y segundo demostrar qué se puede hacer para recibir feedback indiscriminado usando lo anterior.<br /><br />Conocimientos previos:<br />- cherrypy es un API que permite implementar una aplicación web en dos patadas<br />- <a href="http://code.google.com/apis/kml/documentation/">KML </a>es un formato usando principalmente por Google Earth que sirve como contenedor de información geográfica, puntos de interés, etc, etc<br /><br />KML no deja de ser un xml (*sic*) en el cual cabe de todo puntos, líneas, elementos 3D, animaciones y lo que nos interesa, conexiones a un servidor para obtener datos enumrados anteriormente. De esta forma es posible indicarle en un enlace que vaya a un servidor a buscar datos. Hay un pequeño pero efectivo <a href="http://code.google.com/apis/kml/documentation/kml_tut.html#network_links">tutorial </a>en la página del api de google earth.<br /><br />Tomando ese ejemplo creamos el servidor con cherrypy:<br /><br /><span style="color: rgb(160, 32, 240);">import</span> cherrypy<br /><br /><span style="color: rgb(128, 64, 64);"><b>class</b></span> <span style="color: rgb(0, 128, 128);">Root</span>:<br /> <span style="color: rgb(128, 64, 64);"><b>def</b></span> <span style="color: rgb(0, 128, 128);">get_kml</span>(self, latitude, longitude):<br /> kml = (<br /> <span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(255, 0, 255);">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(106, 90, 205);">\n</span></span><span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><br /> <span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(255, 0, 255);">&lt;kml xmlns="<a href="http://earth.google.com/kml/2.2">http://earth.google.com/kml/2.2</a>"&gt;</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(106, 90, 205);">\n</span></span><span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><br /> <span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(255, 0, 255);">&lt;Placemark&gt;</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(106, 90, 205);">\n</span></span><span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><br /> <span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(255, 0, 255);">&lt;name&gt;Random Placemark&lt;/name&gt;</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(106, 90, 205);">\n</span></span><span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><br /> <span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(255, 0, 255);">&lt;Point&gt;</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(106, 90, 205);">\n</span></span><span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><br /> <span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(255, 0, 255);">&lt;coordinates&gt;%f,%f&lt;/coordinates&gt;</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(106, 90, 205);">\n</span></span><span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><br /> <span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(255, 0, 255);">&lt;/Point&gt;</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(106, 90, 205);">\n</span></span><span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><br /> <span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(255, 0, 255);">&lt;/Placemark&gt;</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(106, 90, 205);">\n</span></span><span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><br /> <span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(255, 0, 255);">&lt;/kml&gt;</span></span><span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><br /> ) %(longitude, latitude)<br /> <span style="color: rgb(128, 64, 64);"><b>return</b></span> kml<br /><br /> <span style="color: rgb(128, 64, 64);"><b>def</b></span> <span style="color: rgb(0, 128, 128);">index</span>(self, directory=<span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">"</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(255, 0, 255);">.</span></span><span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">"</span></span>):<br /> cherrypy.response.headers[<span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">"</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(255, 0, 255);">Content-Type</span></span><span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">"</span></span>] = <span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">"</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(255, 0, 255);">application/vnd.google-earth.kml+xml</span></span><span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">"</span></span> <br /> <span style="color: rgb(128, 64, 64);"><b>return</b></span> self.get_kml(-3.332565,42.600353);<br /><br /> index.exposed = True<br /><br /><span style="color: rgb(128, 64, 64);"><b>if</b></span> __name__ == <span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span><span style="background-color: rgb(242, 242, 242);"><span style="color: rgb(255, 0, 255);">__main__</span></span><span style="background-color: rgb(229, 229, 229);"><span style="color: rgb(0, 0, 0);">'</span></span>:<br /> root = Root()<br /> cherrypy.quickstart(root);<br /><br /><br />El tema web no me va, pero estaba interesado en saber como va este tema en python. Me da la impresión que aún está por detrás de Ruby. He estado mirando <a href="http://turbogears.org/">turbogears </a>y la verdad me ha gustado.<br /><br />En el tutorial ponen un ejemplo de KML que se conecta a un servidor, podríamos cambiar la sentencia Link por lo siguiente:<br /><br />&lt;link&gt;<br /> &lt;href&gt;http://localhost:8080/&lt;/href&gt;<br />&lt;/link&gt;<br /><br />De esta forma al cargar ese fichero en google earth se conectaría al servidor y bajaría kml.<br /><br />Ahora la segunda parte: qué pasa si ese kml es generado por una aplicación y el usuario lo carga en su google earth. Pongamos, por ejemplo, un software de guiado para maquinaria agrícola, en el cual después de haber trabajado se puede guardar ese trabajo a KML para poder verlo más tarde en el PC. Pongamos que ese software escribe algo así dentro del fichero kml:<br /><blockquote><br />&lt;link&gt;<br /> &lt;href&gt;http://servidor.com/?license_no=1234&amp;lat=-3.332565&amp;lon=42.600353&lt;/href&gt;<br />&lt;/link&gt;<br /></blockquote><br /><br />Gracias al número de licencia conoces al usuario y con latitud y longitud conoces la localización de sus parcelas. Eso por no hablar que con unos pocos bytes se puede enviar _de todo_. Tiene su parte mala, pero también su parte buena, se le pueden dar bastantes usos.<br /><br />Por cierto, y no digo que tenga algo que ver, ya he implementado el writer para kml de agroguía :):<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_XzuP3e63Ok8/SBt0iTmt08I/AAAAAAAAA3s/BklMrhhdG28/s1600-h/_bis.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_XzuP3e63Ok8/SBt0iTmt08I/AAAAAAAAA3s/BklMrhhdG28/s320/_bis.png" alt="" id="BLOGGER_PHOTO_ID_5195874727829033922" border="0" /></a>javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-3359399991402015622008-04-27T17:25:00.003+02:002008-04-27T17:28:59.185+02:00partes de un negocio: El negociadorMañana he quedado con una empresa Argentina que está interesada en agroguía. Veremos a ver por donde salimos :).javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-90290339939755785822008-04-24T23:54:00.003+02:002008-04-25T00:01:30.300+02:00Python, generators y pipesPara rematar el artículo del otro día sobre <a href="http://blep.blogspot.com/2008/04/generators-en-python.html">generators en python</a> conviene leerse este otro sobre <a href="http://wordaligned.org/articles/takewhile-drops-one">Pipelined Python</a> que no deja de ser <a href="http://en.wikipedia.org/wiki/Syntactic_sugar">syntactic sugar</a> (como diría <a href="http://www.lacoctelera.com/antoniogarrote">alguno</a>), pero queda la mar de c00l.javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-19319572237117162592008-04-21T23:02:00.003+02:002008-04-21T23:29:49.515+02:00Partes de un negocio: cuando te caen piedras encimaHoy me ha pasado una cosa muy curiosa. Hace cosa de unos meses le vendí un sistema de guiado a una persona, cercana a mi pueblo y que llevaba tiempo detrás de ello. Después de meses intentando que le rebajase el precio y tras repetirle mil veces que es precio único, accedió a comprarmelo al precio original. Se hizo una factura desglosando los conceptos y pasó al circuíto habitual (esto es, a pachas con hacienda)<br /><br />Hoy me llama completamente fuera de si, insultándome y llamándome estafador ¿?. En cosa de dos minutos ha dijo todos los improperios que conocía y alguno más, tras lo cual colgó. En ese momento te preguntas, ¿realmente le habré estafado? porque lo mismo no me he dado cuenta y no le he enviado el sistema... pero es que fui yo con mis propias manos a instalarlo. <br /><br />Lógicamente estaba fuera de sí, en persona parecía una persona amable, así que minutos después le llamé para intentar aclarar las cosas. En esa llamada ya me insultó menos :), aunque mantenía que le había estafado 40€, con pocos argumentos, la verdad. Suerte de facturas, mañana he quedado con él para enseñarle la factura, ver qué ha pasado y dar la cara, cosa que cada vez tengo que hacer más, para bien o para mal.<br /><br />Obviamente, lo primero que espero mañana son unas disculpas, si no es así daré por finalizada la relación con esta persona y listo. Ahora pasa que por un individuo encolerado puede que el boca a boca que tanto nos ha ayudado hasta ahora deje de funcionar tan bien como lo ha hecho. No me preocupa mucho, pero molesta que a pesar de esforzarte en hacer las cosas lo mejor posible haya gente que lo pague con malos modos y amenazas.<br /><br />Cada día tengo más claro que la mayoría de las veces, ante situaciones de este tipo lo mejor es dar la callada por respuesta y mantenerse firme, sobretodo cuando se sabe con cierto grado de seguridad que se tiene la razón. Es muy común la creencia de que "montando el pollo" puedes solcionar algo que no puedes usando argumentos... como dice un refrán que yo me sé: "ante el vicio de pedir ... la virtud de no dar" (como me gusta el refranero)javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-16684057759904763972008-04-20T12:59:00.003+02:002008-04-20T13:11:37.201+02:00¿qué responderías a esta pregunta?Hace un tiempo hablando con el padre de unos amigos, que se puede considerar como el típico emprendedor nato (y además con éxito), sobre las entrevistas de trabajo, me dijo que él al final de cada entrevista de trabajo hacía una pregunta al candidato:<br /><br />""" ¿ por qué crees que mereces más este puesto que el resto de personas ? """<br /><br />Suena a pregunta trampa, mi impresión es que no tiene una respuesta válida absoluta, seguramente dependa del entrevistador. Le pregunté que qué esperaba que le respondiesen y me dijo que no esperaba nada, que solo lo usaba para ver la reacción del individuo.<br /><br />¿qué responderías? ¿qué responderías sin parecer prepotente? ¿y sin parecer que no tienes ni idea? :)javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-11537096811866439132008-04-17T22:15:00.003+02:002008-04-17T22:18:47.602+02:00generators en pythonA través de planet python veo una presentación sobre el uso de <a href="http://www.dabeaz.com/generators/">generators en python</a>. Explica desde lo más básico hasta frikadas insospechadas, merece la pena <a href="http://www.dabeaz.com/generators/Generators.pdf">leerlo</a>, muy ameno e instructivo. No sé, la verdad, si tendrá mucha utilidad real para casos más complejos, pero ahí queda.javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-81947114367820428932008-04-14T23:08:00.003+02:002008-04-14T23:43:01.146+02:00¿Nos viene bien la crisis?Asisto con curiosidad a la llegada de la esperada crisis, las inmobiliarias cierran las puertas (eso sí, con los bolsillos hasta arriba) y todo el mundo a la espera de ver que pasa.<br /><br />Entre cifras de IPC, paro y PIB ya se empiezan a escuchar cosas de sentido común, tenemos que ponernos las pilas en tecnología y no depender tanto de la contrucción. Y ojo, no lo digo yo, lo dicen los analistas políticos (esos de las tertulias todo serias de la radio) e incuso los propios políticos. Es tarde, ya la hemos cagado, pero más vale tarde que nunca, llevamos tiempo viendo como el sector va mejorando, se ven mejoras sueldos (algunos informáticos incluso llevan coches de primera mano :), se valoran más algunos puestos, imagino que el dinero que ha salido de la construcción ha ido migrando a otros sectores. <br /><br />Esperemos que no haya otra burbuja .com (esta se llamaría, burbuja 2.0 o burbuja social) y nos, hablando en plata, joda vivos. Sea como sea algo positivo seguro que sacamos, porque no creo que podamos estar peor de lo que hemos estado.javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-65907069779693770332008-04-13T20:19:00.005+02:002008-04-13T20:40:57.234+02:00El peligro de las 100 tareasToda la vida he creído en los refranes populares, son la experiencia plasmada en frases contundentes y fáciles de recordar. Quien no ha oido alguna vez lo de "perro ladrador...", "más vale pájaro en mano..." y lo mejor (o peor, según se mire) quien no se ha tenido que aplicar algunos de ellos más de una vez.<br /><br />El refrán de hoy es "el que mucho abarca, poco aprieta". Cada vez que reviso los feeds a los que esoy suscrito encuentro todos los días varios temas por los cuales estoy interesado, cada uno diferente, sin ir más lejor en esta misma tarde he encontrado varias cosas interesantes, para empezar un <a href="http://code.google.com/p/sv-subversion/wiki/CommandReference">una serie de utilidades para la gestión de ramas en subversion</a>(a raíz de leer <a href="http://blog.doughellmann.com/2008/04/shell-history-jigs-subversion.html">este meme</a>) o un hilo interesantísimo sobre <a href="http://www.gpspassion.com/forumsen/topic.asp?TOPIC_ID=109246&#723155">gps diferencial usando GPS de bajo coste en gpspassion</a>, el uso que hacen los agricultores de agroguía y como están creados los niveles del starfox64 ... :).<br /><br />(viva blender):<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_XzuP3e63Ok8/SAJRq2J5OQI/AAAAAAAAA3c/BGABALQeKzw/s1600-h/n64_shot.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp0.blogger.com/_XzuP3e63Ok8/SAJRq2J5OQI/AAAAAAAAA3c/BGABALQeKzw/s320/n64_shot.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5188799517217601794" /></a><br /><br />(ha quedado chula la foto):<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_XzuP3e63Ok8/SAJS9GJ5ORI/AAAAAAAAA3k/3eF3vyxg3ss/s1600-h/P1000583.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_XzuP3e63Ok8/SAJS9GJ5ORI/AAAAAAAAA3k/3eF3vyxg3ss/s320/P1000583.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5188800930261842194" /></a><br /><br />Total, que al final he mirado 4 ó 5 cosas, pero tengo la sensación de que no he sacado nada en claro, nada más que he curioseado. Me gustaría dejar a un lado algunas de las cosas, pero no puedo!!. Mirando hacia atrás (que bonita es la trazabilidad) me doy cuenta que mejoro en cada uno de los aspectos, pero mi rendimiento es menor porque me cargo de más tareas (será por aquello de los cambios de contexto).<br /><br />Conclusión: qué importante es tener claro lo que uno quiere (y puede) hacer y cuanto de bien tiene poder escribirlo para aclarar las ideas.javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-39891868921154141192008-04-05T15:34:00.002+02:002008-04-05T15:49:54.272+02:00El infinito no es demasiado grandeCuando desarrollas por narices tienes que poner un límite, por desgracia aún no tenemos máquinas con memoria infinita (aunque en pyro digan lo contrario :P). En agroguía había puesto un límite de área de 128x128km, espacio, a priori, mucho más que suficiente para cualquier agricultor, incluso para agricultores en argentina que tienen grandes extensiones. <br /><br />Ayer me llamó un agricultor comentándome que tenía problemas y después de hacerle unas cuantas preguntas le pregunté que cuanto había andado desde que inició el programa, la respuesta soprendente (era jueves):<br />""" pues lleva encendido desde el jueves pasado, entonces habré andado unos 200km"""<br /><br />Esto es todo un record, 1 semana el software cogiendo un dato por segundo y aún no había cascado. <br /><br />Moraleja: nunca creas que el límite supeior es suficientemente grande.javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-23190990526297828402008-04-01T00:08:00.003+02:002008-04-01T00:13:27.517+02:00Diseño de un motor 3D modernoSé que muchos de los que leeis estas líneas tambien lo haceis con <a href="http://www.codepixel.com">codepixel </a>(y si no es un buen momento para empezar). El caso que han empezado con una serie de artículos sobre el <a href="http://www.codepixel.com/content/view/5135/34/">diseño de un motor 3D moderno</a> y no podía dejar pasar la ocasión de linkar, por lo interesante del artículo y por la calidad de los 3 autores.<br /><br />No me gusta poner post de solo links, pero creo que este merece la pena. De momento ya han publicado el primero de una serie, y es una pequeña introducción que en resumen ha dejado claro que el modelo de datos debe ser bueno (como en toda aplicación). Estaré atento al resto de artículos.javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-89057751764361236302008-03-30T18:31:00.004+02:002008-03-30T20:15:24.485+02:00Re: Advergaming: Amor y odioLeo en el blog de <a href="http://koalaensalamanca.blogspot.com/2008/03/advergaming-amor-y-odio.html">juanma zarza (aka mrkoala)</a> una reflexión bastante interesante acerca del advergaming y su fama entre el público en general.<br /><br />Y es que es muy raro que nadie se fije en uno de esos juegos "cutres" que publicitan una marca se vean en ninguna parte. Es cierto que hay mucha mierda y es cierto que muchos juegos móvil no tienen suficiente calidad. Eso sí, vemos a diario rumores sobre posibles juegos de EA o de gameloft (veer <a href="http://www.anaitgames.com/?s=gameloft&x=0&y=0">anaitgames</a>, por poner un ejemplo) que sí, son unas super potencias en cuanto a juegos para móvil, pero que en mi opinión están super-valoradas, y pongo un ejemplo.[Y no quiero no hablar de la calidad de muchos de los juegos de nintendo DS (sobretodo) que se analizan...]<br /><br />El ejemplo es uno de los últimos juegos de unkasoft en el que he participado directamente, que nadie conoce, pero que ya está por ahí. Se trata de una promoción llamada <a href="http://www.idrinks.es/#">idrinks</a> para diferentes bebidas alcohólicas. Bien, el juego está desarrollado en unos 8 días reales (en medio estuvo la navidad), esto es, desde 0 se crea un juego, gráficos, código y música... y todo eso para 450 móviles. Ahora pregunto, tiene eso menos mérito que crear un juegazo en 8 meses como hace gameloft? en 8 meses el equipo de unkasoft (en los juegos todos ponemos nuestro grano de arena) ha creado unos juegos de una calidad muy alta para los tiempos de desarrollo en los que nos movemos. Es tanta la diferencia? <br /><br />¿Qué pasa? pues que somos así, tanto los que crean las noticias, como quienes las escriben. Muy poco se han preocupado los blogs o portales de noticias españolas por unkasoft (y otras muchas que trabajan en la sombra), a pesar de que los juegos que se hagan sean de una calidad altísima (sobretodo últimamente) incluso con licencias de películas que han estado en taquilla (rec, donkey xote), etc, etc. Eso sí, unkasoft tampoco puede/quiere/tiene tiempo de darle un poco más de bombo y publicitar un poco más los juegos que hace... a veces los <a href="http://es.wikipedia.org/wiki/NDA">NDA</a> hacen un flaco favor a una empresa.<br /><br />Me queda el consuelo de ver como cada día vamos mejorando nuestros juegos (a algunos puedes <a href="http://unkasoft.mobi/">jugar gratis en unkasoft gamespace</a>), sobretodo viendo los bocetos y desarrollos que tenemos actualmente en recamara.<br /><br />Más vale pájaro en mano que ciento volando: Menos rumores de iphone y más noticias de verdad.javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-8368927575715725592008-03-29T21:56:00.003+01:002008-03-29T22:58:51.943+01:00Serializando en C++: implementación quick and dirtySi hay una cosa que me molesta es tener que repetir código o funcionalidad. Cuando estás programando te das cuenta que a veces hay partes de funcionalidad que hacen más o menos lo mismo. <br /><br />Hay veces que tienes que implementar algo y cuando lo haces por gusto pues puedes pararte a implementar un mega sistema de serialización que te mueres, pero cuando tienes que hacer algo que sabes que no va a salir de ahí nunca te da igual la orientación a objetos. Esta es una lucha que siempre he tenido con mucha gente, el sobrediseño, el sobre*, es decir, la tendencia a tener que aplicar los patronos existentes, la necesidad de usar una metología o un paradigma concreto, pero eso es otra historia.<br /><br />Necesitaba guardar y cargar datos y no me apetecía andar modificando el loader cada vez que modificase el writer... así que (formato patrocinado por vim):<br /><br /><font face="monospace"><br><font color="#cd5c5c">#include </font><br /><font color="#ffa0a0">&lt;stdio.h&gt;</font><br><br><font color="#bdb76b"><b>class</b></font>&nbsp;A <br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<font color="#f0e68c"><b>public</b></font>:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#bdb76b"><b>int</b></font>&nbsp;a;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#bdb76b"><b>int</b></font>&nbsp;b;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#bdb76b"><b>float</b></font>&nbsp;c;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#bdb76b"><b>typedef</b></font>&nbsp;<font color="#bdb76b"><b>unsigned</b></font>&nbsp;<font color="#bdb76b"><b>int</b></font>&nbsp;(*serialize_t)(<font color="#bdb76b"><b>void</b></font>*, <font color="#bdb76b"><b>unsigned</b></font>&nbsp;<font color="#bdb76b"><b>int</b></font>, <font color="#bdb76b"><b>unsigned</b></font>&nbsp;<font color="#bdb76b"><b>int</b></font>, <font color="#bdb76b"><b>FILE</b></font>* f);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#bdb76b"><b>void</b></font>&nbsp;Save(<font color="#bdb76b"><b>FILE</b></font>* f) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Serialize(f, (serialize_t)fwrite);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#bdb76b"><b>void</b></font>&nbsp;Load(<font color="#bdb76b"><b>FILE</b></font>* f) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Serialize(f, fread);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#bdb76b"><b>virtual</b></font>&nbsp;<font color="#bdb76b"><b>void</b></font>&nbsp;Serialize(<font color="#bdb76b"><b>FILE</b></font>* f, serialize_t ser)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br><font color="#cd5c5c">#define SER(x) ser(&amp;(x), </font><font color="#f0e68c"><b>sizeof</b></font><font color="#cd5c5c">(x), </font><font color="#ffa0a0">1</font><font color="#cd5c5c">, f)</font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SER(a);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SER(b);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SER(c);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>};<br><br><br><font color="#bdb76b"><b>int</b></font>&nbsp;main()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<font color="#bdb76b"><b>const</b></font>&nbsp;<font color="#bdb76b"><b>char</b></font>* fn = <font color="#ffa0a0">&quot;test.bin&quot;</font>;<br>&nbsp;&nbsp;&nbsp;&nbsp;<font color="#bdb76b"><b>FILE</b></font>* f = fopen(fn, <font color="#ffa0a0">&quot;wb&quot;</font>);<br>&nbsp;&nbsp;&nbsp;&nbsp;A a;<br>&nbsp;&nbsp;&nbsp;&nbsp;a.a = <font color="#ffa0a0">11</font>;<br>&nbsp;&nbsp;&nbsp;&nbsp;a.b = <font color="#ffa0a0">22</font>;<br>&nbsp;&nbsp;&nbsp;&nbsp;a.c = <font color="#ffa0a0">33.33f</font>; <br>&nbsp;&nbsp;&nbsp;&nbsp;a.Save(f);<br>&nbsp;&nbsp;&nbsp;&nbsp;fclose(f);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;A c;<br>&nbsp;&nbsp;&nbsp;&nbsp;f = fopen(fn, <font color="#ffa0a0">&quot;rb&quot;</font>);<br>&nbsp;&nbsp;&nbsp;&nbsp;c.Load(f);<br>&nbsp;&nbsp;&nbsp;&nbsp;printf(<font color="#ffa0a0">&quot;a: </font><font color="#ffdead">%d</font><font color="#ffa0a0">, b </font><font color="#ffdead">%d</font><font color="#ffa0a0">, c </font><font color="#ffdead">%f</font><font color="#ffdead">\n</font><font color="#ffa0a0">&quot;</font>, c.a, c.b,c.c);<br>&nbsp;&nbsp;&nbsp;&nbsp;fclose(f);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<font color="#f0e68c"><b>return</b></font>&nbsp;<font color="#ffa0a0">0</font>;<br>}<br></font><br /><br />guarro, poco elegante, rompe todos los paradigmas, pero rápido, funcional y efectivo :Djavi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-18833439389373277672008-03-26T21:48:00.004+01:002008-03-26T21:54:30.902+01:00agroguía 2.0Sí, ahora que estamos con la fiebre de la 2.0, de la web social, de facebook, de twitter y de todas esas cosas para las que todavía no he encontrado utilidad, resulta que ahora los usuarios de agroguía generan y suben su propio contenido a la web.<br /><br />Nosotros frecuentemente subimos videos para tener a la gente interesada y "enganchada" en cierto modo. Hay uqe tener en cuenta que el target de usuarios de esta aplicación no soy muy dados a las nuevas tecnologías (aunque más de lo que se cree y me creía debo decir. Resulta que buscando un poco por youtube sobre sistemas similares me encuentro con que un cliente nuestro se ha grabado en video usando agroguía y lo ha subido... :).<br /><br /><object width="425" height="355"><param name="movie" value="http://www.youtube.com/v/fFoDeHtoBNk&hl=en"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/fFoDeHtoBNk&hl=en" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"></embed></object><br /><br />Estyo terminando algunas de las nuevas features de agroguía, en unos días subiré unos videos mostrando como funcionan... eso siempre que sea capaz de hablar despacio, no hay nada peor que grabarse y comprobar que lo que te han repetido durante años es verdad, hablo a toda leche, me como palabras y me explico mal :).<br /><br />Ya lo estoy viendo, de aquí a un año los agricultores subiendo sus parcelas, con sus tiempos, sus rendimientos, intentando estar en el top10 :)javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-27926873280906134352008-03-23T21:43:00.005+01:002008-03-29T23:02:39.852+01:00clase transaccional en pythonDespués de unas "largas" vacaciones sin tocar el pc (apenas recuerdo donde están las teclas :) apetece leerse algún buen artículo, como por ejemplo uno de <a href="http://www.harald-hoyer.de/linux/pythontransactionclass">clases transaccionales en python</a>.<br /><br />Interesante artículo por varios motivos:<br /> <br />- La propia clase, personalmente creo que puede ser bastante útil, luego pongo un ejemplo<br />- El uso de introspection (o reflexion o como quiera que se llame) en python. Simple y efectivo<br />- La explicación, paso a paso, y el código final con sus test unitarios. <br /><br />Este es el típico ejemplo de pequeña clase que se complica y que termina siendo un verdadero infierno si no se tienen claros los contratos. Personalmente he tenido muy malas experiencias con clases en teoría simples, pero que dado su uso intensivo terminan por matar una aplicación. Por ejemplo, una clase tan simple como un vector, que en resumen no dejan de ser 4 métodos, es usada en todo el código, seguramente por varias personas que no tendrán ni idea de como está implementada (con razón), de la cual se pueden sacar unas cuantas "condiciones de contorno" que pueden hacer que la aplicación fracase estrepitosamente ya que cada persona puede decir: "es que yo pensé que funcionaba así"<br /><br />En cuanto a la clase transaccional, se me ocurre un uso muy práctico. Estamos acostumbrados a ver diálogos wizards y configururaciones en todas las aplicaciones. El usuario cambia valores, toquetea y al final pulsa sobre 'Ok' o sobre 'Cancel'. El planteamiento de la lógica del diálogo podría ser el siguiente:<br /><br />- al comienzo del diálogo se hace una copia de los datos.<br />- se modifica la copia en función de los eventos de usuario<br />- si el usuario acepta, se vuelcan los cambios que están en la copia en los datos originales.<br /><br />Queda mucho más elegante el siguiente funcionamiento:<br />- se modifican los datos (que implementan el modelo transacional) en función de los eventos de usuario. <br />- si el usuario cancela se hace rollback.<br /><br />Pero es que además, con este modelo tenemos solucionado el típico undo que tantos quebraderos de cabeza da de forma "transparente" (de hecho implementa el típico patron memento). Si unes esto a una serialización como dios manda ya tienes solucionado medio modelo de datos de la aplicación :). <br /><br />Eso sí, la clase tiene varios problemas, por lo menos dos que yo vea:<br />- si hay atributos muy pesados en 4 commits te has zumbado unos megas de ram y estos lenguajes dinámicos no son precisamente ahorradores en este aspecto<br />- a poco mal que hagas el modelo de datos habrá variables que no te interese, perdón, que no deban guardar el estado. Pasa exactamente lo mismo que con la serialización.javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-85435259727789616552008-03-12T22:29:00.003+01:002008-03-12T22:41:31.093+01:00Los aerogeneradores como farosLo bueno que tiene hacer de comercial es que a veces te encuentras con cosas curiosas. Resulta que el otro día fui a <a href="http://maps.google.es/maps?f=q&hl=es&geocode=&q=torrelobaton&ie=UTF8&ll=41.673296,-5.064998&spn=0.023529,0.051498&t=h&z=15">Barruelos del Valle (google maps)</a> y curiosamente el agricultor interesado era el alcalde del pueblo. Charlando con él acerca de algunos temas técnicos, salió el tema de los aeorgeneradores aprovechando que al lado había un parque eólico y le pregunté para qué servían esas luces que tienen en la parte superior.<br /><br />Resulta que cada molino tiene una luz que parpadea periódicamente y la verdad es que incluso a plena luz del día ya se veía con claridad. El chico me comentó que de noche era un verdadero infierno, que se hacía de día cada medio segundo... No me lo creía hasta que he podido comprobar que desde mi pueblo, a unos 50kms, (y más lejos) puedo ver las luces. Si pasas por la A-62 o la A-6 lo podrás ver desde bastante lejos.<br /><br />Otra cosa que me llamó la atención es que las luces de los aerogeneradores están sincronizadas. Lógicamente nadie se gasta dinero en sincronizar las luces para nada. Según me comentaron, estas luces se usan como faros para loa aviones. Cada parque eolico tiene un periodo diferente, de forma que viendo los periodos es posible "triangular" y saber donde se está.<br /><br />Una curiosidad técnica y un martirio para los habitantes cercanos al parque.javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-60599080386545509362008-02-28T20:34:00.003+01:002008-02-28T20:56:15.637+01:00java... oh noJava no me gusta y no me gusta por muchas cosas que ya he comentado, odio ese quiero pero no puedo, ni es totalmente dinámico ni totalmente dinámico, ni es multiplataforma ni deja de serlo... y es que java ahora mismo está a medio camino entre C++ y otros lenguajes de alto nivel como python, ruby o C#.<br /><br />El caso es que llevo unos días trabajando con python para diferentes tareas de administración y automatización y te me doy cuenta que soy mucho más productivo y puedo dedicar el tiempo a otras cosas que no sean poner try catch, casts e interminables líneas para crear una simple lista.<br /><br />A nadie que tenga cierta experiencia en programación se le escapa que las listas, maps, sets y demás son estructuras de datos básicas, que se usan para casi absolutamente todo y por tanto que el lenguaje los tenga "siempre a mano" y mantenga cierta simplicidad en su uso es vital. Por ejemplo, en java para filtrar una lista tienes lo siguiente:<br /><br /><blockquote><br />void filter(List<type> src) {<br /> List<type> li = new ArrayList<type>();<br /> for (Type t: src) {<br /> if( t != null)<br /> li.add(t);<br /> }<br />}<br /></blockquote><br /><br />Menudo coñazo, es que dan ganas de morir según lo tecleas... la misma cosa en python:<br /><blockquote><br />li = [t for t in src if t != None];<br /></blockquote><br /><br />Una cosa tan simple se convierte en algo tedioso, cuando tienes que hacer bastantes operaciones con listas, maps, etc, ya es el súmun. Y no se trata de apelotonar todo en una línea, al final eso es una bomba de relojería para un proyecto, pero tampoco estamos hablando de un tema complejo, es una simple lista que usamos para absolutamente todo. Ya no digo nada cuando veo frameworks como ruby on rails, con el que recientemente he tenido algo más de contacto.javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-30470080531986873242008-02-25T21:29:00.003+01:002008-02-25T21:55:39.716+01:00un año en UnkasoftMañana hace ya un año que entré a trabajar en <a href="http://www.unkasoft.com/">Unkasoft</a>. El resumen del año es muy positivo, he aprendido mucho, he conocido a gente muy buena, he cumplido uno de los sueños que tenía desde pequeño, trabajar en una empresa de videojuegos y un montón de cosas más. <br /><br />Lo mejor de todo es que la cuerda no se acaba, todos los días sugen cosas nuevas que investigar y que desarrollar, algo que considero fundamental en una empresa y que tendré muy en cuenta a lo largo de mi vida profesional. Si de algo me ha servido este año es para darme cuenta de que es imprescindible tener retos y metas que sirvan como alimento diario, además de estar en un entorno que lo favorezca.<br /><br />Nada, lo dicho, a <a href="http://unkasoft.mobi/">jugar con el móvil se ha dicho... ehh!! que es gratis!!</a>javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-58619630364550470272008-02-12T21:14:00.001+01:002008-03-29T23:03:19.400+01:00Partes de un negocio: la trazabilidadSigo con la mini-serie con el original título "partes de un negocio". Esta vez voy a hablar de algo más cercano a lo técnico, esto es, no me basaré en suposiciones ni en historietas del abuelo :).<br /><br />Los desarrolladores tenemos la costumbre de incluir errores en las aplicaciones, algunos dicen que son bugs, otros pequeños errores... por lo general cuando un error llega a una versión release quiere decir que vas a perder dinero y es proporcional a la gravedad y al número de licencias vendidas.<br /><br />Pongamos un caso real, yo vendo un sistema con un software a 10 personas, todo parece funcionar perfecto, así que incluyo algunas mejoras y vendo esta nueva versión a otras 10. Pasa un año y resulta que una de esas personas te reporta un error. No pasa nada, un error aislado no es un error, es un contratiempo... sin embargo te llama otro y te cuenta lo mismo, empiezas a sospechar. Haces tus pruebas y todo parece funcionar bien, por tanto echas la culpa al usuario. Por experiencia, cuando te llaman dos personas con el mismo problema el fallo es tuyo, con lo cual ponte a buscar el error como un loco.<br /><br />Comos unos hachas desarrollando reproducimos el error con los ficheros de log que hemos guardado (somos unos bestias y no se nos escapa ni un dato), vemos que es una buena metedura de pata, lo arreglamos y se lo corregimos a los clientes que han llamado.<br /><br />¿Cual es el problema? De las 20 versiones que hemos vendido, cuántas tienen el error y cuantas no? Les estará funcionando mal al resto y no se han dado cuenta? solo hemos vendido 3 licencias de esa versión? <br /><br />Para tener esto controlado hay dos reglas muy simples que hay que seguir:<br /><br />- <span style="font-weight:bold;">Congela tú código y marcalo</span>: da igual que sea un cambio de un espacio en una línea de código, un cambio en un script de compilación... lo que sea, lo marcas y lo congelas de alguna forma (con ficheros zip, con tags en <a href="http://blep.blogspot.com/2006/02/usa-subversion-por-favor.html">subversion</a>, lo que sea). <br />Corolario: Ten siempre a mano y usables TODAS las versiones. Esto es, en cualquier momento pueden venir unos datos de una versión y tienes que sacarla del baúl y usarla. Hay que ser muy muy estricto con esto, no hay que dejar pasar ni un solo cambio sin marcar. <br />Corolario: todos los datos que genere la aplicación deben llevar en alguna parte la versión que corresponde.<br /><br />Si no haces esto vas a perder mucho tiempo en encontrar la versión que usaste, no vas a saber si es un error propagado por diferentes versiones, es decir, estás en pelotas.<br /><br />Como ejemplo yo mantengo ahora mismo 3 ramas de desarrollo mas una estable, en las ramas pruebo cosas sin desestabilizar la estable. Además, todos los datos que recojo de mis pruebas o de clientes los tengo también en el repositorio convenientemente marcadas y asociadas a las versiones de las que partieron, todo eso junto a información de las pruebas. <br /><br />- <span style="font-weight:bold;">Mantén un mapeo cliente-versión</span>: parece de sentido común, pero se suele dejar porque es un coñazo. Además ten un mapeo de cosas que creas que nunca van a afectar... por ejemplo, nosotros guardamos la versión del software, marca, modelo y números de serie de todos los componenetes, marca del tractor, zona de trabajo, metros de las máquinas que tiene, cuantos tractores tiene la persona, etc, etc.<br />De esa forma puedes obtener una relación directa si te llama más de una persona.<br /><br />Subversion es una herramienta básica para cualquier persona que use un PC y tenga que mantener versiones de datos, la gente se rie cuando le dices que usas subversion hasta para el currículum, pero es una de esas herramientas que deberían venir por defecto instaladas en el sistema operativo. Con un sistema de control de versiones con muy poco trabajo tendrás todo etiquetado, con un histórico envidiable, acceso a cualquier cosa, puedes ver el diferencial, mantener copias de seguridad... no es necesario mantener un tracker ni complejos scripts si no tienes demasiado tiempo como es mi caso. No me cansaré de hablar bien de subversion.javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-60207357842546304132008-02-05T00:34:00.000+01:002008-02-05T00:42:55.602+01:00qué se siente cuando te quieren robar?A mi me han robado pocas veces, pero la verdad es una sensación mala, te sientes desprotegido y sin saber muy bien qué hacer. Sin embargo hay veces que ver que te intentan robar es algo que reconforta y que te anima a seguir.<br /><br />Me encuentro con lo siguiente en los <a href="http://foro.todopocketpc.com/showthread.php?p=1160298">foros de todo Pocket PC</a>. Sí señor, alguien está interesado en robar agroguía, eso quiere decir que a la gente le está gustando... :).<br />De todas formas no es la primera vez, ya he visto a gente buscandolo por los foros, por ejemplo en <a href="http://vagos.es/showthread.php?t=192085&page=419">este</a> y lo más patético, <a href="http://www.agroterra.com/foro/foros/forum_posts.asp?TID=5483">en este </a>que el fulano tiene los cojonazos de pedirlo incluso sabiendo que el autor escribe líneas más arriba :)<br /><br />Lo más será el día que estén en el emule :)javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.comtag:blogger.com,1999:blog-5644592.post-70804382098124979702008-02-03T20:58:00.000+01:002008-02-03T21:42:45.248+01:00Test unitarios en C++: guía rápidaPropongo un contexto real: estamos programando bajo una plataforma <strike>asquerosa</strike> difícil de trata, pongamos una PDA. Tenemos un módulo, por ejemplo una clase que carga un fichero de configuración, que queremos probar y no queremos crear un programa específico para PDA que use la clase, cargue un fichero que hemos tenido que copiar y luego muestre resultados. Es mucho más cómodo hacerlo haciendo un "make" desde la línea de comandos.<br /><br />Hay diferentes frameworks para hacer test unitarios en C++, cada uno con sus ventajas, se puede ver un análisis (bastante pragmático) en <a href="http://www.gamesfromwithin.com/articles/0412/000061.html">games from whitin</a>. Yo he escogido <a href="http://www.gamesfromwithin.com/articles/0512/000103.html">cppunitlite</a>, por las siguientes razones:<br /><br />- tiene todo lo que necesito: fixtures, asserts <br />- no tiene dependencias, se compila con un solo make y a funcionar<br />- apenas son 10 ficheros<br /><br />Una vez bajado para arrancar a funcionar solo es necesario tener instalado un compilador. Para windows me gusta usar <a href="http://www.mingw.org/">Mingw </a>ya que además trae make. Además conviene tener instaladas las <a href="http://unxutils.sourceforge.net/">herramientas de línea de comandos de linux para windows</a> (si no las tienes intaladas ya mereces un castigo).<br /><br />Bueno, vamos a crear el primer test unitario (formateo patrocinado por el conversor a HTML de vim):<br><font color="#87ceeb">//</font><br><font color="#cd5c5c">#define GLOBAL_CONFIGURATION </font><font color="#ffa0a0">&quot;configuration.txt&quot;</font><br><font color="#cd5c5c">#define DEBUG_INFO</font><br><font color="#cd5c5c">#include </font><font color="#ffa0a0">&quot;lib/TestHarness.h&quot;</font><br><font color="#cd5c5c">#include </font><font color="#ffa0a0">&quot;../../src/configuration.h&quot;</font><br><br><br><font color="#bdb76b"><b>class</b></font>&nbsp;ConfigurationFixtureSetup : <font color="#f0e68c"><b>public</b></font>&nbsp;TestSetup<br>{<br><font color="#f0e68c"><b>public</b></font>:<br>&nbsp;&nbsp;&nbsp;&nbsp;<font color="#bdb76b"><b>void</b></font>&nbsp;setup()<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entries.push_back(conf_entry(<font color="#ffa0a0">&quot;LOG_PROY_DATA&quot;</font>,<font color="#ffa0a0">0</font>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entries.push_back(conf_entry(<font color="#ffa0a0">&quot;GGA&quot;</font>,<font color="#ffa0a0">1</font>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entries.push_back(conf_entry(<font color="#ffa0a0">&quot;GGL&quot;</font>,<font color="#ffa0a0">1</font>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entries.push_back(conf_entry(<font color="#ffa0a0">&quot;RMC&quot;</font>,<font color="#ffa0a0">1</font>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entries.push_back(conf_entry(<font color="#ffa0a0">&quot;RMZ&quot;</font>,<font color="#ffa0a0">1</font>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entries.push_back(conf_entry(<font color="#ffa0a0">&quot;VTG&quot;</font>,<font color="#ffa0a0">0</font>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entries.push_back(conf_entry(<font color="#ffa0a0">&quot;GSA&quot;</font>,<font color="#ffa0a0">1</font>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entries.push_back(conf_entry(<font color="#ffa0a0">&quot;LOG_REAL_DATA&quot;</font>,<font color="#ffa0a0">0</font>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entries.push_back(conf_entry(<font color="#ffa0a0">&quot;SMOOTH_DIR&quot;</font>,<font color="#ffa0a0">0</font>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entries.push_back(conf_entry(<font color="#ffa0a0">&quot;RATE&quot;</font>,<font color="#ffa0a0">10</font>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entries.push_back(conf_entry(<font color="#ffa0a0">&quot;THRESHOLD_VEL&quot;</font>,<font color="#ffa0a0">0</font>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entries.push_back(conf_entry(<font color="#ffa0a0">&quot;SHOW_CALC_DIR&quot;</font>,<font color="#ffa0a0">0</font>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entries.push_back(conf_entry(<font color="#ffa0a0">&quot;SHOW_VELOCITY&quot;</font>,<font color="#ffa0a0">0</font>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entries.push_back(conf_entry(<font color="#ffa0a0">&quot;SHOW_SAT_INFO&quot;</font>,<font color="#ffa0a0">1</font>));<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<font color="#bdb76b"><b>void</b></font>&nbsp;teardown()<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entries.resize(<font color="#ffa0a0">0</font>);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<br><font color="#f0e68c"><b>protected</b></font>:<br>&nbsp;&nbsp;&nbsp;&nbsp;Configuration fixture;<br>&nbsp;&nbsp;&nbsp;&nbsp;<font color="#bdb76b"><b>struct</b></font>&nbsp;conf_entry <br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conf_entry(<font color="#bdb76b"><b>const</b></font>&nbsp;<font color="#bdb76b"><b>char</b></font>&nbsp;*n, <font color="#bdb76b"><b>int</b></font>&nbsp;v):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;varName(n),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value(v) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#bdb76b"><b>const</b></font>&nbsp;<font color="#bdb76b"><b>char</b></font>* varName;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#bdb76b"><b>int</b></font>&nbsp;value;<br>&nbsp;&nbsp;&nbsp;&nbsp;};<br>&nbsp;&nbsp;&nbsp;&nbsp;std::vector&lt;conf_entry&gt; entries;<br>};<br><br><br><br><font color="#87ceeb">/*</font><font color="#87ceeb">*</font><br><font color="#87ceeb">&nbsp;</font><font color="#87ceeb">*/</font><br>TESTWITHSETUP (ConfigurationFixture,Test_ReadConf)<br>{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<font color="#f0e68c"><b>for</b></font>(<font color="#bdb76b"><b>int</b></font>&nbsp;i = <font color="#ffa0a0">0</font>; i &lt;&nbsp;&nbsp;entries.size(); ++i) <br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#bdb76b"><b>int</b></font>&nbsp;value;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CHECK(Configuration::GlobalConfiguration()-&gt;getValue(entries[i].varName, value));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(<font color="#ffa0a0">&quot;</font><font color="#ffdead">%s</font><font color="#ffa0a0">&nbsp;-&gt; </font><font color="#ffdead">%d</font><font color="#ffdead">\n</font><font color="#ffa0a0">&quot;</font>,entries[i].varName, value);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CHECK( value == entries[i].value);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br><br /><br />En resumen lo que hace es cargar un fichero de configuración y testear que todos los valores cargados son los esperados. <br /><br />Es un test muy simple y se puede lanzar desde la línea de comandos después (o antes) de la compilación sin necesidad de meterlo en la PDA, que es un coñazo terrible.<br /><br /><br /><br />Si de verdad quieres saber un detalle como hacer test unitarios en C++ recomiendo que leas <a href="http://www.lawebdejm.com/prog/cpp/cppunit.html">Pruebas unitarias con C++</a>, extenso y completo artículo de como hacer test en C++ con CPP unit escrito pon JM, un compañero de Unkasoft.javi santanahttp://www.blogger.com/profile/07638486113933454853noreply@blogger.com