Fábula de los dos cerditos (o las ventajas del Test Driven Development)

8 03 2012

Érase una vez que se era, un lejano país donde vivían dos cerditos, Pablo y Adrián que, además, eran hermanos. Ambos eran los cerditos más listos de la granja y, por eso, el gallo Iván (el gerente de la misma) organizó una reunión en el establo, donde les encargó desarrollar un programa de ordenador para controlar el almacén de piensos. Les explicó qué quería saber en todo momento: cuántos sacos de grano había y quién metía y sacaba sacos de grano del almacén. Para ello sólo tenían un mes pero les advirtió que, en una semana, quería ya ver algo funcionando. Al final de esa primera semana, eliminaría a uno de los dos.

Adrián, que era el más joven e impulsivo, inmediatamente se puso manos a la obra. “¡No hay tiempo que perder!”, decía. Y empezó rápidamente a escribir líneas y líneas de código. Algunas eran de un reciente programa que había ayudado a escribir para la guardería de la vaca Paca. Adrián pensó que no eran muy diferentes un almacén de grano y una guardería. En el primero se guardan sacos y en el segundo, pequeños animalitos. De acuerdo, tenía que retocar algunas cosillas para que aquello le sirviera pero bueno, esto del software va de reutilizar lo que ya funciona, ¿no?

Pablo, sin embargo, antes de escribir una sola línea de código comenzó acordando con Iván dos cosas: qué era exactamente lo que podría ver dentro de una semana y cómo sabría que, efectivamente, estaba terminada cada cosa.

Iván quería conocer, tan rápido como fuera posible, cuántos sacos de grano había en cada parte del almacén porque sospechaba que, en algunas partes del mismo, se estaban acumulando sacos sin control y se estaban estropeando. Como los sacos entraban y salían constantemente, no podía saber cuántos había y dónde estaban en cada instante, así que acordaron ir contabilizándolos por zonas y apuntando a qué parte iba o de qué parte venía, cada vez que entrara o saliera un saco. Así, en poco tiempo podrían tener una idea clara del uso que se estaba dando a las distintas zonas del almacén.

Mientras Adrián adelantaba a Pablo escribiendo muchas líneas de código, Pablo escribía primero las pruebas automatizadas. A Adrián eso le parecía una pérdida de tiempo. ¡Sólo tenían una semana para convencer a Iván!

Al final de la primera semana, la demo de Adrián fue espectacular, tenía un control de usuarios muy completo, hizo la demostración desde un móvil y enseñó, además, las posibilidades de un generador de informes muy potente que había desarrollado para otra granja anteriormente. Durante la demostración hubo dos o tres problemillas y tuvo que arrancar de nuevo el programa pero, salvo eso, todo fue genial.

La demostración de Pablo fue mucho más modesta, pero cumplió con las expectativas de Iván y el programa no falló en ningún momento. Claro, todo lo que enseñó lo había probado muchísimas veces antes gracias a que había automatizado las pruebas. Pablo hacía TDD, es decir, nunca escribía una línea de código sin antes tener una prueba que le indicara un error. Adrián no podía creer que Pablo hubiera gastado más de la mitad de su tiempo en aquellas pruebas que no hacían más que retrasarle a la hora de escribir las funcionalidades que había pedido Iván. El programa de Adrián tenía muchos botones y muchísimas opciones, probablemente muchas más de las que jamás serían necesarias para lo que había pedido Iván, pero tenía un aspecto “muy profesional”.

Iván no supo qué hacer. La propuesta de Pablo era muy robusta y hacía justo lo que habían acordado. La propuesta de Adrián tenía cosillas que pulir, pero era muy prometedora. ¡Había hecho la demostración desde un móvil!

Así que les propuso el siguiente trato: “Os pagaré un 50% más de lo que inicialmente habíamos presupuestado, pero sólo a aquel de los dos que me haga el mejor proyecto. Al otro no le daré nada.”. Era una oferta complicada porque, por un lado, el que ganaba se llevaba mucho más de lo previsto. Muy tentador. Pero, por el otro lado, corrían el riesgo de trabajar durante un mes completamente gratis. Mmmmm.

