NPM y el síndrome New Balance

Hola,

No demonicéis el título tan rápido, tendrá sentido cuanto antes. La idea de hoy no es hablaros de ninguna de las dos cosas, de todas formas. El tema es que…

NPM se ha convertido en el registro de software más grande del mundo.

Tal cual.

La gente como yo, que somos de esos que nos hacemos preguntas, nos preguntamos por qué. ¿NPM se publicó en 2010, hace 8 años, y ya tiene más software que cualquier otro registro de software?

¿Cuando se publicó C? ¿En 1970? ¿Y cuantos superrepos de C tenemos?

¿Qué pollas tiene que ver esto con New Balance?

New Balance, una marca de zapatillas que ni recomiendo ni boicoteo, tuvo un interesante tema con unas zapatillas tonificantes que supuestamente te hacían adelgazar más rápido al usarlas para correr o andar. Fueron denunciados por publicidad engañosa.

Los estudios para el juicio concluyeron que “a pesar de que no hay ninguna evidencia estadísitica de que esos zapatos sean más saludables que otros, sí que han conseguido motivar a muchas personas a cambiar a una vida saludable al darles la creencia de que con ellos sería más sencillo”.

Pues ese es para mí el síndrome New Balance. Eso es lo que le pasa a NPM.

Es tan fácil sacar módulos de NPM que da gusto hacerlo. Se publican con un comando:

npm publish

Y punto. Una gestión de dependencias sencilla y eficaz hacen el resto.

Me vas a decir que tenemos miles de módulos en la carpeta node_modules, montón de dependencias pesadas, proyectos con kilos de dependencias que no necesitan, idiotas usando NPM para publicar CSS y cargándolo en el index.html con un path que empieza por node_modules dejando en evidencia que están sirviendo toda la carpeta. Me vas a escupir toda esa mierda de que te ha fallado alguna vez con nosequé y que yarn es mejor y no sé qué mierda más. Y luego te meterás con JavaScript porque te parece una basura, con su callback hell y todo eso. Que Java es mejor. Mil cosas más.

Pero, como dicen los angloparlantes, al final del día, no tendrás un repo tan grande de software porque no has pensando en lo importante.

En hacer unas zapatillas que te hagan adelgazar al ponértelas. O que no lo hagan, pero que tú te lo creas.

Eso es NPM.

Un sistema de paquetes fácil de usar, sobre un lenguaje que todo el mundo cree saber (aunque pocos dominen), que es fácil de aprender y que adelgaza. Así es como se consigue tener éxito.

Cuando es tan evidente de usar que da igual si lo hace bien o no mientras a ti te sirva.

Anima a la gente a programar. Da igual que PIP sea mejor, o que python nosequé, ni que CPAN sea un verdadero gestor de paquetes, que Yarn se haya creado directamente con el semen del señor Z. Da puto igual.

Es tan fácil, que todos lo usan.

 

Y tú también.

 


Por lo que sea:

Esa entrada es para generar un poco de debate y los comentarios están para eso. No se me ha ido la pinza todavía.
Creo.

Anuncios

Cryptonight o por qué se puede minar criptomoneda en el browser

Hola,

Hoy me veo obligado a contaros una cosa que hace tiempo que he revisado y estudiado pero que creo que tenéis que conocer. La proliferación del script de Coinhive1 y su reciente aparición en la web de Movistar creo que son razón suficiente para contaros qué coño está pasando con las criptomonedas y por qué podéis minarlas en un browser.

Como habréis leído, Coinhive no es un minero de Bitcoin, por mucho que los medios que no se enteran de nada lo estén diciendo. Sí que hay algunos que han acertado diciendo que Coinhive es un minero de Monero, otro tipo de criptomoneda enfocada al anonimato de sus usuarios.

Dicho esto, con esta entrada lo que pretendo es sacaros de vuestras dudas a los que estáis flipando por ver gente minar criptomonedas en el Browser. Os contaré por qué se puede y cómo funciona.

Como introducción:

Para minar criptomonedas, cualquiera de ellas, el proceso es el siguiente:

  • El minero crea bloques para añadir al blockchain. También os lo podría contar pero lo dejamos para otra vez. Investigad un poco y preguntad si lo necesitáis.
  • Para que el bloque sea aceptado en el blockchain tiene que pasar el Proof-Of-Work. En Bitcoin el Proof-Of-Work se basa en encontrar un Nonce para el que el SHA-256 del bloque sea menor que el número marcado por la dificultad. Tampoco voy a entrar.
  • Se manda el bloque a la red y si eres el primero te lo aceptarán y cobrarás tu premio.

Monero, recordemos que no es Bitcoin lo que mina el coinhive, utiliza un Proof-Of-Work distinto inventado por la peña de CryptoNote. Esa es la razón de todo lo que os voy a contar hoy.

El Proof-Of-Work del que os hablo fue inventado como solución a un problema que probablemente ya conocéis: En Bitcoin dependiendo de cuál sea el equipo que usas para minar, tu capacidad de minado cambia mucho. Cuando minas por GPU en Bitcoin le das mil vueltas a un tío con un PC, así que minar con PC ya no tiene sentido. Lo mismo pasa con los chips específicos, ahora tienen tanto rendimiento que una GPU se queda muy pequeña.

Con el PoW (Proof-of-Work) que os voy a presentar hoy esto no pasa. La peña de CryptoNote hizo lo que ellos llaman “Egalitarian Proof-of-Work” que significa Proof-of-Work igualitario en inglés y que básicamente viene a decir que es igual de difícil minar con él en una CPU, en una GPU, etc. Y que hacer un ASIC para esto no es factible. Simple, ¿no?

Este PoW igualitario es igual que el de Bitcoin pero con una función de hashing distinta. En lugar de utilizar SHA-256 usa una función de hashing diseñada por las mismas personas de CryptoNote. La función de hashing se llama CryptoNight. Esta función tiene como peculiaridad que es una función memory-hard: Requiere mucha memoria para resolverse.

Vamos al por qué de todo esto y luego vamos al algoritmo.

Como he dicho en la introducción, tienes que ser el primero en entregar el bloque para llevarte el premio. En Bitcoin el primero es el que más potencia de computación tiene porque la función SHA-256 se resuelve con operaciones matemáticas. El que sea más rápido haciéndolas es el que se lleva el premio. Las GPUs son hardware específicamente diseñado para resolver este tipo de matemáticas y hacerlo de forma paralela, por eso son mejores mineras que una CPU. Los ASIC, Application Specific Integrated Circuit, es evidente por qué son más rápidos que una GPU, simplemente han nacido para serlo porque están diseñado específicamente para resolver esas operaciones.

CryptoNight no permite esto, porque su dificultad no está en la cantidad o complejidad de las operaciones matemáticas que tiene, sino en la cantidad de memoria que necesita. Con CryptoNight el primero no es el que más capacidad de computación tiene, sino el que más rápido accede a la gran cantidad de memoria que el algoritmo requiere. Requiere mucha memoria y le hace muchas operaciones de lectura, convirtiéndola en el cuello de botella del algoritmo.

