<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2993584829070686554</id><updated>2024-09-21T23:33:49.853+02:00</updated><category term="Android"/><category term="Symfony2"/><category term="PHP"/><category term="Linux"/><category term="Testing"/><category term="Agile"/><category term="Ant"/><category term="Capifony"/><category term="Integración Continua"/><category term="Java"/><category term="Jenkins"/><category term="Management"/><category term="PHPUnit"/><category term="Redes"/><category term="SSH"/><category term="Scrum"/><category term="Web services"/><category term=".NetMF"/><category term="ARP"/><category term="AccountManager"/><category term="BDD"/><category term="BOOTP"/><category term="Base de datos"/><category term="Behat"/><category term="Bitbucket"/><category term="Broadcast"/><category term="Checkstyle"/><category term="ContentProvider"/><category term="DHCP"/><category term="DPWS"/><category term="Dispatcher"/><category term="Doctrine"/><category term="Eclipse"/><category term="Emma"/><category term="FOSUserBundle"/><category term="FindBugs"/><category term="Fixtures"/><category term="GWT"/><category term="Git"/><category term="JUnit"/><category term="LaTeX"/><category term="Live CD"/><category term="Maven"/><category term="Mink"/><category term="PMD"/><category term="RARP"/><category term="REST"/><category term="Robotium"/><category term="Ruby"/><category term="SyncAdapter"/><category term="Threading"/><category term="UDP"/><category term="XAMPP"/><category term="chroot"/><category term="reparar"/><title type='text'>/dev/kmem</title><subtitle type='html'>Apuntes de Linux y programación.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>27</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-5906719316054465875</id><published>2015-05-18T17:49:00.000+02:00</published><updated>2015-05-18T17:49:13.359+02:00</updated><title type='text'>Nuevo sitio</title><content type='html'>&lt;div&gt;
Desde hace tiempo este url llego a su fin. Pueden encontrar todo el contenido de este blog asi como nuevas entradas en&amp;nbsp;&lt;a href=&quot;http://alexismas.com/&quot; target=&quot;_blank&quot;&gt;alexismas.com&lt;/a&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/5906719316054465875/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2015/05/nuevo-sitio.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/5906719316054465875'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/5906719316054465875'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2015/05/nuevo-sitio.html' title='Nuevo sitio'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-8057285745274133973</id><published>2013-10-15T11:38:00.001+02:00</published><updated>2013-10-15T14:10:32.294+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GWT"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Maven"/><title type='text'>Creacion de un WAR de GWT</title><content type='html'>&lt;div&gt;
Esto mas que un post es una especie de post-it.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Al principio estaba creando el war de un proyecto GWT el comando &lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;war:war&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;incluida el bytecode Java, pero no esta incluyendo el contenido&amp;nbsp;&lt;/span&gt;estático&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;del proyecto. Debemos compilar las clases Java y el contenido&amp;nbsp;&lt;/span&gt;estático&lt;span style=&quot;font-family: inherit;&quot;&gt;.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;mvn compile gwt:compile war:war&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Con esto&amp;nbsp;&lt;/span&gt;deberíamos&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;tener el war con todo el contenido listo para desplegar.&lt;/span&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/8057285745274133973/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2013/10/creacion-de-un-war-de-gwt.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/8057285745274133973'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/8057285745274133973'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2013/10/creacion-de-un-war-de-gwt.html' title='Creacion de un WAR de GWT'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-3968397152842047298</id><published>2013-03-21T11:38:00.000+01:00</published><updated>2013-03-21T11:38:05.045+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="BDD"/><category scheme="http://www.blogger.com/atom/ns#" term="Behat"/><category scheme="http://www.blogger.com/atom/ns#" term="Mink"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="Symfony2"/><title type='text'>BDD con Symfony 2: Behat y Mink</title><content type='html'>Luego de estar unos meses poniendo en practica &lt;a href=&quot;http://es.wikipedia.org/wiki/Desarrollo_guiado_por_pruebas&quot; target=&quot;_blank&quot;&gt;TDD&lt;/a&gt; se dio la oportunidad de comenzar un nuevo proyecto y poder hacerlo mediante &lt;a href=&quot;http://en.wikipedia.org/wiki/Behavior-driven_development&quot; target=&quot;_blank&quot;&gt;BDD&lt;/a&gt;.&amp;nbsp;Así&amp;nbsp;que&amp;nbsp;decidí&amp;nbsp;ensuciarme un poco las manos y ponerlo a prueba.&lt;br /&gt;
&lt;br /&gt;
El enfoque usado seria el mismo, primero definimos que es lo que hay que implementar para luego ponernos a solucionar el problema. La diferencia es la forma en que se define cada uno de ellos, TDD esta centrado para el equipo de desarrollo mientras que BDD esta pensado tanto como los desarrolladores como para la gente no entiende absolutamente nada de&amp;nbsp;programación (al menos una parte). Defiendo los requisitos mediante pruebas unitarias (TDD) y historias de usuario (BDD).&lt;br /&gt;
&lt;br /&gt;
Pongamos por ejemplo una calculadora, para definir la capacidad de realizar una suma en TDD seria algo asi:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/Axxiss/5208561.js&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
Mientras que en BDD es mucho mas legible para la gente no-técnica.&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/Axxiss/5208597.js&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
¿No hace falta comentar la diferencia no?&lt;br /&gt;
&lt;br /&gt;
Obviamente con definir la historia de usuario no alcanza, el siguiente paso es asociar mediante una&amp;nbsp;expresión&amp;nbsp;regular cada linea de la historia de usuario a una&amp;nbsp;función. Suena horrorosamente complicado, pero es mucho mas simple de lo que parece.&lt;br /&gt;
&lt;br /&gt;
En este caso en concreto veremos como hacerlo con &lt;a href=&quot;http://behat.org/&quot; target=&quot;_blank&quot;&gt;Behat&lt;/a&gt; y &lt;a href=&quot;http://mink.behat.org/&quot; target=&quot;_blank&quot;&gt;Mink&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
Behat&lt;/h2&gt;
Behat como dice en su web se un framework php para probar las&amp;nbsp;expectativas&amp;nbsp;de negocio. Es quien se&amp;nbsp;encarga&amp;nbsp;de la&amp;nbsp;ejecución&amp;nbsp;de las &lt;strike&gt;pruebas&lt;/strike&gt;&amp;nbsp;historias&amp;nbsp;de usuario. Aparte de lo que es fichero de&amp;nbsp;configuración&amp;nbsp;de Behat hay dos componentes claves en su&amp;nbsp;funcionamiento.&lt;br /&gt;
&lt;br /&gt;
El primer componente serian las historias de usuario, estas se definen en ficheros &lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;.feature&lt;/span&gt; mediante el lenguaje &lt;a href=&quot;https://github.com/cucumber/cucumber/wiki/Gherkin&quot; target=&quot;_blank&quot;&gt;Gherkin&lt;/a&gt; (el snippet anterior esta hecho en Gherkin) cada funcionalidad a implementar se define en un fichero dividido en tres partes:&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;i&gt;Feature:&lt;/i&gt;&amp;nbsp;descripción&amp;nbsp;de la&amp;nbsp;característica&amp;nbsp;a&amp;nbsp;implementar.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;Background:&amp;nbsp;&lt;/i&gt;definición&amp;nbsp;del contexto en el cual vamos a ejecutar las pruebas (un fixture, vamos).&lt;/li&gt;
&lt;li&gt;&lt;i&gt;Scenarios:&lt;/i&gt;&amp;nbsp;los escenarios definen las partes necesarias para implementar la nueva&amp;nbsp;característica, a su vez cada escenario esta compuesto por un numero finito de &lt;i&gt;steps&lt;/i&gt;&amp;nbsp;(pasos)&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&lt;h2&gt;
Mink&lt;/h2&gt;
Mink es la otra pieza clave para poder llevar a cabo BDD en un entorno web. Nos brindara un navegador, ya sea en php puro como &lt;a href=&quot;https://github.com/fabpot/Goutte&quot; target=&quot;_blank&quot;&gt;Goutte&lt;/a&gt;&amp;nbsp;(el usado por Symfony 2), este tipo de navegadores suelen ser muy&amp;nbsp;rápidos&amp;nbsp;pero no podremos interactuar ni ver los resultados obtenidos al aplicar javascript en la parte del cliente;&amp;nbsp;también&amp;nbsp;podemos usar un navegador real a&amp;nbsp;través&amp;nbsp;de &lt;a href=&quot;http://sahi.co.in/&quot; target=&quot;_blank&quot;&gt;Sahi&lt;/a&gt;&amp;nbsp;donde veremos los resultados que se producen al ejecutar javascript en nuestra&amp;nbsp;pagina. Se puede usar otro dos navegadores Zombie y Selenium, la configuración de cada uno de ellos esta detallada en la &lt;a href=&quot;http://mink.behat.org/#different-browsers-drivers&quot; target=&quot;_blank&quot;&gt;documentación&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Ademas de encapsular el navegador nos brinda una serie de funciones&amp;nbsp;predefinidas&amp;nbsp;para poder interactuar con él. En esta &lt;a href=&quot;http://blog.lepine.pro/wp-content/uploads/2012/03/behat-cheat-sheet-en.pdf&quot; target=&quot;_blank&quot;&gt;cheatsheet&lt;/a&gt; pueden consultar las funciones definidas.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
Symfony 2&lt;/h2&gt;
&lt;div&gt;
La&amp;nbsp;integración&amp;nbsp;de Behat y Mink en nuestro proyecto Symfony 2 es bastante sencilla, como ya es costumbre basta con agregar las dependencias a composer. Dependiendo si usamos Mink u otro de los drivers proporcionados tendremos que agrega la correspondiente dependencia.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Una vez instalados tendremos que crear un fichero de&amp;nbsp;configuración&amp;nbsp;en la raiz de nuestro proyecto llamado &lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;behat.yml&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;y generar la estructura necesaria para la&amp;nbsp;&lt;/span&gt;ejecución&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;de las pruebas. El ultimo paso se hace llamando a &lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;vendor/bin/behat --init&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt; (si lo instalamos&amp;nbsp;&lt;/span&gt;según&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;la&amp;nbsp;&lt;/span&gt;documentación). Creando la carpeta &lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;Features&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;dentro de nuestro bundle.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;script src=&quot;https://gist.github.com/Axxiss/5212013.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Al ejecutar las pruebas no&amp;nbsp;saldrán&amp;nbsp;dos errores, diciendo que no esta definido los siguientes pasos:&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Given There is no &quot;User&quot; in database&lt;/li&gt;
&lt;li&gt;And the following users&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
Si lo volvemos a ejecutar con la&amp;nbsp;opción&amp;nbsp;--append-snippets, veremos que en el fichero FeatureContext tendremos agregadas las dos funciones a ejecutar cuando se ejecuta cada uno de esos pasos, faltandonos solo definir el cuerpo de cada&amp;nbsp;función&amp;nbsp;según&amp;nbsp;nuestras necesidades&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;script src=&quot;https://gist.github.com/Axxiss/5212105.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Y eso seria todo cuanto necesitamos para empezar a aplicar BDD en un proyecto Symfony2.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/3968397152842047298/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2013/03/bdd-con-symfony-2-behat-y-mink.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/3968397152842047298'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/3968397152842047298'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2013/03/bdd-con-symfony-2-behat-y-mink.html' title='BDD con Symfony 2: Behat y Mink'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-4618038300582766474</id><published>2012-11-30T11:55:00.000+01:00</published><updated>2012-11-30T11:55:06.701+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Android"/><category scheme="http://www.blogger.com/atom/ns#" term="Ant"/><category scheme="http://www.blogger.com/atom/ns#" term="Checkstyle"/><category scheme="http://www.blogger.com/atom/ns#" term="Emma"/><category scheme="http://www.blogger.com/atom/ns#" term="FindBugs"/><category scheme="http://www.blogger.com/atom/ns#" term="Integración Continua"/><category scheme="http://www.blogger.com/atom/ns#" term="Jenkins"/><category scheme="http://www.blogger.com/atom/ns#" term="JUnit"/><category scheme="http://www.blogger.com/atom/ns#" term="PMD"/><category scheme="http://www.blogger.com/atom/ns#" term="Robotium"/><category scheme="http://www.blogger.com/atom/ns#" term="Testing"/><title type='text'>Android y Jenkins: Integración continua</title><content type='html'>En el articulo &lt;a href=&quot;http://devkmem.blogspot.com.es/2012/10/android-conoce-jenkins.html&quot; target=&quot;_blank&quot;&gt;Android conoce a Jenkins&lt;/a&gt;&amp;nbsp;explicamos como configurar Jenkins para que este consultara&amp;nbsp;periódicamente&amp;nbsp;nuestro repositorio en busca de cambios y compilara la aplicación, eso es una pequeña parte de lo que se puede y debe llegar a hacer si queremos desarrollar una&amp;nbsp;aplicación&amp;nbsp;de calidad. Si queremos tomarnos en serio la integración continua tendremos que crear dos tareas nuevas en Jenkins una para la&amp;nbsp;ejecución&amp;nbsp;de pruebas y otra para el&amp;nbsp;análisis&amp;nbsp;de la calidad del&amp;nbsp;código.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;Pruebas automatizadas&lt;/span&gt;&lt;/h2&gt;
Las pruebas son una parte vital para asegurarnos que nuestra&amp;nbsp;aplicación&amp;nbsp;cumple con los requisitos, pero a medida que el proyecto va creciendo va dejando de ser eficaz ejecutar las pruebas manualmente desperdiciando&amp;nbsp;así&amp;nbsp;mucho tiempo que puede ser dedicado para otras cosas.&lt;br /&gt;
&lt;br /&gt;
Para las pruebas usaremos Ant, JUnit y Robotium.&lt;br /&gt;
&lt;br /&gt;
En &lt;b&gt;eclipse&lt;/b&gt; creamos un nuevo &lt;b&gt;proyecto de pruebas&lt;/b&gt;, la creación y conceptos basicos estan explicados en estos dos articulos&lt;a href=&quot;http://developer.android.com/tools/testing/testing_eclipse.html&quot; target=&quot;_blank&quot;&gt; Testing from Eclipse with ADT&lt;/a&gt; y &lt;a href=&quot;http://developer.android.com/tools/testing/testing_android.html&quot; target=&quot;_blank&quot;&gt;Testing Fundamentals&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Ant&lt;/h3&gt;
&lt;div&gt;
En este caso la&amp;nbsp;única&amp;nbsp;diferencia es que tenemos que indicarle a ant que esta vez el proyecto es un proyecto de pruebas.&lt;br /&gt;
&lt;br /&gt;
&lt;pre nbsp=&quot;nbsp&quot; style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; android update test-project -m &amp;lt;main_path&amp;gt; -p &amp;lt;test_path&amp;gt; &amp;nbsp;&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
Robotium&lt;/h3&gt;
&lt;div&gt;
&lt;a href=&quot;http://code.google.com/p/robotium/&quot; target=&quot;_blank&quot;&gt;Robotium&lt;/a&gt;&amp;nbsp;es un framework para la&amp;nbsp;realización&amp;nbsp;de pruebas en Android su uso facilita bastante las pruebas (sobre todo las relacionadas con UI). Para poder ejecutarlas en Jenkins sin problemas debemos colocar el jar de robotium en la carpeta&amp;nbsp;&lt;b&gt;libs/&lt;/b&gt;&amp;nbsp;del proyecto de pruebas y subirlo a nuestro repositorio.&lt;/div&gt;
&lt;br /&gt;
&lt;h3&gt;
Jenkins&lt;/h3&gt;
&lt;div&gt;
La creación de la tarea es igual que la del articulo&amp;nbsp;anterior, para obtener el&amp;nbsp;código&amp;nbsp;tenemos dos opciones obtenerlo directamente desde el repositorio o clonar el workspace de la tare de&amp;nbsp;compilación. En mi caso voy a usar la segunda&amp;nbsp;opción, ya que reduce el tiempo de&amp;nbsp;ejecución&amp;nbsp;y el consumo de ancho de banda. Para poder realizar la clonación tenemos que instalar &lt;a href=&quot;https://wiki.jenkins-ci.org/display/JENKINS/Clone+Workspace+SCM+Plugin&quot; target=&quot;_blank&quot;&gt;Clone Workspace SCM Plugin&lt;/a&gt;, una vez instalado abrimos la tarea de compilación y en &lt;b&gt;Post-build Actions&lt;/b&gt;&amp;nbsp;agregamos la acción &lt;b&gt;Archive for Clone Workspace SCM.&lt;/b&gt;&lt;br /&gt;
Luego en el proyecto de pruebas dentro de &lt;b&gt;Source Code Management&lt;/b&gt;&amp;nbsp;eligiremos &lt;b&gt;Clone Workspace Parent Project&lt;/b&gt;&amp;nbsp;y en lista desplegable elegimos el proyecto principal.&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
En&amp;nbsp;&lt;b&gt;Build Triggers&lt;/b&gt;&amp;nbsp;hay que indicar que la tarea se iniciara al completarse la tarea anterior, en mi caso el nombre de esa tarea es Finder.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiptRmZe_UHglEKo-oejzx0oawV_sB3MrFsNsox5crR7sHjOcVL2vKYwRiB6HzbTA-STa58a964A0nBrTSGCyNwsMBu0hJBjdHp0xdxPafXA87Y7_8mtCK_q21M9LvVFOXi_NNX_bD7LAcd/s1600/build_triggers.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;112&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiptRmZe_UHglEKo-oejzx0oawV_sB3MrFsNsox5crR7sHjOcVL2vKYwRiB6HzbTA-STa58a964A0nBrTSGCyNwsMBu0hJBjdHp0xdxPafXA87Y7_8mtCK_q21M9LvVFOXi_NNX_bD7LAcd/s400/build_triggers.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;h4&gt;
Emulador de Android&lt;/h4&gt;
&lt;/div&gt;
&lt;div&gt;
Cuando creamos un emulador mediante el SDK de Android, este por defecto se guarda en ~/.android/avd/. Por lo que &lt;b&gt;si creamos un emulador con nuestro usuario este no&amp;nbsp;podrá&amp;nbsp;ser accedido por Jenkins&lt;/b&gt; ya que mirara en su home y no en el nuestro.&lt;br /&gt;
&lt;br /&gt;
Lo mas simple es iniciar sesión con Jenkins y crear el emulador con el terminal con la instrucción&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;android create avd&lt;/span&gt;. En la&amp;nbsp;&lt;a href=&quot;http://developer.android.com/tools/devices/managing-avds-cmdline.html&quot; target=&quot;_blank&quot;&gt;documentación&lt;/a&gt;&amp;nbsp;podemos consultar con detalle todas las opciones de este comando.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo para crear un emulador con Froyo,&amp;nbsp;ejecutaríamos
&lt;br /&gt;
&lt;pre nbsp=&quot;nbsp&quot; style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; android avd create -n nombre -t android-8 &amp;nbsp;&lt;/code&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;
&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Dependiendo de nuestra combinación HW+SW podemos encontrarnos con un error bastante molesto, al ejecutar el emulador con el usuario jenkins se generara un segmentation fault. Lo raro es que al ejecutarlo con nuestro usuario no hay&amp;nbsp;&lt;/span&gt;ningún&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;problema. Leyendo el&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;http://code.google.com/p/android/issues/detail?id=34233&quot; style=&quot;font-family: inherit;&quot; target=&quot;_blank&quot;&gt;informe&lt;/a&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;del bug, podemos ver que se&amp;nbsp;&lt;/span&gt;encontró&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;un &quot;workaround&quot; para evitar el error, basta con renombrar la&amp;nbsp;&lt;/span&gt;librería&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;ANDROID_SDK/tools/lib/&lt;/span&gt;libOpenglRender.so. Al renombrar la&amp;nbsp;librería&amp;nbsp;el emulador no la encontrara por lo que&amp;nbsp;hará&amp;nbsp;el renderizado via software.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Build&lt;/h4&gt;
&lt;div&gt;
Ya tenemos configurado el repositorio y el emulador ahora hay que definir que hacer en la&amp;nbsp;compilación. Para eso agregaremos solo una instruccion en la seccion &lt;b&gt;Build &lt;/b&gt;de Jenkins la cualr sera &lt;b&gt;Invoke Ant&lt;/b&gt;&amp;nbsp;tendremos que especificar el target como:&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre nbsp=&quot;nbsp&quot; style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; clean emma debug install test fetch-test-report &amp;nbsp;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;clean&lt;/b&gt;: limpia el proyecto&lt;/li&gt;
&lt;li&gt;&lt;b&gt;emma&lt;/b&gt;: indica que se analizara el code coverage&lt;/li&gt;
&lt;li&gt;&lt;b&gt;debug&lt;/b&gt;: aplicacion en modo debug&lt;/li&gt;
&lt;li&gt;&lt;b&gt;install&lt;/b&gt;: instala la aplicación en el emulador&lt;/li&gt;
&lt;li&gt;&lt;b&gt;test&lt;/b&gt;: ejecuta las pruebas&lt;/li&gt;
&lt;li&gt;&lt;b&gt;fetch-test-report&lt;/b&gt;: obtiene el resultado de las pruebas desde el emulador, lo definiremos mas adelante&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
Si tenemos las pruebas en el mismo repositorio que la aplicación tendremos que especificar que fichero build.xml usara ant ya que al buscar en la&amp;nbsp;raíz&amp;nbsp;encontrara el correspondiente a la&amp;nbsp;aplicación&amp;nbsp;y no al proyecto de pruebas. Para ello en el campo &lt;b&gt;Build File&lt;/b&gt;&amp;nbsp;ingresamos &lt;b&gt;test/build.xml&lt;/b&gt; o la ruta donde se encuentren nuestro proyecto de pruebas.&lt;br /&gt;
Finalmente tendremos que definir dos propiedades en el campo &lt;b&gt;Properties&lt;/b&gt;, la ruta del SDK y el target a usar&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; sdk.dir=/opt/android-sdk-linux  
 target=android-8  &lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;h4&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;Emma&lt;/span&gt;&lt;/h4&gt;