Adrián, tan impulsivo y arrogante como siempre, no dudó ni un instante. “¡Trato hecho!”, dijo. Pablo explicó que aceptaría sólo si Iván se comprometía a colaborar como lo había hecho durante la primera semana. A Iván le pareció razonable y les convocó a ambos para que le enseñaran el resultado final en tres semanas.

Adrián se marchó pitando y llamó a su primo Sixto, que sabía mucho y le aseguraría la victoria, aunque tuviera que darle parte de las ganancias. Ambos se pusieron rápidamente manos a la obra. Mientras Adrián arreglaba los defectillos encontrados durante la demo, Sixto se encargó de diseñar una arquitectura que permitiera enviar mensajes desde el móvil hasta un webservice que permitía encolar cualquier operación para ser procesada en paralelo por varios servidores y así garantizar que el sistema estaría en disposición de dar servicio 24 horas al día los 7 días de la semana.

Mientras tanto, Pablo se reunió con Iván y Bernardo (el encargado del almacén) para ver cuáles deberían ser las siguientes funcionalidades a desarrollar. Les pidió que le explicaran, para cada petición, qué beneficio obtenía la granja con cada nueva funcionalidad. Y así, poco a poco, fueron elaborando una lista de funcionalidades priorizadas y resumidas en una serie de tarjetas. A continuación, Pablo fue, tarjeta a tarjeta, discutiendo con Iván y Bernardo cuánto tiempo podría tardar en terminarlas. De paso, aprovechó para anotar algunos criterios que luego servirían para considerar que esa funcionalidad estaría completamente terminada y eliminar alguna ambigüedad que fuera surgiendo. Cuando Pablo pensó que, por su experiencia, no podría hacer más trabajo que el que ya habían discutido, dio por concluida la reunión y se dispuso a trabajar. Antes que nada, resolvió un par de defectos que habían surgido durante la demostración y le pidió a Iván que lo validara. A continuación, se marchó a casa a descansar.

Al día siguiente, cogió la primera de las tarjetas y, como ya había hecho durante la semana anterior, comenzó a automatizar los criterios de aceptación acordados con Iván y Bernardo. Y luego, fue escribiendo la parte del programa que hacía que se cumplieran esos criterios de aceptación.

Pablo le había pedido ayuda a su amigo Hudson, un coyote vegetariano que había venido desde América a pasar el invierno. Hudson no sabía programar, pero era muy rápido haciendo cosas sencillas. Pablo le encargó que comprobara constantemente los criterios de aceptación que él había automatizado. Así, cada vez que Pablo hacía algún cambio en su programa, avisaba a Hudson y este hacía, una tras otra, todas las pruebas de aceptación que Pablo iba escribiendo. Y cada vez había más. ¡Este Hudson era realmente veloz e incansable!

A medida que iba pasando el tiempo, Adrián y Sixto tenían cada vez más problemas. Terminaron culpando a todo el mundo. A Iván, porque no les había explicado detalles importantísimos para el éxito del proyecto. A la vaca Paca, porque había incluido una serie de cambios en el programa de la guardería que hacía que no pudieran reutilizar casi nada. A los inventores de los SMS y los webservices, porque no tenían ni idea de cómo funciona una granja. Eran tantos los frentes que tenían abiertos que tuvieron que prescindir del envío de SMS y buscaron un generador de páginas web que les permitiera dibujar el flujo de navegación en un gráfico y, a partir de ahí, generar el esqueleto de la aplicación. ¡Eso seguro que les ahorraría mucho tiempo! Al poco, Sixto, harto de ver que Adrián no valoraba sus aportaciones y que ya no se iban a usar sus ideas para enviar y recibir los SMS, decidió que se marchaba, aún renunciando a su parte de los beneficios. Total, él ya no creía que fueran a ser capaces de ganar la competición.

