DevelUY

Planeta de desarrolladores uruguayos

26 de enero de 2012

Bruno Buzzi

Ventajas de la Reflexión en Programación – Meta-programación Simple

Sistema

Se está construyendo un sistema el cual debido a su naturaleza fuera de lo común tiene cerca de 200 métodos que devuelven un String simplemente.

En la siguiente imagen se muestra 1 de estos métodos, como el sistema está relacionado con el PMI, el texto que se muestra es copyright  © de PMI.org.

Problema

Por cada uno de estos 200 métodos hay que crear otro método derivado que replique un mismo patrón, por lo hay que crear 200 nuevos métodos. Es un trabajo que tedioso que lleva tiempo y es propenso a errores.  Aquí es donde nos “salva” la REFLEXIÓN y la META PROGRAMACIÓN, en este caso es bastante sencilla.

Como quedaría el método luego de aplicar el patrón a mano:

Habría que aplicar el mismo patrón para otros 199 metodos y así sucesivamente. Con este nuevo método #changeRequestsNew tendría una instancia con la descripción que devuelve el método original (#changeRequests) que es solamente texto, que es justamente lo que quiero para este método y el resto.

Patrón

1. nombreNuevoMetodo := Nombre del método actual  + ‘New’. En este caso: changeRequests‘New’ = changeRequestsNew

2. El argumento que se pasa al mensaje #name:  debe ser el nombre del método actual, pero separado por un espacio y cada palabra en mayúsculas.  En este caso es:

name: ‘Change Requests’ - recordar el nombre del método actual (self) es #changeRequests

3. El argumento que se pasa al mensaje #description:  debe  ser una llamada al método actual que devuelve un String. En este caso es:

description: self changeRequests. – la descripción queda con el String del método original.

Este patrón debe aplicarse a 199 métodos más…

Solución

La solución me tomo unos 5 minutos ! y consiste en implementar un método en la clase CompiledMethod. En Smalltalk cada vez que creo un método se crea una instancia de esta clase CompiledMethod, y esta clase es editable y modificable como cualquier otra.

La variable [selector] del método actual (#changeRequests) se concatena con ‘New‘ para formar el selector (nombre) del nuevo método a ser creado.  Este nombre se almacena en la variable temporal [newSelector] como un símbolo #asSymbol (es una clase especial de String).

Ahora en la variable temporal [pmpName] formo el nombre según las reglas. La primera letra la paso a mayúscula (first asUppercase asString) y luego proceso el resto.

Ahora proceso todo menos la primera letra (c) [hangeRequests]. Si esta en minúscula copio y si esta en mayúscula agrego un espacio en blanco y copio. Guardo el resultado de la iteración en la temporal [pmpName].

Ahora creo un template para compilar el método en la variable [newMethod]. Uso el nombre del nuevo método y uso el selector actual (nombre actual) para crear la llamada (description: self’, selector,). Y por último compilo el template [newMethod] en la clase del método actual (methodClass compile: newMethod).

Ahora solamente cada vez que quiero crear uno de estos 200 métodos simplemente le envio el mensaje #compileMethodStringForPMPNewDocument y me crea el derivado.

En un principio pensé hacer esto con el Code Rewriter pero después opte por implementar un método en CompiledMethod.

El Code Rewriter es una herramienta muy poderosa que sirve para hacer transformaciones masivas de código de forma segura, basicamente suplante un AST por otro AST equivalente (mismo comportamiento) pero más óptimo.


por smalltalkuy, el 26 de enero de 2012 a las 14:14

Alejandro Segovia

Vortex adds Render-to-Texture capabilities

I’m very glad to announce Vortex now support render-to-texture capabilities by means of Framebuffer Objects : )

Vortex Render-to-Texture support: a knight is rendered on a texture that is then mapped on a cube. All rendering is done on the GPU, avoiding expensive copies to RAM.

por Alex, el 26 de enero de 2012 a las 12:14

Fernando Briano

¿Y si juntamos a la comunidad de usuarios ArchLinux del Uruguay?

ArchLinux

ArchLinux

Lo que dice el título, ¿y si juntamos un grupo de usuarios ArchLinux en un mismo espacio física esporádicamente y nos unimos a trabajar con algun(os) objetivo(s) en común?

En un principio pensé que la mejor forma de convocar a los usuarios a unirse en grupo era crear una lista de correo, un blog, o algo así. Pero eso son solo herramientas, preferí empezar sin mucha ambición con este post (gracias al principio de KISS). Los invito a dejar un comentario si quieren sumarse a la iniciativa. Hay que ver si hay más interesados, y después entre los que seamos vemos qué se arma :)

Se me ocurren varias razones de por qué esto es una buena idea. Una buena parte de lo positivo de ir a una reunión de personas técnicas (hackatón, conferencias y demás) es conocer a otras personas con los mismo intereses. Ni que hablar que las charlas suelen ser bastante interesantes. Si nos entretenemos leyéndonos por foros, redes sociales y blogs, mejor la vamos a pasar conversando mientras tomamos alguna cerveza y comemos alguna pizza.