A nivel práctico hay muy pocos dispositivos con acceso a una cantidad de memoria como la que CryptoNight necesita (2 MiB) a la velocidad necesaria como para que tenga sentido utilizarlos. Está diseñado específicamente para ser ineficiente en GPUs, FPGAs y ASICs y hace que la diferencia de minar en un ordenador a hacerlo en otro no sea muy grande. Es igualitario.

Pero, ¿por qué?

Cuando hacemos muchas lecturas y escrituras a un bloque de memoria, nuestra CPU usa una cosa que no podemos ni tocar a nivel de programación: la mágica Caché.

La caché es un conjunto de memorias más rápidas que la RAM que forman una arquitectura jerárquica. Estas memorias son mucho más rápidas que la RAM pero también mucho más pequeñas. Resumiendo mucho, la CPU intuye qué datos vas a leer más y los coloca en la caché para poder acceder más rápido.

CryptoNight explota lo que se conoce como data-locality (que los datos estén cerca) para asegurarse que la CPU se los cachea (normalmente en la L3). De esta forma el acceso al bloque de memoria es mucho más rápido. Hacer esto en otro dispositivo es muy ineficiente porque no tienen cachés de esos tamaños y tienen que hacerlo tirando de RAM, lo que tarda algunos órdenes de magnitud más.

Ésta es la razón por la que si buscáis por ahí encontraréis que el Hashing power necesario para minar cualquier moneda que use CryptoNight como función de hashing es muchísimo más bajo, por norma general, que en las demás2.

Como habéis entendido ya, eso permite que alguien programe un minero orientado al Browser, lo compile a webassembly y ponga a los visitantes a su web a minar. No será tan eficiente como un minero en C, pero es lo bastante rápido para sacar buena pasta si tienes muchos visitantes. Se entiende. ¿No?

Ahora voy a contar lo que me interesa a mí, que es cómo funciona el puto CryptoNight. Sirva lo otro de puesta en situación 😀

CryptoNight

Aquí tenéis el estándar, pero yo voy a intentar contarlo de forma más amigable.

Recordemos que CryptoNight no es un PoW, ni un minero, sólo es la función de hashing. Lo otro lo investigáis si queréis (¡o igual lo cuento otro día!).

Que sea una función de hashing significa que, como MD5, SHA-1, SHA-2, SHA-256, etc, es una función que recibe datos (de cualquier tipo y tamaño) como entrada, y que su salida es un churro binario de longitud fija. Estas funciones, para que sean buenas, tienen que ser relativamente rápidas de calcular y tienen que ser impredecibles, no se tiene que poder saber qué salida darán sin ejecutar la función.

Esta función de hashing utiliza varias funciones de hashing dentro así como varias partes del estándar de cifrado AES de una forma bastante peculiar. No nos asustemos que es bastante sencillo.

Todo el algoritmo se basa en una cosa que denomina scratchpad, que es un bloque de memoria bastante tosco que usa para guardar valores intermedios. El scratchpad es lo que se utiliza para explotar la cache.

El algoritmo tiene como 3 etapas principales:

  1. Preparar el scratchpad
  2. El loop principal
  3. Calcular el resultado

Para entrar en la primera etapa hace una especie de etapa inicial que sirve para inicializar lo que ellos llaman state (o keccak-state), que es un pequeño bloque de datos del que surge todo. El state se consigue aplicando la función de hashing keccak a la entrada de nuestro algoritmo. Utiliza unos parámetros concretos, pero eso os lo leéis.

Al haber pasado por keccak, nuestro estado inicial será un churro de 200 Bytes. Este churraco es el que usa para sacar los datos.

Vamos a preparar el scratchpad: Etapa 1.

Se cogen los primeros 32 bytes del state y se expanden a 10 keys de AES. Por si no lo sabíais (yo no lo sabía) AES tiene un sistema de expansión de claves que usa para sus rondas de ejecución, el sistema lo podéis encontrar aquí.

Primero se obtienen 8 bloques de 16 bytes de los bytes 64-191 del state y se usan como bloques iniciales. Esos bloques se pasan por 10 rondas de AES usando las claves obtenidas y su resultado se inyecta en los primeros espacios del scratchpad (que es un array de 2097152 bytes) uno a uno. El resultado de aplicar AES a cada uno de los bloques será tomado como los nuevos bloques y se pasarán por las rondas de AES de nuevo para llenar con ellos los siguientes bytes del scratchpad. Este proceso se repite hasta llenar todo el scratchpad.

Por si no lo sabéis (yo tampoco lo sabía), AES funciona por rondas. Para el tamaño de clave que usamos aquí, AES-256, se aplican más de 14 rondas pero nosotros aquí no lo haremos. Además, algunas de las rondas son especiales, pero para nosotros no lo serán, nuestras rondas usan los pasos: SubBytes, ShiftRows y MixColumns.

Una vez tenemos scratchpad lleno lo leemos a lo loco: Etapa 2.

La etapa 2 es el memory-hard loop. Una etapa un poco extraña que usa un par de variables llamadas a y b (se ve que no estaban muy creativos) y unas pocas funciones: toScratchpadAddress, 8ByteAdd y 8ByteMultiply. Las funciones éstas sirven para convertir un valor a una dirección del scratchpad (lo hace en little-endian y movidas), para sumar sumar dos argumentos de 64 bits jugando con el endianness y para multiplicar de una forma concreta, respectivamente. No voy a entrar en cómo lo hace, porque a parte de ser bastante sencillas no afectan demasiado en la visión general que quiero aportar.

Lo primero que hace es inicializar las variables a y b cada una con la mitad izquierda y derecha del XOR de los primeros 32 bits del state y de los segundos, respectivamente. Una vez que las inicializa se dispara el loop. El memory-hard loop es un bloque de código que se ejecuta 524288 veces.

En el loop se utilizan las variables a y b como direcciones del scratchpad y se van transformando y releyendo. Con esto, se hacen un montón de lecturas al scratchpad haciendo que el cuello de botella de la función sea la latencia de lectura. Concretamente se hace de la siguiente manera:

  1. Se convierte a a una dirección del scratchpad con la función que hemos definido.
  2. Se le aplica una ronda de AES al contenido del scratchpad en la dirección obtenida de a en la etapa anterior usando a como key y se guarda el resultado en esa dirección del scratchpad.
  3. El resultado obtenido en la etapa 2 se guarda como b pero antes se utiliza el valor anterior de b para aplicarle un XOR con el valor de la etapa 2 y guardarlo en la posición del scratchpad de la etapa 2. Si os fijáis, ambas cosas deben hacerse a la vez porque cada una pisa la otra.
  4. Se convierte b a una dirección del scratchpad con la función de antes.
  5. Se obtiene una nueva a haciendo la suma de a y el resultado de la multiplicación de b y el valor del scratchpad en la dirección obtenida en la etapa 4. Ambas funciones, multiplicación y suma, son las que hemos definido más arriba.
  6. Se obtiene una nueva a desde el XOR de a con el valor del scratchpad obtenido en el paso 4 y, al mismo tiempo, se iguala el valor del scratchpad en esa dirección al valor anterior de a. Igual que antes ojo, que una cosa pisa a la otra.

Una vez repetido ese loop 524288 veces, toca sacar el resultado.

El resultado: Etapa 3