&lt;a href=&quot;http://emma.sourceforge.net/&quot; target=&quot;_blank&quot;&gt;Emma&lt;/a&gt;&amp;nbsp;calculara el code coverage (cobertura de&amp;nbsp;código)&amp;nbsp;, lo cual es realmente&amp;nbsp;útil&amp;nbsp;para saber que partes de nuestro proyecto&amp;nbsp;están&amp;nbsp;cubiertas por las pruebas. Tendremos que instalar&amp;nbsp;&lt;a href=&quot;https://wiki.jenkins-ci.org/display/JENKINS/Emma+Plugin&quot; target=&quot;_blank&quot;&gt;Emma Plugin&lt;/a&gt;&amp;nbsp;en Jenkins y agregar en&amp;nbsp;&lt;b&gt;Post-build Action&lt;/b&gt;&amp;nbsp;la acción&amp;nbsp;&lt;b&gt;Record Emma coverage report.&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;Hay que indicar la ruta donde se encuentra el informe de cobertura, en nuestro caso sera en la carpeta bin del proyecto por lo que seria&amp;nbsp;&lt;b&gt;**/bin/coverage*.xml&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjIw2Y9r77Ft4b9gutn-7yae_HhqnkJRRHxXUCOA1-MuvLIiyxrDe8p8jOj2dfcnsELIRWvBfyGXHDa0GTI_lCJUjkAnS1eyCOYIQtXvCM0f-BfDVzLbG0SV0rgpRbcQY4TliDq__SP_pP/s1600/jenkins_emma.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;145&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjIw2Y9r77Ft4b9gutn-7yae_HhqnkJRRHxXUCOA1-MuvLIiyxrDe8p8jOj2dfcnsELIRWvBfyGXHDa0GTI_lCJUjkAnS1eyCOYIQtXvCM0f-BfDVzLbG0SV0rgpRbcQY4TliDq__SP_pP/s400/jenkins_emma.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En caso de que la ruta fuera distinta al ejecutar las pruebas con Emma en la consola de salida se muestra la ruta donde se guardan los informes&amp;nbsp;bastaría&amp;nbsp;con ver donde se guardan y modificar la ruta acorde a nuestro proyecto.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
JUnit&lt;/h4&gt;
&lt;div&gt;
Para poder mantener un registro de las pruebas realizadas y saber en detalle cuales fallaron y cuales no, Jenkins necesita el resultado de las pruebas en formato XML y ahi es cuando entra en juego&amp;nbsp;&lt;a href=&quot;http://zutubi.com/source/projects/android-junit-report/&quot; target=&quot;_blank&quot;&gt;Android JUnit report&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://github.com/jsankey/android-junit-report/downloads&quot; target=&quot;_blank&quot;&gt;bajamos&lt;/a&gt;&amp;nbsp;el jar y lo agregamos a la carpeta&amp;nbsp;&lt;b&gt;libs/&lt;/b&gt;&amp;nbsp;del proyecto y lo subimos al repositorio.&lt;br /&gt;
&lt;br /&gt;
Para configurarlo hay que hacer un par de cambios en nuestro proyecto primero nos vamos a AndroidManifest.xml, buscamos el tag&amp;nbsp;&lt;b&gt;instrumentation&lt;/b&gt;&amp;nbsp;y cambiamos el atributo&amp;nbsp;&lt;b&gt;android:name&lt;/b&gt;&lt;br /&gt;
&lt;pre nbsp=&quot;nbsp&quot; style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; android:name=&quot;com.zutubi.android.junitreport.JUnitReportTestRunner&quot; &amp;nbsp;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
El segundo paso es crear el fichero&amp;nbsp;&lt;b&gt;custom_rules.xml&lt;/b&gt;&amp;nbsp;en la carpeta raiz del proyecto&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/4147213.js?file=custom_rules.xml&quot;&gt;&lt;/script&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Con esto estamos definiendo el target&amp;nbsp;&lt;b&gt;fetch-test-report&lt;/b&gt;&amp;nbsp;el cual ejecutara el comando pull en adb para obtener el informe y lo guardara en reports/junit-report.xml.&lt;br /&gt;
&lt;br /&gt;
A esta altura tenemos ant configurado para que obtenga el resultado de las pruebas desde el emulador, lo siguiente es añadir &lt;b&gt;Publish JUnit test result&amp;nbsp;report&lt;/b&gt;&amp;nbsp;en &lt;b&gt;Post-build Actions&lt;/b&gt;&amp;nbsp;y definir donde encontrar el &amp;nbsp;informe si no modificaron el custom_rules.xml anterior esta ruta seria&amp;nbsp;&lt;b&gt;**/tests/reports/junit-report.xml&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;
Ya estamos listos para ejecutar la tarea,&amp;nbsp;si todo sale bien en el dashboard del proyecto tendremos dos&amp;nbsp;gráficos uno que nos indica el estado de las pruebas y otro el estado del code coverage. Tiene que ejecutarse al menos dos veces para poder ver la&amp;nbsp;gráfica&amp;nbsp;con datos. Al hacer click sobre las graficas se mostraran los detalles de cada informe.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9qhBDuC6R1xJcHT68LNgdYj4y5bYn0HF1MUieSeIYhvnIhP_XM9fLyF01VeWzbG2wVQTDzL_jW-N1eIORCNCxLIK6rtUQnlM5YZXWd3zI2FL1y2RIVUPh4MwpV2diqWW9MkBYG_OJQHN0/s1600/dashboard.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;215&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9qhBDuC6R1xJcHT68LNgdYj4y5bYn0HF1MUieSeIYhvnIhP_XM9fLyF01VeWzbG2wVQTDzL_jW-N1eIORCNCxLIK6rtUQnlM5YZXWd3zI2FL1y2RIVUPh4MwpV2diqWW9MkBYG_OJQHN0/s400/dashboard.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;h2&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;
Calidad del&amp;nbsp;código&lt;/span&gt;&lt;/h2&gt;
&lt;div&gt;
En esta parte nos centraremos en analizar la calidad de nuestro&amp;nbsp;código, buscando&amp;nbsp;código&amp;nbsp;repetido, comprobando reglas de estilo y encontrando posibles bugs mediante&amp;nbsp;análisis&amp;nbsp;estadístico. Para esto crearemos nuevamente una tarea free-style. La configuración del repositorio y la&amp;nbsp;compilación&amp;nbsp;es igual que el proyecto de pruebas salvo que esta vez la&amp;nbsp;compilación&amp;nbsp;en vez la de ejecutarse al finalizar el proyecto principal se ejecutara al finalizar el proyecto de pruebas.&lt;br /&gt;
&lt;br /&gt;
Nos&amp;nbsp;quedaría&amp;nbsp;definido el siguiente escenario: tenemos tareas, Finder, Finder-test y Finder-code-quality. Al hacer un commit se ejecuta la tarea Finder si no hay fallos se ejecuta Finder-test y nuevamente&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Build&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
Nuevamente a la hora de compilar lo&amp;nbsp;único&amp;nbsp;que haremos sera invocar a Ant. El target sera&lt;br /&gt;
&lt;pre nbsp=&quot;nbsp&quot; style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; findbugs pmd lint &amp;nbsp;&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
Ejecutando findbugs y cpd, a&amp;nbsp;continuación&amp;nbsp;veremos que es cada uno y en el caso que no nos interese ejecutar uno de ellos simplemente borramos el target.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
FindBugs&lt;/h3&gt;
&lt;div&gt;
&lt;a href=&quot;http://findbugs.sourceforge.net/&quot; target=&quot;_blank&quot;&gt;FindBugs&lt;/a&gt; tal como su nombre indicara buscara bugs en nuestro&amp;nbsp;código&amp;nbsp;mediante&amp;nbsp;análisis&amp;nbsp;estadístico. Precisaremos el jar findbugs-ant el cual en mi caso no venia incluido en la&amp;nbsp;versión&amp;nbsp;de findbugs de Fedora&amp;nbsp;así&amp;nbsp;que lo baje e instale manualmente. Una vez bajado el archivo y descomprimido en /opt/findbugs-x.y.z donde x.y.z es la&amp;nbsp;versión tendremos que copiar el archivo &lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;$FINDBUGS_HOME/lib/findbugs-ant.jar&lt;/span&gt; a&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt; $ANT_HOME/lib&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Antes de ponernos a configurar FindBugs tendremos que instalar el &lt;a href=&quot;https://wiki.jenkins-ci.org/display/JENKINS/FindBugs+Plugin&quot; target=&quot;_blank&quot;&gt;plugin&lt;/a&gt; para Jenkins que nos mostrara el informe de manera detallada.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
Tendremos que definir en ant el target findbugs, agregando el siguiente&amp;nbsp;código&amp;nbsp;al fichero custom_rules.xml &amp;nbsp;sino existe lo creamos en la&amp;nbsp;raíz&amp;nbsp;de nuestro proyecto NO en el de pruebas.&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/4147349.js?file=custom_rules.xml&quot;&gt;&lt;/script&gt;El tag class indica donde se encontrar los archivos .class tenemos dos opciones forzar la&amp;nbsp;compilación&amp;nbsp;diciendo que el target findbugs depende de&amp;nbsp;algún&amp;nbsp;otro target que genere las clases (debug por ejemplo) mediante el atributo depends o usar las clases generadas por la tarea Finder, esta ultima&amp;nbsp;opción&amp;nbsp;es la que yo estoy usando. Por lo que ustedes&amp;nbsp;tendrán&amp;nbsp;que decidir que es lo que prefieren y adaptar la configuración de findbugs.&lt;br /&gt;
&lt;br /&gt;
Al definir este target necesitaremos especificar el valor de algunas variables en el campo Properties de llamada a Ant.&lt;br /&gt;
&lt;br /&gt;
&lt;pre nbsp=&quot;nbsp&quot; style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; findbugs.home=/opt/findbugs-2.0.1
 android.jar=/opt/android-sdk-linux/platforms/android-8/android.jar&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Tenemos que indicar la ruta del jar de Android como classpath auxiliar, es decir, es necesario para el analisis ya que se realizan llamadas a sus&amp;nbsp;métodos&amp;nbsp;en caso de no indicarlo cada vez que se haga una instancia de una clase de Android tendremos un error de missing class.&lt;br /&gt;
&lt;br /&gt;
Y como ultimo paso para ejecutar y obtener los resultados de findbugs en &lt;b&gt;Post-build Actions&lt;/b&gt;&amp;nbsp;añadiremos &lt;b&gt;Publish FindBugs analysis results&lt;/b&gt;&amp;nbsp;y como ruta de los informes&amp;nbsp;&lt;b&gt;**/reports/findbugs.xml&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;
&lt;h3&gt;
Open Tasks&lt;/h3&gt;
&lt;div&gt;
Con &lt;a href=&quot;https://wiki.jenkins-ci.org/display/JENKINS/Task+Scanner+Plugin&quot; target=&quot;_blank&quot;&gt;Open Tasks&lt;/a&gt; analizaremos nuestro&amp;nbsp;código&amp;nbsp;en&amp;nbsp;búsqueda&amp;nbsp;de tareas tipo TODO o FIXME, que muchas veces se añaden al&amp;nbsp;código&amp;nbsp;para indicar que falta algo por hacer o hay algo que arreglar y así&amp;nbsp;permanecen durante la eternidad. Luego de instalar el plugin añadiendo &lt;b&gt;Scan workspace for open tasks&lt;/b&gt; en &lt;b&gt;Post-build Actions&lt;/b&gt;&amp;nbsp;podremos configurar los&amp;nbsp;parámetros&amp;nbsp;de la&amp;nbsp;búsqueda.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWZHfrQZmENvm2DGO6m1Jy4HnZ8X-ShC2LMGi_BIF4mRgQs2HZ8yAI_tk5FyxsEmB1OJ3F6KbFGA611YyrfYkAdd33rZvhyphenhyphenGWjdbNaAhVBAQfsf6GES0E22xyElsZvblu12_DaAdVot8Xr/s1600/opentasks.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;247&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWZHfrQZmENvm2DGO6m1Jy4HnZ8X-ShC2LMGi_BIF4mRgQs2HZ8yAI_tk5FyxsEmB1OJ3F6KbFGA611YyrfYkAdd33rZvhyphenhyphenGWjdbNaAhVBAQfsf6GES0E22xyElsZvblu12_DaAdVot8Xr/s400/opentasks.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Como vemos en la imagen, tendremos que indicar que archivos queremos analizar, cuales excluir y los tags a buscar con su respectiva prioridad.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Checkstyle&lt;/h4&gt;
&lt;/div&gt;
&lt;div&gt;
El estilo del&amp;nbsp;código&amp;nbsp;también&amp;nbsp;debe tenerse en cuenta a la hora de medir la calidad del mismo. Dependiendo del lenguaje con el que estemos trabajando tendremos un estilo definido para cada uno de ellos. &lt;a href=&quot;http://checkstyle.sourceforge.net/&quot; target=&quot;_blank&quot;&gt;Checkstyle&lt;/a&gt; se encargara de analizar este aspecto de nuestro&amp;nbsp;código. Me&amp;nbsp;encontré&amp;nbsp;con el siguiente &lt;a href=&quot;https://sourceforge.net/p/checkstyle/bugs/683/&quot; target=&quot;_blank&quot;&gt;problema&lt;/a&gt;, lo mas raro es que si lo ejecutaba con mi usuario funcionaba sin problemas pero al ejecutarse mediante Jenkins daba ese error. Modificando ANT_HOME el problema se solucionaba parcialmente, ahora si lo ejecutaba con el usuario jenkins funcionaba, pero cuando era el propio Jenkins quien lo ejecutaba el error&amp;nbsp;seguía&amp;nbsp;ahí. La&amp;nbsp;solución&amp;nbsp;que&amp;nbsp;encontré&amp;nbsp;fue instalarlo desde el repositorio de Fedora.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
Al igual que con findbugs, tendremos que definir el target para ant&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/4174999.js?file=custom_rules.xml&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
No hay un fichero oficial para comprobar el estilo para Android, pero si que hay varios fichero por la vuelta, uno de ellos lo pueden encontrar en &lt;a href=&quot;https://github.com/taoufix/Android/blob/master/android-checkstyle.xml&quot;&gt;android-checkstyle.xml&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;h4&gt;
PMD&lt;/h4&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;a href=&quot;http://pmd.sourceforge.net/&quot; target=&quot;_blank&quot;&gt;PMD&lt;/a&gt;&amp;nbsp;analizara el&amp;nbsp;código&amp;nbsp;en busca de posibles errores, variables sin usar,&amp;nbsp;código&amp;nbsp;muerto, demasiado complejo,&amp;nbsp;duplicado, etc. Como siempre descargamos los binarios, y pasamos a agregar el target a Ant. Ya que CPD forma parte de PMD, no usaremos el informe de codigo duplicado ya que se encontrara dentro del informe de PMD.&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/4167656.js?file=custom_rules.xml&quot;&gt;&lt;/script&gt;

