Sábado 03 de diciembre de 2016

Javier Smaldone

Javier Smaldone
Blog de Javier Smaldone

Propuestas para fortalecer el sistema electoral

El sistema electoral argentino tiene problemas. El Gobierno impulsa una supuesta mejora que en realidad lo debilitará peligrosamente, pudiendo llevarlo a la situación anterior a la Ley Sáenz Peña de 1912. A continuación, una breve —realmente muy breve— propuesta de mejoras reales, para cada una de las etapas que lo componen.

Urnas de votación

Consideraciones generales

La votación

La boleta única de papel es una grilla en la que aparecen todos los cargos electivos y los candidatos o partidos, es decir, la oferta electoral completa. Es entregada al votante en la mesa de votación. Luego, este se dirige a una pequeña casilla o box (que reemplaza al cuarto oscuro) y marca en ella en las opciones que reflejen su preferencia electoral. Finalmente, pliega la boleta y la introduce en la urna.

El siguiente spot publicitario del Gobierno de la Ciudad Autónoma de Buenos Aires del año 2014 (antes de que decidiera la utilización de voto electrónico) ilustra la utilización de la boleta única de papel:

Con respecto al diseño y utilización de la boleta única existen varios aspectos a analizar:

  • Opción de lista completa: puede incluirse o no una opción de “votar por lista completa” al lado de cada partido, logrando mediante la misma el efecto de la llamada “boleta sábana”.
  • Opción de voto en blanco: puede aparecer la opción explícita de “voto en blanco”, o puede considerarse que este está determinado por la ausencia de selección.
  • Múltiples boletas únicas: en caso de elecciones complejas, puede dividirse la selección de cargos en varias boletas —por ejemplo: nacionales, provinciales, municipales— por lo general de distintos colores (como en Italia y en la Provincia de Santa Fe), que luego son colocadas en distintas urnas. Esto posibilitaría, además, el escrutinio de cada urna por separado (e incluso bajo la supervisión de órganos electorales diferentes).
  • Listas de candidatos: en los casos de la elección de listas de múltiples candidatos —típicamente, los cargos legislativos—, puede reducirse el tamaño de la boleta disponiendo de una versión “ampliada” o completa adherida al box de votación, donde el votante pueda leer claramente todos los nombres, e incluyendo en la boleta de votación solamente la identificación partidaria.
  • Control de voto cadena: puede incluirse un sistema de sellos, o un troquel similar al utilizado en la llamada “boleta única electrónica” para evitar la sustracción de boletas y el llamado “voto cadena” o “voto calesita”. Nunca debe utilizarse alguna forma de numeración, ni firmas de los integrantes de la mesa.
  • Elección por parte del votante: puede disponerse que sea el votante quien retira su boleta única de una pila en la mesa de votación, de forma de asegurar que nadie más que él tenga contacto con ella, evitando la posibilidad de marcas que luego la identifiquen.
  • Sistema de marcado: las marcas pueden ser realizadas o bien con un marcador, o bien con un sello y tintas especiales (como en Corea del Sur). Esto dificultaría el agregado de marcas en manipulaciones posteriores como el escrutinio de mesa. También puede utilizarse algún mecanismo como una “película” colocada sobre los casilleros de selección tal que luego de realizada la misma sea retirada e imposibilite la realización de nuevas marcas.

La boleta única de papel es el método de votación más usado en el mundo, en particular por aquellos países que, habiendo probado distintos sistemas electrónicos, los abandonaron. Es un método simple, comprensible y controlable por cualquier persona, y garantiza tanto la oferta electoral (evitando el robo de boletas) como el secreto del voto.

El escrutinio de mesa

Con la boleta única, el único que debe manipular las boletas una vez abierta la urna es el presidente de mesa, quien toma cada una, la exhibe a los fiscales partidarios y realiza el conteo correspondiente. Existen varios métodos para agilizar el conteo, e incluso para producir actas impresas (reduciendo la posibilidad de errores en las transcripciones manuales):

  • Sistema de asistencia electrónica: el presidente de mesa puede llevar el conteo en un dispositivo tipo “tablet”, dotado de una aplicación especialmente diseñada, de forma que al finalizar —y con el acuerdo de los fiscales sobre los totales contabilizados—, sea conectado a una impresora que emita las actas (y copias) correspondientes. Un sistema de este tipo está siendo analizado en la Provincia de Santa Fe. Incluso, el código fuente de la aplicación podría estar disponible para que cualquiera lo use o adapte a sus necesidades y pueda usarlo en la fiscalización.
  • Sistema de conteo electrónico: puede utilizarse un dispositivo lector de marcas, que procese y contabilice cada una de las boletas. En la mayor parte de los EE.UU. las boletas de papel son contabilizados por un sistema de este tipo en el momento de su introducción en la urna (el lector se encuentra en la boca de la misma). Investigadores de la Universidad Nacional de Córdoba han desarrollado un prototipo de lector de muy bajo costo. En el caso de la implementación de estas tecnologías, es fundamental realizar además controles manuales que garanticen la exactitud del resultado.

También debería considerarse la posibilidad de utilizar un presidente de mesa “fresco” para el escrutinio, para reemplazar a quien ha estado controlando el comicio durante todo el día. Es humanamente imposible que una persona esté debidamente concentrada para realizar el conteo, luego de más de 10 horas de trabajo en situación de tensión.

El escrutinio provisorio

La transmisión de datos y el proceso de escrutinio provisorio son la etapa del sistema electoral que menos transparencia muestra hoy de cara a la ciudadanía. Hay varias soluciones que la informática puede aportar:

  • Transmisión de datos: existen formas de usar Internet de forma segura para la carga de datos directamente desde los centros de votación (escuela). De esta forma, el presidente de mesa (junto a los fiscales) puede ser quien supervise este proceso. Investigadores de la Universidad del Comahue han desarrollado un sistema de este tipo.
  • Publicación en tiempo real: los datos de cada una de las mesas deben ser publicados en el mismo instante en que son recibidos desde los centros de votación, sin ninguna demora, verificación ni totalización parcial de funcionarios estatales ni privados.
  • Interfaz de acceso a los datos: los datos publicados deben ser accesibles a través de una interfaz de programación de aplicaciones (API) previamente definida, de modo de facilitar el desarrollo independiente de programas que realicen distintos tipos de controles.

La publicidad del proceso de transmisión y escrutinio provisorio da a la ciudadanía y a los partidos políticos la posibilidad de detectar anomalías de forma temprana, a la vez que desalienta la realización de cualquier forma de adulteración de los resultados.

El escrutinio definitivo (el único resultado legal) debería incluir la publicación de todos los datos, mesa por mesa, tal como fueron considerados finalmente, según la misma interfaz utilizada en el escrutinio provisorio.

Conclusión

Estos son apenas algunos lineamientos para mejorar el sistema electoral argentino. En cada punto existen numerosas posibilidades y matices que pueden —y deben— ser discutidos antes de intentar su implementación. La informática puede aportar mucho a la transparencia, pero no puede —en la actualidad— actuar como intermediaria entre el votante y su voluntad. La propuesta actual del Gobierno argentino (que posiblemente se convierta en ley en los próximos días) no sólo no avanza en el sentido de estas propuestas, sino que retrocede en el camino que los países más desarrollados del mundo han recorrido en materia electoral.

Viernes 02 de diciembre de 2016

Usemos Linux: Cómo hacer que el teclado de Apple funcione correctamente en Ubuntu
Javier Smaldone

Javier Smaldone
Blog de Javier Smaldone

Conferencia sobre voto electrónico en la Ekoparty 12

Al igual que el año pasado, los organizadores de la conferencia de seguridad ekoparty nos dieron un lugar para hablar sobre el voto electrónico, en una especie de actualización de la charla anterior.

Esta es la presentación que utilizamos (con algunas actualizaciones):

Su navegador no soporta iframes.

Luego de la presentación en la ekoparty, seguimos avanzando con el RFID sniffing.

Agradecimientos

Un agradecimiento muy especial al diputado nacional experto en tecnología Marcelo Wechsler por la idea de la “capa de Faraday” que inspiró nuestro vestuario.

Marcelo Wechsler con la capa de Faraday

Jueves 01 de diciembre de 2016

Usemos Linux: Disponible Devuan Jessie Beta2: Debian sin Systemd
Mariano Mendez

Mariano Mendez
[A]NTRAX - [L]ABS

Como Hackear Facebook



Haciendo algunas búsquedas de keywords para mejorar el posicionamiento, me puse a buscar cuales son las búsquedas mas frecuentes. No me sorprendí al ver que una de las mas usadas es como hackear facebook.

Al revisar en Google, me sorprendí la cantidad de resultados que hay y la cantidad de basura con la que me encontré.

En este post expondré realidades y mitos acerca de este tema.

Comenzaré hablando sobre mitos o mentiras que uno suele encontrar en internet. Vi páginas que te hacen dejar el ID del perfil de facebook, luego debes pagar o enviar un sms y te devuelve la contraseña de ese facebook.
Yo creo que es cuestión de razonar al menos un poco. Si fuese tan facil "hackear" un facebook, entonces todos los facebooks ya estarían hackeados. Por lo tanto es MENTIRA que existe tal página o programa que haga este tipo de mágia.

Facebook es una empresa grande, e invierte millones de dolares para mantener la seguridad, por lo que sería bastante tonto pensar que alguien podría tener un programa que saque las passwords solo poniendo su perfil de facebook.

Dicho esto podemos concluir con que no existe un programa mágico o página capaz de hacer esto.

Ahora si expondré alguno de los métodos que se pueden utilizar para sacar credenciales de Facebook, pero no con la finalidad de enseñarlos en detalle, sino para que no caigan en este tipo de amenazas. Claro está que en internet hay muchisima información sobre como hacer todo este tipo de lameradas por si alguien quiere aprender.


Fake webs o Scams

 

Por un lado tenemos las web fake o scams. Para pasar en limpio, son webs replicas a la original, y al colocar nuestras credenciales (mail y contraseña), se quedan con nuestra cuenta. Es decir, en lugar de entrar a facebook.com, ingresamos a faceb00k.com o facebo0k.com. Mucha gente no revisa bien a que sitio está ingresando y llega a un sitio falso. Esto es un claro ejemplo de un scam.

¿Como me doy cuenta si un sitio es real o no?

- Primero que nada de la procedencia del enlace. Si nos llega un mail diciendo: has ganado 1000 dolares, ingresa para obtener más información y dejan un link de facebook enmascarado (Phishing)
- Revisando la URL, ver si tiene https:// en lugar de http://
- Ver si la URL a la cual ingresamos es la URL real o si es una acortada o distinta a la real.


Troyanos

 

Los troyanos son malwares que se utilizan para infectar una PC y poder acceder a los datos de la misma.
Los troyanos tienen funciones como la de un Keylogger, el cual se encarga de capturar todas las teclas presionadas. Entonces cuando la persona infectada ingresa a facebook, el atacante puede ver tanto el mail como la password que escribió.
Para prevenir esto, recomiendo tener siempre el antivirus actualizado y no descargar softwares o ejecutables de sitios poco confiables.
También tengan cuidado con prestar las PC, ya que alguien podría conectar un pendrive con un troyano y de esta forma ejecutar el malware.
Para saber más sobre malwares, recomiendo las revistas de malwares de Underc0de


Stealers

 

Los stealers son otro tipo de malwares, cuya única función es la de robar credenciales almacenadas. (cuando iniciamos sesión en algún sitio y ponemos recordar la contraseña)

A esto simplemente lo evitamos no guardando contraseñas en nuestra computadora.



Correo electrónico

 

Todos sabemos que al poner la opción de "olvidé contraseña" en facebook, nos envía un mail con un link para cambiar la password, por lo que si obtienen el acceso a nuestro correo electrónico, podrían acceder a nuestro facebook.
Para evitar esto, recomiendo tener una buena pregunta de seguridad para que no puedan adivinarla. La forma de hacer esto, es facil. Por ejemplo, si la pregunta es:

-  ¿Nombre de tu primer profesor?

Simplemente respondemos con cualquier otra cosa como "Milanesa", "Argentina", "Futbol", etc. De esta forma no podrán adivinarlo.


Otras medidas a tener en cuenta

 

Mucho cuidado con usar PCs que no sean la nuestra. No sabemos quien estuvo ahí antes, tampoco sabemos si está infectada.


Usemos Linux: Disponible la versión Alpha de Trisquel GNU/Linux 8.0 “Flidas”
Mariano Mendez

Mariano Mendez
[A]NTRAX - [L]ABS

XSS por POST


Hace unos días reportaron un XSS por POST en el formulario de contacto de Underc0de. Por suerte no era nada riesgoso, pero era una vulnerabilidad que debíamos arreglar.
En esta ocasión usaremos el código de ese formulario de contacto para reproducir la falla y para ver como probar si nuestras aplicaciones son vulnerables a los XSS por POST.

El código del formulario de contacto está acá: www.hospedando.com.mx/descargas/formulario.zip por si alguno desea realizar la prueba.

Además, necesitaremos alguna herramienta que modifique los parámetros que enviemos por POST. Yo usare Tamper Data que es un complemento de Firefox:

https://addons.mozilla.org/es/firefox/addon/tamper-data/

Una vez montado el formulario de contacto se vera algo así:



El primer paso será completar todos sus campos y abrie Tamper Data. Una vez hecho esto, damos en "Comenzar Modificación" (En el tamper data) y enviamos el formulario de contacto.
Seguido a esto, nos aparecerá una alerta en Tamper Data para modificar los datos que estamos enviados.


Damos en modificar, y revisamos los valores que está enviando del lado derecho, que son los que hemos cargado desde el formulario.


Ahora es momento de jugar con estos campos. Este formulario de contacto no filtra sus variables, asique colocaremos algún vector de XSS en sus parámetros.
En este caso, coloqué un simple alert en el campo correo.

<script>alert('XSS')</script>

Pero podemos buscar o usar cualquier otro. Al dar en Aceptar, el sitio seguirá cargando con la nueva información suministrada...


Y como podrán apreciar, apareció el Alert con nuestro mensaje.

Espero que les sirva!

Miércoles 23 de noviembre de 2016

Javier Smaldone

Javier Smaldone
Blog de Javier Smaldone

Declaración ante el agravio del diputado Tonelli a especialistas en informática

En los últimos meses diversos especialistas en informática han mostrado al público las múltiples falencias del voto electrónico, explicando por qué es imposible garantizar la ausencia de vulnerabilidades en cualquier software, aún habiendo sido auditado. Entre los expertos que presentaron estos resultados hay reconocidos referentes del mundo de la seguridad informática y científicos del CONICET y diferentes universidades nacionales.

En este marco resulta inaceptable que un Diputado de la Nación, depositario de la facultad de legislar, y por ende obligado a informarse con rigurosidad sobre los temas de los que opina públicamente, manifieste tal grado de ignorancia o malicia al pretender fantasiosos los argumentos que profesionales y científicos aportaron a la discusión relacionada con el uso de los sistemas de voto electrónico y, en particular, de la boleta electrónica (que dicho sea de paso, es una de las formas del voto electrónico). Las demostraciones realizadas en los plenarios de comisiones del Senado ilustran de manera tangible cuestiones técnicas que podrían resultar abstractas a interlocutores externos a la comunidad informática. No obstante, se han explicado los fundamentos y los principios de la propia disciplina que sustentan tales exhibiciones. Entre ellas, las que afectaron al ballotage del año 2015 en la CABA. Allí, nuevamente por falta de información o malicia, el Estado porteño obligó a la población a utilizar un sistema que se probó vulnerable tanto en sede judicial como en las demostraciones antes mencionadas.

