Docker y symfony

Lo primero sería explicar brevemente que es Docker y porqué puede ser útil emplearlo en tus proyectos de Symfony (u otros) y luego pasaremos a crear un entorno completamente funcional empleando ambos paquetes. Vamos allá:

Docker es un paquete de software que te permite crear un sistema de ficheros independiente que contiene todo lo que necesitas para tener: código, herramientas y librerías del sistema y código en ejecución.

Esto parece un poco como tener una virtualización de un sistema operativo y ciertamente es algo similar pero Docker es un contenedor que necesita muchos menos recursos comparado con un completo sistema virtualizado. Esto te permite tener en equipos modestos diversos contenedores ejecutandose al mismo tiempo lo que a su vez facilita el escalado de tus aplicaciones de una manera muy sencilla y eficaz simplemente generando nuevos contenedores.

Docker también te permite resolver el problema de “en mi máquina funciona” pues cada desarrollador tendrá su propio contenedor que es una copia del contenedor o contenedores de otros entornos (test, producción)

Vayamos a la parte práctica e intentemos generar un entorno con symfony en docker. Para ello presupongo que estas trabajando en GNU-linux y ya tienes instalado docker en tu sistema. Si no es así vete a la página de Docker para saber como instalarlo.

Lo primero sería crear un máquina virtual linux:

$ docker-machine create symfony-project

Así creamos una nueva máquina virtual a la que hemos llamado symfony-project

Para conectarte a la máquina recién creada debes introducir:

$ eval $(docker-machine env symfony-project)

Para ver las máquinas que tienes en ejecución y comprobar que la que acabamos de crear está funcionando basta ejecutar:

$ docker-machine ls

Ahora comencemos con symfony creando un instalación nueva

 

$ symfony new symfony-docker

Cuando esté instalada entramos en el directorio y creamos un nuevo fichero docker-composer.yml

$ cd symfony-docker

$ touch docker-compose.yml

En nuestro nuevo entorno además de Symfony tendremos que instalar otras aplicaciones como php y un servidor web como nginx

Todas estas aplicaciones deberían proceder del hub de Docker que son contenedores ya creados y mantenidos con estas aplicaciones.

Ahora edita tu docker-compose.yml e introduce las siguientes líneas:

nginx:
  image: nginx:latest
  ports:
    - "8080:80"

php:
  image: php:7.0-fpm

 

Ahora ejecuta

$ docker-compose up -d

para inicializar los contenedores

Ejecuta

$ docker-compose ps

Para verificar que está funcionando. Ahora para conectarte a la máquina habría que saber su ip con:

$ docker-machine ip symfony-project

En mi caso es 192.168.99.100 así que para conectarte al nginx habría que conectarse a http://192.168.99.100:8080/

Ahora habría que configurar nginx para que apunte a nuestra aplicación symfony. Para ello tenemos que crear el fichero Dockerfile

Dockerfile representa cada paso que se ha de llevar a cabo una vez que el contenedor esté listo para usar. Normalmente usariamos una herramienta como puppet, ansible o chef  para hacer esto pero en Docker se emplea el fichero Dockerfile.

 

Para ello creamos la carpeta docker/nginx/

$ mkdir -p docker/nginx

y aquí creamos el fichero Dockerfile con el siguiente contenido

$ vi docker/nginx/Dockerfile

FROM nginx:latest
 
COPY symfony3.conf /etc/nginx/conf.d/symfony3.conf

Además creamos el fichero symfony3.conf con la configuración de nginx para symfony

$ vi docker/nginx/symfony3.conf

server {
    server_name symfony3.dev www.symfony3.dev;
    root /app/web;
 
    location / {
        # try to serve file directly, fallback to app.php
        try_files $uri /app.php$is_args$args;
    }
    # DEV
    # This rule should only be placed on your development environment
    # In production, don't include this and don't deploy app_dev.php or config.php
    location ~ ^/(app_dev|config)\.php(/|$) {
        fastcgi_pass php:9000;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        # When you are using symlinks to link the document root to the
        # current version of your application, you should pass the real
        # application path instead of the path to the symlink to PHP
        # FPM.
        # Otherwise, PHP's OPcache may not properly detect changes to
        # your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126
        # for more information).
        fastcgi_param  SCRIPT_FILENAME  $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;
    }
    # PROD
    location ~ ^/app\.php(/|$) {
        fastcgi_pass php:9000;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        # When you are using symlinks to link the document root to the
        # current version of your application, you should pass the real
        # application path instead of the path to the symlink to PHP
        # FPM.
        # Otherwise, PHP's OPcache may not properly detect changes to
        # your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126
        # for more information).
        fastcgi_param  SCRIPT_FILENAME  $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;
        # Prevents URIs that include the front controller. This will 404:
        # http://symfony3.dev/app.php/some-path
        # Remove the internal directive to allow URIs like this
        internal;
    }
}