Ahora se expanden los bytes 32-63 del state para obtener 10 keys como en la etapa de inicialización y se usan los bytes 64-191 del state como bloque inicial. A éstos últimos se les aplica un XOR con los primeros 128 bytes del scratchpad y el resultado se cifra como se hizo en la primera parte, con las rondas internas de AES y las keys obtenidas. El resultado se pasa por un XOR con los segundos 128 bytes del scratchpad y se vuelve a cifrar. Y así hasta pasar por todo el scratchpad.

El resultado de pasar por el scratchpad completo se inserta en el state, en los bytes 64-191, para dar lugar al Modified state. Una vez tenemos eso, le aplicamos una permutación de keccak (también llamado keccak-f) al estado modificado.

Por si no lo sabíais (que yo no lo sabía), keccak es una familia de funciones hash que se propuso para ganar el SHA-3 y ganó. Son funciones muy interesantes de tipo esponja y nosequé. La permutación es una de las etapas internas, tampoco necesitamos saber mucho más por ahora.

Del resultado de la permutación se obtienen los dos bits menos significativos de su primer byte. Con ellos se elige entre las siguientes funciones de hasheo:

Valor Función
00 Blake-256
01 Groestl-256
10 Jh-256
11 Skein-256

La función elegida se le aplica al Modified State y su resultado será el resultado de CryptoNight.

No sé si lo sabíais (yo no lo sabía), pero las funciones de la lista son las finalistas del concurso de SHA-3. La ganadora fue keccak, pero éstas llegaron a la final. Cada una es una función de hash distinta.

Ya sé que así es bastante infumable, así que os dejo a continuación un cachito de código que escribí en el que se hace CryptoNight. Es un pedazo de pseudocódigo con comentarios en inglés. Creo que es CoffeeScript valido, pero no lo aseguro. La idea es que lo podáis leer más fácilmente, nada más. Lo hice para enterarme de lo que leía cuando leí el paper.

EDIT: Os dejo el fichero de código aquí por si no veis el código que está debajo de esta línea.


# Pseudocode for Cryptonight
# --------------------------
#
# Written in CoffeeScript for simplicity but untested.
# See:
# https://cryptonote.org/cns/cns008.txt

#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.

#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.

#   You should have received a copy of the GNU General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
# 

get_keccak_state = (input)->
    keccak_block_width = 1600 # b
    keccak_capacity    = 512  # c

    # final_state expects a list of bytes for simplicity
    final_state = keccak input, keccak_block_width, keccak_capacity
    return final_state

scratchpad_init = (final_state)->
    scratchpad         = []

   # +-------------------------------------------------------------+
   # |                         Final state                         |
   # +-------------+--------------+---------------+----------------+
   # | Bytes 0..31 | Bytes 32..63 | Bytes 64..191 | Bytes 192..199 |
   # +-------------+--------------+---------------+----------------+

    # Make the keys with the first part of the final state
    # Expand to 10 round keys
    keys = aes256_expand_key final_state[0..31], 10


    # Make 8 blocks of 16 bytes with the third part of the final state
    initial_blocks = final_state[64..191]
    blocks = []
    for i in [0..7]
        blocks[i] = initial_blocks[i*16..(i+1)*(16)]

    # Fill the scratchpad
    s_byte = 0
    while s_byte < 2097152
        # Encrypt each block where aes256_round function does: SubBytes,
        # ShiftRows and MixColumns on the block and the result is XORed with
        # the key.  Note: the first and the last are not special like in
        # standard AES.
        for i in [0..9]
            blocks = (aes256_round b, keys[i] for b in blocks)
        for block in blocks
            for byte in block
                scratchpad[s_byte] = byte
                s_byte++

    return scratchpad

memory_hard_loop = (final_state, scratchpad) ->
    # define a and b variables
    vars = xor final_state[0..31], final_state[32..63]
    a = vars[0..15]
    b = vars[16..31]

    # Memory-hard loop
    iter = 0
    while iter < 524288
        addr = to_scratchpad_address a
        scratchpad[addr] = aes256_round scratchspad[addr], a
        [b, scratchpad[addr]] = [scratchpadd[addr], xor b, scratchpad[addr]]

        addr = to_scratchpad_address b
        a = _8byte_add( a, _8byte_mul(b, scratchpad[addr]))
        [a, scratchpad[addr]] = [xor(a, scratchpad[addr]), a]

        iter++

    # Result calculation
    keys = aes256_expand_key final_state[32..63], 10
    block = final_state[64..191]
    iters = 0
    while iters < scratchpad.length()/128
        # Encrypt like before
        block = xor block, scratchpad[i..i*128-1]
        for i in [0..9]
            block = aes256_round block, keys[i]
        iters++

    # the bytes 64..191 of the Keccak state are replaced with the result
    final_state[64..191] = block

    keccak_block_width = 1600 # b
    keccak_capacity    = 512  # c
    modified_state = keccak_f final_modified_state, keccak_block_width, keccak_capacity

    # two last bits of the first byte of the modified_state
    selector = modified_state[0] % 4
    functions =
        0: blake_256
        1: groestil_256
        2: jh_256
        3: skein_256

    # result:
    return functions[selector] modified_state

cryptonight = (input)->
    final_state = get_keccak_state input
    scratchpad  = scratchpad_init final_state
    result      = memory_hard_loop  final_state, scratchpad
    return result

Y esto es todo por hoy, me parece.

Vale ya, sí.

Esta entrada ha sido durilla. Para que no creáis que todo es lloriqueo y gilipollez.

Un abrazo.


  1. Coinhive es una empresa que te da una librería para que insertes en tu página web y que los visitantes minen criptomonedas al entrar. Ellos se quedan con un porcentaje. No pongo link, lo siento, mi religión me lo prohíbe.
  2. Hay más PoW igualitarios. Los que usan EquiHash, por ejemplo.

Oink Oink

Si tuviese que resumir el año me reiría de mí mismo de la forma más cruel. Pero como no tengo que hacerlo sólo voy a contar lo que se me ocurra.

Ya sabes lo que ando haciendo, las mierdas de siempre.

A veces siento que mi año empezó en Febrero. Cuando dejé ese curro y todo cambió. A veces siento que necesitaba ese par de meses anteriores para que todo fuese un giro bestial. No sé si quiero hablarte de eso o de otras cosas, sinceramente.

A las 5 de la mañana me he despertado y hasta que me he dormido he preparado un boceto en mi cabeza de lo que te quería contar y se me ha olvidado todo. Las cosas que tiene la vida. He tenido un día intenso. Sólo me he quedado con el título. Real.

Igual estás flipando ahora mismo. Creo que necesitas cierto contexto… Con esto bastará:

https://pfctelepathy.wordpress.com/2017/04/26/futuro-presente/

https://pfctelepathy.wordpress.com/2017/03/25/verguenza-inocente/

He informado demasiado poco y como en un buen embudo que es nuestra capacidad comunicativa ahora todo se atasca y no tengo ni puta idea de qué decirte. Tendría que borrar esto después pero si lo hiciera no estaríamos charlando tan a gusto, ¿lo entiendes verdad?

Gracias por comprenderlo. Sólo necesito que esto arranque.

Sí, lo tengo.

