electroduendes.com

bitácora de un desarrollador interactivo

electroduendes.com header image 1

Material charla Realidad Aumentada Subflash

November 26th, 2009 · 3 Comments

Por aquí os dejo el material de la charla sobre Realidad Aumentada que ofrecí en los talleres Subflash 2009. Os dejo el código fuente que usamos como ejemplo de implementación con el que podréis crear vuestra propia aplicación de Realidad Aumentada así como la presentación de la charla, y las clases que nos sirvieron como introducción a Papervision3D.

Papervision3D y Realidad Aumentada (rar)

→ 3 CommentsTags: Actionscript 3.0 · Eventos, charlas · Experimental · Flash

AS3: Composición, paso de parámetros por valor y por referencia

October 7th, 2009 · 2 Comments

En este post hablaré sobre algo muy básico aunque imprescindible sobre teoría de clases y composición aplicados a as3. Con él podemos entender la manera en que es tratada la composición de clases (una clase contiene otra clase como atributo) y los conceptos de paso de variables a métodos por valor y por referencia.

El paso de parámetros por valor, se utiliza en programación para realizar una copia del valor del objeto cuando es pasado a través de la invocación de un método. Es decir, al llamar a un método de una clase que requiere un objeto, realizo una copia de dicho objeto. Si dentro de la clase, modifico ese objeto, los cambios no son propagados fuera de la clase.

El paso de parámetros por referencia, pasa “un puntero del objeto”, es decir, de alguna manera estamos pasando el objeto, y si dicho objeto es modificado dentro de la propia clase, sus cambios serán propagados fuera de la misma.

Hay lenguajes que permiten definir el método de paso de variables (referencia o valor), como es el caso de C++. En Actionscript, de momento no podemos pasar por valor de manera nativa, aunque nuestro método siempre puede hacer una copia internamente del argumento recibido para no modificar el original. En Actionscript 3, el paso de parámetros, siempre se realiza de la misma manera:

  • Las instancias de clases son pasadas por referencia
  • Los tipos primitivos se pasan por valor

Si estás aprendiendo Actionscript 3 y has llegado hasta aquí, te recomiendo que analices a fondo este código, puesto que puede resultarte muy esclarecedor para entender este concepto tan básico como fundamental sobre la orientación a objetos.

Primero, definimos dos Clases, ClaseA y ClaseB. ClaseB está compuesta por un atributo, atributoB que es de tipo Number.

package
{
	public class ClaseB
	{
		public var atributoB:Number;	
		public function ClaseB()
		{
		}
	}
}

ClaseA tiene otro atributo de tipo ClaseB. Estamos hablando por tanto, de una relación de composición entre las dos clases.

package
{
	public class ClaseA
	{
		public var atributoA:ClaseB;
		public function ClaseA(atributo:ClaseB){
			atributoA = atributo;
		}
	}
}

Ahora nuestra clase principal. Nótese cómo atributoB devuelve el mismo valor independientemente del lugar desde donde es modificado (es el mismo objeto) y cómo esto no sucede con tipos primitivos. En este caso paso un parámetro al constructor de la clase ClaseA (nuestro objeto de tipo ClaseB), para posteriormente modificarlo desde diferentes ámbitos y trazar los resultados.

package {
	import flash.display.Sprite;
 
	public class ReferenciaValorTest extends Sprite
	{
		/**
		 * @autor Alejandro Sánchez
		 * http://www.electroduendes.com/blog/
		 * */
		public function ReferenciaValorTest()
		{
			var b:ClaseB = new ClaseB();
			b.atributoB = 10;
			trace(b.atributoB) // OUTPUT: 10
 
			var a:ClaseA = new ClaseA(b);
			trace(a.atributoA.atributoB) // OUTPUT: 10
 
			a.atributoA.atributoB = 5;
			trace(a.atributoA.atributoB) // OUTPUT: 5
			trace(b.atributoB) // OUTPUT: 5
 
			b.atributoB = 10;
			trace(a.atributoA.atributoB) // OUTPUT: 10
			trace(b.atributoB) // OUTPUT: 10
 
			var c:Number = 20;
			a.atributoA.atributoB = c			
			trace(a.atributoA.atributoB); // OUTPUT: 20
			trace(b.atributoB); // OUTPUT: 20
			trace(c); // OUTPUT 20
 
			c = 30;
			trace(a.atributoA.atributoB); // OUTPUT: 20
			trace(b.atributoB); // OUTPUT: 20
			trace(c); // OUTPUT 30
 
		}
	}
}