Mientras tanto, Pablo le pidió un par de veces a Iván y a Bernardo que le validaran si lo que llevaba hecho hasta aquel momento era de su agrado y les hizo un par de demostraciones durante aquellas 3 semanas, lo que sirvió para corregir algunos defectos y cambiar algunas prioridades. Iván y Bernardo estaban francamente contentos con el trabajo de Pablo. Sin embargo, entre ellos comentaron más de una vez: “¿Qué estará haciendo Adrián? ¿Cómo lo llevará?”.

Cuando se acercaba la fecha final para entregar el programa, Adrián se quedó sin dormir un par de noches para así poder entregar su programa. Pero eran tantos los defectos que había ido acumulando que, cada vez que arreglaba una cosa, le fallaba otra. De hecho, cuando llegó la hora de la demostración, Adrián sólo pudo enseñar el programa instalado en su portátil (el único sitio donde, a duras penas, funcionaba) y fue todo un desastre: mensajes de error por todos sitios, comportamientos inesperados… y lo peor de todo: el programa no hacía lo que habían acordado con Iván.

Pablo, sin embargo, no tuvo ningún problema en enseñar lo que llevaba funcionando desde hacía mucho tiempo y que tantas veces había probado. Por si acaso, dos días antes de la entrega, Pablo había dejado de introducir nuevas características al programa porque quería centrarse en dar un buen manual de usuario, que Iván había olvidado mencionar en las primeras reuniones porque daba por sentado que se lo entregarían. Claro, Adrián no había tenido tiempo para nada de eso.

Moraleja:

Además de toda una serie de buenas prácticas y un proceso de desarrollo ágil, Pablo hizo algo que Adrián despreció: acordó con Iván (el cliente) y con Bernardo (el usuario) los criterios mediante los cuales se comprobaría que cada una de las funcionalidades estaría bien acabada. A eso que solemos llamar “criterios de aceptación”, Pablo le añadió la posibilidad de automatizar su ejecución e incorporarlos en un proceso de integración continua (que es lo que representa su amigo Hudson en este cuento). De esta manera, Pablo estaba siempre tranquilo de que no estaba estropeando nada viejo con cada nueva modificación. Al evitar volver a trabajar sobre asuntos ya acabados, Pablo era más eficiente. En el corto plazo, las diferencias entre ambos enfoques no parecen significativas, pero en el medio y largo plazo, es evidente que escribir las pruebas antes de desarrollar la solución es mucho más eficaz y eficiente.

Este texto está extraído de http://www.dirigidoportests.com/wp-content/uploads/2009/12/disenoAgilConTDD.pdf, un libro sobre desarrollo ágil apoyado en pruebas disponible gratuitamente para descarga. Aunque la fábula dista mucho de la realidad (como siempre, pero más en informática), cualquier acercamiento a este enfoque es beneficioso en cualquier proyecto nuevo que se aborde… aunque muchos de los que recibiréis esto ya lo sabéis.





Aplicar permisos de forma recursiva cuando sólo disponemos de FTP, ¿la solución? PHP

9 06 2011

Bien conocido es la problemática que se le presenta al desarrollador de aplicaciones web cuando, por ejemplo, necesita asignar permisos a un árbol de directorios lo suficientemente profundo como para que hacerlo elemento por elemento sea una tarea tediosa cuando el proveedor de servicios de hosting no ofrece acceso por SSH y sólo dispone de acceso por FTP al sistema de ficheros del plan contratado.

Casi ningún cliente de FTP permite asignación de permisos de manera recursiva o en profundidad, esto es, a un directorio y a todo lo que esté bajo el mismo; yo al menos no he encontrado ninguno que lo haga.

Entonces, ¿cuál es la solución para agilizar este procedimiento?

Pues si habéis sido listos y habéis escogido Linux para vuestro plan de alojamiento y éste permite ejecución de scripts, estáis de enhorabuena, pues tanto Perl como PHP poseen funciones que permiten cambiar permisos a ficheros y directorios del sistema en el que se estén ejecutando.

A continuación os dejo un sencillo script en PHP que asigna permisos 755 a todos los directorios y 644 a todos los ficheros:

// Comenzamos desde el directorio donde se ejecuta este script
$dir = "./";
$dirModes = 0755;
$fileModes = 0644;
$d = new RecursiveDirectoryIterator( $dir );
foreach (new RecursiveIteratorIterator($d, 1) as $path) {
    if ($path->isDir()) {
        chmod($path, $dirModes);
    } else if (is_file($path)) {
        chmod($path, $fileModes);
    }
}




Crear accesos directos de Windows desde aplicaciones Java

13 08 2010

Una de las cuestiones sobre las que no existe demasiada información en la red es la creación de accesos directos de Windows de forma programática y menos aún cómo hacerlo desde una aplicación Java. En este post explicaré cómo realizar esta tarea de una manera bastante sencilla.

Para empezar, decir que no existe ningún comando en Windows con el que sea posible crear accesos directos, al menos en Windows XP y Windows Server hasta su versión 2008.

Imaginemos ahora el siguiente escenario: tenemos un recurso compartido por Samba o en nuestra red de Windows y tenemos un aplicativo Java ejecutándose desde un servidor Windows Server 2008 que se encarga de hacer accesible este recurso desde todos los equipos de la red, mediante un acceso directo en el escritorio de los usuarios, por ejemplo. Asumiendo que tenemos ya controlado el acceso por Samba a los equipos desde nuestra aplicación, las dos cuestiones a resolver para conseguir nuestro objetivo son:

1. Averiguar qué mecanismo usa Windows para la creación de accesos directos y

2. Hacer una llamada al mismo desde nuestra aplicación Java.

Analicemos ambas cuestiones por separado:

1. Averiguar qué mecanismo usa Windows para la creación de accesos directos:

Tras mucho buscar en Internet topé con una buena referencia [1] de la cual se desprende que para crear accesos directo en Windows programáticamente es a través de CScript.

Sabiendo esto, podemos escribir un sencillo script como el siguiente:

'Creación del objeto Shell
Set WshShell = WScript.CreateObject("WScript.Shell")

'Recuperamos los argumentos de la llamada a este script
LinkName = WScript.Arguments(0)
LinkPath = WScript.Arguments(1)
LinkTargetPath = WScript.Arguments(2)

'Definimos la localización del fichero LNK
LinkFilename = LinkPath + "\" + LinkName + ".lnk"

'Creamos el objeto LNKFile
Set LNKFile = WshShell.CreateShortcut(LinkFilename)

'Establecemos los contenidos del fichero LNK
LNKFile.TargetPath = LinkTargetPath
LNKFile.Arguments = ""
LNKFile.Description = "Acceso directo a " + LinkTargetPath
LNKFile.HotKey = ""
LNKFile.WindowStyle = "1"
LNKFile.WorkingDirectory = ""

'Guardamos el fichero LNK en disco
LNKFile.Save

A este script lo llamaremos createlnk.vbs y recibirá tres parámetros: 1º: nombre para el fichero (sin extensión), 2º: ruta donde se guardará el fichero lnk (p.e.:c:\links), 3º: destino del acceso directo (p.e.: \\shared\folder).

Obsérvese que este script se ejecutará en nuestro servidor, en el cual se está ejecutando la aplicación Java.

2. Hacer una llamada al mismo desde nuestra aplicación Java:

Esta parte es más sencilla, puesto que desde Java es posible lanzar ejecutables mediante la creación y ejecución de procesos. La llamada al script descrito en el primer punto podría ser algo como lo siguiente:

Process process = Runtime.getRuntime().exec("cscript \"c:\\scripts\\createlnk.vbs\" \"test\" \"c:\\links \\\\shared\\resource\"");
if (process.waitFor() == 0) {
    // OK
} else {
    // Error
}

Sólo quedaría copiar este acceso directo a las máquinas remotas que nos interesen mediante Samba.

Referencias:

[1] Administering Windows Server 2008 Server Core





Instalación personalizada de OpenCms con Maven y Ant

15 06 2010

Una tarea que puede resultar enormemente tediosa es aquella de poner en producción un sistema desarrollado sobre el gestor de contenidos OpenCms, debido al gran número de módulos que pueden llegar a desarrollarse para un proyecto meianamente complejo. Poniendo que tengamos listas nuestras máquinas y el software de producción (aka, servidores de bases de datos, contenedor servlet, etc) y que ya hemos instalado OpenCms from scratch desplegando el war y siguiendo el asistente de instalación de Alkacon, instalar todos los módulos que hemos desarrollado, así como establecer todos los parámetros de configuración que nuestro sistema requiera en los ficheros de configuración de OpenCms puede suponer una verdadera pérdida de nuestro valioso tiempo.

No hace mucho que en la empresa donde trabajo estábamos preparando la puesta en producción de un sistema desarrollado sobre OpenCms que contaba con un número considerable de módulos y una configuración muy específica para que los mismos funcionasen correctamente sobre la instalación estándar de OpenCms, cosa que nos hizo tomar la decisión de hacer una pausa y emplear algo de tiempo en pensar una estrategia que hiciera de esta labor una tarea fácil y completamente automática. Pues bien, tras no demasiado tiempo pensando dimos con la solución que mejor se ajustaba a esta necesidad: construir nuestro propio asistente de instalación. ¿Cómo se consigue esto? Querido lector, siga usted leyendo.

La herramienta fundamental que se ha empleado para la construcción de un asistente de instalación personalizado ha sido Apache Maven.

En primera instancia, antes de abordar esta idea ya contábamos con las bondades de Maven para modelar y construir los módulos de OpenCms, como explica un antiguo compañero en este post, lo cual nos dejaba entrever un camino interesante para el propósito que estamos tratando.

Como elementos indispensables para desarrollar este instalador necesitamos:

En principio, modelamos nuestro asistente personalizado como un proyecto Maven conteniendo los siguientes elementos:

  • El asistente de instalación de Alkacon, que no es más que el war que desplegamos en nuestro contenedor, pero descomprimido en un directorio en el proyecto.
  • Los fuentes de todos los módulos de nuestro proyecto que queramos instalar en OpenCms, cada uno será un proyecto Maven, siendo el proyecto objeto de estudio en este post el proyecto padre.
  • Un fichero build.xml el cual le diremos a Ant cómo compilar y empaquetar nuestro asistente de instalación.

La estructura, pues, del sistema de ficheros de nuestro proyecto es algo con la siguiente forma:

/custom-opencms
| + opencms-module-1
  ...
   | - pom.xml
   | - profiles.xml
| + opencms-module-2
  ...
   | - pom.xml
   | - profiles.xml
 ...
| + opencms-module-N
  ...
   | - pom.xml
   | - profiles.xml
| + opencms-webapp
| + build.xml
| + pom.xml

A partir de este punto se asume que el lector he trabajado lo suficiente con Maven y Ant como para que sea capaz de entender el desarrollo que a continuación se expone.

Lo primero que tendremos que hacer, una vez montado el proyecto anterior en nuestro IDE favorito será escribir el fichero pom.xml para que contemple la compilación de todos los módulos de OpenCms de nuestro proyecto, para ello, simplemente crearemos una sección modules conteniendo todos los módulos que deseamos instalar:

<modules>
    <module>opencms-module-1</module>
    <module>opencms-module-2</module>
    ...
    <module>opencms-module-N</module>
</modules>

Hecho esto, debemos conseguir que los módulos compilados se alojen en algún lugar en el target de nuesto proyecto, para ello, mediante maven-antrun-plugin, crearemos un directorio bajo el directorio target del proyecto donde copiaremos todos los zips de los módulos ya compilados.