Durante este tiempo desde “la huída” he tenido ocasión de recapacitar, eso que me gusta tanto, pararme a pensar en la realidad que nos rodea y, sobre todo, hacer autoanálisis. Creo que la razón por la que estoy aquí, escribiendo esto, y fuera del sistema, creando un curro para mí en ElenQ Technology, es la misma. La puta misma.

Oink oink.

Ayer enseñe las figuras que hago (en digital y tradicional) cuando me aburro y me dijeron que tenía que aburrirme más a menudo. Respondí que sueño con mandarlo todo a la mierda y dedicarme a eso, al arte, y que si alguien me compra esa Cintiq 13HD de 800 napos puede que lo haga.

¿Podría?

No lo sé, puede que sea una droga para mí. Esa cosa que no puedo parar de hacer: diseñar cosas, inventar movidas, crear cosas jodidas y cuando las tengo diseñadas dejarlas sin terminar. Eso es lo que me vuelve loco. Eso es lo que hago. Pero echo tanto de menos otras cosas… Por suerte, ahora soy yo quien organiza cómo y cuándo las hago hasta cierto punto. Sólo hasta cierto punto.

Tengo que comer y eso es una putada.

Oink oink.

Es chungo que tenga que buscarle utilidad a lo que más me gusta hacer, para que a alguien le guste y crea que debe pagarme por ello. Es una putada. Puede que sea un first-world problem pero yo no puedo ser otro pavo más en la oficina, otro esclavo más del sistema que te dice lo que tienes qué hacer, cuándo y cómo.

Hablo de mí para no hacer que nadie se sienta incluido, pero somos muchos ahí fuera. Tú también eres así, estoy seguro. Trabajes en una mierda de curro o hayas tirado por tu cuenta, tú también lo eres. ¿Quizás no lo suficiente?

Oink oink.

Sirva esto de introducción para resumir lo que he estado haciendo últimamente, obligado por las fechas o motivado por ellas. Llámalo como quieras ¡Que dependa de tu estado de ánimo!

A esto me refería cuando decía las mierdas de siempre. He estado trabajando con cosas de ElenQ Technology, que no deja de ser una extensión de mí mismo, cosas molonas de esas que me quitan el sueño y me hacen sonreír. He cambiado el mundo un poco, para bien esta vez, y me siento genial.

Estoy trabajando en proyectos de los que no sé si sacaré un puto duro. Oink oink. Así es. No pasa nada tampoco, al menos de momento. Os hago una lista:

Hoy se me ha vuelto loco el día porque he publicado esto:

https://mastodon.art/gallery/index.html

Una galería artística que usa Mastodon como fuente de datos para visualizar. Esto pretende ser un proyecto artístico, una performance, para enseñar a la gente que montar cosas es fácil. Que podemos tener impacto. Ya os contaré. Ésta es una de esas cosas que hago por hacer y está causando puto furor. Así pasa. Ahora en seguida os cuento por qué. Oink oink.

Es gracioso porque lo he desarrollado con un lenguaje de programación que he aprendido desde que voy por libre, estudiando en mi sofá.

También estoy currando en cosas que hace tiempo anuncié o dije o igual no. Estoy trabajando en las cosas de Sotapatroi, un sistema de salvamento marino que necesitaban (o querían o whatever) a alguien con mis locuras para desarrollar tecnología libre, como una barra de esas que tanto os gustan.

Para que veáis lo que es la vida, ese desarrollo me ha llevado a aprender miles de cosas. Cómo funciona Arduino por dentro y cómo crear una placa Arduino propia desde cero y configurarla, como he hecho aquí. Muchas más, por supuesto. También he hecho hardware, coño, y ha funcionado a la primera.

Esto vino por un conocido que ahora no dudo en llamar amigo. Que valora lo que hago y no tiene miedo en decirlo en público. Me conoció por este blog y por las gilipolleces que digo en las redes y ahora aprendo por su culpa, o gracias a él.

Joder… ¿Qué más?

He modelado cosas. Hasta quedé tercero en un concurso. Con este cerdo.

Ese concurso me dio presupuesto para imprimir cosas en 3D, lo que me está haciendo involucrarme en miles de movidas más. Pero eso lo contaré otro día, supongo.

También estoy trabajando cosas para unos periodistas que están haciendo unos mapas de las guerras del mundo. Tienen montón de información y quieren hacer que la gente se informe bien de los conflictos bélicos. Eso no lo puedo enseñar. Qué putada. ¿Quizás tendría que terminarlo ya para poder enseñarlo?

Ese también tiene gracia. Buscaban colaboradores y decidí usar lo que había aprendido rastreando personas en contra de su voluntad para hacer el bien. Hice una prueba de concepto pero querían algo demasiado profesional para hacerlo gratis. Me ofrecieron algo de pasta, lo poco que se pueden permitir unos estudiantes y aquí estamos. Cambiando el mundo de nuevo.

¿Oink oink? Nah, esta vez no.

He conocido gente, una cosa que no siempre valoro lo bastante. He ido a eventos gracias a un viejo conocido. Gracias, tío, por sacarme de casa. A veces me pierdo tras esta pantalla y se me va el tiempo. Eso me ha dado ganas de compartir, compartir lo que hago, en la vida real a parte de aquí.

Curioso de nuevo. Nos conocimos por hacer artes marciales, hace unos cuantos años ya de esto.

Sí, también he hecho otras cosas. He aprendido movidas.

Ya he dicho antes que he aprendido Clojure/ClojureScript gracias a la gente que ha estado apoyándome y ayudándome y al tiempo que le he dedicado, por supuesto. También me han dejado libros de otras cosas y me he comprado algún otro. He aprendido mucho. Casi siempre de alguien, que es como se aprenden las cosas.

He escuchado mucha música también. Ahora tengo puesto a Evidence.

También he hecho la web de la empresa o de la cosa y unas tarjetas de visita y todo, que, por suerte, alguna persona me ha pedido.

Cuantas cosas he hecho ¿no?

Y las que me estoy dejando… Como cocinar y todas esas que la gente no respeta tanto… Muchas. Demasiadas.

“Hacer algo, cabrones, hacer algo” decía el Muchacho y no se equivocaba. Cada una dispara otra y hacen que todo gire. Eso se me da bien ¿sabes? No parar nunca es mi especialidad. Hace como media hora que me estoy meando y aquí sigo, delante de la pantalla, porque no parar es mi especialidad.

Ahora sólo falta que la pelota de nieve sea tan grande que arrastre un banco y se le peguen todas las monedas y billetes. Eso hace falta. Mientras tanto, puedes darle un pequeño empujón para que no pierda fuelle:

https://liberapay.com/ekaitz

Oink oink.

Así estamos.

No tardará en pasar, pero aún va despacito. Mi bro en Madrid dice que vamos despacio porque vamos lejos, quizás tenga razón, pero hoy me cuesta pensar lo mismo. Aquí mientras te escribo, en mi casa, en Bilbao, sentado en mi mecedora con los cascos y un portelo que se pasa el día encendido y sufriendo el aporreo de mis dedos en sus teclas, no siento que vayamos muy lejos. Puede que porque no tengamos la opción o porque tengamos nosotros la culpa. En este preciso momento, muchos se preparan para ponerse tibios, a comer y a beber, para luego regalarse cosas en nombre de otros, cosas que posiblemente no les gusten, sólo porque toca regalarlas, porque alguien lo dijo o alguien nació o alguien dijo que alguien nació o todas a la vez.