A continuación listo algunos objetivos/ideas/razones más que me vienen en la cabeza sin caer en nada muy ambicioso.

  • Aprender a empaquetar aplicaciones y buscar alguna aplicación que podríamos enviar a AUR. Es un conocimiento que viene bien, y seguramente todos han toqueteado algún PKGBUILD en algún momento. De repente sale algo interesante.
  • Ayudar con la traducción de la wiki, si alguien tiene algo de tiempo libre para aportar al proyecto, esta es una buena manera. (más ideas acá)
  • Dar a conocer cosas interesantes que hayamos logrado, scripts, personalizaciones, etc. Ayudar con algún problema particular que algun usuario pueda tener con el sistema.
  • “Evangelizar” a usuarios de otras distros, ayudarles a darse cuenta que ArchLinux es la mejor distribución de GNU/Linux :P
  • Comprar camisetas de ArchLinux. Al ser muchos, podemos conseguir un buen precio para mandar a hacer camisetas de Arch.
  • DRY: No repetirnos. No hay que reinventar la rueda, crear más wikis y demás información repetida. Creo que si en algún momento armamos alguna representación virtual del grupo en internet, habría que limitarse al tema de las reuniones y demás posibles organizaciones que podamos llevar a cabo. Nada de reescribir o copiar y pegar todo el conocimiento que tan bien documentado está en la wiki de Arch.

Si hay convocatoria, coordinamos una fecha y me comprometo a conseguir un lugar para reunirnos por primera vez y ver qué sale. No hay mucha idea o compromiso, simplemente juntarse a ver qué sale.

Para finalizar el post, los dejo con un texto de la wiki:

En Biología, mutualismo es una interacción entre dos organismos en que ambos organismos obtienen beneficio. Este principio puede también ser aplicado a miembros proactivos y motivados de la comunidad de ARCH que quieren estar involucrados y contribuir a su distribución favorita GNU/Linux. Esta participación beneficia no solo a los miembros de la comunidad y sus compañeros Arches, pero también a todos los fans potenciales de Software libre y de codigo abierto

por Fernando, el 26 de enero de 2012 a las 12:00

Alejandro Segovia

Stencil Shadow Volumes

I’ve built Stencil Shadow Volumes into the Vortex Engine.

Shadows are a very interesting feature to implement in an renderer, as they provide important visual cues that help depict the relationship between objects in a scene. Notice in the following image how the shadow tells our brains that the Knight is standing on the floor (as opposed to hovering over it).

A Knight, lit by a green light, casts a shadow on a tiled floor.

The implementation is at this point no more than a prototype and requires significant more testing, however, since the visual results are very appealing, I wanted to share some of the images.

I personally have a bias towards using Shadows Volumes instead of Shadow Maps; I think the former algoritm leaves out much of the guesswork that Shadow Maps require. Furthermore, Shadow Volumes are not subject to some of the limitations of Shadow Maps, such as the map’s resolution.

Another point for Shadow Volumes is the fact that they provide a natural way to implement “soft shadows”: shadows that are not completely black but rather transparent. The following image corresponds to the same scene but with two minor changes: the light has been changed to white and the floor texture is different. Notice how we can see the floor texture englobed in the Knight’s translucent shadow.

The same knight, lit by a white light this time, casts a soft shadow on an industrial floor. Notice the shadow "translucency".

I hope we can have Shadow Volumes available for both rendering pipelines as part of Vortex 2.0.

Edit: Thanks to Gabriel G. for noting the term “soft shadows” was being used incorrectly.

por Alex, el 26 de enero de 2012 a las 11:47

25 de enero de 2012

Fernando Briano

Disponible Oil Rush 1.00 :)

Oil Rush

Oil Rush

El excelente juego de estrategia naval en tiempo real Oil Rush (clic en el enlace para leer mi reseña) está disponible en su versión 1.00. Aquellos que lo preordenamos lo podemos descargar ya desde Unigine Online Store.

Se está trabajando en versiones para Steam, Desura y Ubuntu Software. Éstas estarán disponibles en uno o dos días.

La versión 1.00 nos trae el tan esperado modo de campaña para un jugador. Pre ordené el juego en marzo del año pasado, y desde entonces he ido viendo cómo evoluciona poco a poco con cada nueva versión. Ahora me toca el turno de hacer la campaña y ver qué han estado preparando los desarrolladores para nosotros…

Es un juego bastante importante en lo que respecta al mundillo de videojuegos en plataformas GNU/Linux. Fue construido sobre el motor Unigine que da la oportunidad de realizar unos gráficos 3D impresionantes, corriendo de forma nativa en nuestro querido sistema.

Con suerte el juego tenga éxito, así lo espero. Esto abriría más el mercado de videojuegos en GNU/Linux, dándole la publicidad necesaria a su motor para que otras compañías lo tengan en cuenta a la hora de desarrollar sus juegos.

Ya estoy descargando esta nueva versión, y más tarde tendré la oportunidad de probarlo. Ahí les contaré qué me pareció. Mientras les dejo algunas fotos de versiones anteriores para que se hagan una idea de los excelentes gráficos del juego:

Oil Rush 0.66

Oil Rush 0.82

 

por Fernando, el 25 de enero de 2012 a las 12:30

23 de enero de 2012

Dario Clavijo

Wolrd ipv6 launch day

IP version 6 es la nueva versión del protocolo de direccionamiento de Internet.
El 6 de junio del corriente año se celebrara una puesta en marcha masiva de servicios que actualmente ya estaban en IP version 4.
Los nuevos servicios serán Facebook, Google(actualmente se puede acceder a través de http://ipv6.google.com) y varios ISP entre otros...  que

Para mas info pueden visitar: http://www.worldipv6launch.org

A nivel de cliente si quieren tener conectividad ipv6 pueden seguir estas guías Como configurar Túnel IPv6 tspc en Linux Debian / Ubuntu o Configurando Router IPv6

por Daedalus (noreply@blogger.com), el 23 de enero de 2012 a las 11:57

22 de enero de 2012

Alejandro Segovia

Implementing sqrt

I was reading some post about interview questions of 2011 and came across one that stated “find the square root of a number”.

Assuming we can’t use the sqrtf function of the standard C math library, let’s see how we can calculate the square root of a number x.

Given n, we know that its square root is a number x that holds:

\sqrt{n} = x

Let’s work on this equation a little. Raise both sides to the second power:

n = x^2

Move to the left of the equality:

0 = x^2 - n

If we found the roots of this last equation somehow, we would have found the square root of n. We can do this by using the Newton-Raphson iteration.

The Newton-Raphson iteration states that we can find the root of an equation using the following formula iteratively:

x_{n+1} = x_n - \frac{f(x)}{f'(x)}

Where f’(x) is the derivative of function f(x). We will approximate the derivative using the definition of derivative at a point (we could also note that the derivative could be trivially calculated; this method is more general).

f'(x) = \frac{f(x+h) - f(x)}{h}

The error of the Newton-Raphson iteration is given by:

|x_{n+1} - x_n|

Starting with a hardcoded seed value, we will perform this iteration in a loop until the error is less than a given value. I have chosen to iterate until the error is less than 1×10^(-10): 0.00000000001.

Let us see what a tentative “pythonesque” pseudocode for this loop could be:

def sqrt(n):
    f = function(x*x - n)
    x = 1 # seed
    xant = 0
    do:
        f1 = (f.eval(x+h) - f.eval(x)) / h
        xant = x
        x = x - f.eval(x)/f1
    while abs(x - xant) > err;
    return x

Assuming we have a symbolic function type, that loop does not seem too difficult. In order to code this in C, since the equation is always the same, I will hardcode it as a plain function.

typedef double real; // change to float for single precision

real f(real x, real n)
{
    return x*x - n;
}

real sqrt(real n)
{
    real err = 0.00000000001f;
    real h = 0.01f;

    real x = 1.0f; // seed
    real xant = 0.0f;

    do
    {
        xant = x;
        real df = (f(x+h, n) - f(x, n))/h;
        x = x - f(x, n)/df;
    }
    while (abs(x - xant) > err);

    return x;
}

Here are the results of running our custom square root function, compared to the standard version provided with the C programming language:

[ale@syaoran sqrt]$ ./sqrt 1.0
Custom sqrt of: 1 = 1
libm sqrt of: 1 = 1

[ale@syaoran sqrt]$ ./sqrt 2.0
Custom sqrt of: 2 = 1.41421
libm sqrt of: 2 = 1.41421

[ale@syaoran sqrt]$ ./sqrt 4.0
Custom sqrt of: 4 = 2
libm sqrt of: 4 = 2

[ale@syaoran sqrt]$ ./sqrt 16.0
Custom sqrt of: 16 = 4
libm sqrt of: 16 = 4

[ale@syaoran sqrt]$ ./sqrt 32.0
Custom sqrt of: 32 = 5.65685
libm sqrt of: 32 = 5.65685

[ale@syaoran sqrt]$ ./sqrt 100.0
Custom sqrt of: 100 = 10
libm sqrt of: 100 = 10

[ale@syaoran sqrt]$ ./sqrt 1000000.0
Custom sqrt of: 1e+06 = 1000
libm sqrt of: 1e+06 = 1000

por Alex, el 22 de enero de 2012 a las 22:17

A short detour along the way…

I wanted to improve the Stencil Shadow Volumes code a little bit and enable it for the Programmable Pipeline in Vortex, however, I had to take a small detour to fix an issue related to mobile device support.

It turns out that OpenGL ES, the 3D library that Vortex uses to render its graphics on mobile devices, does not support rendering indexed geometry for indices larger than 16 bits. Keep this in mind when developing for mobile devices such as the iPhone or iPad.

I can completely understand the reasoning behind this decision. 32-bit indices could be considered too much data to submit to the GPU in a mobile device. Furthermore, they are not strictly necessary, as they could be replaced (if needed) by splitting the geometry into two groups defined by 16-bit indices.

The solution I devised, which is now part of Vortex 2.0, is to allow the user to specify the data size for the indices when defining the geometry. This provides the flexibility to use 32, 16 or 8 bit indices. You can even have several geometric objects with different index sizes in a scene.

The advantage of leveraging this mechanism is that now it is very easy to fine-tune the number of bytes used for index representation for improving performance. For example, using 16-bit indices instead of 32-bit indices would make no difference for representing models composed of less than 65536 vertices, while requiring a copy of just half the number of bytes to the GPU.

In the extreme case of 8-bit indices we would be constrained to only 256 vertices, but we would be sending only one fourth of the data to the GPU.

This was mostly plumbing work, so no new picture this time. Stay tuned for more updates!

por Alex, el 22 de enero de 2012 a las 22:12

20 de enero de 2012

Enrique Almeida

Funcionalidades que me gustaría agregar al KBDoctor (continuación)

otrasSearch&Replace

Poder poner un texto a buscar y otro a sustituir y cambiarlo en todos los objetos.
El cambio puede ser en el código, en las pantallas, en las propiedades.
Seria opcional buscar con el Indice que GeneXus ya posee, o que recorra todos los objetos, los distribuya y si el texto esta en dicho objeto, lo modifique y vuelva a consolidarlo.

Seria muy util, para muchas situaciones, por ejemplo para eliminar el &Planilla.UseAutomation, que no se porque motivo el Search de Genexus no lo encuentra.

por noreply@blogger.com (Enrique Almeida), el 20 de enero de 2012 a las 12:48

Marcos Crispino

Nuevo blog: GeneXus for Smart Devices

Esta nota es solo para contarles que estamos empezando un nuevo blog: GeneXus for Smart Devices.

La idea es tener un lugar donde contar las cosas que estamos haciendo, nuevas funcionalidades, tips, como extender los generadores, etc.

Los invito a que lo visiten y se suscriban (por RSS). Ya tiene un par de notas, la bienvenida y una nota contando una funcionalidad nueva :)

El blog está en inglés, porque parece lo más razonable para una comunidad de desarrolladores.

por noreply@blogger.com (Marcos Crispino), el 20 de enero de 2012 a las 11:30

18 de enero de 2012

Enrique Almeida

Funcionalidades que me gustaría agregarle al KBDoctor.


KBDoctorHay un conjunto de funcionalidades que me gustaría agregarle al KBdoctor y dado el ritmo de trabajo que preveo para este año no voy a poder encarar.

TRNCleaner.

Toma una transacción que no esta siendo usada (solo se usa para crear la tabla) y le saca todas las reglas, pantalla, documentación. Opcionalmente puede eliminar también formulas no redundantes o atributos que no pertenezcan a las tablas básicas de la transacción. También debería marcarla como no generable, para que no jorobe mas por un tiempo.

ThemeCleaner.

Dado un tema, borrar todas las clases no referenciadas por ningún objeto de la KB, tomando en cuenta la jerarquía lógica.

ThemeFixer.

Recorrer todos los objetos WEB y corregir todos aquellos controles que tengan clases que no existan en el tema asignado, poniéndole la clase por defecto para dicho control.

SDTFixer.

Dado un SDT, generar un proc que define una variable basado en dicho SDT, y lo genera forzado para todos los ambientes del modelo. Luego borra el procedimiento.

ObjectState.

Al especificar cada objeto, si el mismo tiene errores o warnings, almacenarlos en listas con los codigos de errores, de forma que sea facil saber cuantos objetos tienen un warning determinado y poder corrergirlo, sin tener que hacer un build all.

ObjectNavigation.

Es importante poder ver la navegación de un objeto, de forma rápida. Para esto, se podría agregar una parte a todos los objetos especificables y guardar en ella, la ultima navegación (o navegaciones si esta en mas de un ambiente).

BuildEnvironment.

Muchas veces nos interesa regenerar todo un ambiente pero no hacer un build all que demora horas. Poder largar una regeneración de todos los objetos que perteneces a un determinado ambiente.

ForceAttDelete.

Tengo un atributo y quiero borrarlo, porque no se debe usar mas. Si el atributo esta siendo usado en mas de un lugar, es bastante engorroso. Me gustaría poder cambiar todos los objetos que tengan variables basadas en dicho atributo y que la cambie por variables basadas en el tipo de datos del atributo.
Si hay índices con dicho atributo, debería eliminarlo del mismo.
Si esta en la estructura de alguna transacción y en los formularios, también debería eliminarlo. En el código y en las reglas, es un poco mas difícil, pues no tenemos un parser del código que permita su manipulación en forma fácil y se podría dejar para hacerlo manualmente.
Por otro lado hay que hacerle muchas mejoras, pues con el paso del tiempo algunas funcionalidades han dejado de funcionar correctamente y por otro lado se han implementando funcionalidades adicionales que podrian aprovecharse mejor desde el KBDoctor.
Como dije antes, no creo que vaya a dedicarle muchas energias a esto, y comento mis ideas por si alguien quiere tomarlas e implementar alguna.

ForceTheme. 

Recuperar el Force Theme que habia en el Genexus 9.0, que recorre todos los controles de las pantallas web, y les asigna la clase por defecto a cada uno. Es util, para cuando traemos objetos desarrollados en otros sitemas con otros temas.

por noreply@blogger.com (Enrique Almeida), el 18 de enero de 2012 a las 15:05

16 de enero de 2012

Fernando Briano

ArchLinux: pacman 4 en el repositorio principal

pacman

pacman

Llegó la hora de actualizar nuestros sistemas operativos ArchLinux a pacman 4. En esta versión trabajaron 24 personas creando 893 commits. Pueden ver todos los cambios en este enlace. La característica más esperada de esta versión es el firmado gpg de los paquetes, algo que generó bastante controversia en su momento en la comunidad de Archers.

De todas formas, esta característica viene deshabilitada por defecto en la configuración de pacman. Esto será así hasta que se pulan algunos detalles de la nueva funcionalidad. Para probar la verificación de los paquetes, tenemos que antes darnos una vuelta por la wiki de Arch e informarnos sobre Pacman-key.

pacman 4

pacman 4

En algunas ocasiones, la actualización de pacman puede requerir intervención manual. Por ejemplo en mi sistema:

error: failed to prepare transaction (could not satisfy dependencies)
:: package-query: requires pacman3.6
:: pyalpm: requires pacman3.6

Al intentar desinstalar el paquete pyalpm, encontré otras dependencias hasta que pude corregir la instalación completa haciendo:

[fernando@hoth ~]$ sudo pacman -R pyalpm namcap package-query yaourt

Ya luego no hubo problemas para instalar pacman:

[fernando@hoth ~]$ sudo pacman -S pacman

Y ya con la nueva versión volví a instalar yaourt y demás :)