Además necesitamos añadir el siguiente registro en nuestro fichero local /etc/hosts :

$ sudo vi /etc/hosts

192.168.99.100 symfony3.dev

Recuerda que la ip que pones aquí es la que has obtenido mediante la ejecución de:

$ docker-machine ip symfony-project

 

Con estos cambios actualizamos el docker-compose.yml:

nginx:
  build: docker/nginx
  ports:
    - "8080:80"
  links:
    - php
  volumes:
    - ./:/app
 
php:
  image: php:7.0-fpm
  volumes:
    - ./:/app
  working_dir: /app

 

Ahora para aplicar los cambios debemos detener los contenedores y construirlos de nuevo con estas modificaciones para ello:

$ dockercompose stop
$ dockercompose build
Ahora iniciamos de nuevo los contenedores con:
dockercompose up d
Ahora podemos acceder a nuestra instalación de symfony en la máquina a través de http://symfony3.dev:8080/app_dev.php
Con pequeñas modificaciones puedes aplicar este entorno dockerizado para symfony4

SPHINX, motor para la creación de buscadores de texto

Sphinx es un motor para la búsqueda de textos open source (licencia GPLv2). Está desarrollado en C++ lo que lo diferencia claramente de su competidor Lucene que está desarrollado en java. El nombre Sphinx es un acrónimo inglés que significa SQL Phrase Index (índice de frase de SQL).

Sphinx es un paquete de software independiente que proporciona búsquedas en textos rápidas y relevantes. Como su nombre índica ha sido especialmente diseñado para integrar información almacenada en bases de datos SQL, y para ser fácilmente accesible por lenguajes de script (guión). Sin embargo, Sphinx no depende o requiere de ninguna base de datos específica para su funcionamiento y puede emplear otras fuentes de datos, como por ejemplo XMLs.

Las aplicaciones pueden acceder al servicio de búsqueda (llamado searchd) usando diversos métodos: API nativa (SphinxAPI), una implementación propia del protocolo de red de MySQL (empleando un subconjunto de instrucciones mySQL llamadas SphinxQL) o mediante un servidor MySQL empleando su propio motor de almacenamiento (SphinxSE)

Existe implementaciones nativas oficiales para PHP, Perl, Ruby y Java que están incluidos en el paquete de distribución pero ha sido portado a más lenguajes (Perl, C#, Haskell, Ruby-on-Rails, …etc).

Sphinx soporta de manera nativa información procedente de MySQL, PostgreSQL y XML

Phonegap, desarrollo aplicaciones móviles para múltiples plataformas

Existen muchos puntos fuertes para el desarrollo de aplicaciones para móviles empleando PhoneGap. Pero los más interesantes son estos dos:

1) Phonegap te permite desarrollar en diferentes plataformas móviles y tablets empleando prácticamente el mismo código: Android, iPhone, iPad, Windows mobile, Bada, blackberry, symbian, …
2) Phonegap no emplea nuevos lenguajes, simplemente utiliza javascript (interacción), html5, css3 (presentación).

Cualquier desarrollador web podría comenzar a crear aplicaciones móviles multiplataforma sin que supusiera un gran handicap. Además el desarrollador podría emplear la API del móvil pudiendo tener acceso a la geolocalización, camara, multimédia, vibrador, acelerómetros, brújula, contactos del móvil, archivos, redes, notificaciones, vibrador, etc

Además existen ya varios frameworks que te ayudarán a salvar las diferencias entre la web y la aplicación móvil en cuanto a interacción, presentación y usabilidad como por ejemplo xuijs, jQTouch y jQuery Mobile.