Una mierda.

Oink oink.

Esa es la razón por la que es tan triste y difícil tener que venderse. Deformar lo que uno hace hasta que alguien sienta que debe pagar por ello. Es ganarse una vida que te pertenece por derecho.

Que lloren por los lunes, pero son ellos los culpables de su amargura matutina y hoy es cuando mejor lo están representando.

Oink oink.

Algunos despertarán hoy, tras leer esto. Otros puede que mañana, tras trabajar conmigo. Otros morirán dormidos, tras haber cavado su propia tumba.

Oink oink.

¿Sabéis por qué ha molado tanto esa galería que he hecho sobre Mastodon? Porque está lleno de gente que piensa como yo, por alguna razón. En Twitter sé que no funcionaría, que a nadie le gustaría, que le quitarían mérito. Y tú también lo sabes, porque te lo han hecho.

¿Sabes por qué es?

Oink oink, por eso es.

Pero no es un mensaje de pesimismo éste que os tiro a la cara. Es un mensaje de motivación. Un desafío. Ahora sabemos contra qué luchamos, sabemos cómo suena.

Oink oink. ¿Lo oyes?

ElenQ Technology es otra performance, un poco más ambiciosa esta vez. Pero no pongas en duda su alcance todavía. Este año he tocado al menos a una persona y eso me hace que todo haya merecido la pena. Hostias, hasta me ha hecho crecer y aprender por el camino. Está funcionando perfectamente.

Supe deformarme bastante bien. ¿No te parece?

Menos mal que siempre me lo tomé como una obra de arte y no como algo serio. Porque no hay nada en el mundo más serio que el arte. ¿No? ¿Cómo?

Ha sido un buen año, y eso que todavía no ha terminado. Puede acabar mejor si tú también te das cuenta de a qué me refiero.

Te dejo un chiste que me he encontrado por las redes sociales para desearte feliz navidad, un buen día o lo que sea.

Disfruta de los tuyos. Te quiero.

 

EmpoderaLIVE 2017, y eventos en general

Pues hoy no va de software.

Hoy va de que estuve el otro día en el EmpoderaLive, un evento sobre empoderamiento tecnológico en Málaga (días 11 y 12 de septiembre) y, ¡coño! Moló bastante.

Allí conocí a varias personas interesantes y desvirtualicé amigos, cosa que siempre es fantástica. Hablé en inglés durante 2 o 3 días sin parar y sin sentirme rematadamente estúpido y más cosas.

Tuvimos ocasión de ver a mucha gente hablar de sus proyectos y eso nos abrió nuevas vías de pensamiento que todas parten desde nuestro objetivo de respetar a las personas y hacer del mundo un lugar mejor.

Como el evento me pareció un hito interesante para ElenQ Technology he estado trabajando en Schiumato, mi generador de webs estáticas y le he dado la capacidad de crear hilos de noticias y he escrito una cortita sobre mi participación en el evento en la web de ElenQ Tech. Hablé un poco en un apartado de hablar libremente y, como me grabaron en vídeo, os dejo ahí que podáis verme el careto y oír como hablo con entonación rara porque se me había pegado el acentillo del inglés.

Contaría más del tema aquí, pero ese no es el propósito de este blog. Aquí se habla de mis mierdas y de mis frikadas, ¡hombre ya!

No tengo mucho que contar del evento que no podáis ver allí así que nada. Lo dejo aquí. Entrada supercorta hoy.

Me encantó conocer a todas esas personas y disfruté mucho de la ciudad.

Supongo que este evento abre una nueva vía para una persona antisocial como yo, empezaré a moverme a eventos similares y prepararé alguna charlilla por ahí, creo que me vendrá bien salir de casa y conocer gente.

Si veis algún evento en el que pueda encajar me decís y trato de animarme.

Tengo pendiente acercarme a Madrid con la gente de la Ingobernable y otras cosas, pero vayamos con calma.

También he mandado alguna propuesta a algún evento pero no os diré nada más, si salen ya os avisaré.

Un abrazo, pronto os cuento mierdas locas de las que os ponen.

Mis mierdas sobre el respeto y el insomnio

He vuelto.

Está siendo un verano jodido respecto a muchas cosas y esta entrada no hablará de software o hardware pero sí de las mierdas de uno. Aunque muchas veces suelo tener un hilo conductor que me guía a la hora de escribir una entrada, a pesar de que el resto lo improvise, en ciertas ocasiones especiales todo parte de un cúmulo de sensaciones recogidas de lo vivido recientemente. Ésta es una de esas ocasiones.

Primero tengo que contextualizar un poco hablándoos de mi vida porque no sé cómo resumir esto de otra manera. Sabéis todos que he trabajado en investigación y desarrollo, entre otras cosas porque soy una especie de hombre del renacimiento por culpa de mi insaciable apetito de crear y por mi forma rara de pensar. Esta mañana he leído una frase que decía:

Investigación es ver lo mismo que los demás pero pensar algo diferente.

Supongo que eso es lo que me ha hecho caer en el I+D. No sé.

De todos modos, aunque parezca que os estoy hablando de algo bueno, la verdad es que no. No tengo nada claro que lo sea.

Muchas veces acabo cayendo en lugares un poco extraños debido a mi forma de pensar, que puede ser novedosa a veces y estrambótica otras. No suelo comprender con sencillez lo que para todo el mundo es algo que “se hace” y “es normal” y necesito analizarlo profundamente para tener realmente claro si es algo que es lógico bajo mi criterio. Esto se aplica a todas las cosas. No suelo creerme nada directamente. Todo pasa por un proceso de análisis previo, aunque muchas veces el resultado de éste no sea el más común.

Detalles que a la gente pueda sorprender son que a mis 26 años, no tenga tarifa de datos en el teléfono móvil porque es un dispositivo que casi no utilizo y que no beba casi alcohol y no me haya emborrachado nunca. Fuera de estos anecdóticos datos, no me gustan las aglomeraciones de gente, los ruidos fuertes, las luces, la gente que no escucha, los que no te dejan terminar de hablar, los que exigen tu atención, que le prestes atención al móvil mientras hablamos, etc.

Todas estas cosas, lejos de ser algo que nadie me ha enseñado, han salido de mí mismo, igual que muchas otras, que son las que quiero mencionar para dejar claros un par de conceptos.

Dejé mi trabajo porque tras más de dos años pensando, llegué a la conclusión de que así no se pueden hacer las cosas, del mismo modo que creé ElenQ Technology para hacerlas como creo que deben hacerse. Esto no sale de que alguien me dijo que la ética era así o asau. No. Sale de un montón de personas de las que he aprendido y he sacado mis propias conclusiones sobre lo que es justo o no.

Esto mismo es perfectamente extrapolable a muchos otros campos como el feminismo, muy de moda en Twitter últimamente, donde me he encontrado con verdaderos imbéciles de rebaño atacándome porque pensaban que el análisis que estaba haciendo iba en contra de lo que ellos tenían que defender sin pensar realmente el contexto que yo pudiera tener o cuál pudiera ser mi opinión en el tema.

