Programación

Esta semana me tope con varias cosas:

  1. http:/comunidad.4geeks.codonde-estan-los-desarrolladores-venezolanos/
  2. http://ivanjovanovic.com/2012/04/26/programming-languages-are-simply-not-powerful-enough/https://news.ycombinator.com/item?id=5302667
  3. http://www.code.org/

1.- Comunidad de desarrolladores venezolanos

Leí el artículo y me agradó mucho lo que dice. Concuerdo en todo y me gustaría apoyar con lo que pueda.

Para mí en este país no existe una buena cultura de programadores/afines como tal. Por el hecho de ser un programador el resto de la sociedad en general te ve como un nerd o parecido. Gracias a eso y muchos otros factores, entre los que están la situación del país, industria de informática poco desarrollada, etc., no hay motivación para ayudar y/o emprender. Nadie quiere hacer cosas interesantes y es justamente lo que refleja el texto. Lo que termina sucediendo es que muchas personas se vayan del país a buscar mejores vidas. De ahí que es muy complicado conseguir y conocer buenos desarrolladores.

Yo tuve la suerte de en mi trabajo anterior conocer a mi actual jefe y a otros dos grandes de la informática. No soy nadie para colocarlos en la lista, yo cumplí con el deber de decirles. Tampoco me pondría a mi mismo. Apenas tengo año y medio en el campo laboral y no me siento experto con alguna herramienta. A pesar de ésto, estoy 100% dispuesto a ayudar con lo que pueda.

¡ Ojalá sigan surgiendo cosas así y que está logre sus objetivos !

2.- El poder expresivo de los lenguajes

Encontré un artículo criticando las primitivas en muchos lenguajes actuales. Específicamente a la forma de abstracción que obligan a uno. Se apoya y sugiere el uso de DSL (Domain Specific Lenguages)  a la hora de programar.

Leí todo lo que pude al respecto y me quedaron varias dudas con lo que se toca en el texto. De lo que entendí los DSL son un lenguajes con un vocabulario específico para resolver problemas de un mismo estilo. Son como un API , pero mucho más poderosos. Facilitan la abstracción de los problemas. Pero,  ¿a qué costo? y ¿realmente son útiles y/o necesarios?

El único DSL o lo más parecido que he tocado es Django. Es muy útil y comprensible el código que se hace. Pero, yo no me imagino cada vez que quiera programar crear un lenguaje (lexer  + parser) y luego programar en él.  Es demasiado tiempo innecesario perdido. Es mucho más eficiente buscar librerías con muchas cosas hechas que nos sean útiles y trabajar con esas cosas. Ya hay muchas cosas hechas para tener que perder tiempo creándolas. La abstracción puede llegar a ser la misma o tener un nivel muy alto si se siguen buenas prácticas de programación.

La programación siempre sera el arte de abstraer y traducir un problema a un lenguaje que entiendan las computadoras. 

Los lenguajes de programación nunca tendrán la expresividad del lenguaje humano (son ambiguos y no hay computadora que los reconozca).  Por ello lo usual es expresar primero la especificación del problema de una forma genérica en un lenguaje sencillo (pseudo-código, matemático, humano) y luego traducirla al lenguaje en que se va a implementar.

La idea es cierta de una forma e interesante, pero por los momentos no convence.

3.- Todos debemos saber algo de programación

Code.org es una organización creada para promover y enseñar a programar. En el video de 5 min aparecen muchos de los grandes de la informática: Bill Gates, Mark Zuckerberg, el creador de Twitter, el de Dropbox, entre otros.

El objetivo es muy simple: la programación es algo que debe ser conocida por todos en esta época.

En casi todas las empresas hay un departamento de computación o requieren de trabajos en el área. Crear una página web, montar un programa para recopilar información, manejar el inventario y facturación mediante un programa, etc. son ejemplos. Por lo menos tener un conocimiento básico a la hora de salir al mercado laboral va a ser importante.

Además, programar enseña como pensar, resumiendo la primera frase en el video de Steve Jobs. Es usar lógica para escribir una seria de pasos para resolver un problema. Ver una pequeña dosis en el colegio puede ayudar y motivar a estudiar una carrera informática a las personas. Y no solo eso, también hay una gran demanda de informáticos, pero no hay oferta. Ésto es algo muy inusual en el mundo actual. Las personas deben saber de ésto.

A la final nadie puede ni debe obligar a otra persona estudiar o hacer algo que ella no quiere. Ya veremos como siguen evolucionando las cosas.

Advertisements

Backbone.js & Knockout

He tenido mucho trabajo y cosas que hacer, que no he podido escribir.

El año pasado mi jefe me pidió que viera las diversas librerías existentes estilo Backbone.js y Knockout. La idea era ver todas las opciones y tomar la más conveniente.

Para ello me puse a leer y buscar bastante información. Además, aproveche de probar cada una y ver como me sentía.  Para ello primero cree una aplicación en Backbone.js y luego observé que tal sería usar Knockout.

El resultado se los comento acá con el código. Así aprenden un poco y elijen el que más les guste.

Backbone.js

Es muy poderoso y usado por muchas personas, pero tiene una curva de aprendizaje un poco fuerte. Se tiene un modelo, con un montón de cosas que hay que definir. Luego, si se siguen las convenciones, al ser modificado, cambia de una vez las vistas. Acá pueden ver mucho mejor todos los detalles.

Lo ideal para trabajar con  él, es tener servicios web de tipo REST.

Crear la aplicación me quitó una tarde y parte de la mañana.

El html:

<div>
    <fieldset>
        <legend>Person List - Using Backbone</legend>
        <div id="person-container">
            <input type="button" value= "Create New" class="Add" id="btn-create-new-person" />
            <table id="person-list">
                <tr>
                    <th>
                        Name
                    </th>
                    <th>
                        Description
                    </th>
                    <th>
                    </th>
                </tr>
            </table>
        </div>
        <script id='person-template' type='text/template'>
            <td><%=ID%></td> <td><%=FirstName%></td> <td><%=LastName%></td> <td><%=Age%></td>
            <td><input type="button" value="Edit" class="person-edit" /> | <input type="button" value="Details" class="person-detail" /> | <input type="button" value="Delete" class="person-delete" /></td>
       </script>
    </fieldset>
