Acerca de:

Este blog contiene los códigos, ejemplos y bases de datos que he usado cuando aprendía acerca de algún tema específico. En lugar de borrarlos (una vez dominado ya el tema), he decidido publicarlos :)

viernes, 22 de julio de 2016

Cambiando la codificación de un archivo de Python en Python Tools for Visual Studio 2013 Express

Como siempre olvido cómo ponerle la codificación UTF-8 a mis archivos de python he hecho este tutorial. Por defecto el IDE les pone codificación Ansi, sucede que a veces mis comentarios tienen acentos y el intérprete me tira error al ejecutarlos.

1. En la primera línea le ponemos la codificación deseada, en este caso es "# coding=utf-8". La codificación debe ir con el símbolo de numeral para que el intérprete la reconozca:



2. Vamor a Archivo->Guardar como...



3. Elegimos "Guardar con codificación..."



4. Elegimos la codificación "Unicode UTF-8":


De esta forma el intérprete no tirará error al poner comentarios con caracteres internacionales.

martes, 7 de junio de 2016

Detectar si un puerto está abierto en un host específico.

El código original es de Mark Ribaul, yo sólo lo arreglé para testear un puerto específico (probado en Windows 7):


from socket import *
import sys

# http://serverfault.com/a/311580

if __name__ == "__main__":
    fTimeOutSec = 1
    sNetworkAddress = sys.argv[1].split(":")[0]
    aiPort = sys.argv[1].split(":")[1]

    setdefaulttimeout(fTimeOutSec)

    print ("Starting Scan...")
   
    s = socket(AF_INET, SOCK_STREAM)
    result = s.connect_ex((sNetworkAddress, int(aiPort)))

    if (result == 0):
        print ("OPEN: " + sNetworkAddress + ":" + aiPort)

    elif (10035 == result):
        print ("Timeout or inexistent host")
        pass
    else:
        print ("closed: " + sNetworkAddress + ":" + aiPort)

    s.close()

    print ("Scan Completed.")



He puesto el script en un archivo llamado "scan_port.py", y los argumentos que se le pasan son la ip y el puerto separados por dos punto, es decir, de la siguiente manera: "ip:puerto":


Aquí estoy probando con localhost, pero también funciona para ips remotas.

sábado, 21 de mayo de 2016

Error en Visual Studio 2013, no se encontraron exportaciones que coincidieran con la restricción: ContractName

Un día quise abrir mi Visual Studio 2013 Express y me salió una ventana con el siguiente error:

"Error en Visual Studio 2013, no se encontraron exportaciones que coincidieran con la restricción: ContractName".