→ 2 CommentsTags: Actionscript 3.0 · Flash · Metodología, arquitectura · Tutos

Triángulo de Penrose

October 5th, 2009 · No Comments

El triángulo de Penrose, es un objeto imposible que fue creado en 1934 por el artista sueco Oscar Reutersv?¤rd. Posteriormente fue redescubierto de forma independiente por el físico Roger Penrose, en la década de 1950, quien lo hizo popular, describiéndolo como “imposibilidad en su más pura forma”.

Fuente: Wikipedia

penrose
Pulsa en la imagen para lanzar el experimento

Triángulo de Penrose

El juguete visual está escrito en Actionscript 3 y Papervision3D. El autor del modelo SketchUp es Martin Triebel. Con el artefacto, intento abrir una puerta racional al triángulo de imposibilidad, a través de un juego de interacción, en la idea de que no existe una realidad absoluta, sino meras interpretaciones, ahí queda eso.

Resulta generacional la atención que la gente tiene sobre esta figura, y su repercusión en camisestas, fieltros, esculturas de rotondas y portadas de libros. Desde icono pop hasta figura del op art, este símbolo seguirá sorprendiendo a generaciones y perpetuándose como un ejemplo del escepticismo creativo radical.

→ No CommentsTags: Actionscript 3.0 · Experimental · Flash

Nuevos aires, nuevos objetivos

October 5th, 2009 · No Comments

Antes de nada. Avisaros que no voy a anunciar un cambio de trabajo. El cambio de aires será esta vez para el blog.

Los que estéis suscritos a mi feed, os habréis dado cuenta que he estado actualizando algunos posts antiguos. El motivo es que estos días he estado ocupado en dar a este blog un nuevo aire. Así que me he calzado algunas entradas de poco interés, he actualizado las entradas técnicas para que no quedaran obsoletas, y migrando los post sobre opinión/artículos a mi otro blog.

Lo cierto es que el blog se estaba convirtiendo en un compendio de artículos de opinión y sobre publicidad y marketing, mezclados con posts sobre código, entradas off-topic, enlaces sobre diseño… El blog era como un traje de retales, cada uno de su padre y de su madre: demasiado heterogéno y puede que a pocos llegara a abrigar del todo. Dicen que el que mucho abarca poco aprieta.

Así que mi propósito de este año lectivo hacia este blog es redirigir la temática que encontraréis a partir de ahora, que será principalmente técnica. En este blog se hablará de arquitectura, metodología y programación web, centradas en el lenguaje Actionscript, aunque probablemente toque otros lenguajes, así como cuestiones sobre diseño weby prototipado . El tono de las entradas intentará ser más directo, orientado a cubrir a fondo los detalles técnicos, intentando cuidar la didáctica y la claridad. Dejaré a un lado opiniones y artículos que no versen sobre esta materia.

No estoy diciendo que dejaré de opinar, criticar o de aplaudir. Tampoco digo que dejaré de hablar de Marketing o de Publicidad On-line. Lo que quiero decir es que lo dejaré de hacer en este blog.

Y con la esperanza de que ésta sea mi última entrada no técnica en este blog y de que todos mis propósitos se vean cumplidos junto a vosotros, os doy la bienvenida a esta nueva etapa.

→ No CommentsTags: Personal

removeChild y ArgumentError: Error #2025: no más dolores de cabeza

July 1st, 2009 · No Comments

Como muchos de vosotros, estoy continuamente utilizando los métodos addChild y removeChild de DisplayObjectContainer.

Gracias a Dios con la llegada de as3 llevo un tiempo sin sufrir los tediososos attachMovie y createEmptyMovieClip, que resultaban a veces confusos.

