WASP Blog
13May/100

AS3: Segundos a Formato Hora

Tratando de crear un video player personalizado em encontre con la necesidad de coger el tiempo que me arroja el streaming que es en segundos y pasarlo a el formato conocido de h:mm:ss. Asi qeu cree esta clase estatica muy sencilla que hace esto de  manera  facil.  Podemos testiar nuestro codigo de la siguiente manera:

trace(TimeFormat.formatTime(210, TimeFormat.SECONDS));

Obteniendo para este caso "0:03:30".

Nuestro Clase estaria definida de la siguiente forma:

package com.wasp{

public class TimeFormat{

public static const HOURS:uint = 2;

public static const MINUTES:uint = 1;

public static const SECONDS:uint = 0;

public function TimeFormat() {
}

public static function formatTime(time:Number, detailLevel:uint = 2):String {
var intTime:uint = Math.floor(time);
var hours:uint = Math.floor(intTime/ 3600);
var minutes:uint = (intTime - (hours*3600))/60;
var seconds:uint = intTime -  (hours*3600) - (minutes * 60);
var hourString:String = detailLevel == HOURS ? hours + ":":"";
var minuteString:String = detailLevel >= MINUTES ? ((detailLevel == HOURS && minutes <10 ? "0":"") + minutes + ":"):"";
var secondString:String = ((seconds < 10 && (detailLevel >= MINUTES)) ? "0":"") + seconds;
return hourString + minuteString + secondString;
}

}

}
  • Share/Bookmark
27Nov/090

PHP: listar archivos de un directorio

Listar los archivos de un directorio es necesario cuando se desea eliminar una carpeta pues no se puede eliminar carpetas con elementos dentro, de igual forma podriamos crear una siemple galeria en base a todas las imagenes que tenga una carpeta especifica.

//Directorio actual:$direct";
echo "Los rchivos:";
while ($archivo = readdir($directorio))
  echo "$archivo";
closedir($directorio);
?>

Es frecuente que podamos encontrar otras carpetas dentro de la misma y en esos casos si estas carpeta contiene informacion se tendria que elimnar primero la informacion dentro de ella antes de poderse borrar la carpeta respectiva. Para poder evaluar este tipo de situaciones podemos utilizar el funcion is_dir . Entonces si queremos mostrar todos los contenido incluidos los de las subcarpetas podemos utilizar algo asi como:

//Directorio actual:$directr";
echo "Los archivos:";
while ($archivo = readdir($directorio)) {
  if($archivo == '.')
    echo "$archivo";
  elseif($archivo == '..'){
    if($dir != '.'){
      $carpetas = split("/",$dir);
      array_pop($carpetas);
      $dir2 = join("/",$carpetas);
      echo "$archivo";
    }
  }
  elseif(is_dir("$dir/$archivo"))
    echo "$archivo";
  else echo "$archivo";
}
closedir($directorio);
?>

?>

Ya para eliminar agregamos la funcion unlink a la estructura deseada.

  • Share/Bookmark
Etiquetado con: , Sin Comentarios
16Nov/090

PHP: Clases abstractas

PHP desde su version 5 a configurado unlenguaje más robusto y tratando de ser un lenguaje Orientado a Objetos como java, c++, c# entre muchos otros. La posibilidad de crear objetos (funcionalidad propia de todo le nguaje OO) ha generado un gran entusiasmo en todo los programadores de PHP.
La abstracion de clases es un elemento sumamente importante por que son clases que definen patrones para otras clases que extiendes de estas (guias).
Un ejemplo muy interesante e ilustrativo que vemos permanentemente en los libros de programacion es el de los medios de transporte donde la clase abstracta es la de vehiculo y de la cual extienden objetos como carro, moto, bus, bicicleta etc.
La clase abstracta se declara de la siguiente forma:

    abstract class Vehículo
   {
    public $potencia;
    public $peso;
  }

Debemos saber que esta clase no se puede instanciar, si lo intentas de arrojara un error.

La clase abstracta definira las propiedades y metodos que se necesitaran para implementar las clases derivadas. Para ilustrarlo mejor refiriendonos a la clase vehiculo tenemos lo siguiente:

abstract class Vehículo
{
  public $potencia;
  public $peso;

  function __construct($potencia,$peso)
  {
    $this->potencia = $potencia;
    $this->peso = $peso;

    return true;

  }

