miércoles, 28 de diciembre de 2016

GeneXus M

Hace unos pocos días pude ver la presentación "Evolución de la arquitectura de GeneXus", por Germán Asiz, en el GX26, y me he quedado bastante contento por el camino que se está tomando, pues se trata de definiciones que dan inicio a una época totalmente nueva en GX, con unas posibilidades muy atractivas.

El caballito de batalla de esta nueva etapa va a ser, cómo no, una nueva versión de GeneXus, que entre otras cosas recoge un antiguo anhelo de cierto tipo de usuarios (me incluyo) y casi una "exigencia" de las nuevas generaciones: que el IDE se pueda instalar en cualquier sistema operativo.
Tal cual. Yo me apuntaré con alguna distribución Linux.


El nuevo IDE, GeneXus M, va a ser gratuito, liviano y Open Source -ya hicieron un prototipo basado en Atom- con todas las posibilidades de colaboración que eso lleva y con lo que se están sentando las bases para el advenimiento de una diversidad de iniciativas y herramientas que serán desarrolladas por la gente de GeneXus y también por terceros (si me quedara algo de tiempo para disfrutar este tipo de cosas, yo mismo trabajaría en algún proyecto así, algo basado en Eclipse, por ejemplo). Puede que en el futuro veamos, además de la evolución del clásico IDE de GX, otros exclusivos para determinadas plataformas o dispositivos.

Pongo énfasis en lo del IDE porque es lo que siempre nos entusiasma, no?. Pero claramente la cosa va mucho más allá, porque se sostiene en cambios a nivel de arquitectura de GeneXus que implican un desacople de componentes del GX que conocemos hoy -que es algo así como un solo bloque- y esos componentes en la nueva organización van a posibilitar nuevas formas de desarrollar y colaborar.
Va a ser interesante ver cómo vamos a trabajar con la capa de servicios de GeneXus (GXServices). Y cómo vamos a pagar por usarla. Porque este nuevo escenario también plantea la necesidad de revisar cuestiones de licenciamiento y de estrategia de llegada a muchos más desarrolladores, clientes y partners.

En toda esta historia hay algo que a mí me gustaría ver y no sé si realmente estará en planes de alguien. Se trata de un "desacople" un tanto particular: que la generación de la UI/UX esté por separado en generadores especializados y que, de paso, también sea posible que terceros desarrollen esos generadores. Es decir, por ejemplo, que podamos usar el generador Java tradicional de GX complementado con un generador de UI (Desktop, Mobile, Web o lo que sea) desarrollado por Simplifica o Dvelop. O con alguno que pueda desarrollar cada uno en sus "tiempos libres".


 Work With generado con el pattern wuiServices y template Angle

Esta idea me quedó dando vueltas de mi experiencia desarrollando wuiServices, un pattern WW muy sencillo que en vez de Webpanels generaba directamente Html y Javascript. Pues estando en eso te das cuenta de que si estás generando esos fuentes, ese código, tal vez lo que deberías estar desarrollando es un generador y no un pattern. 

Un generador de UI debiera trabajar a partir de un input desde el editor de formularios del IDE GeneXus, aunque también podría ser desde otro tipo de editor en una herramienta desarrollada por terceros. La salida de estos generadores serían "Vistas" naturalmente ajenas a la implementación de las lógicas de negocio o de acceso a datos, pero integradas totalmente a la solución desarrollada.
Una cuestión complicada de esto podría ser la generación de código de eventos, pero podría darse casos en que simplemente vamos a querer escribir eventos del lado cliente por nuestra cuenta y serían nativos del generador.

Me gusta pensar que esa separación de generador backend y generador UI podría dar paso a una buena oferta de soluciones y con ello una mejora interesante de la competitividad de GeneXus.

Esto pinta bien, me gustaría participar de cosas así y además tengo un buen presentimiento con el 2017: de seguro va a ser mejor que el 2016.

salu2!!!

viernes, 3 de junio de 2016

Scripting GX Java 8 Nashorn

A riesgo de parecer reiterativo, he querido hacer una actualización del tema de scripting Java, esta vez con GeneXus Xev3, Java 8 y el -no tan- nuevo engine Nashorn, que reemplaza al anterior Rhino.
Nashorn cuenta con algunas características que lo ponen por sobre su predecesor: mejor performance, posibilidad de invocar Java desde Javascript y viceversa, cuestiones de seguridad, etc..

El ejemplo que ahora les traigo es bastante sencillo y no pretende ahondar en cuestiones tan avanzadas, sino ser una guía inicial. De ahí en adelante depende de ustedes.
Por decir algo, alguien podría querer extender con Javascript las clases que genera GeneXus en un proyecto cualquiera...

Pero bueno, nuestro caso se trata de lo siguiente: tendremos un webpanel que llama a un procedure pasándole un pequeño script por parámetro. El procedure llamado es el que instancia el engine Nashorn y ejecuta el script.
Por su parte, el script, es una función que tiene su propia llamada a otro procedure gx, el cual hace una lectura a la tabla Product y retorna un string.

Webpanel testNashorn

El webpanel sólo cuenta con un textblock y un botón asociado al evento Enter, en el cual ponemos la llamada al procedure jsEngine, pasando el script a ejecutar.

Event Enter
 
 //el script a ejecutar: una función que invoca el método "generaMsg" y retorna un texto
 &script = 'function mainFunc() {' + newline()
 + '    var myMsg = jsEngine.generaMsg("hola");' + newline()
 + '    return myMsg;' + newline()
 + '}' + newline()
 textBlock1.Caption = jsEngine.Udp(&script)
 
EndEvent

Procedure jsEngine

