estos tres juntos crean un swc --> llamado tambien skin. Por defecto Flex 2 trae uno que se llama haloo.
Pero normalmente se suele llegar solo al css.
Los estilos permiten cambiar el aspecto visual de nuestra aplicación usando las propiedades de estilo de los componentes (UIComponent). Estas propiedades están sujetas al "tema" que se use.
Pueden ser aplicados jerárquicamente o a un componente específico. - Las propiedades de estilo pueden recibir valores en los formatos de Tiempo, longitud y color. - Existe un global Selector relacionado.
Formas de encontrar información de estilo:
-Fichero de estilo externo: Fichero de estilo común enlazado -Definición de estilo local: Definición de estilo común -clase StyleManager: Permite acceder a los selectores de CSS definidos (clases de tipo CSSStyleDeclaration) y modificarlos y manipularlos. -Métodos getStyle() y setStyle): Permiten modificar las propiedades de estilo de un objeto en concreto desde actionscript. -Estilos en línea.
Cascade Style Sheet en Flex (CSS)
-Propiedades y selectores: sintaxis hyphenated (font-color) y camel-case (fontColor). -herencia en CSS: Las propiedades se aplican a las clases padres e hijos -Diferencias con la especificación de CSS:Flex implementa solo una parte en dependencia del tema. -Selectores: Se define el estilo con la propiedad styleName y se puede usar una clase del Framework directamente -Estilos soportados: color, fontFamily, fontSize, fontStyle, fontWeight, paddingBottom, paddingLeft, paddingRight, paddingTp, textAlign, textDecration, textIndent. -Recursos embebidos: backgroundImage
en este link existen varios ejemplos, una vez cargado el ejemplo de aplicacion pulsar boton derecho para ver el source. http://www.adobe.com/devnet/flex/
En este tutorial aprenderás desde cero a obtener datos desde una base de datos en MySQL y a representarlos en un DataGrid de Flex. Desde la configuración de WebORB hasta el código Actionscript 3, hecho fácil.
Para lograrlo:
1. Instalaremos WebORB, como agente de intercambio Cliente/Servidor en formato AMF3, el cual funciona con Flex perfectamente. Gracias a WebORB podremos acceder fácilmente a los Servicios PHP que desarrollaremos para nuestro ejemplo en Flex. 2. Crearemos una base de datos en MySQL muy sencilla, a través de phpMyAdmin para el ejemplo. 3. Escribiremos una clase/servicio en PHP y la registraremos en WebORB. 4. Y finalmente, construiremos una pequeña aplicación en Flex Builder 2, que acceda al Servicio PHP creado, y rellene un DataGrid con los datos recibidos.
NOTA: Si desconoces alguno de los conceptos anteriores, te recomendamos leer estos tutoriales: Tutorial de Flex Builder 2, Tutorial básico de bases de datos, Crear una base de datos MySQL desde cPanel.
Todo esto lo haremos, paso a paso y explicando el porqué de cada cosa, desde los conceptos más elementales, hasta los más avanzados, para que al final del tutorial entiendas perfectamente, qué, cómo y porqué de todo lo que se está manejando. Empecemos por el principio...
Voy a comenzar, explicando los conceptos fundamentales que rigen la filosofía de trabajo Cliente/Servidor que representa RemoteObject.
Estamos acostumbrados a usar archivos de texto, XML, SOAP, HTTPServices, etc, como servidores de datos remotos. Todos ellos se basan en un modelo de representación plano, es decir, la aplicación oyente recibe de sus orígenes un texto plano estructurado, que es parseado y tratado apropiadamente por nuestros algoritmos personales.
Adobe agregó a Actionscript 3 (Y por ende a Flex) el estándar E4X que realmente ayuda mucho en el parseo de este tipo de orígenes, pero aún así seguimos limitados a un procesamiento previo al uso efectivo de los datos, con código adicional en nuestros desarrollos. A esto se suma la perdida del tipo de datos, carencia que deberíamos resolver nuevamente a mano.
Aún con todo, para aplicaciones sencillas suele ser una muy buena opción de uso, ya que no requieren alto rendimiento ni integridad de tipos, cosa que se vuelve fundamental en una aplicación un poco más seria, como sería una Rich Internet Application.
Para salvar esta problemática apareció Flash Remoting, que aportaba un protocolo de transporte de datos en formato binario, al cual llamaron AMF0, pensado para trabajar con ColdFusion como agente de transporte. Este protocolo permitía hacer uso de objetos complejos de una manera cuasi-transparente entre nuestro Flash y los servicios AMF que se ejecutaban en el servidor a través de un agente de transporte que codificaba y descodificaba el protocolo contra las clases servicio que se les registraban, el más famoso y efectivo de la época AMF0 es sin duda AMFPHP para PHP y OpenAMF para Java. En resumen: Permitía transferir objetos y variables entre Flash y un lenguaje del servidor (PHP, Coldfusion, Java) sin que se perdiera el tipo de datos.
Para sacar partido a la ventaja que este protocolo ofrecía, crearon un tipo de objeto en Flash al cual llamaron RemoteObject, el cual permitía ejecutar RPC's (Remote Procedure Call) o sea llamadas a procedimientos remotos en un clase instanciada en el servidor, superando el problema del texto plano y la serialización de datos que hasta entonces sufríamos. Resumen: Un RemoteObject permite invocar funciones escritas en código del lado del servidor y usar su resultado en Flash.
AFM0 evolucionó hacia AMF3 con la llegada de Flex 2, corrigiendo varias carencias que tenía el protocolo original, y mejorando con mucho la velocidad, el peso, el modo en como se transmite la información, y sobre todo unificando criterios de llamada y construcción de clases, al estilo Java para todos los lenguajes que lo soporten.
Una vez sabes que demonios es RemoteObject y AMF3, vamos a ver como instalamos un agente de transporte que implementa AMF3 sobre PHP en el servidor, WebORB.
NOTA: Un agente de transporte es un bloque de código que permite conectar a Flex o Flash con PHP u otro lenguaje del lado del servidor.
WebORB, es la alternativa (gratis y libre) más lograda a la versión de Abobe del protocolo AMF3, el cual es LiveCycle Data Services. LiveCycle solo puede usarse en entornos Java, en cambio WebORB da soporte al protocolo en Java, .NET, PHP y Ruby on Rails, con un rendimiento muy alto y estable. El sistema para configurarlo es idéntico al que usa LiveCycle, con lo cual lo que aprendas ahora para WebORB te valdrá también para LiveCycle.
Esquema de conexión de WebORB
WebORB es la serie de archivos del lado del servidor (En PHP en este caso) que permiten a Flash o Flex conectarse directamente con PHP por medio de AMF3.
Antes de pasar a rellenar xml's como loco para configurarlo y que copies y pegues sin saber realmente que estas haciendo, voy a explicarte como funciona un agente de transporte, para que sepas porqué y para qué son los distintos xml's que tiene en configuración.
Entra al sitio de descarga de WebORB para PHP, descarga el .zip y descomprimelo en la raiz de tu sitio, de modo que todo el contenido del zip quede en www.tusitio.com/weborb/. Esta dirección será la raiz de weborb y a partir de esto empezará el tutorial.
WebORB tiene su carpeta de configuración alojada dentro /Weborb/WEB-INF/ (Buscala dentro de la carpeta donde descomprimiste el .zip). Dentro de ésta se encuentran las clases de PHP, configuración y librerias que requerirá el agente para poder generar el protocolo e incluir nuestras clases personales dentro de las clases usables en despliegue.
En Flex Builder has de indicar la ruta hasta la carpeta WebORB (contenedora de WEB-INF), para encontrar los xml's de configuración a la hora de compilar.
Dentro de /WEB-INF/flex/ la estructura que encontramos es esta:
Los 3 primeros no se usan en WebORB para PHP, ya que hacen referencia a funcionalidades que no se pueden ofrecer en PHP, pero que si tienen soporte en su versión Java y en LiveCycle, el cual presenta la MISMA estructura de configuración. Lo que realmente necesitamos
services-config.xml En este fichero se le indica al agente, que servicios del protocolo va a ofrecer y como se llaman. No lo editaremos en nada, a excepción de un atributo id. Puedes copiar y pegar el siguiente código completo dentro del archivo .xml.
Analicemos su estructura. Lee los comentarios (En verde) para entender el XML
Este fichero era el más complejo, ¿A que no era tan complicado?
remoting-config.xml Éste es el que más tocaremos, de hecho el anterior viene preconfigurado en la distribución y difícilmente necesitaras tocarlo. Este es remoting-config. Lee los comentarios (En verde) para entender el XML.
Y con esto ya sabes que es cada cosa en los xml que hay que tocar, y ademas de camino hemos añadido la configuración para nuestro ejemplo. Notese que la ruta de nuestra clase es relativa a la carpeta /Services/ dentro de la raiz de /weborb/. En esa carpeta /Services/ es donde guardaremos nuestros archivos .PHP de la aplicación. Creamos la Base de Datos
phpMyAdmin: Administrador de base de datos instalado en todos los hosting y servidores con PHP y MySQL.
Entra a phpMyAdmin. Dentro encontramos el panel general, donde se nos ofrece la posibilidad de crear una nueva base de datos. Ahí le damos el nombre a nuestra DB (Base de datos), y especificamos con cuidado el cotejamiento y el charset, de modo que sea utf8_unicode_ci, dado que Flex usa esa codificación de caracteres, y ademas nos aseguramos la compatibilidad con cualquier cliente de otros paises. Ponle cualquier nombre a la DB.
Con la nueva DB creada, entramos al panel de administración de tablas. En esta pantalla creamos nuestra tabla de ejemplo, con esta sencilla especificación:
* Nombre de la tabla: user * Campos: 2 o campo: id o tipo: int, auto_increment, primary_key
o campo: name o tipo: VARCHAR(255), charset: utf8
Con esta estructura, ya tenemos nuestra tabla lista para trabajar, no olvides llenarla de datos para tener algo que mostrar ;)
Si no quieres usar phpMyAdmin, este código en SQL genera la base de datos:
CREATE TABLE `user` ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , `name` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL );
Construimos las clases para comunicar en PHP y Actionscript 3.
Crearemos dos clases que definirán la estructura de los datos que recibimos entre PHP y Actionscript 3. Estas clases se conoces como tipos complejos de datos. Para mantener este tipo complejo correcto tanto en nuestro Flex como en nuestro PHP, nos creamos dos clases gemelas, una en AS3 y la otra en PHP, de manera que lo que enviemos por PHP sea recibido identido en AS3. Para ello, indicamos en Actionscript 3 con el metatag [RemoteClass(alias=””)] donde está su pareja AMF3 escrita en PHP.
RECUERDA: PHP es el lenguaje del lado del servidor que se conecta a MySQL. Actionscript 3 es el lenguaje del lado del cliente que muestra los datos en Flex. AMF3 es el protocolo de comunicación entre PHP y Actionscript 3 que en AS3 ya está programado internamente y en PHP lo implementamos usando las librerías WebORB para PHP. En otras palabras, AMF3 es, para efectos practicos, WebORB Código en Actionscript 3
Creamos un archivo llamado UsuarioVO.as, que colocaremos en la misma carpeta raiz del proyecto de Flex (Donde está el .mxml).
package
{
[Bindable]
[RemoteClass(alias="flex.morphx.UsuarioVO")]
public class UsuarioVO {
public function UsuarioVO() {
}
public var name:String = ""; } }
Este objeto tiene una propiedad "name" y nada más. name será el nombre de usuario a mostrar en el DataGrid, que es el campo de contenido de nuestra tabla. Este valor será llenado por medio de PHP. Código en PHP
Versión de PHP WebORB requiere obligatoriamente, PHP 5.
Crearemos nuetro fichero PHP en /Services/flex/morphx/UsuarioVO.php nota que la ruta de carpetas coincide con la ruta de la clase que indicamos en el XML, de ese modo AMF3 es capaz de encontrar nuestra clase PHP, y replicarla correctamente. De esto se deduce que las mayusculas y minusculas en los nombres de las carpetas ha de coincidir plenamente con la ruta indicada antes. En programación es muy importante mantener mayusculas y minusculas de manera exacta.
class UsuarioVO {
public $name;
public function UsuarioVO() {
}
} ?>
Si os fijáis es un objeto que tiene exactamente la misma estructura que nuestro UsuarioVO.as, y de hecho sus propiedades han de llamarse exactamente igual, incluso manteniendo el mismo uso de mayusculas y minusculas.
ValueObject: Esta combinación de clases gemelas en PHP y Actionscript 3, cuyo objetivo es mantener un mismo tipo de datos entre lenguajes, se conoce como ValueObject. Clase en PHP de conexión a MySQL. Servicio.
Vamos a crear ahora una clase servicio en PHP para nuestro ejemplo, ubicala en la misma carpeta que el PHP anterior.
Nota: Las carpetas de clases en programación se conoces como paquetes. La clase anterior tendría como su paquete a "flex.morphx"
La llamaremos UsuarioService.php, y será ésta la clase a la que nos conectaremos desde Flex, en la cual podremos usar sus metodos, por tanto es ésta la clase que hemos de asociar al “destination” en la configuración de WebORB, como vimos antes (El XML). Lee los comentarios del código (En verde) para entender su funcionamiento.
require_once ("UsuarioVO.php"); //Importamos nuestro objeto de transporte, nuestro ValueObject
class UsuarioService {
public function UsuarioService() {
}
//Nuestro metodo a llamar public function getUsuario() {
//Cabecera de conexión a la BD //DEBES CAMBIAR LOS VALORES de "SERVER", "USER" y "PASS" de acuerdo a tus datos //de conexión a tu base de datos. $sqlconnect = mysql_connect("SERVER", "USER", "PASS"); $db = "DBNAME"; //DEBES CAMBIAR "DBNAME" por el nombre de tu base de datos.
if (!$sqlconnect) throw new Exception("No fue posible conectarse a MySQL");
if (!mysql_select_db($db)) throw new Exception("No se puede seleccionar la base de datos $db");
//Ejecutamos la consulta SQL para obtener todos los registros de la tabla $rst = mysql_query("SELECT * FROM USER");
if (!$rst) throw new Exception("Error en la consulta SQL");
$respuesta = array (); //Array de datos a devolver. //De este modo nuestro ArrayCollection en Flex, //tendrá una serie de objectos con la propiedad "name" //para pasarle al DataGrid
while ($row = mysql_fetch_object($rst)) //Tomamos record a record y lo encapsulamos //en nuestro objeto de transporte { //Creación de los Objetos de Transporte $vo = new UsuarioVO(); //Le añadimos a nuestro ValueObject el nombre obtenido de MySQL $vo->name = $row->name;
//Añadimos a nuestro array el ValueObject creado $respuesta[] = $vo; }
//Devolvemos el resultado hacia Flex return $respuesta; } } ?>
Y finalmente construimos nuestro ejemplo Flex. Código MXML en Flex
Ahora definimos nuestro MXML en Flex desde el que llamaremos a nuestro servicio PHP.
RemoteObject: Un RemoteObject es un tag de MXML que permite conectarse a un servicio PHP configurado con WebORB.
Aclaremos cuales son los principios de una llamada a través de un RemoteObject. Una llamada de éste tipo, es por definición “asíncrona”, es decir, tenemos que pedir al RemoteObject la ejecución del procedimiento que necesitemos y luego “esperar” a que el servicio nos conteste, y para ello es imperativo el delegar esa espera a un listener (Un manejador de evento), para avisarle al usuario que los datos están cargando y cuando están cargados. Visto lo anterior, se entiende que una llamada a un método remoto implica 3 acciones:
* La llamada al método en sí. * Un evento “result” que entrega un ResultEvent, y es lanzado cuando nos llegan los datos. * Un evento “fault” que entrega un FaultEvent, y es lanzado en caso de obtener un error en el proceso.
Por lo tanto el tratamiento de los datos esperados tras una llamada tipo “servicio.getUsuario()” donde "srv" es el id de nuestro RemoteObject en Flex, no puede hacerse en la línea siguiente a ella, sino que se hará en una función a parte que será lanzada por el evento “result” y que nos pasará por parámetro un ResultEvent con los datos recibidos y lo salvaremos en un ArrayCollection. ArrayCollection es un tipo de datos de Flex que nos encapsula un Array, con una serie de metodos de manejo que nos permiten un gran numero de operaciones avanzadas sobre la "colección" de datos, tales como: Filtros, Cursores, Ordenaciones, etc. Por ello recogemos los datos en un objeto de este tipo, que actuará como DataSet.
[Bindable] private var usuarios : ArrayCollection;
//Esto lo hacemos para forzar al compilador //a incluir la clase UsuarioVO en el swf de salida, //de modo que reconozca los objetos recibidos desde WebORB. private var forceimport:Array = [UsuarioVO];
private function onResult(event:ResultEvent):void{ usuarios = ArrayCollection(event.result); //Es necesario convertir el "result" a un ArrayCollection (Eso se llama hacer cast) //Asignamos al ArrayCollection, //la colección de objetos de //transporte recibidos desde WebORB. }
Ahora tan solo nos queda dar de alta en /Weborb/WEB-INF/flex/remoting-config.xml nuestro “destination” tal y como vimos antes, para que el compilador de Flex encuentre la clase remota a llamar a la hora de generar nuestro swf, para ello incluiremos en dicho fichero el siguiente segmento de código (Si ya lo hiciste antes en la configuración, no necesitas duplicarlo):
flex.morphx.UsuarioService
Ya tenemos todo, ahora solo queda compilar en Flex y probarlo. No olvides enviar tus preguntas al foro de Flex y Actionscript 3 o al de WebORB.
Este es el primer problema que me surgió cuando instalé el Flex Builder 3. Por defecto trae como opción de control de versiones el CVS. Lo que no está mal, ya que al ser open source es una excelente opción.
Pero si les pasa como a mí y necesitan usar el mismo estándar en toda la empresa (el VSS, en mi caso), la cosa se complica.
Este mismo problema ya había surgido con la versión anterior de Flex Builder 3, el Flex Builder 2, donde la solución era instalar un plugin, el Java Developer Tools, y luego el del VSS. Pero este mismo método no me funcionó, porque no pude encontrar el plugin de Java entre los plugins que me ofrecía Flex Builder 3.
Mi solución fue optar por trabajar con Eclipse 3.3 y el plugin de Flex (que me costó bastante encontrar, link abajo). Luego de descargar ambos, instalé el plugin de VSS y todo anduvo de mil maravillas.
Pero como me quedé con ganas de usar Flex Builder 3 (por que no me quería dar por vencido, hasta donde sé, Flex Builder 3 y Eclipse son funcionalmente idénticos), copié todos los plugins que tenía en el Eclipse y los pegué (sin reemplazar nada) en la carpeta de plugins de Flex Builder 3.
Y funcionó, sin mayor problema. Lo único malo es que debería haber probado copiar los plugins uno por uno para ver cuál era exactamente el que tenía que copiar en un principio.
Conclusión: Si, como yo, se ven en la necesidad de usar el VSS, opten por Eclipse. Es más práctico.
* Descargar Elipse 3.3.2 * Descargar el plugin de VSS para Eclipse
Descargar el plugin de Flex 3 es más complicado y requiere estar registrado en Adobe. Lo que tienen que hacer es ir a adobe.com/downloads, seleccionar Flex 3 en las opciones y descargarlo. Por las dudas el link a la página de descarga, una vez logueados es esta.
VSS (SourceSafe), CVS y SVN (SubVersion) son software de control de versiones. Muy útiles y a mi parecer indispensables en proyectos donde más de un desarrollador participa. Permite entre otras cosas llevar historial de los cambios hechos al proyecto en cada uno de sus ficheros.
No he usado SourceSafe, no puedo dar mi opinión, pero si he estado usando con mi equipo CVS y SVN SubVersion y con el cambio a Flex 3 tambien tuvimos un par de dolores de cabeza para instalar el plug-in de SubVersion, algo parecido a lo que cita HernanRivas en este post Les dejo los pasos para instalar el plug-in en Flex Builder 3 de SubVersion:
* Help Menu * Software Updates * Find and Install * Search for New Features to Install * Click en Europa Discovery Site * Escoger un Mirror * Exapndir Europa Discovery Site * Exapndir Java Development * Seleccionar lo siguiente: o Eclipse plug-in development Environment (PDE) o Java Development Tools (JDT)
* Aceptar los términos y reiniciar Flex Builder 3
Luego se sigue el mismo proceso hasta "Search for New Features to Install",
* New Remote Site: * Se agrega el sitio "Subversion" (o el nombre que se desee) y la url http://www.polarion.org/projects/subversive/download/eclipse/2.0/update-site/ * Se agrega el sitio "Conectores" (o el nombre que se desee) y la url http://www.polarion.org/projects/subversive/download/eclipse/2.0/update-site/ * Escoger un mirror si no está automático. * Expandir "Conectores" Seleccionar el paquete Subversive Connectors. * Expandir "Subversion" Seleccionar el paquete Subversive (Incubation).
Con esto queda listo el plug-in. Otro pequeño tip, si están detrás de un proxy-firewall deben darle acceso al puerto 3690 para poder trabajar con SVN.
Un buen host de control de versiones es www.assembla.com; para los que quieren empezar teniendo un servidor SVN remoto para proyectos privados, tiene una muy buena opción gratuita; y si el proyecto es abierto obviamente esta el Señor Google con code.google.com/hosting/. Y obviamente también pueden instalarlo localmente, más información.
* Versiones anteriores * ActionScript 3.0 se basa en ECMAScript * Máquina virtual de ActionScript (AVM) * Metas de ActionScript 3.0 y características
ActionScript 3.0 es un lenguaje de programación de gran alcance, orientado a objeto que significa un paso importante en la evolución de las capacidades de desarrollo en las aplicaciones. La motivación que conduce ActionScript 3.0 es crear una lengua ideal para crear Aplicaciones Ricas de Internet, que se han convertido en una parte esencial en las aplicaciones de Internet.
Versiones anteriores de ActionScript ofrecieron la energía y la flexibilidad requeridas para crear experiencias en línea muy completas. ActionScript 3.0 ahora fomenta avances en el lenguaje, proporcionando un funcionamiento magnífico y la facilidad de desarrollo para facilitar el uso altamente complejos, datasets grandes, y código orientado a objeto, basa reutilizable. Con ActionScript 3.0, los desarrolladores pueden alcanzar productividad y funcionamiento excelentes con el contenido y los usos que apuntan al usuario.
ActionScript 3.0 se basa en ECMAScript, el lenguaje de programación estandarizado internacional para scripting. ActionScript 3.0 es obediente con la especificación de la lengua de ECMAScript, tercera edición (ECMA-262). También contiene la funcionalidad basada en trabajo en curso sobre la edición 4 de ECMAScript.
ActionScript es ejecutado por la máquina virtual de ActionScript (AVM) construida en el Flash Player. AVM1, la máquina virtual usada para ejecutar el código de ActionScript de la herenciael poder de Flash Player hoy hace posible una amplia gama de medios interactivos y de usos ricos del Internet.
Sin embargo, los desarrolladores han comenzado a empujar AVM1 a sus límites; sus requisitos del proyecto ahora exigen una brecha importante. ActionScript 3.0 introduce una máquina virtual altamente optimizada nueva de ActionScript, AVM2, que excede dramáticamente el funcionamiento posible con AVM1. Consecuentemente, el código de ActionScript 3.0 ejecuta hasta 10 veces más rápidamente que el código de ActionScript.
La máquina virtual nueva AVM2 está disponible en el Flash Player 9, y será la máquina virtual primaria para la ejecución de ActionScript. El AVM1 más viejo continuará siendo apoyado por Flash Player para la compatibilidad con las aplicaciones nuevas.
Hay numerosos productos que generan el contenido y los usos apuntados en el tiempo de pasada de destello del jugador. Estos productos incorporan a menudo ActionScript para agregar interactividad y comportamiento a sus aplicaciones. En la familia de productos de Adobe, los diseñadores y los desarrolladores profesionales pudieron utilizar ActionScript dentro de varias herramientas como flash, flex, etc. La familia de producto de flex, será la primera línea de productos para tener acceso a las nuevas capacidades de ActionScript 3.0. Metas de ActionScript 3.0 y características
ActionScript 3.0 se diseña para tratar las metas siguientes:
* Seguridad: El lenguaje soporta tipos de seguridad para que los desarrolladores puede escribir código inequívoco, fácilmente conservable. * Simplicidad: El lenguaje es bastante intuitiva para que los desarrolladores puedan leer y escribir programas sin constantemente consultar un manual de referencia. * Funcionamiento: El lenguaje permite a los desarrolladores escribir programas complejos y que estos funciones eficientemente. * Compatibilidad: ActionScript 3.0 es un dialecto de ECMAScript que formaliza las características de ActionScript 2.0, agregue las capacidades de ECMAScript para XML (E4X), y unifique el lenguaje.
Ampliando el artículo anterior sobre la generación de charts, voy a recomendar también algunas herramientas o APIs que he utilizado en la generación de informes de mis aplicaciones: