miércoles, 21 de enero de 2015

Publicado “Ant” para plataformas android, minijuego basado en el framework cocos2d-x.

Ant es un pequeño juego que se acaba de publicar para plataformas android >= 2.3, la idea es bastante sencilla, tienes un grupo de hormigas moviéndose en la pantalla que debes matarlas, tienes dos modos de hacerlo, el primero es por tiempo, ver en 60 segundos cuantas hormigas puedes matar y el segundo modo es ver en que tiempo puedes matar una determinada cantidad de hormigas. La aplicación puede ser descargada desde la tienda de google, aquí te dejo unas capturas de la misma:

Es tan sencillo de jugar como de implementar(y es aquí donde entra la información relevante para ti si eres desarrollador de software), de hecho el único punto que quiero comentar es la manera en que se mueven las hormigas, se ha hecho usando algo de inteligencia artificial muy básico, se conoce como Agentes Autónomos, específicamente comportamientos guiados o Steering Behavior ya que no estoy seguro como es la traducción, pero independiente del término en español tendrás una idea bien clara de a que se refiere cuando acabes de leer este post.
Hay varias definiciones de Agentes Autónomos, yo te comparto la que mejor acepto:
Un agente autónomo es un sistema situado dentro de un entorno (del cual forma parte) al cual puede percibir  y sobre el cual puede actuar, durante el tiempo, en búsqueda de sus propios objetivos y sospechar como serán los efectos que percibirá en el futuro.

Por ejemplo podrías diseñar un agente autónomo que se comporte como un conejo y otro como un zorro, en este caso el conejo podría “percibir” el zorro y de forma autónoma comportarse para evadirlo, mientras que si el zorro “percibe” el conejo se comportaría de forma autónoma para perseguirlo, y este comportamiento autónomo debería suceder sin que el programador tenga que intervenir posteriormente en alguna forma.
El movimiento de un agente autónomo puede ser descompuesto hasta en tres capas:
  1. Selección de la Acción: Este es el punto en el que el agente selecciona sus objetivos y un plan a seguir para lograrlos, es como ...ir aquí... y hacer A ,B y por último C.
  2. Guiado: Este punto es donde se calculan las trayectorias deseadas para cumplir los objetivos y siguiendo el plan en la etapa anterior. El comportamiento guiado es la implementación de esto que se enuncia. Este produce una “fuerza guía” que dice la dirección en que debe moverse y que tan rápido debe estar en el lugar de destino.
  3. Locomoción: La capa inferior, Locomoción, los aspectos mecánicos del movimiento de un agente. Es la definición exacta de como viajar de A hasta B. Por ejemplo si usted implementa la mecánica para mover un camello, un tanque y un goldfish y les da un comando para hacer un mismo viaje, ellos podrían(y muy probablemente lo hagan) usar diferentes procedimientos mecánicos para alcanzar su objetivo aún cuando este es el mismo, …hacer el viaje indicado con el comando... La separación de esta capa de la anterior(guiado) es lo que hace posible, con pequeñas modificaciones tener un mismo guiado con locomoción totalmente diferente.
El algoritmo seleccionado para representar el movimiento de las hormigas es un Wander(vagabundear), el cual está diseñado para dar la impresión de que el agente se mueve de forma aleatoria alrededor de su entorno. La solución de Craig Reynold consiste proyectar un circulo frente al vehículo (libro al final) y avanzar hacia un punto contenido en el perímetro (circunferencia) creado un movimiento variable sin movimientos bruscos (temblor). Este método puede ser utilizado para producir un amplio rango de movimientos aleatorios, desde cambios ondulados y suaves hasta alocados movimientos típicos de un salón de baile un tanto remolinado y lleno de piruetas, solo dependiendo de el tamaño del círculo, la distancia hasta el vehículo y la velocidad con que te mueves hacia ese punto. La siguiente imagen puede ser de ayuda para entender la idea.


NOTA: Estas ideas se han tomado del libro Programming Game AI by Example by Mat Buckland, a las cuales les he hecho pequeñas modificaciones, o sea, cualquier error introducido es mi único “aporte”.

La aplicación la puedes decargar para android >= 2.3 desde Google Play


Saving Las Vegas: videojuego basado en el framework cocos2d-x para plataformas Android >= 2.3.




Breve descripción:
Las Vegas está siendo atacada por una lluvia de meteoritos. El objetivo  principal del juego es proteger la ciudad de la destrucción. Deberás evitar la caída de los asteroides detonando bombas en el cielo para destruirlos.
La puntuación final será determinada por:
-el numero de asteroides destruidos.
-la precisión en el uso de las bombas.
-el tiempo de supervivencia, medido en días.

¿Cómo jugar?
Las primeras veces que juegues, se mostrarán algunas indicaciones que te  ayudarán a entender cómo obtener más armas y cómo usarlas. El juego se irá poniendo más difícil al pasar el tiempo pero tendrás mejores armas que te ayudarán a sobrevivir.

Este videojuego ha sido desarrollado por un pequeño equipo del que formo parte. Se usó c++11, el framework cocos2d-x(3.2), inkscape para la imágenes, y lmms para el audio. La idea original proviene del libro Cocos2d-x by Example Beginner's Guide de RogerEngelbert, procedimiento totalmente legal(http://www.copyright.gov/fls/fl108.html)

Categoría: Arcade → Aventura.

La aplicación para Android(>=2.3) podrás descargarla desde Google Play.

jueves, 1 de mayo de 2014

Cómo colaborar en un proyecto de software libre(GitHub)?


En este post estaré explicando la manera de colaborar con un proyecto de software libre existente y de qué manera esto te puede ser útil.