<build>
    <plugins>
        <plugin>
	    <groupId>org.apache.maven.plugins</groupId>
	        <artifactId>maven-antrun-plugin</artifactId>
	        <version>1.1</version>
	        <executions>
	            <execution>
	                <id>zip-module</id>
	                    <goals>
	                        <goal>run</goal>
	                    </goals>
	                    <phase>package</phase>
	                    <inherited>false</inherited>
	                    <configuration>
	                        <tasks>
	                            <echo>Packaging OpenCMS Modules...</echo>
	                                <mkdir dir="target/dist/modules" />
	                                <copy file="opencms-module-1.zip/target/es.joselopezpua.opencms-module-1.zip"
	                                      todir="target/dist/modules" />
	                                <copy file="opencms-module-2.zip/target/es.joselopezpua.opencms-module-1.zip"
	                                      todir="target/dist/modules" />
                                        ....
	                                <copy file="opencms-module-N.zip/target/es.joselopezpua.opencms-module-1.zip"
	                                      todir="target/dist/modules" />
                                        ...

Hasta aquí ya tenemos todos los módulos de nuestro proyecto recién salidos del horno con sólo hacer $ mvn clean package, ¿qué tal si los copiamos al instalador y le decimos que se prepare para instalarlos?

En la estructura de ficheros del asistente de instalación de Alkacon, que está bajo nuestro directorio opencms-webapp, en WEB-INF/packages/modules/, se encuentran los zips de todos los módulos que se instalarán durante el proceso de instalación, así que escribiremos las líneas apropiadas en nuestro fichero build.xml para que nuestra tarea Ant realice este trabajo.

<project>
    <target name="dist">
        <!-- Genera el directorio target/opencms-webapp -->
	<mkdir dir="target/opencms-webapp"/>
	<!-- Copia los ficheros del webapp de instalación de OpenCms -->
	<copy todir="target/opencms-webapp">
	    <fileset dir="opencms-webapp/target/dist" />
	</copy>
	<!-- Copia los módulos del proyecto a la carpeta de módulos del webapp de instalación -->
	<copy todir="target/opencms-webapp/WEB-INF/packages/modules">
	    <fileset dir="target/dist/modules" />
        </copy>
   </target>
</project>

Con esto el asistente ya tendrá nuestros módulos en el directorio en el que los espera, sólo nos falta indicarle que los importe, cosa que haremos modificando el fichero opencms-webapp/setup/components.properties, suponiendo que la paquetería de nuestros módulos es es.joselopezpua.custom.* y que el nombre para el conjunto de módulos será custom:

component.custom.name=Modulos de ejmplo de este post
component.custom.description=Modulos de OpenCms de mi proyecto
component.custom.modules=es\.joselopezpua\.custom.*
component.custom.position=200
component.custom.checked=true

Sólo queda decirle a nuestra tarea Ant que comprima el asistente en un war que desplegaremos en nuetro contenedor J2EE para instalar nuestro proyecto, para ello, añadir estas líneas a build.xml antes del cierre del nodo target:

	    <zip destfile="target/custom-opencms.war" basedir="target/opencms-webapp" />

Y listo, ahora cada vez que deseemos realizar un nuevo instalador con nuestros módulos tan sólo tendremos que ejecutar Maven y Ant de la siguiente forma:

$ mvn clean package

$ ant dist

Tendremos en el directorio target un war con un asistente de instalación de OpenCms que instalará todos nuestros módulos.

Para personalizar la configuración de partida de nuestro OpenCms, antes de construir este proyecto simplemente habrá que modificar conveniente los ficheros de configuración de OpenCms del instalador (en nuestro ejemplo, el directorio opencms-webapp). Incluso es posible modificar, dentro del subdirectorio setup, las páginas de los pasos del asistente, imágenes, scripts de creación de tablas en la base de datos, etc.

El punto fuerte de lo que se ha presentado en este post es la automatización, la cual nos brinda la oportunidad de distribuir el software que hemos desarrollado sobre la plataforma OpenCms de manera rápida, sencilla y segura (siempre y cuando hayamos realizado las instalaciones de prueba oportunas en nuestros entornos de prueba y preproducción) con el acabado profesional de una instalación desde cero en forma de Wizard.

Atrás quedan esas tardes aburridas instalando módulos uno por uno, desafiando a los ficheros de configuración y obteniendo desagradables sorpresas.





¿Indecente?

14 05 2010

Publico en este post un correo que me llegó reenviado por un amigo donde no se dicen nada más que verdades.