Si bien es cierto que no soy uno de “los suyos” porque como habréis entendido desde lo de arriba, nunca he sido uno de los de nadie, ya que pertenecer a un grupo de forma clara implica muchas cosas con las que mi forma de ser no encaja, como tener un pensamiento propio demasiado analítico o crítico, no se puede decir que esté en contra, puesto que mis valores son igualitarios y están basados en el respeto por los demás, lo que incluye, por supuesto, a las mujeres. Estos son los mismos principios del feminismo.

Yo no soy un feminista porque hay que posicionarse y lo que he visto en mi contexto es lo que dicta cómo debo ser, soy un feminista porque creo que es lo justo. Estoy a favor del respeto y la igualdad y el feminismo viene en el pack, porque el feminismo es el pack.

Esto me trae al hilo del memo de Google, y cuando hablo de memo me refiero a la persona. Por muchos doctorados que se tengan, exponer ese tipo de ideas en un entorno de colaboración es razón suficiente para que despidan a uno y no saber eso es de (como dice mi madre) género idiota. Y, entrando en lo que dijo, que he tenido ocasión de ojear, creo que es evidente que los hombres y las mujeres tienen diferencias biológicas, pero me parece una puta mamarrachada decir que son peores programadoras a nivel evolutivo. A parte de eso, dedicarle a este señor toda la atención que ha recibido, creo, es excesivo. No a nivel de reivindicación, porque la existencia de este tipo de individuos claramente deja en manifiesto el problema real que hay con el machismo en la tecnología, pero sí a nivel de llegar a lo que para muchos ojos puede parecer un linchamiento. Para mí, el lo del linchamiento tiene dos puntos muy claves:

  1. Que parezca un linchamiento o una respuesta excesiva puede haber posicionado a ciertos sectores a favor del personaje.Las meadas fuera de tiesto de algunos y el constante aparecer de este incidente en todos lados ha podido dar razones a esa gente que dudaba para ponerse a su favor.

    Lo mismo ocurre con el terrorismo islamista (aunque no me guste relacionarlo con el Islam). El desprecio con el que se ha tratado a esta religión en ciertos medios y los insistentes ataques que han sufrido han servido como caldo de cultivo para radicalizar a otros y perpetuar el terrorismo, ahora con más razón porque se sienten vejados y humillados.

  2. Ese señor, por mucho que nos pese, es, ante todo, una persona. Imbécil, sí, pero una persona. Sus ideas no se merecen ningún respeto pero él sí y esto no lo comprendemos tan fácilmente. Que sea un ignorante que se ha equivocado ojo, no en unas declaraciones ni en la forma de hacerlas, si no en un análisis de la sociedad, no es una excusa para desahogarse con él.Haciéndolo, no somos muy diferentes a él.

    El otro día leí una comparativa que básicamente está a favor de golpear a nazis y yo, sinceramente, no lo estoy. No estoy a favor de golpear a nadie a no ser que mi integridad física corra peligro real. No por sistema ni porque sus ideas y las mías estén confrontadas.

    Una posible forma de arreglar eso es educar mejor a la gente y minimizar estos grupos cortando sus vías de financiación y mostrando una repulsa colectiva y, por supuesto, tomando medidas legales contra todo el que ataque a alguien o haga actos ilegales.

    Como comparativa de esto, puedo mencionar las pseudociencias. Según el criterio de muchos, como esa gente está equivocada o lo que dice es una estupidez, yo, con mi Ingeniería por delante, podría simplemente golpearles collejas o llamarles magufos y humillarles públicamente. Y no, eso no me vale y creo que a nadie debería.

A este personaje quizás tendrían que haberlo despedido directamente y haberle hecho salir por la puerta de atrás y haber esperado a que él montase el numerito de hacerse la víctima para que se hubiese puesto en evidencia él solo mientras que la empresa preparaba un comunicado claro en el que se mostraba su código de conducta y su posición respecto a la discriminación con un apoyo claro y sincero a las mujeres o colectivos atacados por este individuo. Pero no lo sé. No soy un experto en estas cosas. Sólo es algo que he pensado durante un tiempo posiblemente insuficiente para resolver un problema de estas características. Este escrito sólo es un brainstorm de ejemplo.

Ahora voy a retorcer un poco el tema para hablar del sesgo, que era lo que quería escribir pero que los recientes acontecimientos me han forzado a desviar. Dentro de todo lo que he dicho es evidente que encontraréis incongruencias pero soy consciente de que las tengo. Por ejemplo, digo que no habría que atacar a este personaje y al mismo tiempo le llamo imbécil y memo. Sí. Tú mismo sabrás si es coherente o no. O si lo que he dicho es una estupidez. Todo depende de cómo te leas esto.

El sesgo es algo muy cabrón, porque te puede hacer entender una cosa de una manera completamente equivocada. Desde mi punto de vista analítico, en el que nunca me he sentido identificado con un grupo ni colectivo, estoy en una posición bastante cómoda respecto a esto, quiero pensar. Soy un tío de sangre caliente pero intento vivir con amor en mi corazón desde hace un tiempo, dando siempre la oportunidad de releer a las personas que se ponen agresivas de golpe. Siempre me decepciono cuando lo hago. No suelen pensar distinto la segunda vez, ni siquiera intentan ponerse en el lugar desde el que yo enfoco las discusiones que, normalmente, como ya sabréis por el blog, no es la línea más habitual y requiere algo de pensamiento.

Ya como guía para los que deciden releerse este texto completamente o tienen intención de seguir mi blog o hablar conmigo, normalmente hay dos niveles en mis conversaciones:

  1. El nivel literal: en el que siempre podrás deducir que soy idiota.
  2. El nivel figurado: que requiere mucho más trabajo descifrar y posiblemente te lleve a una conclusión similar pero por un camino mucho más tortuoso en el que puede, y sólo puede, que te encuentres alguna joya entre tanta caca de vaca.

Es curioso que estos dos puntos no sólo sean parte de mi nivel de conversación, si no del de muchas personas con las que habláis a diario y con las que a mí, dentro de mi introspectivo y vergonzoso carácter, me enamora conversar.

Esto es lo que me lleva al sesgo de la idiotez. Pensar que todo lo que la gente dice es literal o que la posición que está tomando en una conversación es su opinión personal es una lamentable representación de lo vacío que está uno a nivel de entendimiento. Tristemente, muchos medios de comunicación o críticos profesionales de las redes sociales con miles de seguidores leen con esta máxima y eligen en que bando estás, arrastrando consigo a miles de espectadores ovinos cuya opinión es un calco directo de lo que leyeron o escucharon. El complejo arte de la descontextualización, la generalización y la absurdificación.

Lo más cojonudo de todo esto, es que quien más cae en estas cosas es quien cuyo ego le eclipsa todo tipo de capacidad para pensar que otra persona, quizás, en ese tema, sepa un poco más que él o, aunque sea por casualidad, haya llegado a un razonamiento más acertado. ¿Cómo era aquello de la flauta y el burro?

Ahora, volviendo a lo que ocurre en las redes sociales, pasaré a un mundo distinto en un planeta diferente. Desde un tiempo a esta parte podéis encontrarme en las redes libres como @ekaitz_zarraga@mastodon.social. En ese maravilloso mundo he podido hablar sobre el Anarquismo, la responsabilidad, la ética, muchos temas de programación y análisis y resolución de problemas complejos siempre desde el respeto y la educación. Considerando que los demás eran tan válidos como yo para hablar del tema. He conocido a un montón de personas transgénero y homosexuales, colectivos con los que no me había topado mucho en mi vida y su cercanía y cultura me han impresionado sobremanera. Su lucha, que es realmente difícil, está ganada desde la base en la que se quieren unos a otros y respetan, por defecto, a cualquiera. Supongo que serán justo los que me he encontrado en ese lugar, pero me han hecho recuperar la fe en el ser humano y en la forma en la que resolvemos ciertos conflictos. Con el amor y el respeto mutuo por delante.

Eso es un bias-killer, un mata-sesgos, para mí. Pero no lo es para cualquiera. No sé. Sólo puedo ver a esa comunidad como una fuente de inspiración.

Esto me recuerda a cuando estaba en la universidad. Un compañero mío era un absoluto genio y hablando de ello con otro me dijo: “Es un lujazo tener a alguien así con quien aprender”. Esto me chocó mucho después de haber sufrido humillaciones por ser el mejor de mi clase en los estudios (antes de llegar a la uni claro), pero me hizo recapacitar. No todos los sitios son como donde yo me crié y me alegro de que haya gente así. Su sesgo fue el que decidió tomarse a un alumno brillante como un apoyo igual que el sesgo de mis compañeros de clase fue el que decidió tomarme como una amenaza o alguien a quien atacar.

Curioso todo esto.

Complejo.

No sé como cerrar, si os digo la verdad porque todo es un cúmulo de opiniones y pensamientos inconexos aunque sí que creo que llevan el mismo lugar:

Pienso, todo el rato, y esto a menudo me hace desaparecer y me mantiene despierto por las noches. Nada de lo que yo diga está dicho sin pensar, puede que esté equivocado, pero no está dicho sin pensar y así debéis tomároslo. Tanto lo mío como lo de otro.

Y ya vale de tanto mamoneo agresivo de frases con dobleces para insultar o gilipolleces en Twitter reduciendo a lo absurdo lo irreductible. No sois tan listos, no sabéis tanto. Empezad por ahí, respirad, y os llevaréis mejor con todo el mundo y no sólo con los que piensan como vosotros.

No seáis de nadie. Sed de vosotros mismos, y apreciad lo bueno de todos.

Un abrazo, con todo el amor del que dispongo, como siempre. Respetaos más, que nunca es suficiente.


Para ti que crees que esto no debería ir en este blog, puesto que es no es algo técnico, estás de enhorabuena. Te doy la razón.

Así que pronto serás premiado con un texto muy sesudo en la línea de los que me gustan a mí, diseccionando una aplicación muy compleja y sacando todos esos puntos divertidos a la luz.

No lo puedo publicar aún, porque participé en un concurso de divulgación con él, pero cuando se resuelva, a principios de septiembre, intentaré publicarlo para que todos podáis leerlo.

Siento hacerte esperar, por mí ya estaría publicado.

Café y webs multi-idioma

¡Hola!

Tras mucho currelar en esto ya toca el momento de hablar de Schiumato, un generador de sitios web estáticos que ya mencioné en mi entrada sobre el amado arte de afeitar animales lanudos.

Lo hice para gestionar la página web de ElenQ Technology, la empresa que estoy fundando y que también os mencioné in the past.

Como ya he hecho la web y esto ha funcionado es momento de contar cómo funciona y cómo se utiliza.

La verdad es que tiene una lista más larga de cosas pendientes que la lista de cosas hechas, pero es un programa tan extremadamente sencillo que da risa. Pero funciona. Como tiene que ser.

Lo podéis instalar directamente con:

npm install -g schiumato

Para usarlo también os recomiendo que instaléis un servidor HTTP para probar.

npm install -g live-server

Este servidor mola porque cuando se hacen cambios en sus ficheros te actualiza el browser automáticamente. ¡Para nuestro proceso vendrá perfecto!

Schiumato funciona de la siguiente manera:

Tienes un conjunto de plantillas de nunjucks con un par de movidas extra que yo he añadido: _() y filter translate sirven para traducir. Todo string bajo esas funciones será traducido tomando como referencia los ficheros de locales. Tenéis más explicaciones en la minidocumentación de Schiumato.

Cuando disparemos schiumato create, se procesarán esas plantillas y el resultado se copiará en la carpeta de destino de forma ordenada. Las plantillas se renderizan en orden, una vez por idioma, y se vuelcan en su carpeta correspondiente. Los ficheros de la carpeta estática se copian literalmente. Por ejemplo, con mi web:

www
├── en
│   ├── about.html
│   ├── contact.html
│   ├── index.html
│   ├── services.html
│   └── support.html
├── es
│   ├── about.html
│   ├── contact.html
│   ├── index.html
│   ├── services.html
│   └── support.html
├── eu
│   ├── about.html
│   ├── contact.html
│   ├── index.html
│   ├── services.html
│   └── support.html
└── static
    ├── css
    │   ├── fonts.css
    │   ├── normalize.css
    │   ├── skeleton.css
    │   └── style.css
    ├── files
    │   └── publickey.hello@elenq.tech.txt
    ├── fonts
    │   ├── LatoLatin-Light.eot
    │   ├── LatoLatin-Light.ttf
    │   ├── LatoLatin-Light.woff
    │   ├── LatoLatin-Light.woff2
    │   ├── LatoLatin-Regular.eot
    │   ├── LatoLatin-Regular.ttf
    │   ├── LatoLatin-Regular.woff
    │   ├── LatoLatin-Regular.woff2
    │   └── OFL.txt
    └── img
        ├── ElenQTechLogo.png
        ├── ElenQTechLogo.svg
        ├── faces
        │   └── ekaitz.jpg
        ├── liberapay.svg
        └── projects
            └── sotapatroi.png

10 directories, 34 files

Veis como se vuelca 3 veces el HTML, en Inglés, Español y Euskera. El contenido estático está sólo una vez porque no se traduce y así no se replica.

Con live-server arrancado en la carpeta www, podéis ir viendo cómo quedan las cosas cada vez que lanzáis una creación.

Y este es el rollo.

Si queréis ver las plantillas podéis verlas en el repo de la web aquí.

Para hacer el deploy copiáis toda la carpeta WWW y ya, eso sí, tenéis que seleccionar el idioma que queréis que se muestre por defecto para que os redireccione ahí vuestro servidor para que se vea algo al entrar a la raíz. Eso es fácil de hacer.

Y nada, esta es la web resultante:

http://elenq.tech

Esta también redirecciona a HTTPS 😉

Espero que os mole el rollo.

Sed buenos.

Traducciones y tripas

Hola chavales,

He sacado un rato para contaros una cosilla que me ha tocado investigar últimamente. Las herramientas de traducción de aplicaciones, también conocidas i18n y l10n por internationalization y localization (contad las letras de las palabras y entenderéis el número).