por Fernando, el 16 de enero de 2012 a las 23:07

14 de enero de 2012

Fernando Briano

Webcomics uruguayos: Mi Vida sin un Jetpack y Marche un Cuadrito

La producción de cómics uruguaya viene en aumento desde hace un buen tiempo. Como parte de esta cultura, no podían quedar afuera los webcómics. Hoy voy a compartir con ustedes un par de webcómics que sigo y vale la pena que conozcan.

Mi vida sin un jetpack

Mi Vida sin un Jetpack

Mi Vida sin un Jetpack

Es un webcómic de MaGnUs quien como no ha obtenido el jetpack que le prometieron, decidió hacer cómics. MaGnUs es escritor, y ha participado de varios proyectos en el mundo de los cómics. Para esta ocasión se alió con Federico Taibó (más conocido como Taibox) para traernos pequeñas dosis autobiográficas en formato webcómic semanal. Ambos compañeros de foro en Multiverseros.

El sitio se actualiza todos los viernes con versiones en inglés y español. Cada historieta viene acompañada del relato de MaGnUs y una canción elegida para acompañar la tira. Los invito a entrar al archivo donde también pueden ver la galería de arte de invitados que aportaron sus interpretaciones de Mi Vida sin un Jetpack.

En algún momento pensé en copiarle la idea a MaGnUs y hacer mi propio webcómic: Mi Vida sin un Lanzallamas. ¿Por qué? Porque no tengo un lanzallamas (aunque nadie me ha prometido uno por ahora), y muchas cosas en la vida serían mas fáciles teniendo un lanzallamas…

