Archivo para la categoría ‘Proyectos’

ScreenCrop v0.1

ScreenCrop es una pequeña utilidad que he creado en Delphi basándome en una similar que trae Windows 7 y que sirve para hacer capturas de pantalla parciales o totales.

Basta con iniciar la aplicación y, mediante la técnica de arrastrar y soltar con el ratón, dibujar un cuadrado en la pantalla. El contenido de dicho cuadro será copiado al portapapeles en forma de imagen, que luego se podrá pegar en (casi) cualquier sitio.

Si, durante la realización del cuadrado, nos ha quedado mal, se puede cancelar la creación manteniendo pulsada la tecla Control y soltando el botón del ratón. También se puede salir directamente de la aplicación mediante la tecla Escape, o hacer una captura completa mediante la tecla Enter.

Si se hace clic con el botón derecho una vez iniciada la aplicación, aparecerá un menú contextual con las opciones más comunes así como con una pequeña configuración.

Y aquí, como no, una pequeña captura de pantalla (que no, no está hecha con la aplicación :) ):

Captura de pantalla de la aplicación 'ScreenCrop'

Por supuesto, podéis descargaros el ejecutable y, si queréis el código fuente, sólo tenéis que pedirlo.

Descargar ScreenCrop v0.1 – ZIP – 294 KB

Mini manual de Subversion

He creado un pequeño manual de Subversion donde se muestra lo básico para crear y administrar un repositorio en una máquina con Linux con este sistema de control de versiones. Los contenidos son:

  1. Introducción
  2. Qué es Subversion
  3. Creación y configuración de un repositorio
  4. Seguridad básica en un repositorio de Subversion
  5. Estructura recomendada de un repositorio
  6. Creación y manejo de proyectos
  7. Comandos básicos
  8. Creación y manejo de branches (ramas)
  9. Resumen de comandos
  10. Anexo A: Script de inicio del servidor de Subversion — svnserve

Es un manual simple (en papel son apenas ocho páginas) pero que contempla los aspectos básicos de este sistema de control de versiones y es muy útil para empezar a utilizarlo.

Espero que os sirva ;) .

Mis antiguas páginas Web

Ya en el 2004 cuando estaba finalizando la carrera, se me dio por hacer mi propia página Web por eso de compartir la información y los proyectos que uno hacía. Además, desde cero, sin gestor de contenidos (tampoco sabía lo que era en aquella época) ni nada. Directamente en PHP. Además, también hacía mis pinitos con Photoshop:

Pantallazo de mi primera página Web (del año 2004)

No podía publicar noticias ni nada, simplemente se añadían más archivos PHP con los datos de las nuevas páginas y listo. Ni siquiera hacía uso de una base de datos.

Luego ya, viendo que la página era de crecimiento limitado, me decidí ha hacer un pequeño gestor de contenidos a medida. También en PHP y esta vez con acceso a bases de datos para las noticias:

Mi primer blog

Se notaba por aquella época mi predilección por el Firefox dejando de lado el IE (y vuelve esa idea), además de la resolución de pantalla y de la —todavía en uso en muchas páginas que se las dan de estándar— maquetación usando tablas. Vamos, no tenía casi ni idea de CSS y ni mucho menos de usabilidad y de accesibilidad. Pero por algo hay que empezar y esto era una buena idea.

Incluso hasta tenía una parte de administración con seguridad (usuario y contraseña, como casi todas) desde donde se podían añadir noticias, categorías, gestionar usuarios, proyectos, descargas, estadísticas,… vamos, como era a medida podía añadir lo que necesitara (¡pedazo de cabecera! Como se notaba que también estaba practicando con el Photoshop):

Consola de mantenimiento del blog personalizada

¿Alguien se acuerda de todo esto?

Luego descubrí WordPress (la versión 2.0), lo instalé y a funcionar. Y con él sigo.

La verdad es que desarrollando un blog hubiera aprendido mucho de PHP, además del HTML correspondiente y su maquetación, sobre todo por los fallos de principiante, esos que veo ahora que miro el código :) .

De todas formas, por aquella época (más o menos el 2004) ya tenía más o menos bastante claro como hacer un software mantenible, ya que había hecho que todo se procesase desde el index.php cargando éste las partes que eran necesarias, cosa que sigo llevando a la práctica.