Si trabajáis y no sois políticos ni funcionarios de ayuntamientos os sentiréis perfectamente identificados con esto.

Ha  dicho la Vicepresidenta del gobierno que es indecente que mientras la  inflación es -1%,y tengamos más de 4.000.000 de parados, haya gente que no esté de  acuerdo en alargar la jubilación a los 70 años.

Nos gustaría transmitirle a esta “Sra. Vicepresidenta” y a todos los políticos, lo que consideramos  indecente :

INDECENTE,  es que el salario mínimo de un trabajador sea de 624 €/mes y el de un diputado de 3.996, pudiendo llegar, con dietas y otras prebendas, a  6.500 €/mes.

INDECENTE, es que un profesor, un maestro, un catedrático de universidad o un  cirujano de la sanidad pública, ganen menos que el concejal de festejos  de un ayuntamiento de tercera.

INDECENTE, es que los políticos se  suban sus retribuciones en el porcentaje que les apetezca (siempre por  unanimidad, por supuesto, y al inicio de la  legislatura).

INDECENTE, es que un ciudadano tenga que  cotizar 35 años para percibir una jubilación y a los diputados les baste  sólo con siete, y que los miembros del gobierno, para cobrar la pensión  máxima, sólo necesiten jurar el cargo.

INDECENTE, es que los  diputados sean los únicos trabajadores (¿?) de este país  que están  exentos de tributar un tercio de su sueldo del IRPF.

INDECENTE, es colocar en la administración a miles de asesores = (léase amigotes  con sueldos que ya desearían los técnicos más cualificados.)
INDECENTE, es el  ingente dinero destinado a sostener a los partidos, aprobados por los  mismos políticos que viven de ellos.

INDECENTE, es que a un  político no se le exija superar una mínima prueba de capacidad para  ejercer su cargo. (ni cultural ni intelectual.)

INDECENTE, es el coste que representa para los  ciudadanos sus comidas, coches oficiales, chóferes, viajes (siempre en  gran clase) y tarjetas de crédito por doquier.

INDECENTE No es que no se congelen el sueldo sus señorias, sino que no se lo bajen.

INDECENTE, es que  sus señorías tengan seis meses de vacaciones al año.

INDECENTE, es que ministros,  secretarios de estado y altos cargos
de la política, cuando cesan, son  los únicos ciudadanos de este país que pueden legalmente percibir dos  salarios del ERARIO PÚBLICO.

Y que sea cuál sea el color del gobierno, toooooooodos los políticos se benefician de este moderno “derecho de pernada” mientras no se cambien las leyes que lo regula. ¿Y quiénes las cambiarán? ¿Ellos mismos? Já. Juntemos firmas para que haya un proyecto de ley con “cara y ojos” para acabar con estos privilegios, y con otros.

Haz que esto llegue al Congreso a traves de tus amigos

ÉSTA  SÍ DEBERÍA SER UNA DE ESAS CADENAS QUE NO SE DEBE ROMPER, PORQUE SÓLO  NOSOTROS PODEMOS PONERLE REMEDIO A ESTO, Y ÉSTA, SI QUE TRAERÁ AÑOS DE  MALA SUERTE SI NO PONEMOS REMEDIO. esta en juego nuestro futuro y el de nuestros hijos.

Lo más triste es que a nadie le pilla de sorpresa. A mí sinceramente me da igual que alguien se jubile a los 70, siempre que esté cualificado para desempeñar su trabajo (p.e.: un cirujano al que le tiembla el pulso a causa de la edad no tiene ningún sentido), pero habiendo leído esto sí que es verdad que es indignante que sigan pasando estas cosas, que en los ayuntamientos ya es exagerado (si sois de un pueblo, como yo, en donde todo se sabe sabréis de qué hablo).

El verdadero problema es que la política es un círculo cerrado donde son sólo los políticos los que hacen y deshacen y, si son todos iguales como se dice aquí (que lo son), ¿quién pone remedio a este descaro?





Desplegables horizontales en HTML

30 03 2010