Marche un cuadrito

Marche un cuadrito

Marche un cuadrito

Se trata de un proyecto que reune a varios artistas y dibujantes del entorno local y regional. Marche un Cuadrito ofrece una página de historieta por día. Cada día de la semana estará a cargo de uno o más historietistas, en su mayoría miembros de AUCH.

Las historietas:

  • Lunes
    Regreso a las montañas de la locura
    Guión: Rodolfo Santullo | Dibujo: Alejandro Rodríguez Juele
    Adaptación libre de la obra de HP Lovecraft
  • Martes
    Vientre
    Guión: Roy | Dibujo: Lauri Fernández & Nacha Vollenweider
    Dos mujeres, dos puntos de vista sobre la maternidad.
  • Miércoles
    La liga latina
    Guión: Silvio Galizzi | Dibujo: Matías Bergara
    Anécdotas de viajes por iberoamérica en forma de historieta.
  • Jueves
    El loco de los pájaros
    Guión: Federico de los Santos | Dibujo: Sebastián Martínez
    Una leyenda sobre la libertad en alta mar.
  • Viernes
    Fedra
    Guión y dibujo: Maco
    El mundo interior de Fedra y su hermano Nino.
  • Sábado
    La mudanza
    Guión y dibujo: Nicolás Peruzzo
    Una historia sobre seguir siguiendo
  • Domingo
    Sacrificio
    Guión y dibujo: Esteban Caballero
    Luego de un horrendo crimen, ¿qué hay verdaderamente tras los hechos de Paso Cuarto?
  • Domingo
    Ladoga Maldito
    Guión y dibujo: Nahus
    Para los que pueden contar el cuento, es un ángel, es un mártir, es el mismísimo diablo.