&lt;br /&gt;
Y mas de lo mismo, indicar en &lt;b&gt;Post-build Actions&lt;/b&gt; que queremos publicar el informe generado por PMD.&lt;br /&gt;
&lt;br /&gt;
Y finalmente tenemos todo listo, no es una tarea&amp;nbsp;difícil&amp;nbsp;pero si que puede ser bastante ardua. Sobre todo al principio si nunca&amp;nbsp;habíamos&amp;nbsp;usado Ant haciendo muchos cambios a base de prueba y error.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/4618038300582766474/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2012/11/android-y-jenkins-integracion-continua.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/4618038300582766474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/4618038300582766474'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2012/11/android-y-jenkins-integracion-continua.html' title='Android y Jenkins: Integración continua'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiptRmZe_UHglEKo-oejzx0oawV_sB3MrFsNsox5crR7sHjOcVL2vKYwRiB6HzbTA-STa58a964A0nBrTSGCyNwsMBu0hJBjdHp0xdxPafXA87Y7_8mtCK_q21M9LvVFOXi_NNX_bD7LAcd/s72-c/build_triggers.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-3169001606500725461</id><published>2012-10-22T11:00:00.000+02:00</published><updated>2012-11-06T12:05:25.461+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Android"/><category scheme="http://www.blogger.com/atom/ns#" term="Ant"/><category scheme="http://www.blogger.com/atom/ns#" term="Bitbucket"/><category scheme="http://www.blogger.com/atom/ns#" term="Git"/><category scheme="http://www.blogger.com/atom/ns#" term="Integración Continua"/><category scheme="http://www.blogger.com/atom/ns#" term="Jenkins"/><category scheme="http://www.blogger.com/atom/ns#" term="SSH"/><title type='text'>Android conoce a Jenkins</title><content type='html'>&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaCl548-aayJHhTKqqJefr2vwasMK5eSq8ghfmz5NMOwhjvrjy6uazGG2n23YYFyhqQxiiGwHVPdDi_G4Bg0SL2WchWG8rquDxE-g2IjeDCLyPTZS8-jdvxkSGYYzVjyJ7g4Fioxy3e26l/s1600/jenkins_logo.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;102&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaCl548-aayJHhTKqqJefr2vwasMK5eSq8ghfmz5NMOwhjvrjy6uazGG2n23YYFyhqQxiiGwHVPdDi_G4Bg0SL2WchWG8rquDxE-g2IjeDCLyPTZS8-jdvxkSGYYzVjyJ7g4Fioxy3e26l/s320/jenkins_logo.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
La &lt;a href=&quot;http://en.wikipedia.org/wiki/Continuous_integration&quot; target=&quot;_blank&quot;&gt;integración continua&lt;/a&gt; es una técnica software en la cual se integran los cambios muy frecuentemente (generalmente horas), tratando de detectar errores lo mas pronto posible, automatizando la compilación y la ejecución de las pruebas.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Para pode&lt;/span&gt;r desarrollar nuestra aplicación en un entorno de integración continua haremos uso de&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://ant.apache.org/&quot; target=&quot;_blank&quot;&gt;Ant&lt;/a&gt; que se encargara de la automatización&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.jenkins-ci.org/display/JENKINS/Home&quot; target=&quot;_blank&quot;&gt;Jenkins&lt;/a&gt; sera el encargado de la integración continua.&lt;/li&gt;
&lt;li&gt;En este caso &lt;a href=&quot;http://git-scm.com/&quot; target=&quot;_blank&quot;&gt;Git&lt;/a&gt;&amp;nbsp;y &lt;a href=&quot;https://bitbucket.org/&quot; target=&quot;_blank&quot;&gt;Bitbucket&lt;/a&gt; como control de versiones &lt;/li&gt;
&lt;/ul&gt;
Como punto de partida tendremos un proyecto Android con su respectivo proyecto de pruebas, para mas detalles consultar la &lt;a href=&quot;http://developer.android.com/tools/testing/index.html&quot; target=&quot;_blank&quot;&gt;documentación&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Configuración de Ant&lt;/span&gt;&lt;/h2&gt;
Primero que nada necesitamos indicar que nuestro proyecto va a ser compilado con Ant y donde queremos&amp;nbsp;despegarlo,&amp;nbsp;para ello abrimos el terminal, vamos a la carpeta donde se encuentra nuestro proyecto y ejecutamos:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;script src=&quot;https://gist.github.com/3924681.js?file=android-ant.sh&quot;&gt;&lt;/script&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Como resultado se creara el archivo &lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;b&gt;build.xml&lt;/b&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;h2&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Jenkins&lt;/span&gt;&lt;/h2&gt;
Hay dos posibles maneras de instalar Jenkins: desde un repositorio o desplegando un war en apache, las instrucciones las podemos encontrar en la &lt;a href=&quot;https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins&quot; target=&quot;_blank&quot;&gt;documentación&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Una vez instalado&amp;nbsp;Jenkins&amp;nbsp; abrimos el navegador y entramos a &lt;b&gt;localhost:8080&lt;/b&gt; si vemos la pagina inicial de&amp;nbsp;Jenkins&amp;nbsp;es que todo esta bien, sino tendremos que iniciar el servicio.&lt;br /&gt;
&lt;br /&gt;
Ahora si, ya tenemos a&amp;nbsp;Jenkins&amp;nbsp;ejecutándose&amp;nbsp;y&amp;nbsp;el siguiente paso a dar es añadir el soporte de Git (o el&amp;nbsp;repositorio&amp;nbsp;escogido), lo cual puede hacer&amp;nbsp;fácilmente&amp;nbsp;instalando el plugin&amp;nbsp;&lt;b&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;Jenkins Git plugin&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;
&lt;h3&gt;
&lt;/h3&gt;
&lt;h3&gt;
Creación de la tarea&lt;/h3&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Jenkins se encarga de ejecutar tareas, por lo tanto todo lo que queramos hacer&amp;nbsp;&lt;/span&gt;tendrá&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;que ser definido como tal.&amp;nbsp;&lt;/span&gt;En el panel izquierdo tendremos la&amp;nbsp;opción&amp;nbsp;de crear una tarea, y a continuación nos mostrara una serie de opciones. Para nuestro proyecto Android tendremos que elegir &lt;b&gt;Free-style Project&lt;/b&gt;&lt;i&gt;. &lt;/i&gt;Ya en la pantalla de creación de la tarea tendremos que configurar lo que queremos hacer, en este caso &lt;b&gt;compilar e instalar la aplicación.&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;
&lt;h4&gt;
Repositorio&lt;/h4&gt;
Esta parte no tiene mucho misterio, simplemente es especificar los datos de nuestro repositorio.&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;b&gt;URL&lt;/b&gt;: de&lt;/span&gt; tipo&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt; git@bitbucket.org:usuario/proyecto.git&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;b&gt;Browser&lt;/b&gt;: &amp;nbsp;bitbucketweb&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;b&gt;Browser URL&lt;/b&gt;: de la forma&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;https://bitbucket.org/usuario/proyecto&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
Ignoren los posibles errores que surjan al indicar la web de repositorio, mas adelante se explicara como solucionarlo.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Planificación&lt;/h4&gt;
Jenkins&amp;nbsp;tendrá&amp;nbsp;que saber cuando se compilara la aplicación, para integración continua lo más adecuado es que se haga ni bien se detecta un cambio en el&amp;nbsp;código, es decir cada vez que se haga un commit. Por lo que en &lt;b&gt;Build Triggers&lt;/b&gt; tendremos que marcar &lt;b&gt;Poll SCM&lt;/b&gt;&lt;i&gt;, &lt;/i&gt;para que&amp;nbsp;Jenkins&amp;nbsp;consulte el repositorio cada cierto tiempo en busca de cambios, la frecuencia de la consulta se define siguiendo el formato de &lt;a href=&quot;http://es.wikipedia.org/wiki/Cron_(Unix)&quot; target=&quot;_blank&quot;&gt;cron&lt;/a&gt;. Por ejemplo &quot;&lt;span style=&quot;font-family: inherit;&quot;&gt;15 * * * *&quot;&amp;nbsp;&lt;/span&gt;comprobara el repositorio pasados los 15 minutos de cada hora, es decir 12:15, 13:15, 14:15, etc.&lt;br /&gt;
&lt;br /&gt;
Bitbucket brinda un &lt;a href=&quot;https://confluence.atlassian.com/display/BITBUCKET/Setting+Up+the+Bitbucket+Jenkins+Service&quot; target=&quot;_blank&quot;&gt;servicio&lt;/a&gt; en el cual es el propio Bitbucket el que notifica a Jenkins de que hubo&amp;nbsp;algún&amp;nbsp;cambio en el&amp;nbsp;código, pero para esto se necesita una url publica para&amp;nbsp;Jenkins.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Compilación e Instalación&lt;/h4&gt;
A esta altura&amp;nbsp;Jenkins&amp;nbsp;ya sabe de donde obtener el&amp;nbsp;código&amp;nbsp;y cada cuanto comprobar si hay&amp;nbsp;algún&amp;nbsp;cambio, nos&amp;nbsp;faltaría definir como compilar y que hacer&amp;nbsp;después&amp;nbsp;de compilar. La compilación se&amp;nbsp;hará&amp;nbsp;mediante Ant para ello añadiremos dos pasos &lt;b&gt;clean debug&lt;/b&gt;&amp;nbsp;para limpiar el proyecto y compilar en modo debug; y &lt;b&gt;debug install&lt;/b&gt;&amp;nbsp;para instalar el .apk generado.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA3vehMQ_DKlbpQtqjB9n5qBw8vr2H-2zwx29enr_hIt-7SkArs0qYk7k-ljlXdmLKGGsganSO1p5miIWzLR59P0-NrrJgujmuct1PKFjpWQcMeP2QEttKXewyYGFmWwqdUFH8MAUk6NBW/s1600/build_jenkins.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;260&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA3vehMQ_DKlbpQtqjB9n5qBw8vr2H-2zwx29enr_hIt-7SkArs0qYk7k-ljlXdmLKGGsganSO1p5miIWzLR59P0-NrrJgujmuct1PKFjpWQcMeP2QEttKXewyYGFmWwqdUFH8MAUk6NBW/s320/build_jenkins.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Para poder instalar la aplicación tendremos dos opciones usar un dispositivo real o el emulador, en este caso usaremos el emulador. Para ello dependeremos de &lt;a href=&quot;https://wiki.jenkins-ci.org/display/JENKINS/Android+Emulator+Plugin&quot; target=&quot;_blank&quot;&gt;Android Emulator Plugin&lt;/a&gt;&amp;nbsp;podemos hacer el propio plugin cree el emulador en tiempo de ejecución o definirlo nosotros mismo. Si decidimos crearlo a mano en el documento &lt;a href=&quot;http://developer.android.com/tools/devices/managing-avds-cmdline.html&quot; target=&quot;_blank&quot;&gt;Managing AVDs from the Command line&lt;/a&gt; esta muy bien explicado.&lt;br /&gt;
&lt;br /&gt;
Dentro de las opciones avanzadas de compilación encontraremos un campo llamado &lt;b&gt;Properties&lt;/b&gt;, en el cual tendremos que indicar donde se encuentra el SDK de Android y la plataforma sobre la que trabajaremos.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;script src=&quot;https://gist.github.com/3924723.js?file=jenkins-android-properties.txt&quot;&gt;&lt;/script&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Si queremos conservar los .apk generados en cada&amp;nbsp;compilación, tendremos que ir a la sección &lt;b&gt;Post-build Actions&lt;/b&gt;&lt;i&gt;, &lt;/i&gt;la opción que nos interesa es &lt;b&gt;Archive the artifacts&lt;/b&gt;&lt;i&gt;. &lt;/i&gt;Especificando la ruta donde queremos guardarlo, por ejemplo para guardarlo en la ruta asignada por defecto y agregando &quot;-debug&quot; al final del nombre del fichero seria:&amp;nbsp;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;b&gt;**/*-debug.apk&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Ya tenemos la tarea configurada, pero si compilamos ahora mismo fallara. Viendo el log generado veremos que se debe a que no tenemos los permisos necesarios para acceder al repositorio, obviamente si es un repositorio publico esto no pasara.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;h3&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Dando permisos a Jenkins&lt;/span&gt;&lt;/h3&gt;
Una vez creada la tarea realizar la configuración necesaria para que el usuario Jenkins (desde le cual se ejecuta la aplicación) tenga los permisos necesarios para acceder al repositorio. No sera necesario crear un nuevo usuario en Bitbucket exclusivo para Jenkins ya que se puede configurar una clave ssh otorgando acceso de solo lectura mediante una Deployment Key. El primero paso sera iniciar sesión con el usuario Jenkins, pero por defecto viene desactivado&amp;nbsp;así&amp;nbsp;que tendremos que habilitar el inicio de&amp;nbsp;sesión&amp;nbsp;modificando el fichero &lt;b&gt;/etc/passwd&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Una vez tengamos ubicada la linea del usuario Jenkins, cambiaremos&amp;nbsp;&lt;b&gt;/bin/false&lt;/b&gt; por &lt;b&gt;/bin/bash&lt;/b&gt; para poder iniciar&amp;nbsp;sesión&amp;nbsp;con dicho usuario.&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/3924750.js?file=jenkins-permission.sh&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
Por ultimo queda asegurarnos que Jenkins tiene permisos para acceder a las herramientas proporcionadas por el SDK de Android, es decir que tiene permisos de lectura en Android-SDK/tools/&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;
Ya terminamos con la&amp;nbsp;configuración&amp;nbsp;en el lado del cliente, solo queda agregar la clave creada en Bitbucket para eso&amp;nbsp;accedemos al &lt;b&gt;panel de administración&lt;/b&gt; de nuestro&amp;nbsp;proyecto en Bitbucket creamos una &lt;b&gt;Deploymente key&lt;/b&gt; nueva y pegamos el contenido del fichero &lt;b&gt;/var/lib/jenkins/.ssh/id_rsa.pub&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
Si el repositorio no esta en la lista de &lt;b&gt;host conocidos&lt;/b&gt; (.ssh/known_hosts) debemos&lt;b&gt; clonar el repositorio manualmente &lt;/b&gt;en una carpeta temporal y cuando se nos pregunte si queremos añadirlo a la lista de host conocidos tendremos que decir que si, ya que Jenkins no es capaz de gestionar dicho escenario.&lt;br /&gt;
&lt;br /&gt;
Y por hoy eso es todo, en el&amp;nbsp;próximo&amp;nbsp;articulo veremos como crear pruebas automatizadas con Jenkins.</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/3169001606500725461/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2012/10/android-conoce-jenkins.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/3169001606500725461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/3169001606500725461'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2012/10/android-conoce-jenkins.html' title='Android conoce a Jenkins'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaCl548-aayJHhTKqqJefr2vwasMK5eSq8ghfmz5NMOwhjvrjy6uazGG2n23YYFyhqQxiiGwHVPdDi_G4Bg0SL2WchWG8rquDxE-g2IjeDCLyPTZS8-jdvxkSGYYzVjyJ7g4Fioxy3e26l/s72-c/jenkins_logo.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-8688150046932967176</id><published>2012-05-21T15:52:00.000+02:00</published><updated>2012-05-21T15:52:15.798+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="AccountManager"/><category scheme="http://www.blogger.com/atom/ns#" term="Android"/><category scheme="http://www.blogger.com/atom/ns#" term="REST"/><category scheme="http://www.blogger.com/atom/ns#" term="SyncAdapter"/><category scheme="http://www.blogger.com/atom/ns#" term="Web services"/><title type='text'>Sincronizando Android con la Nube</title><content type='html'>Viendo la presentación&amp;nbsp;&lt;a href=&quot;http://www.google.com/events/io/2010/sessions/developing-RESTful-android-apps.html&quot; style=&quot;font-style: italic;&quot; target=&quot;_blank&quot;&gt;Developing Android REST client applications&lt;/a&gt;&amp;nbsp;se habla dos &lt;b&gt;errores muy grandes&lt;/b&gt; que todo principiante comete al implementar servicios web con Android:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;ejecutar el servicio web en el hilo principal&lt;/li&gt;
&lt;li&gt;alojar los recursos obtenidos en la memoria en lugar de en almacenamiento permanente&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
La parte negativa del primer punto es que las transferencias de datos pueden llevar bastante tiempo derivando en una UI lenta y en ocasiones que esta deje de responder. Por otro lado el no persistir los datos se pude pensar que&amp;nbsp;hará&amp;nbsp;nuestra aplicación mas&amp;nbsp;rápida. Pero ¿que pasa si el S.O. decide expulsar de memoria a nuestra&amp;nbsp;aplicación&amp;nbsp;para darle lugar a otra? Que tendremos que volver a pedir los datos al servidor conllevando mas gasto de CPU por lo tanto de&amp;nbsp;batería&amp;nbsp;y el esperar tiempo necesario para volver a transferir el recurso.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
En la charla se proponen tres patrones de diseño diferentes:&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;Service&lt;/li&gt;
&lt;li&gt;Content Provider&lt;/li&gt;
&lt;li&gt;Content Provider y SyncAdapter&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Cada uno de las diseños se pueden ver las transparencias de la charla.&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
En este caso veamos como se implementa el ultimo de ellos. En los dos primeros patrones tenemos que encargarnos manualmente del estado de los recursos y de las transacciones, pero en el ultimo caso todo esto se hace&amp;nbsp;automáticamente&amp;nbsp;a&amp;nbsp;través&amp;nbsp;de SyncAdapter. SyncAdapter sera el encargado de gestionar el estado de los recursos y actualizarlos cuando sea conveniente, este es el&amp;nbsp;patrón&amp;nbsp;usado por Gmal, Facebook, LastFM, por citar algunos.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguJIy42UEKY7ZNjHgflNtszHZ_r-jUGhHLICVGthjqmyMkSk9OfbZwGTOLbW77ss4GQ3MU2D4JrQKpRaXXe6fkKWc89s-zFB9gyQ003wRYSXjALSfi7ubkkB4X0IY3aJY2r-9dGyybxS5M/s1600/Selection_002.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;206&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguJIy42UEKY7ZNjHgflNtszHZ_r-jUGhHLICVGthjqmyMkSk9OfbZwGTOLbW77ss4GQ3MU2D4JrQKpRaXXe6fkKWc89s-zFB9gyQ003wRYSXjALSfi7ubkkB4X0IY3aJY2r-9dGyybxS5M/s400/Selection_002.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Imagen tomada de las transparencias de la presentación.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div&gt;
Como vemos la estructura se divide en cinco partes. La capa mas alta se encarga de mostrar los datos al usuario. La actividad es una actividad&amp;nbsp;común&amp;nbsp;y corriente, que interactúa con el usuario guardando&amp;nbsp;pidiéndole&amp;nbsp;o mostrando los datos que nos interesen. El &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;CursorAdaptar&lt;/span&gt; es quien refresca los datos que&amp;nbsp;están&amp;nbsp;en el &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;ContentProvider&lt;/span&gt; con la interfaz, mostrando siempre los datos mas recientes. Los datos son almacenados en un &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;ContentProvider&lt;/span&gt;, si no quieren usar un content provider para guardar los datos&amp;nbsp;deberán&amp;nbsp;engañar al sistema, creando uno que no haga nada, en &lt;a href=&quot;http://stackoverflow.com/questions/4649808/syncadapter-without-a-contentprovider&quot; target=&quot;_blank&quot;&gt;StackOverflow&lt;/a&gt; se explica mas o menos como hacerlo.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;ContentProvider&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
Como crear un &lt;a href=&quot;http://developer.android.com/guide/topics/providers/content-providers.html&quot; target=&quot;_blank&quot;&gt;ContentProvider&lt;/a&gt;&amp;nbsp;ya se explico en un &lt;a href=&quot;http://devkmem.blogspot.com/2012/05/android-creacion-de-un-contentprovider.html&quot; target=&quot;_blank&quot;&gt;post anterior&lt;/a&gt;&amp;nbsp;así&amp;nbsp;que como es de suponer no se&amp;nbsp;volverá&amp;nbsp;a explicar. Es más, dicho post fue pensado para usarlo como base para este.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Account Authenticator&lt;/span&gt;&lt;br /&gt;
Para poder sincronizar nuestra&amp;nbsp;aplicación&amp;nbsp;con un servidor primero debemos agregar una cuenta al sistema. &amp;nbsp;Para ello que mejor que echarle un vistazo a los ejemplos de Google, en concreto a &lt;a href=&quot;http://developer.android.com/resources/samples/SampleSyncAdapter/index.html&quot; target=&quot;_blank&quot;&gt;este&lt;/a&gt;. El ejemplo&amp;nbsp;también&amp;nbsp;se&amp;nbsp;puede&amp;nbsp;encontrar dentro del SDK que tenemos instalado, pero no es exactamente igual a la&amp;nbsp;versión&amp;nbsp;online, traten de usar la&amp;nbsp;versión&amp;nbsp;online que es la mas actual.&lt;br /&gt;
&lt;br /&gt;
Dentro del paquete &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;authenticator&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;se implementa la&amp;nbsp;&lt;/span&gt;gestión&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;de cuentas haciendo uso de tres clases:&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Authenticator&lt;/span&gt;: implementa la&amp;nbsp;gestión&amp;nbsp;de la cuenta.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;AuthenticationService&lt;/span&gt;: define un servicio que&amp;nbsp;instancia&amp;nbsp;a &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Authenticator&lt;/span&gt; para realizar las tareas en el background.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;AuthenticatorActivity&lt;/span&gt;: la actividad mostrada para pedir las claves al usuario.&lt;/li&gt;
&lt;/ul&gt;
Para tener todo la&amp;nbsp;gestión&amp;nbsp;de cuentas haremos uso del viejo y querido &lt;i&gt;copy &amp;amp; paste&lt;/i&gt;, en un mundo ideal funcionaria sin ninguna modificación pero es demasiado bueno para ser verdad asi que hay que hacer algunas modificaciones. En el ejemplo usa otra dos clases, &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Constants&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;NetworkUtilities.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;Si quieren&amp;nbsp;&lt;/span&gt;también&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;las pueden copiar, sino:&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;definir las dos constantes definidas en &lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Constants&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt; en la clase &lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Authenticator&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;reemplazar &lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Networkutilities&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt; por la clase donde este implementado el acceso al servidor, el&amp;nbsp;&lt;/span&gt;método&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;authenticate&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt; es el que nos interesa, ya que es con el que se validan las credenciales del usuario.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
Si usaron&amp;nbsp;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;AuthenticatorActivity&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;en lugar de una actividad propia, hay que copiar el fichero &lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;xml/authenticator.xml,&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;el contenido de &lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;values/strings.xml&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;, y añadir al Manifest&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;la&amp;nbsp;&lt;/span&gt;definición&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;del servicio y de la actividad.&lt;/span&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/2762238.js?file=services.xml&quot;&gt;
&lt;/script&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;La variable android:name indica la ruta de la clase AuthenticatorService.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Con eso si instalamos nuestra&amp;nbsp;&lt;/span&gt;aplicación&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;al ir a &lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Settings &amp;gt; Accounts and sync &amp;gt; Add account &lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;s&lt;/span&gt;aldrá&amp;nbsp;nuestro el tipo de cuenta que acabamos de definir.&lt;br /&gt;
&lt;br /&gt;
Tengan&amp;nbsp;muchísimo&amp;nbsp;cuidado al declarar el servicio ya que al estar trabajando con XML es muy&amp;nbsp;fácil&amp;nbsp;meter la pata, en mi caso cuando se creaba la cuenta se iniciaba la&amp;nbsp;sesión&amp;nbsp;sin problema pero mas tarde al volver a intentarlo no se iniciaba la&amp;nbsp;sesión&amp;nbsp;porque no estaba guardando el password de usuario. Todo eso por tener mal los ficheros XML.&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;SyncAdapter&lt;/span&gt;&lt;br /&gt;
Con lo anterior ya esta la&amp;nbsp;gestión&amp;nbsp;de la cuenta ahora viene lo que realmente nos interesa como sincronizar nuestro&amp;nbsp;teléfono&amp;nbsp;con un servidor. Nuevamente tendremos que crear un servicio para que se ejecute ocultamente sin molestar a nadie. Para eso se precisan dos clases SyncAdapter y SyncService.&lt;br /&gt;
&lt;br /&gt;
SyncAdapter define las acciones a realizar cuando se lleva a cabo la sincronizacion, en este caso llama al metodo syncLog de la clase VideoLogger.&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/2762286.js?file=SyncAdapter.java&quot;&gt;
&lt;/script&gt;
&lt;br /&gt;
syncLog implementa lo que realmente se hace al sincronizar, esto puede ir dentro de syncAdapter, pero pero claridad y facilidad de mantenimiento decididí gestionarlo aparte. Como veran primero obtiene todos los objetos PendingMovie que hay almacenados y luego va iterando sobre ellos y subiendolos al servidor, en este caso en concreto el metodo upload, borrara el objeto del ContentProvider una vez recibido el ACK del servidor.&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/2762303.js?file=syncLog.java&quot;&gt;
&lt;/script&gt;
&lt;br /&gt;
Y SyncService instancia a SyncAdapter comom un singleton y lo vincula al servicio.&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/2762338.js?file=SyncService.java&quot;&gt;
&lt;/script&gt;
&lt;br /&gt;
Finalmente hay que crear un XML con la definición del syncadapter y definir el servicio en el Manifest.&lt;span style=&quot;font-size: x-large;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;res/xml/syncadapter.xml&lt;/b&gt;
&lt;script src=&quot;https://gist.github.com/2762349.js?file=sync-adapter.xml&quot;&gt;
&lt;/script&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/2762376.js?file=AndroidManifest.xml&quot;&gt;
&lt;/script&gt;