Para comenzar a utilizar phonegap basta con tener listo el SDK para el desarrollo para móviles de tu plataforma favorita. Para android por ejemplo basta con tener instalado eclipse 3.4 o posterior junto con una copia del SDK para android (http://developer.android.com/sdk/index.html) y el complemento ADT de eclipse.

A continuación hay que descargarse phonegap y comenzar un proyecto android en el eclipse.

1) Se crean los directorios /libs y /assets/www
2) De phonegap descargado se copian los archivos phonegap.js en /assets/www y phonegap.jar en /libs
3) En la clase Activity inicial del proyecto debe cambiar el extend Activity por extend DroidGap
4) Sustituir setContentView() por super.loadUrl(“file:///android_asset/www/index.html”);
5) Añadir el principio del fichero el import : import com.phonegap.*;
6) Añadir los permisos que vayas a utilizar para la aplicación (En el archivo AndroidManifest.xml debajo de versionName)
7) Colocar el archivo plugins.xml de phonegap en la carpeta /res/xml/

Y listos para programar en tu fichero index.html en /assets/www

Si tienes problemas y no quieres liarte con crear entornos de desarrollo para todas las plataformas puedes empezar a desarrollar directamente empleando PhoneGap build en http://build.phonegap.com/
Aquí puedes enviar tu código y recibir una aplicación lista para publicar en Market, ya sea IOS, Android, webOS, Symbian, BlackBerry, Windows Phone u otros dispositivos.

Para empezar a programar basta entender una lista de nuevos eventos y API que permiten acceder a las funcionalidades del móvil empleando sólo javascript

Como ejemplo, en phonegap está disponible el evento onDeviceReady:

<script type=”text/javascript”>
document.addEventListener(“deviceready”, onDeviceReady, false);

function onDeviceReady()
{
//llamada inicial a la API de phonegap
}
</script>

Este evento índica que se ha cargado el DOM del documento HTML y ya podemos comenzar a ejecutar nuestro código. Además tenemos estos nuevos eventos javascript disponibles en phonegap

backbutton
deviceready
menubutton
pause
resume
searchbutton
online
offline

Que permiten detectar los eventos propios asociados a un móvil para poder actuar en consecuencia. Creo que los nombres son bastante autoexplicativos.

Para acceder a toda la funcionalidad del móvil basta con estudiar la documentación de la API http://docs.phonegap.com/en/2.4.0/index.html (cuando escribí este articulo era la 2.4.0). Donde puedes ver como acceder a todo las funcionalidades del móvil empleando solamente javascript.

Espero que este artículo te sirva para atreverte con esta nueva tecnología

 

Robot phonegap
Robot phonegap

 

Convertir int a string in php

A pesar de que php es un lenguaje con un tipado débil. Esto significa que, para los tipos primitivos de datos, estos son convertidos automáticamente para poder operar con ellos sin que el programador tenga que hacer nada. Por lo tanto en la mayoría de las ocasiones esta operación de convertir int a string no es realmente necesaria. Sin embargo es posible que nos encontremos con algunos casos en la que si lo sea. Existen varias posibilidades para realizar esta operación:

Type casting

Basta con forzar la conversión empleando el cast (string). Exemplo:

$a = (string)345;
var_dump($a);

Funcion strval:

Directamente convierte una variable (no tiene porque ser un entero) en un string

$a = strval(354);
var_dump($a);

Conversión forzada
Forzar la conversión a cadena (string) empleando alguna operación que lo requiera

Podemos encontrar diversos ejemplos de esta técnica

$a = 456.””; //concatenación de cadenas

$b = 567;
$a = “$b”; //formación de cadenas

Benchmark

Haciendo un benchmark de todos estos métodos con una version de php 5.2.5

Este sería el código empleado:

<?php

echo ‘PHP version: ‘.phpversion().”\n\n”;

$microtime = microtime(true);
for($i=0;$i<1000000;$i++) $a = (string)567;
echo ‘Método cast: ‘.(microtime(true)-$microtime).” segundos\n”;

var_dump($a);

$microtime = microtime(true);
for($i=0;$i<1000000;$i++) $a = strval(343);
echo ‘Función strval: ‘.(microtime(true)-$microtime).” segundos\n”;

var_dump($a);

$b = 456;
$microtime = microtime(true);
for($i=0;$i<1000000;$i++) $a = $b.””; //concatenación de cadenas
echo ‘Concatenación de cadenas: ‘.(microtime(true)-$microtime).” segundos\n”;

var_dump($a);

$b = 567;
$microtime = microtime(true);
for($i=0;$i<1000000;$i++) $a = “$b”; //formación de cadenas
echo ‘Formación de cadenas: ‘.(microtime(true)-$microtime).” segundos\n”;

var_dump($a);
?>

Y estos los resultados obtenidos en mi caso:

PHP version: 5.2.5

Método cast: 6.115082025528 segundos
string(3) “567”
Función strval: 6.3874759674072 segundos
string(3) “343”
Concatenación de cadenas: 6.1379280090332 segundos
string(3) “456”
Formación de cadenas: 6.1571230888367 segundos
string(3) “567”

El método cast es el más rápido y la función strval la más lenta quizás debido a que este método tiene más funcionalidades. Los otros métodos parecen ligeramente inferiores en rapidez.

Tenemos otra artículo relacionado con este por si estas interesado en la conversión de int a string en java. Java es un lenguaje con el tipado más estricto que php por lo que conocer esta conversión de tipos para este lenguaje puede serte útil también.

Tutorial Git (recetario)

Git es un sistema de control de versiones distribuido. Los clientes de Git no se descargan la última versión de los ficheros de un proyecto: sino que se bajan el repositorio completamente. Git también permite tener más de un repositorio remoto.

Git almacena los datos como instantáneas (snapshots) del proyecto a lo largo del tiempo. Para ganar en eficiencia, si los ficheros no cambian, Git no almacena el fichero otra vez — simplemente un enlace a la versión idéntica y anterior que ha sido almacenada previamente. Git no almacena los “deltas” de los ficheros cambiados. Almacena el fichero cambiado entero.

Casi todas las operaciones en Git son locales ya que toda la información histórica está en el repositorio local.

Git verifica la integridad de ficheros empleando sumas de verificación (checksums) (empleando el algoritmo SHA-1, que devuelve una representación de 40 caracteres hexadecimales en minúscula)

Casi todas las operación simplemente añaden datos a la base de datos de Git. Es muy difícil hacer que el sistema haga algo que no se pueda deshacer.

Los 3 estados
Git tiene 3 estados principales para los ficheros que tiene bajo control: entregado (committed), modificado (modified) y (preparado) staged

Entregado (commited) – los datos han sido almacenados y están seguros en la base de datos local.
Modificado (modified) – El fichero han cambiado pero no se ha entregado todavía
Preparado (staged) – Significa que has marcado un fichero modificado en su versión ACTUAL para ser entregado en la siguiente instantánea (snapshot).

Esto nos lleva a las 3 versiones principales de un proyecto Git: el directorio Git, el directorio de trabajo y el área de preparación (staging area)

Directorio Git – es donde los metadatos y los objetos de la base de datos es almacenado (directorio .git)
El directorio de trabajo – es una de las versiones de los ficheros del proyecto (instantanea) donde el usuario generalmente modifica los ficheros
El área de preparación (staging area) es un simple fichero, generalmente contenido en el directorio Git que almacena toda la información sobre la siguiente entrega de ficheros.

Así que un fichero puede estar entregado (en el directorio Git), preparado (en el área de preparación) o modificado (solo en el directorio de trabajo)

¿Cúal es tu navegador preferido?

Volviendo al tema recurrente de la guerra de los navegadores podemos ver que firefox sigue en cabeza y con cierta ventaja respecto a su más directo competidor Internet explorer. Pero, a día de hoy, ¿Cúal es tu navegador preferido?


Compararé los datos procedentes del tráfico a este blog con las votaciones, creo que va a haber algunas sorpresas…

Así comenzó google

Equipos con los que empezó google

Estos son los equipos con los que iniciaron el proyecto en la universidad de Standford. Larry Page y Sergey Brin en aquella época tenían 25 y 24 años respectivamente. El proyecto se llamaba entonces BackRub y era el año 1996 por lo que los equipos no estaban nada mal para la época. Además los consiguieron gracias a ayudas y donaciones, principalmente de IBM.

* 4-proc PPC 604 333mhz, 512mb, eight 9gb drives
* 2-proc UltraSparc II 200mhz, 256mb, three 9gb drives, six 4gb drives
* 2-proc Pentium II 300mhz, 512mb, five 9gb drives
* 2-proc Pentium II 300mhz, 512mb, four 9gb drives

* Disk expansion, eight 9gb drives
* Disk expansion, ten 9gb drives

Este era el resultado (Captura de google 1998 desde archive.org)

captura web google en sus origenes

Hoy en día google dispone de más de 500.000 servidores no hay otra entidad pública o privada con tal cantidad de servidores en internet.

Google original servers [EN]

Patrones de diseño