Ahora, eso sí, con un pequeño framework en PHP personal, no para el blog pero sí para otros pequeños proyectos.

Nueva versión del plugin jQuery TimePicker

He reescrito de nuevo el plugin para jQuery que hice hace tiempo, jQuery TimePicker, que sirve para seleccionar la hora (horas y minutos) dentro de una caja de texto mediante la rueda del ratón.

Este plugin ha sido totalmente reescrito ya que no funcionaba correctamente en Internet Explorer y en algunas versiones de Firefox. Además, ahora usa la nueva versión del plugin jQueryMouseWheel que corrige algunos fallos de la anterior versión (de hecho ha cambiado hasta de desarrollador).

Ahora funciona correctamente en Firefox 3 para Windows y Linux, Firefox 2 para Windows y en Internet Explorer 6 y 7, aunque no funciona correctamente en Google Chrome (extrañamente suma las horas y los minutos de dos en dos).

Espero que ahora sea algo más útil que en su versión anterior (que no valía para nada, la verdad). Ya me contaréis si esta versión funciona correctamente en todos los sistemas o si hay que añadirle o quitarle algo.

Clase Image en PHP

El otro día estaba haciendo un captcha para la página con las primitivas de dibujado de imágenes de PHP y al final me decidí por lo más lógico para que me sirva para un futuro: hacer una clase Image en PHP con todas las primitivas y hacer una clase CaptchaImage que herede de la clase Image.

De momento no voy a poner aquí el código porque está sin terminar, pero vamos, es tan sencillo como hacer una clase en PHP que tenga las funciones de dibujar dentro de ella y que sepa cargar imágenes desde archivos.

El problema me surgió cuando intenté posicionar texto de fuentes True Type rotado con un ángulo determinado, ya que al rotar dicho texto, las posiciones de X e Y así como el ancho y algo del contenido cambian.

Para esto, PHP tiene una función que se llama imagettfbbox(...) que dado un texto, el tamaño, el ángulo y la fuente, devuelve un array con las posiciones de todos sus puntos, es decir, las coordenadas (x,y) de las 4 posiciones de color azul que se muestran en la imagen:

Caja de texto

Pero para poder posicionar ese texto dentro de la imagen, lo que necesitamos saber son las posiciones de los puntos naranjas. O, mejor aún, el ancho y el alto del cuadrado naranja y ya daremos nosotros la posición de la izquierda y de arriba para posicionar la caja completa.

Hay que tener en cuenta que las coordenadas que devuelve la función de PHP siempre se refieren a la caja de texto como si este estuviese horizontal, es decir, si rotamos el texto 180 grados, las coordenadas (6,7), por ejemplo, seguirían siendo la posición superior izquierda aunque visualmente estuviesen en la posición inferior derecha.

Mirando en la documentación de la función en cuestión, hay varias personas que han puesto sus funciones de posicionado, (bastante complicadas, por cierto). Pero las he probado y no van bien, sobre todo con texto rotado, que al fin y al cabo, es la cuestión de la función, así que me hice la mía:

function calculateTextBox($text,$fontFile,$fontSize,$fontAngle) {
$rect = imagettfbbox($fontSize,$fontAngle,$fontFile,$text);

$minX = min(array($rect[0],$rect[2],$rect[4],$rect[6]));
$maxX = max(array($rect[0],$rect[2],$rect[4],$rect[6]));
$minY = min(array($rect[1],$rect[3],$rect[5],$rect[7]));
$maxY = max(array($rect[1],$rect[3],$rect[5],$rect[7]));

return array(
“left” => abs($minX),
“top” => abs($minY),
“width” => $maxX$minX,
“height” => $maxY$minY,
“box” => $rect
);
}

$mystring = “Hello world!”;

$imgWidth = 300;
$imgHeight = 150;
$angle = 40;

$image = imagecreate($imgWidth,$imgHeight);

imagefill($image,0,0,imagecolorallocate($image,200,200,200));

