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 | Deja un comentario

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

¿ Visual Studio Code ?

La mayoría quedamos marcando ocupado cuando supimos que Microsoft tenía un editor para escribir donde fuera.

Así que corrí al Mac, y descargué la aplicación. Al abrirla … mi reacción fue: “Pero si esto es un SublimeText! ” Y si, es parecido. Otros lo pueden encontrar parecido a Atom. Captura de pantalla 2015-04-30 a las 0.55.42

Entonces dije: “ok, hagamos algo. Quiero un sistema chico en C# que corra en el Mac, y ocupando este nuevo editor”… Y ahí me quedé … no encontraba la opción para crear un nuevo proyecto o para configurarlo D:

Resulta que VSCode está orientado a carpetas/archivos, razón por la cual no podemos “crear” un proyecto directamente desde VSCode. Para “hacer” algo, tenemos que recurrir a yeoman para que nos cree un “proyecto. Había escuchado hablar sobre yerman hace un año atrás en la StarTechConf que se realizó en Chile … y nunca más escuché de él … nunca siquiera lo había usado… así que ahora va una pequeña introducción como para quedar bien😀

Yeoman es una herramienta para, a palabras simples, generar el proceso de “iniciar” un proyecto. Crea el esqueleto de carpetas, descarga dependencias, etc. Todo esto usando Bower y Grunt.

Por ejemplo, en mi caso siempre creo 4 carpetas para mis sistemas: asset, model, view, controller. Descargo bootstrap y jQuery en asset, genero las clases en model, y así. Es un proceso que hago siempre y pierdo unos minutos en hacerlo. Si usara Yeoman, sería automágico😀

Para instalar Yeoman, primero necesitamos node y su npm. Una vez que lo tengamos instalado (npm) seguimos con Yeoman, Grunt, Bower y un generador “especial” para apps de asp.net

npm install -g yo grunt-cli generator-aspnet bower

Y eso es todo, ahora podemos crear un directorio/proyecto usando Yeoman:

yo aspnet

Este generador nos da distintas opciones a elegir. Para una app web, marcan obviamente la que indica Captura de pantalla 2015-04-30 a las 1.33.55 y luego de indicar un nombre nos generará todas las carpetas con el árbol correspondiente. Algo así: Captura de pantalla 2015-04-30 a las 1.35.14

Ahora que ya tenemos el “proyecto” saltamos a VSCode y buscamos la carpeta creada. Automágicamente nos reconoce todo … pero, al menos en mi PC, me daba un error al no “entender” los archivos en C# Captura de pantalla 2015-04-30 a las 1.39.02

Dicha herramienta era OmniSharp, quién se encarga de que cualquier editor tenga el autocompletado, resaltado de errores, y virtualmente todas las “ayudas” que Visual Studio te da al escribir en C#. Pero para que ella funcione, necesitas tener instalado “Mono“. Captura de pantalla 2015-04-30 a las 2.02.44

Ahora, abrimos nuevamente VSCode y no hay errores … pero si un warning Captura de pantalla 2015-04-30 a las 2.03.50

Se refiere a DNX, que son herramientas propias de ASP.NET 5 que permiten que las apps creadas funcionen tanto en Windows como en Mac/Linux.

Para instalarlo, nos vamos a Homebrew:

brew tap aspnet/dnx
brew update
brew install dnvm

y una vez descargado, saltamos nuevamente a VSCode y ahora nos mostrará un aviso de que tenemos dependencias que no encuentra y que hagamos un “restore” para solucionar el problema descargando dichas dependencias.Captura de pantalla 2015-04-30 a las 2.40.45.

Desde la consola, en la carpeta creada por yeoman:

dnu restore

Si no encuentra el comando, es porque les faltó hacer esta parte:

Checking connectivity... done.
==> Checking out branch dev
==> bash -c 'source /usr/local/Cellar/dnvm/1.0.0-dev/libexec/dnvm.sh; dnvm upgra
==> Caveats
Add the following to the ~/.bash_profile, ~/.bashrc or ~/.zshrc file:

  source dnvm.sh

==> Summary
🍺  /usr/local/Cellar/dnvm/1.0.0-dev: 4 files, 56K, built in 14 seconds

Entonces, luego de reiniciar la consola, y correr el dnu restore, tenemos algo así Captura de pantalla 2015-04-30 a las 2.50.34Ahora si, volvemos a VSCode y lo único que nos falta es levantar el “servidor” y probar. Para ello, llamamos el “kicker” con las teclas ⇧⌘P y escribimos kestrel (que es un comando creado en project.son). Éste comando nos abre la consola y levanta el servidor.

Accedemos desde http://localhost:5001 y … nos da el siguiente error Captura de pantalla 2015-04-30 a las 2.57.03

Es un error conocido por la comunidad, por suerte, así que tiene solución:

  1. Dar de baja el servidor
  2. Ejecutar el siguiente comando en la consola el siguiente comando, y luego iniciar nuevamente el servidor
export MONO_MANAGED_WATCHER=disabled

Listo ! Captura de pantalla 2015-04-30 a las 23.25.30

Fuentes:

Publicado en Aplicación | Etiquetado , | Deja un comentario

Mironeando PictureBook (O la extensión que “hackea” a Facebook)

Hace poco salió la noticia de que una extensión para Chrome podía ver las fotos ocultas de la personas en Facebook.

La gente se volvió loca !! Y la verdad es que no es nada grave como para entrar en pánico.

Para tomar un ejemplo, entré al perfil de una persona que publicó algo en un grupo en Facebook. No lo conozco, y no tengo amigos en común y tiene todo bloqueado.

Si voy a ver sus fotos, logro ver algunas pocas.

Aquí entra en juego la extensión. Le das un click y mágicamente te da una grilla con las fotos de la persona. No son todas, y aún no entiendo el criterio que ocupa para mostrar las que sí puedes ver…

Lo único que hace, en realidad, es usar el mismo enlace que Facebook entrega… por lo que depende de Facebook. De ninguna manera es un crackeo ni nada, así que no hay nada que temer.

Lo que hace la extensión es “redirigir” a la siguiente URL

https://www.facebook.com/search/facebook_id_persona/photos-of

Y eso es todo …

Y si no conozco el FacebookID de la persona ?

Lo primero que puedes hacer es ver la URL de la persona. El link del tipo que estoy usando es : https://www.facebook.com/juansebastian.munozgonzalez

En este caso, no me sirve… ya que la persona está usando el alias.

Para ver el alias de la persona, la forma más fácil es:

  1. Click derecho en página y luego: “Inspeccionar Elemento”.
  2. En el panel nuevo que se abre, ir a “Consola” Captura de pantalla 2014-12-30 a las 13.23.05
  3. Ignorar el mensaje de alerta ( 8D )
  4. Copiar esto:
    console.log(document.getElementById("pagelet_timeline_main_column").dataset.gt);
  5. Pegar (Justo abajo donde dice que no hagas caso cuando te digan que copies y pegues… jajajaja ) y da enter.
  6. Sale algo así y listo
    Captura de pantalla 2014-12-30 a las 13.27.01
    😉 Tenemos el FacebookID (profile_owner).

Ahora que tenemos listo, simplemente reemplazamos en la URL anterior

https://www.facebook.com/search/facebook_id_persona/photos-of

Si se preguntan por qué hice el post … es porque me carga cuando dicen: “ooohhhh lograron hackear a Facebook !!! Vamos a morirrr!!!

Y no, no han “hackeado” a facebook …

Publicado en Demases | Deja un comentario

Los Usuarios (Parte I)

Empezamos nueva categoría en el blog dedicada a nuestros queridos usuarios🙂

Estaba tranquilo en la oficina viendo un video en YouTube sobre las muertes en Star Wars (Algo así como 2.005.000 millones de muertes) y llegó una usuaria con un papel en la mano.

Dentro de mis funciones, es mi deber minar la BD en busca de personas con enfermedades raras. Obviamente, cuando llegó la usuaria con el papel en mano automáticamente asumí que me iba a pedir los datos de X persona… la primera con ebola en la ciudad de Iquique.

Pero no. En el papel tenía nada más que un link a youtube:

-“Mario, cómo puedo tener este video en mi carpeta?”
-“Mmm crea un link a la página, o lo descarga directo desde YouTube”
-“Ya, quiero eso. Cómo lo descargo?”
-(Yo, con cara de: “para qué me pregunta si me va a pedir a mi que lo haga”) “Mándeme ese mismo enlace por correo y yo lo descargo”
-“Ah, pero no se cómo mandarlo…”
-“De la misma manera en que lo copió para imprimirlo en ésta hoja… y me lo manda por correo”
-“Ya ! Ok, te lo mando ahora”

Y como podrán estar pensando … lo que llegó por correo fue un word adjunto con el link del video dentro …

Captura de pantalla 2014-10-27 a las 9.00.59

Publicado en Usuarios | Deja un comentario

En busca de un cochino sonido en un cochino juego en un cochino programa en un cochino celular

La cosa es así: Escuché el sonido de un pollito, como esos de goma, que me quedó gustando. Quise que me lo mandaran para ponerlo como tono cuando llegara una notificación al celular (WP 8.1 … ahora se puede😉 8) ). La cosa es que el sonido venía de un juego … no de algo que se pueda enviar fácil y bonito.

Buscando el juego (Mr. Flap) en google encontré su .APK y la descargué.

Los que han desarrollado para android más o menos saben lo que sigue… para el resto, seguir los pasos😉

  1. Descargar el APK y cambiar la extensión a .zip
  2. Al descomprimir tenemos distintas carpetas, la que nos importa es res o resources.
  3. En mi caso, el sonido se encontraba aquí Captura de pantalla 2014-05-02 a la(s) 11.46.10
  4. Lo siguiente es enviarlo al equipo (En mi caso un Lumia 920) usando el software de Windows:
    1. Únicamente se pueden usar .mp3 o .wma … por lo que, el .wav no me sirve… Lo convierto online aquí.
    2. Lo abro con iTunes, click derecho y obtener información. Al fondo, le agrego el género de ringtoneCaptura de pantalla 2014-05-02 a la(s) 11.59.07
    3. Ahora, el programa me lo reconoce y lo puedo enviar al equipo ;) Captura de pantalla 2014-05-02 a la(s) 12.00.53
  5. Con el archivo en el teléfono, vamos a las configuraciones y luego “Ringtones y Sonidos”:
    1. Bajamos hasta el final y nos lleva a los sonidos por aplicación: wp_ss_20140502_0003
    2. Siguiente, abrimos la aplicación a la que vamos a asignar el sonido: wp_ss_20140502_0001
    3. Por último, buscamos el sonido :D wp_ss_20140502_0002
  6. Y eso fue todo😀 Simple para los que hacemos esto… pero un poco más complicado para la gente común y silvestre.

Espero les sirva😉

Publicado en Tutoriales, Windows Phone | Etiquetado , , | 1 Comentario