  function relacionPesoPotencia()
  {
    if ($this->potencia>0)
    {
      return ($this->peso/$this->potencia);
    }

    return -1;
  }

  abstract function aceleracionAproximada();

}

La clase carro que extiende de vehiculo seria:

//// una Carro es un Vehículo
class Carro extends Vehículo
{
  function __construct($potencia,$peso)
  {
    $this->potencia = $potencia;
    $this->peso = $peso;

    return true;
  }

  function aceleracionAproximada()
  {
     $coeficienteTransmision = 3.0;

     $t = $this->peso * 771.73 / (2.0 * $this->potencia * 735);
     $t = $t * $coeficienteTransmision;
     return $t;
  }
}

Caracteristicas:

  • Las clases abstractas no se pueden instanciar.
  • Las clases que heredan de esta deben implementar todos los metodos abstractos.
  • Las clases abstractas pueden heredar de otras clases.
  • Los parametros de los metodos deben ser iguales, ya que sino sera tratado como otro metodo.
  • Si una clase tiene un metodo abstracto esta debe declararse también como clase abstracta.
  • Share/Bookmark
Etiquetado con: , , , Sin Comentarios
12Nov/090

Detectar visitantes mobiles en PHP

En estos dias tenia que realizar un proyecto en el que necesitaba presentar una versión movil de un sitio si esta era accedida desde un dispositivio con estas caracteristicas y por otro lado mostrar el sitio en todo su explendor si se entraba desde un computador.

Pense en hacer yo mismo la funcion que hiciera la detección utilizando $_SERVER['HTTP_USER_AGENT'] como base, la cual me arrojara información del dispositivo de donde se realiza la conexión.

Meditando un poco y buscando encontre si necesidad de pensar mucho (ya otro lo ha hecho por mi), una función realmente util y completa que hace esta tarea. La probe con mi celular que tiene Windows Mobile 6.1 con Opera Mobile e Internet Explorer y funciona de maravilla. Aqui les dejo el codigo y espero que les sirva.  :-)

<?PHP

$mobile_browser = '0';

IF(PREG_MATCH('/(up.browser|up.link|mmp|symbian|smartphone|midp|wap|phone)/i',
STRTOLOWER($_SERVER['HTTP_USER_AGENT']))){
$mobile_browser++;
}

IF((STRPOS(STRTOLOWER($_SERVER['HTTP_ACCEPT']),'application/vnd.wap.xhtml+xml')>0) or
((ISSET($_SERVER['HTTP_X_WAP_PROFILE']) or ISSET($_SERVER['HTTP_PROFILE'])))){
$mobile_browser++;
}

$mobile_ua = STRTOLOWER(SUBSTR($_SERVER['HTTP_USER_AGENT'],0,4));
$mobile_agents = ARRAY(
'w3c ','acs-','alav','alca','amoi','audi','avan','benq','bird','blac',
'blaz','brew','cell','cldc','cmd-','dang','doco','eric','hipt','inno',
'ipaq','java','jigs','kddi','keji','leno','lg-c','lg-d','lg-g','lge-',
'maui','maxo','midp','mits','mmef','mobi','mot-','moto','mwbp','nec-',
'newt','noki','oper','palm','pana','pant','phil','play','port','prox',
'qwap','sage','sams','sany','sch-','sec-','send','seri','sgh-','shar',
'sie-','siem','smal','smar','sony','sph-','symb','t-mo','teli','tim-',
'tosh','tsm-','upg1','upsi','vk-v','voda','wap-','wapa','wapi','wapp',
'wapr','webc','winw','winw','xda','xda-');

IF(IN_ARRAY($mobile_ua,$mobile_agents)){
$mobile_browser++;
}
IF (STRPOS(STRTOLOWER($_SERVER['ALL_HTTP']),'OperaMini')>0) {
$mobile_browser++;
}
IF (STRPOS(STRTOLOWER($_SERVER['HTTP_USER_AGENT']),'windows')>0) {
$mobile_browser=0;
}

IF($mobile_browser>0){
// do something
} ELSE {
// do something else
}

?>
  • Share/Bookmark
8Nov/090

AJAX con JQUERY