Y eso es todo.
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/8688150046932967176/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2012/05/sincronizando-android-con-la-nube.html#comment-form' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/8688150046932967176'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/8688150046932967176'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2012/05/sincronizando-android-con-la-nube.html' title='Sincronizando Android con la Nube'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguJIy42UEKY7ZNjHgflNtszHZ_r-jUGhHLICVGthjqmyMkSk9OfbZwGTOLbW77ss4GQ3MU2D4JrQKpRaXXe6fkKWc89s-zFB9gyQ003wRYSXjALSfi7ubkkB4X0IY3aJY2r-9dGyybxS5M/s72-c/Selection_002.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-2271912695368563127</id><published>2012-05-15T22:22:00.000+02:00</published><updated>2012-05-15T22:22:54.088+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Agile"/><category scheme="http://www.blogger.com/atom/ns#" term="Management"/><category scheme="http://www.blogger.com/atom/ns#" term="Scrum"/><title type='text'>Scrum II: Scrum Team</title><content type='html'>&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgouRYL4dvEYVyQ5GhzA8M0rFAGj5nMhoKc-eszUL-r-2dbM7Ys4dbpBaIKRqqqVGgWz-9izL7_I07VS-5sZBUIkL5Yg1Ps59qiNVGtP0xunMnpgz76V1kINDFr7hAFjFIFKbmnq7UC8YLK/s1600/population.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgouRYL4dvEYVyQ5GhzA8M0rFAGj5nMhoKc-eszUL-r-2dbM7Ys4dbpBaIKRqqqVGgWz-9izL7_I07VS-5sZBUIkL5Yg1Ps59qiNVGtP0xunMnpgz76V1kINDFr7hAFjFIFKbmnq7UC8YLK/s320/population.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Imagen obtenida de&amp;nbsp;openclipart&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Luego de haber comentado un poco la&amp;nbsp;&lt;a href=&quot;http://devkmem.blogspot.com/2012/04/scrum-i-la-base.html&quot; target=&quot;_blank&quot;&gt;teoría&lt;/a&gt;&amp;nbsp;en la que se basa Scrum, es posible hablar de quienes son los responsables de llevarlo a cabo. La puesta en practica se lleva a cabo en equipos denominados &lt;b&gt;Scrum Team&lt;/b&gt;, cada equipo esta formado por&amp;nbsp;&lt;b&gt;Product Owner&lt;/b&gt;, &lt;b&gt;Development Team &lt;/b&gt;(o equipo de&amp;nbsp;desarrollo) y&amp;nbsp;&lt;b&gt;Scrum Master.&lt;/b&gt;&amp;nbsp;Estos equipos son completamente&amp;nbsp;autónomos,&amp;nbsp;multidisciplinarios y auto-organizados. Con este modelo se pretende tener flexibilidad, creatividad y productividad. Entremos un poco en los detalles de cada perfil.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Product Owner&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
El &lt;b&gt;Product Owner&lt;/b&gt; es quien gestiona el valor del producto, es decir quien decide que es lo que hay que hacer, se&amp;nbsp;podría&amp;nbsp;comparar con la figura tradicional del Jefe de proyecto. Product Owner hay &lt;b&gt;uno y solo uno&lt;/b&gt;, ni dos, ni tres;&amp;nbsp;únicamente&amp;nbsp;una persona determinada es quien puede cumplir este rol.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Para realizar la tarea con&amp;nbsp;éxito, &lt;b&gt;toda la&amp;nbsp;organización&amp;nbsp;debe respetar las decisiones tomadas&lt;/b&gt; por el Product Owner. Nada de el jefe del jefe del jefe dice A o B, el que quiera cambiar algo que hable con el Product owner, tan sencillo como eso. Si lo convencen bien, sino mala suerte, si esta en ese puesto&amp;nbsp;sabrá&amp;nbsp;lo que esta haciendo.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Las tareas que tiene a cargo son:&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;Definir los elementos del Product Backlog&lt;/li&gt;
&lt;li&gt;Ordenar el Product Backlog para lograr los objetivos establecidos&lt;/li&gt;
&lt;li&gt;Asegurarse que el equipo de desarrollo cumple con su trabajo&lt;/li&gt;
&lt;li&gt;Asegurarse que el Product Backlog es visible, transparente y comprensible para todos&lt;/li&gt;
&lt;li&gt;Asegurarse que el Product Backlog muestra realmente el trabajo planificado&lt;/li&gt;
&lt;li&gt;Asegurarse que el equipo entiende un elemento del Product Backlog al nivel necesario&lt;/li&gt;
&lt;/ul&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Development Team&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
Los integrantes del equipo de desarrollo&amp;nbsp;serán&amp;nbsp;los que llevaran a cabo las tareas para poder implementar el incremento del producto. Para poder realizar el desarrollo completo de un incremente logicamente&amp;nbsp;tendrán&amp;nbsp;que ser grupos &lt;b&gt;multi-disciplinarios&lt;/b&gt;.&amp;nbsp;La &lt;b&gt;organización del grupo depende de si mismos&lt;/b&gt; y las &lt;b&gt;relaciones internas son de igual a igual&lt;/b&gt;, no hay diferencias de roles, todos son considerados como desarrollador. A pesar de que cada persona tenga un conjunto de habilidades especifico, la regla anterior tiene que cumplirse por lo que cada uno tiene que ser capaz de saber cuales son sus puntos fuertes y sus puntos&amp;nbsp;débiles.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
El tamaño de los equipos es algo que siempre se discute en cualquier metodología, Scrum particularmente no define una cifra concreta sino que determina dos rangos, uno inferior y otro superior. No es&amp;nbsp;aconsejable&amp;nbsp;que el equipo tenga &lt;b&gt;menos de tres personas&lt;/b&gt;, aunque a primera vista parezca algo bueno ya que se reduce el tiempo de&amp;nbsp;comunicación&amp;nbsp;aumentando un poquito la productividad, es muy probable que la productividad ganada se desperdicie cuando el equipo se encuentre con un &lt;b&gt;problema que no es el mas adecuado para sus habilidades&lt;/b&gt;. Y en el caso contrario equipos de de &lt;b&gt;más de nueve&lt;/b&gt; personas requiere &lt;b&gt;mucha&amp;nbsp;comunicación&lt;/b&gt;&amp;nbsp;llevando a una&amp;nbsp;reducción&amp;nbsp;de la productividad.&lt;br /&gt;
&lt;br /&gt;
Una posible&amp;nbsp;combinación&amp;nbsp;para un equipo&amp;nbsp;podría&amp;nbsp;tener los siguientes roles: ingeniero de software, arquitecto, analista, programador, tester y diseñador de UI.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Scrum Master&lt;/span&gt;&lt;br /&gt;
El Scrum Master es el director de la orquesta, tiene que ser capaz de sincronizarse a la perfeccion con el equipo tratando de eliminar todos los posibles obstaculos que aparezcan por el camino. Gran parte de su tarea es estar pendiente de que el equipo de desarrollo siga las pautas de Scrum (teoria, practicas y reglas). Otra de sus funcionalidades es de actuar como un enlace entre el equipo y el mundo exterior, decidiendo cuando el equipo puede o no interactuar con alguien del exterior.&lt;br /&gt;
Brinda tres tipos de servicio:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Servicios para el Product Owner&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Proveer de&amp;nbsp;técnicas&amp;nbsp;eficaces para la&amp;nbsp;gestión&amp;nbsp;del Product Backlog&lt;/li&gt;
&lt;li&gt;Comunicar el objetivo del Product Backlog al equipo de desarrollo&lt;/li&gt;
&lt;li&gt;Enseñar a todo el equipo como diseñar elementos del Product Backlog&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Servicios para el Equipo de desarrollo&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Ayudar con la&amp;nbsp;organización&amp;nbsp;del equipo&lt;/li&gt;
&lt;li&gt;Ayudar con la&amp;nbsp;creación&amp;nbsp;de un producto de gran valor&lt;/li&gt;
&lt;li&gt;Eliminación&amp;nbsp;de&amp;nbsp;obstáculos&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Servicios a la organización&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Guiar a la&amp;nbsp;organización&amp;nbsp;a adoptar Scrum como&amp;nbsp;metodología&lt;/li&gt;
&lt;li&gt;Generar cambios que produzcan un aumento en la productividad de equipo&lt;/li&gt;
&lt;li&gt;Trabajar coordinadamente con otros Scum Masters para aumenta la eficacia de Scrum en la organización.&lt;/li&gt;
&lt;li&gt;Planificar la implementación de Scrum con la organización&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;br /&gt;
Los servicios que brinda un Scrum Master como puede verse son muchos y muy variados, sin duda que es un perfil muy flexible. Es una pieza clave para el desarrollo de Scrum, al principio sera un&amp;nbsp;guía, un instructor enseñando al equipo con mucha frecuencia, luego que el equipo adquiera&amp;nbsp;experiencia&amp;nbsp;tendrá&amp;nbsp;que enfocarse en la&amp;nbsp;motivación, para que esta no decaiga.&lt;br /&gt;
&lt;br /&gt;
Para la&amp;nbsp;próxima eventos y artifactos.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/2271912695368563127/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2012/05/scrum-ii-scrum-team.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/2271912695368563127'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/2271912695368563127'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2012/05/scrum-ii-scrum-team.html' title='Scrum II: Scrum Team'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgouRYL4dvEYVyQ5GhzA8M0rFAGj5nMhoKc-eszUL-r-2dbM7Ys4dbpBaIKRqqqVGgWz-9izL7_I07VS-5sZBUIkL5Yg1Ps59qiNVGtP0xunMnpgz76V1kINDFr7hAFjFIFKbmnq7UC8YLK/s72-c/population.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-2170767635318097963</id><published>2012-05-04T12:37:00.000+02:00</published><updated>2012-05-04T12:42:20.516+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Android"/><category scheme="http://www.blogger.com/atom/ns#" term="ContentProvider"/><title type='text'>Android: Creación de un ContentProvider</title><content type='html'>Un &lt;a href=&quot;http://developer.android.com/guide/topics/providers/content-providers.html&quot; target=&quot;_blank&quot;&gt;ContentProvider&lt;/a&gt; es una interfaz que nos brinda Android para acceder a una base de datos que se encuentre en nuestro&amp;nbsp;teléfono. Y hacer que las aplicaciones puedan compartir información&amp;nbsp;fácilmente.&lt;br /&gt;
&lt;br /&gt;
Los pasos a seguir para la implementación son los siguientes:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Extender la clase ContentProvider&lt;/li&gt;
&lt;li&gt;Crear la base de datos&lt;/li&gt;
&lt;li&gt;Implementar getType&lt;/li&gt;
&lt;li&gt;Implementar onCreate&lt;/li&gt;
&lt;li&gt;Implementar los metodos CRUD&lt;/li&gt;
&lt;li&gt;Registar el ContentProvider en AndroidManifest.xml&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
Se va a explicar como crear un Content Provider que llevara un registro de los ficheros que abre un usuario.&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Extender la clase ContentProvider&lt;/span&gt;&lt;br /&gt;
Al definir que nuestra clase extiende ContentProvider se nos crear el esqueleto&amp;nbsp;básico&amp;nbsp;de nuestra clase.&lt;br /&gt;
Que&amp;nbsp;debería&amp;nbsp;ser algo&amp;nbsp;así:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/2500398.js?file=VisioStormProvider.java&quot;&gt;
&lt;/script&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Crear la base de datos&lt;/span&gt;&lt;br /&gt;
Ya con la estructura creada, tenemos que definir una URI para nuestra base de datos, para que el sistema pueda identificarla. En el futuro cuando llegue el momento que queramos realizar alguna consulta a la base de datos se&amp;nbsp;hará&amp;nbsp;a&amp;nbsp;través&amp;nbsp;del URI que vamos a definir. Se definen en la linea 2 y 3.&lt;br /&gt;
&lt;br /&gt;
Ademas del URI, hay que definir una serie de propiedades, entre&amp;nbsp;paréntesis&amp;nbsp;se indica el numero de linea:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Tipos de URI, un&amp;nbsp;ítem&amp;nbsp;especifico o un conjunto de ellos (6 - 11)&lt;/li&gt;
&lt;li&gt;La base de datos, nombre,&amp;nbsp;versión&amp;nbsp;y nombre de la tabla (14 - 20)&lt;/li&gt;
&lt;li&gt;Columnas de la tabla y su respectivo indice (23 - 28)&lt;/li&gt;
&lt;li&gt;Controlador de peticiones (30-36)&lt;/li&gt;
&lt;/ul&gt;
&lt;script src=&quot;https://gist.github.com/2593560.js?file=AcmeProviderMembers.java&quot;&gt;
&lt;/script&gt;
&lt;br /&gt;
Ahora hay que pasar a la&amp;nbsp;creación&amp;nbsp;de la BD, para ello hay que implementar &lt;a href=&quot;http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html&quot; target=&quot;_blank&quot;&gt;SQLiteOpenHelper&lt;/a&gt; como una clase privada. Y como pueden ver en la constante &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;CREATE_TABLE&lt;/span&gt; se define la&amp;nbsp;creación&amp;nbsp;de la tabla con SQL usando las columnas definidas anteriormente. Mediante SQLiteOpenHelper el inicio de la base de datos se hace de manera perezosa, es decir hasta que no se necesita no se inicia. Evitando que nuestra aplicación se inicie mas lentamente, y que surjan errores relacionados con la base de datos al iniciar la aplicación.&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/2593635.js?file=AcmeDatabaseHelper.java&quot;&gt;
&lt;/script&gt;