$box = calculateTextBox($mystring,“./Verdana.ttf”,15,$angle);
$color = imagecolorallocate($image,0,0,0);
imagettftext($image,
15,
$angle,
$box["left"] + ($imgWidth / 2) – ($box["width"] / 2),
$box["top"] + ($imgHeight / 2) – ($box["height"] / 2),
$color,
“./Verdana.ttf”,
$mystring);

header(“Content-Type: image/x-png”);
imagepng($image);
imagedestroy($image);

La función calculateTextBox(...) calcula la caja real donde encaja el texto dado, con su alto y ancho además de las posiciones de izquierda y derecha (necesarias para un correcto posicionamiento).

Luego ya sólo es necesario crear una imagen y dibujar el texto centrado sabiendo lo que ocupa.

Yo esto lo tengo dentro de un par de clases de PHP que me solucionan bastante los problemas. En cuanto estén listas las pongo por aquí por si a alguien les sirven de ayuda.

DiskSpace 1.20

En otro de mis ratos libres (que no tengo muchos, pero alguno hay) he actualizado la versión de DiskSpace a la 1.20 añadiendo alguna que otra mejora, entre ellas:

  • Icono en la bandeja del sistema.
  • Dicho icono parpadea según se realicen cambios en el disco monitorizado.
  • La aplicación ahora se minimiza a la bandeja del sistema.
  • Información de la unidad en un globo de ayuda.
  • Algún que otro bug corregido.

Captura de pantalla de la versión 1.20 de DiskSpace

Y como siempre, podéis bajaros el ejecutable y si queréis el código fuente, sólo tenéis que pedirlo. Por cierto, está hecho en Delphi:

Descargar DiskSpace v1.20 – 481 KB

Server Live Load

Otro pequeño proyecto que presento aquí para los que les guste cacharrear un poco con esto de la programación. El proyecto se llama «Server Live Load» y lo que hace es mostrar la carga instantánea del procesador o procesadores del sistema vía Web al mejor estilo de htop:

Pantallazo del proyecto Server Live Load

Mediante esta aplicación se puede monitorizar la carga instantánea del procesador o procesadores del sistema mediante información textual y mediante unas barras que, según su tamaño, indican la carga en porcentaje de cada uno de los procesadores.

La información textual cuenta con el nombre del servidor, el uptime o tiempo que lleva encendida la máquina, el número de tareas totales y las que están en ejecución y la carga media al minuto, 5 minutos y 15 minutos.

La aplicación está desarrollada en PHP y la librería jQuery de Javascript. Lógicamente, para la actualización de los valores de carga se usa AJAX también mediante jQuery.

Para que funcione sólo es necesario tener un servidor con Linux (con Windows como que no funciona), desplegarla en cualquier directorio al que tenga acceso Apache (o lighttpd o cualquier otro servidor Web que soporte PHP) y listo. Lo único a tener en cuenta es que el usuario con el que se ejecute el servidor Web debe tener permiso de acceso al programa /bin/cat y a los directorios /proc/stat y /proc/uptime.

Por supuesto y como (casi) siempre, se puede ver una demostración de esta misma máquina. Y también, si queréis ver las chapuzas de programas que hago, lo podéis descargar:

Descargar CPULoadWebViewer0.1.tar.gz

Para la siguiente versión a ver si pongo la memoria y el swap además de que sea un poco más configurable. Y ya de estar, aunque quizás sea para la 0.3, un histórico del uso de CPU. Pero bueno, eso con tiempo.

También se podrían poner las tareas que se están ejecutando en cada momento, pero eso cargaría demasiado el sistema, así que ahí se queda.

TimePicker: mi primer plugin para jQuery

Dentro de la página de plugins de jQuery existen varios que muestran un calendario para selccionar una fecha en un formulario. Pero he visto muy pocos (casi ninguno) que muestre un selector de hora, por ejemplo, para seleccionar un horario de trabajo. Y los que he visto tampoco es que sean muy interesantes (aunque es cierto que he visto uno muy bueno llamado NoGray Time Picker pero es con la librería Moo Tools).

Por eso, he hecho mi primer plugin para jQuery que es eso mismo, un selector de hora.

Mediante este plugin, en el input que esté activado, saldrá un selector con la hora actual en formato HH:MM donde, mediante la rueda del ratón, se podrá seleccionar una hora que se asignará automáticamente al input.