Un patrón de diseño (en programación orientada a objetos, POO) es una descripción de diversos objetos y clases preparados para resolver un problema de diseño general aplicado a un contexto específico. Un patrón de diseño identifica las instancias y clases que participan en dicho patrón además de sus papeles, sus relaciones y sus responsabilidades para llevar a cabo la tarea a resolver. Cada patrón de diseño se centra en resolver un problema particular en la POO. Describe cuando se puede aplicar, si puede ser aplicado desde el punto de vista de las limitaciones del diseño y las consecuencias tanto positivas como negativas que tiene su utilización.

Pongamos un ejemplo: MVC (model-view-controller) consiste en 3 tipos de objetos. El modelo son los objetos de la aplicación (lógica de la aplicación), la vista es su representación a los usuarios y el controlador define la manera en el que la interfaz con el usuario (generado por la vista) reacciona ante la introducción de datos por parte del usuario. Dentro de MVC hay varios patrones de diseño que pueden ser empleados para facilitar el desarrollo de este tipo de arquitectura.

Por ejemplo la relación vista-controlador es un ejemplo del patrón de diseño “Strategy”. Strategy es un objeto que representa un algoritmo. El patrón es útil en realidad cuando pretendes reemplazar este algoritmo estática o dinamicamente cuanto tienes varias variantes del algoritmo o cuando el algoritmo tiene una estructura de datos compleja que quieres encapsular.

MVC usa otro patrón de diseño “Factory Method” para especificar la clase controladora por defecto para una vista y “Decorator” se puede emplear por ejemplo para añadir scroll a una vista. Pero la principal relación en MVC es dado por los patrones “Observer”, “Composite” y “Strategy”

Antes de describir alguno de ellos defino brevemente los parámetros que se emplean para describir los patrones de diseño:

Nombre del patrón y clasificación, intención (¿Que hace este patrón?) ,otros nombres por los que también es conocido, motivación (escenario que ilustra su funcionamiento), aplicabilidad (en que escenarios es válido), estructura (representación gráfica de las clases involucradas y diagramas de interacción para ilustrar secuencias de peticiones y colaboraciones entre objetos), participantes (clases, objetos y sus responsabilidades), colaboraciones (como los participantes pueden colaborar en sus responsabilidades), consecuencias (¿Cómo el patrón realiza su cometido?¿Cuales son los compromisos a tener en cuenta al aceptar esta solución?), implementación (dificultades, riesgos, pistas o técnicas a tener en cuenta a la hora de implementar el patrón), ejemplo de código, usos conocidos y patrones relacionados.

Nombre: Observer
Clasificación: Behavioral Patterns
También conocido como: Dependents, Publish-Subscribe, Event-Observer
Motivación: Un problema muy común al particionar un sistema en una colección de clases cooperativas es la necesidad de mantener la consistencia entre objetos relacionados pero sin tenerlos fuertemente acoplados ya que esto reduce su reusabilidad. El patrón define un sujeto y uno o varios observadores de este suejto. Todos los observadores son notificados si el sujeto lleva a cabo un cambio de estado (evento).
Aplicabilidad:
– Cuando un objeto cambia y esto requiere el cambio de varios objetos y se desconoce el número de objetos que necesitarán este cambio
– Cuando una abstracción tiene dos aspectos, una dependiente de la otra. Encapsular estos aspectos te permite variarlos y reusarlos independientemente
– Cuando un objeto tiene que notificar a otros objetos sin hacer asunciones sobre su naturaleza. En otras palabras no se quiere que estos objetos esten fuertemente acoplados
Estructura: Diagrama de clases
Diagrama de clases patrón observer

Participantes:
– Subject (conoce sus observers que pueden ser uno, ninguno o varios y proporciona un interfaz para registrar y desregistrar observadores)
– Observer (define un intefaz para actualizar que debe ser llamado cuando el subject cambia de estado)
– ConcreteSubject (almacena el estado de interes para los objetos ConcreteObserver y les envia notificaciones cuando su estado cambia)
– ConcreteObserver (Mantiene referencia al objeto ConcreteSubject, almacena estado de manera consistente con el del objeto ConcreteSubject e implementa interfaz de actualización para las notificaciones)
Colaboraciones: ConcreteSubject notifica a sus observadores sobre un cambio que podría hacer el estado de los observadores fuera inconsistente con el suyo propio. Después de ser informado el observador del cambio en el sujeto. El observador podría requerir informacion al sujeto para conciliar su estado
Consecuencias: El patrón observer te permite cambiar sujetos y observadores de manera independiente de manera que se pueden rehusar ambos. Puede violar la separación en capas de tu aplicación pues los observadores pueden pertenecer a capas diferentes de la del sujeto. Las actualizaciones en el sujeto pueden generar un coste desconocido pues no se sabe cuantos ni cuales observadores pueden estar registrados al sujeto.
Implementación: Temas conflictivos: mapear subjects a observers y observers a más de un subject. ¿Quien dispara la actualización? 2 opciones, el propio subject cuando cambia de estado o hacer a los clientes responsables de enviar la notificacion.
Ejemplos de código: Symfony event dispatcher
Usos conocidos: Cualquier interfaz de usuario GUI implementado empleando OOP como KDE
Patrones relacionados: Mediator, Singleton