Siempre que hacemos algo hay un motivo detrás: dinero, odio, aburrimiento, satisfacción, aventurarse, aprender y hasta porque sí! como comentan a veces los hackers ja. En el caso del desarrollo de software también aplican algunos de estos motivos, por ejemplo en mi caso me hice una cuenta en github con el objetivo de colgar algunos proyectos que pudiese integrar a mi portafolio de trabajo y en cunato me creé la cuenta me percaté de algo que señalan los estudiosos de la metodología de la investigación científica "...para resolver un problema, lo primero que necesitas es precisamente eso, tener un problema..." y he ahí el mio, uso aplicaciones básicas a diario y por lo general resuelven todas mis necesidades. Después de pasado algún tiempo tenía algunos proyecticos que creé para aprender mientras "jugaba" con alguna que otra biblioteca o framework, ya cuando me decidí a trabajar en algo en concreto revisé algunos proyectos existentes que me parecieran interesantes en busca de algún candidato con el que me gustaría colaborar finalmente seleccioné un wannabe de textmate(editor de texto de MAC OS X) el cual no mencionaré porque no viene al caso... El mismo día que fui a hacer mi fork vi un correo de embebidos32@googlegroups.com en el cual se comentaba algo acerca de un proyecto llamado CIAA, ja sorpresa, me olvidé de el editor, si eres una persona que le gusta la electrónica, la automatización, la domótica y todos estos temas relacionados con el software de/para sistemas embebidos, este es el proyecto que buscas, son infinitas las oportunidades que tienes para aprender al integrarte a este. Y esto solo de gratis...?, pués rsulta que no, el día que esté en busqueda de empleo y me pidan un currículo esta es otra de las cosas que puedo enseñar ya que es un proyecto bien fomentado, que además es de software libre por lo que mi código esta disponible a ser leido. Además de esto si eres argentino que trabaja con este tema de los embebidos o relacionados deberías estar al tanto de este proyecto y prever las oportunidades que este depara en un futuro cercano en la medida en que este sea adoptado por las compañías y centros educacionales(que hoy están trabajando en su desarrollo), en la página oficial puedes ver algunas de las multiples aplicaciones de este.

Los proyectos de software libre han cambiado el mundo del software. Detrás de la ejecución de tales proyectos se encuentran personas que dedican su tiempo a crear tecnologías abiertas en las que cualquiera puede contribuir. Hay una falsa creencia que para participar en estos proyectos es imprescindible ser un gran programador o tener mucho tiempo. Pero no, no es un requisito indispensable. Existen muchas formas de las que puedes ser colaborador de un proyecto de software libre, aunque casi siempre hay dos o tres que son unos genios,(Dennis Ritchie, Sara Sharp, Dave Jones, Linus Torvalds, Richard Stallman, …) el resto suelen ser personas común y corriente como tu y como yo y que para nada esto nos hace menos importantes, hay que tener en cuenta que hasta las más grandes obras se hacen a partir de la unión de pequeñas partes, y siempre tiene haber una primera vez para todo, donde verás que aprender es un proceso activo y no pasivo. Todo este comentario relacionado al hecho de que en los proyectos de software hay varios roles, no solo el de programar, además tener en cuenta que según Roger Pressman el software es un conjunto de uno o varios programas + un conjunto de documentos, aquí te dejo una lista no exaustiva de algunos de los roles que puedes asumir:

  • Integrarse en la comunidad y ayudar a su difusión.
  • Detección y la resolución de bugs.
  • Código del proyecto.
  • Documentar y crear ejemplos.
  • Traducción a diferentes idiomas.
  • Manual de usuario.
  • Testear.
  • Reportar bugs.
  • Otros...


Trabajar en el código del proyecto.
Yo en mi caso he seleccionado esta parte y de aquí el título del post que está dedicado principalmente a los que van escribir código nuevo para el proyecto y no se han decidido a empesar. Una de las primeras cosas que debes hacer es consultar cuál es el estilo de código del proyecto, para esto puedes buscar un archivo llamado HACKING en el código fuente en el que encontrarás información de este tipo, revisar en la wiki, escribir en las listas, e incluso si coincide que están usando alguno bien conocido y que además tu sepas reconocer es algo que queda implícito en el código, esto parecería una pavada pero busca los proyectos más famosos que conozcas y verás como cada uno guarda su propia formalidad como GNU, Linux, Qt, … la responsabilidad es otra de las buenas cosas que puedes aprender manteniendo el estilo y hacer los commit lo más oportunos posibles para que los desarrolladores más experimentados integren nuestro código en la rama principal en caso de haber hecho algo bueno, de no ser correcto, de seguro recibes algún comentario y esto también es bueno porque te hace aprender, no se pierde de ninguna manera :). Puedes comenzar por las partes que sean menos difíciles de integrar en el proyecto como hacer pruebas unitarias, probar la portabilidad, y de ahí podrías resultar por ejemplo el encargado de dar soporte a alguna plataforma que conozcas bien. Te puedes dedicar además a solucionar errores de los recién llegados, resolver tickets, y cualquier cosa que pueda ayudar a liberar los desarrolladores de manera que centren su esfuerso en el código.

Una vez entendido esto lo que sigue es seleccionar el proyecto en el que quieres colaborar, como comentaba en mi caso seleccioné CIAA (Computadora Industrial Abierta Argentina), específicamente la parte de software para PC. El primer paso es, estando en el repositorio “forkear” el repositorio.







Y ya tenemos el repositorio en nuestra cuenta.









Esto es necesario porque como es común no debes tener permiso directo sobre repositorio de los proyectos y cuando haces un fork en esa copia del proyecto cambian algunas cosas como por ejemplo la propiedad y por ende los permisos que ahora son plenos, entonces la idea es clonarte el repositorio desde su url(ver imagen), hacer los cambios, subirlos y hacer un pull rquest.