El nuevo árbol de herencia de los objetos de visualización es ahora realmente orientado a objetos y muy completo, y es algo que agradecí al migar de as2 a as3.

Con el método addChild, no tengo pegas, pues me parece necesario identificar sobre qué padre vamos a incluir el DisplayObject que estamos creando.

Pero para el método removeChild, cuando estoy eliminando un Sprite, pues realmente no interesa saber cual es el padre, lo que realmente interesa, es eliminarlo y punto.

De hecho, yo tiendo a hacer lo siguiente:

miMc.parent.removeChild(miMc)

Se me ocurrió hace poco que una clase para eliminar Sprites sería útil, algo como un Terminator de DisplayObjects

DisplayObjectTerminator.remove(miMc)

Esta clase, encapsularía este comportamiento y además evitaría problemas tales como que el objeto a elminar exista, que no sea nuloâ?¦ etc etc.

Y antes de ponerme a escribir, googleé un poco y encontré una clase bastante útil para estos menesteres que comparto con vosotros:

http://www.actionscript.org/forums/showthread.php3?t=178317

/**
 * written by evride //
 * Actionscript.org forums user //
 * found a problem? tell me there //
 */
package com.evride{
	public class RemoveObject {
		public static  function remove(obj:Object) {
			if (obj) {
				if (obj is DisplayObject) {
					if (obj.parent) {
						try {
							obj.parent.removeChild(obj);
						} catch (e:Error) {
							trace("Couldn't remove the object. It wasn't a child of a DisplayObject.");
						}
					} else {
						trace("Couldn't remove object. Parent property is null.");
					}
				} else {
					trace("Couldn't remove object. It is not a DisplayObject.");
				}
			} else {
				trace("Couldn't remove the object. It was null or doesn't exist.");
			}
		}
	}
 
}

→ No CommentsTags: Actionscript 3.0 · Flash

Talleres de verano de SubFlash 2009

June 18th, 2009 · 1 Comment

Ya están aquí un año más los talleres de verano de Subflash, donde un grupo de 50 personas de nuestro gremio y más concretamente todo lo que rodea a Flash, se reunen para compartir experiencias, impartir charlas y por qué no, tomar unas cañas y pasar un buen rato juntos.

Después de haber asistido a cuatro ediciones, te puedo afirmar que si perteneces a este gremio como diseñador o desarrollador, y además tienes la suerte de compartir trabajo y afición o sentir pasión por este mundo, no dejes de asistir este año.

