IoT – El Internet de las Cosas con Arduino

Hoy os dejo la presentación que hice para mi proyecto final de carrera de Ingeniero en Informática.

El tema del proyecto fue “Pagos por móvil con Arduino & NFC para el Internet de las cosas“. Mi trabajo se centró en la parte de Arduino y ahí aprendí a programar este tipo de tarjetas electrónicas basadas en el microcontrolador  Atmel AVR. También conocí el Movimiento Maker y el Internet de las cosas.

El trabajo tomó como modelo de negocio las máquinas de vending. Conectamos una máquina de vending a la nube por medio de una comunicación GPRS.

La tarjeta Arduino provista de un procesador GPRS SIM900 conecta la máquina de vending con Internet.

El negocio en la nube está centrado en OpenCart, una tienda virtual. Nuestra tienda virtual son los productos que se venden en las máquinas de vending.

IoT

 

El ciclo de vida de una venta es el siguiente:

  1. Un cliente acerca su terminal móvil con tecnología NFC a la máquina de vending
  2. El cliente recibe en su móvil la URL de OpenCart correspondiente a la tienda virtual que representa a esa máquina de vending (relación 1:1) y en la pantalla puede ver los productos que puede comprar.
  3. El cliente selecciona un producto en su móvil y Arduino, que esta haciendo poll contra OpenCart por medio del GPRS, detecta que tiene que entregar un producto ya que en la tienda virtual se acaba de hacer una venta.
  4. Arduino recibe los parámetros del precio y código del teclado correspondiente al producto seleccionado.
  5. Arduino pone el crédito y selecciona el producto actuando sobre el teclado multiplexado. Para esto desarrollé un programa que trabajaba con el protocolo MDB y convertía a la tarjeta Arduino en un dispositivo Cashless (pago sin dinero en efectivo). Lógicamente, el cliente tiene que tener un fondo de dinero precargado en OpenCart.
  6. Si el producto se entrega con éxito, Arduino confirma en OpenCart la venta y se le descuenta el dinero al cliente de su cuenta.

Espero que os guste!!

Sustituir conexión micro usb en tablet BQ

En este post voy a mostrar cómo sustituir el conector micro usb en una tablet BQ Currie. Este conector se utiliza en casi todos los móviles y tablets y sirve para cargar la batería o para transferir datos con otro terminal.

Lo primero que debemos preparar es la mesa de trabajo, debe estar despejada de objetos que nos puedan estorbar y debe tener una buena iluminación. Las herramientas necesarias son:

  1. Un destornillador de cruz tipo Philips
  2. Una pinza de puntas finas
  3. Soldador
  4. Estaño
  5. Un trozo de malla desoldadora (opcional)
  6. Un poco de Flux para soldar (opcional)
  7. Una cuña de plástico para abrir la tapa de la tablet

El ensamblado de la tablet se compone de la pantalla, del táctil, del circuito electrónico y de la batería. Todo esto forma un conjunto que se cierra con una tapa de plástico que es lo que tenemos que abrir para poder cambiar el conector micro usb.

Lo primero que debemos hacer es colocar la tablet con la pantalla hacia arriba e introduciremos la cuña de plástico comenzando por el lado contrario a donde tiene las conexiones externas. Ir haciendo palanca con mucho cuidado mientras vamos girando alrededor de la tablet con la cuña, es como si abriésemos un tupper.

Abrir tablet

Una vez abierta la tablet debemos soltar la conexión del altavoz que está en la tapa, tirar de ella con cuidado y siempre estirando del conector, no de los cables. Si nos ayudamos con una pinza mejor. Hacer lo mismo con el resto de conectores. Los conectores de lámina tiene un bloqueo que se levanta con ayuda de una pinza, después, estirar de la lámina que sale con facilidad.

Conectores

Otro conector especial es el de la antena, sale hacia arriba con ayuda de una pinza

Soltando conectores

Una vez hemos soltado todos los conectores procedemos a quitar un par de tornillos con cabeza de estrella que hay en un extremo, donde están los conectores externos. La tarjeta sale deslizándola un poco hacia el lado donde estaban los tornillos. La levantamos con cuidado ya que hay un conector de lámina en la parte interior, levantamos el prisionero y estiramos de la lámina.