Espero que se den una vuelta por los respectivos sitios y con suerte se enganchen con estos webcomics :)

por Fernando, el 14 de enero de 2012 a las 12:00

13 de enero de 2012

Fernando Briano

Global Game Jam: Encuentro mundial de creación de juegos

Global Game Jam

Global Game Jam

Uruguay se suma al Global Game Jam: Un hackatón de 48 horas para crear videojuegos. Gracias al groso de Rodrigo Fernández de UruguayGamer.com, Fernando Sansberro de Batovi Studios y el Dr. Gonzalo Frasca, el Jam le dió recientemente la bienvenida a nuestro país en su blog.

El evento cuenta con presencia en 212 ubicaciones en 46 países, entre los cuales se encuentran varios de habla hispana: Argentina, Colombia, Costa RicaEspaña, Méjico, Panamá, Perú, Uruguay y Venezuela.

Para el video introductorio, se anunció una lista de oradores impresionante:  Will Wright, Baiyon, Gonzalo Frasca, Brenda Garno Brathwaite y John Romero. Si conocen ALGO del mundo de los videojuegos, tienen que conocer al menos uno (o dos) de esos nombres.

¡Cuenten conmigo! Siempre hay que aprovechar las oportunidades de este estilo. Voy a intentar repasar algo de PyGame para poder ir con alguna idea de desarrollo por lo menos. La creación de videojuegos es un tema en mi lista, pero no he hecho mucho al respecto más que algunas pruebas con PyGame mismo. Espero poder estar al nivel :)

Tengan en cuenta que el desarrollo de videojuegos es una actividad multidisciplinaria (bah, como casi todo en el mundo del desarrollo), donde no se necesitan solo programadores. Artistas, diseñadores, modeladores, gamers con muchas ideas, todos estos perfiles son bienvenidos y aportan a cada equipo.

Un video presentación del evento para entender un poco más de qué va la cosa:

Los dejo con el anuncio y la información de la incorporación de Uruguay al evento:

Uruguay ahora es parte del evento mundial de creación de juegos en 48 horas: El Global Game Jam!
Juntate con amigos, conocé más gente en la movida y venite a crear juegos junto a todo el mundo!

¿Qué es el Global Game Jam?
El Global Game Jam (GGJ) es el mayor encuentro mundial de creación de juegos. Dura 48 horas y tiene lugar cada año a finales de enero. El GGJ reúne a miles de entusiastas de los videojuegos, los cuales participan desde sedes repartidas por todo el mundo.

Un encuentro cuyo objetivo es colaborar para crear juegos. Los participantes elaboran diseños de juego y desarrollan rápidamente un prototipo, con la intención de aportar nuevas ideas para ayudar a crecer a la industria. Compartimos un tema y limitaciones comunes. Se pide a los participantes que creen un juego de principio a fin en un tiempo preestablecido (en el GGJ son 48 horas). La brevedad del plazo pretende fomentar el pensamiento creativo para obtener juegos experimentales pequeños pero innovadores.

¿Cúando es?
El fin de semana del 27 al 29 de Enero de 2012

¿Dónde es?
En Montevideo la Universidad ORT estará proporcionando el lugar. Más detalles de la ubicación serán confirmados a la brevedad.
Habrá comida, bebida e internet para los participantes registrados. Se recomienda que lleven sus propios equipos.

¿Cómo me registro?
El registro es sin costo. Habrá que crear un usuario y registrarlo en esta página: http://globalgamejam.org/sites/2012/montevideo-universidad-ort

¿Dónde puedo tener más información?
En el sitio oficial del evento y sus preguntas frecuentes: http://globalgamejam.org/wiki/basic-questions/es
El sitio http://www.UruguayGamer.com estará cubriendo el evento en su web, twitter y Facebook.

Si tienen dudas pueden enviarlas a los foros de UruguayGamer.

Saludos y nos vemos!

por Fernando, el 13 de enero de 2012 a las 12:23

12 de enero de 2012

Enrique Almeida

PiensoPienso: Cómo implementar semáforos en GeneXus?

semaforosSe tiene una aplicación que se ejecuta en muchas computadoras diferentes sobre la misma base de datos y comparten el file system.

Hay un determinado proceso que por su consumo no puedo permitir mas que tres ejecuciones simultaneas del mismo pues la performance de  toda la aplicación se degrada hasta niveles no aceptables. 

Dicho proceso, puede tener cortes o caídas que hagan que no termine en forma correcta. 

Cuales son las posibles implementaciones con GeneXus para lograr un máximo de tres ejecuciones simultaneas?

Se valorarán las que maximicen la concurrencia y no provoquen bloqueos.

Para los que quieran les dejo el link de wikipedia sobre el tema y otro sobre mutex.

por noreply@blogger.com (Enrique Almeida), el 12 de enero de 2012 a las 16:48

KB grandes

Update: A pedido de Artech pasó para las 11:00 en la sala Picasso.

A pedido del publico * vamos a juntarnos a charlar sobre Kb grandes en el tercer piso mañana miércoles a las 11:30 en la sala de sofás.