Cuando recien descubria el verdadero poder de AJAX (Asynchronous JavaScript And XML), me puse en la tarea de crear mi propia libreria de trabajo para facilitar el desarrollo de las aplicaciones que realizaba. Luego descubri los diferenes frameworks de javacript como jquery, mootools, dojo YUI, entre otras (pueden ver mi post donde hablo sobre estos frameworks), los cuales integran el manejo de ajax de una forma muy poderosa por asi decirlo.

logo_jquery_215x53

Dado la cantidad de frameworks, me ha gustado bastante trabajar con jQuery, que es sumamente sencillo de implementar y esta muy bien documentado. En este ejemplo pretendo mostrar como invocar una pagina asincronicamente utilizando las funciones que me provee jQuery.

Antes que nada debemos descargar jQuery, lo podemos hacer desde ete link. una vez agregado el framework a nuestro proyecto vamos a crear un link o boton el cual al hacer click sobre este actuliza una zona de la pagina (div) con un contenido. Le asignamos posteriormente un evento, y dentro de este invocamos nuestra funcion de ajax de jQuery. Paralelamente utilizamos la funcion ajaxStart(), para poner un letrero que diga cargando mientras trae la información.

  <html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Prueba Ajax</title>

<script type="text/javascript" src="jquery.js"></script>

<script type="text/javascript" >

function obtenerDato(){
 $("#loading").ajaxStart(function(){
 $(this).show();

 });

 $.ajax({
 type: "POST",
 url: "obtenerDatos.php",
 data: "nombre=Cesar&apellido=Suarez",
 success: function(msg){
 $("#datos").append(msg);
 $("#loading").hide();
 }
 });

}
$(document).ready(function(){
 $("#loading").hide();
 });
</script>

</head>

<body>
<label>
<input type="button" name="button" id="button" value="Enviar" onclick="javascript: obtenerDato();"/>
</label>
<div id="loading">Cargando</div>
<div id="datos"></div>
</body>
</html>

Dentro del framework de jQuery podemos encontrar varios eventos como el utilizado (ajaxStart). Estos son:

ajaxError, ajaxSend, ajaxStop, ajaxSucces. Si miramos igual la documentacion se podra encontrar el envio de datos por GET (aqui se mostro con POST), entre otras muchsa opciones.

Descargar archivos aqui.

  • Share/Bookmark
26Oct/092

Twitter php API – crear nuevo mensaje

twitter logo

twitter logo

En el post anterior explique como leer los mensajes que hemos escrito en Twitter, ahora les mostrare como crear un nuevo mensaje, la verdad la documentacion de la libreria es mala, pero si uno se pone a analizar las funciones, son muy intuitivas y faciles de usar, creo que este sera el ultimo post sobre este tema (caso cerrado). Primero que todo inicializamos nuestra cuenta como se vio en el Post anterior, luego simplemente invocamos la funcion update de la libreria y escribimos nuestro mensaje.

Tenemos que tener en cuenta que este no puede ser mayor a 140 caracteres.


 <?php

include_once('class.twitter.php');

$t = new Twitter;
$t->username = 'usuario';
$t->password = '****';
$t->type = 'xml';
$t->update("no se que mensaje colocar");
?>

Si tiene alguna duda con cualquiera de la funciones me pueden escribir y con gusto les ayudare.

  • Share/Bookmark
23Oct/091

Twitter php API – Leer publicaciones

Twitter es la plataforma de microbloging, que para las personas que no estan familiarizadas o le suena algo extraño el termino es escribir mensajes cortos (140 caracteres máximo), con alguna información relevante (muchas veces irrelevante). La verdad twitter en un principio no me llamo la atención, tal vez porque a las personas que seguian solo escribian lo que le pasaba en un momento determinado (tengo sueño, estoy en el trabajo etc). Le vine a encontrar un sabor distinto cuando empecé a agregar portales de información y ahi creo que va a estar el valor de la plataforma, el poder agregar las fuentes de información deseadas y reunirlas en un solo lugar (pueden agregarme a twitter prometo llevarle informacion realmente útil).

Ahora bien, ya habiéndote convencido del potencial que ofrece twitter, les mostrare como podemos integrarlo a tu sitio utilizando la API de php (Seleccione la más sencilla pero la peor documentada). Para iniciar tenemos que fijar un objetivo en este caso queremos mostrar en nuestra pagina todos los mensajes que hemos escrito.