Conexión interior

Ya tenemos la tarjeta electrónica fuera y podemos empezar a preparar todo para desoldar el conector micro usb.

Circuito electrónico

Despejamos la mesa dejando únicamente esta tarjeta electrónica.

Es el momento de enchufar el soldador y esperar a que pille temperatura.

El conector micro usb tiene cuatro puntos de soldadura en sus esquinas y cinco pines soldados al circuito impreso. En la siguiente imagen viene identificado con el nombre JP4. Estos conectores se rompen muy fácil ya que se utiliza con mucha frecuencia, ¡cada vez que cargamos la tablet!

Conector

Para soltar el conector vamos a poner estaño en las cuatro esquinas y en los cinco pines, sin importar que se junten entre si. Hay que estar con el soldador y el estaño cubriendo todas las patas. A su vez nos ayudamos de una pinza de puntas más gruesas que la utilizada anteriormente para sujetar el conector e ir moviéndolo, tanteando si se va soltando.

OS dejó un vídeo realizado por Eugenio @fidestec donde podéis ver cómo desoldar un circuito integrado haciendo uso de esta técnica.

 

soldador

Finalmente el conector sale

Circuito sin conector

conector micro usb

No te preocupes por el residuo que ha dejado el estaño. Repasa con el soldador el circuito impreso retirando el estaño sobrante. Ayúdate de un desoldador o de una malla para desoldar. Cuando hayas retirado el estaño limpia la zona con un bastoncillo de algodón untado en acetona o alcohol, si no tienes, aunque te costará más limpiar bien la zona.

Circuito limpio

Sacamos el conector nuevo de su capsula de plástico

conector nuevo

Lo encajamos en la tarjeta electrónica de manera que queden las cuatro esquinas en su sitio y que los cinco pines coincidan con sus puntos de contacto en el circuito. Para esto te tendrás que ayudar con una lupa.

ajustando el conector

Pon estaño en una esquina y fíjate si el conector está bien ajustado, si no corrige calentando la esquina.

ajustando 2

Cuando estés seguro de que todas las esquinas y pines están en su sitio continua soldando las cuatro esquinas. Después suelda los pines. A nada que pongas la punta del soldador, el estaño que había en el circuito va a agarrar los pines del conector. Ayúdate de una lupa.

El resultado será este

conector soldado

Para más seguridad puedes comprobar con un polímetro que no hay cortocircuito entre los pines.

polímetro

Lo siguiente es empezar a montar la tablet. Primero encajar la tarjeta en su sitio, conectar todos los conectores y atornillar los dos tornillos.

atornillar

Nos aseguramos que todo está en su sitio.

todo en su sitio

Es momento de poner el cargador y ver qué pasa.

prueba carga

Perfecto, parece que funciona!!

Antes de cerrarla, es conveniente revisar la cámara. Para ello encendemos la tablet y vamos a la cámara. Si se ve bien la imagen no hacemos nada, pero si se ve distorsionada hay que ajustar el conector de lámina de la cámara. En mi caso tenía una pequeña holgura que provocaba este error. Lo soltamos y volvemos a meter y probamos de nuevo la cámara.

conexión cámara

Finalmente cerramos la tapa introduciendo primero el lateral de los conectores externos. Cuando veamos que asoman bien todos los conectores del lateral en sus aberturas ya podemos ir cerrando todo el contorno, sonará el típico click, eso es buena señal.

La tablet se enciende y funciona perfectamente ¿es eso lo que queríamos, no?

funciona

 

Espero que os sea útil.

Autor: Patxi Ballesteros

Introducción a la especificación MDB/ICP

MDB/ICP son las siglas de Multi-Drop Bus/Internal Communication Protocol. Aquí voy a describir la versión 4.2 de la especificación.

MDB es un protocolo utilizado en las máquinas de vending para interconectar diferentes módulos, como pueden ser: Monederos (coin changers), billeteros (bill acceptors) y lectores RFID.

El protocolo MDB transmite las señales por un bus serie que trabaja a 9600 baudios en una configuración maestro-esclavo, donde todos los periféricos son esclavos de un controlador maestro. Cada periférico tiene una dirección única y un conjunto de comandos.