Empecemos a trabajar!
Luego de tener el repositorio en nuestra cuenta lo clonamos como comentaba(para este caso usaré https):
cd Software
git branch foo
git checkout foo
#editas tus cambios, durante días, semanas, …
#actualizas tu código, con las cosas que pudieran no estar en tu repo por el paso de los días.
#agregas tus cambios
git add .
git commit -m “no acepte estos cambios, es que estoy escribiendo un tuto”
~/Software (foo) [1]> git commit -m "no acepte estos cambios, es que estoy escribiendo un tuto"
[foo fa6051f] no acepte estos cambios, es que estoy escribiendo un tuto
4 files changed, 14 insertions(+), 10 deletions(-)

Subes los cambios a “tu fork”:
Username for 'https://github.com': testuser23
Password for 'https://testuser23@github.com':
Counting objects: 34, done.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (12/12), 1.09 KiB | 0 bytes/s, done.
Total 12 (delta 9), reused 0 (delta 0)
To https://github.com/testuser23/Software.git
* [new branch] foo -> foo

Es importante mencionar que se recomienda no hacer los cambios en la rama master, sino utilizar otras ramas, para comodidad y evitar perder otros cambios; el master se mantendrá solo para recuperar los últimos cambios del repositorio original.

El último paso para que nuestro aporte se haga efectivo en el repositorio es enviar un Pull Request y esperar a que el encargado del repositorio lo revise, acepte y mezcle en la rama correspondiente a la versión del software.

Hacemos click en "Compare & Pull Request", nos llevará a otra página donde podremos detallar nuestro Pull Request.








Si todo está bien, realizamos el envío con el botón "Send Pull Request".






Además de todo esto comentar que no es ético estar usando proyectos externos hosteados en github para estar haciendo tests por tanto yo no lo haré :)

Sobre todos estos tick puedes ver en el propio github.

sábado, 22 de febrero de 2014

Alta disponibilidad de servidores y balanceo de carga.


Por estos tiempos las entidades dependen cada vez más de sus sistemas de información/informatización y como es obvio se desea que estos estén disponibles la mayor parte del tiempo posible, la interrupción de los mismos presupone serios problemas:
  • Costes directos asociados a la reparación del sistema de información (piezas a reparar o sustituir, portes, servicios técnicos, etc.).
  • Horas de trabajo adicionales para el departamento de sistemas que tiene que reparar la avería.
  • pérdidas de productividad o incluso horas de trabajo perdidas por los empleados que dependen del sistema.
  • Pérdida de ingresos, por las ventas o servicios que se han dejado de realizar.
  • Costes indirectos: satisfacción de los clientes, pérdida de reputación, mala publicidad, desconfianza de los empleados, etc.
La disponibilidad implica varias categorias:Fiabilidad, Recuperación, Detección de errores, Continuas operaciones.

Cluseter de alta disponibilidad:
Un cluster de alta disponibilidad es un conjunto máquinas(no se debe confundir con cluster de alto rendimiento), en su funcionamiento se manifiesta de manera general el monitoreo constante por parte del cluster(también denominado monitor del cluster), en caso de detectar el fallo del algún nodo procede a reemplazarlo de manera automática, este se puede dividir a su vez en dos clasificaciones:
Alta disponibilidad de infraestructura:
Esta clasificación se da cuando al producirse algún fallo de hardware en una de las máquinas activas del cluster el software es capaz de arrancar el servicio en una de las máquinas inactivas(respaldo), a ese proceso se le llama failover y a su contraparte failback que es la operación de devolver el servicio a los responsables originales después de corregirse la falla.
Alta disponibilidad de aplicación:
Esta clasificación se da cuando al producirse algún fallo de hardware o de las aplicaciones en una de las máquinas activas del cluster el software es capaz de de delegar el servicio que ha fallado a un de las máquinas de respaldo, una vez que la maquina del fallo se restablece la responsabilidad de los servicios le es devuelta.

 
Para esto te puedes encontrar con soluciones como:
Balanceo de carga.

El balance o balanceo de carga es una técnica utilizada para repartir el trabajo a realizar entre varios procesos, discos duros, máqinas, etc. El balance de carga se mantiene gracias a un algoritmo que divide de la manera más equitativa posible el trabajo, para evitar los así denominados cuellos de botella.

El problema de cómo gestionar la carga por los grandes de internet(goole, facebook, amazon, twitter, wikipedia, etc) es enfrentado de esta manera, y además resuelve de forma implícita la escalabilidad para el creciente número de usuario con que trabajan cada día.

Para esto te puedes encontrar con soluciones como:






Alta disponibilidad + Balanceo de carga:
La solución más completa consiste en una vinculación de estas dos tecnologías llegando a tener desempeños inigualables.




Por útimo a modo de ejemplificar los post sobre c++11 y Qt5 dejo un pequño demo sobre balanceo de carga, no funciona con un monitor(es un ejemplo de solo unas pocas lineas de código) sino que los clientes se mantienen chequeando constantemente la disponibilidad del servidor y en caso de no estar accesible uno de ellos toma su lugar.



Ver además: 

Algunas ventajas del uso de c++11.

C++ es un lengueaje de propósito general, el nuevo estándar centra sus esfuersos en dos aspectos fundamentales:
  1. Hacer a c++ un mejor lenguaje para la programación de sistemas y creación de biliotecas.
  2. Hacer a c++ más fácil de enseñar y aprender.
Hay muchas aplicaciones en las que podemos encontrar a c++ unas veces como lenguaje principal y otras veces usado en partes críticas de las mismas ej:
  • Google, el motor de búsqueda.
  • Amadeus, para venta de voletos de vuelo.
  • Facebook, la red social.
  • JVM (Oracle).
  • Interpretes javascrip (google V8).
  • Qt, framework para el desarrollo multiplataforma.
  • POCO, para el desarrollo orientado a la web.
  • OpenCV, para el tratamiento en tiempo real de imágenes.
  • Navegadores Web (Internet Explorer, Mozilla, Google-Chrome, Safari).
  • En general se pueden encontrar muchas aplicaciones en finansa, telecomunicaciones, drivers, el ejército, aplicaciones embebidas, videojuegos, matemática computacional(para lo que no fue originalmente creado, sin embargo está siendo ampliamente utilizado), robótica, entre muchas otras.