&lt;span style=&quot;font-size: x-large;&quot;&gt;&lt;br /&gt;&lt;br /&gt;Implementar getType&lt;/span&gt;&lt;br /&gt;
Este metodo se encarga de analizar la consulta y decidir que tipo de datos se esta consultando. Los dos tipos de datos fueron definidos en&amp;nbsp;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;CONTENT_TYPE_LIST&lt;/span&gt; y&amp;nbsp;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;CONTENT_TYPE_ITEM, &lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;el tipo de datos debe empezar por&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;vnd.android.cursor.dir/&lt;/span&gt; y &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;vnd.android.cursor.item/&lt;/span&gt; para una lista y un item especifico, respectivamente.&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/2593692.js?file=getType.java&quot;&gt;
&lt;/script&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;&lt;br /&gt;Implementar onCreate&lt;/span&gt;&lt;br /&gt;
Como estamos usando SQLiteOpenHelper, tan solo le indicamos que queremos crear la base de datos y &amp;nbsp;este mismo ya se encarga de hacerlo cuando sea necesario.&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/2593732.js?file=onCrate.java&quot;&gt;
&lt;/script&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-size: x-large;&quot;&gt;Implementar los metodos CRUD&lt;/span&gt;&lt;br /&gt;
Al definir como realizar las consultas a la base de datos tenemos que ver si se trata de un item especifico &amp;nbsp;o de todos.&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/2593841.js?file=crud.java&quot;&gt;
&lt;/script&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Registar el ContentProvider&lt;/span&gt;&lt;br /&gt;
Suponiendo que nuestro ContentProvider se encuentra en un paquete llamado provider, tenemos que registrarlo en el Manifest&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/2593968.js?file=AndroidManifest.xml&quot;&gt;&lt;/script&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/2170767635318097963/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2012/05/android-creacion-de-un-contentprovider.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/2170767635318097963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/2170767635318097963'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2012/05/android-creacion-de-un-contentprovider.html' title='Android: Creación de un ContentProvider'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-4087342489380174578</id><published>2012-04-20T19:05:00.001+02:00</published><updated>2012-04-24T21:53:05.431+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Agile"/><category scheme="http://www.blogger.com/atom/ns#" term="Management"/><category scheme="http://www.blogger.com/atom/ns#" term="Scrum"/><title type='text'>Scrum I: La base</title><content type='html'>Scrum es un framework para la&amp;nbsp;&lt;b&gt;gestión&amp;nbsp;y desarrollo&lt;/b&gt; de proyectos software mediante un enfoque &lt;b&gt;iterativo e incremental&lt;/b&gt;. El objetivo de Scrum es poder resolver problemas complejos de manera productiva y creativa, creando un producto con la mayor calidad posible. Al ser un proceso con iteraciones de corta duración (como&amp;nbsp;máximo&amp;nbsp;un mes) el feedback obtenido del cliente es constante y la&amp;nbsp;evolución&amp;nbsp;es mas cercana a lo que desea el cliente.&lt;br /&gt;
&lt;br /&gt;
Scrum esta compuesto de cinco elementos: equipo, roles, eventos, artefactos y reglas; siendo cada uno de ellos esencial para su funcionamiento. Estos elementos se&amp;nbsp;cubrirán&amp;nbsp;en detalle en otros articulos.&lt;br /&gt;
&lt;br /&gt;
Hay tres pilares que hay que tener siempre en cuenta a la hora de trabajar con Scrum: &lt;b&gt;transparencia&lt;/b&gt;, &lt;b&gt;inspección&lt;/b&gt; y &lt;b&gt;adaptación&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;Transparencia&lt;/span&gt;&lt;br /&gt;
Los aspectos importantes del proyecto deben ser visibles para todo el entorno, usando un lenguaje común y bien definido&amp;nbsp;asegurándonos&amp;nbsp;que todos entienden lo mismo por el mismo termino.&lt;br /&gt;
&lt;br /&gt;
Un&amp;nbsp;clásico&amp;nbsp;¿Cuando algo esta terminado? Cada persona puede dar una respuesta diferente a esa pregunta.&lt;br /&gt;
&lt;br /&gt;
Lo que se pretende con la transparencia es saber en todo momento en que punto nos encontramos con nuestro proyecto y hacia donde vamos.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;Inspección&lt;/span&gt;&lt;br /&gt;
Sino tenemos transparencia llevar a cabo una inspección seria una tarea extremadamente tediosa,&amp;nbsp;improductiva&amp;nbsp;y seria realmente&amp;nbsp;difícil&amp;nbsp;evaluar la situación actual. Por eso al tener un proceso transparente facilita enormemente la inspección de nuestra situación actual y de como vamos avanzando hacia nuestro objetivo.&lt;br /&gt;
&lt;br /&gt;
La inspecciones deben realizarse con frecuenta pero sin llegar al punto de que obstruya el trabajo. Las inspecciones van de la mano con las adaptaciones, en el siguiente punto se explicara como ponerlas en practica.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;Adaptación&lt;/span&gt;&lt;br /&gt;
Luego de una inspección, los errores o desviaciones detectados que sobrepasen los limites de aceptación deben solucionarse. &amp;nbsp;Los ajustes deben hacerse cuanto antes mejor, minimizando así el grado de desviación, la cantidad de errores actuales, y se evita el arrastre de errores; todo esto ayuda a mantener la&amp;nbsp;planificación&amp;nbsp;y el coste inicial.&lt;br /&gt;
&lt;br /&gt;
Formalmente Scrum define cuatro puntos de inspección y adaptación:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Sprint Planning&lt;/li&gt;
&lt;li&gt;Daily Scrum&lt;/li&gt;
&lt;li&gt;Sprint Review&lt;/li&gt;
&lt;li&gt;Sprint Retrospective&lt;/li&gt;
&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/4087342489380174578/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2012/04/scrum-i-la-base.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/4087342489380174578'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/4087342489380174578'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2012/04/scrum-i-la-base.html' title='Scrum I: La base'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-4518137665444321813</id><published>2012-04-18T22:57:00.000+02:00</published><updated>2012-04-18T22:57:29.095+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ARP"/><category scheme="http://www.blogger.com/atom/ns#" term="BOOTP"/><category scheme="http://www.blogger.com/atom/ns#" term="DHCP"/><category scheme="http://www.blogger.com/atom/ns#" term="RARP"/><category scheme="http://www.blogger.com/atom/ns#" term="Redes"/><title type='text'>Protocolos de arranque y configuración</title><content type='html'>&lt;div&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Address&amp;nbsp;Resolution&amp;nbsp;Protocol&lt;/span&gt;&lt;br /&gt;
Primero que nada aclara que el protocolo de arranque y&amp;nbsp;configuración&amp;nbsp;seria &lt;b&gt;RARP&lt;/b&gt;, pero es mucho mas claro explicar ARP para entender RARP, ya que es su caso inverso.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;b&gt;A&lt;/b&gt;ddress &lt;b&gt;R&lt;/b&gt;esolution &lt;b&gt;P&lt;/b&gt;rotocol o ARP, es un protocolo que partiendo de una&amp;nbsp;dirección&amp;nbsp;de un protocolo de nivel superior (TCP, FTP, TELNET, etc) nos permite obtener la dirección Ethernet de un dispositivo.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;Generación&amp;nbsp;de paquetes ARP&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
Supongamos que trabajamos con el protocolo IP a nivel de red. Al enviar un mensaje desde el host A al host B, solo conocemos la direccion IP de la maquina de destino, pero a&amp;nbsp;nivel de enlace el paquete es encapsulado en una trama Ethernet, por lo que sera&amp;nbsp;necesario&amp;nbsp;saber la&amp;nbsp;dirección&amp;nbsp;Ethernet de nuestra maquina destino (en caso de estar en la misma red) o de la maquina a&amp;nbsp;través&amp;nbsp;de la cual se&amp;nbsp;hará&amp;nbsp;el enrutamiento. Este proceso se hace media &lt;b&gt;broadcasting&lt;/b&gt;, al ser un procedimiento muy costoso cada cliente mantiene una &lt;b&gt;tabla de correspondencia&lt;/b&gt; con con los pares &lt;i&gt;IP-Ethernet&lt;/i&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;Recepción&amp;nbsp;de paquetes ARP&lt;/span&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
Como se dijo anteriormente cuando un terminal necesita determinar la dirección Ethernet de una maquina, &amp;nbsp;lo&amp;nbsp;hará&amp;nbsp;mediante un broadcast. Cuando una&amp;nbsp;petición&amp;nbsp;de resolución llega a un cliente, primero se actualiza la tabla de correspondencia (para evitar futuros broadcast) y luego se comprueba si nuestra&amp;nbsp;dirección&amp;nbsp;de protocolo es la buscada. Si el mensaje no va&amp;nbsp;dirigido&amp;nbsp;a nosotros se descarta, en caso contrario se responde al dispositivo que genero el mensaje&amp;nbsp;indicándole&amp;nbsp;nuestra&amp;nbsp;dirección&amp;nbsp;Ethernet.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Para consultar la tabla de correspondencia podemos ejecutar&amp;nbsp;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;arp -a&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Como se dijo al principio el caso inverso, es &lt;/span&gt;&lt;b style=&quot;font-family: inherit;&quot;&gt;RARP&lt;/b&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;, es decir conocemos la&amp;nbsp;&lt;/span&gt;dirección&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;&lt;/span&gt;física&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;del&amp;nbsp;&lt;/span&gt;dispositivo&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;y queremos saber la&amp;nbsp;&lt;/span&gt;dirección&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;IP.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
Suponiendo que tenemos que mandar un mensaje desde A (.10) a B (.20), la secuencia de mensajes de ARP es la siguiente:&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;arp who-has 192.168.1.10 tell &amp;nbsp;192.168.1.20&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;arp reply &amp;nbsp; 192.168.1.20 is-at 00:11:22:33:44:55&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
Esto se puede ver perfectamente con &lt;i&gt;Wireshark&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: inherit; font-size: x-large;&quot;&gt;Bootstrap Protocol&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Para lidiar con los problemas del broadcast limitado de RARP (255.255.255.255) surge BOOTPl objetivo de este protocolo es saber la IP de un host a partir de su&amp;nbsp;&lt;/span&gt;dirección&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;&lt;/span&gt;física&lt;span style=&quot;font-family: inherit;&quot;&gt;. Se basa en UDP usando los puertos 67 y 68 &amp;nbsp;para el servidor y el cliente respectivamente.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;El mayor problema de BOOTP es que el administrador de la red debe introducir manualmente la tabla de correspondencia IP y Ethernet, para evitar eso BOOTP evoluciono a DHCP.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit; font-size: x-large;&quot;&gt;Dynamic Host Configuration Protocol&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;DHCP se encarga de automatizar la&amp;nbsp;&lt;/span&gt;configuración&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;(IP, gateway, mascaras, etc) de los dispositivos. Para el cliente es como si usara BOOTP, ya que usa los mismos puertos y protocolo. La gran diferencia con los protocolos anteriores es que el servidor DHCP no tiene porque estar en la misma red, siendo necesario un agente&amp;nbsp;&lt;/span&gt;re-transmisor&lt;span style=&quot;font-family: inherit;&quot;&gt;. Cuando el cliente desea saber su IP genera un mensaje &lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;DHCP discover&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;mediante broadcast, en caso de que el servidor se encuentre en la misma red le responde directamente sino el agente de&amp;nbsp;&lt;/span&gt;retransmisión&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;re enviara el mensaje al servidor.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;discover:&lt;/b&gt; enviado desde al servidor para solicitar una IP, puede sugerir la IP deseada.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;decline:&lt;/b&gt;&amp;nbsp;rechaza la IP solicitada por el cliente.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;offer:&lt;/b&gt;&amp;nbsp;el servidor le ofrece una&amp;nbsp;configuración&amp;nbsp;al cliente.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;request:&lt;/b&gt;&amp;nbsp;es un mensaje generado por el cliente para confirmar/rechazar ofertas.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ack / nak:&lt;/b&gt;&amp;nbsp;confirmación&amp;nbsp;/&amp;nbsp;negación&amp;nbsp;de un mensaje de tipo &lt;i&gt;request&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/4518137665444321813/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2012/04/protocolos-de-arranque-y-configuracion.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/4518137665444321813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/4518137665444321813'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2012/04/protocolos-de-arranque-y-configuracion.html' title='Protocolos de arranque y configuración'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-6072576147948977125</id><published>2012-04-09T10:00:00.000+02:00</published><updated>2012-04-09T10:00:07.289+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Capifony"/><category scheme="http://www.blogger.com/atom/ns#" term="Linux"/><category scheme="http://www.blogger.com/atom/ns#" term="Ruby"/><title type='text'>Permisos de acceso y Capifony</title><content type='html'>En el ultimo post se explico como desplegar un proyecto &lt;a href=&quot;http://devkmem.blogspot.com/2012/04/desplegar-symfony2-con-capifony.html&quot; target=&quot;_blank&quot;&gt;Symfony 2 con Capifony&lt;/a&gt;. Dependiendo del servidor con el que estemos trabajando debemos tener mas o menos cuidado con los permisos de usuario. Git en concreto solo guarda&amp;nbsp;información&amp;nbsp;sobre el bit ejecutable de un archivo. En mi caso al desplegar me encuentro con que el servidor se queja de los siguiente:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Carpetas 775 en lugar de 755&lt;/li&gt;
&lt;li&gt;Archivos 664 en lugar de 644&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Al intentar servir una pagina web en la que el archivo o la carpeta no tenga los permisos adecuados , se genera un error 500.&amp;nbsp;Así&amp;nbsp;que hay que hacer algo para realizar los cambios pertinentes. Seria bastante&amp;nbsp;estúpido, montar todo Capifony para desplegar&amp;nbsp;cómodamente&amp;nbsp;con la&amp;nbsp;ejecución&amp;nbsp;de un comando para tener que cambiar los permisos de los ficheros manualmente.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Por defecto Capifony le&amp;nbsp;dará&amp;nbsp;permisos de escritura al grupo, asi que para ello hay que agregar a Deploy.rb la&amp;nbsp;opción:&lt;/div&gt;
&lt;pre style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; set :group_writable, false  
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Con eso&amp;nbsp;están&amp;nbsp;solucionados los permisos de las carpetas, sin embargo para los ficheros no hay una&amp;nbsp;opción&amp;nbsp;que podamos modificar. Mirando el&amp;nbsp;código&amp;nbsp;de &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Symfony2.rb&lt;/span&gt;, cuando se despliega el&amp;nbsp;código&amp;nbsp;la ultima tarea ejecutada antes del commit es &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;deploy:symlink&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;asi que teniendo esto en cuenta podemos modificar deploy.rb para que cambie los permisos de los ficheros cuando termine de desplegar. Yo solo necesito eliminar los permisos de escritura para todos los que no sean el propietario.&lt;/span&gt;&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; after &quot;deploy:symlink&quot; do  
  run &quot;cd #{latest_release} &amp;amp;&amp;amp; chmod -R go-w web/&quot;  
 end  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/6072576147948977125/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2012/04/permisos-de-acceso-y-capifony.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/6072576147948977125'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/6072576147948977125'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2012/04/permisos-de-acceso-y-capifony.html' title='Permisos de acceso y Capifony'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-7998050589344089659</id><published>2012-04-07T14:37:00.000+02:00</published><updated>2012-04-07T18:22:28.434+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Capifony"/><category scheme="http://www.blogger.com/atom/ns#" term="Linux"/><category scheme="http://www.blogger.com/atom/ns#" term="SSH"/><category scheme="http://www.blogger.com/atom/ns#" term="Symfony2"/><title type='text'>Desplegar Symfony2 con Capifony</title><content type='html'>Seguro que a más de uno con tan solo escuchar la palabra desplegar se le&amp;nbsp;pondrán&amp;nbsp;los pelos de punta. Si hay algo importante en las&amp;nbsp;metodologías&amp;nbsp;ágiles&amp;nbsp;es el famoso DRY (&lt;i&gt;don&#39;t repeat yourself&lt;/i&gt;), ¿porque romper con ese enfoque para desplegar? no tiene&amp;nbsp;ningún&amp;nbsp;sentido desplegar a la vieja usanza, lidiando con ver que ficheros subir a&amp;nbsp;producción, cuales no y empezar a subir los ficheros mediante FTP o rsync. Para evitarnos esos dolores de cabeza es donde &lt;a href=&quot;http://capifony.org/&quot; target=&quot;_blank&quot;&gt;Capifony&lt;/a&gt; entra en juego. Capifony nos&amp;nbsp;permitirá&amp;nbsp;desplegar nuestro proyecto con tan solo un&amp;nbsp;comando, tan sencillo como &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;cap deploy&lt;/span&gt;. Aunque a ese estado no se llega por arte de magia, primero&amp;nbsp;habrá&amp;nbsp;que realizar ciertas instalaciones y configuraciones,&amp;nbsp;así&amp;nbsp;que vamos a ello.&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;Salvo que se indique lo contrario las instrucciones deben ser ejecutadas DESDE donde se desplegara la&amp;nbsp;aplicación.&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Instalación de Capifony&lt;/span&gt;&lt;br /&gt;
Para instalar Capifony debemos tener instalado &lt;a href=&quot;http://rubygems.org/&quot; target=&quot;_blank&quot;&gt;RubyGems&lt;/a&gt;&amp;nbsp;y usaremos&amp;nbsp;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;capistrano_rsync_with_remote_cache&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;para poder desplegar con mayor rapidez, ya que solo se subir los cambios realizados y no todo el respositorio.&lt;/span&gt;&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; sudo apt-get install rubygems  
 sudo gem capifony  
 sudo gem capistrano_rsync_with_remote_cache  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Configuración del entorno&lt;/span&gt;&lt;br /&gt;
Lo más&amp;nbsp;cómodo&amp;nbsp;(y seguro) es usar ssh con nuestra clave publica, en lugar de introducir el password cada vez que vayamos a desplegar. En caso de no tener una clave RSA generada, crearla es tan&amp;nbsp;fácil&amp;nbsp;como seguir los pasos del asistente que se nos muestra al ejecutar:&lt;br /&gt;
&lt;pre style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; ssh-keygen  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Copiar la clave publica al SERVIDOR.&lt;/b&gt;&lt;br /&gt;
Personalmente tuve algunos problemas al conectarme y tratar de copiar mi calve publica desde el terminal,&amp;nbsp;así&amp;nbsp;que tuve que copiarlo mediante cPanel. Hay que copiar el fichero &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;~/.ssh/id_rsa.pub &lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;(nuestra maquina)&lt;/span&gt;&amp;nbsp;a &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;~/.ssh/authorized_keys &lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;(servidor)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Para probar si la clave quedo bien instalada, hay que ejecutar:&lt;/span&gt;&lt;br /&gt;
&lt;pre style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; ssh usuario@ip -p puerto  
&lt;/code&gt;&lt;/pre&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
Si en nuestro &lt;b&gt;servidor&lt;/b&gt; conviven PHP 5.2 y 5.3, y en el PATH solo se encuentra la&amp;nbsp;versión&amp;nbsp;5.2, debemos agregar 5.3 al PATH, sino tendremos problemas (ver la ultima&amp;nbsp;sección&amp;nbsp;del post). Para hacerlo tenemos que modificar el fichero (en el servidor)&amp;nbsp;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;~/.bashrc&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;y añadir la siguiente linea:&lt;/span&gt;&lt;br /&gt;
&lt;pre style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; PATH=/path/to/php5.3:$PATH   
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Cerramos la&amp;nbsp;sesión&amp;nbsp;y listo.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Configuración del proyecto&lt;/span&gt;&lt;br /&gt;
El proyecto se puede desplegar de dos maneras: obteniendo el&amp;nbsp;código&amp;nbsp;desde desarrollo o desde un&amp;nbsp;repositorio. Se detallara como hacerlo desde un repositorio externo, para ver como hacerlo desde desarrollo consultar la&amp;nbsp;documentación&amp;nbsp;de Capifony.&lt;br /&gt;
&lt;br /&gt;
Para crear los ficheros necesarios de capifony basta con ejecutar.&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; cd /path/to/project  
 capifony .  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Esto nos creara dos archivos:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Capfile: se encuentra en la raiz del proyecto, es el ejecutable que indica que estamos trabajando con Symfony.&lt;/li&gt;
&lt;li&gt;Deploy.rb: este fichero se encuentra en &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;app/config/&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;y se usara para configurar Capifony.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
Ahora hay que editar Deploy.rb para configurar Capifony, vayamos por partes.&lt;br /&gt;
&lt;br /&gt;
En esta&amp;nbsp;sección&amp;nbsp;se define lo que es la&amp;nbsp;aplicación&amp;nbsp;en si&amp;nbsp;básicamente&amp;nbsp;el nombre y donde se despliega.&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; #Application 

&amp;nbsp;set :application, &quot;acme&quot; 
&amp;nbsp;set :domain, &amp;nbsp; &quot;#{application}.com&quot; 
&amp;nbsp;set :deploy_to, &amp;nbsp;&quot;/path/to/project&quot; 
&amp;nbsp;set :app_path, &amp;nbsp;&quot;app&quot; 
&amp;nbsp;set :keep_releases, 3 

&amp;nbsp;role :web, &amp;nbsp; &amp;nbsp;domain 
&amp;nbsp;role :app, &amp;nbsp; &amp;nbsp;domain 
&amp;nbsp;role :db, &amp;nbsp; &amp;nbsp; domain, :primary =&amp;amp;gt; true 