No quiero que la charla se convierta en una sesión de catarsis de quejas, por lo que les pido que vengan con propuestas para los problemas de formase poder formalizar los pedidos a Artech o a empresas que desarrollen herramientas.

* siempre quise usar la expresión "a pedido del publico".

por noreply@blogger.com (Enrique Almeida), el 12 de enero de 2012 a las 13:55

Marcos Crispino

Implementar un User Control para el generador iOS

En los generadores para Smart Devices en GeneXus X Evolution 2, tenemos la posibilidad de crear user controls, para extender el comportamiento del generador.

La idea de esta nota es contar como desarrollar un nuevo user control para el generador iOS.

Nota: crear un nuevo user control involucra varios pasos: implementación en la plataforma, definición del control, implementar resolvers para las propiedades, distribución, etc. Ahora me voy a concentrar solo en la parte de implementación.

Como ejemplo, voy a mostrar como implementar el SD ImageMap. Básicamente lo que hace es mostrar una imagen de fondo con un conjunto de imágenes en posiciones determinadas, que cuando se seleccionan tiene la posibilidad de disparar una acción.

El código completo del control (al día de hoy) lo pueden ver en https://gist.github.com/1600064

Clase base

Como decía, el control muestra una lista de imágenes con una imagen grande de fondo. Esa lista puede venir de una tabla en la base de datos, o de un SDT collection. En cualquier caso, los controles que reciben una lista de registros, se implementan a partir de un control Grid en GeneXus, cambiando la propiedad Control Type según corresponda.

Lo primero que tenemos que hacer entonces es crear la clase GXControlImageMap, como subclase de GXControlGridBase.

Advertencia: los nombres que empiezan con "GX" están reservados. En este caso el control es parte del Framework, por lo tanto puede llamarse así. Cuando implementen sus controles usen algún otro nombre...

Creación de la vista

Lo primero que debemos implementar es el método que crea la vista que va a utilizar el control. La forma de hacerlo es implementar el método newGridViewWithFrame:, que será llamado por la clase base cuando se haga el loadView.

Es importante notar que no es aconsejable implementar el loadView directamente, ya que la clase base hace varias cosas además de crear la vista del control (por ejemplo crea otra vista donde coloca la vista que estamos creando, le aplica la propiedad "Visible", etc.).

- (UIView *)newGridViewWithFrame:(CGRect)frame {
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
    [imageView setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];

    NSString *imageName = [self imageName];
    if (imageName) {
        UIImage *embededImage = [GXResources imageForName:imageName];
        if (embededImage) {
            [imageView setImage:embededImage];
        }
        else {
            NSURL *imageUrl = [GXResources urlForImageName:imageName];
            [imageView setImageWithURL:imageUrl placeholderImage:nil];
        }
    }
    
    [imageView setUserInteractionEnabled:YES];
    
    UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleImageTap:)];
    
    [imageView addGestureRecognizer:tapGestureRecognizer];
    
    [tapGestureRecognizer release];
    
    return imageView;
}

El método newGridViewWIthFrame: hace lo siguiente:
  • crea un UIImageView donde va a dibujar la imagen de fondo
  • carga la imagen, el valor lo obtiene usando el método imageName (ver más adelante)
  • agrega un "tap gesture recognizer" para poder detectar cuando se hace un tap sobre alguna de las imágenes
Acceso a la vista del control

El UIImageView que estamos creando en este método queda accesible usando el método gridView de la clase base. Es recomendable implementar un método que permita acceder a esta vista con el tipo de datos correcto, ya el gridView es un UIView genérico. Por lo tanto, el control implementa el método imageView

- (UIImageView *)imageView {
    return (UIImageView *)[self gridView];
}

Propiedades definidas en GeneXus

El control también va a necesitar acceso a las propiedades definidas en GeneXus. Para eso define nueve métodos, uno por cada una de las propiedades:

- (NSString *)imageName;
- (NSString *)imageAtt;
- (NSString *)imageField;
- (NSString *)horizontalCoordinateAtt;
- (NSString *)horizontalCoordinateField;
- (NSString *)verticalCoordinateAtt;
- (NSString *)verticalCoordinateField;
- (NSString *)sizeAtt;
- (NSString *)sizeField;

La propiedad imageName tiene el nombre de la imagen de fondo a usar.

Las demás propiedades vienen en pares, una con sufijo "Att" y la otra con sufijo "Field". La propiedad con sufijo "Att" indica el nombre del atributo o variable que contiene el valor. La propiedad con sufijo "Field" contiene el "field specifier", que se usa en el caso que el "Att" sea un SDT, e indica el nombre del miembro del SDT.

Ejemplos:
  • Si usamos el atributo MyAttribute, en la propiedad "Att" viene "MyAttribute" y la propiedad "Field" viene vacía
  • Si usamos la variable &MyVar, en la propiedad "Att" viene "&MyVar" y la propiedad "Field" viene vacía.
  • Si usamos un miembro de un SDT, &MySDT.Item, entonces en la propiedad "Att" viene "&MySDT" y en la propiedad "Field" viene "Item"