Como lo dice el título del post, acá les comparto algo de lo nuevo de c++11 antiguamente conocido como c++0x (si quieres una referencia más completa deberás leer un libro, yo recomiendo “The C++ Programming Language . Fourth Edition. Bjarne Stroustrup (el creador original de C++... que más se puede decir...)”, autores como estos además te recomiendan para ver material técnico específico la especificación de la iso(ISO C++ standard (ISO/IEC 14882-2011) [C++,2011] )).
Bueno las novedades de c++ abarcan la forma de escribir(sintácsis), el rendiemiento, facilidades de la biblioteca estandar, entre otras, de manera general son bastantes los cambios(a mi concideración para bien). C++11 salió ya hace algún tiempo: en 2009 se realiza una primera revisión del estándar a modo de borrador, en agosto de 2011 fue aprobado por la iso, en 2012 sale la primera implementación completa y hoy estamos aquí, algunos sin usarlo todavía a pesar de que actualmente es soportado por gcc(g++), clang, visualc++, por solo mencionar los compiladores más populares. Resulta que la “inercia” por lo que conocemos en ocaciones es muy fuerte y hace que nos estanquemos mientras la tecnología avanza. Yo concidero que un ingeniero no se debe medir tanto por lo que sabe como por lo que está dispuesto a aprender, una empresa que contrate un desarrollador o ingeniero en general que no esté dispusto a seguir los avances estaría adquiriendo un recurso humano que rapidamente quedaría sin soporte, es mejor tener un desarrollador LTS(Longer Time Support, :-P que se adapta a los cambios tecnológicos al pasar el tiempo).

Para ver un ejemplo de comparación del rendimiento(performace) del nuevo c++(c++11) en comparación con el antiguo(2003 que fue una revisión/corrección del c++ iso 1998) consideremos el siguiente ejemplo.
std::vector<int> getInts()
{
std::vector<int> ints;
for(int i =0; I <=10000000; i++) ints.push_back(i);
return ints;
}
Como podemos ver aquí se está creando un vector de enteros en un ámbito más reducido al que probablemente usará el valor de retorno, en este caso una vez que se tenga en memoria este vector al retornarlo se llama al constructor de copia para copiar uno por uno los elementos del vector para retornar esta copia y eliminar(de forma automática) de la memoria el creado originalmente, como te podrás dar cuenta tiene poco sentido esto de que teniendo los datos en meoria se cree una copia, se elimine el original y el copiado sea el que se use por el simple hecho de salirse del ámbito(el ámbito es la definición del espacio de vida de un objeto que puede ser global, de espacio de nombre, de clase, de función, de bloque, etc). Pués bien c++11 provee algunas soluciones a esto, una de ellas es la utilización de el contructor move que en vez de hacer una copia lo que hace es mover la dirección de memoria del dato en cuestión y entregarsela al ámbito que hizo el pedido.
Otra forma de resolver este problema hubiese sido usando un puntero reservando memoria para él de forma dinámica y retornando su dirección de memoria, esto en realidad es una solución implementable pero a la vez es un antipatrón ya que va en contra del principio de RAII (‘‘Resource Acquisition Is Initialization’’), o sea si la memoria se crea en este ámbito quién debería ser el responsable de eliminarla para mantener este esquema... pués c++11 también provee una solución elegante desde esta perpectiva y es con el uso de shared_ptr lo que crea un objeto de propiedad compartida que devolverá la memoria reclamada en cuanto el último de sus propietarios lo haga sin tener que llamar de forma explícita a delete.

Otro ejemplo es al usar regex(nuevo), si quieres representar una expresión que incluya algún slash invertido o comilla doble este debe ser precedido por un backslash(es a lo que se le llama escapar la cadena). Por ejemplo al representar lo siguiente:
string s = "\\w\\\\w"; // I hope I got that right
podemos darnos cuenta que esto es propenso a errore, para ello el nuevo c++(c++11) provee raw string literals en el cual un backslash es un backslash!!!, ej:
string s = R"(\w\\w)"; // I’m pretty sure I got that right

Otro ejemplo que me gustaría comentar, auto y range-for:
La palabra auto ha cambiado el significado de las antiguas versiones donde la había heredado de C, antes significaba que la variable era autodestruible, o sea escribir auto int era equivalente a int esto indicaba que el objeto llamaba a su destructor de forma automática al salirse del ámbito, ahora indica detecció de tipo desde el inicializador con lo cual podriamos por ejemplo escribir:
template<class T> void f1(vector<T>& arg)
{
for (vector<T>::iterator p = arg.begin(); p!=arg.end(); ++p) *p = 7;
for (auto p = arg.begin(); p!=arg.end(); ++p) ∗p = 7;
}
los cuales serían equivalentes y por su puesto el segundo más elegante que el primero.

El range-for te permite recorrer un contenedor de forma muy sencilla, tal como sigue:
void print_book(const vector<Entry>& book)
{
for (const auto& x : book) cout << x << '\n';
}
esto no se explica, solo se mira y el código habla por si solo, además comentar que para tener un contenedor propio capaz de usar esta cualidad solo hay que implemntar el begin y el end del contenedor.

Como último ejemplo las expresiones lambda o funciones lambda (simplemente lambda como también se les suele llamar). Lambda es una notación simplificada para definir y utilizar objetos o instancias de funciones anónimas. Esto es particularmente útil cuando pasas una operación como argumento a un algorimo, aquí puedes ver un ejemplo:
template<class C>
void print_modulo(const C& v, ostream& os, int m)
// output v[i] to os if v[i]%m==0
{
breadth_first(begin(v),end(v),
[&os,m](int x) { if (x%m==0) os << x << '\n'; }
);
}
Un ejemplo de la utilidad de esto lo puedes ver al usar signal/slog(un concepto de Qt framework).