El maestro sondea continuamente el bus para conocer la actividad de los periféricos. Es decir, cada periférico recibe una encuesta y éste responde con un acuse de recibo, acuse de recibo negativo, o datos específicos dependiendo de la actividad que esté realizando. Si un periférico no responde dentro de un tiempo predefinido se supone que no está presente en el bus. Las colisiones dentro del bus se evitan debido a que cada periférico solo responde cuando es encuestado. Como solo hay un maestro, y toda comunicación es iniciada por éste, las colisiones en el bus se evitan fácilmente.

El protocolo MDB tiene tres niveles funcionales. El nivel 3 es el que más comandos soporta. Ningún dispositivo responderá a comandos de un nivel superior al suyo.

Comunicación

El protocolo MDB utiliza una transmisión serie asíncrona para el envío de los datos. La velocidad de transmisión es de 9600 baudios con una codificación NRZ.

Se transmiten 11 bits: 1 bit de arranque, 8 bits de datos (primero el LSB), 1 bit de modo y 1 bit de parada.

trama

Bit de modo en la transmisión de Maestro a periférico: El bit de modo a 1 indica un byte de dirección, si es un 0 indica un byte de datos. La dirección la leen todos los periféricos pero solo responde el que tiene esa dirección. El byte de datos solo lo lee el periférico direccionado.

Bit de modo en la transmisión de periférico a maestro: Se pone a 1 cuando el periférico envía el último byte del bloque de datos.

Formato del bloque

  • Maestro a periférico

La transmisión de un comando desde el maestro hasta un periférico consiste en:

  1. Un byte con la dirección del periférico (bits 3, 4, 5, 6 y 7) y un comando (bits 0,1 y 2). Modo = 1
  2. Opcionalmente un byte con un subcomando. Modo = 0
  3. Opcionalmente n bytes de datos. Modo = 0
  4. Un byte con el checksum. Modo = 0

El maestro puede responder a un periférico con ACK, NAK o RET. Modo = 0

maestroperiferico

  • Periférico a maestro

La respuesta de un periférico al comando enviado por el maestro consiste en:

  1. N bytes de datos. Modo = 0
  2. un byte con el checksum. Modo = 1

Si no tiene nada que enviar al maestro responderá con ACK. Modo = 1

Si no recibe lo que esperaba responderá con NAK. Modo = 1

  • Checksum

El byte de checksum se calcula sumando todos los bytes del bloque enviado. El bit de acarreo en el checksum se ignora ya que el checksum es de 8 bits.

En la siguiente imagen se muestra un ejemplo del cálculo del checksum en un bloque de datos enviado por el maestro. Observe como al resultado de sumar los seis bytes, es decir a 0x23E, se le aplica un AND 0xFF para quedarse solo con 8 bits e ignorar el acarreo.

checksum

Tiempo de respuesta

Si el maestro no recibe una respuesta del periférico en 5 ms volverá a enviar el mismo comando u otro distinto hasta que reciba una respuesta o pase un tiempo de espera configurado por el periférico. Este tiempo por defecto se puede aumentar en la configuración que envía el periférico al maestro en el comando Setup. Más adelante veremos este comando.

Una vez transcurrido este tiempo máximo de espera, el maestro enviará al periférico un comando RESET por lo menos cada 10 segundos.

Códigos de respuesta

  • ACK = 0x00
  • RET = 0xAA
  • NAK = 0xFF

Hardware

Como he comentado en el punto anterior, el protocolo MDB utiliza un bus para la transmisión y recepción de las señales entre el maestro (VMC) y los esclavos (dispositivos periféricos). En la siguiente figura se muestra un esquema de las conexiones entre los distintos dispositivos de una máquina de vending.

hardware

Los periféricos se aíslan eléctricamente del bus mediante unos optoacopladores, ver siguiente imagen.

aislamiento

Dispositivo cashless

Un dispositivo cashless es un dispositivo para realizar pagos sin dinero en efectivo, por ejemplo una tarjeta prepago o un teléfono móvil con tecnología NFC o mediante códigos QR.

El cashless es un esclavo en el bus MDB y las direcciones reservadas para este dispositivo son la 10H y la 60H, utilizare la dirección 10H en el resto de la explicación.