Primero agregamos la referencia de la API al proyecto, que la podemos descargar aqui.

<?php

include_once('class.twitter.php');

$t = new Twitter;
$t->username = 'usuario';
$t->password = '******';
$t->type = 'xml';
$follow=$t->followers();

$status=$t->userTimeline();

for($i=0;$i<count($status);$i++){
 echo $status->status[$i]->text[0]."<br>";
}

?> 

Agregamos nuestro usuario y contraseña. Luego seleccionamos el tipo que en este caso es xml, tambien tenemos la opcion de recibir la informacion como json, XML , RSSAtom. La extension utilizada por la libreria para la manipulacion del xml es SimpleXML, personalmente me gusta mas utilizar DOM, pero bueno SimpleXML es sencillo tambien :-) .

Ya nos desplegara todos los mensajes que hasta la fecha hemos publicado.

  • Share/Bookmark
Etiquetado con: , , , 1 Comentario
21Oct/091

Como usar Lightbox 2

Lightbox es una liberia hecha en javascript que permite visualizar imagenes de una forma agradable (por asi decirlo), aunque tambien permite crear una galeria y facilitar la navegacion. Aqui les mostrare como podemos utilizar esta libreria facilmente.

Lo primero que tenemos que hacer es descargar lightbox. Existen muchos proyectos parecidos y algunos con elementos adicionales, pero sabiendo como implementar uno podremos manejar cualquier otro.

Al descargar los archivos tendremos el javascript, la hoja de estilos y las imagenes (que podemos cambiar a nuestro antojo)

En nuestro proyecto agregamos estos elementos y configuramos nuestra pagina de la siguiente forma:

1. Agregamos la referencia a los archivos javascript del lightbox

<script type="text/javascript" src="js/prototype.js"></script>
<script type="text/javascript" src="js/scriptaculous.js?load=effects,builder"></script>
<script type="text/javascript" src="js/lightbox.js"></script>

2. Agregamos la referencia del archivo de estilo

<link rel="stylesheet" href="css/lightbox.css" type="text/css" media="screen" />

3. Para que se identique a que vinculo se le quiere agregar el lightbox la agregamos la etiqueta rel="lightbox".

<a href="ruta/image-1.jpg" rel="lightbox" title="texto">imagen</a>

4. Si se quiere crear una galeria (poder ver las imagenes en secuencia), la etiqueta va llevar el nombre del grupo rel="lightbox[grupo]". Por pruebas y algunos problemas que tuve, recomiendo colocar los elementos en un div con el mismo class (una buena sugerencia).

<div class="imagenes"><a href="photos/image_01.jpg" rel="lightbox[group]” title=”image title 01>first picture</a></div>
<div class="imagenes">
<a href=”photos/image_02.jpg” rel=”lightbox[group]” title=”image title 02>second picture</a></div>
<div class="imagenes"> <a href=”photos/image_03.jpg” rel=”lightbox[group]” title=”image title 03>third picture</a></div>

Ejemplo

  • Share/Bookmark
12Oct/090

Actionscript 3.0 sendAndLoad

Una de las cosas mas utilizadas a la hora de hacer una aplicacion es la comunicacion con ficheros externos (.php, .asp, .aspx etc), para realizar diversas tareas. Como sabemos o si no lo sabes te comento que esta funcion ya no existe dentro del Core de ActionScript 3 asi que si quieres hacer eso que podias hacer con el sendAndLoad en AS2, solo sigue esta pequeña guia.

Si estamos trabajado sobre un AS, tenemos que importar la librerias necesarias

import flash.display.Sprite;
import flash.net.URLRequest;
import flash.net.URLVariables;
import flash.net.sendToURL;

Creamos el elemento de envio y donde se recibe los datos de respuesta

var url:String = "http://www.waspgroup.com/ejemplos/prueba.php";
var enviar:URLRequest = new URLRequest(url);
var recibir:URLLoader = new URLLoader();

Tambien creamos un elemnto tipo URLVariables que es donde se almaceneran cada una de las variables que se enviaran a la pagina.

var variables:URLVariables = new URLVariables();
variables.numero1 = 7;
variables.numero2 = 10;

enviar.method = URLRequestMethod.POST;
enviar.data = variables;
recibir.dataFormat = URLLoaderDataFormat.VARIABLES;