Como podrás saber es imposible tratar en un simple post sobre todas estas nuevas características por lo que te dejo en manos de Stroustrup:
Here are what I consider the most widely useful new ‘‘building bricks’’ affecting the style of
C++11 code with references to the text and their primary authors:
Control of defaults: =delete and =default: §3.3.4, §17.6.1, §17.6.4; Lawrence Crowl and
Bjarne Stroustrup.
Deducing the type of an object from its initializer, auto: §2.2.2, §6.3.6.1; Bjarne Stroustrup.
I first designed and implemented auto in 1983 but had to remove it because of C compatibil-
ity problems.
Generalized constant expression evaluation (including literal types), constexpr: §2.2.3,
§10.4, §12.1.6; Gabriel Dos Reis and Bjarne Stroustrup [DosReis,2010].
In-class member initializers: §17.4.4; Michael Spertus and Bill Seymour.
Inheriting constructors: §20.3.5.1; Bjarne Stroustrup, Michael Wong, and Michel Michaud.
Lambda expressions, a way of implicitly defining function objects at the point of their use in
an expression: §3.4.3, §11.4; Jaakko Jarvi.
Move semantics, a way of transmitting information without copying: §3.3.2, §17.5.2;
Howard Hinnant.
A way of stating that a function may not throw exceptions noexcept: §13.5.1.1; David Abra-
hams, Rani Sharoni, and Doug Gregor.
A proper name for the null pointer, §7.2.2; Herb Sutter and Bjarne Stroustrup.
The range-for statement: §2.2.5, §9.5.1; Thorsten Ottosen and Bjarne Stroustrup.
Override controls: final and override: §20.3.4. Alisdair Meredith, Chris Uzdavinis, and Ville
Voutilainen.
Type aliases, a mechanism for providing an alias for a type or a template. In particular, a
way of defining a template by binding some arguments of another template: §3.4.5, §23.6;
Bjarne Stroustrup and Gabriel Dos Reis.
Typed and scoped enumerations: enum class: §8.4.1; David E. Miller, Herb Sutter, and
Bjarne Stroustrup.
Universal and uniform initialization (including arbitrary-length initializer lists and protec-
tion against narrowing): §2.2.2, §3.2.1.3, §6.3.5, §17.3.1, §17.3.4; Bjarne Stroustrup and
Gabriel Dos Reis.
Variadic templates, a mechanism for passing an arbitrary number of arguments of arbitrary
types to a template: §3.4.4, §28.6; Doug Gregor and Jaakko Jarvi.


Para ver un pequeño ejemplo de c++11 en acción revisa:

viernes, 21 de febrero de 2014

¿Por qué deberiamos migrar nuestro código a Qt5?

Con un tiempo ya de liberada la versión 5 del framework Qt existen proyectos y personas que aún no actualizan su código a la nueva versión(para garantisar soporte prolongado de las dependencias). Cuando salió Qt4 trajo con sigo grandes cambios en la API con respecto a Qt3 haciendo que la actualización a Qt4 del software escrito en Qt3 fuese una tarea relmente difícil, era casi como reescribir el programa. Por el contrario de lo que occurrió con Qt5 que ha mantenido armonía con la API de Qt4, la mayor parte de esta permanece idéntica, lo que hace que la transición de las aplicaciones basadas en Qt4 a Qt5 sea con menores dolores de cabeza de lo que fue alguna vez entre otras versiones.
En Qt5, QML se ha puesto en el punto de mira del proyecto, es uno de los módulos más importantes que por supuesto usa al resto, pero esta es casi la presentación, la portada, lo que ve el usuario. A su vez el cambiar a Qt/C++ por Qt/Quick no es del todo positivo, mejor dicho no es que no sea positivo, es que si alquien escoje C++ teniendo como primer medidor el performace realmente no creo que Qt/Quick se le pueda comparar, en este sentido lo que se suele hacer es crear interfaces modernas y vistosas (look-and-feel) usando QML que pueden tener un potente lógica por detrás escrita en C++ y vinculada al código javascrip sin una mayor cantidad de esfuerso.
He estado escribiendo esto porque por un lado ves a algunos proyecto muy bien plantados con Qt4 tratando de migrar a Qt5 mientras que por otro lado vemos a algunos que están naciendo y tienen planificado el uso de Qt4.*, pues esto es algo sobre lo que devemos reflexionar, como mismo hasta aquí escribía refiriendome a que el “nuevo” Qt no trae tantos cambios entonces por qué deberiamos migrar?, aquí dejo algo de lo nuevo:
1. Ahora las Qwidgets  son un módulo aparte, pues existe una clase Qwindows de la cual heredan todas las ventanas, esto se implementó para permitir que QML pudiera tomar el control visual de las ventanas principales sin depender de Qwidget .
2. El procedimiento de creación de plugins se ha cambiado por completo(para bien, aunque debido a este cambio los modulos y plugins diseñados con Qt4 no son compatibles con los de la nueva versión).
3. Ahora connect en vez de  retornar un bool, retorna un QmetaObject::Connection .
4. C++11 viene con soporte de funciones lambda y Qt5 le añade soporte a las conecciones para  estas funciones .
5. Módulo de puerto serie incluido (Qt5.1).
6. QWS no forma parte de Qt5, desde la versión 4.8 se introdujo QPA, con eso puedes ir portando desde Qt4, en Qt5 QPA pasó a ser la parte central de Qt dejando atrás a QWS que tenía algunos problemas arquitectónicos.
7. Para usar c++11 puedes poner CONFIG += c++11  en el *.pro y basta.

Como podrás ver esta lista no es(ni pretende) exaustiva así que si quieres una lista completa de los cambios por release puedes consultar URLs como las que siguen:
5.1
5.2
5.3
Qt 5 Supported Platforms

Para ver un ejemplo de uso de Qt5 y c++11 revisa:

miércoles, 20 de noviembre de 2013