&amp;nbsp;set :model_manager, &quot;doctrine&quot; &amp;nbsp;&lt;/code&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
La&amp;nbsp;mayoría&amp;nbsp;de los&amp;nbsp;parámetros&amp;nbsp;dejan bien claro que es lo que hacen, aunque algunas aclaraciones no&amp;nbsp;estarían&amp;nbsp;de mas:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;
keep_releases&lt;/b&gt;&lt;br /&gt;
&lt;div&gt;
es la cantidad de versiones (las mas nuevas) que se dejaran en el servidor al ejecutar &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;cap deploy:cleanup&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;, es decir si desplegamos 10 veces, tendremos 10 versiones en la carpeta &lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;releases, &lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;al realizar el &lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;clean up &lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;se eliminar las versiones mas viejas dejando&amp;nbsp;&lt;/span&gt;únicamente&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;las mas nuevas, en este caso tres.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;b style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b style=&quot;font-family: inherit;&quot;&gt;role&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;si estamos desplegando solo a una maquina, hay que dejarlo tal cual esta, pero si necesitamos desplegar en varias al mismo tiempo,&amp;nbsp;&lt;/span&gt;deberá ser algo&amp;nbsp;así:&lt;/div&gt;
&lt;div&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; role :web, &quot;subdom1.domino.com&quot;, &quot;subdom2.dominio.com&quot;, &quot;subdom3.dominio.com&quot; 
&amp;nbsp;role :app, &quot;subdom1.dominio.com&quot;, &quot;subdom2.dominio.com&quot;, &quot;subdom3.dominio.com&quot; 
&amp;nbsp;role :db, &quot;db.dominio.com&quot; &amp;nbsp;&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
La&amp;nbsp;configuración&amp;nbsp;al repositorio es muy simple,&amp;nbsp;&amp;nbsp;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;ssh_options[:forward_agent] = true&lt;/span&gt;&amp;nbsp;le indica a capifony que estamos usando ssh para acceder al repositorio, y que la clave se encuentra en nuestra maquina, sino&amp;nbsp;habría&amp;nbsp;que indicar el usuario y el password.&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; #Repository  
 set :repository, &quot;url&quot;  
 set :scm,     :git  
 set :deploy_via, :rsync_with_remote_cache  
 set :git_enable_submodules, 1  
 ssh_options[:forward_agent] = true  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Los ficheros compartidos (shared), como lo indica su nombre son compartidos, compartidos entre versiones, por lo que se mantienen de&amp;nbsp;versión&amp;nbsp;a&amp;nbsp;versión. En las ultimas dos opciones se indica que cada vez que se despliegue se actualicen los vendors y se instalen los assets (imágenes, css, etc que se encuentran dentro de un Bundle).&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; #Symfony2  
 set :shared_files,   [&quot;app/config/parameters.ini&quot;]  
 set :shared_children,   [app_path + &quot;/logs&quot;, web_path + &quot;/uploads&quot;, &quot;vendor&quot;]  
 set :update_vendors, true  
 set :dump_assetic_assets, true  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Finalmente se configura el acceso al servidor, si trabajamos en un &lt;b&gt;servidor compartido&lt;/b&gt; es &lt;b&gt;IMPORTANTISIMO&lt;/b&gt;, indicarle a Capifony que no puede usar sudo, ya que generara problemas de acceso, porque no tendremos privilegios de administrador.&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; #Server connection  
 set :user, &quot;user&quot;  
 ssh_options[:port] = &quot;port&quot;  
 set :use_sudo, false  &lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Despliegue&lt;/span&gt;&lt;br /&gt;