Hace unos días en el trabajo, mientras aplicaba estilos a un input select de un formulario en un documento HTML, cometí un error al aplicar un estilo in-line, encontrándome con esto:

Select horizontal

Select horizontal

Mi reacción fue reirme, dado que nunca había visto un desplegable de esta forma pero, ¿qué sucedió?

Bien, la cuestión es que en lugar de aplicar la propiedad de estilo css display:inline al elemento select, lo apliqué al alemento option de ese select, con lo que la siguiente opción se coocó justo a continuación y no debajo, como está estabecido por defecto (display:block).

Intrigado, me pregunté si sería posible disponer las opciones de un desplegable como una matriz y la conclusión es que sí se puede.

La solución es mezclar la aplicación errónea del estilo display:inline con el uso de elementos optgroup. Cada optgroup será una fila de nuestra matriz de opciones y cada opción dentro de cada fia tendrá aplicado un estilo display:inline. Como por defecto los elementos HTML se muestran como block, cada fila (optgroup) se mostrará debajo de la anterior y dentro de ellas, cada opción, al tener aplicado estilo display:inline, se mostrará justo al lado de la anterior🙂

Así podemos construir de una forma sencillísima cosas como esta:

Select matricial

Select matricial

El código HTML correspondiente es el siguiente:

<select id="selectMatricialDesplegable" size="1">
    <optgroup>
        <option style="display:inline;">01</option>
        <option style="display:inline;">02</option>
        <option style="display:inline;">03</option>
        <option style="display:inline;">04</option>
        <option style="display:inline;">05</option>
        <option style="display:inline;">06</option>
        <option style="display:inline;">07</option>
    </optgroup>
    <optgroup>
        <option style="display:inline;">08</option>
        <option style="display:inline;">09</option>
        <option style="display:inline;">10</option>
        <option style="display:inline;">11</option>
        <option style="display:inline;">12</option>
        <option style="display:inline;">13</option>
        <option style="display:inline;">14</option>
    </optgroup>
    <optgroup>
        <option style="display:inline;">15</option>
        <option style="display:inline;">16</option>
        <option style="display:inline;">17</option>
        <option style="display:inline;">18</option>
        <option style="display:inline;">19</option>
        <option style="display:inline;">20</option>
        <option style="display:inline;">21</option>
    </optgroup>
    <optgroup>
        <option style="display:inline;">22</option>
        <option style="display:inline;">23</option>
        <option style="display:inline;">24</option>
        <option style="display:inline;">25</option>
        <option style="display:inline;">26</option>
        <option style="display:inline;">27</option>
        <option style="display:inline;">28</option>
    </optgroup>
</select>

No es nada espectacular pero mola. Espero que os sirva.





El siguiente paso

1 03 2010

Siendo casi las 23:00 y en un estado importante de agotamiento, por fin concluye mi mudanza de la calle Evangelista a la calle Torneo, en la que me he aventurado a vivir yo solo tras muchos años compartiendo pisos.

Resulta extraño, si justo un año atrás alguien me hubiera dicho que iba a tomar esta decisión me hubiese reido en su cara, puesto que por aquel entonces no concebía abandonar el frenesí de vivir entre colegas… pero lo cierto es que ya me tocaba, pues cuando el cuerpo te lo pide día tras día, difícil es negarse ¿verdad?.

Pensando positivamente considero esta decisión como un salto de calidad de vida en el momento oportuno, ni más ni menos. He aquí algunos de mis recuerdos de mi último piso, en la calle Evangelista:

  • Una sensación: sentirme como en casa.
  • Una escena: los “guateques” que solíamos organizar cada jueves.
  • Un sonido: el del camión de Lipasam a las 2:00 de la mañana😦
  • Un sabor: el de las pizzas caseras de mi compi Álvaro.
  • Un olor… me lo reservo😉

Quisiera agradecer también de todo corazón a mis amigos Yayo y Diego su ayuda, sin la cual me hubiera resultado imposible mudarme tan rápidamente.

Para terminar, me gustaría despedir este post con una canción de R.E.M. cuyo título viene al pelo😉








A %d blogueros les gusta esto: