Paso a paso subdominio

Esto es para mi en realidad … siempre que quiero agregar un subdominio tengo que revisar el historial de comandos para ver qué hice. Entonces, ahora lo dejaré aquí 😀

  1. Crear una copia del archivo de configuración para el subdominio (en mi caso nginx).
    cp /etc/nginx/sites-available/existente /etc/nginx/sites-available/nuevo
  2. Editar dicha copia, reemplazando los existente por nuevo (obviamente donde corresponda).
  3. Guardar archivo.
  4. Crear carpeta nuevo en la dirección que especificamos en el archivo de arriba.
  5. Crear el enlace desde sites-available a sites-enabled.
    ln -s /etc/nginx/sites-available/nuevo /etc/nginx/sites-enabled/nuevo
  6. Revisar nginx
    nginx -t
  7. Ejecutar certbot
    cerbot --nginx
  8. Reiniciar nginx
    systemctl reload nginx

Y eso es todo 😀

Minientrada | Publicado el por | Deja un comentario

Las peripecias para cambiar a un .dev

Hola !!

Hace raaaaato que no escribía algo, porque no tenía nada interesante que aportar.

Tenía comprado un dominio .rs (por mi nombre… Mario Cares => marioca.rs ) pero como hace poco salieron los dominios .dev … ps, quedaría mejor un mariocares.dev Así que lo compré en GoDaddy .

Ahora, el dominio por si sólo no sirve de nada, necesitamos algo a qué asociarlo. En mi caso, un VPS (Vultr).

Lo siguiente va a depender de dónde compren su dominio y dónde el VPS, pero básicamente tienen que asociar uno con otro.

En GoDaddy, en la administración del dominio:

Y, a su vez, en Vultr =>

Hasta ahí no hay dramas.

Pasadas unas horas ya estaba todo ok …. peeeeero, y aquí viene lo entretenido, no me funcionaba x_X

Y es que, según Google (Porque los .dev son de ellos):

Todos los dominios .dev se incluyen en la lista de precarga HSTS

Entonces, estamos obligados a contar con:

  • Que nuestro servidor pueda suplir HTTPs
  • Un certificado que pueda manejar la s en el HTTP

El tema es que generalmente esos certificados SSL no son gratis… al menos en GoDaddy cuesta cerca de 40K CLP por año… no es ninguna gracia.

Y ahí es donde entra Let’s Encrypt.

Let’s Encrypt is a free, automated, and open Certificate Authority.

Así que, bien ! Podemos generar nuestro propio certificado sin dramas y gratis.

Manos a la obra. Básicamente usaremos un bot que se encarga de generar el certificado y renovarlo cada cierto tiempo.

Es cosa de seguir el paso a paso de aquí => https://certbot.eff.org/

Una vez terminado, tenemos algo así =>

Certbot, lo otro que hace, es editar el archivo de configuración de nginx, por lo que no tenemos que hacer nada de nada, salvo reiniciar nginx.

Y eso sería todo !

Publicado en Tips | Etiquetado , , | Deja un comentario

Crear usuario root MongoDB (Debian 8)

Después de muuuucho tiempo, vuelvo a usar MongoDB para un proyecto personal.

Todo comenzó cuando traté de conectarme a la BD en el servidor desde mi PC. No pude porque Mongo solamente escucha peticiones desde localhost. Traté, entonces, de hacer un tunnel por ssh pero tampoco lo logré… así que al final le dije que escuchara de todos lados del mundo, activé la autenticación y luego creé un usuario para poder conectarme (por defecto, Mongo no pide nada… le da acceso a todos).

Vamos por parte. Para decirle que escuche desde todos lados :

1.- Editar el archivo /etc/mongod.conf y luego, bajo network interfaces, comentar la línea de bindIp.

Algo así:
# network interfaces
net:
port: 27017
# bindIp: 127.0.0.1

2.- Ahora reiniciamos el servidor con service mongod restart y listo. Ahora podemos conectarnos de cualquier lado !

3.- Pasemos ahora a la creación de usuario. Asumiendo que ya estamos en Mongo:
use admin;
db.createUser({
user: "nombre_de_usuario",
pwd: "password",
roles: [
{"userAdminAnyDatabase", "admin"},
{"readWriteAnyDatabase", "admin"},
{"dbAdminAnyDatabase", "admin"}
]
});

Ahora ya tenemos un usuario que puede hacer de todo en cualquier BD dentro del servidor.

5.- Volvemos a editar el archivo /etc/mongod.conf para decirle a Mongo que utilice la autenticación al aceptar conexiones. Descomentamos la línea de security y agregamos authorization: enabled

Con ésto ya podemos conectarnos desde cualquier con el usuario y clave.

Publicado en MongoDB, Uncategorized | Deja un comentario

Emulador Android -> Audio Muere

Escuchar música mientras trabajas es una cosa necesaria para concentrarse mejor… al menos para mi.

Ahora último estoy haciendo una app en Android de un sistema que ya tenemos (es un más un cliente para un módulo, algo así) y cada vez que lanzaba el emulador, no escuchaba nada de audio …

Tengo unos Phillips SHB4000 (Bluetooth) y pensé que el problema podría ser que intentaban parearse con el emulador … pero no.

En una de esas era el emulador que se “adueñaba” del audio del PC así que lancé el emulador con -no-audio, pero el problema seguía. Intenté con unos audífonos “alámbricos” y el audio si funcionaba… Le di mil vueltas hasta que me rendí y me fui a google: encontré la solución.

Resulta que si los audífonos tienen micrófono (independiente de la marca) el S.O. (da lo mismo cuál) activa el micrófono y por eso no se escucha nada …

Solución: cambiar el dispositivo de grabación por el micrófono interno.

Captura

Y eso fue todo … En Mac o los Linux debería ser el mismo arreglo.

Publicado en Android, Aplicación, Tips, Windows | Deja un comentario

Neo4j II (Cosas)

Siguiendo con Neo4j, ahora vamos a ver las distintas “cosas” que corren aquí.

Lo primero que hay que entender es que en las BD de grafos, lo que se guarda son cosas. Por ejemplo, en las BDs relacionales lo que guardas son tuplas de datos, que a su vez están almacenadas en tablas, que a su vez interactúan con otras tablas. En estricto rigor, una tupla de datos en una tabla nunca se relaciona directamente con otra tupla en otra tabla. Es el motor de BD el que se encarga de hacer dicha relación por medio de JOINS. Aquí no, una cosa está directamente relacionada con otra cosa, que a su vez se puede relacionar con otra cosa y así.

Con eso en mente, definamos las cosas.

Nodos

Los nodos son las cosas básicas. Un nodo (o arista) representa una entidad o un tipo de dato complejo.

Un nodo representa una instancia de algo. Por ejemplo, en una BD relacional existe la tabla persona que contiene todas las personas. Aquí no. No existe el nodo persona, pero si existe el nodo Mario, el nodo Juanito, el nodo Pepito, etc.

Los nodos tienen propiedades, pueden agruparse por etiquetas y se relacionan entre ellos:

Propiedades

Las cuales representan atributos o metadatos de algún nodo. Ya que cada nodo es una instancia de alguna entidad, es el nodo el que tiene las propiedades NO la entidad. Las propiedades pueden ser distintas entre nodos. Por ejemplo, un nodo puede tener las propiedades: edad, color_pelo ; mientras que otro puede tener: nacimiento, color_ojos, altura.

Las propiedades son de estilo llave: valor. La llave es key sensitive y los tipos de datos que tiene son: string, number, bool. Además, puedes tener un array de dichos tipos. Ya que un nodo puede o no tener alguna propiedad que otro nodo tenga, el tipo de dato null no existe.

Etiquetas

El nodo Marito, Juanito y Pepito son Personas. Entonces, podríamos etiquetarlos como tales. No es obligación, ya que un nodo puede tener 0..n . Las etiquetas también son key-sensitive

Relaciones

Existen para conectar nodos. Tienen un nombre y una dirección (origen-final), de modo que le dan la estructura al gráfico. Además, le dan un contexto semántico a un nodo.

Al conectar nodos, no todas las Personas van a tener las mismas relaciones. Cada nodo puede tener 1..n

Las relaciones pueden tener propiedades, las cuales se usan para darle una magnitud o peso a la relación.


Ahora que tenemos los elementos básicos, podemos comenzar a modelar.

Publicado en Bases de Datos, Neo4j | Etiquetado | Deja un comentario

Empezando con Neo4j (Instalación)

Resulta que un día andaba en twitter y alguien puso algo de otros motores de bd y descubrí las Graph Database, que a falta de traducción mejor sería: “Base de datos en grafos”.

Me llamó la atención y empecé a buscar información. Así llegué a Neo4j, que es como la más publicitada BD que trabaja en grafos. Ellos mismos tienen unos videos en su página y como estoy haciendo un sistema de peluquería para mi esposa, decidí de empezar de nuevo, pero en vez de usar MySQL, con Neo4j.

La idea es que busquen info ustedes mismos, pero a modo de resumen, la gracias es que los datos se almecenan de la misma forma en que harías un diseño en una pizarra.

De esa forma, es más fácil de entender para una persona que no está en el ámbito de las BD. Pero no es solamente eso, considera que si es más fácil de diseñar, será más fácil de pensar al programar 😀

Y al momento de llamar los datos, es más rápido por el simple hecho de no saltar de tabla en tabla buscando los registros en un join.

En cambio, usando grafos

to_graph_model

Aquí otro ejemplo

Captura
Listo, a instalarlo.

En mi caso lo estoy instalando en un Centos 7 x86_64. Si usan Debian/Ubuntu, Neo4j tiene su paquete correspondiente… pero para el resto, hay que bajar el tar.gz.

En este momento, la última versión (community) se descarga aquí. Luego un tar -xf neo4j_XXXX.tar.gz es suficiente. Al ejecutar el archivo bin/neo4j se ocupa el parámetro start para iniciarlo en segundo plano, o console para mironear todo lo que pase.

Al momento de abrirlo, tengo lo siguiente:

[root@luk0s neo4j-community-3.0.4]# ./bin/neo4j start
Starting Neo4j.
WARNING: Max 1024 open files allowed, minimum of 40000 recommended. See the Neo4j manual.
Started neo4j (pid 30355). By default, it is available at http://localhost:7474/
There may be a short delay until the server is ready.
See /opt/neo4j-community-3.0.4/logs/neo4j.log for current status.

El mensaje que indica el máximo de archivos abiertos es porque, en grafos, la cantidad de índices que son leídos son muchos más que 1K. También depende de la cantidad de conexiones que podríamos esperar. Para aumentar ese valor:

  1. Terminar proceso neo4j: ./bin/neo4j stop
  2. Editar /etc/security/limits.conf
  3. Agregar las 2 siguientes líneas
    1. neo4j soft nofile 40000
    2. neo4j hard nofile 40000
  4. Guardar
  5. Editar /etc/pam.d/su
  6. Agregar la siguiente línea
    1. session required pam_limits.so
  7. Guardar y reiniciar máquina

Obviamente lo anterior como root. Al iniciar nuevamente, el mensaje ya no existe.

Ahora tenemos el servicio corriendo. Para comprobarlo con un curl:

[root@luk0s neo4j-community-3.0.4]# curl http://localhost:7474
{
"management" : "http://localhost:7474/db/manage/",
"data" : "http://localhost:7474/db/data/"
}

Pero al intentar ir a la web desde el navegador, no podía acceder. Debería ser así, accesible únicamente desde localhost y entrar por un tunnel. En mi caso, no necesito taaanta seguridad así que lo dejo abierto para todos.

Entonces, detenemos el servicio:

[root@luk0s neo4j-community-3.0.4]# ./bin/neo4j stop

Luego editamos el archivo $NEO4J_HOME/conf/neo4j.conf , buscamos la línea dbms.connector.http.address=localhost:7473 y en vez de localhost => 0.0.0.0. Lo mismo para los siguientes puertos.

Por último, en caso de ser necesario, abrir el puerto 7474 (http), 7473 (https) y 7687 (Bolt, un ‘driver’):

firewall-cmd --permanent --zone=public --add-port=7474/tcp
firewall-cmd --permanent --zone=public --add-port=7473/tcp
firewall-cmd --permanent --zone=public --add-port=7687/tcp
firewall-cmd --reload

Listo!

Captura

Ahora le asignamos una contraseña y estamos listos.

Para mayor info, siempre a la raíz

http://neo4j.com/docs/operations-manual/3.0/deployment/

Publicado en Bases de Datos, Centos, Neo4j, Tutoriales | Etiquetado , | Deja un comentario

Error específico JSP, JSTL, Tomcat, y Intellij

Hola!

Lo siguiente es un error muy específico … tanto que tuve que escribirlo aquí por si es que alguien más tenía dicho error.

Descargué la nueva versión de Intellij IDEA (la 15) para ver qué tal y también porque necesitaba hacer un sistema en java web.

Para cambiar aires me fui con Tomcat, porque nunca lo había usado.

Resulta que al agregar las librerías de JSTL, saltaba el siguiente error: Captura

Se suponía que todo estaba bien… la librería estaba donde correspondía pero, aún así… no funcionaba. Captura

Buscand en stackOverFlow, llegué a alguien con un problema parecido… y mironeando, tenía el “mismo” error.

Captura

Por qué al descargar JSTL desde maven pasa eso … pues no tengo ni idea si se supone que las dependencias no deberían sobrescribirse … pero pasó.

Entonces, la solución más simple fue descargar los .jar y agregarlos directamente como librerías: Captura

Para luego agregarlos al proyecto Captura

Como dije al comienzo, es algo bien específico… no me pasó nunca en netBeans ni en Intellij cuando ocupaba Glassfish como servidor…

Publicado en Java, Tips | Deja un comentario

Mini Chrome-Extension Manda-Reportes

Hola!

Hace rato que no escribía nada porque no encontraba nada “nuevo” que hacer… hasta ayer, que nació una idea en la oficina:

Que los usuarios puedan mandar un reporte de error, simple, desde la misma página web.

Y paff, nació Chocapic. Leyendo en la información de Google, hice una mini-extension que hace justamente eso, enviar reportes.

Todas las extensiones (al menos para Chrome) cuentan con 4 partes:

  1. Ícono que muestra la extensión.
  2. Archivo popup.html que sirve se “ve” cuando le das click a la extensión.
  3. Archivo(s) auxiliares
  4. Un manifest que describe la extensión

Estas 4 partes se guardan en una carpeta. No es necesario comprimirla.

manifest.json

Tiene que llamarse así. El archivo “base” es algo así.

{
  "manifest_version": 2,
  "name": "EL NOMBRE DEL PLUGIN",
  "description": "LA DESCRIPCIÓN DEL PLUGIN",
  "version": "1.0",
  "browser_action": {
    "default_title": "LO QUE LEO CUANDO DEJO EL PUNTERO SOBRE EL ÍCONO",
    "default_popup": "popup.html"
  },
  "icons": {
    "16": "icon_16.png",
    "48": "icon_48.png",
    "128": "icon_128.png"
  },
  "permissions": [
    "tabs",
    "<all_urls>",
    "http://EN_CASO_DE_MANDAR_PETICION_A_SERVIDOR_EXTERNO"
  ]
}

Se explica sólo, pero mironeemos mejor el permissions:

  • Aquí le digo a Chrome que mi extensión utilizará la API relacionada con las pestañas (chrome.tabs) y ventana en si (chrome.window).
  • Además, le digo que funcionará bajo cualquier protocolo (http://, file://, ftp://, etc), en cualquier dominio, y con cualquier ruta auxiliar.
  • Por último le digo voy a ser “bienvenido” en el servidor X. Esto para, por ejemplo, enviar peticiones AJAX desde mi extensión.

Icons

Definimos los íconos a usar. Son 3, cada uno con su tamaño establecido (16×16, 48×48, 128×128). Se utilizan para el favicon, ícono “clickeable” y pestaña “extensiones” en Chrome.

popup.html

Es una página simple. Que se “muestra” al darle click a la extensión. En mi caso, es así: CapturaEl código es igual de simplesito.

<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <button id="btn_get_screenshot">Tomar Screenshot</button>
    <img id="img_screenshot" width="300" height="300"/>
    <form id="form">
      <input type="hidden" name="base64_imagen" id="base64_imagen" />
      <input type="text" name="txt_titulo" placeholder="Título"/>
      Descripción:
      <textarea name="txt_descripcion"></textarea>
      <input type="button" value="Enviar" id="btn_enviar_reporte"/>
    </form>
    <script type="text/javascript" src="popup.js"></script>
  </body>
</html> 

Como ven, una imagen, un formulario y un link a un .js .

Obviamente, va a depender de qué quieran hacer ustedes 😉

popup.js

Por último, el código que hace todo posible. En mi caso, 2 eventos: click para tomar screenshot y click para enviar formulario. El código sería así.

function getScreenshot(){
  chrome.windows.getCurrent(function (win){
    chrome.tabs.captureVisibleTab(win.id,{"format":"png"}, function(imgUrl){
      document.getElementById('img_screenshot').src = imgUrl;
      document.getElementById('base64_imagen').value = imgUrl;
    });
  });
};

function sendForm(){
  var form = document.getElementById('form');
  var xhr = new XMLHttpRequest();
  xhr.onload = function(){
    alert(xhr.responseText);
  };
  xhr.open('post', 'http://LA_MISMA_DEL_PERMISSIONS', true);
  xhr.send(new FormData(form));
  return false;
}

document.getElementById('btn_get_screenshot').addEventListener('click', getScreenshot);
document.getElementById('btn_enviar_reporte').addEventListener('click', sendForm);

Como ven, al tomar la screenshot, lo que obtenemos es el base64 de la misma. Entonces, si queremos “convertirla” a imagen, lo podemos hacer así al recibir el formulario en el servidor:

list($type, $data) = explode(';', $_POST["base64_imagen"]);
list(, $data)      = explode(',', $data);
$data = base64_decode($data);
file_put_contents('temporal/img.png', $data);

El Cielo es el límite !

Links de Interés:

Publicado en JavaScript | Deja un comentario

Separar nombre completo PHP

En un archivo que mandaron venían nombres de personas en una única columna. Algo así:

Mario Andrés Cares Cabezas

Pero nosotros en la BD tenemos el nombre separado en 3 columnas.

Entonces, hice lo que cualquier programador haría … convertir el tema. Entonces, hice una función que haga la pega.

  1. Crear un array con las excepciones. Básicamente palabras claves en nombres compuestos: “Del Carmen”, “San Martín”, etc.
  2. Dividir el string inicial cortando por “espacios”. Invertirlo
  3. Iterar por cada trocito e ir rellenando un array con los campos.
  4. Indicar que el primer trocito que leamos tiene que ir en el apellido materno.
  5. Limpiar por si quedaron espacios en blanco.

En otras palabras, esto:

array_reverse(explode(" ", strtoupper($nombreCompleto)));
$exceptions = ["DE", "LA", "DEL", "LOS", "SAN", "SANTA"];
$nombre = array( "Materno" => "", "Paterno" => "", "Nombres" => "" );
$agregar_en = "materno";
foreach($chunks as $chunk){
    if($primera_vez){
        $nombre["Materno"] = $chunk . " " . $nombre["Materno"];
        $primera_vez = false;
    }else{
        if(in_array($chunk, $exceptions)){
            if($agregar_en == "materno")
                $nombre["Materno"] = $chunk . " " . $nombre["Materno"];
            elseif($agregar_en == "paterno")
                $nombre["Paterno"] = $chunk . " " . $nombre["Paterno"];
            else
                $nombre["Nombres"] = $chunk . " " . $nombre["Nombres"];
        }else{
            if($agregar_en == "materno"){
                $agregar_en = "paterno";
                $nombre["Paterno"] = $chunk . " " . $nombre["Paterno"];
            }elseif($agregar_en == "paterno"){
                $agregar_en = "nombres";
                $nombre["Nombres"] = $chunk . " " . $nombre["Nombres"];
            }else{
                $nombre["Nombres"] = $chunk . " " . $nombre["Nombres"];
            }
        }
    }
}
$nombre["Materno"] = trim($nombre["Materno"]);
$nombre["Paterno"] = trim($nombre["Paterno"]);
$nombre["Nombres"] = trim($nombre["Nombres"]);

Y eso era suficiente… obtenía algo así

Array
(
    [Materno] => Cabezas
    [Paterno] => Cares
    [Nombres] => Mario Andrés
)

Funciona como debería … el problema llegó cuando apareció un nombre con este formato:

Cares Cabezas Mario Andrés

Aquí tuve que cambiar el algoritmo de arriba:

  1. Agregar un parámetro a la función que me diga si el nombre viene dado vuelta o no. Como es un string, el script no tiene como saber si el trocito que viene es un nombre o un apellido, así que este parámetro es responsabilidad del usuario (o módulo) desde donde se llama a la función.
  2. En base a ese parámetro, si empieza por el apellido, entonces no invierto los trocitos.
  3. En vez de empezar rellenando el apellido Materno, empiezo por el Paterno.
  4. Si no lo invierto, tengo que invertir el orden de ingreso de trocitos a determinado campo. Entonces, primero reviso si alguno de los trocitos es parte de un apellido o nombre compuesto. En base a eso cambio el orden de ingreso.

Resumiendo, quedó así:

public static function getNombreSplit($nombreCompleto, $apellido_primero = false){
    $chunks = ($apellido_primero)
        ? explode(" ", strtoupper($nombreCompleto))
        : array_reverse(explode(" ", strtoupper($nombreCompleto)));
    $exceptions = ["DE", "LA", "DEL", "LOS", "SAN", "SANTA"];
    $existen = array_intersect($chunks, $exceptions);
    $nombre = array( "Materno" => "", "Paterno" => "", "Nombres" => "" );
    $agregar_en = ($apellido_primero)
        ? "paterno"
        : "materno";
    $primera_vez = true;
    if($apellido_primero){
        if(!empty($existen)){
            foreach ($chunks as $chunk) {
                if($primera_vez){
                    $nombre["Paterno"] = $nombre["Paterno"] . " " . $chunk;
                    $primera_vez = false;
                }else{
                    if(in_array($chunk, $exceptions)){
                        if($agregar_en == "paterno")
                            $nombre["Paterno"] = $nombre["Paterno"] . " " . $chunk;
                        elseif($agregar_en == "materno")
                            $nombre["Materno"] = $nombre["Materno"] . " " . $chunk;
                        else
                            $nombre["Nombres"] = $nombre["Nombres"] . " " . $chunk;
                    }else{
                        if($agregar_en == "paterno"){
                            $nombre["Paterno"] = $nombre["Paterno"] . " " . $chunk;
                            $agregar_en = "materno";
                        }elseif($agregar_en == "materno"){
                            $nombre["Materno"] = $nombre["Materno"] . " " . $chunk;
                            $agregar_en = "nombres";
                        }else{
                            $nombre["Nombres"] = $nombre["Nombres"] . " " . $chunk;
                        }
                    }
                }
            }
        }else{
            foreach ($chunks as $chunk) {
                if($primera_vez){
                    $nombre["Paterno"] = $nombre["Paterno"] . " " . $chunk;
                    $primera_vez = false;
                }else{
                    if(in_array($chunk, $exceptions)){
                        if($agregar_en == "paterno")
                            $nombre["Paterno"] = $nombre["Paterno"] . " " . $chunk;
                        elseif($agregar_en == "materno")
                            $nombre["Materno"] = $nombre["Materno"] . " " . $chunk;
                        else
                            $nombre["Nombres"] = $nombre["Nombres"] . " " . $chunk;
                    }else{
                        if($agregar_en == "paterno"){
                            $nombre["Materno"] = $nombre["Materno"] . " " . $chunk;
                            $agregar_en = "materno";
                        }elseif($agregar_en == "materno"){
                            $nombre["Nombres"] = $nombre["Nombres"] . " " . $chunk;
                            $agregar_en = "nombres";
                        }else{
                            $nombre["Nombres"] = $nombre["Nombres"] . " " . $chunk;
                        }
                    }
                }
            }
        }
    }else{
        foreach($chunks as $chunk){
            if($primera_vez){
                $nombre["Materno"] = $chunk . " " . $nombre["Materno"];
                $primera_vez = false;
            }else{
                if(in_array($chunk, $exceptions)){
                    if($agregar_en == "materno")
                        $nombre["Materno"] = $chunk . " " . $nombre["Materno"];
                    elseif($agregar_en == "paterno")
                        $nombre["Paterno"] = $chunk . " " . $nombre["Paterno"];
                    else
                        $nombre["Nombres"] = $chunk . " " . $nombre["Nombres"];
                }else{
                    if($agregar_en == "materno"){
                        $agregar_en = "paterno";
                        $nombre["Paterno"] = $chunk . " " . $nombre["Paterno"];
                    }elseif($agregar_en == "paterno"){
                        $agregar_en = "nombres";
                        $nombre["Nombres"] = $chunk . " " . $nombre["Nombres"];
                    }else{
                        $nombre["Nombres"] = $chunk . " " . $nombre["Nombres"];
                    }
                }
            }
        }
    }
    // LIMPIEZA DE ESPACIOS
    $nombre["Materno"] = trim($nombre["Materno"]);
    $nombre["Paterno"] = trim($nombre["Paterno"]);
    $nombre["Nombres"] = trim($nombre["Nombres"]);
    return $nombre;
}

El problema, ahora, es que muchas partes se repiten … y no me gusta como se ve 😯 … pero por apuro, se queda así.

Publicado en Uncategorized | 3 comentarios

Los Usuarios (Parte II)

– Mario, puede abrir mi correo… es para mostrarle algo. Usuario X pass Y

(Yo pensando) Y por qué mejor no me llama a verlo en SU escritorio, estoy al lado ¬¬ Ya, abriendo Chrome en ventana privada.

-Baje más, es de ayer. Mmmm un poquito más. Ese, ese es. Mire ábralo. Me mandaron ese archivo raro que no puedo ver…

Era un .eml, de esos que te adjunta outlook cuando el usuario es un trollazo que no es capaz de responder un mail de manera normal.

-Ah si, es un archivo del outlook. Lo descargo y lo abrimos ahora.

-Se supone que es un excel con una planilla.

-A ver. (abriendo archivo). Ya, tiene algo adjunto … pero es un word… no un excel.

-Nooo ella me dijo que era un excel. Seguro que no es un excel ?

-Si. Seguro. Mire, vea la extensión. (era docx). Pero veamos que tiene dentro. Si, mire, es una tabla. Es esa la planilla que le mandaron ?

-Si, tiene la misma forma. Pucha que fome que no la mandaran en excel. Ya no importa. Mándeme el archivo por favor, el que acaba de abrir.

-Ok. Listo.

(A los 10 segundos)

-Mario, me mandaron una imagen. No es una tabla. Puede verlo ?

(Abriendo archivo de nuevo)

-Si verdad (aquí me reí internamente xDD quién en su sano juicio manda una imagen 😀 ). Es una imagen. Es una screenshot del excel original.

-Qué ?

-Una foto del archivo original, del excel.

-Pucha pero no me sirve. Puede convertirlo a excel?

(Aquí en este punto la risa estaba a punto de hacerse visible)

-No, no puedo convertirlo a excel si es una imagen… Si fuera un PDF podría ser… pero no una imagen.

-Y si convierte la imagen en PDF, podrá después hacerlo excel?

(wajajajajaj)

-No, no se puede… sigue siendo una imagen (esto lo dije con mi cara más seria que podía tener).

-Pucha, bueno. Gracias.

Publicado en Uncategorized | Deja un comentario