Los cuatro grupos de propiedades que tienen esta característica son:
  • image: contiene la imagen del ítem a mostrar
  • horizontalCoordinate: la posición horizontal donde se debe mostrar, relativo al tamaño de la imagen de fondo (el origen de coordenadas {0,0} está en la parte superior izquierda de la imagen de fondo)
  • verticalCoordinate: la posición vertical
  • size: el tamaño con el que se debe mostrar la imagen, relativo al tamaño de la imagen de fondo.
Las propiedades se leen de forma muy simple, por ejemplo:

- (NSString *)horizontalCoordinateAtt {
    return [[self properties] getPropertyValueString:@"@SDImageMapHCoordAtt"];    
}

La única que tiene algo más de complejidad es imageName, que por ser una imagen viene con un prefijo que es el GUID de las imágenes, y debemos separarlo para poder usarla:

- (NSString *)imageName {
    NSString *imageName = [[self properties] getPropertyValueString:@"@SDImageMapImage"];
    imageName = [GXObjectHelper parseObjectNameOfType:kGXObjectIdImage from:imageName];
    return imageName;
}

Carga de datos

La carga de datos la maneja la clase base, y cuando termina de obtener los datos del servidor le manda el mensaje reloadData al control.

En este caso la implementación invoca un método privado loadData: pasándole la cantidad de registros que tiene el proveedor de datos:

- (void)reloadData {
    [self loadData:[[self entityDataListProvider] numberOfLoadedEntitiesInSection:0]];
}

El método loadData: es más interesante.

Lo primero que hace es borrar cualquier imagen que tuviera ya cargada, porque las va a volver a agregar:

[[[self imageView] subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];

Luego obtiene los valores de las propiedades configuradas en GeneXus:

NSString *imageNameAtt = [self imageAtt];
NSString *imageNameField = [self imageField];
NSString *hCoordAtt = [self horizontalCoordinateAtt];
NSString *hCoordField = [self horizontalCoordinateField];
NSString *vCoordAtt = [self verticalCoordinateAtt];
NSString *vCoordField = [self verticalCoordinateField];
NSString *sizeAtt = [self sizeAtt];
NSString *sizeField = [self sizeField];

Lo siguiente es iterar sobre los registros disponibles (la cantidad se le pasa como parámetro al loadData: en la variable count)

for(NSUInteger index = 0; index < count; index++)

y para cada uno, obtener los valores. Para eso usamos el método valueForEntityDataFieldName:fieldSpecifier:indexPath: de la clase base:

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
NSString *imageName = [self valueForEntityDataFieldName:imageNameAtt fieldSpecifier:imageNameField indexPath:indexPath];
NSNumber *hCoord = [self valueForEntityDataFieldName:hCoordAtt fieldSpecifier:hCoordField indexPath:indexPath];
NSNumber *vCoord = [self valueForEntityDataFieldName:vCoordAtt fieldSpecifier:vCoordField indexPath:indexPath];
NSNumber *size = [self valueForEntityDataFieldName:sizeAtt fieldSpecifier:sizeField indexPath:indexPath];

Nótese que el indexPath le indica al proveedor de datos cual es el registro que estamos procesando.

El resto del código del evento es específico al control y no viene mucho al caso, lo pueden ver en el link con el código completo. Lo único para destacar es que con los valores de las propiedades leídas crea un UIImageView para cada ítem y lo agrega a la vista principal del control con

[[self imageView] addSubview:itemView];

Disparo de acciones

Por último, lo que hace el control es disparar la "default action" cuando se selecciona una de las imágenes.

Eso se configuró en el método newGridViewWithFrame: cuando agregamos el "tap gesture recognizer", que va a invocar el método handleImageTap:

- (void)handleImageTap:(UITapGestureRecognizer *)sender {
    UIView *mainView = [self imageView];
    
    CGPoint tapPoint = [sender locationInView:mainView];
    UIView *tappedView = [mainView hitTest:tapPoint withEvent:nil];
    
    if (tappedView && tappedView != mainView) {
        NSUInteger index = [tappedView tag];
        [self executeDefaultActionForEntityAtSection:0 row:index];
    }
}

Este método determina sobre cual ítem se hizo el tap, y luego simplemente llama al método executeDefaultActionForEntityAtSection:row: de la clase base para que se encargue.

Resumen

La nota quedó bastante larga, pero en realidad no es mucho lo que hay que hacer para implementar un user control. La parte más compleja se encarga la clase base: obtener los datos (ya sea de un data provider o de un SDT), lectura de propiedades, manejo de la vista del control, manejo de eventos, etc.

En resumen, lo que tiene que hacer el control es:

  • crear la vista, en el método newGridViewWithFrame:
  • implementar el método reloadData para cargar los datos que vienen en el provider (en este caso se implementó en un método privado loadData:, pero es lo mismo)
  • determinar cuándo se debe disparar una acción y cuál es el ítem que corresponde.

por noreply@blogger.com (Marcos Crispino), el 12 de enero de 2012 a las 13:21