</div>

Javascript:

$(function () {

    // Person Model
    var Person = Backbone.Model.extend({
        urlRoot: '/Person/List/',
        initialize: function () {
            console.log('Person initialize');
        },
        defaults: {
            ID: 0,
            FirstName: 'Unknown',
            LastName: 'Unknown',
            Age : 0
        }
    });

    // Person Collection
    var PersonCollection = Backbone.Collection.extend({
        model: Person,
        url: '/Person/List/'
     });

     // Person View - el returns the template enclosed within a tr
     var PersonView = Backbone.View.extend({
         template: _.template($('#person-template').html()),
         tagName: "tr",
         initialize: function () {
             console.log('PersonView initialize');
             this.model.bind('change', this.render, this);
             this.model.bind('remove', this.unrender, this);
         },
         render: function () {
             console.log('PersonView render');
             $(this.el).html(this.template(this.model.toJSON()));
             return this;
         },
         unrender: function () {
             console.log('PersonView unrender');
             $(this.el).remove();
             return this;
         },
         events: {
             "click .person-edit": 'EditPerson',
             "click .person-delete": 'DeletePerson'
         },
         EditPerson: function () {
             console.log('PersonView EditPerson');
             this.model.set({ FirstName: 'Unknown' });
             var self = this;
             this.model.save(this.model, { success: function () {
                 $("input:button", $(self.el)).button();
             }});
        },
        DeletePerson: function () {
            console.log('PersonView DeletePerson');
            this.model.destroy();
        }
    });

    // Actual App view
    var AppView = Backbone.View.extend({
        initialize: function () {
            console.log('AppView initialize');
            this.collection.bind('add', this.AppendPerson, this);
        },
        el: '#person-container',
        counter: 3,
        events: {
            "click #btn-create-new-person": "AddNewPerson"
        },
        AddNewPerson: function () {
            console.log('AppView AddNewPerson');
            this.counter++;
            var newPerson = new Person({ ID: this.counter, FirstName: 'Unknown ' + this.counter, LastName: 'Damn ' + this.counter, Age: this.counter });
            this.collection.add(newPerson);
            newPerson.save(newPerson, { success: function () {
                $("input:button", "#person-list").button();
            }});
        },
        AppendPerson: function (person) {
            console.log('AppView AppendPerson');
            var personView = new PersonView({ model: person });
            $(this.el).find('table').append(personView.render().el);
        },
        render: function () {
            console.log('AppView render');
            if (this.collection.length > 0) {
                this.collection.each(this.AppendPerson, this);
            }
            $("input:button", "#person-list").button();
        }
    });

    var persons = new PersonCollection();
    var view = new AppView({ collection: persons });

    persons.fetch({ success: function () {
        console.log('Fetch called');
        view.render();
    }});
});