Autotools (3): Integración de libtool en autotools para la creación de una biblioteca a instalar en el sistema.

En otros post anteriores vimos la escencia de las bibliotecas así como de libtool, si además haz realizado aunque sea un “hello world” con autotools entonces ahora veamos como integramos a libtool con autotool para la creación de una biblioteca.

#configure.ac
LT_INIT: Es la forma en que actualmente se define LIBTOOL.

# Checks for programs.
AC_PROG_CXX: Chequea por un compilador para c++.
AC_PROG_AWK: Chequea gawk, mawk, nawk, and awk, en ese orden y lo establece como variable.
AC_PROG_CC: Chequea por un compilador para c.
AC_PROG_CPP: Muetra el valor de la variable CPP que contiene el preprocesador.
AC_PROG_INSTALL: Muetra el valor de la variable INSTALL para instalación.
AC_PROG_LN_S: Chequea que ls sistema en que te encuentras soporta links simbólicos(ln -s), en caso que este no esté disponible lo establece a ln, en otro caso a cp -pR.
AC_PROG_MAKE_SET: Establece el comando make.

#lib/Makefile.am:
CLEANFILES: Para que make clean borre los archivos que coincidan.

AM_CPPFLAGS: El contenido de esta variable es pasado a todas las reglas de compilación que invoquen el preprocesador de C.

Definiciones para el uso de pkg-config una vez creada la lib.
pkgconfigdir = @libdir@/pkgconfig
pkgconfig_DATA = libmatX.pc

A diferencia del primer ejemplo donde poniamos bin_PROGRMAS para crear ejecutables aquí usamos esta macro a la cual le decimo el nombre de la lib a crear y en el source debe transformar el nombre a su forma canónica.
lib_LTLIBRARIES = libmatX.la
libmatX_la_SOURCES = \
matX.cc

libmatX_la_LDFLAGS: Flags para el elnlazador.


“#Headers/Makefie.am
includedir: Referencia al directorio include donde se pondran los headers
nobase_include_HEADERS: Para que no se instale dos veces con una invocación del programa.
Una vez configurado el proyecto procedemos a la contrucción:
1. mkdir -p m4
2. libtoolize --copy –force
3. aclocal -I m4
4. autoheader
5. autoconf
6. automake -a
7. ./configure
.8 make
Ya podrás ver que se ha creado lib/libmatX.la, incluso lo podrías leer(cat lib/libmatX.la) ya que es texto plano, en este punto la biblioteca ya es usable, esto sería en nuestro progrma usar la macro LDADD (tambien con el nombre del ejecutable como prefijo y con _ al final) para esto puedes consultar GNU Automake aunque este ejemplo cuneta con su *.pc.
9. sudo make install
Ya deberías poder verificar como instalada la biblioteca en tu sistema
10. pkg-config --list-all | grep hello_libtool

Ya teniendo esta infraestructura básica del proyecto veamos como crear las bibliotecas estática y dinámica correspondiente.

Biblioteca estática:
make clean
./configure --disable-shared
make
Biblioteca dinámica:
make clean
./configure --disable-static
make

NOTA: En caso de no especificar se crea la dinámica y la estática.

Desde aquí puedes descargar el ejemplo:

git clone https://github.com/denisacostaq/EmbeLinux --branch hello-libtool

martes, 19 de noviembre de 2013

Creación de bibliotecas mediante el uso de libtool (Parte 2).

Si ya revisaste el post anterior sobre construcción de bibliotecas podremos proseguir con el hecho de que ya tenemos algunos conceptos básicos de nuestro lado, esta vez relizaremos el mismo ejemplo lo que cambia es las herramientas. Primero construiremos la lib estática, después compartida y por último de ejecución (que no es más que la misma biblioteca compartida lo que se carga en tiempo de ejecución).

Libtool:
Según su propia documentación (apt-get install libtool-doc) fue diseñado desde sus inicios para soportar un número arbitrario de tipos de bibliotecas, más tarde se ha ido portando a otras plataformas y gradualmente se han ido desarrollando nuevos paradigmas que describen la relación entre las bibliotecas y los programas.

Consideremos el sigiente código con el cual crearemos la biblioteca estática y compartida:
//module.c
float mult (float fac1, float fac2)
{
return fac1 * fac2;
}

Biblioteca estática:
1. Creamos un directorio donde “instalaremos” la lib.
mkdir -p /tmp/install
2. Compiamos el código.
libtool --verbose --mode=compile gcc -g -O -c module.c -static
3. Enlazamos el código, si no ponemos -rpath /tmp/install al comando anterior tendremos que ejecutar
libtool --finish /usr/local/lib después para que se complete la instalación correctamente.
libtool --verbose --mode=link gcc -module -o module.la module.lo -rpath /tmp/install -static
4. Instalamos
libtool --mode=install install module.la /tmp/install
Ya tenemos lista la lib en /tmp/install que puedes usar como en el post anteriorque mencionaba al inicio y además notar que se encuentra en el direcorio oculto (ls .libs/).

Biblioteca dinámica:
Recomendable eliminar los archivos anteriores para ver el nuevo resultado y repitiendo los pasos para este caso tenemos:
1. mkdir -p /tmp/install
2. libtool --verbose --mode=compile gcc -g -O -c module.c -shared
3. libtool --verbose --mode=link gcc -module -o module.la module.lo -rpath /tmp/install -shared
4. libtool --mode=install install module.la /tmp/install

Biblioteca de ejecución:

Para ver como usamos una lib en tiempo de ejecución usaremos el siguiente código:

#include <stdio.h>
#include <ltdl.h>
#include <stdlib.h>

//declaramos una variable(puntero a la función así que
//debe coincidir en los tipos)
float (*mult)(float fac1, float fac2);