Finalmente tenemos todo listo para hacer el despliegue.&lt;br /&gt;
&lt;br /&gt;
La &lt;b&gt;primera&lt;/b&gt; &lt;b&gt;vez&lt;/b&gt; hay que crear la estructura para Capifony.&amp;nbsp;Así&amp;nbsp;que desde la carpeta de nuestro proyecto ejecutamos&lt;br /&gt;
&lt;pre style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; cap deploy:setup  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
El cual creara una estructura como la siguiente:&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; `-- /path/to/project  
  |-- current   
  |-- releases  
  `-- shared  
   |-- log  
   |-- config  
   `-- web  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Cada vez que despleguemos se creara una carpeta en &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;releases&lt;/span&gt; con el timestamp actual, y se enlazara &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;current&lt;/span&gt; con la ultima&amp;nbsp;versión.&lt;br /&gt;
&lt;br /&gt;
Un fichero fundamental es &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;app/config/parameters.ini&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;, antes de ejecutar el primer despliegue, tendremos que copiarlo a &lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;shared/app/config/parameters.ini&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; scp -P puerto app/config/parameters.ini user@domain:/path/to/project/acme/shared/app/config/parameters.ini  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
¡Ahora si estamos listos para desplegar!&lt;br /&gt;
&lt;pre style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; cap deploy  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Si, todo fue bien (esperemos que si) nuestra aplicación ya esta desplegada en producción. Y por si fuera poco Capifony nos permite acceder a la consola de Symfony directamente desde nuestra maquina, para ver todos los comando disponibles ejecutar &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;cap -T&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Posibles problemas&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;
Sin acceso root&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
Leé nuevamente la sección &lt;i&gt;Configuración &amp;nbsp;del proyecto &lt;/i&gt;;)&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;No such file or directory&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
Este error me surgio en dos ocasiones, una haciendo referencia a una carpeta de un Bundle y otra a &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;web/images/&lt;/span&gt; y &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;web/js/&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
En el primer caso esto pasa cuando en el fichero &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;deps&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;en la URL de&amp;nbsp;&lt;/span&gt;algún&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;bundle tenemos&amp;nbsp;&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;git=git://...&lt;/span&gt; en lugar de &amp;nbsp;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;git=http://...&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;En el otro caso, capifony busca las carpetas &lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;web/images/&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;web/js/&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt; por lo que al no encontrarlas lanza el error, para solucionarlo hay que&amp;nbsp;crear la carpeta en&amp;nbsp;&lt;/span&gt;cuestión&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;en nuestro proyecto con un fichero vacio (para que la detecte git) y agregarla al repositorio.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit; font-size: large;&quot;&gt;Parse error: syntax error&lt;/span&gt;&lt;br /&gt;
En concreto este error me dio bastante problemas,&amp;nbsp;después&amp;nbsp;de muchas horas pude dar con la fuente del problema. El error se genera al indicar manualmente (porque el default es 5.2) el path para el ejecutable de PHP 5.3 para reinstalar los vendors, cuando se terminan de actualizar se actualiza el bootstrap, y en ese momento es cuando se genera el error. Ya que la&amp;nbsp;construcción&amp;nbsp;del bootstrap se hace con el ejecutable de PHP que se encuentra en el path.&lt;br /&gt;
&lt;br /&gt;
Para solucionarlo hay que agregar al PATH la ruta donde se encuentra PHP 5.3. En caso de no poder modificar el path por&amp;nbsp;algún&amp;nbsp;motivo en concreto&amp;nbsp;habría&amp;nbsp;que modificar el shebang de los ficheros que&amp;nbsp;están&amp;nbsp;dando problemas, indicando manualmente la ruta de PHP 5.3, esto ultimo no es muy aconsejable, pero bueno nos puede sacar de un apuro.&lt;/div&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/7998050589344089659/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2012/04/desplegar-symfony2-con-capifony.html#comment-form' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/7998050589344089659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/7998050589344089659'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2012/04/desplegar-symfony2-con-capifony.html' title='Desplegar Symfony2 con Capifony'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-4422155313557168185</id><published>2012-03-28T11:32:00.002+02:00</published><updated>2012-03-28T11:32:36.504+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="Symfony2"/><title type='text'>Symfony 2: múltiples formularios en una página</title><content type='html'>Al momento de usar dos formularios no relacionados en la misma pagina, surgieron mas complicaciones de las que me esperaba. Aunque cada formulario estuviera definido en su propio controlador y funcionaran correctamente cuando estaban aislados, al mostrarlos en la misma pagina obtuve dos errores:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;This form should not contain extra fields&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;The CSRF token is invalid&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;La manera de solucionarlo fue asignarle un nombre a cada formulario para comprobar que la solicitud esta asociada a dicho formulario. Para poder darle nombre a un formulario hay que acceder al servicio brindado por &lt;/span&gt;&lt;a href=&quot;http://api.symfony.com/2.0/Symfony/Component/Form/FormFactory.html&quot; target=&quot;_blank&quot;&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;FormFactory&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;usando el metodo &lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;createNamedBuilder&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;. Un ejemplo con la estructura&amp;nbsp;&lt;/span&gt;básica&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;seria el siguiente:&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;script src=&quot;https://gist.github.com/2224984.js&quot;&gt;
 
&lt;/script&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Un par de aclaraciones,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Acme&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;es una entidad,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;AcmeType&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;es un formulario definido en dicha clase.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Como se puede ver, el nombre del formulario es &lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;acme_form&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;, por el cual se puede identificar cual fue el formulario que genero la&amp;nbsp;&lt;/span&gt;petición&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;POST&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;. &amp;nbsp;&lt;/span&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/4422155313557168185/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2012/03/symfony-2-multiples-formularios-en-una.html#comment-form' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/4422155313557168185'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/4422155313557168185'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2012/03/symfony-2-multiples-formularios-en-una.html' title='Symfony 2: múltiples formularios en una página'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-8666011583439461726</id><published>2012-03-23T09:38:00.002+01:00</published><updated>2012-03-23T09:38:54.460+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Base de datos"/><category scheme="http://www.blogger.com/atom/ns#" term="Doctrine"/><category scheme="http://www.blogger.com/atom/ns#" term="Fixtures"/><category scheme="http://www.blogger.com/atom/ns#" term="PHPUnit"/><category scheme="http://www.blogger.com/atom/ns#" term="Symfony2"/><category scheme="http://www.blogger.com/atom/ns#" term="Testing"/><title type='text'>Symfony 2: Aislamiento de pruebas</title><content type='html'>La base de datos es parte de nuestra aplicación por lo que&amp;nbsp;también&amp;nbsp;debe formar parte de las pruebas. Ya que sino las pruebas&amp;nbsp;estarán&amp;nbsp;incompletas y dejaran un agujero en la calidad de nuestro software.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Las pruebas a una base de datos deben hacerse de manera aislada. ¿Que&amp;nbsp;pasaría&amp;nbsp;si una prueba corrompe la base de datos? Nuestro entorno de desarrollo se&amp;nbsp;vería&amp;nbsp;afectado y las siguientes ejecuciones de otras pruebas&amp;nbsp;podrían&amp;nbsp;fallar. Por lo que&amp;nbsp;habría&amp;nbsp;que&amp;nbsp;solucionar&amp;nbsp;el problema restaurando la base de datos.&amp;nbsp;Seguro que nadie quiere molestarse en perder tiempo volviendo a un estado fiable de la base de datos.&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
Un par de cosas a tener en mente a la hora de realizar las pruebas, que sean cortas y&amp;nbsp;concisas; y que la base de datos no tenga gran cantidad de datos (salvo que sea necesario) para poder ejecutar las pruebas&amp;nbsp;rápidamente.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Para lograr iniciar las pruebas siempre en el mismo estado y por ende que los cambios no se reflejen en la base de datos, tenemos que usar Doctrine Fixtures. Los fixtures permiten definir los datos que necesitamos &amp;nbsp;para una&amp;nbsp;ejecución&amp;nbsp;correcta de las pruebas. Estos deben ir definidos en la ruta &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;AcmeBundle/DataFixtures/ORM&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;, y su&amp;nbsp;&lt;/span&gt;definición&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;es bastante sencilla.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/2168158.js?file=gistfile1.aw&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;
Como podemos ver se crean cuatro objetos&lt;font face=&quot;&#39;Courier New&#39;, Courier, monospace&quot;&gt; certification, person, movie &lt;/font&gt;&lt;font face=&quot;inherit&quot;&gt;y&lt;/font&gt;&lt;font face=&quot;&#39;Courier New&#39;, Courier, monospace&quot;&gt; cast. &lt;/font&gt;&lt;font face=&quot;inherit&quot;&gt;Cada uno de ellos definidos en sus correspondientes entidades,&amp;nbsp;&lt;/font&gt;creándolos&lt;font face=&quot;inherit&quot;&gt;&amp;nbsp;y&amp;nbsp;&lt;/font&gt;manipulándolos&lt;font face=&quot;inherit&quot;&gt;&amp;nbsp;como en cualquier otra parte de nuestra aplicación. Se añade una referencia al objeto &lt;/font&gt;&lt;font face=&quot;&#39;Courier New&#39;, Courier, monospace&quot;&gt;movie &lt;/font&gt;&lt;font face=&quot;inherit&quot;&gt;para poder acceder a el desde otro fixture. Y finalmente se indica el orden de carga (en &lt;/font&gt;&lt;font face=&quot;&#39;Courier New&#39;, Courier, monospace&quot;&gt;getOrder&lt;/font&gt;&lt;font face=&quot;inherit&quot;&gt;) del fixture, para evitar violar las restricciones de la base de datos.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;
&lt;font face=&quot;inherit&quot;&gt;&lt;br&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;
&lt;font face=&quot;inherit&quot;&gt;Ya con los fixtures creados podemos cargarlos en el entorno de pruebas, para ello hay que cambiar&amp;nbsp;&lt;/font&gt;sobrescribir&lt;font face=&quot;inherit&quot;&gt;&amp;nbsp;en &lt;/font&gt;&lt;font face=&quot;&#39;Courier New&#39;, Courier, monospace&quot;&gt;config_test&lt;/font&gt;&lt;font face=&quot;inherit&quot;&gt; los&amp;nbsp;&lt;/font&gt;parámetros&lt;font face=&quot;inherit&quot;&gt;&amp;nbsp;de&amp;nbsp;&lt;/font&gt;conexión&lt;font face=&quot;inherit&quot;&gt;&amp;nbsp;a la base de datos.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;
&lt;font face=&quot;inherit&quot;&gt;&lt;br&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;
&lt;script src=&quot;https://gist.github.com/2168227.js?file=config_test.yml&quot;&gt;
&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
Y por ultimo hice un pequeño shell script con las ordenas para borrar el esquema actual, crear uno nuevo y cargar los datos.&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/2168240.js?file=load-fixtures.sh&quot;&gt;
&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
Con eso ya tenemos listo nuestro entorno de pruebas.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/8666011583439461726/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2012/03/symfony-2-aislamiento-de-pruebas.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/8666011583439461726'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/8666011583439461726'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2012/03/symfony-2-aislamiento-de-pruebas.html' title='Symfony 2: Aislamiento de pruebas'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-2177590105218811689</id><published>2012-03-15T10:58:00.003+01:00</published><updated>2012-03-15T10:59:07.776+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="FOSUserBundle"/><category scheme="http://www.blogger.com/atom/ns#" term="PHPUnit"/><category scheme="http://www.blogger.com/atom/ns#" term="Symfony2"/><category scheme="http://www.blogger.com/atom/ns#" term="Testing"/><title type='text'>Autentificación con Symfony2 y PHPUnit</title><content type='html'>Al momento de hacer pruebas es bastante mas comodo hacer la autentificación mediante HTTP basic que manejando los formularios con el crawler de Symfony2 (que por cierto me da bastantes problemas). Para poder iniciar sesion con los datos de un usuario en las pruebas, tenemos que agregar al fichero config_test.yml lo siguiente:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; security:  
   firewalls:  
     main:  
       pattern:  /.*  
       http_basic:  
         realm: &quot;Secured Area&quot;  
         provider: fos_userbundle  
       logout:   true  
       security:  true  
       stateless: true  
       anonymous: true  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
En mi caso uso FOSUB como proveedor de usuarios, si se usa otro proveedor obviamente habria que cambiarlo.&lt;br /&gt;
&lt;br /&gt;
Y finalmente en las las pruebas hay que crear el cliente como se indica en la documentación de Symfony.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; $client = static::createClient(array(), array(  
   &#39;PHP_AUTH_USER&#39; =&amp;gt; &#39;username&#39;,  
   &#39;PHP_AUTH_PW&#39;  =&amp;gt; &#39;pa$$word&#39;,  
 ));  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Algo bastante sencillo para los dolores de cabeza que me dio.</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/2177590105218811689/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2012/03/autentificacon-con-symfony2-y-phpunit.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/2177590105218811689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/2177590105218811689'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2012/03/autentificacon-con-symfony2-y-phpunit.html' title='Autentificación con Symfony2 y PHPUnit'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-637746760065481473</id><published>2012-03-14T22:13:00.000+01:00</published><updated>2012-03-14T22:14:07.435+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="LaTeX"/><title type='text'>Latex: instalar moderncv</title><content type='html'>Los paquetes de Latex que vienen empaquetados en Ubuntu son bastante viejos, pero por un tema de pereza y espacio (unos 2GB, para instalar manualmente la ultima&amp;nbsp;versión), sigo usando lo que viene por defecto con el sistema ya que no tengo que hacer nada muy avanzado ni complejo. Lo uso para escribir documentación y para hacer mi CV.&lt;br /&gt;
&lt;br /&gt;
El paquete que uso para mi CV es &lt;a href=&quot;http://www.ctan.org/tex-archive/macros/latex/contrib/moderncv/&quot; target=&quot;_blank&quot;&gt;moderncv&lt;/a&gt;,&amp;nbsp;hay que instalarlo manualmente y siempre me olvido como hacerlo,&amp;nbsp;así&amp;nbsp;que&amp;nbsp;ahí&amp;nbsp;va el mini tutorial:&lt;br /&gt;
&lt;br /&gt;

Descargamos el zip desde la pagina oficial y desde la carpeta se descomprimió ejecutamos lo siguiente:

&lt;pre  style=&quot;font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;padding:0px;color:#000000;text-align:left;line-height:20px;&quot;&gt;&lt;code style=&quot;color:#000000;word-wrap:normal;&quot;&gt; sudo rm -rf /usr/share/texmf-texlive/tex/latex/moderncv/  
 sudo mv moderncv/ /usr/share/texmf-texlive/tex/latex/  
 sudo texhash  
&lt;/code&gt;&lt;/pre&gt;

&lt;br /&gt;
La primer linea es para eliminar el paquete obsoleto de Ubuntu, la segunda para instalar el paquete nuevo, y la ultima para actualizar las referencias internas de Latex.

Y listo, nada mas.</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/637746760065481473/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2012/03/latex-instalar-moderncv.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/637746760065481473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/637746760065481473'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2012/03/latex-instalar-moderncv.html' title='Latex: instalar moderncv'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-6081743625943676914</id><published>2012-03-12T12:00:00.001+01:00</published><updated>2012-03-12T12:00:18.769+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Android"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="Symfony2"/><title type='text'>Android + Symfony2: Autentificación</title><content type='html'>Hoy en día una tarea bastante&amp;nbsp;común&amp;nbsp;es validar las credenciales de un usuario remotamente. En mi caso necesito que una aplicación&amp;nbsp;ejecutándose&amp;nbsp;en Android se valide en el sistema principal que esta construido con Symfony2 y con &lt;a href=&quot;https://github.com/FriendsOfSymfony/FOSUserBundle&quot; target=&quot;_blank&quot;&gt;FOSUserBundle&lt;/a&gt; como proveedor de usuarios.&lt;br /&gt;
&lt;br /&gt;
Ya que FOSUB se encarga de la&amp;nbsp;validación en el sitio web, lo ideal y mas&amp;nbsp;lógico&amp;nbsp;seria que&amp;nbsp;también&amp;nbsp;se encarga de la&amp;nbsp;validación&amp;nbsp;remota, evitando duplicar trabajo y cometer errores. En esencia es el mismo escenario&amp;nbsp;que cuando el usuario quiere iniciar&amp;nbsp;sesión&amp;nbsp;desde un navegador tradicional. Pero con algunas diferencias,&amp;nbsp;así&amp;nbsp;que manos a la obra.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Symfony2&lt;/span&gt;&lt;br /&gt;
En nuestro proyecto de Symfony tenemos que definir un firewall para hacer accesible la autentificacion via HTTP:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;security.yml&lt;/b&gt;&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; api:  
  pattern: ^/api/.*  
  stateless: true  
  security: true  
  http_basic:  
    realm: &quot;API&quot;  

access_control:
  - { path: /api/, role: ROLE_USER }
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Con estas lineas presentes en el firewall, cada vez que se quiera acceder una ruta del siguiente tipo &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;lt;nuestro-domino&amp;gt;/api/&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;se generara una&amp;nbsp;&lt;/span&gt;petición&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;para&amp;nbsp;&lt;/span&gt;iniciar&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;&lt;/span&gt;sesión&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;mediante HTTP.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;b&gt;routing.yml&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; api_login:  
   pattern: /api/login  
   defaults: { _controller: AcmeUserBundle:Security:apiLogin }  
&lt;/code&gt;&lt;/pre&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;En el rounting es necesario indicar el controlador y la acción a realizar.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;b&gt;SecurityController&lt;/b&gt;&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; public function apiLoginAction()  
 {  
   $response = new Response();  
   $response-&amp;gt;setContent(&#39;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;OK&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&#39;);  
   $response-&amp;gt;setStatusCode(200);  
   $response-&amp;gt;headers-&amp;gt;set(&#39;Content-Type&#39;, &#39;text/html&#39;);  
   
   return $response;  
 }  
&lt;/code&gt;&lt;/pre&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Y finalmente en el controlador generamos la respuesta, es muy importante indicar el&amp;nbsp;&lt;/span&gt;código&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;html de la respuesta para poder saber en Android si el login fue correcto o no.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Android&lt;/span&gt;&lt;br /&gt;
En Android hay que implementar la siguiente funcion, creando un cliente HTML y dandole una peticion GET para acceder a la URL.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;span style=&quot;color: teal;&quot;&gt;  1&lt;/span&gt; &lt;span style=&quot;color: blue;&quot;&gt;public&lt;/span&gt; int login(String username, String password)
&lt;span style=&quot;color: teal;&quot;&gt;  2&lt;/span&gt; { 
&lt;span style=&quot;color: teal;&quot;&gt;  3&lt;/span&gt;     HttpClient httpClient = &lt;span style=&quot;color: blue;&quot;&gt;new&lt;/span&gt; DefaultHttpClient();
&lt;span style=&quot;color: teal;&quot;&gt;  4&lt;/span&gt;      
&lt;span style=&quot;color: teal;&quot;&gt;  5&lt;/span&gt;     &lt;span style=&quot;color: green;&quot;&gt;//construir peticion get&lt;/span&gt; 
&lt;span style=&quot;color: teal;&quot;&gt;  6&lt;/span&gt;     HttpGet httpGet = &lt;span style=&quot;color: blue;&quot;&gt;new&lt;/span&gt; HttpGet(&lt;span style=&quot;color: maroon;&quot;&gt;&quot;url&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: teal;&quot;&gt;  7&lt;/span&gt;     httpGet.addHeader(BasicScheme.authenticate( 
&lt;span style=&quot;color: teal;&quot;&gt;  8&lt;/span&gt;             &lt;span style=&quot;color: blue;&quot;&gt;new&lt;/span&gt; UsernamePasswordCredentials(username,password), &lt;span style=&quot;color: maroon;&quot;&gt;&quot;UTF-8&quot;&lt;/span&gt;, &lt;span style=&quot;color: maroon;&quot;&gt;false&lt;/span&gt;)); 
&lt;span style=&quot;color: teal;&quot;&gt;  9&lt;/span&gt;      
&lt;span style=&quot;color: teal;&quot;&gt; 10&lt;/span&gt;     &lt;span style=&quot;color: green;&quot;&gt;//ejecutar get y recibir respuesta&lt;/span&gt; 
&lt;span style=&quot;color: teal;&quot;&gt; 11&lt;/span&gt;     HttpResponse response = &lt;span style=&quot;color: blue;&quot;&gt;null&lt;/span&gt;; 
&lt;span style=&quot;color: teal;&quot;&gt; 12&lt;/span&gt;     Boolean error = &lt;span style=&quot;color: maroon;&quot;&gt;false&lt;/span&gt;; 
&lt;span style=&quot;color: teal;&quot;&gt; 13&lt;/span&gt;     &lt;span style=&quot;color: blue;&quot;&gt;try&lt;/span&gt; { 
&lt;span style=&quot;color: teal;&quot;&gt; 14&lt;/span&gt;         response = httpClient.execute(httpGet); 
&lt;span style=&quot;color: teal;&quot;&gt; 15&lt;/span&gt;     } &lt;span style=&quot;color: blue;&quot;&gt;catch&lt;/span&gt; (ClientProtocolException e) { 
&lt;span style=&quot;color: teal;&quot;&gt; 16&lt;/span&gt;         error = &lt;span style=&quot;color: maroon;&quot;&gt;true&lt;/span&gt;; 
&lt;span style=&quot;color: teal;&quot;&gt; 17&lt;/span&gt;         e.printStackTrace(); 
&lt;span style=&quot;color: teal;&quot;&gt; 18&lt;/span&gt;     } &lt;span style=&quot;color: blue;&quot;&gt;catch&lt;/span&gt; (IOException e) { 
&lt;span style=&quot;color: teal;&quot;&gt; 19&lt;/span&gt;         error = &lt;span style=&quot;color: maroon;&quot;&gt;true&lt;/span&gt;; 
&lt;span style=&quot;color: teal;&quot;&gt; 20&lt;/span&gt;         e.printStackTrace(); 
&lt;span style=&quot;color: teal;&quot;&gt; 21&lt;/span&gt;     } &lt;span style=&quot;color: blue;&quot;&gt;finally&lt;/span&gt;{ 
&lt;span style=&quot;color: teal;&quot;&gt; 22&lt;/span&gt;         &lt;span style=&quot;color: green;&quot;&gt;//cerrar conexion htl y liberar recursos&lt;/span&gt;
&lt;span style=&quot;color: teal;&quot;&gt; 23&lt;/span&gt;         httpClient.getConnectionManager().shutdown(); 
&lt;span style=&quot;color: teal;&quot;&gt; 24&lt;/span&gt;     } 
&lt;span style=&quot;color: teal;&quot;&gt; 25&lt;/span&gt;      
&lt;span style=&quot;color: teal;&quot;&gt; 26&lt;/span&gt;     &lt;span style=&quot;color: green;&quot;&gt;//devolver algun codigo (exito, fallo, error, etc) &lt;/span&gt;
&lt;span style=&quot;color: teal;&quot;&gt; 27&lt;/span&gt; }&lt;/pre&gt;
&lt;br /&gt;
Este es el caso mas&amp;nbsp;básico&amp;nbsp;de autentificación, ya que al ser HTTP Basic, el usuario y el password van en texto plano. Pero para la etapa de desarrollo y&amp;nbsp;depuración&amp;nbsp;es bastante&amp;nbsp;útil.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Y con esto&amp;nbsp;estaría&amp;nbsp;todo funcionando. Mas adelante me tocara implementar un inicio de&amp;nbsp;sesión para producción (así&amp;nbsp;que&amp;nbsp;tendrá&amp;nbsp;que ser seguro),&amp;nbsp;así&amp;nbsp;que eso ya&amp;nbsp;vendrá&amp;nbsp;en otro post.</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/6081743625943676914/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2012/03/android-symfony2-autentificacion.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/6081743625943676914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/6081743625943676914'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2012/03/android-symfony2-autentificacion.html' title='Android + Symfony2: Autentificación'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-910678414014669837</id><published>2012-03-08T11:23:00.000+01:00</published><updated>2012-03-08T11:23:28.975+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="Testing"/><category scheme="http://www.blogger.com/atom/ns#" term="XAMPP"/><title type='text'>Instalar PHPUnit en XAMPP</title><content type='html'>&lt;a href=&quot;http://www.phpunit.de/manual/3.7/en/automating-tests.html&quot; target=&quot;_blank&quot;&gt;PHPUnit&lt;/a&gt; es un framework para la&amp;nbsp;realización&amp;nbsp;de pruebas unitarias en PHP. Mi entorno de desarrollo normalmente es XAMPP, asi que vamos a ver como se instala PHPUnit en XAMPP.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;cd /opt/lampp/bin&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;sudo ./pear config-set auto_discover 1&amp;nbsp;&lt;/span&gt;&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;sudo ./pear install pear.phpunit.de/PHPUnit&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Y por ultimo habria que indicadarle a nuestro IDE donde encontrar el ejecutable de PHPUnit, su ruta es&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;/opt/lampp/bin/phpunit&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
¿Complicado no?&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/910678414014669837/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2012/03/instalar-phpunit-en-xampp.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/910678414014669837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/910678414014669837'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2012/03/instalar-phpunit-en-xampp.html' title='Instalar PHPUnit en XAMPP'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-6338799089117400662</id><published>2012-03-07T17:26:00.000+01:00</published><updated>2012-03-08T08:57:09.994+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Android"/><title type='text'>Android: pasando datos entre Actividades</title><content type='html'>En muchas ocasiones al iniciar una &lt;a href=&quot;http://developer.android.com/reference/android/app/Activity.html&quot; target=&quot;_blank&quot;&gt;actividad&lt;/a&gt;&amp;nbsp;necesitamos&amp;nbsp;enviar&amp;nbsp;información&amp;nbsp;extra. Se&amp;nbsp;podría&amp;nbsp;asimilar con&amp;nbsp;un&amp;nbsp;parámetro&amp;nbsp;de una&amp;nbsp;función, pero no disponemos de ellos.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Objetivo&lt;/span&gt;&lt;br /&gt;
El usuario indica la ruta de un fichero en una actividad y se pasa la ruta a la actividad siguiente.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Pasando los datos&lt;/span&gt;&lt;br /&gt;
Para poder enviar los datos a otra actividad debemos hacerlo mediante un &lt;a href=&quot;http://developer.android.com/reference/android/os/Bundle.html&quot; target=&quot;_blank&quot;&gt;Bundle&lt;/a&gt;. A grandes rasgos un &amp;nbsp;Bundle es un contenedor de tipos primitivos, y su uso es bastante sencillo.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;1:  Intent player = new Intent(this, Player.class);  
2:    
3:  String path = &quot;/sdcard/clip.avi&quot;  
4:              
5:  Bundle bundle = new Bundle();  
6:  bundle.putString(&quot;filePath&quot;, path);  
7:    
8:  player.putExtras(bundle);  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Con un par de lineas esta todo hecho. Se crea un Bundle se le agregan todos los datos que queramos (en mi caso solo preciso un String) y finalmente se agrega el Bundle al Intent mediante &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;putExtras.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Recibiendo los datos&lt;/span&gt;&lt;br /&gt;
Y para ir finalizando solo queda recuperar los datos desde la actividad&amp;nbsp;recién&amp;nbsp;iniciada.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt; Bundle bundle = getIntent().getExtras();  
 String filePath = bundle.getString(&quot;filePath&quot;);  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Y colorín colorado este cuento se ha acabado.</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/6338799089117400662/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2012/03/android-pasando-datos-entre-actividades.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/6338799089117400662'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/6338799089117400662'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2012/03/android-pasando-datos-entre-actividades.html' title='Android: pasando datos entre Actividades'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-5069038515544902396</id><published>2012-03-06T16:28:00.001+01:00</published><updated>2012-03-06T16:29:42.134+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Android"/><category scheme="http://www.blogger.com/atom/ns#" term="Eclipse"/><category scheme="http://www.blogger.com/atom/ns#" term="Linux"/><title type='text'>Android: Emular tarjeta SD con Eclipse</title><content type='html'>Muchas veces no tenes un dispositivo a mano para poder desplegar nuestra&amp;nbsp;aplicación, por lo que tenemos que usar el emular para ir depurando. Y en alguno de esos caso necesitamos depurar el acceso a una tarjeta SD. Para poder emular una tarjeta SD hay que crear una imagen, montarla, copiar el contenido y finalmente usarla con el emulador.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Creando la imagen&lt;/span&gt;&lt;br /&gt;
El SDK de Android contiene varias herramientas una de ellas es&lt;span style=&quot;background-color: white;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;mksdcard&lt;/span&gt;, de la ayuda del ejecutable podemos ver:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
mksdcard: create a blank FAT32 image to be used with the Android emulator.&lt;br /&gt;
usage: mksdcard [-l label] &amp;lt;size&amp;gt; &amp;lt;file&amp;gt;&lt;br /&gt;
if &amp;lt;size&amp;gt; is a simple integer, it specifies a size in bytes&lt;br /&gt;
if &amp;lt;size&amp;gt; is an integer followed by &#39;K&#39;, it specifies a size in KiB&lt;br /&gt;
if &amp;lt;size&amp;gt; is an integer followed by &#39;M&#39;, it specifies a size in MiB&lt;br /&gt;
if &amp;lt;size&amp;gt; is an integer followed by &#39;G&#39;, it specifies a size in GiB&lt;br /&gt;
Minimum size is 9M. The Android emulator cannot use smaller images.&lt;br /&gt;
Maximum size is 1099511627264 bytes, 1073741823K, 1048575M or 1023G&lt;/blockquote&gt;
&lt;br /&gt;
Sino tenemos el SDK de android como variable de entorno nos desplazamos a &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;android-sdk-linux/tools&lt;/span&gt;&amp;nbsp;y ejecutamos&lt;br /&gt;
&lt;br /&gt;
./mksdcard 512M droidcard&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Montando la tarjeta en Linux&lt;/span&gt;&lt;br /&gt;
Una de las maneras de pasar ficheros a la tarjeta es haciendo un &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;push&lt;/span&gt; mediante &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;adb &lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;pero para mi gusto es mas&amp;nbsp;&lt;/span&gt;fácil&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;montar la tarjeta y copiar todo lo queramos como si fuera una carpeta mas. Para eso es necesario crear un punto de montaje para luego poder montar la tarjeta.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;sudo mkdir /media/droidcard&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;sudo mount -o loop droidcard /media/droidcard&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Nota: el nombre del fichero de la tarjeta no tiene porque coincidir con el punto de montaje.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Agregando ficheros a la tarjeta&lt;/span&gt;&lt;br /&gt;
A estas alturas ya&amp;nbsp;podríamos&amp;nbsp;estar copiando (como root) cosas a nuestra tarjeta sin&amp;nbsp;ningún&amp;nbsp;problema. Una vez terminado hay que desmontarla para poder usarla con el emulador.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;sudo umount /media/droidcard&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-large;&quot;&gt;Usando la tarjeta en el emulador&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
En Eclipse dentro de &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Run configuration, &lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;vamos a la&amp;nbsp;&lt;/span&gt;opción&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;, y en &lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Additional configuration command line options &lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;agregamos el siguiente comando:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;-sdcard /ruta/a/tu/tarjeta&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Y listo, eso es todo.</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/5069038515544902396/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2012/03/android-emular-tarjeta-sd-con-eclipse.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/5069038515544902396'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/5069038515544902396'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2012/03/android-emular-tarjeta-sd-con-eclipse.html' title='Android: Emular tarjeta SD con Eclipse'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-9046143327705606458</id><published>2012-02-01T11:46:00.000+01:00</published><updated>2012-02-03T16:22:56.799+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><title type='text'>XAMPP + NetBeans + Symfony</title><content type='html'>Para tener Symfony funcionando al 100% con XAMPP y Netbeans hay que hacer unas pequeñas configuraciones.&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: large;&quot;&gt;Symfony&lt;/span&gt;&lt;br /&gt;
Simplemente bajar el .tar de la pagina web de symfony y descomprimirlo. En mi caso esta en&lt;br /&gt;
/home/alexis/programas/symfony&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: large;&quot;&gt;XAMPP&lt;/span&gt;&lt;br /&gt;
Para que el servidor sea capaz de acceder al contenido de Symfony y evitar que los archivos que no&amp;nbsp;estén&amp;nbsp;en la carpeta web de nuestro proyecto sean visibles hay que modificar dos ficheros de configuracion&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;/opt/lampp/etc/httpd.conf&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;VirtualHost 127.0.0.1:80&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; ServerName www.nuestraapp.com.localhost&lt;br /&gt;
&amp;nbsp; &amp;nbsp; DocumentRoot &quot;/home/alexis/NetBeansProjects/nuestraapp/web&quot;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; DirectoryIndex index.php&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;lt;Directory &quot;/home/alexis/NetBeansProjects/nuestraapp/web&quot;&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; AllowOverride All&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Allow from All&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; Alias /sf /home/alexis/programas/symfony/data/web/sf&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;lt;Directory &quot;/home/alexis/programas/symfony/data/web/sf&quot;&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; AllowOverride All&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Allow from All&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;lt;/Directory&amp;gt;&lt;br /&gt;
&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;/etc/hosts&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
127.0.0.1&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;www.nuestraapp.com.localhost&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: large;&quot;&gt;Netbeans&lt;/span&gt;&lt;br /&gt;
Hay que indicar donde esta el interprete PHP, agregar Symfony al path por defecto y indicarle a nuestro proyecto la URL del mismo.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAEgojBjQZRTHLAzkJQXo4amCiRmJz_DQl9HCRMHtDPwVYkyottEfSqbA07RRVjdgnHa7ajpeziqh96vkU_RvNzovzbAVZGsP0DhbWQIFNdJXxldsz0QckKyqGu7-139DhITQTo4Sy02KC/s1600/symfony.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;494&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAEgojBjQZRTHLAzkJQXo4amCiRmJz_DQl9HCRMHtDPwVYkyottEfSqbA07RRVjdgnHa7ajpeziqh96vkU_RvNzovzbAVZGsP0DhbWQIFNdJXxldsz0QckKyqGu7-139DhITQTo4Sy02KC/s640/symfony.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Interprete PHP&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoK6GLV3h3pmn3fQsFsEzIKiGBMDbBbLn0XcO7nA-b-ZQz6DStGosOeutG39FzaJP2iLorKRb2Wwjkqk2RVcTtqkn8stxg5IiKT54vxX_EqgpaGCt0_RCl7GmTxGwxPl46hOb7ZVkiOlqw/s1600/path.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;493&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoK6GLV3h3pmn3fQsFsEzIKiGBMDbBbLn0XcO7nA-b-ZQz6DStGosOeutG39FzaJP2iLorKRb2Wwjkqk2RVcTtqkn8stxg5IiKT54vxX_EqgpaGCt0_RCl7GmTxGwxPl46hOb7ZVkiOlqw/s640/path.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Inclusión de Symfony en el path.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj42cyo6CIvK190fyMV2ZN0eAxxPUMXLMhIr7ddvIhnAhjq2IHcZPYLaMWlb5TnptUyWxLOopTtm-2IoExRUeHGW5Bgk5AEFlcPTluuIofUuI05AYw2S3n6aOYq3hc_aSrSRxeC72mYItHd/s1600/url.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;423&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj42cyo6CIvK190fyMV2ZN0eAxxPUMXLMhIr7ddvIhnAhjq2IHcZPYLaMWlb5TnptUyWxLOopTtm-2IoExRUeHGW5Bgk5AEFlcPTluuIofUuI05AYw2S3n6aOYq3hc_aSrSRxeC72mYItHd/s640/url.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;URL de nuestro proyecto&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: large;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: large;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: large;&quot;&gt;&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/9046143327705606458/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2012/02/xampp-netbeans-symfony.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/9046143327705606458'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/9046143327705606458'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2012/02/xampp-netbeans-symfony.html' title='XAMPP + NetBeans + Symfony'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAEgojBjQZRTHLAzkJQXo4amCiRmJz_DQl9HCRMHtDPwVYkyottEfSqbA07RRVjdgnHa7ajpeziqh96vkU_RvNzovzbAVZGsP0DhbWQIFNdJXxldsz0QckKyqGu7-139DhITQTo4Sy02KC/s72-c/symfony.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-1963704104135805165</id><published>2011-12-06T00:40:00.001+01:00</published><updated>2011-12-18T20:22:35.952+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Android"/><category scheme="http://www.blogger.com/atom/ns#" term="Broadcast"/><category scheme="http://www.blogger.com/atom/ns#" term="Redes"/><category scheme="http://www.blogger.com/atom/ns#" term="UDP"/><title type='text'>Broadcast en una LAN</title><content type='html'>Varias veces me he topado con tener que hacer un pequeño servicio de descubrimiento para localizar un servicio en una LAN. Siempre caigo en la trampa de enviar los datos a las dirección de broadcast predeterminada. Y en cada uno de los intentos&amp;nbsp;el broadcast no se llevaba a cabo.&lt;br /&gt;
&lt;br /&gt;
El siguiente ejemplo esta hecho para Android, pero la idea es la misma para todas las plataformas, obtener la&amp;nbsp;dirección&amp;nbsp;IP donde se esta ejecutando nuestra&amp;nbsp;aplicación&amp;nbsp;y la mascara de red, con esos datos se aplica un AND y vamos obteniendo byte a byte la dirección IP.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;1:  DhcpInfo dhcp = wifi.getDhcpInfo();  
2:  int broadcast = (dhcp.ipAddress &amp;amp; dhcp.netmask) | ~dhcp.netmask;  
3:  byte[] ip = new byte[4];  
4:  for (int i = 0; i &amp;lt; 4; i++)  
5:    ip[i] = (byte) ((broadcast &amp;gt;&amp;gt; i * 8) &amp;amp; 0xFF);  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Otra metida de pata basten comun es usar el mismo puerto en el cliente y en el servidor,&amp;nbsp;por lo que al hacer el broadcast detectamos que nos llegan datos al puerto donde estamos esperando la respuesta cuando en realidad es el mensaje que acabamos de difundir por la red.</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/1963704104135805165/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2011/12/broadcast-en-una-lan.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/1963704104135805165'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/1963704104135805165'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2011/12/broadcast-en-una-lan.html' title='Broadcast en una LAN'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-960970934494765633</id><published>2011-12-03T18:54:00.001+01:00</published><updated>2011-12-03T19:55:29.882+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NetMF"/><category scheme="http://www.blogger.com/atom/ns#" term="Dispatcher"/><category scheme="http://www.blogger.com/atom/ns#" term="Threading"/><title type='text'>Permisos de acceso en hilos (.Net MF)</title><content type='html'>Trabajando para un proyecto de la&amp;nbsp;universidad&amp;nbsp;me toco implementar el refresco&amp;nbsp;automático&amp;nbsp;de la interfaz de usuario de la&amp;nbsp;aplicación.&amp;nbsp;Básicamente&amp;nbsp;era llamar a un&amp;nbsp;método&amp;nbsp;que recogiera las medidas de los diferentes sensores conectados a una placa Tahoe II y actualizar los valores en pantalla. Hasta&amp;nbsp;ahí&amp;nbsp;todo bien, una tarea que a priori no&amp;nbsp;debería&amp;nbsp;llevar mucho tiempo.&lt;br /&gt;
&lt;br /&gt;
Lo raro era que cuando la&amp;nbsp;obtención&amp;nbsp;de datos se hacia solo una vez funcionaba todo correctamente, pero al introducir el Timer para realizar la&amp;nbsp;actualización&amp;nbsp;cada 10 segundos,&amp;nbsp;empezó&amp;nbsp;a generarse el error&amp;nbsp;InvalidOperationException. Mi primera&amp;nbsp;reacción&amp;nbsp;fue&amp;nbsp;alguna&amp;nbsp;condición&amp;nbsp;de carrera estaba jodiendo todo, pero al mirar bien la documentación me di cuenta que no era eso. Sino que desde el Timer no se&amp;nbsp;tenían&amp;nbsp;los permisos de acceso adecuados para llamar a un objeto&amp;nbsp;de otro Thread, en este caso el hilo principal.&lt;br /&gt;
&lt;br /&gt;
Resulta que usar un Thread o un Timer fue una mala elección, en su lugar la mejor opcion es usar la clase DispatcherTimer, en la que los permisos de acceso son totalmente transparentes para el programador. Y todo el problema se reduce a las siguientes lineas&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;1:  refreshTimer = new DispatcherTimer(currentView.Dispatcher);  
2:  refreshTimer.Interval = new TimeSpan(0, 0, periodTime);  
3:  refreshTimer.Tick +=new EventHandler(refreshRoutine);  
4:  refreshTimer.Start();  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
En este caso currentView es el objeto al que queremos acceder, y refreshRoutine es el&amp;nbsp;método&amp;nbsp;que queremos ejecutar para actualizar la pantalla.</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/960970934494765633/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2011/12/permisos-de-acceso-en-hilos-net-mf.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/960970934494765633'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/960970934494765633'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2011/12/permisos-de-acceso-en-hilos-net-mf.html' title='Permisos de acceso en hilos (.Net MF)'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-8374913724952198721</id><published>2011-11-08T20:49:00.002+01:00</published><updated>2011-11-08T20:49:18.177+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="DPWS"/><category scheme="http://www.blogger.com/atom/ns#" term="Web services"/><title type='text'>Introducción a DPWS</title><content type='html'>El&amp;nbsp;estándar&amp;nbsp;DPWS es el acrónimo de &lt;i&gt;Devices Profile for Web Services, &lt;/i&gt;define las funcionalidades&amp;nbsp;mínimas&amp;nbsp;para garantizar :&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;comunicación&amp;nbsp;bidireccional y de manera segura con un servicio web&lt;/li&gt;
&lt;li&gt;descubrimiento&amp;nbsp;dinámico&amp;nbsp;de un servicio web&lt;/li&gt;
&lt;li&gt;descripción de un servicio web&lt;/li&gt;
&lt;li&gt;suscribirse y recibir eventos de un servicio web.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Como podemos ver en la figura 1, un dispositivo (terminal que brinda servicios) podrá&amp;nbsp;albergar mas de un servicio web, y&amp;nbsp;podrá manejar&amp;nbsp;múltiples&amp;nbsp;conexiones con diferentes clientes.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjT6J3mX2hvyrh-dvqPAQPxCdRkHCR3ULEo6U1gXCsSRPnWNQq6qWTwjOGL0qSqi5S0ugpCNhTRzKXyIgRTszWZQeeKMGJ3mhZl6yQpz6U47PpEj8ks8VjdTrwR8cAfKtjgn2Q5nCmP_nLc/s1600/cliente-host.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;300&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjT6J3mX2hvyrh-dvqPAQPxCdRkHCR3ULEo6U1gXCsSRPnWNQq6qWTwjOGL0qSqi5S0ugpCNhTRzKXyIgRTszWZQeeKMGJ3mhZl6yQpz6U47PpEj8ks8VjdTrwR8cAfKtjgn2Q5nCmP_nLc/s400/cliente-host.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figura 1: clientes y dispositivos.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div&gt;
La comunicación se hace a&amp;nbsp;través&amp;nbsp;de mensaje. Siempre contienen un mensaje SOAP y generalmente transportan encabezados HTTP, TCP y de IP.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: large;&quot;&gt;Descubrimiento&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
El descubrimiento es el mecanismo por el que el cliente es capaz de detectar un servicio que se encuentre en su propia red. Sin embargo si el cliente y el servicio&amp;nbsp;estén&amp;nbsp;en redes&amp;nbsp;distintas, la comunicación sera posible siempre y cuando el cliente tenga una IP y un puerto al que enviar la petición.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Los mensajes &lt;i&gt;Hello, Bye, Probe y Resolve&lt;/i&gt;, son los que definen y hacen posible el servicio de descubrimiento. Cuando un dispositivo que brinda un servicio se conecta a la red,&amp;nbsp;envía&amp;nbsp;un mensaje &lt;i&gt;Hello,&lt;/i&gt; notificando al resto de equipos de la red que esta brindando un servicio. Por otra parte si el cliente no sabe a quien acudir para hacer uso de un servicio, enviara un mensaje &lt;i&gt;Probe &lt;/i&gt;(o &lt;i&gt;Resolve&lt;/i&gt; en caso de estar en redes distintas). Y por ultimo si el dispositivo deja la red enviara un mensaje &lt;i&gt;Bye&lt;/i&gt;, para que el resto se enteren de su marcha.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Los servicios se agrupan en dispositivos para evitar la saturación de redes con capacidad limitada. Por ejemplo si un dispositivo tiene 15 servicios, se enviara un solo mensaje Hello a la red anunciando que el dispositivo tiene dichos servicios, en lugar de enviar 15 mensajes, uno para cada servicio.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: large;&quot;&gt;Descripción&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
Cada dispositivo tiene la habilidad de describirse a si mismo, en otras palabras, sabe que servicios brinda y es capaz de&amp;nbsp;comunicárselo&amp;nbsp;a los clientes.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Cuando un cliente&amp;nbsp;envía&amp;nbsp;la&amp;nbsp;petición&amp;nbsp;WS-Transfer Get SOAP ENVELOPE a un dispositivo&amp;nbsp;obtendrá una respuesta con la siguiente información:&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;&amp;nbsp;Modelo (modelo, numero de modelo, fabricante, etc)&lt;/li&gt;
&lt;li&gt;Dispositivo (firmware, numero de serie, etc)&lt;/li&gt;
&lt;li&gt;Servicios (tipo,&amp;nbsp;dirección, etc)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
Los servicios&amp;nbsp;también&amp;nbsp;tiene la habilidad de describirse, esto podemos hacerlo una vez que sepamos los datos del dispositivo. Para saber que funcionalidades brinda un servicio lo hacemos con GetMetadata.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: large;&quot;&gt;Eventos&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
Como cualquier lenguaje orientado a objetos, el DPWS nos brinda la posibilidad de sincronizar los clientes y los dispositivos mediante eventos. Los eventos son lanzados por los&amp;nbsp;dispositivos&amp;nbsp;y los clientes que&amp;nbsp;estén&amp;nbsp;suscritos&amp;nbsp;podrán&amp;nbsp;manejar los eventos y realizar las acciones que sean necesarias. Si por&amp;nbsp;algún&amp;nbsp;casual lo que nos interesa es suscribirnos a un tipo determinado de eventos, se pueden aplicar filtrados para conseguirlo.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: large;&quot;&gt;Seguridad&lt;/span&gt;&lt;br /&gt;
El&amp;nbsp;estándar&amp;nbsp;no especifica una&amp;nbsp;política&amp;nbsp;de seguridad especifica sino que da un serie de pautas a seguir. Se recomienda:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;firma: para validar la información de los mensajes enviados sin encriptar&lt;/li&gt;
&lt;li&gt;canal seguro:&amp;nbsp;comunicación&amp;nbsp;punto a punto a&amp;nbsp;través&amp;nbsp;de TLS/SSL&lt;/li&gt;
&lt;li&gt;certificado: credencial usada por un cliente o dispositivo para autentificarse&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
Para la&amp;nbsp;próxima&amp;nbsp;un ejemplo de como se crea y configura todo esto con .Net Micro Framework.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/8374913724952198721/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2011/11/introduccion-dpws.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/8374913724952198721'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/8374913724952198721'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2011/11/introduccion-dpws.html' title='Introducción a DPWS'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjT6J3mX2hvyrh-dvqPAQPxCdRkHCR3ULEo6U1gXCsSRPnWNQq6qWTwjOGL0qSqi5S0ugpCNhTRzKXyIgRTszWZQeeKMGJ3mhZl6yQpz6U47PpEj8ks8VjdTrwR8cAfKtjgn2Q5nCmP_nLc/s72-c/cliente-host.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2993584829070686554.post-4126542657375162334</id><published>2011-11-03T19:22:00.002+01:00</published><updated>2011-11-03T21:30:28.372+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Android"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><title type='text'>Primeros pasos con Android</title><content type='html'>&lt;div&gt;
Se&amp;nbsp;podría&amp;nbsp;decir que en toda&amp;nbsp;aplicación&amp;nbsp;Android (con interfaz&amp;nbsp;gráfica) tendremos tres elementos&amp;nbsp;básicos: Views,&amp;nbsp;Layouts y Events.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Los objetos de tipo &lt;i&gt;View&lt;/i&gt; son todos aquellos que el usuario puede ver, es decir, texto,&amp;nbsp;imágenes&amp;nbsp;o botones por nombrar algunos. Los &lt;i&gt;layouts&lt;/i&gt;&amp;nbsp;nos brindaran la infraestructura necesaria para poder organizar como queremos mostrar los diferentes objetos de tipo View en la pantalla de nuestro Android. Y por ultimo los &lt;i&gt;Events&lt;/i&gt;, son los encargados de capturar las acciones realizadas por el usuario y llevar a cabo alguna&amp;nbsp;acción, por ejemplo al tocar un&amp;nbsp;botón&amp;nbsp;emitir un sonido.&lt;br /&gt;
&lt;br /&gt;
A esto es a lo que queremos llegar:&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg92cVUQXVV1lTBcd-lW4AnQ3LK0gjhLPSXLUJGiQz7gvgudhMmvCYbluArBnT8JNtsYxlPIrUy7lSTK6HlRXbLtIhk1U_0yhOuzJjZUbhFxyUZ1cTBTmfNO4VejQmO_sL7GIa955h8Nxvg/s320/resultado.png&quot; width=&quot;201&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: small;&quot;&gt;Imagen usada de fondo fue obtenida de&amp;nbsp;&lt;a href=&quot;http://140geek.com/&quot;&gt;140geek&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Nuestro hola mundo, contiene una imagen sobre la cual se escribe el mensaje &quot;¡Hola Mundo!&quot; y en la parte inferior tenemos la leyenda &quot;Tocar la pantalla para salir.&quot;.&lt;br /&gt;
&lt;br /&gt;
Cuando generemos el proyecto con Eclipse o Motodev (un eclipse tuneado para desarrollar en Android),&amp;nbsp;únicamente&amp;nbsp;tendremos el&amp;nbsp;método&amp;nbsp;onCreate (nuestro &quot;main&quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;1:  public class HelloWorld extends Activity {  
2:    /** Called when the activity is first created. */  
3:    @Override  
4:    public void onCreate(Bundle savedInstanceState) {  
5:      super.onCreate(savedInstanceState);  
6:    }  
7:  }  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
A excepción del ultimo fragmento de&amp;nbsp;código&amp;nbsp;y del fichero xml, todos los fragmentos siguientes deben ir dentro del&amp;nbsp;método&amp;nbsp;onCreate.&lt;br /&gt;
&lt;br /&gt;
Para mostrar texto en pantalla, tenemos que usar objetos de tipo TextView. En las lineas 2 y 8 obtenemos el texto con id &lt;i&gt;hello&lt;/i&gt; y &lt;i&gt;msgExit&lt;/i&gt; respectivamente desde el gestor de recursos. Sino queremos usar el gestor de recursos y poner una cadena de texto normal entre comillas&amp;nbsp;también&amp;nbsp;es valido.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;1:  TextView tvHello = new TextView(this);  
2:  tvHello.setText(R.string.hello);     //obtenemos el string con id hello
3:  tvHello.setGravity(Gravity.CENTER);  //centramos el texto en la pantalla
4:  tvHello.setTextColor(Color.BLACK);   //cambiamos el color de la fuente
5:  tvHello.setTextSize(20);             //cambiamos el tamaño de la fuente
6:    
7:  TextView tvExit = new TextView(this);  
8:  tvExit.setText(R.string.msgExit);  
9:  tvExit.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);  
10:  tvExit.setTextColor(Color.BLACK);  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1edekfOs-Wo4GGcj4o-MmrOvF5MF1fz57pVyTQSKgn8FrSGDEodZH5OncQ0RwlepFYWfCmOo16s2y-2o8SGirh60LBP0J6eXeFX0lD30pNWfTHQdBiWFS1-RBpW68htppokswz_Ensw6k/s1600/res.png&quot; /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
En el explorador de paquetes, nos encontramos con la carpeta &lt;i&gt;res, &lt;/i&gt;donde&amp;nbsp;estarán&amp;nbsp;los recursos contenidos en el gestor de recursos. Si queremos agregar alguna imagen basta con copiarla a alguna de las carpetas &lt;i&gt;drawable&lt;/i&gt;&amp;nbsp;y el identificador sera el nombre del fichero. En cambio para agregar cadenas de texto, tenemos que modificar el fichero &lt;i&gt;strings.xml&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;1:  &amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&amp;gt;  
2:  &amp;lt;resources&amp;gt;  
3:    &amp;lt;string name=&quot;hello&quot;&amp;gt;¡Hola Mundo!&amp;lt;/string&amp;gt;  
4:    &amp;lt;string name=&quot;app_name&quot;&amp;gt;Hola Mundo&amp;lt;/string&amp;gt;  
5:    &amp;lt;string name=&quot;title&quot;&amp;gt;/dev/kmem - Hola Mundo&amp;lt;/string&amp;gt;  
6:    &amp;lt;string name=&quot;msgExit&quot;&amp;gt;Tocar la pantalla para salir.&amp;lt;/string&amp;gt;  
7:  &amp;lt;/resources&amp;gt;  &lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Para no distorsionar la imagen es mejor usa un ImageView en lugar de la propiedad Background de los Layouts, porque esta ultima estrecha o estira la imagen sin respetar las proporciones.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;1:  ImageView ivAndroid = new ImageView(this);  
2:  ivAndroid.setImageDrawable(getResources().getDrawable(R.drawable.android));  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Ya que tenemos creados los tres objetos que queremos mostrar al usuario, ahora tenemos que crear un layout , agregar los elementos y establecer como contenido principal el layout. Como la imagen no ocupa toda la pantalla y para evitar que queden franjas negras por encima y por debajo, cambiamos el color de fondo del layout al mismo que el de la imagen.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;1:  FrameLayout layout = new FrameLayout (this);  
2:  layout.setBackgroundColor(Color.WHITE);  
3:  layout.addView(ivAndroid);  
4:  layout.addView(tvHello);  
5:  layout.addView(tvExit);  
6:    
7:  setContentView(layout);  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Y por ultimo,&amp;nbsp;&lt;i&gt;onTouchEvent&lt;/i&gt; se activa cuando el usuario toca la pantalla, y el método&amp;nbsp;&lt;i&gt;finish&lt;/i&gt;&amp;nbsp;termina la ejecución del programa, por lo que cuando el usuario&amp;nbsp;toque la pantalla se cerrara la aplicación.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoZu7Xmgw88jmb-dBU_vCMDSaUFiTEna_kUbe82k3FkUcnhF0sIKbLps4CWVfoAMdi8MrPNfyNBoZ5sawbqjhnNKMzkAEOmTEKwVb5inYEfkEkP_DovCDgjwwpSFBNJwuUWvaA-BkJ295e/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: black; word-wrap: normal;&quot;&gt;1:    @Override  
2:    public boolean onTouchEvent(MotionEvent ev)  
3:    {  
4:        this.finish();  
5:        return true;  
6:    }  
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Y con eso, tenemos nuestra primera aplicación en Android.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devkmem.blogspot.com/feeds/4126542657375162334/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://devkmem.blogspot.com/2011/11/primero-pasos-con-android.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/4126542657375162334'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2993584829070686554/posts/default/4126542657375162334'/><link rel='alternate' type='text/html' href='http://devkmem.blogspot.com/2011/11/primero-pasos-con-android.html' title='Primeros pasos con Android'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00369221008898869123</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg92cVUQXVV1lTBcd-lW4AnQ3LK0gjhLPSXLUJGiQz7gvgudhMmvCYbluArBnT8JNtsYxlPIrUy7lSTK6HlRXbLtIhk1U_0yhOuzJjZUbhFxyUZ1cTBTmfNO4VejQmO_sL7GIa955h8Nxvg/s72-c/resultado.png" height="72" width="72"/><thr:total>0</thr:total></entry></feed>