Algunas de las presentaciones realizadas en el Congreso de la Nación pueden verse en goo.gl/m1STZV (compromiso del secreto del voto), goo.gl/LvXUq7 (lectura de la boleta con chip a distancia) y goo.gl/P2M2zm (presentación en Diputados).

Reiteramos nuestra voluntad de contribuir constructivamente en esta discusión. Voluntad que no ha caducado y por la que manifestamos nuevamente nuestra disponibilidad para explicar y debatir cuanto sea necesario a fin de aclarar los aspectos técnicos que aún permanezcan oscuros. Esperamos en último término que nuestros representantes puedan tomar una decisión informada que no atente contra la garantía constitucional de secreto del voto ni permita manipulaciones como las que la comunidad informática viene advirtiendo.

Contribuir a evitar tales males nos interesa más que reclamar la debida disculpa ante una ofensa, y por ende invitamos al Diputado Tonelli a debatir este tema de cara a la sociedad en el lugar donde nosotros diariamente generamos conocimiento y lo debatimos: la universidad pública y gratuita.

Firman

Dr. Nazareno Aguirre – Director del Departamento de Computación, Universidad Nacional de Río Cuarto.
Mg. Marcelo Arroyo – Profesor Asociado – Universidad Nacional de Río Cuarto.
Dr. Javier Blanco – Profesor Titular – FAMAF, Universidad Nacional de Córdoba.
Dr. Pablo Castro – Investigador Asistente CONICET – Profesor Universidad Nacional de Río Cuarto.
Dr. Nicolás D’Ippolito – Investigador Asistente CONICET – Profesor Adjunto CONICET – Profesor Adjunto FCEyN, Universidad de Buenos Aires.
Dr. Diego Garberbetsky – Director de Departamento de Computación, FCEyN, Universidad de Buenos Aires.
Tristán Grimaux – Programador.
Dr. Hernán Melgratti – Investigador Adjunto CONICET – Profesor Adjunto FCEyN, Universidad de Buenos Aires.
Dr. Alfredo Ortega – Desarrollador e Investigador de Seguridad.
Juliano Rizzo – Investigador y Consultor de Seguridad Informática.
Lic. Dante Zanarini – Sec. Académico Escuela de Ciencias Exactas y Naturales, Universidad Nacional de Rosario.
Javier Smaldone – Programador y consultor independiente.
Iván Barrera Oro – Programador.
Dr. Sebastián Uchitel – Director del Instituto de Investigación en Ciencias de la Computación, UBA-CONICET.
Dr. Claudio Vaucheret – Decano de la Facultad de Informática, Universidad Nacional del Comahue.
Dr. Nicolás Wolovick – Profesor Adjunto – FAMAF, Universidad Nacional de Córdoba

Original: http://lafhis.dc.uba.ar/users/~dippi/Respuesta_a_Dip_Tonelli.html

Miércoles 02 de noviembre de 2016

Ubuntips: ¿Qué programas funcionan mejor en Linux?
Ubuntips: La tecnología trae el coche sin conductor

Martes 01 de noviembre de 2016

Volviendo a lo básico, POO en Python (parte 4)

Los artículos anteriores sobre Programación Orientada a Objetos los pueden revisar en el enlace.

En este artículo se tocará el tema de la herencia, la encapsulación, el uso de getter, setter y deleter, el uso de método estático y y classmethod.

En el artículo de la parte 3 de POO se explica el uso de @property y @método.setter, falto explicar el deleter que sirve para borrar atributos del objeto.

El @staticmethod se usa cuando no se está usando el argumento self en un método.

El @classmethod define un método que se le pasa entre los argumentos a la clase (por convención se define como cls).

Se creará la clase Punto2D con los siguientes atributos y métodos:

  • Se define al punto como (x,y), la clase Punto2 tiene los atributos privados (estos atributos no se pueden acceder a ellos desde la instancia de la clase, por esa razón se tiene el getter y setter):
    • self.__x
    • self.__y
  • Método __init__ que le asigna los valores inciales a la instancia.
  • getter, setter y deleter de punto.
  • getter, setter y deleter de ValorX y ValorY.
  • Método mover: Asigna nuevo valor a punto.
  • Método reset: Asigna el valor (0,0) al punto. 
  • Método distanciaOtroPunto: Cálcula la distancia con otro punto.



El código de ej12.py se muestra a continuación:



#!/usr/bin/env python3

# -*- coding: utf-8 -*-



from math import sqrt







class Punto2D(object):

    """Representacion de un punto en 2 dimensiones"""

    cont_puntos = 1



    def __init__(self,punto=(0,0)):

        '''constructor del punto'''

        self.__x,self.__y = punto

        Punto2D.cont_puntos += 1



    @property

    def ValorX(self):

        '''Devuelve el valor de X'''

        return self.__x



    @ValorX.setter

    def ValorX(self,x):

        '''Se le asigna un valor  a x por medio de setter'''

        self.__x = x



    @property

    def ValorY(self):

        '''Devuelve el valor de y'''

        return self.__y



    @ValorY.setter

    def ValorY(self,y):

        '''Se le asigna un valor a y por medio del setter'''

        self.__y = y



    @property

    def punto(self):

        """el getter de punto, devuelve el punto"""

        return (self.__x,self.__y)



    @punto.setter

    def punto(self,punto):

        ''''el setter de punto'''

        self.__x,self.__y = punto



    @property

    def cantPuntos(self):

        '''Devuelve la cantidad de puntos creados'''

        return Empleado.cont_puntos



    @punto.deleter

    def punto(self):

        '''deleter de punto'''

        del self.__x

        del self.__y

        cont_puntos = 0



    def mover(self,x,y):

        '''mueve el punto a un nuevo punto'''

        self.__x, self.__y = x,y



    def reset(self):

        '''coloca en el origen al punto'''

        self.mover(0,0)



    def distanciaOtroPunto(self,oPunto):

        '''devuelve la distancia entre el punto original y un punto dado'''

        return sqrt((self.__x - oPunto.punto[0])**2 + (self.__y - oPunto.punto[1])**2 )



    @staticmethod

    def autor(autor):

        '''Se define el autor de la clase'''

        return "El autor de esta clase es: {}".format(autor)



    @classmethod

    def cantidadPuntos(cls,cantidad):

        '''Se cambia la cantidad de puntos'''

        cls.cont_puntos = cantidad



if __name__ == "__main__":

    #Se crea cordenada de la clase Punto2D donde se le pasa (4,6)

    cordenada = Punto2D((4,6))

    #Se muestra el valor del punto.

    print(cordenada.punto)

    #Se asigna por setter un nuevo valor

    cordenada.punto = (10,15)

    #Se muestra el nuevo valor de cordenada

    print(cordenada.punto)

    #Se calcula la distancia con respecto a otro punto.

    print(cordenada.distanciaOtroPunto(Punto2D((100,100))))

    #Se fija el punto en un valor (0,0)

    cordenada.reset()

    #Se muestra el nuevo valor de la cordenada.

    print (cordenada.punto)

    #Se muestra un mensaje pasando el autor de la clase.

    print (cordenada.autor("Ernesto"))

    #Muestra la cantidad de puntos que se han creado.

    print ('Cantidad de puntos : {0}'.format(cordenada.cont_puntos ))

    #Se modifica la cantidad de puntos a 1 por medio de setter.

    Punto2D.cantidadPuntos(1)

    #Se vuelve a mostrar la cantida de puntos.

    print ('Cantidad de puntos : {0}'.format(cordenada.cont_puntos ))

    #Se borra la instancia cordenada.

    del(cordenada)

    #Se intenta mostrar el punto pero va a devolver que no se puede

    try:

        print (cordenada.punto)

    except (NameError):

        print ("No existe el objeto cordenada")





Al ejecutar ej12.py se tiene lo siguiente:

python ej12.py
(4, 6)
(10, 15)
123.794184031
(0, 0)
El autor de esta clase es: Ernesto
Cantidad de puntos : 3
Cantidad de puntos : 1
No existe el objeto cordenada



Ahora se va a crear ej12_3d.py que tendrá la clase Punto3D que hereda de Punto2D.

La clase Punto3D tiene practicamente los mismos métodos, lo único distinto es que ahora maneja un punto con 3 dimensiones, para ello hereda del punto en 2 dimensiones X y Y y maneja Z. 

Así que se sobrecarga los métodos de Punto2D en Punto3D. Para poder acceder al objeto Punto2D se usa super. 

A continuación el código de ej12_3d.py:





#!/usr/bin/env python3


# -*- coding: utf-8 -*-





#Se importa la clase Punto2D de ej12.py


from ej12 import Punto2D


#Se importa raiz cuadrada


from math import sqrt





class Punto3D(Punto2D):


    '''Se define la clase Punto3D'''





    def __init__(self,punto3d):


        '''Método init donde se le asigna x y y a Punto2D por medio de super'''


        super(Punto3D,self).__init__(punto3d[0:-1])


        self.__z = punto3d[-1]





    @property


    def ValorZ(self):


        '''devuelve el valor de z por medio de getter'''


        return self.__z





    @ValorZ.setter


    def ValorZ(self,z):


        '''Se asigna un valor a z por medio de setter'''


        self.__z = z





    @ValorZ.deleter


    def ValorZ(self):


        '''se borra el valor de z por medio de deleter'''


        del (self.__z)





    @property


    def punto(self):


        '''el getter de punto, devuelve el punto'''


        x,y = super(Punto3D,self).punto


        return (x,y,self.ValorZ)





    @punto.setter


    def punto(self,punto3d):


        '''Se le asigna un valor al punto por medio de setter'''


        super(Punto3D,self).mover(punto3d[0],punto3d[1])


        self.__z = punto3d[-1]





    @punto.deleter


    def punto(self):


        '''Se borra el punto por medio de deleter'''


        print ("Punto borrado")


        del Punto2D


        del self.__z





    def mover(self,x,y,z):


        '''Se asigna un nuevo valor al punto''''


        super(Punto3D,self).mover(x,y)


        self.__z = z





    def reset(self):


        '''Se fija el punto como (0,0,0)'''


        super(Punto3D,self).mover(0,0)


        self.__z = 0





    def distanciaOtroPunto(self,oPunto):


        '''devuelve la distancia entre el punto original y un punto dado'''


        x,y = super(Punto3D,self).punto


        z = self.__z


        return sqrt((x - oPunto.punto[0])**2 + (y - oPunto.punto[1])**2 + (z - oPunto.ValorZ) ** 2 )














if __name__ == '__main__':


    #Se crea la instancia Punto3D con el punto.


    punto3d = Punto3D((4,6,4))


    #Se muestra el valor del punto


    print(punto3d.punto)


    #Se asigna un nuevo valor a punto.


    punto3d.punto = (3,3,3)


    #Se muestra dicho valor


    print(punto3d.punto)


    #Se muestra los valores de x,y y z.


    print(punto3d.ValorX)


    print(punto3d.ValorY)


    print(punto3d.ValorZ)


    #Se asigna el valor (0,0,0)


    punto3d.reset()


    #Se muestra su valor.


    print(punto3d.punto)


    #Se calcula la distancia con otro punto.


    print(punto3d.distanciaOtroPunto(Punto3D((15,45,55))))


    #Se borra el punto3d.


    del(punto3d)


    #Se intenta mostrar el valor o devuelve que el objeto no existe.


    try:


        print (punto3d.punto)


    except (NameError):


        print ("No existe el objeto punto3d")






Al ejecutar ej12_3d.py se obtiene lo siguiente:

python ej12_3d.py
(4, 6, 4)
(3, 3, 3)
3
3
3
(0, 0, 0)
72.6291952317
No existe el objeto punto3d



En este artículo se muestra la encapsulación, la herencia y varios métodos.

Los códigos lo pueden encontrar en gitlab tanto para ej12.py como para ej12_3d.py.


Lunes 17 de octubre de 2016

Ubuntips: Las rubias de linux triunfan en youporn

Miércoles 12 de octubre de 2016

API Rest Ful con Flask y MongoDB (Flask-MongoAlchemy y Flask-restful)

 API Rest Ful con Flask y MongoDB (Flask-MongoAlchemy y Flask-restful)


En el artículo anterior se explicó como hacer el API Rest Ful usando HTTP con los métodos GET, POST, PUT y DELETE, sin usar una librería para el Rest Ful. 

En este artículo se usará la librería Flask-RestFul, su documentación la pueden revisar acá

Estructura de archivos y directorios del proyecto


La estructura de archivos y directorios sigue siendo la misma que en el artículo anterior:

tutorial-flask/
├── app
│   └── run.py
├── docker-compose.yml
├── Dockerfile
└── README.md



Archivo Dockerfile y docker-compose.yml


Al archivo Dockerfile se le agrega que se instale flask-restful, a continuación el archivo:





FROM python


WORKDIR /code/





RUN pip3 install --upgrade pip


RUN pip3 install  pymongo


RUN pip3 install Flask


RUN pip3 install Flask-PyMongo


RUN pip3 install Flask-MongoAlchemy


RUN pip3 install Flask-restful








EXPOSE 5000