int main (int argc, char *argv[])
{
lt_dlhandle handle;
lt_dlinit ();
lt_dladdsearchdir ("./");

handle=lt_dlopenext ("module");
if (!handle)
{
printf ("Error, módulo no cargado: %s\n",
                   lt_dlerror());
exit (EXIT_FAILURE);
}

const lt_dlinfo *info;
info = lt_dlgetinfo (handle);
if (!info)
{
fprintf (stderr, "No se pudo obtener la información  del módulo: %s\n", lt_dlerror());
lt_dlclose (handle);
exit (EXIT_FAILURE);
}
if (info->name)
{
printf ("Nombre del módulo: %s\n", info->name);
}
else
{
printf ("No es un módulo libtool\n");
}
//casteo al tipo de la función
mult = (float(*)(float, float))lt_dlsym(handle, "mult");  
if (mult)
{
printf ("Resultado desde el módulo: %f\n", mult(5.0, 10.0));
}
else
{
perror ("No se pudo cargar la función\n");
lt_dlclose (handle);
exit (EXIT_FAILURE);
}
lt_dlclose (handle);
return 0;
}


Recomendable eliminar los archivos anteriores para ver el nuevo resultado y repitiendo los pasos para este caso tenemos:
1. libtool --verbose --mode=compile gcc -g -O -c module.c -shared
2. libtool --verbose --mode=link gcc -module -o module.la module.lo -rpath /tmp/install -shared
3. libtool --mode=link gcc -export-dynamic -o programdl program.c -lltdl

Un detalle importante es notar que la lib se contruye de la misma manera que la compartida, el programa es el que se contruye de forma diferente a la convencional y además con ldd como en el post anterior puedes ver como program no depende de module por lo que los pasos 2 y 3 se pueden cambiar de orden ya que program no necesita saber nada acerca de module en tiempo de compilación.
NOTA: Para tener más referencia consulte man libtool o /usr-sha-doc-libtool-doc.

jueves, 14 de noviembre de 2013

Implementando mi propio shell usando una gramática LL1.

Lo primero que veremos, qué es un shell; después, qué es una gramática, cuando una gramática se clasifica como LL1 (y si no lo es como llevarla) y por último veremos una pequeña implementación en C de un shell.
Shell: Shell (del inglés cascarón, coraza, concha, etc) toma este nombre por ser el shell una interfáz entre el nucleo del Sistema Operativo y el usuario, es un intérprete a través del cual este le da órdenes(ver Fig 1).

Fig 1.


El shell es un programa capaz de interpretar comandos, hacer una petición al sistema y devolver un resultado. Exixsten varias implementaciones: sh, bash, csh, Tcsh, …, etc... Cada usuario tiene una shell predeterminada ej: adacosta:x:1008:1008:PEPSI,,,:/home/adacosta:/bin/bash el cual es ejcutado al autenticarse el usuario en una terminal, o al abrir una emulador de terminal en una sesión X11, lo primero que hace el shell es leer sus configuración de sistema (/etc) y después leer la configuración del usuario (/home/user-name/.*) pudiendo llegar a ser uno o varios archivos, en mi caso:
( /home/adacosta/.bashrc, /home/adacosta/.profile /home/adacosta/.bash_*)

Gramática: Intuitivamente, una gramática es un conjunto de reglas para formar correctamente las frases de un lenguaje; así ́ tenemos la gramática del español, del francés, etc. Según N. Chomsky existen 4 tipos fundamentales de gramáticas:


1. Gramáticas regulares, o de tipo 3: Las reglas son de la forma A → α B o bien A → α, donde A y B son variables (no terminales) y α es una constante (terminal). Estas gramáticas son capaces de describir los lenguajes regulares.
́
2. Gramáticas Libres de Contexto (GLC), o de tipo 2: Las reglas son de la forma X → α, donde X es una variable y α es una cadena que puede contener variables y constantes. Estas gramáticas producen los lenguajes Libres de Contexto.
́
3. Gramáticas sensitivas al contexto (dependientes del contexto) o de tipo 1: Las reglas son de la forma αAβ → αΓβ, donde A es una variable y α, β y Γ son cadenas cualesquiera que pueden contener variables y constantes.
4. Gramáticas no restringidas, o de tipo 0: Con reglas de la forma α → β, donde α no a puede ser vacío, que generan los lenguajes llamados “recursivamente enumerables”.

Los objetivos de una gramática son: definir las sentencias que pertenece a un lenguaje, así como describir estructuralmente dichas sentencias. Las gramáticas generan sentencias mediante secuencias de derivaciónes directas




Como ejemplo veamos una gramática subconjunto del idioma español:
G = ( {<frase>, <sujeto>, <predicado>, <artículo>, <sustantivo>, <verbo>},
{el, la, perro, luna, brilla, corre}, P, <frase>)
P:
<frase> → <sujeto> <predicado>
<sujeto> → <artículo> <sustantivo>
<artículo> → el | la
<sustantivo> → perro | luna
<predicado> → <verbo>
<verbo> → brilla | corre

En correspondencia con esta gramática podriamos generar frases como las que siguen.
{el perro corre , el perro brilla, la perro brilla, ...} estando todas ellas correctas sintácticamente aunque haciendo un análisis semántico (en otra etapa) podriamos detectar que algunas de las frases carecen de sentido.

Gramáticas LL1:
Un analizador LL es llamado un analizador LL (k) si usa k tokens cuando el analizador ve hacia delante de la sentencia. Si existe tal analizador para cierta gramática y puede analizar sentencias de esta gramática sin marcha atrás, entonces es llamada una gramática LL (k). De estas gramáticas, la gramática LL(1), aunque es bastante restrictiva, esta es muy popular (principalmente en actividades docentes) porque los analizadores LL correspondientes sólo necesitan ver el siguiente token para hacer el análisis de sus decisiones. Lenguajes mal diseñados usualmente suelen tener gramáticas con un alto nivel de k, y requieren un esfuerzo considerable al analizar.

