<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jesús Velázquez</title>
    <description>The latest articles on DEV Community by Jesús Velázquez (@tepexic).</description>
    <link>https://dev.to/tepexic</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F511035%2F1b4f908a-5adb-4baf-b26a-9aaa84ba8ab3.png</url>
      <title>DEV Community: Jesús Velázquez</title>
      <link>https://dev.to/tepexic</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tepexic"/>
    <language>en</language>
    <item>
      <title>Consulta de revocación de mandato usando Web3</title>
      <dc:creator>Jesús Velázquez</dc:creator>
      <pubDate>Thu, 17 Feb 2022 15:14:43 +0000</pubDate>
      <link>https://dev.to/tepexic/consulta-de-revocacion-de-mandato-usando-web3-3maa</link>
      <guid>https://dev.to/tepexic/consulta-de-revocacion-de-mandato-usando-web3-3maa</guid>
      <description>&lt;ul&gt;
&lt;li&gt;&lt;a href="https://consulta-popular.netlify.app/" rel="noopener noreferrer"&gt;Aplicación web&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Tepexic/consulta-popular" rel="noopener noreferrer"&gt;Repositorio en GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Este proyecto trata de cómo se puede usar una  una aplicación web que interactúe con un contrato inteligente desplegado en la cadena de bloques (blockchain) de Ethereum para registrar y contar votos. Gráficamente, el objetivo es este:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp0vfd7d4eg9hjsin1wb5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp0vfd7d4eg9hjsin1wb5.png" alt="Arquitectura de la aplicación"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El contrato recogerá la respuesta a la pregunta: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;¿Desea que el presidente continúe en el cargo o que renuncie?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Las posibles respuestas son 3:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sí, que continúe.&lt;/li&gt;
&lt;li&gt;No, que renuncie&lt;/li&gt;
&lt;li&gt;Anular voto&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Primero lo primero: ¿Qué es el blockchain?
&lt;/h2&gt;

&lt;p&gt;Una definición que me gusta es:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;" el blockchain es un libro de contabilidad digital incorruptible de transacciones económicas que se puede programar para registrar no solo transacciones financieras, sino prácticamente todo lo que tiene valor&lt;a href="http://blockchain-revolution.com/" rel="noopener noreferrer"&gt;[1]&lt;/a&gt;".&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;El objetivo del blockchain, es que dos entidades que no se conocen ni confían una en la otra puedan realizar transacciones sin necesidad de un intermediario. Por ejemplo, cuando se hace una compra con una tarjeta de crédito o débito, es probable que ni el comprador ni el vendedor se conozcan, sin embargo, ambos saben que pueden confiar en el intermediario (banco) para realizar la transacción. En el blockchain ocurre lo mismo. Se pueden enviar y recibir transacciones, con la confianza de que serán verificadas, ejecutadas, registradas y almacenadas por la red.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pero, si es lo mismo, ¿para qué quiero el blockchain?
&lt;/h3&gt;

&lt;p&gt;No, no es lo mismo. En el caso del banco, se parte del supuesto de que el banco es una entidad financiera regulada por algún organismo, es decir, podemos confiar en que el banco nos va a guardar el dinero y nos lo va a dar cuando se lo solicitemos. Que cuando paguemos, el costo de lo que compramos será deducido de nuestra cuenta, que no van a desaparecer de una día para otro y llevarse nuestro dinero. Pero, ¿De dónde viene esa confianza? ¿Confiarían en un banco del que nunca han oído?&lt;/p&gt;

&lt;p&gt;En el caso del blockchain, no hay un banco. No hay una entidad. El registro de las transacciones no está guardado en el servidor de alguna compañía, es decir, la información no está &lt;em&gt;centralizada&lt;/em&gt;. Cada uno de los participantes de la red tiene una copia de la lista de transacciones, y no es posible modificarlas ni alterarlas, porque si se cambia algún registro, los demás participantes de la red notarán que ese es un registro falso. Esta es la principal razón por la que se puede aplicar a sistemas de votación.&lt;/p&gt;

&lt;p&gt;Todos los participantes de la red(nodos) trabajan juntos para crear tablas de registros de transacciones y sellarlas con una clave única. Estas tablas se llaman &lt;em&gt;bloques&lt;/em&gt; y están unidas entre sí mediante esas claves. De ahí viene el nombre de &lt;em&gt;cadena de bloques&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Para incentivar a que haya computadoras trabajando en encontrar estas claves y registrar las transacciones, la red recompensa con &lt;em&gt;tokens&lt;/em&gt; a los nodos que hayan encontrado la clave. Estos tokens, son lo que conocemos como &lt;em&gt;criptomonedas&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contratos inteligentes
&lt;/h2&gt;

&lt;p&gt;Ethereum es un tipo especial de blockchain, no solo permite registrar transacciones, sino que también podemos poner código. Este código se conoce como &lt;em&gt;contrato inteligente&lt;/em&gt;. Esto ha abierto la puerta a que se desarrollen diversas aplicaciones conocidas como &lt;em&gt;Dapps&lt;/em&gt; (por decentralized app) o aplicaciones descentralizadas. Hay de todo, hasta juegos. Uno que me gusta mucho y que les recomiendo si son fans los juegos de cartas como Magic o Yu-Gi-Oh! es &lt;a href="https://godsunchained.com/" rel="noopener noreferrer"&gt;Gods Unchained&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Una aplicación común de los contratos inteligentes son los sistemas de votación. El contrato es un juez absolutamente imparcial y es capaz de proporcionar un conteo inmediato de los votos registrados.&lt;/p&gt;

&lt;p&gt;Aplicado al contexto mexicano, esto quiere decir que no sería posible usar la ya conocida técnica de la urna embarazada, debido a que cada voto registrado debe estar asociado a una persona, ni se puede &lt;em&gt;caer el sistema&lt;/em&gt;, porque que la red no está concentrada en un solo sitio, sino distribuida entre todos los participantes. Sin embargo, el contrato sigue siendo vulnerable a la compra de voto y el mapacheo.&lt;/p&gt;

&lt;p&gt;Para interactuar con un contrato inteligente, necesitamos un &lt;em&gt;monedero&lt;/em&gt;, que viene siendo como una cuenta de usuario mediante la cual podemos enviar y recibir transacciones con el blockchain. Pueden leer más sobre monederos en &lt;a href="https://ethereum.org/es/wallets/" rel="noopener noreferrer"&gt;la página oficial de Ethereum&lt;/a&gt;. Personalmente, uso &lt;a href="https://metamask.io/" rel="noopener noreferrer"&gt;Metamask&lt;/a&gt;, que se instala como una extensión del navegador, e incluso tiene una versión como aplicación móvil.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contrato para la consulta popular
&lt;/h2&gt;

&lt;p&gt;Ya con algo de contexto a la mano, a lo que nos truje:&lt;/p&gt;

&lt;p&gt;Necesitaremos una forma de registrar un solo voto por persona. Podríamos usar la CURP, la Clave de Elector o cualquier identificador ciudadano que sea único. Si consideramos que solo las personas que cuentan con una identificación del INE pueden votar, entonces la clave de elector es la opción viable. &lt;/p&gt;

&lt;p&gt;Lo que debe hacer el contrato es simple: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Registrar un voto por cualquiera de las 3 opciones mencionadas.&lt;/li&gt;
&lt;li&gt;No permitir que una clave de elector vote más de una vez.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A continuación, dejo el código del contrato, está hecho en solidity, que es uno de los lenguajes de programación para contratos inteligentes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pragma solidity ^0.8.0;
// We have to specify what version of compiler this code will compile with

import "hardhat/console.sol";

contract Consulta {
    // almacenar dirección desde la que votaron y la clave de elector
    struct Votante {
        string clave;
        address addr;
        uint256 timestamp;
    }
    // Arreglo de votantes registrados, privada
    Votante[] private votantes;
    // Las opciones para votar se guardarán en una estructura con su descripción e identificador
    struct Opcion {
        string descripcion;
        uint256 id;
        uint256 votos;
    }
    // Las opciones de la consulta serán guardadas en un arreglo de Opcion
    Opcion[] private opciones;

    // Evento para cuando se emite un nuevo voto
    event NuevoVoto(string _clave, address _sender, uint256 _timestamp);

    constructor() {
        // inicializar las opciones de votos
        opciones.push(Opcion("si, que continue", 1, 0));
        opciones.push(Opcion("no, que renuncie", 2, 0));
        opciones.push(Opcion("anular voto", 3, 0));
    }

    /*
     * Obtiene las opciones de voto y el numero de votos
     */
    function getOpciones() public view returns (Opcion[] memory) {
        return opciones;
    }

    /*
     * Valida que solo exista un voto por cada clave de elector
     */
    function _validarVotoUnico(string memory _clave)
        private
        view
        returns (bool)
    {
        for (uint256 i = 0; i &amp;lt; votantes.length; i++) {
            if (
                keccak256(abi.encodePacked(votantes[i].clave)) ==
                keccak256(abi.encodePacked(_clave))
            ) {
                return false;
            }
        }
        return true;
    }

    function _validarOpcion(uint256 _opcion) private view returns (bool) {
        for (uint256 i = 0; i &amp;lt; opciones.length; i++) {
            if (opciones[i].id == _opcion) {
                return true;
            }
        }
        return false;
    }

    function votar(string memory _clave, uint256 _opcion) public {
        // Validar origen y sentido del voto
        require(_validarVotoUnico(_clave), "La clave de elector ya ha votado");
        require(
            _validarOpcion(_opcion),
            "La opcion elegida no corresponde a ninguna disponible"
        );

        // Si la opción de voto es válida y la clave no ha votado, registrar el voto
        for (uint256 i = 0; i &amp;lt; opciones.length; i++) {
            if (opciones[i].id == _opcion) {
                opciones[i].votos++;
                votantes.push(Votante(_clave, msg.sender, block.timestamp));
                emit NuevoVoto(_clave, msg.sender, block.timestamp);
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Las partes a destacar son las siguientes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El método &lt;code&gt;constructor()&lt;/code&gt; se ejecuta cuando se despliega el contrato en la red, e inicializa las opciones de votación con cero votos cada una. &lt;/li&gt;
&lt;li&gt;El método &lt;code&gt;votar&lt;/code&gt; valida primero que la opción por la que el cliente está intentando emitir su voto sea una de las opciones que tiene registradas. Después, se revisa que esa clave de elector no haya votado previamente. Finalmente, si los chequeos anteriores fueron exitosos, se guarda la clave de elector del votante, la dirección del monedero desde el que emitió su voto y la fecha en la que ocurre el registro.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Y listo. Con eso ya podemos empezar a registrar votos. Está muy simple y se  puede mejorar en varios sentidos. Pero lo importante es que funciona. &lt;/p&gt;

&lt;p&gt;Para que toda la red tenga acceso al contrato, es necesario desplegarlo, que es el equivalente a poner una página web en un servidor público.&lt;/p&gt;

&lt;p&gt;Pueden ver el contrato desplegado buscando esta dirección &lt;code&gt;0x41464D783f75fd9eE97A857730Cd665bC89A26BE&lt;/code&gt; en el explorador de &lt;a href="https://www.rinkeby.io/#explorer" rel="noopener noreferrer"&gt;la red Rinkeby&lt;/a&gt;. La dirección del contrato es como su URL. Así como los monederos tienen una dirección, los contratos y las computadoras de la red, también. Es su identificador.&lt;/p&gt;

&lt;p&gt;La red Rinkeby es una de las redes de pruebas de Ethereum. Estas redes  de pruebas se usan para proveer a los desarrolladores de un ambiente muy similar a la red principal de Ethereum para los contratos que están programando. El Ether que se intercambia en estas redes no tiene valor monetario.&lt;/p&gt;

&lt;p&gt;Lo que se ve buscando la dirección del contrato en el explorador de bloques es algo así:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcnhbenpvmggwqcp4rv4b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcnhbenpvmggwqcp4rv4b.png" alt="Contrato en el explorador de Rinkeby"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La tabla  de la parte inferior de la imagen es una lista de las transacciones (votos) que se han registrado en el contrato. Se tiene el identificador de la transacción, la dirección del monedero desde el que se votó y hasta el sentido del voto (codificado).  Esto otorga total transparencia al proceso. Si damos clic en alguna de las transacciones, podemos ver los detalles de la misma:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgxbzjum4ff0rcakkg1fg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgxbzjum4ff0rcakkg1fg.png" alt="Detalle de la transaccion"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Aplicación web
&lt;/h2&gt;

&lt;p&gt;También hice una aplicación web que permite registrar y leer los votos de una forma más amigable. &lt;/p&gt;

&lt;p&gt;Para usarla, necesitarán un monedero y, si quieren votar, algo de Ether de Rinkeby. Para obtener un monedero, &lt;a href="https://www.lemmingatwork.com/inversiones/criptomonedas/que-es-metamask/" rel="noopener noreferrer"&gt;en este link hay una guía&lt;/a&gt;, o si hablan inglés, &lt;a href="https://metamask.zendesk.com/hc/en-us/articles/360015489531-Getting-started-with-MetaMask" rel="noopener noreferrer"&gt;acá hay otra&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ya que tengan el monedero, será necesario algo de Ether para poder enviar su voto. El Ether de Rinkeby no tiene valor real, y pueden obtener un poco poniendo la dirección de su monedero en &lt;a href="https://rinkeby-faucet.com/" rel="noopener noreferrer"&gt;este link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faedq1ck086wvscvvlg94.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faedq1ck086wvscvvlg94.png" alt="Aplicación web para votar"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora sí, para votar, entramos a la aplicación y conectamos nuestro monedero, esto es como "iniciar sesión" en la aplicación, con la diferencia de que no necesitamos crear una cuenta, nuestro monedero es la cuenta. Verifiquen también que el monedero esté en la red Rinkeby. La aplicación les mostrará un mensaje si no es así.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fahq2jkl5ucdegz61ejj7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fahq2jkl5ucdegz61ejj7.png" alt="Monedero conectado"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego, hay que introducir una clave de elector válida, al menos en sintaxis, porque no tenemos otra forma de validarla. Necesitamos 6 consonantes, la fecha de nacimiento, la clave de la entidad, el sexo y otros 3 dígitos, por ejemplo: &lt;code&gt;HHRRTT90080713H100&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqx83pb7t56bu2z2hkliv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqx83pb7t56bu2z2hkliv.png" alt="Introduzca su clave de elector"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego se muestra la pregunta, y las 3 opciones por las que se puede votar. Estas opciones aparecen en orden aleatorio.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbvu1y48ly2oad7e2ihs1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbvu1y48ly2oad7e2ihs1.png" alt="Selección de voto"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se generará una transacción desde nuestro monedero hacia el contrato inteligente en la red y debe ser firmada por el usuario, es decir, tenemos que autorizar a que se envíe el voto desde nuestro monedero.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4og0mrykowtfwqkfj08u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4og0mrykowtfwqkfj08u.png" alt="Firmar transacción"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez que la autoricemos, se enviará y el blockchain iniciará el proceso de registro de la transacción, esto puede tomar varios segundos.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi8qb5h59sgd0fna7k6rn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi8qb5h59sgd0fna7k6rn.png" alt="Minando voto"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ya registrado el voto en el contrato, la aplicación nos redirige a la página de resultados.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyfge82i8bs3n2sqs9q2n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyfge82i8bs3n2sqs9q2n.png" alt="Página de resultados"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dejo aquí el link a un video de YouTube con todo el proceso de votación:&lt;br&gt;
&lt;a href="http://www.youtube.com/watch?v=VOI6GzrYNck" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fimg.youtube.com%2Fvi%2FVOI6GzrYNck%2F0.jpg" alt="Consulta de revocación de mandato usando Web3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Notas finales:
&lt;/h2&gt;

&lt;p&gt;Este ejercicio es bastante utópico. Dependería de que todos los ciudadanos tuviesen acceso a un monedero, o a una estación de votación que contenga un monedero compartido y que esté conectada a internet. Además de que se tendría que validar que la clave de elector esté registrada ante el INE, que el monedero desde el que se vota esté autorizado a emitir votos  y un largo etcétera. Como decía al principio, esto es únicamente para mostrar una aplicación del blockchain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Links del proyecto
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Dirección del contrato en Rinkeby: &lt;code&gt;0x41464D783f75fd9eE97A857730Cd665bC89A26BE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://consulta-popular.netlify.app/" rel="noopener noreferrer"&gt;Aplicación web&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Tepexic/consulta-popular" rel="noopener noreferrer"&gt;Repositorio en GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>web3</category>
      <category>ethereum</category>
      <category>javascript</category>
      <category>solidity</category>
    </item>
    <item>
      <title>Get unique objects from an array</title>
      <dc:creator>Jesús Velázquez</dc:creator>
      <pubDate>Tue, 23 Nov 2021 00:35:06 +0000</pubDate>
      <link>https://dev.to/tepexic/get-unique-objects-from-an-array-4cog</link>
      <guid>https://dev.to/tepexic/get-unique-objects-from-an-array-4cog</guid>
      <description>&lt;p&gt;Suppose you have an array of objects with at least one common property that could be used as an identifier.&lt;/p&gt;

&lt;p&gt;This function will allow you to create a new array with unique objects based on the selected property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getUniqueElementsFromArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;uniqueProperty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="c1"&gt;// The map will help us keep a record of the objects&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;uniqueProperty&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// New element, push it into results&lt;/span&gt;
      &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;uniqueProperty&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// you can set any value, we just need it to be in the Map&lt;/span&gt;
      &lt;span class="c1"&gt;// save unique object&lt;/span&gt;
      &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example: &lt;br&gt;
Let's say we have an array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sample&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;game&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;e&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;game&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;game&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;i&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;game&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;e&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;game&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;game&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;o&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;game&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;e&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;game&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;u&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;game&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;i&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;game&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use the property &lt;code&gt;'name'&lt;/code&gt; as identifier&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getUniqueElementsFromArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the result will yield:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;game&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;e&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;game&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;i&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;game&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;o&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;game&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;u&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;game&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding here a typescript version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getUniqueItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;uniqueProperty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;uniqueProperty&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;uniqueProperty&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>array</category>
      <category>object</category>
      <category>map</category>
    </item>
    <item>
      <title>Regex clave de elector de México</title>
      <dc:creator>Jesús Velázquez</dc:creator>
      <pubDate>Sun, 10 Oct 2021 00:47:31 +0000</pubDate>
      <link>https://dev.to/tepexic/regex-clave-de-elector-de-mexico-51ib</link>
      <guid>https://dev.to/tepexic/regex-clave-de-elector-de-mexico-51ib</guid>
      <description>&lt;p&gt;Sin más preámbulo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;BCDFGHJKLMNPQRSTVWXYZ&lt;/span&gt;&lt;span class="p"&gt;]{&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="nx"&gt;HM&lt;/span&gt;&lt;span class="p"&gt;]{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]{&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La clave de elector se compone de 18 caracteres, y se conforma con las primeras consonantes de los apellidos y primer nombre, año, mes, día y clave del estado en que su titular nació, su sexo y una homoclave interna de registro.&lt;/p&gt;

&lt;p&gt;Por partes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;[BCDFGHJKLMNPQRSTVWXYZ]{6}&lt;/code&gt; Captura 6 consonantes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[0-9]{2}&lt;/code&gt; Captura dos dígitos entre 0 y 9, para el año de nacimiento.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[0-1]{1}[0-9]{1}&lt;/code&gt; Captura el mes de nacimiento, la primera parte espera un dígito entre 0 y 1 y la segunda entre 0 y 9. Esto porque los meses los numeran 01, 02, ..., 12. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[0-3]{1}[0-9]{1}&lt;/code&gt; El día de nacimiento, de 01, 02, ..., 31&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[0-3]{1}[0-9]{1}&lt;/code&gt; Clave de la entidad federativa, muy parecida al día, porque se espera un número entre 01 y 31.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[HM]{1}&lt;/code&gt; El sexo del titular. Actualmente limitado a dos opciones, H o M.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[0-9]{3}&lt;/code&gt; Homoclave&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Defectos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El año, mes, día y clave del estado pueden ser 00&lt;/li&gt;
&lt;li&gt;El día y estado pueden llegar hasta 39&lt;/li&gt;
&lt;li&gt;El mes puede llegar hasta 19&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>My first coding challenge while job hunting</title>
      <dc:creator>Jesús Velázquez</dc:creator>
      <pubDate>Tue, 08 Dec 2020 15:49:25 +0000</pubDate>
      <link>https://dev.to/tepexic/my-first-coding-challenge-while-job-hunting-54dj</link>
      <guid>https://dev.to/tepexic/my-first-coding-challenge-while-job-hunting-54dj</guid>
      <description>&lt;p&gt;After several failed attempts to land a coding interview, they finally called me. They went with me over my CV and my previous experience with JavaScript on the phone, and I was really nervous, but I thought I did fine.&lt;/p&gt;

&lt;p&gt;A couple of days later, I got an email with a small coding challenge. But it didn't matter that it was small, it was my first real one. I've tried my hand at some coding challenges before (&lt;a href="https://github.com/Tepexic/project-euler-solutions"&gt;here are my solutions to a few Project Euler problems&lt;/a&gt;), but I've never had an &lt;em&gt;actual&lt;/em&gt; coding challenge for an interview.&lt;/p&gt;

&lt;p&gt;Here's what I had to do:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Write a function in JavaScript called ‘humanSize’ that takes a non-negative number of bytes and returns a string with the equivalent number of ‘kB’, ‘MB’, ‘GB’, ‘TB’, ‘PB’, ‘EB’, ‘ZB’, or ‘YB’, between [0, 1000), with at most 1 digit of precision after the decimal. If the number of bytes is &amp;gt;= 1000 YB, return this number of YB, for example 5120 YB. For example, your function might return ‘107.3MB’. Write this function without writing a separate case for each byte prefix, and without using Math.log or Math.pow.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The planning
&lt;/h2&gt;

&lt;p&gt;The first thing I though was: this will need testing. I needed to write some tests to check that the function was actually doing what I wanted it to do, and the best approach would be using Test Driven Development (TDD). This way I could show that I knew how to test my code and I could plan ahead. I also wanted to set up a GitHub Repo to store all of this.&lt;/p&gt;

&lt;h2&gt;
  
  
  The algorithm
&lt;/h2&gt;

&lt;p&gt;I was certain I needed tests. But I still had no clear idea on how to get it done. So I took my pencil and my notebook and scribbled a flowchart.&lt;/p&gt;

&lt;p&gt;The idea behind was simple: I was to have a dictionary for the prefixes, this was easier to do than a &lt;em&gt;switch-case&lt;/em&gt; statement, or several &lt;em&gt;if-else&lt;/em&gt; ones, and, I was not allowed to use them anyway. This dictionary needed a &lt;em&gt;"pointer"&lt;/em&gt;, a way to tell how many times had I divided by 1000.&lt;/p&gt;

&lt;p&gt;I also needed a loop, a way to constantly divide the input (number of bytes) by 1000, until its integer part was 0, that meant I had reached the maximum times of divisions by 1000, and thus, I had a number to show. The dictionary pointer needed to increase at every run of the loop, and the loop was to run at least once, to check if a had something at least in a size of &lt;em&gt;kB&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The problem statement had another restriction: &lt;em&gt;If the number of bytes is &amp;gt;= 1000 YB, return this number of YB&lt;/em&gt;. This meant that whenever I had divided by 1000 more than 8 times, I had reached the line of thousands of yottabytes. I came into this conclusion by looking up how many zeros there are in a yottabyte. Turns out the factor is 10²⁴, so 24/3 = 8. This was to be a condition within my loop.&lt;/p&gt;

&lt;p&gt;If the loop was broken by this last condition, the function had to return the rounded number of yottabytes. Otherwise, return the rounded number to 1 decimal place and concatenate it as a string to the dictionary prefix extracted by the pointer.&lt;/p&gt;

&lt;p&gt;After some iterations, I had this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BLAKTv79--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8wf4b6y6fn25jnumds5b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BLAKTv79--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8wf4b6y6fn25jnumds5b.png" alt="Algorithm flowchart" width="619" height="699"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wasn't planning on error handling here, I thought that was best left to the coding part, but I wanted the function to return &lt;em&gt;'0kB'&lt;/em&gt; if the input was not valid.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tests
&lt;/h2&gt;

&lt;p&gt;I decided to go with &lt;a href="https://dev.to/aliyalewis/test-driven-development-3086"&gt;TDD&lt;/a&gt; on this one, so the first thing to to is write the Tests. By this point, I already knew 2 things: what the function had to do and how was it going to do it.&lt;/p&gt;

&lt;p&gt;I started a new Node project inside my &lt;em&gt;/human-size/&lt;/em&gt; folder by running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The idea behind each test was to provide a number of bytes and compare the output of the function to what I already knew the conversion value was. I'm familiar with &lt;a href="https://jestjs.io/"&gt;Jest&lt;/a&gt;, so I had to install it first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save jest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then my first test was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test("Should return 3.1kB", () =&amp;gt; {
    expect(humanSize(3125)).toBe("3.1kB");
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Given 3125B, I knew this was 3.125kB, but, by definition, I was to round that number to 1 decimal place, hence &lt;em&gt;3.1kb&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Then I went a bit picky and wrote the tests for an invalid input, such as a &lt;em&gt;String&lt;/em&gt;, &lt;em&gt;NaN&lt;/em&gt;, &lt;em&gt;Object&lt;/em&gt;, &lt;em&gt;Array&lt;/em&gt; or simply a negative number:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test("Should return 0kB when input is String", () =&amp;gt; {
    expect(humanSize("asd")).toBe("0kB");
  });

  test("Should return 0kB when input is NaN", () =&amp;gt; {
    expect(humanSize(NaN)).toBe("0kB");
  });

  test("Should return 0kB when input is Object", () =&amp;gt; {
    expect(humanSize({ a: "foo", b: 123 })).toBe("0kB");
  });

  test("Should return 0kB when input is Array", () =&amp;gt; {
    expect(humanSize([200, 100])).toBe("0kB");
  });

  test("Should return 0kB when input is &amp;lt;0", () =&amp;gt; {
    expect(humanSize(-25)).toBe("0kB");
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From this point onwards, the test should be focused on ensuring the correct output. So I wrote a test for every prefix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test("Should return 31.3kB", () =&amp;gt; {
    expect(humanSize(31250)).toBe("31.3kB");
  });

  test("Should return 31.3MB", () =&amp;gt; {
    expect(humanSize(31250000)).toBe("31.3MB");
  });

  test("Should return 31.3GB", () =&amp;gt; {
    expect(humanSize(31250000000)).toBe("31.3GB");
  });

  test("Should return 31.3TB", () =&amp;gt; {
    expect(humanSize(31250000000000)).toBe("31.3TB");
  });

  test("Should return 31.3PB", () =&amp;gt; {
    expect(humanSize(31250000000000000)).toBe("31.3PB");
  });

  test("Should return 31.3EB", () =&amp;gt; {
    expect(humanSize(31250000000000000000)).toBe("31.3EB");
  });

  test("Should return 31.3ZB", () =&amp;gt; {
    expect(humanSize(31250000000000000000000)).toBe("31.3ZB");
  });

  test("Should return 31.3YB", () =&amp;gt; {
    expect(humanSize(31250000000000000000000000)).toBe("31.3YB");
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, test for the thousands of YB case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test("Should return 3125YB", () =&amp;gt; {
    expect(humanSize(3125000000000000000000000000)).toBe("3125YB");
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now I added the test script to my &lt;em&gt;package.json&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
    "test": "jest",
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The code
&lt;/h2&gt;

&lt;p&gt;I decided to focus on the invalid cases first. If we operate on something that is not a number (let's not count string concatenation), we would get a &lt;em&gt;NaN&lt;/em&gt;. So I did that, and also added another check for negative numbers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function humanSize(b) {
    // default return when input is not valid
    const def = "0kB";
    // Parse input
    if (isNaN(b / 1000)) return def;
    if (b &amp;lt; 0) return def;
  }

  module.exports = humanSize;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will pass the invalid input tests, but fail all others. In TDD, this is the right track.&lt;/p&gt;

&lt;p&gt;Now it's time to translate the flowchart into code. The first part is the dictionary and the initialization of variables&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function humanSize(b) {
    // default return when input is not valid
    const def = "0kB";
    // Parse input
    if (isNaN(b / 1000)) return def;
    if (b &amp;lt; 0) return def;
    // Prefix hash
    const prefix = {
      1: "k",
      2: "M",
      3: "G",
      4: "T",
      5: "P",
      6: "E",
      7: "Z",
      8: "Y",
    };
    // Prefix pointer/counter
    var i = 0;
    // Initialize size variable
    var B = b;
  }

  module.exports = humanSize;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Good, now I needed the loop. Notice I set up the first index of my dictionary to 1, and my pointer starts at 0. I did this because I needed to know if the number of bytes was at least on the range of &lt;em&gt;kB&lt;/em&gt;, that means, the loop has to run at least once. This led me into a Do While statement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function humanSize(b) {
    // default return when input is not valid
    const def = "0kB";
    // Parse input
    if (isNaN(b / 1000)) return def;
    if (b &amp;lt; 0) return def;
    // Prefix hash
    const prefix = {
      1: "k",
      2: "M",
      3: "G",
      4: "T",
      5: "P",
      6: "E",
      7: "Z",
      8: "Y",
    };
    // Prefix pointer/counter
    var i = 0;
    // Initialize size variable
    var B = b;
    // Iterate over the size variable until its integer part is 0
    do {
      if (i &amp;gt; 7) return Math.round(B.toString()) + prefix[8] + "B";
      i += 1;
      B /= 1000;
    } while (Math.trunc(B / 1000) &amp;gt; 0);
  }

  module.exports = humanSize;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also included the check for thousands of &lt;em&gt;YB&lt;/em&gt;, it'll break the loop and return the rounded number of YB. Now the only thing missing was to round the number to 1 decimal place for all other cases. A quick search on &lt;a href="https://www.30secondsofcode.org/"&gt;30 Seconds of Code&lt;/a&gt; gave me a snippet called simply &lt;em&gt;round&lt;/em&gt;, that returns a number rounded to a specified number of decimals:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const round = (n, decimals = 0) =&amp;gt; Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So I embeded that into my &lt;code&gt;humanSize(b)&lt;/code&gt; function, followed by the prefix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function humanSize(b) {
    // default return when input is not valid
    const def = "0kB";
    // Parse input
    if (isNaN(b / 1000)) return def;
    if (b &amp;lt; 0) return def;
    // Prefix hash
    const prefix = {
      1: "k",
      2: "M",
      3: "G",
      4: "T",
      5: "P",
      6: "E",
      7: "Z",
      8: "Y",
    };
    // Prefix pointer/counter
    var i = 0;
    // Initialize size variable
    var B = b;
    // Iterate over the size variable until its integer part is 0
    do {
      if (i &amp;gt; 7) return Math.round(B.toString()) + prefix[8] + "B";
      i += 1;
      B /= 1000;
    } while (Math.trunc(B / 1000) &amp;gt; 0);
    // Return size rounded to 1 decimal with correspoding prefix
    return (
      Number(`${Math.round(`${B}e${1}`)}e-${1}`).toString() + prefix[i] + "B"
    );
  }

  module.exports = humanSize;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function is now passing all the tests, and, believe me, that is one of the best feelings in the world.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final remarks
&lt;/h2&gt;

&lt;p&gt;That was it. The only thing left was to create a &lt;code&gt;.gitignore&lt;/code&gt; to avoid pushing the &lt;em&gt;/node_modules&lt;/em&gt; folder to the GitHub repository. &lt;/p&gt;

&lt;p&gt;They asked me to submit the function inside a GitHub gist, so I did. I'm waiting for their response now. I'll update as soon as I know anything :)&lt;/p&gt;




&lt;p&gt;Update: Didn't get the job. It was a good challenge, though.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Tepexic/human-size"&gt;Here's the repo of this code&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>challenge</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Upload and preview a video using vanilla JavaScript</title>
      <dc:creator>Jesús Velázquez</dc:creator>
      <pubDate>Wed, 11 Nov 2020 22:37:01 +0000</pubDate>
      <link>https://dev.to/tepexic/upload-and-preview-a-video-using-vanilla-javascript-37k2</link>
      <guid>https://dev.to/tepexic/upload-and-preview-a-video-using-vanilla-javascript-37k2</guid>
      <description>&lt;p&gt;I recently googled the title, and found several solutions on how to do it with jQuery, but I was working with Vue and needed a pure JS implementation. &lt;a href="https://codepen.io/tepexic/pen/BazYgJe"&gt;Here's a codepen with the code.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We need an &lt;code&gt;input&lt;/code&gt; field and a &lt;code&gt;video&lt;/code&gt; tag in our HTML to begin with, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt; &lt;span class="na"&gt;accept=&lt;/span&gt;&lt;span class="s"&gt;"video/*"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"input-tag"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;hr&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;video&lt;/span&gt; &lt;span class="na"&gt;controls&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"video-tag"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"video-source"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"splashVideo"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Your browser does not support the video tag.
&lt;span class="nt"&gt;&amp;lt;/video&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, in the JS, let's get the handles of our HTML elements&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;videoSrc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#video-source&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;videoTag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#video-tag&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inputTag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#input-tag&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this ready, we can write the function that will read the video and show it inside the &lt;code&gt;video&lt;/code&gt; tag, we're using the FileReader API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;readVideo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;FileReader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;videoSrc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;
      &lt;span class="nx"&gt;videoTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readAsDataURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The trick here consists on reading the selected file as URL. This way, it can be read by the &lt;code&gt;video&lt;/code&gt; tag. &lt;/p&gt;

&lt;p&gt;When the file has been uploaded (&lt;code&gt;.onload&lt;/code&gt; event), we simply point the &lt;code&gt;src&lt;/code&gt; property of the video to the result of the FileReader instance. Then execute the &lt;code&gt;load()&lt;/code&gt; method from the &lt;code&gt;video&lt;/code&gt; tag.&lt;/p&gt;

&lt;p&gt;That's it. I hope it was helpful. &lt;a href="https://codepen.io/tepexic/pen/BazYgJe"&gt;Here's a codepen with the code again.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Header image by &lt;a href="https://unsplash.com/@kushagrakevat"&gt;Kushagra Kevat&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>html</category>
      <category>filereader</category>
    </item>
  </channel>
</rss>