Esas herramientas de traducción no son simplemente eso. Sirven para traducir y localizar las aplicaciones, no sólo traducen las frases o palabras, también saben elegir si usar un singular o un plural dependiendo de un número o utilizar cuantificadores como “mucho” o “poco” (pluralization). A parte de eso, valen para transformar la moneda, el formato de las fechas, las unidades de medida y ese tipo de cosas. El l10n hace unas cosas y el i18n otras leed al respecto que no es malo informarse (y se escapa a lo que quiero contar aquí).

Hoy quiero contarlos cómo hacer una aplicación de éstas de forma simple, y sólo me centraré en las traducciones. Además, tendréis mi solución de i18n de la que hablé en la entrada anterior, que es rematadamente simple y trata exactamente de lo que hablaré aquí hoy1. Ni más ni menos.

Esta entrada pretende que se os ocurra a vosotros cómo hacer una librería de este estilo, tirando a lo simple, para que los más novatos entendáis cómo es posible hacer cosas útiles con el conocimiento que ya tenéis. No es tan difícil programar. Pensadlo: si lo fuera, posiblemente el que os escribe no sería capaz de hacerlo.

Vale, vamos a por ello.

¿Cómo creéis que funciona una mierda de éstas?

Pensad un poco conmigo. Recordad que sólo queremos que pueda traducir, no queremos pluralización ni extras (luego hablaremos también de eso).

A nivel de usuario de la librería, normalmente funcionan de la siguiente manera:

  1. Importamos la librería en el programa que queramos que pueda ser traducido.
  2. En todo el texto que vaya a ser visto por el usuario se pone un identificador de algún tipo. Normalmente se trata de una llamada a una función entregada por la librería. Ejemplos:

i18n("texto a traducir")

_("texto a traducir")

gettext("texto a traducir")

  1. De alguna manera, se vuelcan todos los strings para traducir en unos ficheros con espacio para su traducción. Uno por idioma.
  2. Se traducen.
  3. Durante la ejecución, la aplicación busca los strings a traducir antes de mostrarlos en los ficheros. Cuando los encuentra, usa la traducción adecuada al lenguaje configurado por el usuario.

Así es como funciona. Simple ¿No?

Si no me he explicado bien podéis buscar algunas librerías de i18n y mirar su documentación para ver qué formato de ficheros utiliza o qué herramienta extrae los strings para la traducción.

Una vez entendido esto, hay que empezar a darle vueltas a cómo lo implementaríamos. Durante el desarrollo de esto haré algunas trampitas, porque soy un poco malévolo, pero os prometo que tendrán sentido.

¿Cómo lo haríais vosotros? ¿Por dónde empezaríais? ¿Qué os parece lo más difícil?

Nosotros vamos empezar por el paso 2 de la lista anterior. La forma de indicar que los strings son traducibles. La mejor forma es meterlos en una función, aunque habría otras. Si le damos al usuario de la librería una función a utilizar será simple: la aplicará a los strings que le interesen y todo irá bien.

Hay muchas formas de hacer esto, la más fácil es que los ficheros de traducción sean simples ficheros tipo JSON donde las claves sean el texto a traducir y los valores la traducción:

{
"hola": "hi",
"adiós": "bye"
}

Con esto así, cuando se llame a la función con un string sería suficiente con buscar en ese JSON la clave y devolver el valor. En JavaScript y simplificando muchísimo:

var traduccion = carga_traduccion();
function _( string ){
  return( traduccion[string] );
}

Lo que no hemos hecho todavía es esa función carga_traduccion que vemos en el snippet y tampoco gestionamos cuál es el idioma actual del usuario.

Eso tampoco es taaan difícil ¿no?

Podemos tirar por un formato orientado a objetos para hacerlo sencillo. Suponemos que el sistema de traducciones es una clase/prototipo (no me voy a poner a discutir esto ahora) con un campo de “idioma actual” y lo de arriba se transformaría en algo un poco más complejo si suponemos que el JSON de idiomas tiene un nivel de más que referencia al idioma. En JavaScript de nuevo:

{
"hola": { "english": "hi", "euskera": "kaixo" }
"adiós": { "english": "bye", "euskera": "agur" }
}

//...
function _( string ){
  this.traduccion[string][this.idioma];
}
//...

Una vez tenemos esto, sólo necesitamos hacer que nuestra clase/prototipo pueda configurar el idioma, leer los ficheros de idioma automáticamente al iniciar (el carga_traduccion de antes) y que le entregue la función _ al hilo principal.

Cargar los ficheros en principio es sólo leer una carpeta y ya. Aunque si estamos en el browser tenemos que hacer alguna magia añadida que no debería costaros mucho. Tema resuelto.

¡Coño! ¿Y ya está?

En realidad no, porque el traductor tendría un desastre de ficheros de idioma, y encima tendría que rellenarlos a mano. Lo suyo es que haya una herramienta tipo gettext que extraiga todos los strings a traducir y los vuelque en ficheros que luego tengan que traducirse. Ésta es la trampa, este punto es el más difícil. En mi solución de i18n, como sé que el lugar donde va a usarse lo permite, la propia clase vuelca los ficheros (también llamados catalog) al terminar la traducción, pero esto no es factible siempre porque si la ejecución del programa nunca pasa por mostrar el string nunca aparecería en los catálogos. (¿Quizás con unos tests brutos podríamos hacerlo?)

Otro punto interesante es tener en cuenta que hemos usado strings con texto, en nuestro caso en castellano. Entonces si el usuario tuviese seleccionado el idioma en castellano no tendrían que traducirse y tendrían que entregarse igual. Hay dos formas sencillas de atacar este problema:

  1. Obligar al usuario a no poner el string en concreto y poner un identificador para siempre se busque en la traducción.
  2. Tener configurado un idioma por defecto que sea el original.

Otra cosa que quiero tocar es que esos ficheros de JSON pueden ser la muerte (a pesar de que algunas herramientas los usan) porque si el texto a traducir es muy largo nos quedaríamos con unas claves gigantescas en una única línea (JSON no permite claves multilínea). El contenido también sería difícil de traducir porque también sería en una sola línea y tendría también caracteres especiales por el medio para marcar los saltos. ¡Quizás sea mejor usar otro tipo de fichero! Mi solución i18n usa YAML1 pero también tiene un sistema diferente para gestionar las claves. Si os interesa me preguntáis o lo miráis.

Otro punto extra es que no tenemos ninguna información sobre lo que estamos traduciendo. La misma palabra puede tener que traducirse de dos maneras diferentes dependiendo de dónde esté porque el contexto puede ser distinto. En este caso, nuestro programa sólo contempla que textos iguales se traducen igual.

Tampoco nos dice en qué línea del programa original está lo que traducimos así que es difícil encontrarlo.

Ni nos da ningún tipo de detalle sobre la traducción, cosa que en algunas soluciones i18n existe: Te permiten poner palabras clave para definir el contexto mejor como guías para los traductores que se ignoran en el programa pero que se vuelcan en los ficheros de traducción. Ejemplo:

i18n("Abrir", "Abre un fichero"); // siendo Abrir el string a traducir

Ya os he hablado de la pluralización antes, y de la internacionalización también. Eso también complica las cosas…

Joder…

Bueno eso, que era fácil…

¿No?

😉

Un abrazo.