En el procedure jsEngine se pueden distinguir dos secciones de código: la primera es donde usamos el truco para insertar un método público generaMsg a la clase java jsengine que GeneXus genera a partir del procedure. Aquí es donde ponemos un llamado a nuestro segundo procedure generaString.
En la segunda sección va el código de instanciar el engine Nashorn y ejecutar el script preparado.
//todas las variables son VarChar(1K)
parm(&script,&return);
//Sección1: iniciamos "cortando" el java que genera GX
java     privateExecute2();
java }
//para poder insertar un método "generaMsg", que luego invocaremos desde el javascript
java public String generaMsg(String msg) {
java     [!&tmpString!] = msg;
//acá podemos poner una llamada a otro procedure, en este caso al proc "generaString"
&tmpString = generaString.Udp(&tmpString)
java     return [!&tmpString!];
java }
java private void privateExecute2( ) {

//Sección2: instancia del engine y la invocación
java try {
java     javax.script.ScriptEngineManager m = new javax.script.ScriptEngineManager();
java     javax.script.ScriptEngine ngNashorn = m.getEngineByName("nashorn");
java     ngNashorn.put("jsEngine", this); //pasamos el objeto actual al engine
java     ngNashorn.eval([!&script!]); //hacemos eval del script
//invocamos la function "mainFunc" y manejamos el resultado
java     Object result = ((javax.script.Invocable)ngNashorn).invokeFunction("mainFunc");
java     [!&return!] = result.getClass().getName();
if &return = !"java.lang.String"
 java [!&return!] = result.toString();
endif
java } catch(javax.script.ScriptException exc) {
java     [!&return!] = "Error evaluating the script: " + exc.getMessage();
java } catch(NoSuchMethodException exc) {
java     [!&return!] = "Error evaluating the script: " + exc.getMessage();
java }
Por cierto que estas cosas se podrían implementar como un External Object y no hacer esta mezcla de código GeneXus y Java. Pero insisto en hacerlo de esta forma, porque así basta con pegar el código en un procedure y nada más, lo que resulta ser bastante práctico y sencillo, y favorece que el usuario gx se anime a probar sin mucha complicación.

Procedure generaString

En este proc, simplemente, concatenamos algunas cosas al string recibido y lo retornamos. Nótese que se debe crear una transaction con atributos ProductId y ProductName, y ponerle algún dato a la tabla.
//todas las variables son VarChar(1K)
parm(&inString,&outString);
for each
 &ProductName = ProductName
 exit
endfor
&outString = &inString + !", qué tal: " + &ProductName

Resultado

Con todo listo, sólo falta hacer Build y ejecutar el webpanel. Click al botón y ya está. Les dejo una vista del webpanel a modo de "evidencia".


Espero que esté lo suficiente claro el ejemplo, que lo corran y que se animen a hacer otras pruebas. Y, claro, a ir pensando cómo usar este tipo de cosas en sus proyectos de la vida real.
salu2!!!

jueves, 10 de marzo de 2016

Editor Abstracto y posibilidades de Extensión

Me ha tocado trabajar en un pequeño proyecto con GXXEv3 y hasta el momento me he sentido bastante cómodo y pensando que ya voy a ir dejando de lado la Ev2, para las cosas que se vengan en lo inmediato.

Pero no voy a entrar en detalles de eso, sino en un tema que me da vueltas desde hace un tiempo y que me vuelve cada vez que veo el editor abstracto de formularios en la Ev3: ¿será que GeneXus se encamina a proveernos de alguna nueva posibilidad de extensión?

Por que si tenemos un editor abstracto, el paso siguiente podría ser alguna forma de exponer los eventos y que, derechamente, usemos herramientas provistas por terceros para el frontend web. O sea, algo así como generadores de interfaz web -con sus propios editores y otras herramientas- basados en cualquiera de los frameworks y librerías javascript que andan por ahí y que proveen tantas posibilidades.
Estos generadores que me estoy imaginando podrían integrarse a GeneXus de forma que el analista siga creando webpanels y transactions casi tal como se hace hoy. Al momento del build se dispararían tareas de generación y al ejecutar todo estaría a punto.



Una gran oportunidad se abriría para las opciones de integrar diseños completos provistos por terceros, a diferencia de lo que puede implicar hoy eso con el Theme Editor.

Ya me estoy viendo a los actuales proveedores de patterns y otras cosas, y a unos cuantos emprendedores, que de seguro aparecerían, preparando una variada oferta de productos que nos vendrían bastante bien para cuando querramos presentar prototipos a nuestros clientes esperando que al finalizar la reunión nos lancen un "dónde firmo?".

AngularJS, Ember, Backbone, etc.. Frameworks MVC, librerías, desarrollo orientado a componentes, en fin, un mundo de cosas que podrían complementar lo que hoy hacemos con GeneXus y que sin duda nos haría más competitivos.

Bueno, seguramente no sería tan simple implementar algo así. Tal vez también haya otras consideraciones políticas o comerciales que uno no se imagina.
Pero soy optimista y, quién sabe, de pronto no estoy tan lejos.

salu2!!!

jueves, 7 de mayo de 2015

Stored Procedure SQL-XML como External Object

En esta ocasión les dejo una pequeña guía para ejecutar un query sql-xml en SQL Server, mediante un sencillo stored procedure que en GX usaremos definido como External Object. Para que tengan de referencia, este ejemplo lo hice usando GXXEv2u6, generador C# y MS Sql Server 2008 R2 sp2.

Creación del Stored Procedure

Acá les dejo el script:
CREATE PROCEDURE [dbo].[sp_dynQuery]
 @query nvarchar(2048) ,
 @outNvar nvarchar(max) OUT
AS
BEGIN
    DECLARE @parmDef nvarchar(512);
    DECLARE @queryTmp nvarchar(2048)
    DECLARE @outTmp nvarchar(max);
    SET NOCOUNT ON;
    SET @parmDef = '@out nvarchar(max) OUTPUT';
    SET @queryTmp = 'SELECT @out = CAST((' + @query + ') AS NVARCHAR(max))';
    EXECUTE sp_executesql @queryTmp, @parmDef, @out=@outTmp OUTPUT; 
    SELECT @outNvar = @outTmp;
    SET NOCOUNT OFF
    RETURN(0)
END
Verán que básicamente lo que hace el SP es ejecutar la query que le daremos por parámetros, pasando el resultado a una variable de tipo nvarchar y retornando en el parámetro de salida. Como se trata de un proc que ejecuta queries dinámicas, que eventualmente puede representar un problema de seguridad, debemos asegurar dejarlo asociado a un usuario con restricciones. Específicamente, sólo permiso para ejecutar el SP y de lectura en tablas. Para estos seteos podemos pedir ayuda a nuestro buen amigo Google, al DBA o algún crack del sql que tengamos cerca.

Para que todo resulte más cómodo, les dejo scripts para crear la tabla del ejemplo y cargarle algunos datos.
CREATE TABLE [dbo].[Developer](
 [DeveloperId] [smallint] NOT NULL,
 [DeveloperName] [varchar](64) NOT NULL,
 [DeveloperLastName] [varchar](64) NOT NULL,
 [DeveloperMail] [varchar](128) NOT NULL,
PRIMARY KEY([DeveloperId])
INSERT INTO [Developer]
([DeveloperId],[DeveloperName],[DeveloperLastName],[DeveloperMail])
VALUES
    (1,'ZERR','Angelo','angelo.zerr@gmail.com')
   ,(2,'Leclercq','Pascal','pascal.leclercq@gmail.com')

A continuación la query que pasaremos al SP desde GX:
SELECT [DeveloperName]     as devname 
      ,[DeveloperLastName] as devlastname
      ,[DeveloperMail]     as devmail
FROM [Developer]
WHERE [DeveloperId] < 3
FOR XML PATH ('developer'), ROOT ('devs')
Este ejemplo es bastante sencillo, consulta algunos campos en una tabla, pero se pueden construir cosas bastante más complejas. Aquí hay un buen post sobre el tema.


Creación de External Object

Lo siguiente es la creación del External Object que en nuestra KB representará al stored procedure. Como con cualquier objeto, lo podemos iniciar con Ctrl-N, asignando el nombre que deseamos, en este caso "dynQuery". Desde antes debemos tener preparado un Data Store, que llamaremos "StoredProcs", especial para ejecutar nuestro Stored Procedure, seteado con una cuenta de usuario que mencioné antes, la cual debe tener ciertas restricciones.
En las propiedades seleccionamos el tipo "Stored Procedure" y asignamos el datastore creado previamente.
El único método a definir será "dynQuery" y en External Name ponemos el nombre del Stored Procedure, en este caso "sp_dynQuery" (se puede ver en el script de creación del SP).

En la definición de cada parámetro debemos considerar las propiedades del Stored Procedure en cuanto a Tipo de Acceso, Tipo de Dato y Nombre.



Uso del External Object

Finalmente, en algún objeto de prueba, podemos poner la invocación al EO de la siguiente forma:
&query = 'SELECT [DeveloperName]     as devname ' +
         '      ,[DeveloperLastName] as devlastname ' +
         '      ,[DeveloperMail]     as devmail ' +
         'FROM [Developer] ' +
         'WHERE [DeveloperId] < 3 ' +
         "FOR XML PATH ('developer'), ROOT ('devs')"
csharp try{
    &result = &dynQuery.dynQuery(&query,&return)
csharp }
csharp catch ( Exception e ){
csharp     [!&error!] = e.ToString();
csharp }

La ejecución de esto, si no hay problemas, debiera darnos en la variable &return el siguiente xml:
<devs>
    <developer>
        <devname>ZERR</devname>
        <devlastname>Angelo</devlastname>
        <devmail>angelo.zerr@gmail.com</devmail>
    </developer>           
    <developer>
        <devname>Leclercq</devname>
        <devlastname>Pascal</devlastname>
        <devmail>pascal.leclercq@gmail.com</devmail>
    </developer>           
</devs>           
Nota: La "indentacion" y los saltos de linea los puse para efectos de mejor visualización.

Este tipo de solución se puede usar en innumerables situaciones. Por mencionar algo, están los reportes dinámicos que les mencioné en el post anterior.
También podemos convertir a JSON si tenemos algún User Control que lo requiera, etc., etc..

martes, 21 de abril de 2015

Ideas de reporting con xDocReport y Gx-Java

Algo que me motiva es hacer aplicaciones que tengan opciones de configuración potentes, que den a los usuarios buenas posibilidades de ajustarse a diferentes escenarios, a cambiantes contextos de negocios. O sea, a lo que tenemos por estos tiempos, cada día.
Tengo la idea de que cada vez es más común y aceptado que usuarios de configuración dispongan de más recursos en este sentido, de tal forma que los sistemas se puedan ajustar y adaptar rápido a determinados cambios. Por ejemplo, cuando se necesita definir un producto nuevo o cuando cambian reglas de cálculo de una nómina.
Otra veta a explotar en este camino es el reporting. En este post les cuento un poco sobre xDocReport, una api Java que nos permite trabajar con templates diseñados por cualquier usuario, usando MS Word, insertando campos de "combinación de correspondencia" (mergefields) que asumirán los valores de un xml al momento de crear el reporte. Usaremos la sintaxis de FreeMarker para los campos en el template docx.

Bueno, lo primero: Descargar xDocReport desde aquí.
Luego crear una KB GX-Java (yo usé la XEv2) con un webpanel que llame a un procedure, copiar todos los Jar a la carpeta web y setear la Path List de la siguiente forma:


A continuación preparar el template con MS Word.
Debe quedar más o menos así:


Dejé resaltados los campos para que se aprecie bien, así que no esperen que el archivo les quede exactamente igual. Los campos se crean usando Ctrl-F9 y se completan con la opción "Editar Campo" que aparece con el click derecho. Ahí deben dejarlo de tipo MergeField y en el nombre poner el identificador o directiva que corresponda (por ejemplo ${doc.project.name}).


El xml lo podemos generar con un sdt y el método ToXml, pero en este ejemplo lo pondremos en un archivo:
<devs>
    <developer>
        <devname>ZERR</devname>
        <devlastname>Angelo</devlastname>
        <devmail>angelo.zerr@gmail.com</devmail>
    </developer>           
    <developer>
        <devname>Leclercq</devname>
        <devlastname>Pascal</devlastname>
        <devmail>pascal.leclercq@gmail.com</devmail>
    </developer>           
</devs>           
El siguiente sería el código del procedure:

&tmpString = !"C:" + chr(92) + "xDocReportFiles" + chr(92)
&fileIN  = &tmpString + !"xDocRptTemplate.docx"
&fileXml = &tmpString + !"xDocRptData.xml"
&fileOUT = &tmpString + !"xDocRptOut.docx"
java try {
// 1) Load Docx file by filling  template engine and cache it to the registry
java     java.io.InputStream in = new java.io.FileInputStream([!&fileIN!]);
java     fr.opensagres.xdocreport.document.IXDocReport report;
java     fr.opensagres.xdocreport.template.TemplateEngineKind kind = fr.opensagres.xdocreport.template.TemplateEngineKind.Freemarker;
java     report = fr.opensagres.xdocreport.document.registry.XDocReportRegistry.getRegistry().loadReport(in,kind);
// 2) Create context Java model
java     fr.opensagres.xdocreport.template.IContext context = report.createContext();
java     java.io.InputStream projectInputStream = new java.io.FileInputStream([!&fileXml!]);
java     org.xml.sax.InputSource projectInputSource = new org.xml.sax.InputSource( projectInputStream );
java     freemarker.ext.dom.NodeModel project = freemarker.ext.dom.NodeModel.parse( projectInputSource );
java     context.put( "doc", project );
// 3) Generate report by merging Java model with the Docx
java     java.io.OutputStream out = new java.io.FileOutputStream(new java.io.File([!&fileOUT!]));
java     report.process(context, out);
java     } catch (Exception e) {
java         System.out.println("Exception thrown: " + e);
java     e.printStackTrace();
java }
RESULTADO
Para ejecutar, asegurarse de que los archivos estén en el directorio que corresponda, especialmente los Jar que deben estar en la "lib" de nuestra aplicación en el Tomcat.
Si todo sale bien, aparecerá nuestro report con los datos provistos por el xml y debiera verse así:



Eso, por ahora.

Queda una lista interesante de cosas por hacer: generar data con SDTs/DataProviders, queries dinámicas con "For Xml" (usando un store proc en Sql Server), convertir a Pdf, convertir las librerías para poder usarlas con Gx-Csharp, etc..

salu2!!!

martes, 20 de enero de 2015

Scripting GX C# con Jint 2.4


Amigos, en esta ocasión hago un "update" del tema de scripting con Jint, uno de los engines javascript que podemos usar con C#, que desde un tiempo pasó a la versión 2.0 con importantes mejoras.

En esta pasada aprovecho de mostrarles cómo hacer para que desde el javascript puedan llamar a procedures gx que estén en la misma KB, lo que favorece de buena forma las posibilidades de este tipo de integración y su aplicación en casos reales.

Pondremos en un procedure jintEngine el código de más abajo, en el que se puede apreciar en las primeras líneas el truco para "cortar" el C# generado por GX y meter en medio una definición de "delegate" y un método que usaremos luego para llamar a un procedure gx desde el javascript. Nótese que el método recibe un string y retorna otro string, tal como el "delegate".

 parm(&jsVarchar,&returnVarchar,&isOK);
 csharp     executePrivate2();
 csharp }
 csharp public delegate string getObjectDeleg(string inStr);
 csharp private string getObject(string inStr)
 csharp {
         csharp [!&in!] = inStr;
         //acá la lamada a otro procedure de nuestra kb
         jintGetObjJsonString.call(&in,&ret)
         csharp return [!&ret!];
 csharp }
 csharp void executePrivate2( )
 csharp {
 
 // código para instanciar el engine Jint
 &returnVarchar = ""
 &isOK = true
 csharp try {
         csharp var engine = new Jint.Engine(cfg => cfg.AllowClr());
         //acá hacemos una instancia del delegate
         csharp getObjectDeleg getObjectDelegInstance = new getObjectDeleg(getObject);
         //y se lo pasamos al engine
         csharp engine.SetValue("getObjJsonStr",getObjectDelegInstance);
         //ejecutar el javascript que viene en &jsVarchar
         csharp engine.Execute([!&jsVarchar!]);
          //el resultado lo dejamos en &returnVarchar
         csharp [!&returnVarchar!] = engine.GetCompletionValue().ToString();
 csharp }
 csharp catch ( Exception e ){
         csharp [!&returnVarchar!] = e.ToString();
         &isOK = false
 csharp }  
El procedure jintGetObjJsonString podrá ser invocado desde el javascript con getObjJsonStr, de acuerdo a cómo se lo pasamos al engine con SetValue.
Para este procedure podríamos tener el siguiente código:
 parm(&in,&ret); //parms de tipo varchar
 //asumimos que en &in viene un json con la estructura de &sdtEntrada
 &sdtEntrada.fromjson(&in)
 ...
 // aquí lo que sea que se necesite para cargar el &sdtSalida
 ...
 &ret = &sdtSalida.tojson() 

Un ejemplo de javascript que podríamos ejecutar:
 //objeto a usar como parm (con la misma estructura de &sdtEntrada)
 var objSdtEntrada = {Id:1,............};
 //llamada al proc gx usando delegate
 var objDesdeGX = getObjJsonStr(JSON.stringify(objSdtEntrada));
 function mainFunction(){
     ...
     var otroDesdeGX = getObjJsonStr(JSON.stringify(objSdtEntrada));
     ...
     //el retorno puede ser un json o cualquier cosa string
     return JSON.stringify(otroDesdeGX);
 }
 //finalizar con la invocación a la función "main"
 mainFunction();
Lo importante de este ejemplo es mostrar cómo se invoca el método delegate mediante la función getObjJsonStr, que finalmente llama al procedure jintGetObjJsonString, y que debemos usar una función para hacer el return que Jint atrapa con GetCompletionValue.

Un abrazo y buen 2015 a todos.
salu2!

P.D.: para este año me gustaría que Artech nos anunciara un generador web basado en AngularJS.

lunes, 13 de octubre de 2014

Scripting GX .Net + Jint (JavaScript Server-Side)

Llevo un rato trabajando con el generador C# y en un determinado proyecto tuve que incorporar un mecanismo de scripting JavaScript server-side, que terminé implementando en base a Jint.
En este tipo de cosas se puede llegar a niveles de complejidad altos, según lo creativos que estemos, pero acá les dejo un par de ejemplos sencillos. A ver si algunos se animan y hacen sus primeras pruebas en este tema.

Caso 1

Se trata de cómo pasar variables sencillas al engine y ejecutar un JavaScript que use esas variables, en este caso sólo con una instrucción return:
 &idVarchar = "miVariable" //id de la variable en el script
 &miVarchar = "Hola Mundo!" //valor de la variable
 &jsVarchar = "return miVariable;" //script del usuario

Acá viene el código C#:
 csharp try {  
     csharp Jint.JintEngine engine = new Jint.JintEngine();  
     csharp engine.SetParameter([!&idVarchar!], [!&miVarchar!]);  
     csharp var result = engine.Run([!&jsVarchar!]);  
     csharp [!&returnVarchar!] = result.ToString();}  
 csharp catch (Jint.JintException e){  
     csharp [!&returnVarchar!] = e.Message;}  
 csharp catch (Exception e ){  
     csharp [!&returnVarchar!] = e.ToString();}  
- Instanciamos el engine
- Pasamos nuestra variable al engine
- Le damos run con el script de una línea
- Y el retorno lo pasamos a una variable varchar (debería traer "Hola Mundo!")
- Si hubiera errores, los atrapamos y retornamos la descripción.

Caso 2

En este ejemplo tomaremos una variable basada en un SDT y la pasamos al engine como un string Json.
 &xidVarchar = "Persona" //id del objeto a crear en el script
 &idVarchar = "jintJson" + &xidVarchar //id del string Json en el script
 &sdtPersona.Nombre = "John Doe Jr." //datos en la variable &sdtPersona
 &sdtPersona.Edad = 35
 &miVarchar = &sdtPersona.ToJson()  //pasamos la variable sdt a un string json
 //iniciamos el script con un eval que transforma el Json en un objeto JavaScript
 &jsVarchar = "var " + &xidVarchar + " = eval('(' + " + &idVarchar + " + ')');" + newline()
 + "//inicio del script del usuario" + newline()
 + "return Persona.Nombre;" + newline()
El código C# es igual al del Caso 1:
- Instanciamos el engine
- Pasamos nuestra variable string Json al engine
- Le damos run con el script que inicia transformando el Json en el objeto Persona
- Y retornamos Persona.Nombre a una variable varchar (debería traer "John Doe Jr.")
- Si hubiera errores, los atrapamos y retornamos la descripción.

Bonus Track

Si se requiere conocer el tipo del valor de retorno, podemos hacer algo apoyándonos en GetType():
 csharp Type typeX = result.GetType();
 csharp [!&typeVarchar!] = typeX.Name;
 do case
     case &typeVarchar = "Double"
         csharp Double returnDbl = (Double)result;
         csharp [!&returnVarchar!] = returnDbl.ToString("F4",System.Globalization.CultureInfo.InvariantCulture);
     case &typeVarchar = "DateTime"
         csharp [!&returnDateTime!] = (DateTime)result;
         &returnVarchar = &returnDtt.ToFormattedString()
     otherwise
         csharp [!&returnVarchar!] = result.ToString();
 endcase

viernes, 10 de octubre de 2014

Pendientes del Live Editing

Estuve la semana pasada en Montevideo con motivo del evento GeneXus 2014 y como siempre quedan muchas cosas dando vueltas por ahí, ideas nuevas, otras no tanto, novedades interesantes y la sensación de que iniciamos nuevamente un ciclo junto a GX.

Ahora les voy a comentar de una de las sorpresas del GX24: el “Live Editing”. Una funcionalidad que podremos ver en la próxima versión de GeneXus, ¿o tal vez antes, en alguna actualización de la Evolution 3?.

De qué se trata el “Live Editing”? Bueno, ni más ni menos que de permitirnos hacer cambios en un objeto y reflejarlos de inmediato en una instancia en ejecución, sin necesidad de build y deploy.


Por ejemplo, puedo estar modificando definiciones en el editor de temas y ver el resultado al instante en los formularios de una aplicación que está corriendo en Tomcat, sin necesidad de hacer build, en algo que parece ser “simplemente” el reemplazo de archivos CSS en el directorio de la aplicación.

Pero es bastante más que eso.

La presentación que vimos iniciaba con algo parecido, pero luego iba a más, derechamente modificando el layout en un panel de una aplicación corriendo en IOS en la que se apreciaba de inmediato el cambio de posición de los elementos. Y para coronar todo, más allá de colores y layouts, pudimos ver un live-editing de un evento de usuario donde el presentador cambió el código y tras un pestañeo la aplicación cambió su comportamiento de mostrar un detalle a mostrar un mensaje.
Luego en la keynote final pudimos ver un ejemplo más impactante: en vez de levantar un popup, ahora pedía tomar una foto y la tuiteaba!


Está muy buena la posibilidad de hacer, o afinar, el diseño con este mecanismo, aunque en lo personal no quiero tener nada que ver con el diseño. Yo preferiría que el diseñador me entregara unos templates html que yo incorporara a la KB y nada más.
También está muy bueno que podamos verificar y corregir el comportamiento de algunos programas sin tener que pasar por el build. En lo personal esto último me importa más.

Pero, bueno, independiente de las preferencias de cada uno, el "Live Editing" contribuirá de buena forma en hacernos más efectivos y productivos con GX.

Por otra parte, sería interesante conocer un poco de en qué se basa la implementación del “Live Editing” en los diferentes generadores. Creo que en general debe tratarse de algunas técnicas de “hot swap” de clases , que consiste en reemplazar las clases cargadas en la máquina virtual (hablando de Java) sin necesidad de reiniciar algo.

miércoles, 17 de septiembre de 2014

Superheroic GeneXus (GX+AngularJS)

He estado experimentando con una idea de pattern, descubriendo algo un tanto obvio: que se trata de una gran cantidad de trabajo!!!

Pero bueno, es mi idea de pattern, ver cómo generar automáticamente una aplicación basada en un template bootstrap que compré por ahí, y estaba en eso, pensando cómo iba a hacer para emular lo de la MasterPage y el ContentPlaceHolder, y me voy dando cuenta que lo ideal era usar otro template que tiene una versión basada en ¡AngularJS de Google!.

https://angularjs.org/

Siempre es bueno descubrir algo nuevo e investigar de qué se trata, así que me puse a leer por aquí, por allá viendo unos videos, de paso me enteré de que hay un Kindle para android, y resultó  que AngularJS pretende ser “lo que HTML debió haber sido”, “HTML mejorado para web apps”, “Superheroic JavaScript MVW Framework”. Lo de MVW me causó gracia.

Básicamente, AngularJS se trata de un conjunto de cosas JavaScript, que permiten, por ejemplo, agregar tus propios tags a la sintaxis HTML y también hacer algo de data binding.

El data binding es la funcionalidad para hacer que un elemento que se muestra en una pantalla esté ligado a un origen de datos, de tal forma que si en los datos hay un cambio de valor, dicho cambio se refleje en la pantalla automáticamente. No es nada nuevo en realidad. Lo interesante es cómo lo implementa AngularJS con templates HTML y objetos JavaScript.


Una forma de data binding en GeneXus es, por ejemplo, cuando ponemos atributos directo en un webform, o en un grid. Nada más es necesario. Sabemos que en la pantalla vamos a ver los valores. Otra forma es cuando cargamos valores en una variable SDT relacionada a un UserControl: el desarrollador se ocupó de lo necesario para que la data se visualize como corresponda, o sea, implementó el data binding.

De vuelta a mi proyecto, estaba en eso de pensar el pattern, construyendo las primeras cosas: templates html, procedures http, business components, data providers y otros, pero nada de webpanels. “Nada de webpanels” estaba diciéndome, pensando cómo lo hago con los eventos y las variables de sesión, y de pronto me salté para otro lado y me imaginé que bueno estaría que GX hiciera el HTML y JavaScript basado en este framework de Google.
Podría ser que estamos frente a un nuevo desafío para ARTech: el reemplazo del actual marco HTML-JavaScript de GeneXus por uno basado en AngularJS.

Con todo lo interesante que me pareció esto de AngularJS y la oportunidad que, a mi modo de ver, representa para GeneXus, también se me hace que este tipo de herramientas, que empiezan a ir en dirección de abstraernos del detalle, de automatizar muchas tareas, también podrían ser vistas como “amenazas”.

Y me vino de vuelta una frase que escuché por ahí: “el mayor problema de GeneXus es que no tiene competencia”. Porque es cierto, no existen competidores directos, que se puedan distinguir con claridad, que ofrezcan la efectividad y productividad que nosotros podemos lograr con GX.
Y es un problema, porque la competencia haría mejor y más fuerte a GX.

martes, 2 de septiembre de 2014

Múltiples condiciones por atributo

A propósito de un pattern que estoy ideando, reparé nuevamente en este asunto y me animé a dejar alguna idea aquí.

Se trata del tema de todos los Where que debemos escribir cuando queremos que la consulta tenga un cierto dinamismo:


Si todo el trabajo lo va a hacer el pattern, no habría de que preocuparse mucho, sean 10 o 50 repeticiones. Pero, claro, ese código no se ve muy "elegante".


A mi me gustaría que tuviésemos una función para usar en conjunto con la cláusula When. Algo así como esto:


La variable a usar estaría basada en un SDT con la estructura necesaria para cargarla con todos los valores y operadores, y esa información se usaría para construir el "where" del query, tal como se hace hoy con las condiciones que incluyen la cláusula When.

Saludos!!!




lunes, 1 de septiembre de 2014

Variables basadas en estructura local

Ando por estos días un tanto creativo, y se me ocurrió dejar este post con un deseable para el editor de variables:



Como se aprecia en la imagen, la idea es que podamos declarar variables basadas en una estructura, y colecciones para usar con las mismas.
Con algo así ganaríamos no tener que definir tantos SDTs que muchas veces sólo se usan puntualmente en uno o dos programas.

Saludos!!!

jueves, 31 de julio de 2014

jqGrid con DataProvider y una idea de pattern


Bueno amigos, aquí estamos con todas las cosas que han estado ocurriendo, todo lo de Smart Devices y ahora la Ev3 con lo de Responsive Web, que me ha dejado atento a lo que hará la gente de DVelop, K2BTools y PXTools con sus respectivos patterns.

En particular, relacionado con lo de jquery-bootstrap-etc, he estado pensando en otra forma de enfocar la generación de la interfaz web, con un nuevo pattern, que directamente generaría HTML y no webpanels GX. Algo parecido a esto seguramente ya lo ha practicado más de alguno: tener un sitio hecho "a mano" que se enganche de alguna forma a programas generados con GX, vía Ajax, por ejemplo.

Para empezar a dar forma más concreta a la idea del pattern, me puse a trabajar en el "canonical example", basándome en una plantilla bootstrap (Ace), tratando en primera instancia de levantar la misma plantilla y enlazar un jqGrid a un DataProvider con paginado.


Así quedó:



La gran tarea aquí es descomponer el diseño original y crear una serie de procedures que retornen el contenido según se requiera.Y a partir de eso ir dando forma al pattern que luego producirá automáticamente los objetos necesarios.


Paso a contarles algunos detalles del ejemplo y en particular de cómo lo hice con el jqGrid.

El programa principal es un procedure Main con Call Protocol HTTP que devolverá todo el html. Podría entenderse como una MasterPage con un navbar, un sidebar y un "ContentPlaceHolder".



El siguiente fragmento corresponde a un procedure que genera contenido de diferentes páginas según una variable "&pageId". En particular en este caso, se incluyen los tags necesarios para la carga del jqGrid en la página "wwproducto".



Luego, en otro procedure se incluyen los scripts. Aquí vemos parte del código que dibuja el grid y el pager en los tags mencionados antes, y el enlace al programa que retorna el json.


Lo más probable es que esto finalmente quede en procedures separados, a ser generados mezclando código de usuario y código automático a partir de la información de la instancia del pattern en los objetos en que se aplique.

A continuación la definición de la estructura a usar para la consulta de datos y carga del jqGrid. En el primer nivel van los parámetros requeridos por el pager, y en la colección los datos solicitados. El pattern debiera generar estas estructuras para cada transaction que se requiera.



El siguiente es el procedure (main, call protocol http) invocado por la jqGrid. Aquí tomamos los parámetros del request, propios de jqGrid (con un poco de csharp), hacemos la llamada al dataProvider y retornamos el json.



 Y finalmente el DataProvider que hace la magia.



Claramente esto es una aproximación al tema y quedan muchos asuntos por ver y resolver. Además de las cosas que pueden cambiar en el camino. Por decir algo: el template que escogí acaban de actualizarlo y esta vez viene con una versión full Ajax.

Se pone interesante.

jueves, 3 de junio de 2010

Scripting con GX Java

Amigos, luego de una -demasiado- larga ausencia, aquí estamos nuevamente para compartir de alguna forma en torno a GeneXus.
Hoy me animo a postear algo sobre el tema de scripting en Java.

Lo de hacer scripts para dejar las aplicaciones con cierto dinamismo, siempre me ha llamado bastante la atención. Al punto que siempre ando buscando en qué poder usar una solución de ese tipo.

Y, así y todo, estaba tranquilo por la vida hasta que -hace unos meses atrás- leí en el foro: "Hola gente, quería saber si es posible agregar algun código Javascript en un procedimiento?".
De inmediato reaccioné con lo de JScriptSrc y JSEvent , y un textblock-raw-html y no sé qué otra cosa que no tenía nada que ver con la pregunta...
Después de un rato me quedó claro que por el lado del cliente no era el tema. Que no era un javascript a ser interpretado por el browser, que tenía que ser server-side y punto!. O capaz que ni se trataba de algo web...

Después de investigar un poco descubrí que había miles de cosas respecto de scripting en el mundo Java y que el mismísimo Javascript se puede usar desde hace un buen tiempo.
No voy a entrar en detalle de las implementaciones que existen, ni de la historia del tema, ni de todos los lenguajes de script que podríamos usar. Sólo les cuento que el scriptengine Rhino viene incluido con Java6 y que para empezar a usarlo bastan una pocas líneas de java embebido en algún programa que hagamos con GX.

Aquí un ejemplo para probar en un procedure.

Primero ponemos algunas funciones javascript en una variable:
&jscript = 'function f1(parm1)' + newline() +
'{' + newline() +
' //aquí el código' + newline() +
'}' + newline() +
'function f2(parm1)' + newline() +
'{' + newline() +
' //aquí el código' + newline() +
'}'

Luego el java para instanciar el scriptengine:
java javax.script.ScriptEngineManager manager = new javax.script.ScriptEngineManager();
java javax.script.ScriptEngine engine = manager.getEngineByName("javascript");


Y luego cargar nuestras funciones javascript e invocar una de ellas:
java try {
java engine.eval([!&jscript!]);
java javax.script.Invocable invocableEngine = (javax.script.Invocable) engine;
java Object ob = invocableEngine.invokeFunction([!&funcionJS!],[!&parm!]);
java [!&out!] = ob.toString();}
java catch(javax.script.ScriptException e){java System.out.println(e);}
java catch (java.lang.NoSuchMethodException e) {e.printStackTrace();}


Las variables &funcionJS, &parm y &out corresponden al nombre de la función, un parámetro y el retorno, respectivamente.

Un problema se nos puede dar con el pasaje de parámetros. En este ejemplo sólo tenemos la posibilidad de pasar uno, y tiene que ser string. Pero si pasamos un string JSON, en el javascript podemos evaluarlo e instanciar un objeto con el que podemos trabajar (podría ser una lista de parámetros, por ejemplo).

Algunas cosas entretenidas que se pueden hacer:
  • usar otras classes java desde un script, por ejemplo conectar a una BD (JDBC)
  • compilar a bytecode java, antes de invocar
  • quién sabe qué más!


Bueno, un saludo a todos y hasta la próxima.-

domingo, 22 de febrero de 2009

Modificando el WorkWith en la XEv1

Primero que nada, para que no se pierda la costumbre y aunque parezca tarde, un feliz y próspero 2009 a los genuxianos de Chile.

Parece que durante el 2008 todos estuvimos bastante ocupados, lo que se tradujo en que no organizamos actividad alguna y ni siquiera escribimos en el blog.
La falta de participación y de entusiasmo, seguramente tiene que ver también con la utilidad que el GUGXChile brinde a los genuxianos en su labor diaria y que hasta ahora no ha sido tal. O sea, falta que esto sea una instancia de colaboración más efectiva.
Puede haber otras cosas, pero ahora quiero ir al motivo del post.


Desde GeneXus 9 contamos con la posibilidad de trabajar con Patterns, que por decirlo de una manera simple se trata de "moldes" o "plantillas" inteligentes con las cuales hacemos automáticamente un montón de trabajo que normalmente haríamos "a mano".

Probablemente el pattern más utilizado es el WorkWith que viene con GeneXus, por lo cual asumo que muchos habrán experimentado un poco creando algunas transactions y viendo como, en segundos, se obtiene una aplicación completa con las pantallas de "trabajar con" y los tabs con vistas según las relaciones dadas por los atributos en las transactions.
A pesar de toda la maravilla, es probable que muchos (fue mi caso) hayan echado de menos alguna forma de control de acceso y permisos y quizás otras cosas más.
¿Por qué ARTech no lo hizo más completo? ¿Será que luego viene otra versión mejorada?
No. La idea es que cada uno haga sus propios patterns y el WorkWith es sólo un buen ejemplo de la potencia de esta herramienta.

ww2
Quise embarcarme en este tema, pero no creando un pattern desde cero, sino que modificando el WorkWith de Artech (GXXEv1 Beta1). A partir de ese trabajo preparé una versión que denominé ww2 y que está disponible en GXOpen.
Esta versión considera:
- Creación de transacciones de Usuarios, Módulos y Permisos.
- Procedimiento de inicialización del usuario admin.
- Procedimientos de validación de accesos y permisos.
- Login en el webpanel Home.
- Adición de rutinas de seguridad en los webpanels generados.

Vista del Login en webpanel Home

La funcionalidad esperada es algo así:
- el usuario sólo tendrá disponibles, en el menú, aquellos módulos para los que está registrado
- en la pantalla de "trabajar con" sólo tendrá disponibles las opciones según permisos (Insert, Update, etc.)
- el usuario podrá tener accesos y permisos individualmente o por formar parte de un grupo de usuarios

Vista del Menu en webpanel Home

Modificar el WorkWith
No pretendo detallar en extenso los cambios, pues sería demasiado largo y la idea es que descubran cosas por si mismos, con un poco de guía, mirando los archivos XML y DKT del ww2.

Modificar el proyecto CSharp
En el caso del WorkWith, los fuentes vienen con el Platform SDK.
Esto es un poco avanzado y orientado a programadores CSharp, más que a usuarios GeneXus.
En el caso del pattern ww2, fue necesario tocar el código csharp para cambiar el nombre de WorkWith a ww2.

Modificar el archivo de recursos
El archivo de recursos es un xml con la definición de los objetos que se consolidan en la KB la primera vez que se aplica el pattern.
Para agregar objetos al archivo de recursos basta con hacer una exportación, abrir el xpz y copiar el elemento Object que nos interesa.
De esta forma agregué las transactions y procedures al archivo de resources del ww2.

Modificar los templates DKT
Los templates DKT son archivos de texto con una programación CSharp embebida que GeneXus interpreta al momento de aplicar el pattern. La ejecución de cada template retorna las partes (Events, Variables, etc.) de los nuevos objetos.
Podría decirse que se trata de una consolidación (importación) especial, no desde un xpz, sino que desde la interpretación de los templates.
En estos templates se puede apreciar con facilidad, por ejemplo, las partes del código GeneXus que son fijas y aquellas que se construyen dinámicamente con la interpretación del csharp.
Un buen ejemplo es el código de la rutina Permissions en el archivo GridEvents.dkt del pattern ww2.

Eso por ahora.

jueves, 10 de enero de 2008

UCPN en Chile !!!

Primero que nada les manifiesto a todos los genuxianos mis deseos de que este 2008 esté re-bueno, que tengamos exito en lo personal y en lo profesional.

Me animé a escribir este post un poco empujado por la envidia que me causa ver cosas que ocurren en otros lados y que ya quisiera ver en Chile. Son ese tipo de cosas que nos llevan a preguntar: ¿Y NOSOTROS CUANDO?. Así mismo, con mayúsculas.

Estaba mirando el sitio técnico de GeneXus y me encontré con un link a una noticia que debe llevar un tiempo ahí (data de Noviembre): Quanta inició la fabricación masiva del laptop XO de la iniciativa OLPC y los primeros países destinatarios son Mongolia y Uruguay!!!


Entre la envidia y la frustración seguí navegando a ver que encontraba relacionado con el tema, y una que estuve mirando un buen rato fue una galería fotográfica de una entrega de laptops en una escuelita uruguaya, en Mayo pasado, creo que en el contexto del plan piloto del OLPC en ese país.

¿En qué estamos los chilenos?. Bueno, por suerte hay alguien que está haciendo algo. Se trata de la campaña de carácter ciudadano UCPN (Un Computador Por Niño).

¿Por qué puede ser que Chile no esté involucrado firmemente en esta iniciativa?
Puede haber razones de tipo técnico, financiera y otras:

- los laptops podrían quedar rápidamente obsoletos (eso pasa con todos los PCs)
- su tecnología no es tan de avanzada como quisiéramos (para escolares es más que suficiente)
- no tienen disco duro (esteeee, ¿y para qué sería?)
- vienen con Linux (entiendo que pronto habrá Windows XP)
- cuestan mucho más que US$100 (el dolar está barato y el cobre sigue alto)
- distorsionarían el mercado (seguramente, para bien del país)
- sería una burda intervención del estado en la educación y la economía (siempre está el problema del sesgo ideológico...)
- se trata de mero populismo (quién podría decir algo así?, desgraciadamente, varios)
- los hijos de familias pobres no sabrían cuidarlos ni usarlos (claro, y son malos desde que nacen...)
- estos niños después van a querer universidad gratis...

Entre estas alternativas algunas son terribles, pero si hay algo que me aterra de verdad es la posibilidad de que no sean esas implicancias las que impidan UCPN en Chile, sino que simplemente nuestros gobernantes no tengan una pizca de visión, que ni siquiera sepan de las posibilidades que pierde el país, que simplemente no se les ocurra pensar o que andan tras los "problemas reales de la gente".

Que tiene que ver esto con el GUGXSCL? Para mí: todo.

Los invito a visitar el sitio http://www.ucpn.cl/ y a buscar alguna forma de apoyar esta causa.

jueves, 14 de junio de 2007

Academia Aprender Haciendo AAH

Desde hace algún tiempo el grupo de usuarios GeneXus Santiago Chile está organizando conjuntamente con INACAP la Academia Aprender Haciendo (AAH).

El objetivo de esta alianza estratégica entre el GUGX Santiago Chile e Inacap es:

Para Inacap: Obtener apoyo para sus alumnos y ex alumnos de esa casa de estudios profesionales en el ámbito de la herramienta Case GX.

Para GuGXSCL: Realizar una de tantas actividades que nos permitan posicionarnos como grupo de usuarios bien constituido, con metas y actividades relevantes en el ámbito que nos compete; dar a conocer la herramienta mostrando (en la medida de lo posible) todas las bondades y beneficios de su utilización y por ende masificar su uso, con todos los beneficios que ello implica para nosotros como profesionales expertos en GX; conocernos e integrarnos como grupo; aprender enseñando; generar lazos y muchos mas.

Hemos distribuido toda la información a los participantes del grupo, indicándoles el cronograma de las actividades que se realizarán durante los 4 sábados que durará la AAH, comenzando el 16 de Junio del 2007 (falta poco).

Mi reflexión respecto a la respuesta que hemos tenido de parte de los integrantes del grupo (hayan participado antes o no) es que algo nos falta para motivarlos. No hemos recibido las respuestas que esperabamos (hablo a título de coordinador de gugxscl en esta etapa). ¿Es que algo no ha quedado claro?, ¿Acaso no se entendió desde el comienzo el objetivo de esta actividad?, ya se había comentado en nuestro primer encuentro y se notó un entusiasmo mayor al que se nota ahora.
Luego se realizará el segundo encuentro del GUGXSCL y la AAH es parte de ello.

Participa, envia tus comentarios, manifiesta tu opinión, solo así lograremos concretar un GUGXSCL al que dé gusto y satisfacción pertenecer.

Tenemos el foro, este blog, el mail de los coordinadores, elije tu opción, te necesitamos!!!.

Un abrazo,
Juan Carlos Báez







viernes, 11 de mayo de 2007

Bienvenidos al blog del GUGX-Chile

Bienvenidos amigos de GX, amigos del GUGX-Chile, todo el mundo.

Voy a partir contándole a los que no sepan (y a los que ya están enterados, da igual) que este blog está dentro del contexto de la iniciativa de crear el GUGX-Chile, que pretende ser una instancia de participación, de discusión, de consulta, de colaboración de los usuarios GX en Chile.

ARTech está impulsando el surgimiento de los GUG, como una forma de fortalecer la comunidad GeneXus (http://www.gxtechnical.com/gug/).

Estamos partiendo con el GUGX desde el 19 de Abril, fecha en que nos reunimos en el Auditorio del Inacap Santiago-Sur (http://picasaweb.google.es/gugxchile), un poco a palpar de qué se trataba esto, de cómo participar y a ver quién llegaba. En esa ocasión se definió un grupo de coordinadores, entre los que me cuento, encargados de darle continuidad a la iniciativa organizando las siguientes actividades.
En esa misma ocasión, gracias al apoyo de Sebastian Agurto, se levantó un foro (http://www.foco.cl/forogx/index.php) que tuvo un inicio bastante movido.

Luego de eso tuvimos un encuentro de coordinadores (no es cerrado, si alguien quisiera asistir alguna vez) y acordamos algunas iniciativas, tales como soportar la continuidad del foro, encuestas para conocer un poco el perfil del desarrollador GX en Chile, iniciar el blog, e ir preparando un segundo encuentro ampliado.



Primera reunión de coordinadores:
Rafael Díaz, Rodrigo Díaz, Juan Carlos Báez y Alejandro Viveros.


En general, la idea es que nos reunamos con cierta periodicidad (una vez al mes, podría ser) a compartir en cualquier actividad y que dos o tres veces en el año hagamos un encuentro más grande, con presentaciones técnicas de interés, por ejemplo: una revisión a fondo a la nueva versión que se nos viene (Rocha, que es un cambio de proporciones) y la siempre necesaria introducción a las aplicaciones web y todos los tips para java y net.

Quién puede participar del blog?
Cualquiera que esté dispuesto a redactar un artículo, un comentario, copiar una foto o un link interesante, poner algunos tips útiles, etc.. Es decir, cualquier usuario GX en Chile que tenga algo que expresar.

Salud, genuxianos!!