Este plugin require jQuery versión igual o mayor a la 1.2.6 y el plugin jQuery MouseWheel versión igual o mayor a la 3.0. Para instalarlo basta con incluir las siguientes líneas en el código HTML (en el mismo orden):

<script type=”text/javascript” src=”jquery.js”></script>
<script type=”text/javascript” src=”jquery.mousewheel.js”></script>
<script type=”text/javascript” src=”jquery.timepicker.js”></script>

Y para activarlo se usa el siguiente código:

<html>
[...]
<script type=”text/javascript”>
$(document).ready(function() {
$(“#timepicker”).timepicker();
});
</script>
[...]
<body>
[...]
<input type=”text” id=”timepicker” name=”timepicker” value=”" />
[...]
</body>
</html>

El id que se le asigna dentro del HTML es __timepicker con lo que se pueden usar hojas de estilo personalizadas.

El plugin está en la versión 0.1 y por dentro está bastante chapucero (es lo que hay ;) ) pero más o menos funciona tanto para Firefox en Windows y Linux como para Internet Explorer. Un problema que he detectado es que en IE versión 6 o menores no carga la hoja de estilos propia del TimePicker. Y un problema muy grave que no he corregido es que ¿qué pasa si tu ratón no tiene rueda? Pues que no puedes asignar la hora más que escribiéndola, por tanto el plugin no sirve para nada. A ver si soluciono esto de una forma elegante sin añadir las típicas flechitas de para arriba y para abajo. ¿Alguna sugerencia?

Podéis ver una demostración y, por supuesto, también podéis descargarlo en el siguiente enlace. Por supuesto que se agradece cualqueir comentario sobre todo de los que digan «¡Hey, que esto no va!»:

Descargar jQuery TimePicker Plugin v0.1

TFileSystemWatcher

Hacía ya bastante tiempo que no programaba por placer, principalmente por la falta de eso mismo, de tiempo libre.

Pero hace poco, revisando lo que tenían por el disco duro, me encontré con una aplicación que había desarrollado hacía bastante y decidí que era un buen momento para retomar su desarrollo.

Esta aplicación está hecha en mi querido Delphi (¡lo que he aprendido yo gracias a él!) para plataformas Windows (creo que vale cualquiera aunque lo he probado en Windows XP) y lo que muestra son todos los cambios que se producen en los archivos de nuestro sistema de archivos indicando si lo que ha cambiado es un archivo o un directorio, el tipo de cambio (adición, modificación, borrado o renombrado) y la ruta donde se ha producido el cambio.

Pero en realidad esta aplicación patata es el test que sirve para desarrollar una clase de Delphi que monitoriza los cambios que se producen en la ruta indicada de nuestro sistema de archivos: TFileSystemWatcher.

File System Watcher en ejecución mostrando los cambios en el sistema de archivos

Como Delphi es un lenguaje de programación dirigida por eventos, cada vez que se produce un cambio en nuestros archivos o directorios, nuestra maravillosa clase, una vez arrancada, generará dos eventos: uno muy genérico dando información de qué ha pasado y otro más específico para poder realizar acciones propias de los cambios que queremos monitorizar.

Si se quiere ver como es por dentro la clase y los eventos que genera, se puede echar un vistazo a continuación:

{**
* @author Diego Lago <beosman@gmail.com>
* @version 0.1 20080318
* @license Creative Commons 2.5 – Reconocimiento – Compartir Igual
*
* @class TFileSystemWatcher
*
* Esta clase hereda de TThread y sirve para monitorizar los cambios en el sistema de
* archivos dada una ruta.
*
* Se pueden instanciar cuantas veces se quiera para monitorizar cualquier directorio.
* Los cambios que se pueden monitorizar son adiciones, borrados, modificaciones y
* renombraciones de archivos y directorios.
*
* Para cada acción se genera un evento genérico que siempre que hay una acción se activa,
* pero también hay eventos más específicos que se activan según el tipo de acción que
* ha ocurrido y según el tipo de archivo (si es archivo o directorio).
*
*}

type

{**
* Tipo de entrada, archivo o directorio, para el evento principal.
*}

TEntryType = (etDirectory,etFile);

{**
* Tipo de acción que se produce sobre el sistema de archivos.
*}

TFileSystemAction = (fsaNoAction,
fsaFileAdded,
fsaFileRemoved,
fsaFileModified,
fsaFileRenamedOldName,
fsaFileRenamedNewName);

{**
* Tipos de eventos producidos por esta clase.
*
* TFileSystemaChangeEvent: Evento genérico. Se produce siempre que hay un cambio en
* el sistema de archivos.
* TFileChangeEvent: Tipo de evento más específico. Se produce cuando hay un cambio en
* archivos o directorios de añadir, borrar y modificar.
* TFileRenamedEvent: Tipo de evento que se produce cuando se renombra un archivo o un
* directorio.
*
* Para más información ver los eventos declarados en la clase.
*}

TFileSystemChangeEvent = procedure(Sender: TObject; EntryType: TEntryType; Path: string; Action: TFileSystemAction) of object;
TFileChangeEvent = procedure(Sender: TObject; FilePath: string) of object;
TFileRenamedEvent = procedure(Sender: TObject; FileOldPath: string; FileNewPath: string) of object;

TFileSystemWatcher = class(TThread)
private

[...]

protected
procedure Execute(); override;

public
{**
* Constructor de la clase.
* @param string FileSystemEntryName Nombre del directorio a monitorizar.
* @param Boolean WatchSubTree Monitorizar también los subdirectorios.
*}

constructor Create(FileSystemEntryName: string; WatchSubTree: Boolean = True);
destructor Destroy(); reintroduce;

procedure Free();

{**
* Inicia la monitorización en un hilo separado.
*}

procedure Start();

{**
* Para la monitorización del directorio.
*}

procedure Stop();

{**
* @property string WatchedPath Directorio que se está monitorizando. Cada
* vez que se cambia se resetean todos los contadores, se para el hilo de ejecución
* y se vuelve a iniciar en caso de que estuviese activo.
*}

property WatchedPath: string read fFileSystemEntryName write setFileSystemEntryName;

property WatchSubtree: Boolean read fWatchSubtree write setWatchSubtree;

{**
* @property Cardinal ChangesCount Número de cambios en el sistema de archivos.
*}

property ChangesCount: Cardinal read fChangesCount;

{**
* @property TDateTime Fecha y hora del último cambio en el sistema de archivos.
*}

property LastChangeAt: TDateTime read fLastChangeAt;

{**
* @event TFileSystemChangeEvent OnFileSystemChange Evento que se produce cada
* vez que hay un cambio en el sistema de archivos.
*}

property OnFileSystemChange: TFileSystemChangeEvent read fFileSystemChangeEvent write fFileSystemChangeEvent;

{**
* Eventos que se producen cada vez que hay un cambio en el sistema de archivos
* sólo para archivos (no para directorios):
*
* @event TFileChangeEvent OnFileAdded Se lanza cuando se añade un archivo.
* @event TFileChangeEvent OnFileRemoved Se lanza cuando se borra un archivo.
* @event TFileChangeEvent OnFileModified Se lanza cuando se modifica un archivo.
* @event TFileRenamedEvent OnFileRenamed Se lanza cuando se renombra un archivo.
*}

property OnFileAdded: TFileChangeEvent read fFileAddedEvent write fFileAddedEvent;
property OnFileRemoved: TFileChangeEvent read fFileRemovedEvent write fFileRemovedEvent;
property OnFileModified: TFileChangeEvent read fFileModifiedEvent write fFileModifiedEvent;
property OnFileRenamed: TFileRenamedEvent read fFileRenamedEvent write fFileRenamedEvent;

{**
* Eventos que se producen cada vez que hay un cambio en el sistema de archivos
* sólo para directorios (no para archivos):
*
* @event TFileChangeEvent OnDirectoryAdded Se lanza cuando se añade un directorio.
* @event TFileChangeEvent OnDirectoryRemoved Se lanza cuando se borra un directorio.
* @event TFileChangeEvent OnDirectoryModified Se lanza cuando se modifica un directorio.
* @event TFileRenamedEvent OnDirectoryRenamed Se lanza cuando se renombra un directorio.
*}