El VMC está continuamente sondeando a los periféricos con el comando POLL. El cashless deberá esperar a este comando si tiene algo que comunicar al VMC.

poll

En la imagen se observa que el primer byte del bloque es el comando 2H (RESET) enviado a la dirección 10H (Cashless). En binario sería 1 00010 010 = 112H (el primer bit es el 8). Es decir, bits 0, 1 y 2 son el comando 2H y los bits 3, 4, 5, 6 y 7 la dirección 10H. El bit 8 es el modo que como es 1 indica que el dato lleva una dirección.

El segundo byte del bloque es el checksum calculado como se ha explicado en uno de los puntos anteriores.

El cashless simplemente devuelve ACK con el bit de modo a 1 por ser el último byte, y único en este caso, del bloque de su respuesta.

Estados

Un dispositivo cashless se puede ver como una máquina de estados (ver siguiente Figura), estos son:

  1. Inactive
  2. Disabled
  3. Enabled
  4. Session Idle
  5. Vend

maquinaestados

Inactive

Es el estado inicial del cashless. Se llega a él tras alimentar al dispositivo o al hacer un RESET en cualquiera de los estados. En este estado el dispositivo no está disponible.

El VMC envía un comando de RESET al dispositivo.

inactive

Seguidamente el VMC se dedica a enviar comandos POLL. Cuando el cashless está listo responde con el comando JUST RESET.

justreset

A continuación el VMC envía el comando SETUP con su configuración y el cashless le responde con la suya. En este ejemplo el VMC le está indicando que trabaja en el nivel 2 y el display que tiene (nº de filas y columnas). El cashless le responde que trabaja en el nivel 1, el código del país, el factor de escala y los decimales que emplea en los valores del crédito, el tiempo máximo de espera sin respuesta y un último byte para configurar otros aspectos como es la recarga de saldo.

setup1

El VMC envía de nuevo el comando SETUP pero con otro subcomando, el que se refiere a la configuración Max/Min precios.

setup2

Entonces el cashless responde con ACK y pasa al estado Disabled.

Disabled

En este estado el cashless recibirá varios comandos POLL y si todo está bien el VMC enviará un comando READER ENABLE que pasará al cashless al estado Enabled.

disabled

Enabled

En este estado el dispositivo cashless está preparado para recibir una señal externa que le haga iniciar una sesión de venta, por ejemplo, un cliente acerca su terminal móvil al tag NFC. En este estado se responde a un comando POLL con BEGIN SESSION, esta respuesta consiste en un bloque de datos con el importe introducido para realizar una compra.

enabled

El dispositivo cashless cambiará al estado Session Idle.

Session Idle

En este estado el cliente selecciona un producto en el teclado de la máquina de vending. Entonces el VMC envía un comando VEND REQUEST con el precio y posición del producto seleccionado. Tras esto, El dispositivo cashless pasa al estado Vend.

 

sessionidle

Vend

En el estado Vend si el dispositivo cashless comprueba que es correcto entregar el producto elegido, responderá a un POLL con VEND APPROVE indicando el importe del producto que valida. Aquí el cashless también podría responder VEND DENIED si no validase la entrega del producto elegido, por ejemplo.

vend

A continuación el VMC confirmará si ha entregado el producto correctamente con el comando VEND SUCCESS, en caso contrario responderá con VEND FAILURE. Existe otro posible subcomando, VEND CANCEL que lo enviará el VMC si el cliente cancela la operación de compra en este momento. Esto sería que pulsa el botón de devolución de monedas.

vendsuccess

Después se vuelve al estado Session Idle y si no hay otra venta pendiente se regresa al estado Enabled tras recibir el comando SESSION COMPLETE.

sessioncomplete

Esto finalizaría un ciclo de venta quedándose el dispositivo cashless preparado para iniciar un nuevo ciclo.

 

Autor: Patxi Ballesteros @patxiba

Referencias:

 

 

Errores de navegación por un mal uso del objeto session

Un uso inadecuado del objeto Session puede llevarnos a situaciones no deseadas y que pueden producir errores cuando navegamos utilizando los botones hacia adelante y hacia atrás del navegador.
Antes de usar Session indiscriminadamente hay que entender lo qué se desea conseguir y no usar este objeto por pura inercia.

Analizaré este escenario con un ejemplo y simplificaré al máximo para destacar lo más importante.

Se trata de un sitio Web para consultar listas de contratación. Estas listas son gestionadas por dos ámbitos, el de Educación y el de Salud. En La primera pantalla existen dos enlaces, uno para cada ámbito, Salud = 1 y Educación = 2. Cuando pulsamos en un enlace nos redirecciona a la segunda página Web pasando por GET el identificador del ámbito. Así que tendremos una URL de este estilo …Pagina2.aspx?ambito=1.

screenshot.34

El segundo Web Form tiene un botón que al pulsarlo nos genera un listado PDF. Esta lista la gestiona únicamente el ámbito elegido.

screenshot.36

También tiene un enlace que recarga la misma página pero con los datos del otro ámbito.

screenshot.35

A continuación se muestra el código de la página Inicio.aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Inicio.aspx.cs" Inherits="Inicio" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
   <title>Inicio</title>
</head>
<body>
<form id="form1" runat="server">
   <ul>
      <li>
         <asp:HyperLink ID="hyperlink1" NavigateUrl="Pagina2.aspx?ambito=1" Text="Salud" runat="server" />
      </li>
      <li>
         <asp:HyperLink ID="hyperlink2" NavigateUrl="Pagina2.aspx?ambito=2" Text="Educación" runat="server" />
      </li>
   </ul>
</form>
</body>
</html>

y el código de la página Pagina2.aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Pagina2.aspx.cs" Inherits="Pagina2" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Búsqueda por Puesto</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:HyperLink ID="hyperlinkMayorPeso" Text="Mayor peso" runat="server" />
    </div>
    <div>
        <asp:Label runat="server" ID="lblAmbitoActual"></asp:Label>
        <br />
        <asp:Button runat="server" ID="btnPdf" OnClick="BtnPdfClick" Text="Temporales" />
        <br />
        <br />
        <asp:Label runat="server" ID="lblResultado"></asp:Label>
    </div>
    </form>
</body>
</html>

Cuando accedemos desde la página de Inicio a la que contiene la lista ésta nos muestra datos sobre el acceso elegido, el nombre del ámbito, etc.
En este momento el servidor no debe saber nada del cliente ¿para que guardamos en servidor -en session- el IdAmbito? ¡guardémoslo en cliente! al igual que el cliente tiene un label con el texto Salud o Educación.
Cuando el cliente haga click, en ese instante y no antes, habrá que enviar al servidor los datos necesarios para que atienda nuestra solicitud.

La situación ideal es una “desconexión” total entre cliente y servidor, eso es el protocolo HTTP ¡un protocolo sin estado!  no hagamos trampas, aunque ASP.NET está lleno de ellas.

En el código se puede comprobar el funcionamiento erróneo si utilizamos Session, en cambio se comprueba el funcionamiento deseado si utilizamos el ViewState.

Primero haré la prueba guardando el identificador que viene por GET en Session

//En este caso no se debería usar session. Comentar este código.
private int Ambito
{
   get
   {
      if (Session["Ambito"] == null)
         return 0;
      return (int)Session["Ambito"];
   }
   set
   {
      Session["Ambito"] = value;
   }
}

En el evento Load se recoge el parámetro y se valida, además se realizan las acciones necesarias para completar el formulario.

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            //Cogemos el parámetro que viene por GET y lo validamos por si lo toca el usuario.
            //Si no está dentro de los valores permitidos redirigimos al inicio.
            int ambito = 0;
            int.TryParse(Request.QueryString["departamento"], out ambito);
            Ambito = ambito;
            if (Ambito != 1 && Ambito != 2)
                Response.Redirect("Pagina1.aspx");

            //Añado un enlace al otro ámbito. Para simular que voy a redirigir a las listas del otro ámbito.
            int otroAmbito = Ambito == 1 ? 2 : 1;
            PonerMayorPeso(otroAmbito.ToString());

            //Labels del formulario
            RellenarFormulario();

            //Simulo un botón de generación de PDF de una lista de temporales, por ejemplo.
            //Si entro a Salud la lista es la PkLista = 50 y si entro a Educación es la PkLista = 60.
            btnPdf.CommandName = "PkLista";
            btnPdf.CommandArgument = Ambito == 1 ? "50" : "60";
        }
    }

El método PonerMayorPeso configura el enlace para recargar la página con los datos del otro ámbito y el método RellenarFormulario añade un label con el nombre del ámbito en el que nos encontramos, más que nada para saber dónde estamos.

private void PonerMayorPeso(string ambito)
{
    hyperlinkMayorPeso.NavigateUrl = string.Format("Pagina2.aspx?ambito={0}", ambito);
    hyperlinkMayorPeso.Text += " en " + (ambito == "1" ? "Salud" : "Educación");
}

private void RellenarFormulario()
{
    lblAmbitoActual.Text = string.Format("Listas en {0}", Ambito == 1 ? "Salud" : "Educación");
}

El evento que se ejecuta al pulsar el botón Temporales recoge el identificador de la lista que queremos generar. En una situación más real hay varios botones cada uno para una lista.

protected void BtnPdfClick(object sender, EventArgs e)
    {
        var pkLista = 0;
        if (sender == null) return;
        var btn = (Button)sender;
        switch (btn.CommandName)
        {
            case "PkLista":
                pkLista = int.Parse(btn.CommandArgument);
                break;
        }

        GetLista(pkLista);
    }

Finalmente en este método se realizarían las acciones oportunas para generar el listado

private void GetLista(int pkLista)
{
    int ambito = Ambito;
    int lista = pkLista;
    //Ir a la BD...
    lblResultado.Text = string.Format("Voy a por la lista con PkLista = {0} de {1}", lista,
                                          ambito == 1 ? "Salud" : "Educación");
}

Probamos. Entro a Salud y obtengo esto:

screenshot.37

pulso en el enlace para ir a Educación y obtengo esto:

screenshot.39

Por ahora va todo bien, pero voy a ir para atrás desde el navegador, debería ir a Salud de nuevo:

screenshot.40

Sí estoy en Salud pero al pulsar para generar la lista me ha generado la de Educación!! ¿Qué ha pasado? Que hemos guardado en session información que pensábamos que nos iba a hacer falta cuando el usuario actuase sobre los botones pero esto no debería hacerse así ya que estamos en un ambiente distribuido y sin estado, el escenario ideal sería petición respuesta y nada más. El cliente pide con los datos necesarios para que el servidor sea capaz de alcanzar el objetivo y el servidor devuelve el resultado y finaliza la petición.
Si en vez de guardar el parámetro en Session lo guardamos en el cliente cada vez que éste haga una solicitud enviará el parámetro correcto. Para esto utilizaré el ViewState de la siguiente manera:

//En este caso no se debería usar session. Comentar este código.
//Si se debería usar ViewState. Descomentar este código.
    private int Ambito
    {
        get
        {
            if (ViewState["Ambito"] == null)
                return 0;
            return (int)ViewState["Ambito"];
        }
        set
        {
            ViewState["Ambito"] = value;
        }
    }

¿Ah entonces hay que usar el ViewState en vez de session? No, cada objeto en su momento, para eso existen los dos!!
Hay que usarlos con precaución, el ViewState carga el peso de la página y Session consume memoria en el servidor. Así que no habría que poner, por ejemplo documentos o listas con datos de la BD en el ViewState, que hay quien los pone…, ni todas o casi todas las variables de la aplicación en Session.

Eliminar duplicados en List

Me ha surgido el problema de tener que eliminar de una lista todos los elementos repetidos y la manera más elegante que he encontrado para hacerlo ha sido apoyarme en una estructura hermana de List, me refiero a Set. List, Set y Queue implementan la interface Collection. Casi todos los subtipos de Collection tienen un constructor que toma como argumento otro objeto Collection, a partir del cual puede rellenar el nuevo contenedor.

Taxonomía completa de los contenedores

Entonces partimos de una lista con objetos repetidos y quiero quedarme con una lista que no tenga ningún objeto repetido. Para esto utilizaré el contenedor Set (interface) ya que cada elemento que se añada al conjunto debe ser diferente; en caso contrario, el objeto Set no añadirá el elemento duplicado. Los elementos añadidos a un conjunto deben al  menos definir equals() con el fin de establecer la unicidad de los objetos. De las implementaciones de Set elegiré LinkedHashSet, ya que mantiene internamente el orden en que se añaden los elementos y tiene la misma velocidad de búsqueda que HashSet.

public List eliminarDuplicados(List list){
    List listSinDuplicados = new ArrayList();
    Set set = new LinkedHashSet(list);
    listSinDuplicados.addAll(set);
    return listSinDuplicados;
}

Con este simple método ya puedo eliminar todos los duplicados de cualquier contenedor List.

HTML5

HTML5 es la próxima generación HTML y será el estándar para HTML, XHTML y HTML DOM, aunque todavía no es una recomendación W3C. Actualmente se trabaja en el estándar pero ya se puede utilizar debido a que los navegadores más modernos ya soportan muchas de las nuevas características.
HTML5 mejora la interoperabilidad y reduce los costes de desarrollo mediante normas precisas sobre cómo manejar todos los elementos HTML, y cómo recuperarse de los errores.
Algunas de las nuevas características de HTML5 son: audio embebido, video, gráficos, almacenamiento local y documentos interactivos. HTML5 también contiene nuevos elementos como <nav>, <header>, <footer> y <figure>.

En los siguientes enlaces hay información precisa de cómo utilizar las nuevas características de este lenguaje
http://msdn.microsoft.com/es-es/ie/hh749019
http://www.desarrolloweb.com/articulos/aprende-html5-5-minutos.html
http://www.w3schools.com/html/html5_intro.asp

https://developer.mozilla.org/en-US/docs/Web/HTML/Element

 

El poder de los lenguajes de programación

¿Qué aspectos deben incluirse para garantizar que, una vez diseñado e implantado un lenguaje de programación, no descubramos que existen problemas cuyas soluciones no pueden especificarse con el lenguaje, y que sí podrían haberlo sido si hubiéramos implantado una versión ampliada del lenguaje?

La estrategia va a ser desarrollar un sencillo lenguaje de programación esencial que permita, suponiendo verdadera la tesis de Church-Turing, expresar una solución para cualquier problema que puede resolverse de manera algorítmica.

Un lenguaje de programación esencial

  • El único tipo de datos que se requiere es el entero no negativo. En un computador digital moderno todo elemento de datos se representa como un entero no negativo, aunque el lenguaje de alto nivel pueda disfrazar esta realidad.
  • Tenemos también dos enunciados de asignación:
incr valor; //Incrementa en uno

decr valor; //Decrementa en uno hasta llegar a 0, una vez es 0 sigue en 0
  •  Finalmente tenemos dos enunciados de control:
while valor ≠ 0 do;
        .
        .
       end;

Este es nuestro lenguaje de programación esencial. Es muy sencillo y, por lo tanto, la primera meta es incorporar enunciados más poderosos que pueden simularse con secuencias de enunciados esenciales.

Por ejemplo:

  • clear x;
while x ≠ 0;
    decr x;
end;
  • x ← y;
clear aux;
clear x;
while y≠ 0 do;
   incr aux;
   decr y;
end;
while aux ≠ 0 do;
   incr x;
   incr y;
   decr aux;
end;
  • z ← x + y
z ← x;
aux ← y;
while aux ≠ 0 do
   incr z;
   decr aux;
end;
  • z ← x – y = {x – y si x ≥ 0;    0 en otro caso
z ← x;
aux ← y;
while aux ≠ 0 do
   decr z;
   decr aux;
end;
  • z ← x × y
clear z;
aux ← y;
while aux ≠ 0 do
   z ← z + x;
   decr aux;
end;
  • z ← x ÷ y
clear z;
w ← x - y;
while w ≠ 0 do
   incr z;
   w ← w - y;
end;

No se ha diseñado ningún lenguaje de programación que tenga mayor poder expresivo que nuestro sencillo lenguaje (aunque los lenguajes más elaborados que se emplean en la actualidad son obviamente superiores en cuanto a legibilidad)

J.G. Brookshear, Teoría de la Computación. Lenguajes formales, autómatas y complejidad. Addison Wesley Iberoamericana (1993).