La solución se encuentra en esta web (link actualizado: https://www.dokry.com/5958 ) pero en mi caso, al usar la versión Express, la carpeta a eliminar está en la ruta "C:\Users\User\AppData\Local\Microsoft\WDExpress\12.0":

sábado, 23 de abril de 2016

Gráfica del Movimiento Browniano unidimensional en Python

El Movimiento Browniano puede considerarse la suma acumulada de una serie de variables aleatorias con distribución normal y media cero. Para aproximar a un Movimiento Browniano continuo, se pueden utilizar "segmentos" (o mejor dicho: sus raíces cuadradas) de un intervalo multiplicado por las variables aleatorias. Las raíces cuadradas resultan de un teorema de convergencia en probabilidad. Esta convergencia se calcula utilizando la función esperanza o media.

El código para generar la gráfica del Movimiento Browniano fue traducido del Matlab al Python a partir del código del capítulo 2 del libro "Stochastic Diferential Equations: Models and Numerics" de Jesper Carlsson, Kyoung-Sook Moon, Anders Szepessy, Raúl Tempone y  Georgios Zouraris. Además, como ejercicio, quise implementar mi propia función de suma acumulada "cumsum". El código resultante es el siguiente:


import numpy as np
import math
import matplotlib.pyplot as plt

def cumsum(lista):
    lista2 = [lista[0]]
    for i in range(1, len(lista)):
        lista2.append(lista[i] + lista2[-1])

    return lista2


N = 1E6
np.random.seed(1337)
A = np.random.normal(0, 1, N-1)
T = 1
dt = 1/(N-1)
t = [c/(N-1) for c in range(0, int(N-1))]
dW = [c*math.sqrt(dt) for c in A]
W = cumsum(dW)

# Aqui se requiere Numpy y Mathplotlib
plt.plot(W)
plt.ylabel('Brownian Motion')
plt.show()

'''
N = 1E6; % number of timesteps
randn('state',0); % initialize random number generator
T = 1; % final time
dt = T/(N-1); % time step
t = 0:dt:T;
dW = sqrt(dt)*randn(1,N-1); % Wiener increments
W = [0 cumsum(dW)]; % Brownian path
LHS = sum(t(1:N-1).*dW);
RHS = T*W(N) - sum(W(1:N-1))*dt;
'''


Para instalar Numpy y Matplotlib se debe bajar el archivo get-pip.py de este enlace. Y se debe ejecutar en la terminal (para Linux) o en el CMD (para Windows) la siguiente instrucción:

python get-pip.py

Si es Linux es mejor poner:

sudo python get-pip.py

La terminal o el CMD deben apuntar a la carpeta donde está el archivo get-pip.py.

Luego se debe instalar numpy y matplotlib. En Linux se ingresa los comandos:

pip install matplotlib
pip install numpy

Si no recuerdo mal, Matplotlib también instala Numpy.

En Windows, como soy muy floja, me descargué el pip-Win e ingresé los respectivos comandos en la caja de texto donde pide el comando:




Éste es el resultado. Estoy usando Python Tools for Visual Studio:




jueves, 17 de marzo de 2016

Calculando el MCD de dos números con el algoritmo de Euclides en Prolog

Esta vez sí estoy usando el algoritmo de Euclides (pero usando restas sucesivas) :D

Blatant Copy/Paste:
La lógica de Prolog es la siguiente: devuelve el valor de retorno en la variable del extremo derecho. La coma es el AND lógico, y el punto y coma el OR lógico. Cada declaración de la función "mcd" equivale a un if.
End of Blatant Copy/Paste

Si el valor en la variable B es 0 ó 1, el algoritmo ignora el valor de A y retorna 0 ó 1 según corresponda. Si no es así, evalúa si A es menor a B, si es así intercambia los valores de A y B, y luego realiza las restas sucesivas como indica el algoritmo. En el algoritmo de Euclides se suele usar un bucle, pero en Prolog se debe utilizar recursividad.

He aquí el código:

mcd(_, 0, 0).
mcd(_, 1, 1).
mcd(A, B, X):- A < B, mcd(B,A,X).
mcd(A, B, X):- N is A - B, N =:= 0, X is B.
mcd(A, B, X):- N is A - B, N =:= B, X is B.
mcd(A, B, X):- N is A-B, N < B, mcd(B, N, X).
mcd(A, B, X):- N is A-B, N > B, mcd(A, N, X).



Estoy usando SWI Prolog 7.2.

miércoles, 10 de febrero de 2016

Visualizar imágenes en Sql Server Management Studio con SSMSBoost

Estaba insertando imágenes a un base de datos en SQL Server 2012 con este código. Luego necesité ver si las imágenes se habían insertado bien. El Sql Server Management Studio no tiene una opción para visualizar imágenes y yo necesitaba algo simple y rápido, de usar y tirar.
Rebuscando en internet hallé un add-on que sí lo permite: el SSMSBoost, el cual tiene una versión Community gratuita que se puede usar para todo, sólo hay que reinstalarla cada tres meses.

Luego de instalarlo, y para poder ver las imágenes, se deben seguir los siguientes pasos:

1. Escoger la tabla con las imágenes y elegir la opción "Visualizar los primeros 1000 registros" haciendo clc derecho (en realidad se debe hacer un select).
2. Hacer click derecho al registro con la imagen que queremos ver, escoger la opción "Visualize as->Settings"


3. En la opción "Picture (any format)", el formato de imagen se coloca png, pues si se deja el valor por defecto (dat) el mspaint no lo va a reconocer:


Esto hace que mspant pueda abrir imágenes png, gif y jpg (no he probado con otros formatos, pero debe funcionar).

4. Luego de presionar el botón "Apply" o "Apply & Close", se escoge la opción "Visualize as->Picture (any format)".

Éste es el resultado:



domingo, 17 de enero de 2016

Implementación del Chatbot Eliza en Prolog

El algoritmo, que permite que Eliza genere una respuesta acorde a las consultas del usuario, se basa en comparar término a término la data ingresada versus una lista de templates con las respuestas predefinidas. Las ideas iniciales para desarrollar este algoritmo fueron obtenidas de [2] y de [3], a partir de estas fuentes se realizó una implementación propia.

El formato de cada template es el siguiente:

template([lista con las palabras del estímulo], [lista con las palabras de la respuesta de Eliza], [lista con las posiciones de las palabras clave en el estímulo empezando de cero]).

Un template de ejemplo tendrá la forma:



Las palabras clave le permiten a Eliza generar una coincidencia para diferentes listas de palabras, tales como “i am sad.” o “i am angry.”. Las palabras claves se reemplazarán en la respuesta en las posiciones donde hay números y no palabras.
 

La función que realiza la comparación es la función “match”. En el estímulo, las palabras clave están marcadas por predicados, mientras que el resto de los términos son atómicos. Cuando la función match detecta un dato no atómico, usando la función de SWI-Prolog “atom”, lo ignora y continúa con la comparación término a término entre la data ingresada y el estímulo. Si se encuentra un template que coincida, devolverá la respuesta correspondiente y la lista de índices. Los índices deben coincidir con las posiciones de los datos no atómicos en el estímulo del template.
 

La función “replace0” se encarga de reemplazar las palabras claves de la data ingresada en las posiciones donde la respuesta del template tiene números. Las palabras clave pueden ser una o más. Para saber qué palabra clave corresponde a qué posición en la respuesta, los números se van incrementando de uno en uno. Si no hay palabras para reemplazar, la lista de índices será una lista vacía.

Esta función llama a las siguientes funciones ya implementadas en SWI-Porlog:

nth0: devuelve el elemento de una lista en una posición dada.

select: reemplaza el valor de un elemento de una lista por otro en función a sus valores.

append: concatena dos listas. En este caso va concatenando las palabras de la respuesta, junto con la palabra reemplazada en la posición donde hay un número, palabra por palabra.
 

La función “replace0” también genera las respuestas a preguntas y consultas del tipo “do you like ...?”, “you are ...” y “do you (verb) ...?”. Los templates correspondientes tienen el siguiente formato:
 


Si la función “replace0” detecta una de las banderas (flags) configuradas, buscará la respuesta correspondiente en las funciones elizaDoes, elizaIs y ElizaLikes, las cuales evalúan los hechos que determinan si Eliza hace, es o le gusta algo. 

El código donde se declaran estos hechos es el siguiente:


El código que le permite al usuario ingresar sus consultas es el siguiente:


La función “readln” convierte las consultas del usuario en una lista. Luego el programa escogerá el primer template de la base del conocimiento, a continuación el estímulo de ese template, y la consulta del usuario (Input), son ingresados a la función “match”. Si el estímulo no coincide con la consulta, Prolog empezará el backtracking, escogiendo el siguiente template y repitiendo la operación. El último template de la base de conocimiento hace que la función “match” retorne verdadero si ninguno de los otros estímulos de los otros templates coincide con la consulta del usuario. Esto evita que se rompa el bucle de Eliza y finalice el programa de forma abrupta. A continuación se llama a la función “replace0”, para luego imprimir la respuesta en la pantalla. Eliza seguirá esperando las consultas del usuario mientras éste no ingrese “bye” o “bye.”.
 

II

Conversando con Eliza


Para interactuar con el programa Eliza, se debe ejecutar el intérprete SWI-Prolog, abrir el archvo eliza_complete.pl y compilarlo. En la consola de SWI-Prolog se deberá ingresar “eliza.” Eliza mostrará un mensaje de bienvenida y esperará por más consultas del usuario. Éstas deben estar en minúsculas y tener un punto al final.

Una conversación de ejemplo es la siguiente:



Eliza da las respuestas en forma de listas de palabras, separadas por comas y entre corchetes. Se mantuvo este formato porque en una aplicación Eliza real, es muy probable que las respuesta halladas requieran un procesamiento posterior.

La aplicación ha sido probada en SWI-Prolog versión 7.2.1. No se ha probado en versiones anteriores. No funcionará en versiones de SWI-Prolog que no tengan implementadas las funciones length, nth0, atom y select.

Esta implementación de Eliza no tiene memoria, es decir, no recuerda las consultas ingresadas y sus respuestas, por lo que la coherencia de la conversación depende del usuario. Por ejemplo, para Eliza es válido ingresar primero la consulta “because you are creepy.” Y luego “i hate you.”.
 

Para ampliar las respuestas de Eliza a más estímulos basta crear más templates con los formatos ya mencionados.


En este programa, la aparente inteligencia de Eliza está en función a la amplitud de su base de conocimientos. Como la coincidencia de las consultas del usuario y los estímulos se realiza término a término, la base de conocimiento de Eliza debe ser bastante grande para producir una conversación coherente, y poder respetar género, número, tiempos verbales, etc. Un programa más completo consideraría toda una lista de palabras clave en lugar de sólo una.

El código completo es (Escrito en Prolog y probado en Swi Prolog v7.2.):


% by: Y3l1nna_Broken_Window:
% la función match permite crear un output para varios inputs.

eliza:-	writeln('Hi, I am Eliza your chatbot,
	please enter your query,
	use only lowercases and a dot at the end:'),
	readln(Input),
	eliza(Input),!.
eliza(Input):- Input == ['bye'],
	writeln('Goodbye. I hope I have helped you.'), !.
eliza(Input):- Input == ['bye', '.'],
	writeln('Goodbye. I hope I have helped you.'), !.
eliza(Input) :-
	template(Stim, Resp, IndStim),
	match(Stim, Input),
	% si he llegado aquí es que he
	% hallado el template correcto:
	replace0(IndStim, Input, 0, Resp, R),
	writeln(R),
	readln(Input1),
	eliza(Input1), !.

% algunos saludos
% debido al backtracking, los templates más específicos deben ir antes
% de los más genéricos. Eso se nota acá:
template([hi, my, name, is, s(_), '.'], ['Hi', 0, 'How', are, you, '?'], [4]).
template([hello, my, name, is, s(_), '.'], ['Hello', 'How', are, you, 0, '?'], [4]).

template([hi, ',', my, name, is, s(_), '.'], ['Hi', 0, 'How', are, you, '?'], [5]).
template([hello, ',', my, name, is, s(_), '.'], ['Hello', 'How', are, you, 0, '?'], [5]).

template([hi, _], ['Hi', 'How', are, you, '?'], []).
template([hello, _], ['Hello', 'How', are, you, '?'], []).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

template([i, s(_), i, am, s(_),'.'], [why, do, you, 0, you, are, 1, '?'], [1, 4]).
template([i, s(_), you, '.'], [why, do, you, 0, me ,'?'], [1]).
template([i, am, s(_),'.'], [why, are, you, 0, '?'], [2]).

% pregunta algo que le gusta a eliza
template([do, you, like, s(_), _], [flagLike], [3]).
% pregunta algo que hace eliza
template([do, you, s(_), _], [flagDo], [2]).
% pregunta algo que es eliza
template([you, are, s(_)], [flagIs], [2]).
template([are, you, s(_), '?'], [flagIs], [2]).

template([how, are, you, '?'], [i, am, fine, ',', thanks, for, asking, '.'], []).

template([i, think, _], [well, that, is, just, your, opinion], []).
template([because, _], [that, is, not, a, good, reason, '.'], []).
template([i, have, s(_), with, s(_), '.'], ['You', have, to, deal, with, your, 0, and, your, 1, in, a, mature, way, '.'], [2, 4]).
template([i, s(_),  _], [i, can, recommend, you, a, book, about, that, issue], []).
template([please, s(_), _], ['No', i, can, not, help, ',', i, am, just, a, machine], []). % didn't passed the Turing Test
template([tell, me, a, s(_), _], ['No', i, can, not, ',', i, am, bad, at, that], []). % classic AI problem: una máquina aún no puede contar una historia coherente.

template(_, ['Please', explain, a, little, more, '.'], []). % cuando se ingresa algo que Eliza no tiene en sus templates, esto debe ir al final o eliza responderá a todo con esto.

% Lo que le gusta a eliza : flagLike
elizaLikes(X, R):- likes(X), R = ['Yeah', i, like, X].
elizaLikes(X, R):- \+likes(X), R = ['Nope', i, do, not, like, X].
likes(apples).
likes(ponies).
likes(zombies).

%%%%%%%%%%%%%%%%%%%%%%

% lo que hace eliza: flagDo
elizaDoes(X, R):- does(X), R = ['Yes', i, X, and, i, love, it].
elizaDoes(X, R):- \+does(X), R = ['No', i, do, not, X ,'.', it, is, too, hard, for, me].
does(study).
does(cook).
does(work).

%%%%%%%%%%%%%%%%%
% lo que es eliza: flagIs
elizaIs(X, R):- is0(X), R = ['Yes', i, am, X].
elizaIs(X, R):- \+is0(X), R = ['No', i, am, not, X].
is0(dumb).
is0(weird).
is0(nice).
is0(fine).
is0(happy).
is0(redundant).

%  http://stackoverflow.com/questions/12939425/prolog-access-specific-member-of-list
% magic happens here :D
% lo que hace match es comparar el input y el estímulo término a
% término, ignorando los s(X) en cada template. Si match falla en el
% loop de la función eliza, empezará el backtracking que permite
% recorrer los templates ingresados. match devolverá verdadero si haya
% un estímulo (primer término del template) que coincide con el Input, y
% devolverá la respuesta.
match([],[]).
match([], _):- true.

match([S|Stim],[I|Input]) :-
	atom(S), % si I es un s(X) devuelve falso
	S == I,
	match(Stim, Input),!.

match([S|Stim],[_|Input]) :-
% I es un s(X), lo ignoro y continúo con el resto de la lista
	\+atom(S),
	match(Stim, Input),!.

% esta función es para que se muestre bien en pantalla las respuestas de
% eliza. Además responde a lo que le gusta Eliza y a lo que hace, la
% función select reemplaza el número en la respuesta por la palabra
% clave hallada:
replace0([], _, _, Resp, R):- append(Resp, [], R),!.

% Eliza likes:
replace0([I|_], Input, _, Resp, R):-
	nth0(I, Input, Atom),
	nth0(0, Resp, X),
	X == flagLike,
	elizaLikes(Atom, R).

% Eliza does:
replace0([I|_], Input, _, Resp, R):-
	nth0(I, Input, Atom),
	nth0(0, Resp, X),
	X == flagDo,
	elizaDoes(Atom, R).

% Eliza is:
replace0([I|_], Input, _, Resp, R):-
	nth0(I, Input, Atom),
	nth0(0, Resp, X),
	X == flagIs,
	elizaIs(Atom, R).

replace0([I|Index], Input, N, Resp, R):-
	length(Index, M), M =:= 0,
	nth0(I, Input, Atom),
	select(N, Resp, Atom, R1), append(R1, [], R),!.

replace0([I|Index], Input, N, Resp, R):-
	nth0(I, Input, Atom),
	length(Index, M), M > 0,
	select(N, Resp, Atom, R1),
	N1 is N + 1,
	replace0(Index, Input, N1, R1, R),!.


sábado, 9 de enero de 2016

Listar los archivos en una carpeta y sus subcarpetas de forma recursiva v2

Esta es una versión mejorada de la función listdir_recurd:

import os
import sys
from os import listdir
from os.path import isfile, isdir, join


def listdir_recurd(files_list, root, folder, checked_folders):

    if (folder != root):
        checked_folders.append(folder)

    for f in listdir(folder):
        d = join(folder, f)       

        if isdir(d) and d not in checked_folders:
            listdir_recurd(files_list, root, d, checked_folders)
        else:
            if isfile(d):  # si no hago esto, inserta en la lista el nombre de las carpetas ignoradas
                files_list.append(join(folder, f))

    return files_list


Esta vez, la función devuelve las rutas completas de solamente los archivos que va encontrando, ignorando las carpetas y subcarpetas. Yo necesité esta función para borrar archivos de prueba que generaba otra aplicación, dejando sólo las carpetas vacías:

if __name__ == "__main__":
    # filez = listdir_recurd([], 'D:\test0', 'D:\test0', []) # esto lista todos los archivos
    # filez = listdir_recurd([], 'D:\test', 'D:\test', ['D:\\test\\t1', 'D:\\test\\t2']) # esto omite las carpetas 'D:\\test\\t1' y '
D:\\test\\t2'
    # filez = listdir_recurd([],
'D:\test', 'D:\test', ['D:\\test\\t1']) # esto omite la carpeta 'D:\\test\\t1'
   
    filez = []

    for f in sys.argv[1:]:
         if os.path.exists(f):
            filez += listdir_recurd([], f, f, [])
    

# la línea siguiente es la que hay que temer, borrará todo lo que se haya encontrado
# si por error se ingresa un directorio raíz... lo borrará todo, dejando las carpetas vacías!!
    [os.remove(c) for c in filez if os.path.exists(c)]
    print 'Files Deleted!!'



Como estoy usando Python Tools For Visual Studio, el script se debe setear como Startup File haciéndole click derecho en el explorador de soluciones. Las carpetas cuyos archivos se desean eliminar se ingresan como:


Hay que tener cuidado al borrar archivos con este método ya que no van a la papelera de reciclaje.

sábado, 19 de diciembre de 2015

Cómo mostrar la fecha completa en un DataGridView cuando es exactamente medianoche

Hice la pregunta originalmente en StackOverflow.

Tengo este DataGridView:


El problema está en la fila seleccionada: en realidad tiene el valor "07/10/2015 12:00:00 am", pero en el DataGridView sólo se muestra "07/10/2015". La siguiente fila tiene el valor de " 07/10/2015 12:00:26 am ". Este problema sólo ocurre cuando los valores DateTime son exactamente medianoche. Cuando paso ese valor al de texto a la izquierda con el siguiente código, el valor DateTime se muestra correctamente (los valores DateTime están en la columna con índice 2):

text1.Text = dgView.SelectedRows[0].Cells[2].Value.ToString();

No quiero cambiar el valor de DefaultCellStyle.Format porque quiero mostrar los valores tipo DateTime en el formato de la configuración regional del sistema operativo (en mi caso es es-pe).

La solución me la dio Jon Skeet. Si se está usando Visual Studio, se debe seleccionar el DataGridView e ir a la ventana Propiedades->DefaultCellStyle e ingresar "G" en "Format":

 
Con esto el DataGridView mostrará las horas exactamente a medianoche y sin cambair la configuración regional.

martes, 3 de noviembre de 2015

Cómo instalar Gnome en Centos 7 Minimal

En mi Centos 7 Minimal (el que no tiene manejador de ventanas), virtualizado con Virtual Box, quise instalar Gnome; pero cuando ingresaba los comandos de yum para descargar e instalar los paquetes, me tiraba que las direcciones de los repositorios estaban mal configuradas y no era capaz de encontrarlas.

Rebuscando en internet hallé la raiz del problema, mi conexión Ethernet no estaba activa. Para activarla se debe ingresar en la terminal:

nmcli & nmtui

lo cual abrirá un menú al mejor estilo DOS donde se podrá activar la conexión Ethernet.

Ya conectado, se puede invocar al instalador de Gnome con este comando:

sudo yum groupinstall "GNOME Desktop"

"sudo" es opcional si ya se está logueado con un usuario con suficientes privilegios.
Con esto, yum descargará los 650 megas de Gnome y los instalará (hay que tenerle un poco de paciencia pues incluye Firefox y LibreOffice).

Luego de descargr los 650 megas de paquetes, yum nos pedirá confirmar un par de veces si se desea incluir una clave con el hash de las descargas, y continuar. Si por error se presiona algo que nos haga salir de la instalación, sólo se debe volver a ingresar el comando yum groupinstall "Gnome Desktop", como los paquetes ya están descargados, esta vez el instalador revisará las dependencias e iniciará la instalación después de pedirnos confirmación.

Para iniciar Gnome (no es necesario reiniciar el sistema) se ingresa:

sudo systemctl start graphical.target

Agradezco el tutorial a nixCraft :D