property OnDirectoryAdded: TFileChangeEvent read fDirectoryAddedEvent write fDirectoryAddedEvent;
property OnDirectoryRemoved: TFileChangeEvent read fDirectoryRemovedEvent write fDirectoryRemovedEvent;
property OnDirectoryModified: TFileChangeEvent read fDirectoryModifiedEvent write fDirectoryModifiedEvent;
property OnDirectoryRenamed: TFileRenamedEvent read fDirectoryRenamedEvent write fDirectoryRenamedEvent;

end;

Como os habréis dado cuenta, este código está incompleto, faltan los datos privados, así que no copiéis y peguéis directamente. Lo mejor es bajarse el código fuente y la aplicación de ejemplo:

Descargar TFileSystemWatcher

Lo interesante de esta aplicación es que se puede sacar la clase TFileSystemWatcher del archivo FileSystemWatcher.pas y se puede incluir en cualquier proyecto que requiera monitorizar una o varias zonas del sistema de archivos. Por ejemplo, para hacer un buscador un poco más eficiente que el que trae el Windows.

La licencia de este software es Creative Commons 2.5 Reconocimiento – Compartir igual, así que esta clase se puede utilizar para lo que más os guste sin restricciones. Quizás en próximas versiones me pase a la GPL aunque todavía no la he estudiado lo suficiente (¿cuál es mejor, esta o la GPL?).

Y eso es todo, por el momento. Ahora intentaré continuar con otro proyecto que tengo en mente haciendo uso de esta clase (pues sí, ese buscador más eficiente que el que trae Windows al estilo Google Desktop… si, venga, vale, ya lo han hecho y funciona bien. Pero yo lo hago por aprender).

Y vosotros, si queréis, podéis probar el aparatín y me contáis ;) .

D System Info

He añadido un nuevo proyecto a mi pequeña lista. Este proyecto es uno que hice hace ya 6 años, cuando me causaba furor el sistema operativo BeOS.

Este no es más que una pequeña aplicación para mostrar la información del sistema y lo que pretendía era aprender a programar con su API y, más o menos, conseguí coger los conceptos básicos, aunque ahora, lógicamente, los tengo casi todos olvidados.

Screenshot de D System Info

También he puesto la descarga de esta aplicación junto con su código fuente. Y en un futuro intentaré compilarla en Haiku, ese sistema operativo con el que se me llena la boca al hablar de él.

QTest

Cabecera de QTest

Hace ya algún tiempo que estaba un poco viciado con las quinielas (bueno, un poco no, la verdad es que la hice un par de veces y como no gané nada, como siempre, pues desistí). El caso es que aburría bastante hacer las comprobaciones de los resultados a mano por lo que decidí hacer un programilla que lo hiciese automáticamente.

A principio pensé en hacerlo en Delphi (ya sabéis que me mola) pero luego pensé cómo se podría actualizar y me decidí finalmente en hacerlo vía web.

Cuando analicé el código fuente de la web de donde podía sacar los resultados (la propia de la ONLAE), vi que era un infierno. En serio. Todo sin estructurar, sin id en las tags HTML, sin seguir estándares con CSS, usando etiquetas <font ... >… lo dicho, un infierno.

Así que no me quedó otro remedio que buscar los resultados a mano, es decir, mediante una librería en JavaScript, exactamente jQuery, recorriendo el DOM del documento y contando las etiquetas de cierto tipo que me debería encontrar antes de la que quería. Vamos, una chapuza en toda regla pero todavía no me ha dado tiempo a pensar en otra forma un poco más óptima.

El caso es que se ejecuta en el lado del cliente (JavaScript) por lo que por el momento es muy lento y puede fallar debido a que si me cambian la estructura de aquel documento pues me joden fastidian.

Bueno, no me enrollo más: desde la página del proyecto se pueden ver los resultados de la quiniela de la última jornada de liga de fútbol y comprobar los resultados de tu quiniela. Basta con introducir todos los resultados seguidos, en forma de cadena de unos, equis y doses, presionar el botón «Comprobar resultados» y listo. Ahí os saldrán los aciertos que tenéis y el premio que os lleváis.

Espero que tengamos suerte… algún día.