Espero que os sea de utilidad. No puedo acabar si pasar la referencia a la biblia de los patrones de diseño creado por el Gang of Four (sus 4 autores)

Design Patterns. Elements of Reusable Object-Oriented Software – Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides – Addison Wesley (GoF- Gang of Four)

Ignorar ficheros y directorios en subversion

Es bastante sencillo cuando trabajamos con subversion u otros tipos de repositorios incluir en nuestra cópia de trabajo ficheros que no debemos subir al repositorio, como compilaciones, ficheros de prueba, ficheros del sistema operativo, logs, etc. Para que subversión los ignore tenemos diversos métodos.

Todos estos métodos modifican la propiedad svn:ignore

1) Editar directamente la propiedad para un directorio en concreto


$ svn propedit svn:ignore ./ruta_ficheros_a_ignorar

A continuación podemos indicar los ficheros a ignorar dentro de la ruta especificada permitiéndose el comodín ‘*’. Así para ignorar todos los ficheros dentro del directorio basta con indicar


\*

Puedes crear una lista de ficheros, uno por linea, por ejemplo:


\*.out
data.log
\*.tmp
test_\*

2) Otro método consistiría en editar el archivo global ~/.subversion/config

Busca la sección [miscellany] dentro de este fichero y cambia la propiedad global-ignores para ignorar los archivos que no deseas subir al repositorio. Hay que emplear un espacio como separador entre “ficheros” en lugar de poner uno por línea como hacíamos antes. Así:


global-ignores = \*.out data.log \*.tmp test_\*

Esto ignorará todos los ficheros que sigan este patrón en todos los repositorios que emplees en tu máquina local

3) Un último método sería empleando el comando propset de subversion


$ svn propset svn:ignore \*.tmp .

El punto final indicaría que es el directorio actual en donde deben ignorarse los fichero son extensión tmp

Podemos especificar un fichero donde tengamos todas las reglas para ignorar ficheros con el modificador -F, así:


svn propset svn:ignore -F ignore.txt .

Recuerda además que si empleas propset y propedit debes ejecutar un commit para que todo el mundo ignore estos ficheros. Ten esto en cuenta a la hora de definir lo que no quieres versionar.. svn:ignore es una propiedad; metadatos en el repositorio que también son versionados. Cada objeto dentro de subversion (ficheros, directorios, enlaces etc) puede tener esta u otras propiedades. Para saber que propiedades tiene un objeto en concreto en nuestro repositorio o copia de trabajo basta ejecutar:


$ svn proplist /ruta_objeto

jMonkeyEngine, motor 3D para desarrolladores java

Como dice su lema ‘serious monkyes. serious engine.’ nos encontramos ante una API de alto rendimiento para la generación de escenas gráficas en 3D realmente maduro. Sólo hay que echarle un vistazo a su sección de películas y demos que da cuenta de las posibilidades actuales de su motor gráfico. jMonkeyEngine es un proyecto de código abierto bajo licencia BSD que comenzo allá por el año 2003. Actualmente acaban de sacar la alpha de la versión 3 del engine.

Para poder empezar a desarrollar basta con descargase las librerías jar del proyecto. Actualmente lo mejor es hacerlo a través de las versiones nocturnas aunque puedas encontrarte con alguna versión más o menos estable el producto está bastante acabado.

Ahora sólo tienes que descomprimirlo (descarga .zip) he importar jMonkeyEngine3.jar y la carpeta lib que se encuentra en el zip dentro de tu proyecto. También tienes los javadoc y el código fuente en el archivo zip y en la página web de jMonkeyEngine puedes ver tutoriales explicativos para poder comenzar a hacer tus pinillos en el mundo 3D.

Happy coding!