Una gramática ambigua es aquella que produce más de una derivación más a la izquierda o más de una derivación más a la derecha para la misma sentencia. En general existen tres estrategias iniciales para eliminar la ambiguedad de las gramáticas, ellas son:
1. Definir la precedencia y asociatividad de los operadores.
2. Eliminar la recursividad izquierda o derecha.
3. Factorizar.
Veamos un ejemplo:
G = ({<Expresión>}, {id, +, - , *, / , (, )}, P, <Expresión>)
P:
(1) <Expresión> → <Expresión> + <Expresión> | <Expresión> - <Expresión>
(2) <Expresión> → <Expresión> * <Expresión> | <Expresión> / <Expresión>
(3) <Expresión> → id | ( <Expresión> )
Precedencia y asociatividad:
Definamos un nivel de prioridad para cada operador como sigue:
1. (), id
2. *, /
3. +, -
Nivel 1 Se introduce un nuevo símbolo No Terminal, que llamaremos <Factor> para describir una expresión indivisible y con máxima precedencia.
<Factor> → id | ( <Expresión> ) .
Nivel 2 Se introduce un nuevo símbolo No Terminal, que llamaremos <Término>, que generará una secuencia de uno o más términos generados por el No Terminal <Factor>, conectados con los operadores de nivel precedencia 2.
<Término> → <Término> * <Factor> | <Término> / <Factor> | <Factor>
Nivel 3 Se mantiene el símbolo No Terminal <Expresión> para describir secuencias de uno o más términos generados por el No Terminal <Término>, conectados con los operadores de nivel precedencia 3.
<Expresión> → <Expresión> + <Término> | <Expresión> - <Término> | <Término>
Aplicando las reglas anteriores la gramática definida anteriormente queda re definida como sigue:
G = ({<Expresión>, <Término>, <Factor>}, {id, +, - , *, / , (, )}, P, <Expresión>)
P:
<Expresión> → <Expresión> + <Término> | <Expresión> - <Término> | <Término>
<Término> → <Término> * <Factor> | <Término> / <Factor> | <Factor>
<Factor> → id | ( <Expresión> )

Recursividad Izquierda :
Una producción de la forma A → Aβ se dice que es recursiva inmediata. Para eliminar las recursividades inmediatas podemos seguir el procedimiento siguiente:
1. Se agrupan las A-producciones:
A→ Aα1 | Aα2 | . . .| Aαm | β1 | β2 . . .| βn
donde ningún βi comienza con A.
2. Se reemplazan las A-producciones por:
A→ β1 A’| β2 A’| . . .| βn A’
A’→ α1 A’| α2 A’| . . .| αm A’| ǫ
Aplicamos el procedimiento anterior para eliminar la recursividad directa en la gramática:
G = ({<Expresión>, <Término>, <Factor>}, {id, +, - , *, / , (, )}, P, <Expresión>)
P:
<Expresión> → <Expresión> + <Término> | <Expresión> - <Término> | <Término>
<Término> → <Término> * <Factor> | <Término> / <Factor> | <Factor>
<Factor> → id | ( <Expresión> )

Para ellos seleccionamos las reglas que son recursivas directa a la izquierda estas son:
(I) <Expresión> → <Expresión> + <Término> | <Expresión> - <Término> | <Término>
(II) <Término> → <Término> * <Factor> | <Término> / <Factor> | <Factor>

Aplicando la regla para la eliminación de ambiguedad 2 sobre (I) y (II) nos queda:

<Expresión> → <Término> <MasExpresión>
<MasExpresión> → + <Término> <MasExpresión> | - <Término> <MasExpresión> | E

<Término> → <Factor> <MasTérmino>
<MasTérmino> → * <Factor> <MasTérmino> | / <Factor> <MasTérmino> | E


Factorización por la izquierda.
La Factorización por la izquierda tiene el objetivo de reescribir las producciones de la gramática con igual comienzo para retrasar la decisión hasta haber visto lo suficiente de la entrada como para elegir la opción correcta. El procedimiento es simple. Si tenemos una regla de producción de la forma:
́ A → αβ1 | αβ2 | . . . | αβn | δi
esta se transforma en las regla.
A → α A′ | δi
A ′ → β1 | . . . | βn

A manera de ejemplo consideremos la regla de producción siguiente:
<Instruciones > → <Instrucción> ; <Instruciones > | <Instrución>

Aplicando la Factorización por la izquierda nos quedan las reglas equivalentes:

<Instruciones > → <Instrucción> <MasInstrucciones >
<MasInstrucciones > → ; <Instruciones > | E

A modo de conclusión podemos decir que las gramáticas constituyen la mejor vía para la descripción sintáctica de los lenguajes de programación. Existen diversas razones que justifican tal afirmación:
Las gramáticas brindan una especificacion sintáctica precisa de los lenguajes de programación.

Para ciertas clases de gramáticas pueden construirse analizadores sintácticos eficientes que determinan si el programa fuente está bien escrito. El proceso de construcción del parser puede además, revelar ambiguedades sintácticas no detectadas en la fase de diseño del lenguaje .

Una gramática bien diseñada puede ayudar a la traducción del programa fuente en código objeto y a la detección de errores.

Se pueden añadir nuevas construcciones al lenguaje de forma fácil.



Un ejemplo de implementación:
Un ejemplo de implementación de un intérprete basado en un gramática LL1 lo puede tomar clonando denishell(git clone https://github.com/denisacostaq/denishell), toda la documentación relevante forma parte del código fuente y/o de la documentación(valga la redundancia) generada con doxygen, en especial fijarse en el comando cd, en la manera que se “simula” la implementació de un pipe (char** run_pipe_on_node (struct ast_node *ast);), en la pesatña examples de dicha documentación puedes aprender cómo comunicar dos procesos con un pipe real, y además puedes ver algunos de los comandos a ejecutar, tambié revisar char** cat_args(); y char** ls_args (); para tener detalles sobre la internacionalización (deni-sh_i18n.h).