Os copio-pego los detalles que hay en la web (http://www.subflash.com/talleres/2009/php/index.php), donde también podrás inscribirte y obtener más info:

lugar
los talleres de 2009 este año tendrán lugar de nuevo en Alicante, en la Villa Universitaria en San Vicente del Raspeig. la Villa Universitaria es un moderno complejo que cuenta con magníficas instalaciones y todos los medios necesarios para poder desarrollar todas las actividades.
Villa Universitaria
Avda. Vicente Savall, 16
03690, San Vicente del Raspeig
Alicante

fechas

viernes 28, sábado 29 y domingo 30 de Agosto de 2009.

precio

100 â??¬ por persona en modalidad de asistencia completa*, que incluye el alojamiento del viernes y sábado, además de la cena del viernes, pensión completa del sábado y desayuno y comida del domingo.
la modalidad oyente es totalmente GRATUITA, aunque los asistentes que se deseen quedar a comer o cenar, tendrán que abonar el precio de sus consumiciones individuales, al precio que marque el lugar.

Plazas disponibles
Aproximadamente 50 plazas disponibles en modalidad de asistencia completa*.

Instalaciones
habitaciones individuales
baño individual
internet en habitaciones por conexión RJ-45 (llevar cable)
cada dos habitaciones antesala con nevera, cocinita y microondas
tv y zonas comunes
sala de 18 ordenadores con conexión a Internet
piscina, padel y pista de fútbol sala
sala de conferecias totalmente equipada
aparcamiento gratuito

→ 1 CommentTags: Enlaces · Eventos, charlas

Tendremos vídeo para rato

May 10th, 2009 · No Comments

Los desarrolladores Flash llevamos desde el 2002, la asidua tarea de trabajar con estos formatos. Por eso, en la parte cliente, se hace necesario el uso de un conjunto de clases que manejen esta labor, y que nos permita tener vídeo para rato sin morir en el intento cada vez que hay que aplicarlo a un proyecto.

Gracias a todos, ( y espero participar en ello pronto) cada día tenemos más proyectos hacia este? área? en la comunidad de desarrollo libre o de pago, y? ya existen soluciones para la creación de players. Incluso existen players de licencia libre que cubren varias funcionalidades, de hecho hay un sano mercado en torno a los players, copado actualmente por JW FLV Media Player, un player bastante completo.

Pero si estamos empeñados en añadir las clases a nuestro repositorio reutilizables para todos los proyectos de tu empresa,?  la tarea de crear un player crece en dos sentidos: el primero crear los componentes de interacción, que si bien algunos ya puedes tenerlos creados o reusarlos, y segundo, conocer las diferentes particularidades de la api de gestión de vídeo en flash para aplicar la funcionalidad a los controles visuales, que dependerá del tipo de vídeo y el total de los que vamos a meter.

En realidad, se trata de un trabajo de semanas partiendo desde cero. Son por sí mismo un subproyecto, o al menos un buen sprint en un desarrollo. A nivel de interacción, los players se deben tratar con cariño, puesto que demandan funcionalidades avanzadas de los usuarios acostumbrados a players de gran consumo, como youtube. Se debe trabajar bien con el seeker para dotarle del mayor número de funcionalidades posible, puesto que cuanto más bueno o largo es el vídeo, más vamos a utilizar este componente.

Para empezar, no está mal echar un vistazo a otros players famosos en Internet.?  Debemos poner interés en añadir funcionalidades tales como añadir alias de teclado como la pausa para el espacio. También es interesante el retroceso del vídeo por click de la barra,?  o avance en caso de que dispongamos de servidor rtmp o tecnología que lo permita. La visualización del vídeo mientras se arrastra la barra será motivo de otro post, y no deberíamos olvidar.

Este desarrollo es buena práctica para aprender la creación y despachado de eventos personalizados porque realmente te puedes hinchar a usar y crear eventos.? Recomiendo separar para ello el código en una clase Player que se encargue de manipular el stream de red y enviar los eventos de usuario necesarios, y un conjunto de clases para el manejo de la interfaz, tales como sliders, buttons, loaders y seekers. Un patrón MVC también es interesante para montar toda la interacción entre clases y por si piden cambiar el skin para adaptar a otros proyectos e incluso en el mismo proyecto.

La parte más aburrida de esta tarea, la podemos simplificar con el uso de la clase Pyro Player que ha creado Turbulent.

var pyroInstance:Pyro = new Pyro(320, 240);
addChild(pyroInstance);
pyroInstance.play("http://myvideosite.com/videos/gratton.flv");

Tras un uso en varios proyectos, puedo afirmar que simplifica bastante la tarea, aunque el diálogo entre esta clase y los controles no te lo quita nadie en? ningún? proyecto a menos que obligues a tus diseñadores ? a que usen los mismos controles en todos los players, o inviertas más tiempo todavía en parametrizar esta opción en tu triada.

Tengo que dar gracias a mi colega Diego por descubrirme esta clase. Como agradecimiento hacia este intercambio de conocimiento tan saludable, os recomiendo a todos también? MySimpleMp3, una clase similar para reproducir mp3?´s.

audio.url = "http://mydomain.com/music.mp3";
audio.play();
audio.pause();
audio.stop();
audio.volume = 0..1;
audio.panning = -1..1;

Los que habéis llegado hasta aquí y os interese este post desde la perspectiva de la publicidad, os remito a esta entrada en mi otro blog.

→ No CommentsTags: Actionscript 3.0 · Enlaces · Librerías, recursos · Metodología, arquitectura

Procesado de imágenes en Java II

July 24th, 2007 · 6 Comments

Javier Murillo me manda una mejora para la clase ImageUtils que publiqué en la entrada procesado de imágenes en Java. Es una alegría saber que otros desarrolladores trabajen con el código que publico, y que, como en este caso, se interesan por mejorarlo y reenviarlo. Gracias Javier!

package es.gaea.utils;
 
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import org.apache.log4j.Logger;
 
/** Clase que implementa un procesador para imagenes y juguetear con ellas */
public class ProcesadorImagenes {
 
	/** Logger de la clase */
	private static Logger logger = Logger.getLogger(ProcesadorImagenes.class);
 
	/** Opciones de renderizado para las imagenes */ 
	private RenderingHints opciones = new RenderingHints(null);
 
	/** Constructor de la clase */
	public ProcesadorImagenes() {
 
		// Cargo las opciones de renderizado que me apetezcan	
		opciones.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		opciones.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
		opciones.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
		opciones.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
		opciones.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
		opciones.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
		opciones.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
		opciones.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
	}
 
	/** Devuelve la lista de formatos disponibles a leer por ImageIO	
	 * @return un array de strings con los mismos.	
	 */
	public String[] dameFormatosUsables(){
 
		return ImageIO.getReaderFormatNames();
	}
 
 
	/** Calcula el factor de escala minimo y en base a eso 
	 * escala la imagen segun dicho factor.	
	* @param nMaxWidth maximo tamaño para el ancho
	* @param nMaxHeight nmaximo tamaño para el alto	
	* @param imagen Imagen que vamos a escalar
	* @return Devuelve la imagen escalada para poderla trastocar o null si hay error
	*/
	public BufferedImage escalarATamanyo(final BufferedImage imagen,
			final int maximoAncho, final int maximoAlto) {
 
		// Comprobacion de parametros
		if (imagen == null || maximoAlto == 0 || maximoAncho == 0) {
			return null;
		}
 
		// Capturo ancho y alto de la imagen 
		int anchoImagen = imagen.getHeight();
		int altoImagen = imagen.getWidth();
 
		// Calculo la relacion entre anchos y altos de la imagen
		double escalaX = (double)maximoAncho / (double)anchoImagen;
		double escalaY = (double)maximoAlto / (double)altoImagen;
 
		// Tomo como referencia el minimo de las escalas
		double fEscala = Math.min(escalaX, escalaY);
 
		// Devuelvo el resultado de aplicar esa escala a la imagen
		return escalar(fEscala, imagen);
	}
 
 
	/** Escala una imagen en porcentaje.
	* @param factorEscala ejemplo: factorEscala=0.6 (escala la imagen al 60%)
	* @param srcImg una imagen BufferedImage
	* @return un BufferedImage escalado
	*/
	public BufferedImage escalar(final double factorEscala, final BufferedImage srcImg) {
 
		// Comprobacion de parametros
		if (srcImg == null) {
			return null;
		}
 
		// Compruebo escala nula
		if (factorEscala == 1 ) {
 
			return srcImg;
		}
 
		// La creo con esas opciones
		AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(factorEscala, factorEscala), opciones);
 
		// Devuelve el resultado de aplicar el filro sobre la imagen
		return op.filter(srcImg, null);
	}
 
 
	/** Metodo que guarda una imagen en disco 
	 * @param imagen Imagen a almacenar en disco
	 * @param rutaFichero Ruta de la imagen donde vamos a salvar la imagen
	 * @param formato Formato de la imagen al almacenarla en disco
	 * @return Booleano indicando si se consiguio salvar con exito la imagen
	 */
	public boolean salvarImagen(final BufferedImage imagen, 
			final String rutaFichero, final String formato) {
 
		// Comprobacion de parametros
		if (imagen != null && rutaFichero != null && formato != null) {
 
			try {
				ImageIO.write( imagen, formato, new File( rutaFichero ));
				return true;
			} catch (Exception e){
				// Fallo al guardar
				if (logger.isDebugEnabled() == true) {
					String CODIGO_MENSAJE_ERROR_GUARDADO_FICHERO = 
						"No se pudo guardar correctamente la imagen en " + 
						rutaFichero;
					logger.debug(CODIGO_MENSAJE_ERROR_GUARDADO_FICHERO);
				}
				return false;
			}
		} else {
			// Fallo en los parametros 
			return false;
		}
	}
 
 
	/** Metodo principal de la clase. Usado como prueba
	 * @param args Argumentos del metodo
	 */
	public static void main(String args[]) {
 
		// Variables locales
		BufferedImage imagen;
 
		try {
			imagen = ImageIO.read( new File( "prueba.jpg" ) );
			ProcesadorImagenes pi = new ProcesadorImagenes();
 
			// Escalo algunas imagenes como pruebas
			BufferedImage imagen800_600 = pi.escalarATamanyo(imagen,800, 600);
			BufferedImage imagenSnap_Shot = pi.escalarATamanyo(imagen,96, 96);
			BufferedImage imagenMediana = pi.escalarATamanyo(imagen,500, 500);
 
			//	Las salvo en disco
			pi.salvarImagen(imagen800_600,"imagenG.jpg","jpg");
			pi.salvarImagen(imagenSnap_Shot,"imagenP.jpg","jpg");
			pi.salvarImagen(imagenSnap_Shot,"imagenE.png","PNG");
			pi.salvarImagen(imagenMediana,"imagenA.gif","gif");
 
			// Extraigo la lista de formatos capaces de leer
			String[] formatos = pi.dameFormatosUsables();
 
			// los voy mostrando
			for (int i=0; i < formatos.length; i++) {
				System.out.println(formatos[i].toString());
			}
 
			// Final del metodo con exito
			System.exit(0);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

→ 6 CommentsTags: Java

Talleres de verano subflash 07

July 17th, 2007 · 3 Comments

Un año más la gente de Subflash organiza unos Talleres abiertos de verano el 25 y 26 de Agosto, donde flasheros de todos los lugares de España y Latinoamérica se juntan para asistir a las ponencias, compartir experiencias, conocimientos y disfrutar del comer y beber del lugar. Tras Teruel, Madrid, Barcelona y Oviedo, este año toca Málaga.
Este evento sin ánimo de lucro está dirigido a todos los desarrolladores web. La convocatoria es abierta, con lo que cualquier persona podrá inscribirse en el sitio web para asistir a las ponencias, bien como oyente si se encuentra en Málaga, o bien mediante opción completa, con alojamiento y pensión completa.
Personalmente solo puedo escribir alabanzas hacia este evento, que… no sólo me ha servido en el plano profesional, sino también en el plano personal, forjando grandes amistades con muchos de los asistentes durante los cuatro años que llevo asistiendo al evento.
Este año no va a poder ser por temas académicos y no podré asistir. Solo les deseo que lo pasen tan bien como yo lo hice en los años anteriores, y animo a todo aquel que habite en el mundillo del desarrollo web y Flash a que se inscriba para este año. La experiencia es única!

Más información:
http://www.subflash.com/talleres/2007/

→ 3 CommentsTags: Actionscript 2.0 · Actionscript 3.0 · Eventos, charlas · Flash · Personal

?rbol de actionscript.es

May 14th, 2007 · No Comments

Por aquí dejo un prototipo de experimento que empecé hace como un año y medio. Se trata de un sistema de visualización gráfica en forma de árbol del rss del sitio web Actionscript.es. Para los que no lo conozcan, actionscript.es es un portal de enlaces y recursos del lenguaje de programación Actionscript donde podemos encontrar los sitios web de obligada visita para cualquier desarrollador de esta plataforma, así como añadir nuevos enlaces al portal. Dicha página, pone a dominio público, un feed RSS de los enlaces de la misma, de manera que cualquiera (en este caso, yo) pueda acceder a los recursos que allí se brindan, y representarlos a su antojo.

La idea del experimento era presentar el directorio de enlaces del portal mediante un juguete visual y dar una vuelta de tuerca al árbol de datos de la web, además de servirme como “sparring” para el desarrollo de un conjunto de clases para el tratamiento de sistemas de representación de redes y datos complejos.

→ No CommentsTags: Actionscript 2.0 · Experimental · Flash · Personal