Luego tenemos los eventos asociados, el primero es el de respuesta, que se ejecuta una vez completado el llamado y si este fue exitoso.
El segundo es el de error, en caso de no tener respuesta por cualquier razon (no existe el vinculo, fallo de conexion, etc)

recibir.addEventListener(Event.COMPLETE,Respuesta);
recibir.addEventListener(IOErrorEvent.IO_ERROR,HayError);

recibir.load(enviar);

function Respuesta(event:Event){

        trace("El resultado es : " + recibir.data.datos);

}
function HayError(event:IOErrorEvent):void {

        trace("Error al cargar la url");

}

El archivo php es el siguiente:

<?php

	$numero1 = htmlentities($_POST[numero1]);
	$numero2 = htmlentities($_POST[numero2]);
	$info = $numero1 ."-". $numero2;
	echo "datos=" . $info;

?>

Este es un ejemplo de como quedaria con algunas funcionalidades adicionales:

  • Share/Bookmark
12Oct/090

Mi Primer mundo para BOX2D en Actionscript 3

Dentro del lo motores fisicos que mencione en un post anterior esta BOX2D que para mi es el mejor y con el cual he empezado a desarrollar proyectos, la idea ante todo es conocer muy bien su funcionamiento y saber donde esta la documentacion para de esta forma saber todas las posibilidades que nos ofrece.

La wiki de BOX2D la puede encontrar aqui.

La libreria de flash se puede descargar aqui.

El primer elemento, o prime paso que se sebe realizar es la creacion del mundo, que es donde los elementos van a interactuar. lo que vamos a realizar se puede ver a continuacion.

Bodies y Shapes (cuerpos y formas)

En este mundo todas las particulas de Box2D son cuerpos rigidos es decir tienen un cuerpo y una forma asociada; el cuerpo tiene unas propiedades como lo son la masa, la posición, el factor de amortiguamiento en cambio la forma maneja las colisiones, la fricción, la densidad entre otras variables. Teniendo todos estos datos, box2d puede llevara  cabo los calculos necesarios para darle el realismo necesario a nuestro mundo.

 /****************************************************
				TUTORIAL DE BOX2D

		Creado por: César Eduardo Suárez T.
				www.waspgroup.com
			    blog.waspgroup.com

	 Si tiene alguna pregunta puede contactarme
				csuarez@waspgroup.com

****************************************************/

package{

	import flash.display.*;
	import flash.events.*;

	//Importamos la librerias necesarias de BOX2D
	import Box2D.Dynamics.*;
	import Box2D.Collision.*;
	import Box2D.Collision.Shapes.*;
	import Box2D.Common.Math.*;

	public class miMundo extends Sprite{

		//Creamos una variables tipo cuerpo shape para crear nuestra caja
		var cuerpoCajaDef:b2BodyDef;
		var cajaDef:b2PolygonDef;
		var cajita:b2Body;
		var piso:b2Body;
		var m_sprite:Sprite;
		var debugvar:Boolean=false;
			//create world variable

		public var m_Mundo:b2World;

		//creamos la variable que permite el render
		//esta variable no dira que tan frecuente se actualizara nuestro mundo. 1/30 significa 1/30 de un segundo, o en otras palabras 30 veces por segundo.
		//las interaciones le dan la presicion a los calculos fisicos a menos iteraciones menor da una menor presicion y mas rapidez
		//a mayor iteracion mayor presicion pero mas tiempo de calculo los expertos recomienda un valor de 10.
		public var m_timeStep:Number = 1/30;
		public var m_iterations:int = 10;

		//Funcion de contruccion
		public function miMundo(){

			//2bAABB crea una caja es una la cual es necesaria para la creacion de el entorno
			//Si un objeto tiene una tamaño mayor a el del mundo quedara congelado.
			var worldAABB:b2AABB = new b2AABB();
			worldAABB.lowerBound.Set(-100.0, -100.0);
			worldAABB.upperBound.Set(100.0, 100.0);
			//this defines the gravity of world. The first parameter is horizontal force, and the second is verticle force.
			var gravity:b2Vec2 = new b2Vec2(0.0, 10.0);
			// Allow bodies to sleep, this effects performance, leave it set to true.
			var doSleep:Boolean = true;
			//Build the world
			m_Mundo = new b2World(worldAABB, gravity, doSleep);

			//Ahora que creamos el mundo vamos a agregar los elementos. Debemos tener en cuenta que
			//1. Cada objeto tiene dos partes el bodyDef y el shapeDef (boxDef, circleDef...)
			//2. Estos objetos son como una relacion de padre/hijo la forma sera aplicada como hijo del cuerpo

			//El piso del scenario
			var boxDef:b2PolygonDef;
			var bodyDef:b2BodyDef;
			bodyDef = new b2BodyDef();
            bodyDef.position.Set(9,10);
			//le asociamos un cuerpo (movie clip previamente creado)
 			var mesita:mesax=new mesax();
			bodyDef.userData=mesita;
			addChild(bodyDef.userData);
            //definimos uss propiedades fisicas a traves de una definicion de forma;
            boxDef = new b2PolygonDef();
            boxDef.SetAsBox(7,1.5);
            boxDef.friction =0.3;
            boxDef.density=0;
		//creamos el cuerpo como tal en nuestro mundo;

           piso = m_Mundo.CreateBody(bodyDef);
           piso.CreateShape(boxDef);

			//Creamos el Cuerpo (la caja wasp)
			//le asociamos un cuerpo (movie clip previamente creado)
			var boxmovie:cajax=new cajax();
			cuerpoCajaDef = new b2BodyDef();
			cuerpoCajaDef.position.Set(5,0);
			cuerpoCajaDef.userData = boxmovie;
			cuerpoCajaDef.userData.width =6*30 ;
			cuerpoCajaDef.userData.height = 6*30;
			addChild(cuerpoCajaDef.userData);
			cajita = m_Mundo.CreateBody(cuerpoCajaDef);
			//create the shape
			cajaDef = new b2PolygonDef();
			cajaDef.SetAsBox(2.0, 2.0);
			cajaDef.density = 1.0;
			cajaDef.friction = 0.3;

			cajita.CreateShape(cajaDef);
			cajita.SetMassFromShapes();

           //El boton para activar el debug
		   var bot:btnCodigo=new btnCodigo();
		   addChild(bot);
		   bot.x=380;
		   bot.y=30;
		   bot.addEventListener(MouseEvent.CLICK,verCodigo);

		addEventListener(Event.ENTER_FRAME, Update, false, 0, true);
		}

		public function verCodigo(eve:MouseEvent){
			if(debugvar==false){
				debugvar=true;

				m_sprite = new Sprite();
				addChild(m_sprite);
				var dbgDraw:b2DebugDraw = new b2DebugDraw();
				var dbgSprite:Sprite = new Sprite();
				m_sprite.addChild(dbgSprite);

				dbgDraw.m_sprite=m_sprite;
				dbgDraw.m_drawScale=30;
				dbgDraw.m_alpha = 1;
				dbgDraw.m_fillAlpha=0.9
				dbgDraw.m_drawScale =30.0;

				dbgDraw.m_lineThickness=1;
				dbgDraw.m_drawFlags=b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit|b2DebugDraw.e_centerOfMassBit;
				m_Mundo.SetDebugDraw(dbgDraw);
				}else{
					debugvar=false;
					removeChild(m_sprite);
					}
			}

		//Esta funcion sera activada cada vez que se entra al frame
		public function Update(e:Event):void{
			//pasos para hacer el render de BOX2D
			m_Mundo.Step(m_timeStep, m_iterations);

				//Realiza la actualizacion de todos los objetos
			for (var bb:b2Body =m_Mundo.m_bodyList; bb; bb = bb.m_next){
					if (bb.m_userData is Sprite){
						bb.m_userData.x = bb.GetPosition().x * 30;
						bb.m_userData.y = bb.GetPosition().y * 30;
						bb.m_userData.rotation = bb.GetAngle() * (180/Math.PI);
					}
				}
		}

	}
}

Basicamente nuetro primer ejemplo con BOX2D consta de 2 objetos, una superficie que es una mesa y un objeto que es una caja, coloque un botón para mirar el debug de box2d y asi no ensuciar la animación. Dentro del mismo codigo he colocado la explicacion de cada uno de los elementos utilizados para la programación. Esperen el siguiente tutorial donde agregare nuevo elementos :-)

Archivos para Descargar.

  • Share/Bookmark