ADD ./app/* /code/


COPY ./app/* /code/


CMD python run.py




El archivo docker-compose.yml si es el mismo del artículo anterior:




flask-rest1:

  build: .

  ports:

    - "5000:5000"

  volumes:

    - "./app/:/code"

  links:

    - mongo

mongo:

  image: mongo

  ports:

    - "27017:27017"

  volumes:

    - "/srv/data/db:/data/db:rw"





Código de la aplicación


Se usarán los mismos métodos HTTP del artículo anterior (GET,POST,PUT y DELETE), el url para las consultas será /empleados y la forma de pasar argumentos por el url es pasando el nombre del empleado /empleados/<string:nombre>  . 

Se crean dos clases:
  • EmpleadoList: Esta clase no se le pasa argumentos por URL, tiene dos métdos GET y POST:
    • GET: Permite listar los empleados que existen en la base de datos.
    • POST: Permite insertar un empleado a la base de datos pasando un json con los datos.
  • Empleado: que a los métodos se le pasa el nombre de un empleado. Se define los métodos GET, PUT y DELETE:
    • GET: Permite buscar un empleado pasando su nombre, se devuelve un json con sus datos.
    • PUT: Permite actualizar la información de un empleado, pasando su nombre y el json con los datos a modificar, devuelve un jso con todos los empleados.
    • DELETE: Permite borrar un empleado de la base de datos, se le pasa el nombre del empleado, devuelve un json con todos los empleados.


El código de app/run.py se muestra a continunación:





#!/usr/bin/env python





#Se importa Flask, reqest y jsonify


from flask import Flask, request,jsonify, Response





#Se importa MongoAlchemy


from flask_mongoalchemy import MongoAlchemy





#Se importa dumps


from bson.json_util import dumps








#rom flask_restful import Resource, Api


from flask_restful import reqparse, abort, Api, Resource











#Se instancia la clase de Flask, se configura el acceso


#a la base de datos mongodb a empleados


app = Flask(__name__)


app.config['MONGOALCHEMY_DATABASE'] = 'empleados'


app.config['MONGOALCHEMY_CONNECTION_STRING'] = 'mongodb://mongo:27017/empleados'








#Se instancia mongoalchemy pasando la app.


db = MongoAlchemy(app)





#Se asocia el API a la aplicacion


api = Api(app)








#Se crea la clase empleados la cual manejara los documentos.


class empleados(db.Document):


    nombre = db.StringField()


    sexo = db.StringField()


    edad = db.IntField()


    dni = db.IntField()














#Se define la funcion de pagina no encontrada.


@app.errorhandler(404)


def not_found(error=None):


    mensaje = {


            'status': 404,


            'message': 'Not Found: ' + request.url,


    }


    resp = Response(jsonify(mensaje),status=404,mimetype='application/json')





    return resp





#Clase EmpleadosList que permite listar los empleados o insertar un empledo.


#Se definen los metdos get y post


class EmpleadosList(Resource):


    #Se define el metodo get el cual devuelve un json con todos los empleados.


    def get(self):


        #Se realiza la busqueda y se devuelve el resultado, si existe un error de atributo (que el empleado no existe)


        #Se devuelve empleado no encontrado.


        try:


            consulta = empleados.query.all()


            resultado = []


            for i in consulta:


                resultado.append(i.wrap())


            resp =  Response(dumps(resultado),status=200,mimetype='application/json')


            resp.headers['Link'] = 'http://blog.crespo.org.ve'


            return resp


        except (AttributeError):


            return not_found





    #Se define el metodo post para agregar un empleado por medio de un json a la


    #base de datos mongoDB.


    def post(self):


        #args = parser.parse_args()


        #Se crea la instancia empleado de la clase empleados donde se


        #logra hacer la inserción de un empleado con el metodo save.





        nombre = str(request.json['nombre'])


        sexo = str(request.json['sexo'])


        edad = int(request.json['edad'])


        dni = int(request.json['dni'])


        empleado = empleados(nombre=nombre,sexo=sexo,edad=edad,dni=dni)


        empleado.save()





        #Se retorna que el usuario fue agregado.


        ###


        consulta = empleados.query.all()


        listado = []


        for i in consulta:


            listado.append(i.wrap())


        resp =  Response(dumps(listado),status=201,mimetype='application/json')


        resp.headers['Link'] = 'http://blog.crespo.org.ve'


        return resp





#Se crea la Clase Empleado que hereda de Resource


#Tiene los metodos get, put y delete


class Empleado(Resource):


    #Se define el metodo get, permite buscar un empleado por su nombre


    def get(self,nombre):


        #Se realiza la busqueda y se devuelve el resultado, si existe un error de atributo (que el empleado no existe)


        #Se devuelve empleado no encontrado.


        try:


            resultado = empleados.query.filter(empleados.nombre == nombre).first()


            return dumps({'nombre':resultado.nombre,'sexo':resultado.sexo,'edad':resultado.edad,'dni':resultado.dni}),200,{'Content-Type':'application/json'}


        except (AttributeError):


            return not_found








    #Se define el metodo put que permite actualizar la informacion de un empleado


    #pasando su nombre, los datos a modificar se pasan en un json.


    def put(self,nombre):


        #Se intenta buscar al empleado en la base de datos, si no esta devuelve error


        try:


            #Se consulta en la base de datos, donde devuelve el primer elemento encontrado


            resultado = empleados.query.filter(empleados.nombre == nombre).first()


            #Se toma los datos de un json y se guardan en sus variables, salvando luego


            #en la base de datos.


            resultado.sexo = str(request.json['sexo'])


            resultado.edad = int(request.json['edad'])


            resultado.dni = int(request.json['dni'])


            resultado.save()


            #Se realiza la consulta desplegando los empleados


            consulta = empleados.query.all()


            listado = []


            for i in consulta:


                listado.append(i.wrap())


            #Se devuelve la nueva lista de empleados en un json.


            resp =  Response(dumps(listado),status=201,mimetype='application/json')


            resp.headers['Link'] = 'http://blog.crespo.org.ve'


            return resp


        except (AttributeError):


            return not_found





    #Se define el metodo delete que permite borrar un empleado de la base de datos


    #pasando el nombre del empleado.


    def delete(self,nombre):


        #Se busca el empleado, si existe se borra de la base de datos y se devuelve


        #mensaje de empleado borrado, si no, se devuelve el mensaje de empleado no


        #encontrado.


        try:


            resultado = empleados.query.filter(empleados.nombre == nombre).first()


            resultado.remove()


            ###


            consulta = empleados.query.all()


            listado = []


            for i in consulta:


                listado.append(i.wrap())


            resp =  Response(dumps(listado),status=200,mimetype='application/json')


            resp.headers['Link'] = 'http://blog.crespo.org.ve'


            return resp


        except (AttributeError):


            return not_found








#Se define las rutas para los recursos con las clases asociadas:


#/empleado


#/empleado/<string:nombre>


api.add_resource(EmpleadosList,'/empleado')


api.add_resource(Empleado,'/empleado/<string:nombre>')














if __name__ == "__main__":


    #Se corre la aplicacion en modo debug


    app.run(host="0.0.0.0",debug=True)







Construcción de la imagen y ejecución del contenedor


Construcción de la imagen Docker:

docker-compose build


Ejecución del contenedor Docker:

docker-compose up


Prueba del API Rest Ful

Se usará postman para consultar al API.

Listar todos los empleados

Se abre postman en el url http://localhost:5000/empleado con método GET, a continuación se muestra una captura de pantalla:


El JSON que se devuelve es el siguiente:

[{"edad": 29, "sexo": "Femenino", "nombre": "Jane Doe", "dni": 8, "_id": {"$oid": "57ebbce45fd2bbeffc51330b"}}, {"edad": 39, "sexo": "Masculino", "nombre": "John Doe", "dni": 7, "_id": {"$oid": "57ebbd195fd2bbeffc51330c"}}, {"edad": 55, "sexo": "Masculino", "nombre": "Pedro Perez", "dni": 6, "_id": {"$oid": "57ebbd505fd2bbeffc51330d"}}, {"edad": 65, "sexo": "Femenino", "nombre": "Petra", "dni": 5, "_id": {"$oid": "57ebbd6b5fd2bbeffc51330e"}}, {"edad": 18, "sexo": "Masculino", "nombre": "Luis Gonzalez", "dni": 4, "_id": {"$oid": "57ebc34d5fd2bbeffc51330f"}}, {"edad": 34, "sexo": "Femenino", "nombre": "Luissana", "dni": 2, "_id": {"$oid": "57ebc3935fd2bbeffc513311"}}, {"edad": 42, "sexo": "Masculino", "nombre": "Neg", "dni": 1, "_id": {"$oid": "57ebc4b85fd2bbeffc513312"}}, {"edad": 29, "sexo": "Femenino", "nombre": "Dayana", "dni": 1050, "_id": {"$oid": "57f64d7d557e3f00086651e8"}}]

Agregar un empleado


Se abre postman en el URL http://localhost:5000/empleado con método POST y se pasa el siguiente JSON:

{
"nombre": "Nadir",
"sexo": "Masculino",
"edad": 45,
"dni": 11059
}



A continuación se muestra la captura de pantalla de la colocación de los datos:


Al ejecutar la acción se tiene el siguiente resueltado (como lo muestra la siguiente captura de pantalla):



El JSON que se devuelve es el siguiente:

[{"edad": 29, "sexo": "Femenino", "nombre": "Jane Doe", "dni": 8, "_id": {"$oid": "57ebbce45fd2bbeffc51330b"}}, {"edad": 39, "sexo": "Masculino", "nombre": "John Doe", "dni": 7, "_id": {"$oid": "57ebbd195fd2bbeffc51330c"}}, {"edad": 55, "sexo": "Masculino", "nombre": "Pedro Perez", "dni": 6, "_id": {"$oid": "57ebbd505fd2bbeffc51330d"}}, {"edad": 65, "sexo": "Femenino", "nombre": "Petra", "dni": 5, "_id": {"$oid": "57ebbd6b5fd2bbeffc51330e"}}, {"edad": 18, "sexo": "Masculino", "nombre": "Luis Gonzalez", "dni": 4, "_id": {"$oid": "57ebc34d5fd2bbeffc51330f"}}, {"edad": 34, "sexo": "Femenino", "nombre": "Luissana", "dni": 2, "_id": {"$oid": "57ebc3935fd2bbeffc513311"}}, {"edad": 42, "sexo": "Masculino", "nombre": "Neg", "dni": 1, "_id": {"$oid": "57ebc4b85fd2bbeffc513312"}}, {"edad": 29, "sexo": "Femenino", "nombre": "Dayana", "dni": 1050, "_id": {"$oid": "57f64d7d557e3f00086651e8"}}, {"edad": 45, "sexo": "Masculino", "nombre": "Nadir", "dni": 11059, "_id": {"$oid": "57fe2800d76747000b2ef40f"}}]


Buscar un empleado

Para buscar un empleado se pasa el siguiente URL http://localhost:5000/empleado/Nadir con método GET al postman, a continuación se muestra una captura de pantalla del resultado:


El JSON que devuelve es el siguiente:

"{\"edad\": 45, \"sexo\": \"Masculino\", \"nombre\": \"Nadir\", \"dni\": 11059}"


Actualizar empleado


Para actualizar al empleado Nadir se pasará el siguiente url a postman http://localhost:5000/empleado/Nadir con método PUT, y se pasará el siguiente json:

{
"sexo": "Masculino",
"edad": 35,
"dni": 11059
}

La captura de pantalla muestra los datos que se cargaron a postman:







Al ejecutar la acción se tiene la siguiente captura de pantalla:



El JSON que devuelve es el siguiente:

[{"edad": 29, "sexo": "Femenino", "nombre": "Jane Doe", "dni": 8, "_id": {"$oid": "57ebbce45fd2bbeffc51330b"}}, {"edad": 39, "sexo": "Masculino", "nombre": "John Doe", "dni": 7, "_id": {"$oid": "57ebbd195fd2bbeffc51330c"}}, {"edad": 55, "sexo": "Masculino", "nombre": "Pedro Perez", "dni": 6, "_id": {"$oid": "57ebbd505fd2bbeffc51330d"}}, {"edad": 65, "sexo": "Femenino", "nombre": "Petra", "dni": 5, "_id": {"$oid": "57ebbd6b5fd2bbeffc51330e"}}, {"edad": 18, "sexo": "Masculino", "nombre": "Luis Gonzalez", "dni": 4, "_id": {"$oid": "57ebc34d5fd2bbeffc51330f"}}, {"edad": 34, "sexo": "Femenino", "nombre": "Luissana", "dni": 2, "_id": {"$oid": "57ebc3935fd2bbeffc513311"}}, {"edad": 42, "sexo": "Masculino", "nombre": "Neg", "dni": 1, "_id": {"$oid": "57ebc4b85fd2bbeffc513312"}}, {"edad": 29, "sexo": "Femenino", "nombre": "Dayana", "dni": 1050, "_id": {"$oid": "57f64d7d557e3f00086651e8"}}, {"edad": 35, "sexo": "Masculino", "nombre": "Nadir", "dni": 11059, "_id": {"$oid": "57fe2800d76747000b2ef40f"}}]

Como se puede notar los datos del empleado Nadir en lo que respecta a su edad ha cambiado.

Borrar empleado

Para terminar se borrará el empleado Nadir de la base de datos, se pasa el url http://localhost/empleado/Nadir con método DELETE, a continuación se muestra el resultado en el postman:


El JSON que devuelve es el siguiente:

[{"edad": 29, "sexo": "Femenino", "nombre": "Jane Doe", "dni": 8, "_id": {"$oid": "57ebbce45fd2bbeffc51330b"}}, {"edad": 39, "sexo": "Masculino", "nombre": "John Doe", "dni": 7, "_id": {"$oid": "57ebbd195fd2bbeffc51330c"}}, {"edad": 55, "sexo": "Masculino", "nombre": "Pedro Perez", "dni": 6, "_id": {"$oid": "57ebbd505fd2bbeffc51330d"}}, {"edad": 65, "sexo": "Femenino", "nombre": "Petra", "dni": 5, "_id": {"$oid": "57ebbd6b5fd2bbeffc51330e"}}, {"edad": 18, "sexo": "Masculino", "nombre": "Luis Gonzalez", "dni": 4, "_id": {"$oid": "57ebc34d5fd2bbeffc51330f"}}, {"edad": 34, "sexo": "Femenino", "nombre": "Luissana", "dni": 2, "_id": {"$oid": "57ebc3935fd2bbeffc513311"}}, {"edad": 42, "sexo": "Masculino", "nombre": "Neg", "dni": 1, "_id": {"$oid": "57ebc4b85fd2bbeffc513312"}}, {"edad": 29, "sexo": "Femenino", "nombre": "Dayana", "dni": 1050, "_id": {"$oid": "57f64d7d557e3f00086651e8"}}]

Como se puede ver el empleado Nadir ya no existe en la base de datos.


Para terminar se muestra la captura de pantalla del contenedor ejecutandose:



Se mantiene resaltado la salida de la ejecución de Flask ( a continuación se muestra el texto):

flask-rest1_1 | 172.17.0.1 - - [12/Oct/2016 12:02:56] "GET /empleado HTTP/1.1" 200 -
mongo_1       | 2016-10-12T12:09:37.175+0000 I COMMAND  [conn2] update empleados.empleados query: { _id: ObjectId('57fe2800d76747000b2ef40f') } update: { _id: ObjectId('57fe2800d76747000b2ef40f'), edad: 45, sexo: "Masculino", nombre: "Nadir", dni: 11059 } keysExamined:0 docsExamined:0 nMatched:1 nModified:1 upsert:1 keyUpdates:0 writeConflicts:0 numYields:1 locks:{ Global: { acquireCount: { r: 2, w: 2 } }, Database: { acquireCount: { w: 2 } }, Collection: { acquireCount: { w: 2 } } } 326ms
flask-rest1_1 | 172.17.0.1 - - [12/Oct/2016 12:09:37] "POST /empleado HTTP/1.1" 201 -
flask-rest1_1 | 172.17.0.1 - - [12/Oct/2016 12:12:40] "GET /empleado/Nadir HTTP/1.1" 200 -
flask-rest1_1 | 172.17.0.1 - - [12/Oct/2016 12:18:23] "POST /empleado/Nadir HTTP/1.1" 405 -
mongo_1       | 2016-10-12T12:20:00.777+0000 I COMMAND  [conn2] update empleados.empleados query: { _id: ObjectId('57fe2800d76747000b2ef40f') } update: { _id: ObjectId('57fe2800d76747000b2ef40f'), edad: 35, sexo: "Masculino", nombre: "Nadir", dni: 11059 } keysExamined:1 docsExamined:1 nMatched:1 nModified:1 keyUpdates:0 writeConflicts:0 numYields:2 locks:{ Global: { acquireCount: { r: 3, w: 3 } }, Database: { acquireCount: { w: 3 } }, Collection: { acquireCount: { w: 3 } } } 124ms
flask-rest1_1 | 172.17.0.1 - - [12/Oct/2016 12:20:00] "PUT /empleado/Nadir HTTP/1.1" 201 -
flask-rest1_1 | 172.17.0.1 - - [12/Oct/2016 12:23:19] "DELETE /empleado/Nadir HTTP/1.1" 200 -



Con esto se ha mejorado la forma de como crear un API Rest, en este caso usando flask-restful. 

El repositorio del proyecto se encuentra en el repositorio gitlab tutorial-flask en la rama mongo-flask-restful.


Jueves 06 de octubre de 2016

API Rest Ful con Flask y MongoDB (Flask-MongoAlchemy)

API Rest Ful con Flask y MongoDB (Flask-MongoAlchemy)

En artículo anterior se hizo un CRUD para Flask con MongoDB usando Mongo-Alchemy, en dicho artículo se manejaron varios URL para hacer el CRUD.

En este artículo se manejará el REST por medio de los URL y con Flask solamente, en próximos artículos se usará Flask-RESTful y Flask-Restless.

Métodos de HTTP 

En este caso se va a estandarizar el CRUD por medio de API Rest Ful, donde se usará el mismo URL con métodos GET, POST, PUT y DELETE.

Los métodos se usarán de la siguiente forma:

  • Agregar Empleado: Método POST, URL /empleado, sin parámetros.
  • Buscar Empleado: Método  GET, URL /empleado, parámetro <string:nombre>.
  • Listar Empleados: Método GET, URL /empleado. 
  • Editar/Actualizar Empleado: Método PUT, URL /empleado, parámetro <string:nombre>.
  • Borrar Empleado: Método DELETE, URL /empleado, parámetro <string:nombre>.


Como puede notarse, con un sólo URL se tiene las acciones del CRUD usando los métodos de HTTP, esto permite estándarizar y simplificar el uso de los URL, y principalmente hacer un correcto uso de HTTP:

Para más información sobre el estilo arquitectónico API REST pueden revisar en wikipedia.

Estructura de directorios y archivos

Se mantiene la misma estructura de archivos y directorios del artículo sobre CRUD:

tutorial-flask
├── app
│   └── run.py
├── docker-compose.yml
├── Dockerfile
└── README.md




Archivo Dockerfile y docker-compose.yml


El archivo Docker contiene lo siguiente:




FROM python


WORKDIR /code/





RUN pip3 install --upgrade pip


RUN pip3 install  pymongo


RUN pip3 install Flask


RUN pip3 install Flask-PyMongo


RUN pip3 install Flask-MongoAlchemy








EXPOSE 5000





ADD ./app/* /code/


COPY ./app/* /code/


CMD python run.py






El archivo docker-compose.yml contiene lo siguiente:


flask-rest1:

  build: .

  ports:

    - "5000:5000"

  volumes:

    - "./app/:/code"

  links:

    - mongo

mongo:

  image: mongo

  ports:

    - "27017:27017"

  volumes:

    - "/srv/data/db:/data/db:rw"



Codigo de la aplicación


El código de run.py se muestra a continuación:




#!/usr/bin/env python






#Se importa Flask, reqest y jsonify


from flask import Flask, request,jsonify





#Se importa MongoAlchemy


from flask_mongoalchemy import MongoAlchemy





#Se importa dumps


from bson.json_util import dumps








#Se instancia la clase de Flask, se configura el acceso


#a la base de datos mongodb a empleados


app = Flask(__name__)


app.config['MONGOALCHEMY_DATABASE'] = 'empleados'


app.config['MONGOALCHEMY_CONNECTION_STRING'] = 'mongodb://mongo:27017/empleados'





#Se instancia mongoalchemy pasando la app.


db = MongoAlchemy(app)





#Se crea la clase empleados la cual manejara los documentos.


class empleados(db.Document):


    nombre = db.StringField()


    sexo = db.StringField()


    edad = db.IntField()


    dni = db.IntField()








#Se define la funcion agregar con metodo get


@app.route('/empleado',methods=['POST'])


def agregar():


    #Se crea la instancia empleado de la clase empleados donde se


    #logra hacer la inserción de un empleado con el metodo save.


    nombre = str(request.json['nombre'])


    sexo = str(request.json['sexo'])


    edad = int(request.json['edad'])


    dni = int(request.json['dni'])


    empleado = empleados(nombre=nombre,sexo=sexo,edad=edad,dni=dni)


    empleado.save()





    #Se retorna que el usuario fue agregado.


    ###


    consulta = empleados.query.all()


    listado = []


    for i in consulta:


        listado.append(i.wrap())


    return dumps(listado)








#Se crea la funcion buscar con metodo get.


@app.route('/empleado/<string:nombre>',methods=['GET'])


def buscar(nombre):


    #Se realiza la busqueda y se devuelve el resultado, si existe un error de atributo (que el empleado no existe)


    #Se devuelve empleado no encontrado.


    try:


        resultado = empleados.query.filter(empleados.nombre == nombre).first()


        return dumps({'resultado':{'nombre':resultado.nombre,'sexo':resultado.sexo,'edad':resultado.edad,'dni':resultado.dni}})


    except (AttributeError):


        return dumps({'resultado': 'Empleado no encontrado'})








@app.route('/empleado',methods=['GET'])


def listar():


    #Se realiza la busqueda y se devuelve el resultado, si existe un error de atributo (que el empleado no existe)


    #Se devuelve empleado no encontrado.


    try:


        consulta = empleados.query.all()


        resultado = []


        for i in consulta:


            resultado.append(i.wrap())


        return dumps(resultado)


    except (AttributeError):


        return dumps({'resultado': 'Empleado no encontrado'})





#Se crea la funcion actualizar que tiene metodo put, con


#url /empleado y se le pasa el nombre a buscar


@app.route('/empleado/<string:nombre>',methods=['PUT'])


def actualizar(nombre):


    #Se intenta buscar al empleado en la base de datos, si no esta devuelve error


    try:


        #Se consulta en la base de datos, donde devuelve el primer elemento encontrado


        resultado = empleados.query.filter(empleados.nombre == nombre).first()


        #Se toma los datos de un json y se guardan en sus variables, salvando luego


        #en la base de datos.


        resultado.sexo = str(request.json['sexo'])


        resulado.edad = int(request.json['edad'])


        resultado.dni = int(request.json['dni'])


        resultado.save()


        #Se realiza la consulta desplegando los empleados


        consulta = empleados.query.all()


        listado = []


        for i in consulta:


            listado.append(i.wrap())


        #Se devuelve la nueva lista de empleados en un json.


        return dumps(listado)


    except (AttributeError):


        return dumps({'resultado': 'Empleado no encontrado'})





#Borrar un empleado de la base de datos, se pasa el url /empleado con el


#string nombre usando el metodo delete.


@app.route('/empleado/<string:nombre>',methods=['DELETE'])


def borrar(nombre):


    #Se busca el empleado, si existe se borra de la base de datos y se devuelve


    #mensaje de empleado borrado, si no, se devuelve el mensaje de empleado no


    #encontrado.


    try:


        resultado = empleados.query.filter(empleados.nombre == nombre).first()


        resultado.remove()


        ###


        consulta = empleados.query.all()


        listado = []


        for i in consulta:


            listado.append(i.wrap())


        return dumps(listado)


    except (AttributeError):


        return dumps({'resultado':'Empleado no encontrado'})











if __name__ == "__main__":


    #Se corre la aplicacion en modo debug


    app.run(host="0.0.0.0",debug=True)




Construcción de la imagen y ejecución del contenedor


Construcción de la imagen Docker:

docker-compose build


Ejecución del contenedor:

docker-compose up



Pruebas del API REST FUL


Para este caso se usará POSTMAN, una aplicación para google chrome.

Listar Empleados


Se usa postman colocando 127.0.0.1:5000/empleados con método GET, en la siguiente figura se muestra el listado:


El JSON que devuelve es el siguiente:

[{"edad": 29, "dni": 8, "sexo": "Femenino", "nombre": "Jane Doe", "_id": {"$oid": "57ebbce45fd2bbeffc51330b"}}, {"edad": 39, "dni": 7, "sexo": "Masculino", "nombre": "John Doe", "_id": {"$oid": "57ebbd195fd2bbeffc51330c"}}, {"edad": 55, "dni": 6, "sexo": "Masculino", "nombre": "Pedro Perez", "_id": {"$oid": "57ebbd505fd2bbeffc51330d"}}, {"edad": 65, "dni": 5, "sexo": "Femenino", "nombre": "Petra", "_id": {"$oid": "57ebbd6b5fd2bbeffc51330e"}}, {"edad": 18, "dni": 4, "sexo": "Masculino", "nombre": "Luis Gonzalez", "_id": {"$oid": "57ebc34d5fd2bbeffc51330f"}}, {"edad": 34, "dni": 2, "sexo": "Femenino", "nombre": "Luissana", "_id": {"$oid": "57ebc3935fd2bbeffc513311"}}, {"edad": 43, "dni": 1, "sexo": "Masculino", "nombre": "Neg", "_id": {"$oid": "57ebc4b85fd2bbeffc513312"}}, {"edad": 29, "dni": 1050, "sexo": "Femenino", "nombre": "Dayana", "_id": {"$oid": "57f64d7d557e3f00086651e8"}}]

Buscar un Empleado

En el postman se coloca el siguiente url con método GET 127.0.0.1/empleado/Neg , la siguiente figura muestra el resultado:


EL JSON que devuelve es el siguiente:

{"resultado": {"edad": 43, "dni": 1, "sexo": "Masculino", "nombre": "Neg"}}


Agregar Empleado

En postman se agrega el url con método POST 127.0.0.1:5000/empleado y se pasa en formato JSON lo siguiente:

{
"nombre": "Fatima",
"sexo": "Femenino",
"edad": 24,
"dni": 1052
}

La siguiente figura muestra la captura de la información que se coloca en postman:



Esto devuelve el siguiente JSON:

[{"edad": 29, "dni": 8, "sexo": "Femenino", "nombre": "Jane Doe", "_id": {"$oid": "57ebbce45fd2bbeffc51330b"}}, {"edad": 39, "dni": 7, "sexo": "Masculino", "nombre": "John Doe", "_id": {"$oid": "57ebbd195fd2bbeffc51330c"}}, {"edad": 55, "dni": 6, "sexo": "Masculino", "nombre": "Pedro Perez", "_id": {"$oid": "57ebbd505fd2bbeffc51330d"}}, {"edad": 65, "dni": 5, "sexo": "Femenino", "nombre": "Petra", "_id": {"$oid": "57ebbd6b5fd2bbeffc51330e"}}, {"edad": 18, "dni": 4, "sexo": "Masculino", "nombre": "Luis Gonzalez", "_id": {"$oid": "57ebc34d5fd2bbeffc51330f"}}, {"edad": 34, "dni": 2, "sexo": "Femenino", "nombre": "Luissana", "_id": {"$oid": "57ebc3935fd2bbeffc513311"}}, {"edad": 43, "dni": 1, "sexo": "Masculino", "nombre": "Neg", "_id": {"$oid": "57ebc4b85fd2bbeffc513312"}}, {"edad": 29, "dni": 1050, "sexo": "Femenino", "nombre": "Dayana", "_id": {"$oid": "57f64d7d557e3f00086651e8"}}, {"edad": 24, "dni": 1052, "sexo": "Femenino", "nombre": "Fatima", "_id": {"$oid": "57f68505557e3f000e1aa766"}}]

Como se nota el empleado Fátima aparece en la base de datos al final.

Borrar Empleado

Para este caso se buscará borrar al empleado Fátima, se coloca el siguiente url en postman con método DELETE: 127.0.0.1:5000/empleado/Fatima .

La siguiente imagen muestra la ejecución en postman:



Esto devuelve el siguiente JSON:

[{"edad": 29, "dni": 8, "sexo": "Femenino", "nombre": "Jane Doe", "_id": {"$oid": "57ebbce45fd2bbeffc51330b"}}, {"edad": 39, "dni": 7, "sexo": "Masculino", "nombre": "John Doe", "_id": {"$oid": "57ebbd195fd2bbeffc51330c"}}, {"edad": 55, "dni": 6, "sexo": "Masculino", "nombre": "Pedro Perez", "_id": {"$oid": "57ebbd505fd2bbeffc51330d"}}, {"edad": 65, "dni": 5, "sexo": "Femenino", "nombre": "Petra", "_id": {"$oid": "57ebbd6b5fd2bbeffc51330e"}}, {"edad": 18, "dni": 4, "sexo": "Masculino", "nombre": "Luis Gonzalez", "_id": {"$oid": "57ebc34d5fd2bbeffc51330f"}}, {"edad": 34, "dni": 2, "sexo": "Femenino", "nombre": "Luissana", "_id": {"$oid": "57ebc3935fd2bbeffc513311"}}, {"edad": 43, "dni": 1, "sexo": "Masculino", "nombre": "Neg", "_id": {"$oid": "57ebc4b85fd2bbeffc513312"}}, {"edad": 29, "dni": 1050, "sexo": "Femenino", "nombre": "Dayana", "_id": {"$oid": "57f64d7d557e3f00086651e8"}}]

Modificar empleado

Para este caso se modificará el empleado Neg, cambiando su edad.

Se abre el postman colocando el url 127.0.0.1:5000/empleado/Neg con método PUT. Adicional se agrega el JSON:

{
"sexo": "Masculino",
"edad": 41,
"dni": 1
}

La siguiente imagen muestra el postman:




Esto devuelve el siguiente JSON:
[{"sexo": "Femenino", "_id": {"$oid": "57ebbce45fd2bbeffc51330b"}, "nombre": "Jane Doe", "dni": 8, "edad": 29}, {"sexo": "Masculino", "_id": {"$oid": "57ebbd195fd2bbeffc51330c"}, "nombre": "John Doe", "dni": 7, "edad": 39}, {"sexo": "Masculino", "_id": {"$oid": "57ebbd505fd2bbeffc51330d"}, "nombre": "Pedro Perez", "dni": 6, "edad": 55}, {"sexo": "Femenino", "_id": {"$oid": "57ebbd6b5fd2bbeffc51330e"}, "nombre": "Petra", "dni": 5, "edad": 65}, {"sexo": "Masculino", "_id": {"$oid": "57ebc34d5fd2bbeffc51330f"}, "nombre": "Luis Gonzalez", "dni": 4, "edad": 18}, {"sexo": "Femenino", "_id": {"$oid": "57ebc3935fd2bbeffc513311"}, "nombre": "Luissana", "dni": 2, "edad": 34}, {"sexo": "Masculino", "_id": {"$oid": "57ebc4b85fd2bbeffc513312"}, "nombre": "Neg", "dni": 1, "edad": 41}, {"sexo": "Femenino", "_id": {"$oid": "57f64d7d557e3f00086651e8"}, "nombre": "Dayana", "dni": 1050, "edad": 29}]


Se muestra en subrayado el empleado Neg que cambió su edad en la base de datos.

Para terminar, ahora se muestra la salida del servidor:

flask-rest1_1 | 172.17.0.1 - - [06/Oct/2016 15:59:33] "GET /empleado HTTP/1.1" 200 -
flask-rest1_1 | 172.17.0.1 - - [06/Oct/2016 16:03:48] "GET /empleado/Neg HTTP/1.1" 200 -
flask-rest1_1 | 172.17.0.1 - - [06/Oct/2016 17:08:22] "POST /empleado HTTP/1.1" 200 -
flask-rest1_1 | 172.17.0.1 - - [06/Oct/2016 17:39:24] "DELETE /empleado/Fatima HTTP/1.1" 200 -
flask-rest1_1 | 172.17.0.1 - - [06/Oct/2016 17:47:59] "PUT /empleado/Neg HTTP/1.1" 200 -


Como se ve, la salida devuelve el URL que se usa y los métodos utilizados.

De esta manera se muestra el uso del estilo arquitectónico API REST y el uso de HTTP con sus diferentes métodos. 

El código fuente de este artículo se encuentra en el repositorio tutorial-flask de gitlab en la rama mongo-restful.

Sábado 01 de octubre de 2016

David Moreno

David Moreno
dm's blog

Thanks Debian

I sent this email to debian-private a few days ago, on the 10th anniversary of my Debian account creation:

Date: Fri, 14 Aug 2015 19:37:20 +0200
From: David Moreno 
To: debian-private@lists.debian.org
Subject: Retiring from Debian
User-Agent: Mutt/1.5.23 (2014-03-12)

[-- PGP output follows (current time: Sun 23 Aug 2015 06:18:36 PM CEST) --]
gpg: Signature made Fri 14 Aug 2015 07:37:20 PM CEST using RSA key ID 4DADEC2F
gpg: Good signature from "David Moreno "
gpg:                 aka "David Moreno "
gpg:                 aka "David Moreno (1984-08-08) "
[-- End of PGP output --]

[-- The following data is signed --]

Hi,

Ten years ago today (2005-08-14) my account was created:

https://nm.debian.org/public/person/damog

Today, I don't feel like Debian represents me and neither do I represent the
project anymore.

I had tried over the last couple of years to retake my involvement but lack of
motivation and time always got on the way, so the right thing to do for me is
to officially retire and gtfo.

I certainly learned a bunch from dozens of Debian people over these many years,
and I'm nothing but grateful with all of them; I will for sure carry the project
close to my heart — as I carry it with the Debian swirl I still have tattooed
on my back ;)

http://damog.net/blog/2005/06/29/debian-tattoo/

I have three packages left that have not been updated in forever and you can
consider orphaned now: gcolor2, libperl6-say-perl and libxml-treepp-perl.

With all best wishes,
David Moreno.
http://damog.net/


[-- End of signed data --]

I received a couple of questions about my decision here. I basically don’t feel like Debian represents my interests and neither do I represent the project – this doesn’t mean I don’t believe in free software, to the contrary. I think some of the best software advancements we’ve made as society are thanks to it. I don’t necessarily believe on how the project has evolved itself, whether that has been the right way, to regain relevancy and dominance, and if it’s remained primarily a way to feed dogmatism versus pragmatism. This is the perfect example of a tragic consequence. I was very happy to learn that the current Debian Conference being held in Germany got the highest attendance ever, hopefully that can be utilized in a significant and useful way.

Regardless, my contributions to Debian were never noteworthy so it’s also not that big of a deal. I just need to close cycles myself and move forward, and the ten year anniversary looked like a significant mark for that.

Poke me in case you wanna discuss some more. I’ll always be happy to. Specially over beer :)

Peace.

Lunes 29 de agosto de 2016

David Moreno

David Moreno
dm's blog

Webhook Setup with Facebook::Messenger::Bot

The documentation for the Facebook Messenger API points out how to setup your initial bot webhook. I just committed a quick patch that would make it very easy to setup a quick script to get it done using the unreleased and still in progress Perl’s Facebook::Messenger::Bot:

use Facebook::Messenger::Bot;

use constant VERIFY_TOKEN => 'imsosecret';

my $bot = Facebook::Messenger::Bot->new(); # no config specified!
$bot->expect_verify_token( VERIFY_TOKEN );
$bot->spin();

This should get you sorted. What endpoint would that be, though? Well that depends on how you’re giving Facebook access to your Plack’s .psgi application.

Domingo 21 de agosto de 2016

David Moreno

David Moreno
dm's blog

WIP: Perl bindings for Facebook Messenger

A couple of weeks ago I started looking into wrapping the Facebook Messenger API into Perl. Since all the calls are extremely simple using a REST API, I thought it could be easier and simpler even, to provide a small framework to hook bots using PSGI/Plack.

So I started putting some things together and with a very simple interface you could do a lot:

use strict;
use warnings;
use Facebook::Messenger::Bot;

my $bot = Facebook::Messenger::Bot->new({
    access_token   => '...',
    app_secret     => '...',
    verify_token   => '...'
});

$bot->register_hook_for('message', sub {
    my $bot = shift;
    my $message = shift;

    my $res = $bot->deliver({
        recipient => $message->sender,
        message => { text => "You said: " . $message->text() }
    });
    ...
});

$bot->spin();

You can hook a script like that as a .psgi file and plug it in to whatever you want.

Once you have some more decent user flow and whatnot, you can build something like:



…using a simple script like this one.

The work is not finished and not yet CPAN-ready but I’m posting this in case someone wants to join me in this mini-project or have suggestions, the work in progress is here.

Thanks!

Miércoles 29 de junio de 2016

PCTux: El hashtag que pide a Messi que no se vaya

Lunes 13 de junio de 2016

Javier Ledesma

Javier Ledesma
Ubuntronics

Richard Stallman nos explica: ¿Por que no usar celulares?

Richard Matthew Stallman (nacido en Manhattan, Nueva York, 16 de marzo de 1953), con frecuencia abreviado como «rms» es un programador estadounidense.


Es principalmente conocido por el establecimiento de un marco de referencia moral, político y legal para el movimiento del software libre, como una alternativa al desarrollo y distribución del software no libre o privativo.

Continuar leyendo »

Domingo 12 de junio de 2016

Javier Ledesma

Javier Ledesma
Ubuntronics

¿Cómo crear una lista de los paquetes instalados con Pacman y Yaourt?

Hacer una lista de todos los paquetes instalados en nuestro sistema ─en mi caso Arch Linux─ por medio de los gestores: Pacman y Yaourt, ¡es muy fácil!


Con ejecutar un solo comando en un Terminal es posible conocer los paquetes que hemos instalados, a excepción de los paquetes "base" y "base-devel".

Continuar leyendo »

Lunes 06 de junio de 2016

Javier Ledesma

Javier Ledesma
Ubuntronics

Jugar a Game Boy Advance en Linux con mGBA

Game Boy Advance (abreviada como GBA) es una popular consola de videojuegos de la compañía Nintendo. Hubo juegos de todos los géneros para esta consola que también, es compatible con todos los juegos de Game Boy y todos los de Game Boy Color.


mGBA en un emulador de Game Boy Advance con el que podrás disfrutar de todos los juegos de la fantástica consola de Nintendo en tu ordenador.

Continuar leyendo »

Jueves 26 de mayo de 2016

Linux Adictos: SuSE anuncia la disponibilidad de SLES for SAP Applications en AWS

Miércoles 25 de mayo de 2016

Linux Adictos: CentOS 6.8 ya está disponible
Linux Adictos: Comienza el desarrollo de OpenSUSE Leap 42.2

Martes 09 de febrero de 2016

Eduardo Federico

Eduardo Federico
Paraiso Linux

Usa tu smartphone para cuidar tu salud

Esto es sencillo y se puede resumir en una frase que vi por algún lado. "El sedentarismo es el nuevo tabaquismo". Hay varios estudios que se han realizado que demuestran exactamente eso. No tengo los links a esos estudios pero busquen en blogs mas especializados como vitonica y seguro los encuentran.

La cuestión es algo así: aun si dedicas una hora al día a correr o caminar pero pasas 8 o 9 hs al día sentado, ya sea trabajando o viendo anime, entonces estarás perjudicando a tu cuerpo, tu salud, por mas ejercicios que hagas antes o después de esa cantidad de horas sentado. Esto problemas son tan graves como aumentar la posibilidad de muerte prematura por problemas de corazón, obesidad (y todos los problemas derivados que esto trae) y hasta cosas "menos graves" como dolores de espalda que estoy seguro que muchos de los que están leyendo esto han padecido o lo están padeciendo en este mismo momento.

8 o 9hs sentado es poco en algunos casos. Ej: eres programador freelance. Entonces te levantas de la cama, te sientas en la pc, trabajas hasta la hora del almuerzo. Almuerzo que por supuesto comes frente a la pc viendo algun capitulo de las tantas series que te gustan, luego sigues trabajando. Y cuando has cumplido con tus horas laborales, llega la hora de ver algunos videos en youtube, leer en Internet sobre cosas que te interesen, jugar, etc. Y así hasta que llega la hora de dormir. Y nunca duermes suficiente por quedarte viendo mas series de algun anime o serie que te guste. Pufff...etc etc, pero al final una persona puede pasar mas de 14 horas al día sentado y hay que tomar conciencia del daño que eso esta causando aunque no lo notemos.

Entonces, la recomendación es que cada hora de estar sentados nos tomemos 2 minutos para caminar o hacer alguna pequeña actividad física.

Soluciones? pues lo primero que se me ocurrió fue comprarme un reloj o pulsera cuantificadora, tipo fitbit o nike fuelband. Se que muchas de ellas detectan si hemos estado sentado y sin hacer ninguna actividad mucho tiempo y entonces vibran en nuestra muñequa para que nos movamos. Eso es genial, pero al menos en mi país no son tan baratas y luego de mucho buscar encontré una app para Android que nos servirá de igual forma.

La app se llama Movn. Y se puede bajar desde play store.

Luego de instalarla y configurarla un poco con nuestros datos y metas básicos, llega la hora de usarla, y es muy sencillo. Les cuento como la uso yo.

movn salud en android

Básicamente tengo el smartphone en mi escritorio de trabajo, y pasada una hora este vibra y tiene una notificación sonora también, indicándome que ha pasado 1 hora sin que me mueva. Entonces agarro el smartphone, lo pongo en el bolsillo del pantalón y me levanto a caminar por mi casa por unos 2 a 5 minutos. Mientras aprovecho para hacer alguna llamada (usando el manos libres) de las que tengo que hacer en el día. Luego a sentarme y seguir trabajando o haciendo lo que sea en la pc.

Recomendación. Usa el manos libres si vas a hablar en esos 2 minutos que estas caminando, porque al menos a mi no me detecta que me he movido a menos que lleve el celular en el bolsillo.

Dentro de la aplicación verán que el único dato importante, o al menos en el que mas me fijo, es el que muestro en la captura de pantalla, que básicamente dice cuanto tiempo llevamos sin movernos.

Y también notaran que habrá un icono en el área de notificaciones todo el tiempo. Eso trae 2 problemas. Primero que la gente se vuelve loca por simplemente verlo ahí todo el tiempo y segundo que eso normalmente indica que la aplicación se esta ejecutando todo el tiempo, consumiendo la batería mas rápido de lo normal, pero si la duración de la batería es mas importante para ti que tu salud entonces seguramente no hayas ni llegado hasta este párrafo.

Bueno, ese es mi pequeño aporte para tratar de cuidar la salud de la gente, al menos de los pocos que lean este articulo. Si te gusto y quieres ayudar a tu familia y amigos a cuidar tu salud entonces...comparte!

La entrada Usa tu smartphone para cuidar tu salud pertenece a Paraiso Linux.

Viernes 05 de febrero de 2016

PCTux: Cupones de descuento en Argentina

Martes 17 de noviembre de 2015

Mariano Mendez

Mariano Mendez
[A]NTRAX - [L]ABS

Desbloquear Netbook del gobierno CX 100nzc 2013


Hola a todos,
Hace un tiempo hice un tutorial de como desbloquear las netbook del gobierno:

http://underc0de.org/foro/hardware/desbloqueo-definitivo-de-la-netbook-del-gobierno-con-un-clip-%28antrax%29/

Pero no sirve para todos los modelos, ahora voy a explicar como desbloquear la CX100, que es similar.

Domingo 08 de noviembre de 2015

Sergio A. Alonso

Sergio A. Alonso
Bunker Blog

Taller de Linux y Ruby on Rails

Hace tiempo que no posteo en el Blog
Sepan disculpar: no solo no me he retirado, sino que gracias a mis dos últimos empleos, Belatrix y Supercanal (donde sigo trabajando) he aprendido mucho y apenas me ha alcanzado el tiempo para transmitir conocimientos nuevos
Como para no dejar completamente de lado la docencia, lanzo la cuarta edición de este Taller, con muchas novedades.
Si bien el Taller es presencial, incluye un aula virtual propia con todo lo necesario para crear los primeros algoritmos en Ruby, diseñar aplicaciones web, hacer scripting, y armar ambientes reales de producción.
El taller es muy intenso: incluye varios meta conocimientos alrededor de esta tecnología adquiridas a lo largo de 20 años de experiencia: intercambio de llaves, GIT, seteo de Apache, balanceadores de carga, debug sobre el terreno, despliegue de nodos, deploy en clouds, y una larga lista de habilidades tanto del desarrollador web como de esa nueva profesión que se viene gestando llamada DevOp.


Ejemplo del aula, la cual gracias a Screen y al fantástico Codebox IDE me permite asistir rápidamente a los alumnos:

Para los impacientes, aquí les dejo un enlace a la descripción del Taller, clase por clase: https://goo.gl/ngQ2BE

Enlace hacia la nota completa: http://goo.gl/BLyqdy

Se agradece su difusión.

Martes 13 de octubre de 2015

¿Que es QRDA? #QRDA @QRDAve

QRDA nace bajo la idea de proveer soluciones tecnológicas a distintas organizaciones sin fines de lucro, a través del apoyo de twitter.com/delbosquetech y con el respaldo de la Comunidad del Software Libre en Venezuela.

Esta idea la propone Luis Ortiz, gran amigo y compañero de trabajo. Se desarrolla en una reunión social (agua, cerveza, jugos, refresco, pizza) por lo que es considerado un evento entre panas que buscamos un mismo fin: dar apoyo con nuestro conocimiento tecnológico para desarrollar proyectos determinados.

Luis en la Charla de Inicio de QRDA

Luego de establecer las bases que sustentarían este proyecto, se fueron creando diferentes tickets en github que permitieran establecer un orden a las actividades que se van desarrollando, para luego crear las diferentes listas de correo y comenzar a trabajar.

Al final de la actividad pudimos compartir con personas que se acercaron de diferentes parte de Venezuela y que integran la Comunidad del Software Libre, gente con la cual me identifico y que se ha ganado mi respeto.

La lista de agradecimiento es extensa, son muchos los involucrados en este maravilloso proyecto que, aún y cuando está comenzando, podría asegurar que ayudará a muchas personas y tendrá un crecimiento positivo. Muchas gracias a todos.

Les dejo las redes sociales de QRDA para que también puedan seguir este proyecto y, si lo desean, puedan unirse a nosotros:

https://twitter.com/QRDAve/
https://instagram.com/qrda.ve
https://www.facebook.com/QRDA.com.ve
http://qrda.com.ve

Nuevamente Gracias por venir.

Lunes 14 de septiembre de 2015

La accesibilidad web para personas con discapacidad visual

“La Accesibilidad” hoy en día es una de las palabras más utilizadas cuando nos referimos a las persona con alguna discapacidad, más específicamente la discapacidad visual. Ésta no solamente abarca los aspectos de software y hardware, sino que además se centra en la vida misma de estas personas, cómo puede hacerse más fácil la tarea de convivir con personas que no tienen este tipo de desventaja; debido a esto, las instituciones del Estado se han interesado y comprometido a realizar medios más accesibles para ellos, así por ejemplo tenemos los pasos peatonales, incluso hoy en día hablamos de la creación de páginas web o sistemas de información accesibles. Es importante resaltar que se debe hacer un buen uso de la tecnología para poder romper las barreras que se presentan.
La construcción de estos sistemas o páginas web son de gran ayuda para las personas que viven con esta discapacidad debido a que han sido de alguna forma discriminados, sin dejar a un lado que este grupo está ya formado por más de 30 mil personas en nuestro país, esto de acuerdo a las cifras arrojadas en el censo realizado por CONAPDIS (Consejo Nacional para las Personas con Discapacidad). Es por ello que en estos momentos se debe luchar por incluir a todas estas personas en las actividades cotidianas del hombre, más específicamente en el mundo de las tecnologías, permitiéndoles conocer, por medio de páginas web por ejemplo, todo el contenido que puede ser de su interés y así pueda salir adelante de una mejor manera. El objetivo principal es que estos sistemas estén disponibles para todas estas personas y que sean incluidas en el aparato productivo de nuestro país, además de que la misión es producir, transformar e implantar bienes y servicios lo suficientemente accesibles para ellos.
La tiflotecnología ha logrado grandes avances; a nivel mundial existen organizaciones dentro de las cuales podemos mencionar a La Once (Organización Nacional de Ciegos Españoles), la cual ha sido pionera en el uso de herramientas o dispositivos que ayudan a las personas con esta discapacidad, a ser independientes. También existen escuelas destinadas a la enseñanza completa de estas personas, como son la Lighthouse International en Estados Unidos, encargada de enseñar de manera completa con la finalidad de lograr el desenvolmiento de estos; les proporcionan ayuda en cuanto a la orientación, el uso del computador, el uso del bastón, además de otras actividades, todo con la finalidad de que cada uno de ellos no pase a ser una carga para sus familias, sino que sean personas independientes y capaces de desenvolverse tanto tecnológicamente como en las relaciones de su vida diaria.
La metodología aplicada en esta investigación es documental, ya que trata de ver lo que existe hoy en día, cómo se puede mejorar y cómo se pueden crear herramientas que verdaderamente sean útiles para el trabajo diario, ya que no tendría ningún sentido desarrollar aplicaciones sin tomar en cuenta a los usuarios interesados acerca de cómo se les puede ayudar.
Palabras Claves: Hardware, Software, Software Libre, Tiflotecnología, Discapacidad, Discapacidad Visual.

Este es uno de los tantos articulo arbitrado realizado en el proceso de postgrado, luego explicare las fases y las herramientas a usar.

Sábado 12 de septiembre de 2015

Instalar Samba en Debian

Primero que nada hacemos la instalación del paquete
root@orthanc:/home/julioh# aptitude install samba

En nuestro home creamos el nombre de una carpeta que vamos a usar para compartir
mkdir share
chmod 777 share

Luego modificamos el archivo de configuración de samba

root@orthanc:/home/julioh# nano /etc/samba/smb.conf


# Samba config file created using SWAT
# from UNKNOWN (192.168.42.219)
# Date: 2014/05/15 14:19:36
[global]
server string = %h server
map to guest = Bad User
obey pam restrictions = Yes
pam password change = Yes
passwd program = /usr/bin/passwd %u
passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* .
unix password sync = Yes
syslog = 0
log file = /var/log/samba/log.%m
max log size = 1000
dns proxy = No
usershare allow guests = Yes
panic action = /usr/share/samba/panic-action %d
idmap config * : backend = tdb
hosts allow = 127.0.0.1, 192.168.41.0/24, 192.168.40.0/24
#hosts deny = 0.0.0.0/0
#Comentamos el HostDeny para que me acepte los rangos de ip #de nuestra red interna
#[homes]
# comment = Home Directories
# valid users = %S
# create mask = 0700
# directory mask = 0700
# browseable = No

#[printers]
# comment = All Printers
# path = /var/spool/samba
# create mask = 0777
# printable = Yes
# print ok = Yes
# browseable = No
[print$]
comment = Printer Drivers
path = /var/lib/samba/printers
[SALA]
comment = Archivos Compartidos
path = /home/julioh/share
#admin users = root, SalaP, sala01, sala02
#username = root
#hosts allow = 192.168.41.0
#read list = @users
#public = yes
#only guest = yes
#Le descomentamos para que puedan escribir
writable = yes
read only = yes
valid users = SalaP, root, sala01, sala02
write list = SalaP, root, sala01, sala02
# Lineas agregadas
# crear archivos con permisos rxw
create mask = 0700
# crear directorios con permisos rxw
directory mask = 0700

Luego Detenemos el demonio y lo volvemos a levantar
root@orthanc:/home/julioh# /etc/init.d/samba restart
[ ok ] Stopping NetBIOS name server: nmbd.
[ ok ] Starting NetBIOS name server: nmbd.
[ ok ] Stopping SMB/CIFS daemon: smbd.
[ ok ] Starting SMB/CIFS daemon: smbd.
[ ok ] Stopping Samba AD DC daemon: samba

Luego de esos podremos compartir archivos en un directorio seguro para una red interna.

Lunes 07 de septiembre de 2015

Sergio A. Alonso

Sergio A. Alonso
Bunker Blog

Shot of work's laptop




A typical work session with Arch, Mate Window Manager, Numix Theme + my own colors.

Vim Janus with Molokai theme, Oh-my-zsh with Agnoster theme, Terminator, Tig, and Fuck correct typos. 

Wallpaper is one of my favorites related to Owl's Moving Castle, downloadable from here: http://www.allmacwallpaper.com/get/iMac-21-inch-wallpapers/-Howl's-Moving-Castle-1920x1080/5226-9.jpg

Lunes 31 de agosto de 2015

Martín Albisetti

Martín Albisetti
Martin Albisetti's blog

Developing and scaling Ubuntu One filesync, part 1

Now that we've open sourced the code for Ubuntu One filesync, I thoughts I'd highlight some of the interesting challenges we had while building and scaling the service to several million users.

The teams that built the service were roughly split into two: the foundations team, who was responsible for the lowest levels of the service (storage and retrieval of files, data model, client and server protocol for syncing) and the web team, focused on user-visible services (website to manage files, photos, music streaming, contacts and Android/iOS equivalent clients).
I joined the web team early on and stayed with it until we shut it down, so that's where a lot of my stories will be focused on.

Today I'm going to focus on the challenge we faced when launching the Photos and Music streaming services. Given that by the time we launched them we had a few years of experience serving files at scale, our challenge turned out to be in presenting and manipulating the metadata quickly to each user, and be able to show the data in appealing ways to users (showing music by artist, genre and searching, for example). Photos was a similar story, people tended to have many thousands of photos and songs and we needed to extract metadata, parse it, store it and then be able to present it back to users quickly in different ways. Easy, right? It is, until a certain scale  :)
Our architecture for storing metadata at the time was about 8 PostgreSQL master databases where we sharded metadata across (essentially your metadata lived on a different DB server depending on your user id) plus at least one read-only slave per shard. These were really beefy servers with a truck load of CPUs, more than 128GB of RAM and very fast disks (when reading this, remember this was 2009-2013, hardware specs seem tiny as time goes by!).  However, no matter how big these DB servers got, given how busy they were and how much metadata was stored (for years, we didn't delete any metadata, so for every change to every file we duplicated the metadata) after a certain time we couldn't get a simple listing of a user's photos or songs (essentially, some of their files filtered by mimetype) in a reasonable time-frame (less than 5 seconds). As it grew we added caches, indexes, optimized queries and code paths but we quickly hit a performance wall that left us no choice but a much feared major architectural change. I say much feared, because major architectural changes come with a lot of risk to running services that have low tolerance for outages or data loss, whenever you change something that's already running in a significant way you're basically throwing out most of your previous optimizations. On top of that as users we expect things to be fast, we take it for granted. A 5 person team spending 6 months to make things as you expect them isn't really something you can brag about in the middle of a race with many other companies to capture a growing market.
In the time since we had started the project, NoSQL had taken off and matured enough for it to be a viable alternative to SQL and seemed to fit many of our use cases much better (webscale!). After some research and prototyping, we decided to generate pre-computed views of each user's data in a NoSQL DB (Cassandra), and we decided to do that by extending our existing architecture instead of revamping it completely. Given our code was pretty well built into proper layers of responsibility we hooked up to the lowest layer of our code,-database transactions- an async process that would send messages to a queue whenever new data was written or modified. This meant essentially duplicating the metadata we stored for each user, but trading storage for computing is usually a good trade-off to make, both in cost and performance. So now we had a firehose queue of every change that went on in the system, and we could build a separate piece of infrastructure who's focus would only be to provide per-user metadata *fast* for any type of file so we could build interesting and flexible user interfaces for people to consume back their own content. The stated internal goals were: 1) Fast responses (under 1 second), 2) Less than 10 seconds between user action and UI update and 3) Complete isolation from existing infrastructure.
Here's a rough diagram of how the information flowed throw the system:

U1 Diagram

It's a little bit scary when looking at it like that, but in essence it was pretty simple: write each relevant change that happened in the system to a temporary table in PG in the same transaction that it's written to the permanent table. That way you get transactional guarantees that you won't loose any data on that layer for free and use PG's built in cache that keeps recently added records cheaply accessible.
Then we built a bunch of workers that looked through those rows, parsed them, sent them to a persistent queue in RabbitMQ and once it got confirmation it was queued it would delete it from the temporary PG table.
Following that we took advantage of Rabbit's queue exchange features to build different types of workers that processes the data differently depending on what it was (music was stored differently than photos, for example).
Once we completed all of this, accessing someone's photos was a quick and predictable read operation that would give us all their data back in an easy-to-parse format that would fit in memory. Eventually we moved all the metadata accessed from the website and REST APIs to these new pre-computed views and the result was a significant reduction in load on the main DB servers, while now getting predictable sub-second request times for all types of metadata in a horizontally scalable system (just add more workers and cassandra nodes).

All in all, it took about 6 months end-to-end, which included a prototype phase that used memcache as a key/value store.

You can see the code that wrote and read from the temporary PG table if you branch the code and look under: src/backends/txlog/
The worker code, as well as the web ui is still not available but will be in the future once we finish cleaning it up to make it available. I decided to write this up and publish it now because I believe the value is more in the architecture rather than the code itself   :)

Jueves 02 de julio de 2015

Che … ¿y los datos?

Hace mas de un año, en abril de 2014, hice una presentación sobre Gobierno Abierto / Datos Abiertos para Libres del Sur / FAP.

En dicha presentación me enteré que dentro de la Secretaría de Desarrollo Tecnológico se había iniciado un proceso de apertura de datos de la administración municipal.

Como con todo aquello que hace el Intendente Pulti, me pareció bien la iniciativa pero me reservé las opiniones para mas adelante, ya que su costumbre siempre es patear para adelante y esperar que los reclamantes se cansen.

Ah, y también hacer mucha parafernalia y ruido con poquitas nueces.

Así fue como apareció el “Portal de Datos Abiertos” de la MGP. Y se hizo un Hackaton. Y un Concurso de Aplicaciones.

Me voy a referir al primer punto, el portal de datos abiertos.

Se suponía que allí uno iba a poder encontrar la información que necesitara sobre la Municipalidad y la ciudad, en formatos libres y abiertos, y actualizada.

Lo que realmente se encuentra (con la excepción de los datos de llamadas al 147, que parecen ser extraídas directamente del sistema que usa el call center), es todo lo que publicaron hace un año y olvidaron ahí.

Asi se ve la parte sobre datos sobre seguridad:

datos_seguridad_20150701

Así los referidos a medio ambiente:

datos_medioambiente_20150701

datos_medioambiente_osse_20150701

Los de movilidad:

datos_movilidad_20150701

Los de economía y presupuesto:

datos_economía_20150701

datos_presupuesto_20150701

Adicionalmente, en la página de Información Presupuestaria, los archivos que hasta el 2014 se publicaban en formato de planilla de cálculo, ahora han pasado a estar publicados en pdf, dificultando así cualquier análisis que uno quiera hacer, u obligando a convertirlos, con los problemas que implica cuando se tratan de datos en esquemas de tablas.

Todo sigue igual. O peor. Pero manteniendo el relato.

Martes 09 de junio de 2015

Eduardo Federico

Eduardo Federico
Paraiso Linux

Software libre para punto de venta

Todos aquellos que estén empezando un negocio, una pyme muy probablemente, lo primero que buscaran en cuestión de software es uno para punto de venta. Que es eso? Pues basicamente es aquel que va instalado en el lugar donde se cobra al cliente, la caja. Y es justamente de uno de programas del que les quiero hablar hoy.

Unicenta oPOS es justamente un software libre que sirve para cobrar al cliente cuando se vende un producto. Pero un software que solo haga eso no llama mucho la atencion y deja mucho que desear. Por suerte este no es el caso.

Las características de Unicenta son tantas que no voy a poder listarlas todas pero dejo las que mas interesantes me parecieron:

  • Interfaz con decenas de skins y ademas personalizable a gusto
  • Integración con scanners de código de barra
  • Integración con sistema de tarjeta de crédito
  • Integración con balanzas
  • Sistema de descuentos integrado
  • Soporte multilenguaje
  • Soporte para varias terminales/impresoras
  • Personalización de boletas/recibos
  • Distintos modos para distintos usos: restaurant, venta por menor, supermecado, etc.
  • Funciona en tablets (se recomienda una de al menos 10 pulgadas)

Me ha pasado, y estoy seguro que a ustedes también, de ver software privativo o a hecho a medida que parecía que alguien lo había diseñado con Paint en Hasefroch 95! En el caso de Unicenta me sorprende ver lo clara y limpia que es la interfaz.

unicenta software punto de venta

Ya me parece bastante como para tenerlo en cuenta pero no solo se encarga de registrar las ventas e imprimir un ticket. Sino que para hacer de este un sistema mas completo también cuenta con:

  • Gestión de inventario
  • Gestión de empleados
  • Gestión de proveedores
  • Gestión de clientes
  • Y un excelente sistema de reportes que completa esta solución para uso de los niveles gerenciales de un negocio.

Requisitos para instalar Unicenta

Un hardware mínimo: cualquier pc con al menos 512Mb de RAM.

Cualquier sistema operativo: Linux, Mac o Windows.

Que este instalado Java.

Y soporta multitud de sistemas gestores de base de datos: MySQL, Oracle Express, PostgreSQL e incluso soporta que tengas tu base de datos en la nube.

Es un software bastante fácil de instalar para alguien que tiene los conocimientos básicos de informática y pueden hacer uso de esta guía de este software para punto de venta.

Pero, si son dueños de un negocio y no tienen los conocimientos para instalar Unicenta, les aseguro que les sera mas económico pedirle a cualquier profesional o técnico que lo haga, a pedirle a ese mismo profesional pero con un software privativo en vez de usar este software libre.

Restricciones del software

Pfff....ninguna, te lo dan completo y como en la mayoria de esta clase de software ganan dinero gracias al soporte que algunas grandes empresas solicitan y a cambios particulares de desarrollo que se solicitan. Tambien pueden donar desde la pagina web oficial.

El software se puede conseguir desde su pagina oficial, desde sourceforge, incluso esta en los repositorios de algunas distros de Linux como en AUR de Arch Linux. Pero un detalle, siempre es mejor conseguirlo de esas fuentes, porque segun indican los mismos creadores hay gente ofreciendo este mismo software como si fuera privativo.

Pagina oficial: https://unicenta.com/

La entrada Software libre para punto de venta pertenece a Paraiso Linux.

Domingo 17 de mayo de 2015

25 años de Internet en Argentina

patchcord_keyboardHoy es el día en que se conmemora el “día de Internet”. En realidad, el Día Mundial de las Telecomunicaciones y de la Sociedad de la Información, pero a veces es bueno simplificar un poco 😉 .

Este festejo surge de una propuesta de la Cumbre Mundial sobre la Sociedad de la Información, que pidió a la Asamblea General de las Naciones Unidas instituir el 17 de mayo como Día Mundial de la Sociedad de la Información, lo cual resultó decidido en forma afirmativa. Luego, la ITU (International Telecommunication Union) decide unificarlo con su Día de las Telecomunicaciones, dado que en esta fecha, y de eso también hoy se festejan los 150 años, se fundaba dicha unión.

Pero, lo que es la casualidad, resultó que un día 17 de mayo de 1990, en la ciudad de Buenos Aires y de la mano de Jorge Amodio, Argentina ponía en marcha su primer enlace a Internet.

Como fue que esto sucedió pueden leerlo en el blog del propio Amodio, haciendo click aquí.

También destaco este documento histórico: el e-mail en el cual se informa al administrador en USA que el enlace estaba funcionando.

>From pete Thu May 17 19:55:20 1990
>Subject: Line up ….
>To: atina!umd5.umd.edu!rcoltun (Rob Coltun)
>Date: Thu, 17 May 90 19:55:20 GMT-3:00
>
> Hi Rob,
>
> glad to contact you again, and very glad now because I’m
>looking the Cisco console showing “line up” over our link.
>
> I sent to Glenn the formal Internet Number and Autonomus
>System registration.
>
> Can you help me with the configuration of the Cisco router,
>I believe that we are able to do real networking tests ( your words
>sometime ago ) …
>
> I’ll wait your response,
>
> Best regards,
> Jorge.

Por esto es que quiero enviar mi saludo y las felicitaciones a quienes fueron los pioneros de Internet en Argentina, los que tras 25 años nos han dejado un legado de posibilidades extrarordinarias.

Gracias colegas!!!

Viernes 10 de abril de 2015

Dinno Vezzoni

Dinno Vezzoni
- GNU/Linux

Nuevo en linux. Ayuda de configuración.

Hola, soy nuevo usando linux, exactamente linux mint 17.1, y he estado intentando configurar diversas apps, para usar juegos y/o aplicaciones de Windows. He usado Wine y el problema es que no me arranca el office por ejemplo.
Ademas desconozco comandos de configuración. Alguien podria ayudarme?

Domingo 05 de abril de 2015

A 10 años del ICANN Meeting en Mar del Plata

Hace 10 años, un día 4 de abril de 2005, se iniciaba en Mar del Plata el ICANN Meeting XXII, el primero en ser realizado en nuestro país.

No fue casualidad que se haya organizado en la ciudad donde vivo. Un año antes, un grupito de marplatenses propusimos que se hiciera en nuestra ciudad y tuvimos la suerte de que los costos de alojamiento y comida estuvieran, en ese momento, bastante mas bajos que en la Ciudad de Buenos Aires, lo que nos dio ventaja en la decisión final de donde se hacía.

Y así empezó esta aventura que hoy es uno de los mas gratos recuerdos de mi vida profesional.

El evento se llevó a cabo en el Hotel Sheraton de Mar del Plata, quien tuvo que acelerar la instalación de su red inalámbrica para poder brindar la conectividad a los que terminaron siendo 604 participantes de 80 países distintos, con 60 APs

La conectividad a Internet se contrató a Comsat, quien tuvo que poner dos parabólicas de 2.5 metros de diámetro para poder brindar los 10 mbps simétricos que nos solicitaron con un rango /23 para contar con 512 Ips.

6 servidores DHCP, DNS y SMTP, con una estación de monitoreo de red, 20 PCs de uso público, transmisión en vivo de las reuniones y hasta hacer de service de los equipos que se le iban rompiendo a los miembros de ICANN.

Todo el grupo estuvo compuesto por gente de primera.

En la organización, Oscar García, del Polo Informático Mar del Plata, Antonio Harris, de Cabase, OTI Internacional en los servicios turísticos y Congress Rental en servicios de audio, video en pantalla gigante, registración, traducción, etc.

En la técnica, Steve Conte, Alexander Kulik, Tim Cole y Mike Evans, de ICANN, Guillermo Pereira Irujo, Claudio Roulliet, Alexis Bertola, Martín Salinas y yo, de Comtron, Marcelo Valencia y Hector Blanche, de Comsat, Juan Gimeno Rossi y German Paak, del Hotel Sheraton.

Y, a continuación, la “medalla” que nos quedó de recuerdo, con la firma, nada mas y nada menos, que de Vinton Cerf.

Descargar (PDF, 1.14MB)

Para el final, el agradecimiento a Ignacio Marcos, que pasó una tarde para conocernos personalmente y que terminó a un costado, tomando un mate y mirándonos ir de un lado para otro, ya que gracias a el y a esa visita este blog existe como tal.

Sábado 04 de abril de 2015

Dinno Vezzoni

Dinno Vezzoni
- GNU/Linux

Solucion a Error Initramfs en arranque de Ubuntu

Buenos días hoy les traigo la solución al problema de arranque initramfs que aveces nos arroja Ubuntu.

1. Introducir el CD Live o Usb con SO, y arrancar sin instalarlo.
2. Abrir la terminal y escribir:

Código: You are not allowed to view links. Register or Login
sudo fdisk -l
Esto mostrara las particiones, nosotros nos preocuparemos y trabajaremos con la que dice solo "Linux"

Ejemplo
Código: You are not allowed to view links. Register or Login
Disk /dev/sda: 250.1 GB, 250059350016 bytes
255 heads, 63 sectors/track, 30401 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: **********
Device Boot Start End Blocks Id System
/dev/sda1 * 1 30238 242886703+ 83 Linux
/dev/sda2 30239 30401 1309297+ 5 Extended
/dev/sda5 30239 30401 1309266 82 Linux swap / Solaris

Una vez hecho esto escribimos en la terminal lo siguiente (en mi caso es /dev/sda1)

Código: You are not allowed to view links. Register or Login
sudo fsck /dev/sda1
3. Montar esta partición, este paso pocas veces lo mencionan pero es esencial para que funcione.

Código: You are not allowed to view links. Register or Login
sudo mount /dev/sda1 /mnt
Y listo, problema resulto. Espero que les haya sido de ayuda.
Saludos,, Cronos.-

Sábado 21 de marzo de 2015

Dinno Vezzoni

Dinno Vezzoni
- GNU/Linux

Kali Linux 1.1.0 Español 2015 (Former BackTrack) (X32 / X64 Bits) (RG)

Kali Linux 1.1.0 Español 2015 (Former BackTrack) (X32 / X64 Bits) (RG)



Kali Linux es una distribución basada en Debian GNU/Linux diseñada principalmente para la auditoría y seguridad informática en general. Fue fundada y es mantenida por Offensive Security Ltd. Mati Aharoni and Devon Kearns, ambos pertenecientes al equipo de Offensive Security, desarrollaron la distribución a partir de la reescritura de BackTrack,que se podría denominar como la antecesora de Kali Linux.
Kali Linux trae preinstalados numerosos programas incluyendo Nmap (un escáner de puertos), Wireshark (un sniffer), John the Ripper (Un crackeador de passwords) y la suite Aircrack-ng (Software para pruebas de seguridad en redes inalámbricas). Kali puede ser usada desde un Live CD, live-usb y también puede ser instalada como sistema operativo principal.


Metasploit Framework

Dado que sigue una política llamada Kali Linux Network Services Policy, no tiene servicios de red, incluyendo servicios de bases de datos, corriendo desde la instalación del sistema. Entonces. se deben seguir un par de pasos para hacer funcionar Metasploit con soporte de base de datos.

Iniciar el servicio de Kali PostgreSQL. Metasploit usa como base de datos PostgreSQL por lo tanto debe ser iniciado el servicio de esta base de datos antes de empezar la ejecución de Metasploit. Para verificar que está iniciado el servicio se puede utilizar el comando ss-ant asegurándose que el puerto 5432 está a la escucha.
Iniciar el servicio de Kali Metasploit. La primera vez que se ejecuta crea una base de datos msf3. También inicia Metasploit RPC y los Web servers que requiera. Se puede ejecutar msfconsole para verificar la conectividad con la base de datos con el comando db status.
Se puede configurar el sistema para que ejecute Metasploit en el inicio.


Forensics Mode en Kali Linux

BackTrack Linux introdujo la opción Forensics Boot al sistema operativo y se vio continuada en BackTrack 5, existe al día de hoy en Kali Linux. Sirve para poner a trabajar las herramientas de software libre más populares en materia forense de forma rápida y sencilla.

Se realizaron algunos cambios importantes:

El disco duro no se utiliza en absoluto. Lo que trae como consecuencia que si existe una partición swap no va a ser usada ni se monta automáticamente ningún disco interno.
Se deshabilitó el automontado de medios removibles. Entonces, ni los pendrives ni las lectoras de CD van a ser montados automáticamente
Herramientas para pruebas de penetración

Hoy en día la cantidad de herramientas o scripts existentes, que realizan tareas similares, es inmenso.
Claramente ciertos casos pueden ser mejores que otros, o puede tratarse de preferencias personales, pero en si el universo de herramientas es enorme. Por lo tanto, mantener un repositorio, de herramientas para pruebas de penetración actualizado, puede llegar a ser una tarea sumamente difícil.


Por el motivo antes expuesto obliga al equipo de desarrollo de Kali a ser muy selectivo al momento de incorporar herramientas.

Algunos de los cuestionamientos planteados al momento de elegir una nueva herramienta son los siguientes: ¿Es útil la herramienta en un entorno de pruebas de penetración?, ¿Contiene la herramienta las mismas funciones de otras herramientas existentes?, ¿Está permitido la libre redistribución por la licencia de la herramienta?, ¿Cuántos recursos requiere la herramienta?, ¿Funcionará en un entorno “estándar”?, etcétera.

TAMAÑO: 2,92 GiB / 2,78 GiB
TIPO DE ARCHIVO: IMAGENES ISO
USAR WINRAR 5.10 PARA DESCOMPRIMIR LAS ISOS




x32 bits.

You are not allowed to view links. Register or Login
You are not allowed to view links. Register or Login
You are not allowed to view links. Register or Login
You are not allowed to view links. Register or Login
You are not allowed to view links. Register or Login
You are not allowed to view links. Register or Login

x64 bits.

You are not allowed to view links. Register or Login
You are not allowed to view links. Register or Login
You are not allowed to view links. Register or Login
You are not allowed to view links. Register or Login
You are not allowed to view links. Register or Login

Editado por Jimeno. Eliminación de gif.

Martes 10 de febrero de 2015

Eduardo Federico

Eduardo Federico
Paraiso Linux

El prompt de tu consola en Linux mucho mas bonito!

Que es el prompt? Abre una terminal o consola. Ves eso que esta escrito? Ver lo unico que esta aparece? Eso es el prompt.

Normalmente tiene un simbolo $ indicando que estas usando la consola como un usuario normal o un simbolo # para indicar que estas usandola como usuario root. Y es muy probable que tambien tenga una barra vertical | o un guion bajo _ titilando para indicar que esta a la espera de una nueva orden.

Un prompt basico y normal se ve algo asi:

prompt basico

Lo que indica este ejemplo basico es:

  • tu nombre de usuario: yourname
  • nombre de la pc: yourhost
  • directorio actual: ~
  • tipo de usuario: $

Apuesto a que ni habias prestado atencion a esos pocos datos verdad?

Pero esto no se queda ahi, podemos hacer mucho mas, para lograr algo mas util y mucho mas vistoso y bonito. Una consola para presumir

En primer lugar debes saber como modificar el prompt del bash. Para ello solo tienes que abrir el archivo .bashrc que esta en tu carpeta home (/home/tu_usuario/.bashrc) con tu editor de texto preferido. Al final de ese archivo tienes que escribir algo asi:

export PS1='cadena_de_texto'

donde cadena de texto se compondra de la suma de algunos de los controles que tenemos disponibles. Vamos a ver cuales son esos controles:

\d – La fecha en formato "Dia Mes Fecha" Ej: "Lun May 26")
\e – Caracter de escape ASCII
\h – El hostname
\H – El hostiname completo
\j – Numero de tareas corriendo actualmente en segundo plano
\n – Nueva linea
\r – Enter
\s – Nombre de la consola
\t – Hora actual en formato HH:MM:SS de 24Hs
\T – Hora actual en formato HH:MM:SS de 12Hs
\@ – Hora actual en formato am/pm de 12Hs
\A – Hora actual en formato HH:MM de 24Hs
\u – Nombre de usuario
\v – Version del bash
\w – Ubicacion actual completa
\W – Directorio actual
\$ – Tipo de usuario ($, #)
\\ – Una barra
\[ – Comienza secuencia de caracteres no imprimibles
\] – Termina secuencia de caracteres no imprimibles

Ejemplos:

Esto va a mostrar una carita distinta segun si el comando que se ejecuto se completo positivamente o si en cambio dio error:

PS1="\`if [ \$? = 0 ]; then echo \[\e[33m\]^_^\[\e[0m\]; else echo \[\e[31m\]O_O\[\e[0m\]; fi\`[\u@\h:\w]\\$ "

carita prompt

Como ves no solo se puede cambiar que es lo que se muestra sino dotarlo de funcionalidades si sabes programar un poquito.

Como encontrar mas ejemplos?

Lo mejor es usar google, no hay un solo lugar donde esten reunidos todos y la cantidad de diseños y usos que se le pueden dar son muchos. Les recomiendo buscar cosas como "bash prompt examples" o "ps1 prompts".

Generadores de PS1

Y si no tienes ganas de buscar entonces hay herramientas online para crear el tuyo propio. En estas herramientas solo tienes que arrastrar y soltar para crear configuraciones totalmente personalizadas, agregar todo el texto o simbolos que quieras y cambiar los colores.

Usa los comentarios para compartir tu configuracion. Si estas logueado podras no solo compartir el codigo que usaste sino tambien subir una imagen de muestra

La entrada El prompt de tu consola en Linux mucho mas bonito! pertenece a Paraiso Linux.

Domingo 01 de febrero de 2015

Martín Albisetti

Martín Albisetti
Martin Albisetti's blog

Disassembling a DeLonghi eco310.r coffee machine

After a few weeks of being coffee-deprived, I decided to disassemble my espresso machine and see if I could figure out why it leaked water while on, and didn't have enough pressure to produce drinkable coffee.
I live a bit on the edge of where other people do, so my water supply is from my own pump, 40 meters into the ground. It's as hard as water gets. That was my main suspicion. I read a bit about it on the interwebz and learned about descaling, which I'd never heard about. I tried some of the home-made potions but nothing seemed to work.
Long story short, I'm enjoying a perfect espresso as I write this.

I wanted to share a bit with the internet people about what was hard to solve, and couldn't find any instructions on. All I really did was disassemble the whole thing completely, part by part, clean them, and make sure to put it back together tightening everything that seemed to need pressure.
I don't have the time and energy to put together a step-by-step walk-through, so here's the 2 tips I can give you:

1) Remove ALL the screws. That'll get you there 95% there. You'll need a philips head, a torx head, a flat head and some small-ish pliers.
2) The knob that releases the steam looks unremovable and blocks you from getting the top lid off. It doesn't screw off, you just need to pull upwards with some strength and care. It comes off cleanly and will go back on easily. Here's a picture to prove it:

DeLongi eco310.r

Hope this helps somebody!

Miércoles 21 de enero de 2015

Gabriel Talavera

Gabriel Talavera
gabrieltalavera

Tar sobre SSH sin tocar el sistema de archivos local

Command Line Kung Fu es un blog de tres eminencias en informática forense que ademas de publicar interesantes retos de linea de comandos entre ellos, (cada uno en su especialidad, bash, powershell y cmd) lo hacen con mucho humor y desmenuzando en detalle los comandos utilizados. Últimamente no postean con mucha frecuencia, pero aún así hay mucho material interesante para aprender.

Una de las joyas que descubrí hace poco es la del Episodio #164, básicamente, copiar un directorio completo creando un archivo tar que escribirá a traves de SSH a un archivo remoto sin tocar el sistema de archivos local.

tar zcf - localfolder | ssh remotehost.evil.com "cd /some/path/name; tar zxpf -"

En el ejemplo, tar creará un tarball de la carpeta "localfolder" y lo extraerá en el servidor remoto remotehost.evil.com sin dejar rastros.

Domingo 18 de enero de 2015

Gabriel Talavera

Gabriel Talavera
gabrieltalavera

Como cambiar el password de una clave privada SSH

Recientemente me vi en la necesidad de cambiar el passphrase mis claves privadas para conexiones SSH, lo hice mediante ssh-keygen:







  • -p: solicita cambiar el passphrase de un archivo de clave privada, al ejecutar ssh-keygen con este parametro deberás proveer dos veces la clave anterior y dos veces la nueva.
  • -f: indica la ruta al archivo de clave privada.

Este método también sirve para establecer un passphrase a a una clave privada creada sin contraseña.

Jueves 06 de noviembre de 2014

Martín Albisetti

Martín Albisetti
Martin Albisetti's blog

Click packages and how they’ll empower upstreams

As the pieces start to come together and we get closer to converging mobile and desktop in Ubuntu, Click packages running on the desktop start to feel like they will be a reality soon (Unity 8 brings us Click packages). I think it's actually very exciting, and I thought I'd talk a bit about why that is.

First off: security. The Ubuntu Security team have done some pretty mind-blowing work to ensure Click packages are confined in a safe, reliable but still flexible manner. Jamie has explained how and why in a very eloquent manner. This will only push further an OS that is already well known and respected for being a safe place to do computing for all levels of computer skills.
My second favorite thing: simplification for app developers. When we started sketching out how Clicks would work, there was a very sharp focus on enabling app developers to have more freedom to build and maintain their apps, while still making it very easy to build a package. Clicks, by design, can't express any external dependencies other than a base system (called a "framework"). That means that if your app depends on a fancy library that isn't shipped by default, you just bundle it into the Click package and you're set. You get to update it whenever it suits you as a developer, and have predictability over how it will run on a user's computer (or device!). That opens up the possibility of shipping newer versions of a library, or just sticking with one that works for you. We exchange that freedom for some minor theoretical memory usage increases and extra disk space (if 2 apps end up including the same library), but with today's computing power and disk space cost, it seems like a small price to pay to empower application developers.
Building on top of my first 2 favorite things comes the third: updating apps outside of the Ubuntu release cycle and gaining control as an app developer. Because Click packages are safer than traditional packaging systems, and dependencies are more self-contained, app developers can ship their apps directly to Ubuntu users via the software store without the need for specialized reviewers to review them first. It's also simpler to carry support for previous base systems (frameworks) in newer versions of Ubuntu, allowing app developers to ship the same version of their app to both Ubuntu users on the cutting edge of an Ubuntu development release, as well as the previous LTS from a year ago. There have been many cases over the years where this was an obvious problem, OwnCloud being the latest example of the tension that arises from the current approach where app developers don't have control over what gets shipped.
I have many more favorite things about Clicks, some more are:
- You can create "fat" packages where the same binary supports multiple architectures
- Updated between versions is transactional so you never end up with a botched app update. No more holding your breath while an update installs, hoping your power doesn't drop mid-way
- Multi-user environments can have different versions of the same app without any problems
- Because Clicks are so easy to introspect and verify their proper confinement, the process for verifying them has been easy to automate enabling the store to process new applications within minutes (if not seconds!) and make them available to users immediately

The future of Ubuntu is exciting and it has a scent of a new revolution.

Martes 30 de septiembre de 2014

Sergio A. Alonso

Sergio A. Alonso
Bunker Blog

El Mundo Según JuanCPovE: Día de la Tierra, ese pequeño punto azul pálido en...

El Mundo Según JuanCPovE: Día de la Tierra, ese pequeño punto azul pálido en...: Siempre en este día cito a Carl Sagan y su obra "Pale Blue Dot". Una buena razón para reflexionar y cambiar de una buena vez nue...

Miércoles 03 de septiembre de 2014

Gabriel Talavera

Gabriel Talavera
gabrieltalavera

Configuracion de targets iSCSI con tgtadm

Entre los objetivos del exámen EX436, no se mencionan dispositivos de almacenamiento basados en FC o FCoE, sin embargo, un conocimiento mínimo de iSCSI es fundamental. RHEL incluye tgtd como servidor iSCSI. En esta entrada vemos una configuración básica.

En el equipo que ofrecera los dispositivos de bloque o particiones a los demás nodos del cluster, instalar el paquete scsi-target-utils:
[root@san ~]# yum install scsi-target-utils

El servicio encargado de responder peticiones iSCSI es tgtd, y se administra con los comandos tgtadm y tgt-admin. El comando tgtadm no funcionará hasta que el servicio tgtd este corriendo, iniciamos este servicio y nos aseguramos de que sea persistente.
[root@san ~]# service tgtd start
Starting SCSI target daemon: [ OK ]
[root@san ~]# chkconfig tgtd on

Creamos un target con ID 1 nombrado iqn.2014-05.lab.demo:sharedStorageTest

[root@san ~]# tgtadm --lld iscsi --mode target --op new --tid 1 --targetname iqn.2014-05.lab.demo:sharedStorageTest

A pesar de que el target iSCSI ya esta listo para contestar peticiones, aún no tiene un dispositivo de bloque asociado (que podría ser, una unidad de disco, un volumen lógico, e incluso un archivo), con el siguiente comando comprobamos que el target esta listo. Puede apreciarse que aún sin añadir un backing store ya existe la LUN 0, que sería como una controladora lógica.

[root@san ~]# tgtadm --lld iscsi --mode target --op show
Target 1: iqn.2014-05.lab.demo:sharedStorageTest
System information:
Driver: iscsi
State: ready
I_T nexus information:
LUN information:
LUN: 0
Type: controller
SCSI ID: IET 00010000
SCSI SN: beaf10
Size: 0 MB, Block size: 1
Online: Yes
Removable media: No
Prevent removal: No
Readonly: No
Backing store type: null
Backing store path: None
Backing store flags:
Account information:
ACL information:

Creamos un archivo de 1GB para utilizarlo como backing store y nos aseguramos de que este en el contexto correspondiente de SELinux:

[root@san ~]# dd if=/dev/zero of=/var/lib/tgtd/sharedLUNS/sharedStorage1.img bs=1M seek=1024 count=0
0+0 records in
0+0 records out
0 bytes (0 B) copied, 0.000229479 s, 0.0 kB/s
[root@san ~]# ls -ltrh /var/lib/tgtd/sharedLUNS/sharedStorage1.img
-rw-r--r-- 1 root root 1.0G May 12 13:21 /var/lib/tgtd/sharedLUNS/sharedStorage1.img
[root@san ~]# restorecon -R /var/lib/tgtd

Agregamos el archivo creado como backing store del target ID 1:

[root@san ~]# tgtadm --lld iscsi --mode logicalunit --op new --tid 1 --lun 1 --backing-store /var/lib/tgtd/sharedLUNS/sharedStorage1.img

Por ahora no nos adentraremos mucho en los aspectos de seguridad del protocolo iSCSI, como en su configuración por defecto tgtd no permite acceso a ningún nodo, abrimos el acceso a todos los iniciadores con el siguiente comando:

[root@san ~]# tgtadm --lld iscsi --mode target --op bind --tid 1 --initiator-address ALL

Verificamos los targets activos:

[root@san ~]# tgtadm --lld iscsi --mode target --op show
Target 1: iqn.2014-05.lab.demo:sharedStorageTest
System information:
Driver: iscsi
State: ready
I_T nexus information:
LUN information:
LUN: 0
Type: controller
SCSI ID: IET 00010000
SCSI SN: beaf10
Size: 0 MB, Block size: 1
Online: Yes
Removable media: No
Prevent removal: No
Readonly: No
Backing store type: null
Backing store path: None
Backing store flags:
LUN: 1
Type: disk
SCSI ID: IET 00010001
SCSI SN: beaf11
Size: 1074 MB, Block size: 512
Online: Yes
Removable media: No
Prevent removal: No
Readonly: No
Backing store type: rdwr
Backing store path: /var/lib/tgtd/sharedLUNS/sharedStorage1.img
Backing store flags:
Account information:
ACL information:

Para que los pasos realizados persistan a traves de reinicios, debe hacerse un dump de la configuración en ejecución y redireccionarlo al archivo targets.conf:

[root@san ~]# tgt-admin --dump
default-driver iscsi

<target iqn.2014-05.lab.demo:sharedStorageTest>
backing-store /var/lib/tgtd/sharedLUNS/sharedStorage1.img
</target>
[root@san ~]# tgt-admin --dump > /etc/tgt/targets.conf

Lunes 01 de septiembre de 2014

PCTux: Mejorar la velocidad de carga de aplicaciones con Prelink

Viernes 04 de julio de 2014

LaREPAWEB: WordPress merchandise

Viernes 06 de junio de 2014

LaREPAWEB: Concatenar filas de una tabla según la clave

Miércoles 30 de abril de 2014

LaREPAWEB: Monitoreo de Apache con Apache GUI en Windows

Jueves 04 de octubre de 2012

LugSaJu: La tecla que te salva del DESASTRE

Jueves 09 de agosto de 2012

Dear Martínez

Dear Martínez
La vida Linux

Software de mensajería instantánea Jitsi 1.0

La competencia entre los programas de mensajería instantánea a través de VoIP, video conferencia y más, es grande y todas satisfacen nuestras necesidades. Competidores somo Skype, Ekiga, lideran el poderío de uso, pero existen otras alternativas menos utilizadas por no ser famosas, pero de mejor dicción y predisposición de servicio al usuario, tal como Jitsi, antes conocido como SIP Communicator y que desde hace tan solo días, ha lanzado su nueva versión estable.

Jitsi 1.0 Software de mensajería instantánea Jitsi 1.0

El renovado Jitsi 1.0 reúne todas las funciones que se pueden encontrar en diversos programas con las herramientas VoIP, video conferencia, mensajería instantánea tanto para Windows como para Mac y GNU/Linux. Esta interfaz es sumamente cómoda y amigable, siendo intuitiva y fácil de utilizar. Es compatible con los protocolos más populares de mensajería instantánea y telefonía, pero también se le puede dar uso con las cuentas habituales de correo tales como Hotmail, Gmail o Yahoo, o bien otros como AIM, XMPP, Jabber, SIP y la posibilidad de emparejar la cuenta de la red social Facebook.

Entre sus características más destacadas se encuentra la de transferencia de llamadas atendidas o ciegas, el cambio de estado automático cuando el usuario no se encuentre utilizando el ordenador, la autoconexión, además de permitir grabar las llamadas para seguridad del usuario y el cifrado de protocolos SRTP Y ZRTP. No obstante, también permite establecimiento de conexión de medios directa mediante protocolo ICE, streaming de escritorio, almacenamiento de contraseñas cifradas, transferencia de archivos, soporte IPv6 para SIP y XMPP, etc.

 

Jueves 02 de agosto de 2012

Dear Martínez

Dear Martínez
La vida Linux

Aprende a tocar la guitarra con TuxGuitar

Un nuevo software para los amantes de la guitarra y la música, además de para aquellos aficionados que siempre quisieron aprender, existe una herramienta llamada TuxGuitar, siendo un editor visual de tablaturas y partituras de código abierto. Esta aplicación ha de ser ideal para llevarla consigo a cualquier parte. Desarrollada hace tiempo, es una idea que surgió para crear una herramienta que le haga competencia al popular Guitar Pro, pero que esta pueda ser utilizada por todo el mundo de forma gratuita.

Tux Guitar Aprende a tocar la guitarra con TuxGuitar

La herramienta de Tux Guitar es muy útil para el aprendizaje de la música y el arte de utilizar cualquier guitarra, aunque también cuenta con bajo, teclado y batería con el cual el usuario podrá aprender lo que no, o poner en práctica lo conocido en la materia. Desarrollado por la compañía Java, se puede abrir y exportar ficheros GP3, GP4 y GP5, además de ser compatible con los archivos del Guitar Pro, permitiendo que se pueda utilizar las partituras creadas para ese programa.

No solamente el Tux Guitar es un simple editor visual de partituras con el que se puede componer la música, sino también ofrece una gran variedad de efectos de sonido, soporte multipista, tempo, posibilidad de tercetos, scroll automático en la reproducción y muchas otras herramientas que lo ayudarán a formar su música tal como la disponga.

Lunes 16 de julio de 2012

Dear Martínez

Dear Martínez
La vida Linux

Nueva versión de MythTV 0.25 con soporte para Windows

El conocido reproductor de TV se ha escondido en la sombra de las noticias tecnológicas respecto a Linux durante un año y medio, sin tener novedades de ellas y varios retrasos en el desarrollo de la última versión del reproductor, por lo que MythTV anunció que ha sido liberado y trae 5200 cambios como si fuera poco. Muchos saben en qué consiste este software reproductor de TV y multimedia, por lo que les interesará saber sobre las novedades de cambios.

MythTV Nueva versión de MythTV 0.25 con soporte para Windows

En la versión 0.25 de MythTV se incluyen nuevas características que destacan el interés en los usuarios, como nuevas capacidades de aceleración de video, tales como VAAPI y video de DirectX2, mejoras de audio, incluyendo soporte para E-AC3, TrueHD y DTS-HD, mejoras de los metadatos que integra gestión de grabaciones y videos, una API para aplicaciones de terceros, para aprovechar la interacción con el frontend y backend, control del televisor y otros componentes AV a través del consumer electronics control, o la inclusión de un HTTP Live Streaming, para compartir el contenido de video en tiempo eral a través de la API integrada.

También se destaca en el nuevo reproductor MythTV, el MythMusic que ha sido completamente reescrito y MythVideo que ahora se ha integrado completamente, en lugar de ser distribuido como un plug-in por separado. Además, a través de MythThemes, todos los temas, incluyendo los de terceros, se pueden descargar directamente desde el selector de temas de la interfaz.

 

Martes 24 de abril de 2012

David Doe

David Doe
e2391

Un alias para fbshot

Para capturar la pantalla en mi sistema sin X suelo utilizar fbshot. Amo este pequeño programa por su simpleza y permitirme documentar mis andanzas en la terminal. Lo único que siempre me da flojera es tener que especificar si o si el nombre del fichero de salida :P

Por eso cree este alias:

alias fbs=’fbshot -s 5 ~/Screenshots/`date +%F_%H:%M:%S_$HOSTNAME.png`’

Ahora mis screenshots están ordenadas por fecha, hora y nombre de la maquina :D

EOF

Lunes 23 de abril de 2012

David Doe

David Doe
e2391

Terminal monocromático

Jugando..

#4DC791
archlinux tmux

#4D6791
archlinux tmux

#898960
archlinux tmux

EOF

Viernes 20 de abril de 2012

David Doe

David Doe
e2391

CLI BASED SYSTEM: Archlinux en Olivetti Pentium III

archlinux tmux tty-clock newsbeuter vitunes vim conky

Ese es Archlinux corriendo en mi notebook Olivetti con un procesador Pentium III 700mhz, 180mb de RAM y un disco rígido de 18gb. Es una configuracíon muy minimalista al punto de no tener Xorg instalado. Todas mis tareas las realizo desde la tty valiéndome de distintas CLI apps. Mención especial para tmux  con el cual puedo ejecutar diferentes terminales virtuales en una misma tty.

Ahora ¿Que puedo hacer desde un entorno tan básico? Con newsbeuter leo mis feeds, a traves de elinks navego por la web y, si lo quiero hacer de forma grafica tiro con links. Gestiono mi mail con mutt, veo videos con mplayer, imagenes con fbi y pdfs con fbgs, escucho musica con vitunes, uso nano para escribir tonterias y editar ficheros de configuracion, vim para programar y hnb para tomar notas. Manejo ordenadores remotos con ssh, descargo torrents con rtorrent, chateo mediante irssi+bitlbee y pruebo la seguridad de mi red con aircrack entre otras cosas.

Cuando compre esta note, me la entregaron con una placa PCMCIA wifi con chipset RALINK, así que en cuanto a ese aspecto no tuve ningun problema. Para administrar mis conecciones utilizo netcfg+wifi-select que es de lo mas minimalista que hay.

El unico problema que tengo es con el brillo, no hay forma de que se lo pueda bajar. No molesta demasiado por suerte, pero no me quejaria si se pudiese modificar. Probe con varias distros y lo mismo, no hay forma. Asi que todavia ando investigando. Sacando eso todo funciona de diez.

Me gusta mucho usar este entorno, siento que aprovecho toda la potencia de esta vieja laptop. Del grub al login hay alrededor de 22 segundos y en el arranque consume unos 18mb de RAM mas o menos, lo que no esta para nada mal. Mas allá de lo que pueda parecer, me resulta muy cómodo usar este sistema. No soy dependiente del mouse y casi siempre me muevo con atajos de teclado por lo que no tarde en acostumbrarme demasiado a usar tmux. Además, el touchpad no es lo mio :P

Por ultimo comentar que me encanta el hecho de poder llevar a cabo tantas tareas en una computadora que tiene mas de una decada. Soy partidario de que los ordenadores viejos pueden reutilizarse de una manera u otra :)

EOF

Jueves 05 de abril de 2012

Soft-Libre: GNOME 3.4 disponible con interesantes novedades
Soft-Libre: Wallpapers para Ubuntu 12.04 LTS