Y en el servidor (en mi caso asp.net MVC 3 con C#):

public class PersonController : Controller
{
    List<Person> Persons = new List<Person> {
        new Person (1, "Federico", "Ponte" , 23),
        new Person (2, "Alejandro", "Drago" , 23),
    };

    // Get Person
    [AcceptVerbs(HttpVerbs.Get)]
    public JsonResult List(int? ID)
    {
        if (ID.HasValue)
        {
            Person PersonResult = Persons.Find(p => p.ID == ID);
            return Json(PersonResult, JsonRequestBehavior.AllowGet);
        }
        return Json(Persons, JsonRequestBehavior.AllowGet);
    }

    // Update Person
    [AcceptVerbs(HttpVerbs.Put)]
    public JsonResult List(int ID, Person UpdatedPerson)
    {
        Person PersonResult = Persons.Find(p => p.ID == ID);
        PersonResult.FirstName = UpdatedPerson.FirstName;
        PersonResult.LastName = UpdatedPerson.LastName;
        PersonResult.Age = UpdatedPerson.Age;
        return Json(PersonResult, JsonRequestBehavior.DenyGet);
    }

    //Add Person
    [AcceptVerbs(HttpVerbs.Post)]
    public JsonResult List(Person CreatePerson)
    {
        Persons.Add(CreatePerson);
        return Json(CreatePerson, JsonRequestBehavior.DenyGet);
    }

    //Delete Person
    [AcceptVerbs(HttpVerbs.Delete)]
    public JsonResult List(int ID)
    {
        Person PersonResult = Persons.Find(p => p.ID == ID);
        Persons.Remove(PersonResult);
        return Json(PersonResult, JsonRequestBehavior.DenyGet);
    }
}
public class Person
{
    public Person(int _ID, string _FirstName, string _LastName, int _Age)
    {
        ID = _ID;
        FirstName = _FirstName;
        LastName = _LastName;
        Age = _Age;
    }

    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}

Como verán es trabajoso, pero trae sus ventajas: super configurable, sirve para celulares, se tienen los servicios web, etc. Si se quiere escalar, es muy fácil.

Es un poco complicado al comienzo, pero una vez que se entiende y se acostumbra es sencillo.

Knockout

Hace uso del patrón Model-View-View Model. Es muy fácil de aprender y es bastante poderoso. Ya viene con un sistema de templates bastante completo y muchas funciones hechas. Se crea el modelo y basta con modificarlo directamente para que las vistas se actualicen. Tiene buena documentación y no es nada complejo.  Para saber más ingresa aquí.

Un modelo sería:

function PersonModel () {
    var self = this;

    self.ID = ko.observable(0);
    self.FirstName = ko.observable('Unknown');
    self.LastName = ko.observable('Unknown');
    self.Age = ko.observable(0);
}

function PersonCollectionModel () {
    var self = this;

    self.Persons = ko.observableArray()
}

$(function (){
    ko.applyBindings(new PersonCollectionModel());
});

La fastidioso es hacer la funcionalidad: no es tan estructurada. Un ejemplo sería lo siguiente:

function PersonModel () {
    var self = this;

    self.ID = ko.observable(0);
    self.FirstName = ko.observable('Unknown');
    self.LastName = ko.observable('Unknown');
    self.Age = ko.observable(0);

    self.changeAndAlert = function (){
        self.FirstName('Hola');
        self.LastName('Chao');

        alert('Me cambie a ' + self.FirstName() + ' ' + self.LastName());
    }
}
</span></span></span>
<pre><pre><pre><div>
    <fieldset>
        <legend>Person List - Using Knockout</legend>
        <div id="person-container">
            <input type="button" value= "Create New" class="Add" id="btn-create-new-person" />
            <table id="person-list">
                <tr>
                    <th>
                        Name
                    </th>
                    <th>
                        Description
                    </th>
                    <th>
                    </th>
                </tr>
                <!-- ko foreach : persons -->
                    <tr>
                        <td data-bind="text : FirstName"></td>
                        <td data-bind="text : LastName"></td>
                        <td><input type="button" data-bind="click : changeAndAlert" value="ChangeAndAlert" /></td>
                    </tr>
                <!-- /ko -->
            </table>
        </div>
    </fieldset>
</div>

El resto de la funcionalidad implementada en el caso de Backbone.js es sencilla de hacer. Con saber usar bien jQuery o alguna otra librería basta con hacer las llamadas ajax correspondientes y modificar el modelo.

Comparación

Personalmente me gustó mucho Backbone.js. Me sentí más cómodo con él. La forma en que incita a uno a programar da una fácil mantenibilidad y pone de forma sencilla el poder escalar. Es un poco complejo de agarrar al comienzo  pero luego se hace fácil.

En cuanto Knockout es el que más he usado y es bastante sencillo. Se aprende fácilmente y es muy simple.

Ambos son igual de capaces, la decisión es por gusto.

Otras

Hace poco me conseguí me con esta librería patrocinada por Google.

Angular JS

Números primos

El fin estaba algo aburrido y venía de leer el siguiente artículo:

http://tech-queries.blogspot.com/2009/04/amazon-interview.html

Lo conseguí ya que me dio curiosidad como es el Fibonacci con eficiencia (n*log(n)) (http://tech-queries.blogspot.com/2010/09/nth-fibbonacci-number-in-ologn.html)

En eso me dio por hacer un problema en http://www.spoj.pl. Entre en mi cuenta, en la cual tengo como 7 problema hechos y vi cual hacer. Elegí uno de generar números primos( http://www.spoj.pl/problems/PRIME1/). Se da una serie de intervalos y hay que imprimir los números primos que hay en ellos.

Empece a programar en Python y yo ya conocía de la criba de Eratóstenes (http://es.wikipedia.org/wiki/Criba_de_Erat%C3%B3stenes) para generar números primos. Fui por una solución simple, buscaba el máximo número en el cual un intervalo terminaba y calculaba los primos hasta ahí y luego imprimía los que había en cada uno de los intervalos.

#!/usr/bin/python
# -*- coding: utf-8 -*-

from sys import stdin

def sieve(end):
    primes = range(2, end+1)
    for i in primes:
        j = 2
        while i * j <= primes[-1]:
            if i * j in primes:
	            primes.remove(i*j)
            j += 1
    return primes


if __name__ == "__main__":
    end = 0
    ncases = int(stdin.readline())
    cases = []

    for ncase in xrange(ncases):
        case = stdin.readline()
        case_start, case_end = map(int, case.split(' '))
        cases.append({'start' : case_start, 'end' : case_end})
        end = max(end, case_end)

    primes = sieve(end)

    count = 1

    for case in cases:
        for prime in primes:
            if prime < case['start']:
                continue
            elif prime <= case['end']:
                print prime
            else:
                break

        if count != ncases:
            print ''

        count += 1

No cumplió por problemas de memoria, ya que el arreglo de primos era muy grande, así que decido hacer lo mismo, pero en C++. Me encargue de hacerlo super eficiente en memoria, usando 1 bit por cada primo, en vez de 1 byte. Con mi computadora me tomó unos minutos sacar todos los primos hasta 1000000000. Me generó un archivo de 500 megas.

#include <iostream>
#include <fstream>
#include <vector>
#include <math.h>
#include <stdlib.h>
using namespace std;

const char masks [] = {-2, -3, -5, -9, -17, -33, -65, 127};

char *sieve(int max)
{
    int max_index = max/8 + 1;
    char *primes = new char[max_index];

    for(int i = 0; i < max_index; i++)
        primes [i] = 255;

    for(int i = 2; i <= max; i++)
    {
        int j = 2;
        int mult =  0;
        while((mult =  i * j) <= max)
        {
            int index = (mult - 1)/8;
            primes[index] &= masks[(mult - 1) % 8];
            j++;
        }

    }

    return primes;

}

int main()
{

    int ntest;
    int case_start, case_end;
    int max_end = 0, test = 1;
    vector<pair<int, int> > cases;

    cin >> ntest;

    for(; test <= ntest; test++)
    {
        cin >> case_start;
        cin >> case_end;

        pair<int, int> test_case(case_start, case_end);

        cases.push_back(test_case);

        max_end = (case_end > max_end ? case_end : max_end);

    }

    char *primes = sieve(max_end);

    vector<pair<int, int> >::iterator it;
    test = 1;

    for ( it=cases.begin() ; it != cases.end(); it++, test++ )
    {
        pair<int, int> test_case = *it;
        case_start = test_case.first;
        case_end = test_case.second;

        if(!(case_start & 1))
            case_start++;

        for(case_start; case_start <= case_end; case_start += 2)
        {
            if(case_start == 1) continue;
            int index = (case_start -1)/8;
            if(primes[index] & (1 << ((case_start -1) % 8)))
                cout << case_start << endl;
        }

        if(test != ntest)
            cout << endl;
    }

}

Esta vez se cayó por tiempo. Era claro que no use el modo correcto para calcular las cosas. Pensé un rato y leí un poco por Internet. Resulta que existe una versión segmentada de la criba de Eratóstenes.  Se calculan los primos hasta la raíz cuadrada del número (en este caso 32000) y luego con esos primos, se revisa en el intervalo si algo de esos es múltiplo de él, sino es un primo. Lo implemente y por tratar de programar de modo legible, entendible y bonito, se me cayo por tiempo. A la final elimine funciones e hice casi todo en la función principal y lo logre. Perdí un buen tiempo, pero fue interesante.

#include <iostream>
#include <fstream>
#include <vector>
#include <math.h>
#include <stdlib.h>
#include <string.h>
using namespace std;

#define MAX_FIRST_SIEVE_INDEX 32000
#define MAX_FIRST_SIEVE_PRIME 32000
#define MAX_PRIMES 4000

bool sieve[MAX_FIRST_SIEVE_INDEX];
int primes[MAX_PRIMES];

void gen_first()
{
    int i = 0, k = 0;

    memset(sieve, true, MAX_FIRST_SIEVE_INDEX);

    for(i = 2; i <= MAX_FIRST_SIEVE_PRIME; i++)
    {
        int j = 2;
        int mult =  0;
        if(sieve[i-1]) 
            primes[k++] = i;

        while((mult =  i * j) <= MAX_FIRST_SIEVE_PRIME)
        {
            sieve[mult-1] = false;
            j++;
        }

    }

}

int main()
{
    int ntest;

    cin >> ntest;
    gen_first();

    for(int test = 1; test <= ntest; test++)
    {
        int case_start, case_end;

        cin >> case_start;
        cin >> case_end;

        for(int i = (case_start > 2 ? case_start : 2); i <= case_end; i++)
        {
            bool print = true;

            for(int j = 0; primes[j]*primes[j] <= i; j++)
            {
                if(i % primes[j] == 0 )
                {
                    print = false;
                    break;
                }
            }
            if(print) cout << i << endl;

        }

        if(test != ntest)
            cout << endl;
    }


}

Big Data, mi opinión y varias cosas cool en Python

Big Data

Ayer revisando mi twitter, me encuentro con lo siguiente:

http://techcrunch.com/2012/10/27/big-data-right-now-five-trendy-open-source-technologies/

Varias de esas tecnología las he escuchado y usado: he usado un poco hadoop mediante pig y otros en el trabajo usan Kafka. Es increíble hacia donde esta yendo el mundo de la computación e información. Ciertamente las metaheurísticas que vi y use para hacer data clustering en mi tesis están en el rumbo correcto. Ya la programación normal no se de abasto. Pensar en paralelización y formas para manejar cantidades gigantes de datos es el futuro. Es la era de la información y hay que saber como explotar y sacar todo lo posible de los datos. Ya veremos como siguen las cosas, mientras a conocer un poco de estas cosas.

Python

En lo que estaba haciendo me vi en la necesidad de hacer request a MySQL, a páginas web, mandar correos, hacer gráficas, entre otras cosas. Todo lo hice mediante Python y ciertos bash para ayudarme.

Request a páginas web

Use lo siguiente: http://docs.python-requests.org/en/latest/. La libreria urllib2 es muy buena y es posible que no halla tenido que usar esta, pero en verdad fue lo que me salió más rápido y conseguí de primero.

Hacer una petición POST es así de tonto:

import requests
    result = request.post(url, params = parametros[, cookies = ....])

Si queremos que sea una petición GET, siemplemente se cambie la palabra. Por ejemplo si queremos atentificarnos en una página y luego sacar información el script sería algo así:

import request

auth_cookies = None
def login():
    request_result = requests.post(url, params = {'username' : usuario, 'password' : clave})
    request_result.raise_for_status()
    global auth_cookies
    auth_cookies = request_result.cookies

def get_information():
    request_result = requests.get(url', params = ..., cookies = auth_cookies)
    request_result.raise_for_status()
    #En request.text esta el resultado, lo parseamos o buscamos lo que necesitamos de acá

if __name__ == "__main__":
    login()
    get_info()
    ....

Así de fácil.

Mandar email

Lo saque de internet y le comenté ciertas cosas que no me agarranon bien:

import os
import smtplib
import mimetypes
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.MIMEAudio import MIMEAudio
from email.MIMEImage import MIMEImage
from email.Encoders import encode_base64
from sys import argv

def sendMail(subject, text, *attachmentFilePaths):
    gmailUser = ''
    gmailPassword = ''
    recipient = ''
    msg = MIMEMultipart()
    msg['From'] = gmailUser
    msg['To'] = recipient
    msg['Subject'] = subject
    msg.attach(MIMEText(text))
    for attachmentFilePath in attachmentFilePaths:
        msg.attach(getAttachment(attachmentFilePath))
        mailServer = smtplib.SMTP('smtp.gmail.com', 587)
        mailServer.ehlo()
        mailServer.starttls()
        mailServer.ehlo()
        mailServer.login(gmailUser, gmailPassword)
        mailServer.sendmail(gmailUser, recipient, msg.as_string())
        mailServer.close()
       print('Email enviado a %s' % recipient)

def getAttachment(attachmentFilePath):
    contentType, encoding = mimetypes.guess_type(attachmentFilePath)
    if contentType is None or encoding is not None:
    contentType = 'application/octet-stream'
    mainType, subType = contentType.split('/', 1)
    file = open(attachmentFilePath, 'rb')
    '''
    if mainType == 'text':
        attachment = MIMEText(file.read())
    elif mainType == 'message':
        attachment = email.message_from_file(file)
    elif mainType == 'image':
        attachment = MIMEImage(file.read(),_subType=subType)
    elif mainType == 'audio':
        attachment = MIMEAudio(file.read(),_subType=subType)
    else:
    '''
    attachment = MIMEBase(mainType, subType)
    attachment.set_payload(file.read())
    encode_base64(attachment)
    file.close()
    attachment.add_header('Content-Disposition', 'attachment', filename=os.path.basename(attachmentFilePath))
    return attachment
 

Mandarlo es simplemente completar las variables y usar las funciones como uno desee.

Como vamos

Primero comentare del pasado domingo brevemente:

No hubo fraude, simplemente tenemos una mayoría en el país que fue exluida por 40 años y ahora que le dan migajas de esperanzas, dan su voto por la mediocridad. Un cambio es necesario y es hora de una política seria.

Desde hace que no posteo nada, he estado ajustado de tiempo. Las cosas que han pasado:

  • Ya no ando programando en asp.NET (use MVC 3.0 con VB y 2.0 con C#)
  • Lo del artículo va en camino de tortuga.
  • Ahora ando en un proyecto de investigación, donde he tenido que usar Java, Python, bash y SQL.
  • Me compre un Nexus 7 y unos audífonos. Excelente hasta ahora, 100% recomendables.
  • asp.net MVC >= 3.0 no tiene nada que envidiarle a otro frameworks. Es facil de usar y de programar. En mi caso use el EntityFramework para manejar la parte del modelo. Es bastante configurable y permite usar stored procedures. Ésto último es muy buena práctica. IIS lo poco que tuve que tocar, me pareció bueno. Mis quejas serían tener que pagar por algo que se puede tener gratis igual o mejor (RoR, Django) y la documentación no es tan buena en comparación con las cosas que son open source.
  • Team Fundation y svn, son un asco al lado de git. Gracias Linus Trovalds.
  • Como escribí antes me encanta Python, lástima que lo conocí y aprendí tarde. Es bastante legible y poderoso. Ando seguro que Perl es muy usado y posiblemente más poderoso, pero odio los $ (si odio php).
  • Es increíble la cantidad de herramientas que existen hoy en día. Ejempo son hadoop, pig, oozie, que otros en el trabajo andan usando.
  • Con respecto al anime, me leí gran parte de las novelas de Sword Art Online. Muy buenas. Salió una ova de Code Gueass.
  • Me puse a ver Breaking Bad. Voy terminando la 3era temporada. Que serie tan buena. Tiene unas partes que te mantienen pegado, pero debo decir que a veces se pone algo calmada y lenta. Ya veremos como sigue.

A ver si tengo cosas más interesantes que colocar, ya veremos.

Lenguajes de Programación

Tenía un rato sin escribir. Muchas cosas encima.

Estaba acordándome de muchas cosas que vi en la universidad. Una de ella fue la electiva de lenguajes de programación. Justo me he estado acordando, primero por programar todo el tiempo y estar leyendo cosas nuevas, que salen. También he programado en muchos lenguajes, en algunos poco y en otros bastante, y siempre ando aprendiendo cosas nuevas.

De la universidad tengo uno que otro libro. Los cuadernos tendría que buscarlo bastante. A lo que quiero llegar, es que lo único que guarde fueron los apuntes de esas cosas que aprendí.

Esa electiva es la abren cada 2 años debido a la poca demanda. Segundo, es considerada bastante compleja y difícil, lo cual es muy cierto. En ella se ve toda la teoría detrás de los compiladores, optimización y alguna que otra cosa que el profesor desee dar (en mi caso, fue equivalencia de lenguajes o algo por el estilo, no me acuerdo 100% bien). Estás razones, agregándole el poco “uso” a la hora de trabajar hacen que muy pocas personas la vean.

Me agradaría comentar el porque yo elegí verla, que opino de ella y que cosas vi y aprendí.

Primero, nunca he sido un gran amante de tener un horario, trabajar y siempre quise primero, tener mucho conocimiento y luego aplicarlo.  Sumando el hecho de mi indecisión de tomar tesis o pasantía, las fechas en que abren las materias, la termine cursando. Me pareció una excelente oportunidad de expandir mis conocimientos y aprender algo que es sumamente complicado en algún trabajo. Me llamó mucho la atención la dificultad, el hecho que se complementara con la otra electiva que tome (diseño de algoritmos) y de tener una gran teórica a la hora que desee aplicar a un postgrado.

Ahora mi opinión. Me pareció excelente, al principio espere otra cosa, pero ya a la mitad del curso se puso sumamente interesante. Capte mucho mejor la teoría detrás de los lexers/parsers. Viví en carne propia como se hace la generación de código ensamblador, lo cual en realidad no es complicado, sino trabajoso. El manejo de memoria estática, como se hace con las variables anidadas. Debido a que el proyecto era en parejas y la cantidad de tiempo limitada, el hacer una manejador de memoria dinámica era opcional y evidentemente no lo hice.

Una de las cosas que más me gusto fueron las técnicas de optimización de código. Vi como 7 – 8,  pero de las más importantes y que mejoran la velocidad significativamente. Es de mucha ayuda generar primero un código intermedio, al cual se le pueden hacer análisis de flujo, optimización de ciclos, eliminar variables innecesarias, etc. Y luego generar el código de máquina objetivo y aplicar las optimizaciones respectivas que se le puedan hacer a eso. Viendo los grafos de flujo del código, se puede eliminar código que no se usar, ver que variables permanecen vivas a medida que el código se ejecuta y mediante eso hacer muchas mejoras.

Con los ciclos se puede sacar invariantes, calcular mucho más rapido el acceso a estructuras (por ejemplo, arreglos), y así muchas otras cosas.

Yo solo vi como un abre boca a la cantidad de mejoras que se pueden hacer. Lo interesante es que en el análisis de flujo, se usan unas ecuaciones matemáticas bastante interesantes llamadas, ecuaciones de punto fijo (fixed point en inglés). Es posible que ande mal, pero sino me equivoco son dos fórmulas recursivas dependientes entre sí mismas. Ya hay un algoritmo matemático que las resuelve y el análisis del flujo se expresa en ese formato.  Se puede crear una especia de librería que tenga la capacidad de optimizar el código y no dudaría si ya existen.

Pienso que salí como un gran programador después de ver la cadena. En mi opinión saber programar y hacerlo bien es más importante que tener todo el conocimiento en algún lenguaje. La capacidad que uno adquiere de adaptarse a cualquier lenguaje, librería, software, luego de ver la electiva, me parece que aumenta. Opino que no tiene nada que envidiarle a cualquier otra electiva y no hay nada que temerle. El conocer como es el funcionamiento por debajo de un lenguaje, las decisiones que se toman a la hora de su diseño, las capacidades, etc., son muy útiles en la vida real.

Eso era todo quería expresar ésto!

Mi tesis

Decidí escribir sobre mi tesis.

Primero hablaré el porque tome este camino y no pasantía. Lo primero, trabajo para mi mismo y mi compañero, es decir, yo dispongo de mi tiempo. Segundo, trabajar usualemente es algo muy mecánico y en la cual uno no toca temas interesantes  de la teoría de la computación, la cual me parece full interesante. Con éstas razones, sumándole de tener un buen compañero y una profesora dispuesta a ser tutora, se dió el proyecto.

Mi tesis trata sobre clustering de datos, el cual hoy en día es usado en diversas aplicaciones, como lo son Data Mining, preprocesamiento de imágenes, etc. Es una búsqueda no supervisada (no se tiene información previa y se clasifica desde cero). Es un problema NP-Hard.

La manera para atacarlo fue mediante metaheurísticas. Éstas son algoritmos, génericos, por ello la palabra meta, que usan suposiciones/intuiciones que no siempre dan resultados exactos, de ahí la palabra heurística. Hay montones: genético, búsqueda Tabu, algoritmo hormiga, PSO, simulated anieling, etc. Mi compañero y yo implementamos 5 de ellas, basadas todas en población e inteligencia colectiva.

La implementación fue en C++. Para este tipo de problemas se quiere un lenguaje que compile a código de máquina. Se busca eficiencia. La diferencia entre C y C++ es mínima en tiempo, siendo este último preferible por ser orientado a objetos.

De todo lo que se hizo, lo que mejor quedó fue el algoritmo genético. Dió los mejores resultados, es muy flexible, eficiente, etc. Mi compañero y yo hemos estados haciendo pruebas, cambiando y mejorando el código para ver si con la tutora, que tenemos abandonada, logramos escribir una publicación. El código ha sido reescrito y mejorado. Ahora es super entendible y a su vez bastante efieciente. Ya en uno de mis post toque el tema de mis intentos y logros por hacer el código mas efieciente.

Es bastante divertido saber la cantidad de lenguajes que usamos. Además de C++, se usan Python, Haskell y Latex, cada uno para cosas diferentes. Para el manejo de versiones se usa GIT. Ya veremos que sucede, posteo unas imágenes para demostrar lo que es capaz de hacer:

Antes:

Peppers

Después:

Peppers, Resultado

Antes:

Lenna

Después:

Lenna, Resultado

Antes:

Fotografía

Después:

Fotografía, Resultado

Finalmente una imagen de la cual se pueden conseguir patrones escondidos:

John Lennon

Eso es todo, hablamos !

Google Maps

Estos días estuve un rato largo lideando con Google Maps para aprender de él y ver sus posibilidades.

El ejemplo que hice es simular un mapa de los Estados Unidos donde se pueden ver diversas propiedades.

Antes que nada hay que obtener un API Key mediante una cuenta de google y de esta forma poder usarlo.

Otra cosa de las cosas usadas fue JQuery. Ya teniendo estás dos cosas se puede echar cógido.

Se puede usar Google Maps de dos formas: una llamada totalmente secuencial y otra asíncrona. El ejemplo usa está última:

En el Javascript:

function loadScript()
{
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = "http://maps.googleapis.com/maps/api/js?key=APIKEYo&sensor=false&callback=initialize";
    document.body.appendChild(script);
}
function initialize()
{
    var myOptions = {
        zoom: 4,
        center: new google.maps.LatLng(38.68551, -99.22852),
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        minZoom: 4,
        maxZoom: 16
    };
    map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
}
$(document).ready(function () {
    loadScript();
});

En el HTML:

<div id="map_canvas"></div>

De acá uno puede empezar a complicar más la cosa. Lo siguiente sería agregar una imagen donde se hizo click en el map, que está al hacerle click salga una ventana de información y ademas debajo del mapa salga un div con un link para eliminarla.

Dentro de la función initialize se coloca lo siguiente:

    image = new google.maps.MarkerImage('path/image.png',
    new google.maps.Size(20, 32),
    new google.maps.Point(0, 0),
    new google.maps.Point(0, 32));
google.maps.event.addListener(map, 'click', function (event) {
    addMarker(event.latLng);
});

La función addMarker es la siguiente:

function addMarker(location, name)
{
    if (name == undefined) name = "default";
    if (markers[name] == undefined) markers[name] = [];
    var marker_number = markers[name].length;
    var contentString = '<div id="marker_info"><h2>Excelente localidad</h2></div>';
    var infowindow = new google.maps.InfoWindow({
       content: contentString,
       maxWidth: 150
    });
    var marker = new google.maps.Marker({
        position: location,
        map: map,
        icon: image,
        title: location.name
     });
    google.maps.event.addListener(marker, 'mouseover', function () {
        infowindow.open(map, marker);
    });
    google.maps.event.addListenerOnce(marker, 'click', function () {
        $('#marks').append('<a href="#" marker="' + marker_number + '">Eliminar- ' + marker_number + '</a>');
        $('[marker=' + marker_number + ']').click(function () {
             removeMarker("default", marker_number);
            $(this).hide();
        });
    });
    markers[name].push(marker);
}
function removeMarker(name, number)
{
    markers[name][number].setMap(null);
    markers[name][number] = null;
    swap(markers[name], number, markers[name].length - 1);
    markers[name].length -= 1;
}
function swap(array, a, b)
{
    var aux = array[a];
    array[a] = array[b];
    array[b] = aux;
}

Markers va a ser un diccionario que mapea a arreglos de marcadores.  Debajo del div donde está el mapa de google se coloca el siguiente:

<div id="marks">Haz click para eliminar </div>

Con lo siguiente se va a poder agregar marcadores en el mapa que muestran información y poder eliminarlos.

Vamos a complicar esto un poco más. Creemos una función para agregar polígonos y otra que simula búsquedas. Para ello agregamos las siguientes funciones:

En el Javascript:

function searchAddress(address, remove)
{
    var houses = searchResults[address];
    if (houses == undefined) {
        geocoder.geocode({ 'address': address }, function (results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                map.setCenter(results[0].geometry.location);
                alert(results[0].geometry.location.latitude + ', ' + results[0].geometry.location.longitude);
            }
            else
                alert("Geocode was not successful for the following reason: " + status);
        });
    }
    else if (houses.length == 0) return;
    else
    {
        var maxX = -360.0,
        maxY = -360.0,
        minX = 360.0,
        minY = 360.0;
        var coordinates = []
        if (remove)
        {
            for (name in searchResults)
            {
                removeMarkers(name);
                removePolygon(name);
            }
        }
        for (house in houses)
        {
            if (houses[house].longitude < minX) minX = houses[house].longitude;
            if (houses[house].longitude > maxX) maxX = houses[house].longitude;
            if (houses[house].latitude < minY) minY = houses[house].latitude;
            if (houses[house].latitude > maxY) maxY = houses[house].latitude;
            addHouseMarker(address, houses[house]);
            coordinates.push(new google.maps.LatLng(houses[house].latitude, houses[house].longitude));
         }
         addHousesPolygon(address, coordinates);
         var southWest = new google.maps.LatLng(minY, minX),
         northEast = new google.maps.LatLng(maxY, maxX);
         var bounds = new google.maps.LatLngBounds(southWest, northEast);
         map.fitBounds(bounds);
         var center_location = new google.maps.LatLng((minY + maxY) / 2, (minX + maxX) / 2);
         map.setCenter(center_location);
     }
}
function searchAllAddress()
{
    var maxX = -360.0,
    maxY = -360.0,
    minX = 360.0,
    minY = 360.0;
    for (address in searchResults)
    {
        var houses = searchResults[address];
        var coordinates = []
        for (house in houses)
        {
            if (houses[house].longitude < minX) minX = houses[house].longitude;
            if (houses[house].longitude > maxX) maxX = houses[house].longitude;
            if (houses[house].latitude < minY) minY = houses[house].latitude;
            if (houses[house].latitude > maxY) maxY = houses[house].latitude;
            addHouseMarker(address, houses[house]);
            coordinates.push(new google.maps.LatLng(houses[house].latitude, houses[house].longitude));
        }
        addHousesPolygon(address, coordinates);
    }
    var southWest = new google.maps.LatLng(minY, minX),
    northEast = new google.maps.LatLng(maxY, maxX);
    var bounds = new google.maps.LatLngBounds(southWest, northEast);
    map.fitBounds(bounds);
    var center_location = new google.maps.LatLng((minY + maxY) / 2, (minX + maxX) / 2);
    map.setCenter(center_location);
}
function removeMarker(name, number)
{
    markers[name][number].setMap(null);
    markers[name][number] = null;
    swap(markers[name], number, markers[name].length - 1);
    markers[name].length -= 1;
}
function removePolygon(name)
{
    if (polygons[name] == undefined) return;
    polygons[name].setMap(null);
    polygons[name] = null;
}

A la sección cuando el documento está listo:

$('#search_address_button').click(function () {
    var address = $('#search_address_text').val();
    searchAddress(address);
});
$('#search_address_text').click(function (event) {
    var keyDown = (event.keyCode ? event.keyCode : event.which);
    if (keyDown == 13)
        searchAddress();
});
$('.state_address').click(function () {
    var address = $(this).attr('address');
    if (address == "all")
        searchAllAddress();
    else
        searchAddress(address, true);
});

Y en el HTML:

<div id="address_selector">
    <div id="state_selector">
        <a class="state_address" address="california" href="#">California</a>
        <a class="state_address" address="washington" href="#">Washington DC</a>
        <a class="state_address" address="florida" href="#">Florida</a>
        <a class="state_address" address="ny" href="#">New York</a>
        <a class="state_address" address="utah" href="#">Utah</a>
        <a class="state_address" address="la" href="#">Los Angeles</a>
        <a class="state_address" address="default" href="#">Mines</a>
        <a class="state_address" address="all" href="#">All</a>
    </div>
    <div id="search_address">
        <input type="text" name="search_address_text" id="search_address_text"/> <input id="search_address_button" type="button" value="Search"/>
    </div>
</div>

searchResults es un arreglo que van a ver en los fuentes que publique con datos que yo mismo genere para probar.

Acá se me es algo complicado explicar el código, no encuentro como poner el código mejor y lo otro que sucede es que es mucho escribir y no tengo mucho tiempo.

Les colocó los dos archivos para que lo vean con más detenimiento y lo prueben si desean:

Javascript:

http://pastebin.com/mRu5H2kG

HTML:

http://pastebin.com/B3Z4GQNB

Tratando de optimizar el código

Ya casi no tengo mucho tiempo para escribir cosas interesantes :S!

En los siguientes post me gustaria hablar de javascript y Google Maps.

Mi tesis(https://github.com/fedep3/Metaheuriscticas-Data-Clustering) está hecha en C++ y es sobre data clustering  de datos numéricos usando metaheurísticas. Esta enfocada en las imagenes principalmente (las imágenes no son mas que conjuntos de vectores de uno o mas colores).

Actualmente ando investigando y mejorando el código para hacer una poblicacion sobre el algoritmo genético que cree yo con mi companero.

En el código he hecho dos cambios:

  1. Cambiar el generador de numeros aleatorios.
  2. Intentar optimizar la función de la distancia euclideana.

El motivo de l primer cambio era que el generador de numeros aleatorios de C++, es un http://en.wikipedia.org/wiki/Linear_congruential_generator , los cuales son muy eficiente, pero no son tan buenos. Habiendo usado python y ya de hace un tiempo que habia leído del tema decidí colocar el http://en.wikipedia.org/wiki/Mersenne_twister que es de los mejores, por no decir el mejor actualmente. Ahora el reto era buscar que implementecion usar o si hacerla uno mismo. Buscando y probando consegui uno creado por un invetigador de Pixar que hace uso de las instrucciones SSE2 y que es increiblemente eficiente(http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/cpp_sse2.zip).

Al principio no me compilo asi que busqué lo que estaba pasando. Después de como 1 hora de leer y probar di con la solucion. El código hace uso de unos defines o funciones que por lo visto no estan incluidos en el emmintrin.h. Basto con cambiar el código y listo compilo.  Lo arregle para usarlo y la diferencia de tiempo/resultados con lo que tenia antes ni se notaba.

Averiguando todo este, me surgió un interés por esas instrucciones SSE2. Quería ver si podía programar en ellas la distancia euclideana. Encontre una especia de API de ellas (http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011/compiler_c/index.htm#intref_cls/common/intref_sse2_int_load.htm) y leyendo otras cosas(http://fastcpp.blogspot.comhttps://developer.apple.com/hardwaredrivers/ve/sse.html) entendí su funcionamiento. Las intrucciones son capaces(segun leí y entendí) de procesar 4 flotantes a la vez o 2 doubles.

Mi tesis usa floats, asi que programé lo siguiente:

float Metaheuristic::euclideanDistance(float* v1, float* v2)
{
    __m128 sum = _mm_setzero_ps(), square;
    for(register int k = 0; k < M; k+=4){
        square = _mm_sub_ps( _mm_load_ps(v1 + k), _mm_load_ps(v2 +k));
        sum = _mm_add_ps(_mm_mul_ps(square,square), sum);
    }
    sum = _mm_sqrt_ps(sum);
    _mm_store_ps(eDistance, sum);
    return eDistance[0];
}

Surgieron un montón de problemas para lograr que éesto funcionara. El principal fue que los arreglos que usan estas instrucciones deben tener tamaño divisible entre 4, ya que se cargan los 4 flotantes a los registros. Cambie gran parte del codigo para que a la hora de crear los objetos se cumpliera esta condición y probé de no tener leaks o errors en la memoria usando valgrind. Cuando ya no tuve problemas y los resultados de las corridas tenían coherencia, observé los tiempo. Una imagen que me corria antes en 1 – 2 segundos pasó a 10 segundos !

Mi intento por optimizar el codigo fue fallido, pero aprendi algo. Para mi la razón de que no funcionara muy bien es que los arreglo en realidad eran arreglos de tamano 1 o 3 transformados a 4. Más tiempo se perdía en la carga y cálculo que el que ganaba de tener la capacidad de procesar 4 cosas a la vez. Eso que hasta intente tener las cosas aleanadas a 16 bytes y nada ! Por supuesto que es posible que halla hecho algo mal, pero ahora no tengo mucho tiempo para seguir jugando con el código, ando full de otras cosas.

Espero que ésto sea de ayuda

XSRF Django

En la web uno se debe cuidar de tres cosas (y muchas otras, pero de las principales y más comunes para mí) son: inyecciones SQL, XSS y XSRF.

La primera como dice el nombre es simplemente a través de llamadas HTTP ingresar código de SQL (esto puede aplicar a otro tipo de bases de datos No-SQL). La forma más común es a la hora de un formulario por el cual se pasan datos bien sea por POST o GET, colocar valores estílo ‘; comando sql;  por medio del cual se pueden robar valores, dañar la base datos, etc.

Luego tenemos los XSS, siglas de cross-site scripting, lo cual es ingresar código en la página que se ataca. Ejemplo un párametro que se pasa por GET y que se imprime en la página. Con poner en ese parámetro algo estilo < iframe src = “http://paginamaliciosa” > </ iframe >  se logra que otras personas vean lo que uno desee y se puede robar información u otras cosas.

Finalmente tenemos el XSRF, siglas de cross-site request forergy. Éste ataque es más complejo, pero puede hacer mucho daño. Consiste en hacer que un usuario autentificado en una página haga cosas que él no autorizo. Un ejemplo sería el siguiente:

  • Un usuario anda autentificado en X página, la cual hace el cambio de contraseña por POST.
  • Una persona maliciosa simplemente debe recrear ese request de POST y hacer que el usuario lo haga sin darse cuenta.

Yo ya en un post pasado publique un link (http://google-gruyere.appspot.com/) que encontré muy bueno que habla de seguridad de páginas web y que explican de estos ataques y como defenderse.

Hable de todo ésto ya que me topé con lo siguiente:

https://docs.djangoproject.com/en/dev/ref/contrib/csrf/

Cada día me sorprendo más con lo excelente que es este framework, al igual que Python.

De un modo bastante simple previsto por Django se es posible defenderse de éste último tipo de ataque que comente. No soy un experto de en programación web, nunca me ha gustado, pero me pregunto si muchos de los otros frameworks tienen está capacidad.

Fuera del tema, ya empezó el curso de seguridad ofrecido por la universidad de Standford, espero poder dedicarle, ya vi por encima el material que colocaron y se ve full interesante, espero tener el tiempo y las ganas de leerlo, ya veremos!