Imaginemos un mundo libre

El blog de Ronny, dedicado a la libertad de acceso al conocimiento.

KDE 4.4 SC released.

leave a comment »

A new big release of KDE Software Compilation has been made. Thanks to everybody involved in KDE for making this happen.and give us great software.

In case you don’t have it installed watch the videos in Youtube..

Written by Ronny Yabar Aizcorbe

February 9, 2010 at 8:19 pm

Posted in KDE

QGraphicsView

leave a comment »

Una introducción a QGraphicsView, ampliamente usado en aplicaciones Qt.

QGraphicsView es el framework dentro de Qt que permite la creación e interacción de elementos gráficos 2D y que usa el método de programación modelo/vista.

De manera simple, varias vistas pueden observar una misma escena y una escena puede contener elementos (items) de diferentes formas geométricas.

El framework está compuesto de 3 elementos:

      QGraphicsScene (La Escena): Representa una escena con items. Es la clase que se encarga de almacenar los widgets, así como manejar propagar eventos a cada item.

      Además esta clase se encarga de manejar los estados de un item. Un objeto QGraphicsScene es muy flexible como para incluir cualquier número de objetos QGraphicsItem.

      QGraphicsView (La Vista): La clase que se encarga de proporcionar los widgets que visualizan el contenido de una escena.

      La vista recibe eventos de entrada del teclado/mouse, y los traslada a la escena.

      QGraphicsItem (El Item): Representa un grupo de items. Es una clase para el manejo de items gráficos en la escena y proporciona varios items estándar para formas típicas como rectángulos, elipses y textos. También soporta eventos del mouse como mover, soltar, presionar, doble click, sobre y eventos del teclado.

      QGraphicsItem, además soporta dos características importantes en elementos gráficos: Drag and Drop (Soltar y arrastrar) y collision detection.

      Cada objeto QGraphicsItem en la escena soporta rotación, zooming, traslado y el poder cortarlo.

Hagamos un ejemplo sencillo de como crear un escena, un item y como visualizarlos:


// Incluimos las clases de la escena, vista y el tipo de item
#include <QtGui/QApplication>
#include <QGraphicsRectItem>
#include <QGraphicsScene>
#include <QGraphicsView>

int main( int argc, char **argv )
{
   QApplication app(argc, argv);

   // Iniciamos la escena y definimos su tamaño
   QGraphicsScene scene;
   scene.setSceneRect(-100, -100, 200, 200);
   // Color y estilo
   scene.setForegroundBrush(QBrush(Qt::lightGray, Qt::CrossPattern));

   // Creamos y agregamos nuestro item (rectángulo) a la escena
   QGraphicsRectItem *item = new QGraphicsRectItem( 0, &scene );
   // izquierda, arriba, ancho y alto
   item->setRect(-60, -30, 140, 60);
   // Línea: Ancho y estilo
   item->setPen(QPen(Qt::blue,4,Qt::SolidLine));
   // Relleno: Color y estilo.
   item->setBrush(QBrush(Qt::green,Qt::SolidPattern)); 

   // Creamos una vista para visualizar la escena
   QGraphicsView view( &scene );
   view.setRenderHints( QPainter::Antialiasing );
   view.show();

   return app.exec();
}

Y el resultado:

QGraphicsRectItem

Written by Ronny Yabar Aizcorbe

January 12, 2010 at 10:34 am

Posted in KDE

Como ser desarrollador de KDE

leave a comment »

Bueno ya que hace poco empecé a involucrarme en el desarrollo de KDE y ya me está yendo bien, quisiera compartir con los programadores latinos, gente de Perú e interesados en general, cómo es el proceso para convertirse en desarrollador de KDE.

Es importante aclarar que estoy en camino de ser desarrollador de KDE, simplemente deseo trasmitir mi experiencia y lo aprendido hasta el momento. Cualquier mejora o aporte a esta guía es bienvenido.

Hay distintos caminos para llegar a este objetivo, y es más, hay gente que ha escrito al respecto como:

The Road to KDE Devland (6 series)
The Road to KDE and Qt Development

y de la web oficial:

Becoming a KDE Developer

Hay muchas cosas en común en esos caminos y básicamente la idea es la misma.

He tratado de ser lo más breve posible y decidido escribir mi pequeña guía “Como ser desarrollador de KDE” en español, pues se que, como yo alguna vez, hay muchos hispano hablantes que desean contribuir a KDE y no tienen alguna idea de cómo empezar. Espero profundizar y continuar esta guía más adelante.

Ojo, hay muchas maneras de contribuir a kDE como arte, documentación, traducción, promoción, reportando fallos, etc. Ahora me voy a enfocar sólo en el desarrollo, ahí vamos:


Cómo ser desarrollador de KDE

Contribuir con el desarrollo de KDE, es uno de los aportes principales a la comunidad y al proyecto. Es una experiencia enriquecedora que te va a permitir compartir, extender tus conocimientos y aprender a trabajar en equipo.

Si eres un estudiante o profesional de la computación, te gusta la programación y el desarrollo de software, deseas participar en proyectos reales y pertenecer a una comunidad internacional de desarrolladores y gente creativa, si es así, entonces estás en el sitio correcto.

Para ser un desarrollador de KDE necesitas aprender lo siguiente:

Está demás decir que debes de tener un nivel aceptable de Inglés, pues la comunicación se realiza en este idioma.

C++

C++ es un potente lenguaje de programación orientado a objetos, diseñado para muchos propósitos, muy usado en la computación gráfica y desarrollo de juegos.

KDE está mayormente escrito en C++. Entonces si no sabes C++, tienes que aprenderlo. Hay muchos libros y excelentes recursos en internet sobre C++. Un gran libro es “Pensando en C++” de Bruce Eckel que también está disponible como libre descarga en castellano. Es imprescindible que aprendas todos los fundamentos de C++ antes que empieces con KDE.

Qt

Para ser un desarrollador de KDE, debes aprender Qt. Qt es una biblioteca multiplataforma escrita en C++ para desarrollar aplicaciones gráficas y también para desarrollar programas sin interfaz gráfica como herramientas de consola y servidores.

Si no estás familiarizado con Qt, puedes ver la documentación oficial de Qt y desarrollar los tutoriales incluidos ahí.

Si prefieres aprender Qt mediante la lectura de un libro tradicional, mira la página de libros acerca de Qt. Algo importantísimo es que aprendas el concepto y la aplicación de Signals and Slots, es fundamental en todas las aplicaciones construidas con Qt.. Básicamente, es un mecanismo de comunicación entre objetos.

KDE

Un punto de partida para empezar a desarrollar en KDE son los tutoriales del sitio oficial. Lo primero que debes revisar es la sección Introducción a la programación en KDE4.. Empiezas con un Hola Mundo, luego a crear ventanas, después añadir acciones, barras, menús y así vas desarrollando paso a paso.

También encontrarás información útil sobre el desarrollo de KDE en la sección de Preguntas Frecuentes.

Otro recurso valioso para desarrollar es la API (Interfaz de programación de aplicaciones) de KDE. Allí encontrarás excelente documentación de clases, métodos y funciones de las librerías y aplicaciones de KDE.

Después que tengas una base de conocimientos en C++, QT y KDE, entonces ya puedes empezar a desarrollar para KDE, pero antes necesitas aprender lo siguiente:

Una vez que hayas compilado la última versión en desarrollo, configurado tu ambiente de desarrollo y realizado tus primeros tutoriales de programación en KDE, quiere decir que ya estás preparado para dar los primeros pasos.

Tienes que tener paciencia, automotivarte y sentir pasión por lo que haces. La comunidad KDE es sensacional y el software que produce es de alta calidad. No todo cae de la noche a la mañana, entonces con trabajo constante, poco a poco verás los frutos de tu esfuerzo.

Bueno, entonces llegó la hora que empieces a escribir código para algún proyecto dentro de KDE. Claro que puedes desarrollar tu propia aplicación, pero se recomienda que antes intentes involucrarte con uno ya existente para que entiendas mejor como funcionan las cosas internamente, aprendas del código de otros, veas como es la organización y el trabajo en equipo.

Puedes ver todo el código de KDE directamente desde el navegador en WebSVN para que explores las aplicaciones y/o librerías que forman parte de KDE.

Puedes descargarte el código de una aplicación/librería con el usuario anónimo de subversion. Obviamente haz tenido que instalar antes subversion. Por ejemplo, con el siguiente comando me descargo kdelibs, que son las librerías básicas de KDE.

svn co svn://anonsvn.kde.org/home/kde/trunk/KDE/kdelibs

Una breve explicación de los directorios y subdirectorios principales:

Branches: Es donde están las distintas versiones de KDE, incluyendo lo que será la próxima revisión de la versión actual de KDE.

Trunk: Es donde se lleva a cabo el desarrollo de la rama principal de KDE, es decir, lo que será la próxima versión de KDE.

-KDE
——kdelibs: Librerías críticas de KDE.
——kdebase: Dividido en 3 partes.
———apps: Aplicaciones que forman parte de la distribución principal de KDE como Dolphin, Kate, Konqueror.
———runtime: Cosas necesarias para todas las aplicaciones KDE en tiempo de ejecución y una dependencia requerida.
———workspace: Cosas específicas de KDE, como Plasma o el gestor de ventanas.

——kdeartwork: Trabajo artístico, diseño gráfico, íconos, sonidos, temas, fondos de pantalla.
——kdeedu: Aplicaciones educativas.
——kdegames: Juegos.
——kdegraphics: Aplicaciones gráficas.
——kdemultimedia: Reproductores de audio y video.
——kdepim: Aplicaciones de manejo de información personal.
——kdepimlibs: Librerías usadas por las aplicaciones kdepim
——kdeplasma-addons: Aplicaciones, tecnologías de Plasma como applets, dataengines, runners.
——kdeutils: Utilitarios para KDE.
——kdewebdev: Aplicaciones para desarrollo web.

-extragear: Aplicaciones que usan las librerías y estásn relacionadas con KDE, pero no forman parte de la distribución principal de KDE.

-koffice: Suite Ofimática de KDE. Tienen sus propias fechas de liberaciones.

-playground: Aplicaciones en estado alpha. Pueden compilar, pero carecen de estabilidad, robustez, internacionalización, usabilidad, arte, en fin, no están maduras para el usuario final.

-kdereview: Cuando una aplicación de playground alcanza cierta madurez y estabilidad, se mueve a kdereview para darle los toques finales y sea revisada profundamente por los desarrolladores para que alcanze un nivel óptimo. Después de kdereview pasan a formar parte de la rama principal de KDE.

-kdesupport: Librerías/software necesario para compilar KDE.

-l10n-kde4: Archivos de traducción de KDE a muchos idiomas.

-www: Aquí se encuentran los archivos, imágenes que pertenecen a las páginas web de KDE.

Elige una aplicación de tu agrado que te gustaría hacerle algún cambio, agregarle una nueva funcionalidad.

Normalmente los desarrolladores dentro del directorio de su proyecto tienen un archivo llamado TODO, donde está la lista de tareas por hacer, un README con la descripción de la aplicación y un archivo HACKING que explica los lineamientos para desarrollar en ese proyecto.

Aparte de agregar una característica a una aplicación, también puedes corregir un fallo. Los fallos se reportan en el Sistema de búsqueda de fallos de KDE, llamado bugs.kde.org.

Desde bugs.kde.org puedes filtrar los fallos existentes en la aplicación que escogiste y ver cuales aún no están resueltos. Escoge uno y trata de resolverlo.

Otra opción para empezar con el desarrollo en KDE, es realizar algún Junior Job, (Tarea o trabajo pequeño). Los Juniors Job son trabajos muy sencillos que necesitan realizarse en las aplicaciones. Normalmente los desarrolladores suben Juniors Jobs a bugs.kde.org para obtener nuevas contribuciones e involucrar a la gente recién iniciada en el desarrollo de KDE. Puedes ver la lista de Junios Jobs aquí.

Sea que haz corregido un fallo, haz agregado una nueva característica, funcionalidad o haz hecho un Junior Job, debes de enviarles tus cambios al desarrollador(es). O mejor dicho, tienes que enviar tus parches.

Un parche consta de cambios que se aplican a un programa, para corregir errores, agregarle funcionalidad, actualizarlo, etc.

La mayoría de proyectos en KDE usan un sistema web llamado Review Board que permite manejar los parches de manera mucho más eficiente. Te registras y envias tu(s) parche(s) a la aplicación que escogiste.

En caso, la aplicación que estás modificando no use Review Board, tienes que enviar tus parches por email al desarrollador o a la lista de correo del proyecto. Debes de enviar tus archivos en un formato que el desarrollador vea los cambios que haz realizado de manera rápida. Para ello existen dos comandos Unix/Linux que te van a ser muy útiles: diff y patch.

Un ejemplo sencillo, imagina que tienes 2 archivos (original.cpp y nuevo.cpp), deseas ver la diferencia entre ambos y generar otro archivo. El comando sería:

diff -u original.cpp nuevo.cpp > miparche.patch

Enviándole el archivo miparche.patch al desarrollador le haces la vida más facil porque puede ver y aplicar tus cambios rápidamente. No importa el tamaño de tu parche, así solucione algo pequeño, pero útil será bienvenido, de lo contrario será rechazado por diversas razones. Entre ellas que quizá no sigues los estándares del código de la aplicación, no resuelves el problema o te faltan pequeños detalles que corregir. Si hay algún problema con tu parche, el desarrollador te lo hará saber y te dirá que le falta para que sea aplicable.

No tengas miedo, los desarrolladores de KDE, son seres humanos y muy buenas personas que muestran mucho respeto por el trabajo de otros y están dispuestos a ayudarte a resolver problemas o guiarte con la solución.

Pero, sea cual sea la respuesta del desarrollador, igualmente muestra respeto y sigue investigando cómo puedes mejorar.
Hay maneras y maneras de decir las cosas. Por eso, es importantísimo que sigas el Código de Conducta de la comunidad KDE.

Bien ya enviaste tus cambios, fueron aceptados, ya te sientes parte de la comunidad y crees que haz cambiado el mundo.

Ahora tienes que solicitar una cuenta subversion en KDE (KDE SVN account). Subversion es el sistema de control de versiones con el cúal trabaja actualmente KDE, posteriormente se cambiará a Git.

Cualquiera que ya haya hecho algún trabajo en KDE puede aplicar a una cuenta svn. Con una cuenta svn podrás aplicar los cambios tú mismo al proyecto, en vez de estar enviando parches y quitarle tiempo a los desarrolladores.

Lee esta guía de como solicitar una cuenta svn. Si tu solicitud fue aceptada, entonces lo siguientes es leer Los primeros pasos con tu cuenta KDE svn.

Una vez que tengas tu cuenta svn y haz leído lo primero que debes de hacer con ella, bien ya puedes trabajar directamente en el proyecto con subversion.

Para descargarte el código de un proyecto y tener una copia local del mismo (checkout), ssh es lo más óptimo:

svn co svn+ssh://tuusuario@svn.kde.org/home/kde/ruta/a/la/aplicacion

En mi caso cuando descargué el juego que empecé a modificar:

svn co svn+ssh://ronnyy@svn.kde.org/home/kde/trunk/playground/games/pege/

Ahora, ingresa al directorio del proyecto que te bajaste:
cd proyecto_kde

Para ver el estado del proyecto, los archivos que han sido agregados, modificados, eliminados:

svn status

Realiza tus cambios y haz tu primer commit:

svn ci -m “My new feature / Fixed bug description.”

Para ver todos los cambios que hiciste dentro de un directorio y generar un archivo .diff

svn diff –diff-cmd diff -x -uw > ~/patch.diff

Para estar al día y actualizado con los últimos cambios que se hicieron al código.

svn up

Son algunos comandos básicos de subversion, puedes encontrar muchos tutoriales y how-tos en la web donde encontrarás mucha más información.

Finalmente, si haces commits a menudo, participas activamente y das un aporte significativo a algún proyecto, la comunidad te tratará como un desarrollador de KDE, si eso pasa, ya podrás llamarte desarrollador de KDE.

Como ves, ser desarrollador de KDE es un proceso que toma su tiempo. Seguramente en el camino encontrarás obstáculos y te estancarás en alguna parte, pero depende de ti poder superar esas barreras.

Contribuir a KDE te va a dar un prestigio y elevar tu karma en la comunidad Open Source/Software Libre. A la larga, todo esto te dará muchos beneficios sociales, técnicos y probablemente puede cambiar tu vida.

Diviértete, comunica, comparte, aprende, enseña y todo se hará más fácil.

Sitio principal para desarrolladores de KDE
http://techbase.kde.org/Development_(es)

Lista de correo
Si estás interesado en el desarrollo de KDE, estás creando tu propia aplicación y quieres hablar con alguien que hace o está interesado en el desarrollo de KDE en general.

Visita: https://mail.kde.org/mailman/listinfo/kde-devel y subscríbete a la lista.

Canal IRC
#kde-devel en irc.freenode.net

Otros lenguajes de programación

Si te gustaría desarrollar para KDE en otros lenguajes de programación, también tienes otras alternativas.

KDE Y Qt disponen de una serie de bindings y tecnologías para diversos lenguajes de programación, entre los principales tenemos a Python, Ruby y Javascript:

Python

Ruby

Javascript

Written by Ronny Yabar Aizcorbe

January 12, 2010 at 10:34 am

Posted in KDE

KDE se cambia a Git

leave a comment »

Como muchos otros proyectos Open Source, (Kernel Linux, Perl, Ruby on Rails, Wine, X.org, Android, VLC, FreeBSD, OpenSuse…) KDE ha iniciado el cambio de sistema de control de versiones de Subversion a Git.

En subversion, que es un sistema centralizado, todos los desarrolladores de determinado proyecto deben de conectarse a un servidor central y los cambios que se realizan afectan a todos. Otro de las desventajas de un sistema centralizado es que muchos contribuyentes o personas que desean contribuir tienen muchas limitaciones de escritura debido a las políticas de acceso. Pero claro Subversion se ajusta a algunos tipos de proyectos y también tiene sus ventajas.

Por el contrario, Git es un sistema de control de versiones distribuido, es decir, que no depende de un repositorio central. Git permite administrar varios tipos de proyectos, especialmente de gran envergadura, de manera rápida y eficiente.

Una de las ventajas de Git, es que abre las puertas a más contribuyentes. Tú puedes tener tu propia rama dentro del proyecto, experimentar, realizar cambios sin afectar a los demás y cuando pienses que tu código es estable y funcional puedes fusionar tus cambios con otra rama.

Git tiene otras características cool, entre ellas, que puedes realizar ciertas cosas estando desconectado de la red.

Probablemente este va a ser un cambio impactante en la comunidad, debido al tamaño de KDE y el número de aplicaciones/desarrolladores/contribuyentes. Pero ya existen proyectos de KDE que han migrado exitósamente a Git como Amarok, Phonon, Konversation y Gluon.

Todo el código de las librerías y aplicaciones de KDE, van a ser movidos a Gitorious, excepto los archivos de traducción y documentación.

Gitorious es un servicio para alojar proyectos Open Source, donde también está alejado Qt y existe una buena relación/comunicación con desarrolladores de Qt en Nokia.

Aaron Seigo, KDE Hacker, explica , más a fondo, en su blog los motivos del cambio.

Si tienes conocimientos en git, esta una gran oportunidad para contribuir a KDE y unirte al KDE Git Team. Entra al canal #kde-git en Freenode.

¿Cómo aprender Git?
Hay mucha información, tutoriales y libros en la web. Yo te recomiendo Git Magic de Ben Lynn empleado de Google.

Gracias a esta guía, tengo una base en Git. Está todo muy bien explicado con palabras sencillas, directo al grano y con todo lo que necesias para empezar a usar Git.

Git en la web de KDE

http://techbase.kde.org/Projects/MovetoGit

http://techbase.kde.org/Development/Tutorials/Git

Written by Ronny Yabar Aizcorbe

January 12, 2010 at 10:32 am

Posted in KDE

KDE Latinoamérica

leave a comment »

No tuve mucho tiempo de postear estas últimas semanas, pero más vale tarde que nunca.

El día 10 de noviembre de 2009 tuve la suerte de asistir a la reunión de comunidades de KDE en latinoamérica, canal #kde-cl en freenode, gracias a la invitación de Christian González de la comunidad KDE Chile. Christian ha escrito una carta dirigida a todas las comunidades de KDE en Lationamérica y España donde resume los puntos tratados en la reunión.

Transcribo la carta para que más personas puedan unirse a esta iniciativa:


Carta abierta a las comunidades de KDE de Latinoamérica y España

El día martes 10 de noviembre de 2009 se efectuó la segunda reunión por IRC [1] de la recientemente formada comunidad KDE Chile, en la cual participaron representantes de varias comunidades latinoamericanas. En dicha reunión se planteó la posibilidad de aunar esfuerzos en pos de construir una comunidad KDE Latinoamérica-España, potenciando así la difusión y el apoyo al proyecto KDE en nuestros países y evitando la duplicación de esfuerzos.

Después de una larga discusión, los representantes de las distintas comunidades establecieron los siguientes acuerdos:

  1. Cada comunidad individual seguirá teniendo plena autonomía para trabajar en sus proyectos locales, así como para administrar sus propios portales web. Se propone tener una plantilla genérica que pueda ser usada por las comunidades que así lo deseen.
  2. Se solicitará la creación de un subforo en idioma español dentro del foro oficial de KDE (disponible en http://forum.kde.org), en el cual puedan participar todos los miembros de las distintas comunidades respondiendo consultas técnicas de los usuarios de habla hispana. Se evaluará la posibilidad de tener una sección por cada país para temas como organización, política interna, actividades locales, etc.
  3. Se apoyarán los esfuerzos de documentación de KDE (especialmente las traducciones) en los wikis oficiales del proyecto: http://techbase.kde.org (para desarrolladores) y http://userbase.kde.org (para usuarios).
  4. Se creará un “Planeta KDE en español” que agrupe los blogs personales de los miembros de las distintas comunidades.
  5. Se decidió crear el canal IRC #kde-latam en el servidor Freenode (irc.freenode.org:6667) como un lugar de coordinación transversal para las distintas comunidades.
  6. Para lograr estos objetivos, se ha establecido contacto con Helio Chissini de Castro, contacto oficial de KDE para Latinoamérica. Estamos bastante confiados en que su intermediación será de mucho provecho para lograr los objetivos antes mencionados.

    Por todo lo anterior, queremos extender esta invitación a todas las comunidades de KDE en España y Latinoamérica. Si están interesados en participar de esta iniciativa, por favor publiquen esta carta en los medios de comunicación de su comunidad (portal web, lista de correo, etc.) y envíen un aviso a la lista de correos de KDE Chile (http://www.kde.cl/group), o comuníquense a través del canal IRC #kde-latam.

    Esperamos que más comunidades puedan unirse y podamos difundir y apoyar al proyecto KDE en nuestros países.


    Desde Perú, nos unimos a esta iniciativa de agrupar a las todas las comunidades de KDE en Lationamérica y España.

    Se ha creado hace poco la lista oficial kde-latam, así que se invita a usuarios y desarrolladores de KDE para que participen.

Written by Ronny Yabar Aizcorbe

January 12, 2010 at 10:31 am

Posted in KDE

My KDE life started

with 4 comments

KDE Community

KDE is the community and the Open Source/Free Software project that I always wanted to be part of. I am a KDE user for about 3 years and enjoy using KDE applications everyday. I use Kate for web development, can’t live without Amarok, Dolphin, Kaffeine, digiKam, Kopete, Konversation and Konsole obviously.

Unfortunately, I haven’t had enough time to contribute to KDE in a real way due to other responsibilities. I just blogged a little about KDE, shared Kubuntu and OpenSuse CDs with some friends and adapted a small script to add Peruvian radios in Amarok. No more.

But, I am following the KDE development since the 4.0 times reading the dot.kde.org and planet.kde.org and all articles around the web about KDE development. I think is time to give KDE a real contribution. Why?

Simple, I love the KDE community. These people have fun creating things and software, really smart, creative, friendly and with great passion for what they do. That is really encouraging for me.

In my case, I want to develop and promote KDE. I think is better to start contributing to an existing project to see how all this works, have a good understanding of the KDE platform and then write your own application.

I have some knowledge of C++, learned the principles of QT and checked the KDE examples at Techbase. Also, I set up my KDE development environment. So, I felt ready to start and took a look at many KDE apps/projects and see where I can get involved. Finally, I decided to start with KDE games. I enjoy playing KSudoku, Palapelli and KPat. (Didn’t try the others yet).

Well, I picked up a game from playground called Peg-E, an implementation of the game Peg solitaire (also known as Hi-Q). The game consists of jumping over pieces in order to remove them from the board. The goal is to remove all pegs but one. Peg solitaire at Wikipedia:

Playground is the section in the KDE source code repository where live KDE applications in alpha version. Many of those applications compile, but they lack of stability, international support, artwork and are not ready to use for the masses.

This game was abandoned for about 8 months. I compiled, become addicted and started hacking on it. I had to study libkdegames which is a library used for games in KDE. The first thing I did was to add difficulty levels, a timer, highscores and follow the KDE coding style. After that, I sent the patches to the developer (Graeme Gott) and requested him the maintainership of the game. The developer answered me that KDE is not a good fit for him, and accepted me to be the maintainer (Thanks a lot Graeme), but I have to change the name of the game because he has a pure QT version called Peg-E and users can be confused. The game name probably will be KPeg.

Then, I applied for my KDE svn account attaching the patches and happily, after some hours, my svn account was created and I made my first commit. Now, if everything goes fine this game will be part of KDE games for the KDE SC 4.5 release. I’ll work hard on it and sure I’ll learn much more about programming and games development.

I am impressed about the interesting algorithms and math behind the Peg Solitaire. That’s why I choose it. The game looks relatively simple, but it is very difficult to leave only one peg. There are many competitions around the world and papers about how fast and efficient you can be to solve a Peg solitaire. Well, I created my TODO list and currently reading some technical articles about the game.

That’s how my KDE life started and now I am happy of being part of the KDE community. Of course, I will write all my progress about the development of the game and my new adventures in the KDE devland.

Wait, wait, wait I forgot to tell you something. There is another KDE user in my family: Celeste, my daughter. I showed her the game KTurbeling and she loved it. I promised her to write a Lazy Town theme. She is a real fan and crazy about that program.

I am preparing more posts about KDE and have a surprise for you: Peruvian KDE users/developers.

So, Stay tuned.

Written by Ronny Yabar Aizcorbe

December 17, 2009 at 8:42 am

Posted in KDE

La Última Lección de Randy Pausch

with one comment

Ayer fue uno de esos días duros que uno tiene, fue el día más triste y doloroso de mi vida, estaba completamente destrozado, desmotivado y con una depresión inmensa por ciertas situaciones.

Derramé muchas lágrimas (Sí también los programadores tienen emociones), pero lo bueno es que tuve la compañía de mi hija en todo momento, estuvo a mi lado y me decía no llores papito, sentí todo su amor y su cariño. Igual necesitaba algo más como comprenderán.

Hasta que encontré el video de La Última Lección (Last Lecture) que dio Randy Pausch meses antes de morir de cáncer al páncreas. Simplemente despuès de ver el video completo me sentí mejor por lo educativo, divertido, inspirador y motivante que es. Esta es una lección de humanidad que la voy a compartir con mis amigos y familia. Después de ver el video me descargué el libro entero sobre su última lección, donde cuenta detalles que no dijo en el auditorio.

Simplemente brillante. En mi opinión Randy es un genio de la manera como transmitir emociones y sabiduría.

Randy no necesita presentación, fue un profesor y gran científico de la Ciencia de la computación y más que eso un ejemplo para millones de personas en el mundo. Hay miles de artículos y homenajes hacia el y bastante información sobre su vida en la web, así que prefiero no hablar mucho de su vida, mas si sobre su libro.

Una de las cosas que me impactó del libro es la manera como Randy sabiendo que iba a morir, tenía tanto sentido del humor para hablar acerca de la vida y además la manera como expresa cada una de sus historias.

Este libro, es sin duda, uno de los mejores que he leìdo y que dejaron huella en mi vida. Considero que hay mucho, mucho de que aprender de Randy y es un must-have en la cabecera de tu cama, en tu escritorio o en tu oficina.

Hay 2 capítulos que me marcaron:
Cumple tus sueños de la infancia.. Aquí Randy explica todos los sueños que tuvo de niño y como los fue cumpliendo todos. Sumamente entretenida la historia.

Uno de esos sueños y con el que me identifico es como llegó a ser un creativo de Disney y todo lo que luchó para llegar ahí y que lo resume muy bien en dos palabras: Trabajo duro. Claro que mi sueño no es exactamene igual al de Randy, pero si estoy luchando duro para llegar a un lugar que para mí es el trabajo con el que siempre he soñado.

Y el otro sueño que me hizo reír y acordar de mi infancia es “Ganar animales de peluche”, me acuerdo como jugaba y de la manera como lo hacía con tanta pasión para llevarle un peluche a mi madre y hermanita. Nunca me olvidaré esos sueños de niño. Simplemente sensacional este capítulo, me di cuenta lo importante que es siempre llevar ese niño adentro, para no dejar de soñar y usar la imaginación.

El otro capìtulo que nunca olvidaré:
La cuestión es como vivir tu vida está llena de emociones y lecciones de Randy. Aún seguía con un vacío inmenso y después de leer este capìtulo, me sentí mas reconfortado, fue cuando realmente desperté y me di cuenta que tenía una vida por delante, que debo vivir cada segundo como si fuera el último y no debo perder el optimismo y emplear mi tiempo correctamente.

Y sobre todo lo que aprendí de “La cuestión es como vivir tu vida” es que leí una frase que a partir de ahora estará en mi vida para siempre:

«Los muros existen por alguna razón. No están para dejarnos afuera, sino para darnos la oportunidad de mostrar hasta qué punto deseamos algo. Están para detener a los que no lo desean lo suficiente.»

Si así es la vida, la cuestión es como vivir tu vida y tú decides si quieres vivir quejándote de la vida, de tu suerte y de tu entorno o si quieres vivir con alegrìa, con pasíón, con humildad y ver siempre el lado bueno de las personas.

No se como agradecerle a Randy por todo lo que sus enseñanzas me dejaron y sobre todo por ayudarme en este momento tan difícil en mi vida. Se que cumpliendo mis sueños el estaría conforme, pero he decidido darle un pequeño homenaje: Voy a hacer feliz, muy feliz a las personas que tanto amo, como lo hizo Randy. Voy a trabajar y ser constante para llegar lejos. Y el día que llegue donde me he trazado, ese día, Randy va a estar en la lista de invitados a la celebración y va a recibir un reconocimiento especial.

Randy, estés donde estés, gracias eternamente.

Disfruten aquí el video en Inglés,prefiero verlo así para aprende más, pero también lo pueden encontrar en partes con subtítulos en español. Dura 1:16, ya tiene billones de visitas y es un fenómeno en Internet.

Written by Ronny Yabar Aizcorbe

December 16, 2009 at 12:52 pm

Posted in Libros, Personal

Peruvian Radios in Amarok

with 5 comments

Estimados KDEeros peruanos y usuarios de Linux en general:

Acabo de publicar un script que agrega algunas radios online de nuestro querido Perú en el excelente reproductor Amarok versión 2.0+. Lo pueden descargar desde aquí

Para instalar el script se van al Menú Tools->Script Manager->Install Script seleccionan el script que descargaron, presionan OK y listo.

Otra forma es en vez de hacer click en “Install script” presionan “Get More Scripts”, y hacen click en “Install” a lado de “Peruvian Radio Stations” y listo. Cierran y vuelven a abrir Amarok y tendrán una pantalla como esta:

Peruvian Radio Stations in Amarok

Peruvian Radio Stations in Amarok

Hacen click en Peruvian Radio Stations y les aparecerá:

Peruvian Radio Stations in Amarok

Peruvian Radio Stations in Amarok

He agregado todas las radios que pude encontrar en la web. Disfruten escuchando la música de su preferencia, así como noticias, deportes, etc. Normalmente cuando cambias de una radio a otra, demora de 1 a 5 segundos.

Las siguientes radios fueron testeadas una y otra vez y funcionan correctamente:

Lima:
Callao 1400 KHZ AM
Capital 96.7 FM
Corazon 96.7 FM
CPN Radio 90.5 FM
Doble Nueve 99.1 FM
Felicidad 88.9 FM
La Unión 103.3 FM
Miraflores 96.1 FM
Moda 97.3 FM
Panamericana 101.1 FM
Planeta 107.7 FM
Ritmo Romántica 93.1 FM
RPP 89.7 FM
San Borja 91.1 FM
Secretos al corazón 93.1 FM
Studio92 92.5 FM
Telestereo 88 FM

Arequipa:
La Mega 94.3 FM
Las Vegas 99.3 FM
Melodia 104.3 FM
Panorama 96.5 FM
Super Stereo 105.5 FM
Yaravi 106.3 FM

Tacna:
Power 98.1 FM
Super Stereo 103.5 FM
Uno 93.7 FM

Cusco:
TV Color 98.1 FM
Willkamayu 940 AM

Trujillo:
La Grande 96.1 FM
Libertad Mundo 1160 Kcs AM

Ica:
Sonica 92.1 FM

Este pequeño script está basado en el script de Radio France con ciertas modificaciones. Gracias al desarrollador y a este tutorial que encontré en la web de Kubuntu que me permitió entender mejor como funcionan los scripts en Amarok..

Si desean que una radio sea agregada, por favor, simplemente envíen un mail a ronnycontacto(at)gmail.com indicando la stream url de la radio o simplemente la dirección del sitio web y gustosamente agregaré la radio en la brevedad posible..

Written by Ronny Yabar Aizcorbe

August 5, 2009 at 7:44 am

Posted in KDE

Congratulations KDE team for Caizen (KDE 4.3)

with one comment

kde 4.3 (Caisen) was released today. Please read the announcement, see the improvements, applications, the platform and give this desktop a try and you will see the difference.

Congratulations and thanks to all the KDE team for the hard work..

KDE 4.3

KDE 4.3

I love KDE and now that I am doing more c++ and QT I hope to be part of the team for 4.4.

Written by Ronny Yabar Aizcorbe

August 4, 2009 at 6:21 pm

Posted in KDE

Upgrade to Django 1.1

leave a comment »

Developing or considering Django to create your cool 2.0 web applications/sites?

Please, try the new version of Django (1.1) which comes with interesting new features.

If you already have Django installed, you must remove the old version directory before upgrading. The path to the directory depends of your system, but it is usually located at:

/usr/local/lib/python$version/dist-packages/
/usr/local/lib/python$version/site-packages/
or
/usr/lib/python$version/dist-packages/
/usr/lib/python$version/site-packages/

One of the new features I recently tried is the possibility to create admin actions that allow for bulk updates to many objects at once.

Example:

Imagine you have a field called status which is a boolean field and you want to change the status of many elements at the same time. It’s annoying to select an object one by one to change the status. Here come “admin actions”, they are really useful.

In this short example, I want to make some objects published/unpublished. I will define two methods in my admin.py to achieve this.

def published(modeladmin, request, queryset):
    queryset.update(status=1)
published.short_description = 'Published stores'

def unpublished(modeladmin, request, queryset):
    queryset.update(status=0)
unpublished.short_description = 'Unpublished stores'

As you can see, in this case, the actions take an argument: queryset, which contains the action to perform and the fields that will be affected.

Then, you add these actions to your model admin:

class StoreAdmin(admin.ModelAdmin):
  ...
  actions = [published,unpublished]

And your admin interface will look like this:

Django admin actions

Django admin actions

Now you can select Published/Unpublished and press “Go” to test the actions.

I selected some elements to make them unpublished and in a second I got the following:

After performing admin actions in Django

After performing admin actions in Django

Simple right?. KISS is always important. But, there are some things to consider before finishing:

Those actions(published, unpublished) are placed outside the class ModelAdmin. (StoreAdmin in this example). But, we also can define these actions as methods of the ModelAdmin.

The advantage is that defining actions as methods gives the action a more direct access to the ModelAdmin (Performance) and the possibility to call any of the methods provided by the admin.

So, I am going to define the actions as methods of StoreAdmin and rename modeladmin parameter to self.

And finally I put the strings ‘published’,'unpublished’ in actions to tell the ModelAdmin to see those actions as methods instead of direct references to functions:

class StoreAdmin(admin.ModelAdmin):
  ...
  actions = ['published','unpublished']

  def published(self, request, queryset):
    queryset.update(status=1)
  published.short_description = 'Published stores'

  def unpublished(self, request, queryset):
    queryset.update(status=0)
  unpublished.short_description = 'Unpublished stores'

And that’s it. If you want to know more about admin actions or implement advanced action techniques, take a look at the excellent Django documentation.

Another feature I tried in Django 1.1 was the option: list_editable which allow edit and save multiple rows at once from the change list page. This option has the same format that list_display, but you have two restrictions:

  • Any field in list_editable must be in list_display.
  • The same field can’t be listed in both list_editable and list_display_links
  • class StoreAdmin(admin.ModelAdmin):
      ...
      list_display = ('customer', 'state','city','phone','status')
      list_editable = ['phone']
    

    A screenshot of the list_editable option for the field phone of my Store model.

    Django - list_editable option

    Django - list_editable option

    Well, I’ll continue exploring the new features in Django 1.1. If you have something to share, don’ t hesitate to post a comment or blog about that.

    Written by Ronny Yabar Aizcorbe

    August 3, 2009 at 7:46 am

    Posted in Django

    Búsqueda lineal y búsqueda binaria

    with one comment

    Los algoritmos de búsqueda lineal y binaria son 2 de los algoritmos más usados para encontrar elementos en una estructura de datos.

    La búsqueda lineal probablemente es sencilla de implementar e intuitiva. Básicamente consiste en buscar de manera secuencial un elemento, es decir, preguntar si el elemento buscado es igual al primero, segundo, tercero y así sucesivamente hasta encontrar el deseado. Entonces este algoritmo tiene una complejidad de O(n).

    La búsqueda binaria al igual que otros algoritmos como el quicksort utiliza la técnica divide y vencerás. Uno de los requisitos antes de ejecutar la búsqueda binaria, es que el conjunto de elementos debe de estar ordenado. Supongamos que tenemos el siguiente array.

    57 53 21 37 17 36 22 3 44 97 89 26 31 47 8 17

    Debemos ordenarlo
    3 8 17 17 21 22 26 31 36 37 44 47 53 57 89 97

    ¿Como funciona la búsqueda binaria?
    Necesitamos una seria de datos para realizar la búsqueda: El elemento en la posición inicio, fin, medio. Y porsupuesto el tamaño del vector y elemento que queremos buscar.

    inicio = 0;
    fin = tam – 1;
    medio = (inicio + fin) / 2;

    Preguntamos si el elemento buscado es igual al elemento que se encuentra en la posicion medio del array, si es afirmativo ya encontramos el elemento y no hay nada más que hacer.

    if(buscado == array[medio]){
      cout << "Se encuentra en la posicion " << medio + 1 << endl;
      return array[medio];
    }
    

    Si no es así. Preguntamos si el elemento que se encuentra en la posición medio es mayor al elemento buscado, si es afirmativo y como el array está ordenado, quiere decir que elemento buscado es menor al del medio. Entonces ahora solo buscaríamos en esa división del array,
    por lo tanto, el fin ahora sería el elemento anterior al medio.

    if(array[medio] > buscado){
      fin = medio - 1;
    }
    

    De lo contrario quiere decir que elemento buscado es mayor al del medio, entonces debemos buscar en la otra división del array, por lo tanto el inicio sería el elemento posterior al medio.

    else {
      inicio = medio + 1;
    }
    

    Con cualquiera de estas 2 operaciones descartamos la otra mitad del array y por lo tanto reducimos notablemente el número de iteraciones.
    Por lo tanto, en cada iteración, la búsqueda se reduce a la mitad del array. Realizamos esto en un bucle mientras el inicio sea menor o igual al fin.

    El algoritmo de búsqueda binaria tiene una complejidad de O(log n).

    Veamos la implementación de la búsqueda lineal y binaria en C++.

    Nota: Para realizar la búsqueda binaria, estoy incluyendo el archivo que contiene el algoritmo de ordenamiento quicksort, para no volver a escribirlo y así reutilizar código.
    #include “quicksort.h”

    Aquí tienen el código del algoritmo y una breve explicación. Retiren el main para utilizarlo en otros programas.

    #include <iostream>
    #include "quicksort.h"
    
    using namespace std;
    
    int busqueda_lineal(int *array,int buscado,int tam)
    {
        for(int i=0;i<tam;i++){
            if(buscado==array[i]){
              cout << "Se encuentra en la posicion " << i+1 << endl;
            }
       }
    }
    
    int busqueda_binaria(int *array, int buscado, int tam)
    {
        int medio, inicio, fin;
        inicio = 0;
        fin = tam-1;
    
        while(inicio <= fin){
          medio = (inicio + fin) / 2;
    
          if(buscado == array[medio]){
            cout << "Se encuentra en la posicion " << medio + 1 << endl;
            return array[medio];
          } else{
              if(array[medio] > buscado){
                fin = medio - 1;
              } else {
                inicio = medio + 1;
              }
          }
        }
        return -1;
    }
    
    void imprimir(int *array,int tam)
    {
       for(int i=0;i<tam;i++){
            cout << array[i] << "  ";
       }
       cout << endl << endl;
    }
    
    int main()
    {
        int tam;
        int buscado;
        cout << "Ingresa el tamanyo del array" << endl;
        cin >> tam;
    
        int array[tam];
    
        srand(time(NULL));
        for(int i=0;i<tam;i++){
            array[i] = rand() % 100;
        }
    
        cout << endl;
        cout << "Array al inicio " << endl;
        imprimir(array,tam);
    
        cout << "Ingresa el elemento a buscar (Busqueda lineal) ";
        cin >>buscado;
        busqueda_lineal(array,buscado,tam);
    
        cout << "Array ordenado " << endl;
        quicksort(array,0,tam);
        imprimir(array,tam);
    
        cout << "Ingresa el elemento a buscar (Busqueda binaria) ";
        cin >>buscado;
        busqueda_binaria(array,buscado,tam);
    
        return 0;
    }
    

    Ejemplo de la salida del programa:

    Ingresa el tamanyo del array
    16
    
    Array al inicio
    57  53  21  37  17  36  22  3  44  97  89  26  31  47  8  17
    
    Ingresa el elemento a buscar (Busqueda lineal) 36
    El elemento se encuentra en la posicion 6
    Array ordenado
    3  8  17  17  21  22  26  31  36  37  44  47  53  57  89  97
    
    Ingresa el elemento a buscar (Busqueda binaria) 89
    El elemento se encuentra en la posicion 15
    

    Written by Ronny Yabar Aizcorbe

    July 9, 2009 at 6:31 pm

    Posted in C++

    Listas enlazadas – Clase Lista,Nodo en c++

    with 8 comments

    Una lista es una estructura de datos que nos permite agrupar elementos de una manera organizada. Las listas al igual que los algoritmos son importantísimas en la computación y críticas en muchos programas informáticos.

    Las listas están compuestas por nodos, estos nodos tienen un dato o valor y un puntero a otro(s) nodo(s).

    Existen varios tipos de listas: Simplemente enlazada, doblemente enlazada, circular simplemente enlazada, circular doblemente enlazada.

    Vamos a revisar las listas enlazadas simples, por ser el punto de partida y fundamentales para poder entender las otras.

    Una lista enlazada tiene un conjunto de nodos, los cuales almacenan 2 tipos de información: El dato que contienen y un puntero al siguiente nodo en la lista. El último nodo de la lista tiene como siguiente nodo el valor NULL. Entonces las listas enlazadas simples solo pueden ser recorridas en una dirección, apuntando al nodo siguiente, mas no a un nodo anterior.

    Aquí una ejemplo de un lista enlazada simple.

    En cristiano:
    55-> 60-> 31-> 5-> 4-> 51-> 9-> 27-> 68-> 62-> NULL
    
    Internamente:
    Nodo-> Dato: 55 Direcion: 0x3d2c00 Siguiente: 0x3d2c80
    Nodo-> Dato: 60 Direcion: 0x3d2c80 Siguiente: 0x3d2c90
    Nodo-> Dato: 31 Direcion: 0x3d2c90 Siguiente: 0x3d2ca0
    Nodo-> Dato: 5  Direcion: 0x3d2ca0 Siguiente: 0x3d2cb0
    Nodo-> Dato: 4  Direcion: 0x3d2cb0 Siguiente: 0x3d2cc0
    Nodo-> Dato: 51 Direcion: 0x3d2cc0 Siguiente: 0x3d3ab8
    Nodo-> Dato: 9  Direcion: 0x3d3ab8 Siguiente: 0x3d3ac8
    Nodo-> Dato: 27 Direcion: 0x3d3ac8 Siguiente: 0x3d3ad8
    Nodo-> Dato: 68 Direcion: 0x3d3ad8 Siguiente: 0x3d3ae8
    Nodo-> Dato: 62 Direcion: 0x3d3ae8 Siguiente: 0
    

    Obviamente, internamente no existen las palabras nodo, dato,dirección y siguiente, es solo una representación.

    Como una lista es una estructura de datos dinámica, el tamaño de la misma puede cambiar durante la ejecución del programa.

    Como vimos en post anteriores, se puede generar memoria dinámicamente para un array, pero un array es una estructura estática pues su tamaño tiene un limite y así creáramos array dinámicos hay que redimensionar el tamaño si es necesario, lo cual ya implica un costo de volver a generar memoria dinámica.

    Entonces podemos ver una ventaja de la listas sobre los arrays: No tener que redimensionar la estructura y poder agregar elemento tras elemento indefinidamente.

    Cuando uno ya ha trabajado con arrays (vectores y matrices) y empieza a estudiar las listas, se da cuenta que una restricción de las listas es el acceso a los elementos. En un vector podíamos hacer algo como v[50] y nos estábamos refiriendo al índice 50 del vector v. A esto se le conoce como acceso aleatorio.

    En el caso de las listas el acceso es secuencial, es decir, para acceder a un elemento del conjunto debemos de recorrer uno por uno los elementos hasta llegar al solicitado. Rápidamente se puede concluir que el tiempo de acceso a los elementos de un array es muchísimo más rápido que en una lista. Esta es una gran desventaja de las listas, por lo que buscar elementos por índice sería muy costoso. Esto no quiere decir que trabajar con arrays sea mejor que con listas. Las listas son muy flexibles y para muchos casos son imprescindibles.

    Bueno, aquí va la primera práctica que hice sobre listas enlazadas. Implementación de una clase Lista, clase Nodo y los siguientes métodos:

    • Añadir un elemento al inicio.
    • Añadir un elemento al final
    • Añadir un elemento de manera ordenada
    • Llenar la lista por teclado
    • Llenar la lista aleatoriamente
    • Imprimir la lista
    • Buscar un elemento
    • Eliminar un elemento por dato
    • Eliminar un elemento por posicion o índice
    • Eliminar toda la lista
    • Invertir una lista
    • Ordernar una lista
    • Cargar una lista desde archivo
    • Guardar la lista en un archivo
    • Concatenar una lista a otra
    • Intersección entre 2 listas

    Podrán ver la variable *temp en casi todos los métodos , este es el puntero de tipo Nodo que me va a permitir moverme a través de la lista y que inicialmente es igual a la cabeza (head). Mientras exista algo en la lista, voy avanzado el puntero para que apunte al siguiente. Esto se consigue en casi todos los casos con un while.

    While(temp)
    temp = temp->gte

    Otra operación común en los métodos es preguntar si inicialmente la lista está vacía, es decir, si la cabeza no contiene algo o es igual a Null.

    if(!head) o if(head==NULL)

    Apliqué mis limitados conocimientos de templates para tener una lista genérica y así pueda funcionar con varios tipos de datos y de verdad funciona.

    Ahí la definición e implementación de la clase, lista, clase nodo y el main para ver el funcionamiento. Cualquier crítica, sugerencia o comentarios son bienvenidos siempre.

    Nodo.h

    #ifndef NODO_H
    #define NODO_H
    #include <iostream>
    
    using namespace std;
    template <class T>
    class Nodo
    {
      public:
        T dato;
        Nodo *sgte;
        Nodo();
        Nodo(T);
        ~Nodo();
    
        void print();
        void eliminar();
    };
    
    #endif // NODO_H
    

    Nodo.cpp

    #include "Nodo.h"
    
    //constructor por defecto
    template<typename T>
    Nodo<T>::Nodo()
    {
      dato = NULL;
      sgte = NULL;
    }
    
    //constructor por parametro
    template<typename T>
    Nodo<T>::Nodo(T dato_)
    {
      dato = dato_;
      sgte = NULL;
    }
    
    //imprimir un nodo
    template<typename T>
    void Nodo<T>::print()
    {
      //cout << "Nodo-> " << "Dato: " << dato << " Direcion: " << this << " Siguiente: " << sgte << endl;
      cout << dato << "-> ";
    }
    
    //eliminar todos los nodos
    template<typename T>
    void Nodo<T>::eliminar()
    {
      if(sgte)
        sgte->eliminar();
      delete this;
    }
    
    template<typename T>
    Nodo<T>::~Nodo(){}
    

    Lista.h

    #ifndef LISTA_H
    #define LISTA_H
    
    #include <iostream>
    #include "time.h"
    #include <fstream>
    #include <string>
    #include "Nodo.h"
    #include "Nodo.cpp"
    
    using namespace std;
    
    template <class T>
    class Lista
    {
      private:
        int dim,num_nodos;
        T line;
        string archivo;
    
      public:
        T ele;
        Nodo<T> *head;
        Lista();
        ~Lista();
    
        void llenar_teclado(int);
        void llenar_aleatorio(int);
        void print();
        void add_end(T);
        void add_head(T);
        void add_sort(T);
        void search(T);
        void del_dato(T);
        void del_pos(int);
        void del_all();
    
        void invertir();
        void sort();
        void load(string);
        void save(string);
    
        void concat(Lista);
        void interseccion(Lista);
    };
    
    #endif // LISTA_H
    

    Lista.cpp

    #include "Lista.h"
    
    using namespace std;
    
    //constructor por defecto
    template<typename T>
    Lista<T>::Lista()
    {
      num_nodos = 0;
      head = NULL;
    }
    
    //llenar la lista por teclado
    template<typename T>
    void Lista<T>::llenar_teclado(int dim)
    {
      for(int i=0;i<dim;i++){
        cout << "Ingresa el elemento " << i + 1 << endl;
        cin >> ele;
        add_end(ele);
      }
    }
    
    //llenar la lista aleatoriamente para enteros
    template<typename T>
    void Lista<T>::llenar_aleatorio(int dim)
    {
      srand(time(NULL));
      for(int i=0;i<dim;i++){
        add_end(rand() % 100);
      }
    }
    
    //imprimir la lista
    template<typename T>
    void Lista<T>::print()
    {
      Nodo<T> *temp = head;
      if(!head){
        cout << "La lista esta vacia " << endl;
      } else{
        while(temp){
          temp->print();
          if(!temp->sgte) cout << "NULL";
          temp = temp->sgte;
        }
      }
      cout << endl << endl;
    }
    
    //insertar al final
    template<typename T>
    void Lista<T>::add_end(T dato_)
    {
      Nodo<T> *temp = head;
      Nodo<T> *nuevo = new Nodo<T> (dato_);
    
      if(!head){
          head = nuevo;
      } else{
        while(temp->sgte !=NULL){
          temp = temp->sgte;
        }
        temp->sgte = nuevo;
      }
      num_nodos++;
    }
    
    //insertar al inicio
    template<typename T>
    void Lista<T>::add_head(T dato_)
    {
      Nodo<T> *temp = head;
      Nodo<T> *nuevo = new Nodo<T> (dato_);
    
      if(!head){
        head = nuevo;
      } else{
        nuevo->sgte = head;
        head = nuevo;
        while(temp){
          temp = temp->sgte;
        }
      }
      num_nodos++;
    }
    
    //insertar de manera ordenada
    template<typename T>
    void Lista<T>::add_sort(T dato_)
    {
      Nodo<T> *nuevo = new Nodo<T> (dato_);
      Nodo<T> *temp = head;
    
      if(!head){
        head = nuevo;
      } else{
        if(head->dato > dato_){
          nuevo->sgte = head;
          head = nuevo;
        } else{
          while((temp->sgte != NULL) && (temp->sgte->dato < dato_)){
            temp = temp->sgte;
          }
          nuevo->sgte = temp->sgte;
          temp->sgte = nuevo;
        }
      }
      num_nodos++;
    }
    
    //buscar el dato de un nodo
    template<typename T>
    void Lista<T>::search(T dato_)
    {
      Nodo<T> *temp = head;
      int cont = 1;
      int cont2=0;
      while(temp){
        if(temp->dato == dato_){
    	  cout << "El dato se encuentra en la posicion: " << cont << " (Para seres humanos)" << endl;
    	  cont2++;
        }
    	temp = temp->sgte;
    	cont++;
      }
      if(cont2 == 0){
        cout << "No existe el dato " << endl;
      }
      cout << endl << endl;
    }
    
    //eliminar por dato del nodo
    template<typename T>
    void Lista<T>::del_dato(T dato_)
    {
      Nodo<T> *temp = head;
      Nodo<T> *temp1 = head->sgte;
    
      int cont=0;
    
      if(head->dato == dato_){
        head = temp->sgte;
      } else {
        while(temp1){
          if(temp1->dato == dato_){
    	    Nodo<T> *aux = temp1;
            temp->sgte = temp1->sgte;
            delete aux;
            cont++;
            num_nodos--;
          }
    	  temp = temp->sgte;
    	  temp1 = temp1->sgte;
        }
      }
      if(cont == 0){
        cout << "No existe el dato " << endl;
      }
    }
    
    //eliminar por posicion del nodo
    template<typename T>
    void Lista<T>::del_pos(int pos)
    {
      Nodo<T> *temp = head;
      Nodo<T> *temp1 = temp->sgte;
    
      if(pos < 1 || pos > num_nodos){
        cout << "Fuera de rango " << endl;
      } else if(pos==1){
        head = temp->sgte;
      } else{
        for(int i=2;i<=pos;i++){
          if(i==pos){
            Nodo<T> *aux = temp1;
            temp->sgte = temp1->sgte;
            delete aux;
            num_nodos--;
          }
          temp = temp->sgte;
          temp1 = temp1->sgte;
        }
      }
    }
    
    //eliminar todos los nodos
    template<typename T>
    void Lista<T>::del_all()
    {
      head->eliminar();
      head = 0;
    }
    
    //invertir la lista
    template<typename T>
    void Lista<T>::invertir()
    {
      Nodo<T> *temp = head;
      Nodo<T> *prev = NULL;
      Nodo<T> *next = NULL;
    
      while(temp){
        next = temp->sgte;
        temp->sgte = prev;
        prev = temp;
        temp = next;
      }
      head = prev;
    }
    
    //ordenar de manera ascendente
    template<typename T>
    void Lista<T>::sort()
    {
      T aux2;
      Nodo<T> *aux = head;
      Nodo<T> *temp = aux;
    
      while(aux){
        temp=aux;
        while(temp->sgte){
          temp=temp->sgte;
    
          if(aux->dato>temp->dato){
            aux2=aux->dato;
            aux->dato=temp->dato;
            temp->dato=aux2;
          }
        }
        aux=aux->sgte;
      }
    }
    
    //cargar una lista de un archivo
    template<typename T>
    void Lista<T>::load(string archivo)
    {
      ifstream in;
      in.open(archivo.c_str());
    
      if(!in.is_open()){
        cout << "No se puede abrir el archivo: " << archivo << endl << endl;
      } else{
        while(in >> line){
          add_end(line);
        }
      }
      in.close();
    }
    
    //guardar una lista en un archivo
    template<typename T>
    void Lista<T>::save(string archivo)
    {
      Nodo<T> *temp = head;
      ofstream out;
      out.open(archivo.c_str());
    
      if(!out.is_open()){
        cout << "No se puede guardar el archivo " << endl;
      } else{
        while(temp){
          out << temp->dato;
          out << " ";
          temp = temp->sgte;
        }
      }
      out.close();
    }
    
    //concatenar a otra lista
    template<typename T>
    void Lista<T>::concat(Lista Lista2)
    {
      Nodo<T> *temp2 = Lista2.head;
    
      while(temp2){
        add_end(temp2->dato);
        temp2 = temp2->sgte;
      }
    }
    
    //numeros que coinciden en 2 listas
    template<typename T>
    void Lista<T>::interseccion(Lista Lista2)
    {
      Nodo<T> *temp = head;
      Nodo<T> *temp2 = Lista2.head;//cabeza de la segunda lista
      Lista lista_interseccion;//creo otra lista
    
      int num_nodos2 = Lista2.num_nodos;//nodos de la segunda lista
      int num_inter=0;//numero de coincidencias
    
      //creo 2 vectores dinamicos
      T *v1 = new T[num_nodos];
      T *v2 = new T[num_nodos2];
    
      //lleno los vectores v1 y v2 con los datos de la lista original y segunda lista respectivamente
      int i=0;
      while(temp){
        v1[i] = temp->dato;
        temp = temp->sgte;
        i++;
      }
    
      int j=0;
      while(temp2){
        v2[j] = temp2->dato;
        temp2 = temp2->sgte;
        j++;
      }
    
      //ordeno los vectores
      insert_sort(v1,num_nodos);
      insert_sort(v2,num_nodos2);
    
      int v1_i= 0;//indice del 1er vector (v1)
      int v2_i= 0;//indice del 2do vector (v2)
    
      //mientras no haya terminado de recorrer ambas listas
      while (v1_i < num_nodos && v2_i < num_nodos2) {
        if(v1[v1_i] == v2[v2_i]){//cuando los datos de ambas sean iguales
          lista_interseccion.add_end(v1[v1_i]);//utilizo mi metodo add_end para llenar la lista de intersecciones
          v1_i++;
          v2_i++;
          num_inter++;
        } else if(v1[v1_i] < v2[v2_i]){
          v1_i++;
        } else{
          v2_i++;
        }
      }
    
      //Solo si hay alguna interseccion imprimo la nueva lista creada
      if(num_inter > 0) {
        cout << "Existen " << num_inter << " intersecciones " << endl;
        lista_interseccion.print();
      } else {
        cout << "No hay interseccion en ambas listas" << endl;
      }
    }
    
    //usado por el metodo interseccion
    template<typename T>
    void insert_sort(T a[],int tam)
    {
      T temp;
      for(int i=0;i<tam;i++){
        for(int j=i-1;j >=0 && a[j+1] < a[j];j--){
          temp = a[j+1];
          a[j+1] = a[j];
          a[j] = temp;
        }
      }
    }
    
    template<typename T>
    Lista<T>::~Lista(){}
    

    main.cpp

    #include <iostream>
    #include "Lista.h"
    #include "Lista.cpp" //por errores de linking de tipo "undefined reference to" (estudiando)
    
    using namespace std;
    int main()
    {
      Lista<int> l1;
      Lista<int> l2;
    
      int dim,pos;
      string archivo;
    
      cout << "Ingresa la dimension de la lista " << endl;
      cin >>dim;
    
      l1.llenar_aleatorio(dim);//llenar_teclado para otros tipos
    
      cout << "Lista A al inicio " << endl;
      l1.print();
    
      cout << "Agrega un elemento por la cabeza" << endl;
      cin >>l1.ele;
      l1.add_head(l1.ele);
      l1.print();
    
      cout << "Lista invertida " << endl;
      l1.invertir();
      l1.print();
    
      cout << "Lista ordenada " << endl;
      l1.sort();
      l1.print();
    
      cout << "Agrega un elemento (Sera ordenado)" << endl;
      cin >>l1.ele;
      l1.add_sort(l1.ele);
      l1.print();
    
      cout << "Busca un elemento" << endl;
      cin >>l1.ele;
      l1.search(l1.ele);
    
      cout << "Elimina un elemento por dato" << endl;
      cin >>l1.ele;
      l1.del_dato(l1.ele);
      l1.print();
    
      cout << "Elimina un elemento por posicion" << endl;
      cin >>pos;
      l1.del_pos(pos);
      l1.print();
    
      cout << "Cargar una lista desde archivo - Ingresa el nombre" << endl;
      cin >> archivo;//debe estar en el mismo directorio que este programa
      l2.load(archivo);
      cout << "Lista B" << endl;
      l2.print();
    
      cout << "Guardar la lista en un archivo - Ingresa el nombre" << endl;
      cin >> archivo;//ingresa un nombre cualquiera *.*
      l2.save(archivo);
    
      cout << "Interseccion entre las listas A y B " << endl;
      l1.interseccion(l2);
    
      cout << "Listas A y B concatenadas " << endl;
      l1.concat(l2);
      l1.print();
    
      l1.del_all();
      l1.print();
    
      return 0;
    }
    

    Un ejemplo de la salida del programa:

    Ingresa la dimension de la lista
    10
    Lista A al inicio
    55-> 60-> 31-> 5-> 4-> 51-> 9-> 27-> 68-> 62-> NULL
    
    Agrega un elemento por la cabeza
    18
    18-> 55-> 60-> 31-> 5-> 4-> 51-> 9-> 27-> 68-> 62-> NULL
    
    Lista invertida
    62-> 68-> 27-> 9-> 51-> 4-> 5-> 31-> 60-> 55-> 18-> NULL
    
    Lista ordenada
    4-> 5-> 9-> 18-> 27-> 31-> 51-> 55-> 60-> 62-> 68-> NULL
    
    Agrega un elemento (Sera ordenado)
    45
    4-> 5-> 9-> 18-> 27-> 31-> 45-> 51-> 55-> 60-> 62-> 68-> NULL
    
    Busca un elemento
    51
    El dato se encuentra en la posicion: 8 (Para seres humanos)
    
    Elimina un elemento por dato
    60
    4-> 5-> 9-> 18-> 27-> 31-> 45-> 51-> 55-> 62-> 68-> NULL
    
    Elimina un elemento por posicion:
    11
    4-> 5-> 9-> 18-> 27-> 31-> 45-> 51-> 55-> 62-> NULL
    
    Cargar una lista desde archivo - Ingresa el nombre
    prueba.txt // mi archivito prueba.txt tenia estos datos
    Lista B
    8-> 59-> 23-> 15-> 94-> 63-> 9-> 17-> 62-> 33-> NULL
    
    Guardar la lista en un archivo - Ingresa el nombre
    otralista.txt // abre tu archivo y mira el contenido
    Interseccion entre las listas A y B
    Existen 2 intersecciones
    9-> 62-> NULL
    
    Listas A y B concatenadas
    4-> 5-> 9-> 18-> 27-> 31-> 45-> 51-> 55-> 62-> 8-> 59-> 23-> 15-> 94-> 63-> 9->17-> 62-> 33-> NULL
    
    La lista esta vacia.
    

    Hasta pronto

    Written by Ronny Yabar Aizcorbe

    July 4, 2009 at 5:36 pm

    Posted in C++

    Operaciones con matrices – Clase Matriz en c++

    with 3 comments

    El siguiente es el primer ejercicio que hice con matrices. Quizás alguno de estos ejercicios te puedan servir como una base. Puedes leer el post anterior sobre vectores, matrices y punteros si aún no haz trabajo con ellos.

    Recomiendo que intentes y practiques mucho antes de copiar y pegar. Si te sientes estancado en algún problema recién trata de buscar una guía para llegar a la solución.

    Esta clase matriz tendrá 3 atributos: Matriz,número de filas y número de columnas. Tiene un constructor por defecto,constructor copiador y un constructor por parámetro que recibe el número de filas y columnas.

    Las siguientes funciones fueron implementadas:

    • Generar una matriz dinámicamente
    • LLenar la matriz desde teclado:
    • Llenar la matriz aleatoriamente:
    • Imprimir la matriz
    • Hallar el mayor elemento.
    • Hallar el menor elemento.
    • Hallar la moda.
    • Intercambiar filas.
    • Intercambiar columnas.
    • Sumar otra matriz: Sumar 2 objetos de tipo matriz retornar otra matriz. Ejem: c = a + b.
    • Restar otra matriz: Igual que la suma. Ejem: c= a – b
    • Multiplicar por otra matriz: Ejem: c = a * b. El nro de filas de a debe ser igual al nro de columnas de b
    • Multiplicar por un escalar: Ingreso un número y todos los elementos de la matriz se multiplican por ese número.
    • Hallar matriz transpuesta: matr[m][n] su transpuesta es matr[n][m]. Se obtiene cambiando filas por columnas. Donde los elementos de la fila m ahora pertenecen a la columna m de la transpuesta.
    • Verificar si es simétrica: Una matriz es simétrica si es cuadrada(filas=columnas) y cuando su transpuesta es igual a su matriz original.
    • Verificar si es identidad: Es identidad si tiene todos sus elementos nulos excepto los de la diagonal principal que son iguales a 1.

    NOTA: He aplicado un poco de templates para manejar la matriz con varios tipos de datos (int, float, char,double) y sobrecarga de operadores para la suma, resta y multiplicación de matrices.

    Recien estoy aprendiendo a usar estas 2 características importantes del lenguaje (templates y sobrecarga de operadores) por lo tanto, estos temas serán tratados a profundidad el proximo año.

    En breve:

    Un template es una manera de que funciones, clases métodos puedan ser usados con varios tipos de datos. Imagínense crear una lista de datos y tener que crear funciones insertar, eliminar, buscar, concatenar, etc para cada tipo de dato. Si los métodos y la clase tienen la misma lógica para que reescribir código si podemos reutilizar.

    La sobrecarga de operadores es una manera de realizar las mismas operaciones que solemos hacer con tipos de datos comunes con tipos abstractos de datos. Por ejemplo, la sobrecarga me permitió sumar 2 objetos de tipo Matriz y almacenar el resultado en otro objeto Matriz, del modo c = a + b

    Al grano:

    Definición de la clase Matriz (La cabecera o header):

    matriz.h

    #ifndef MATRIZ_H
    #define MATRIZ_H
    
    #include <iostream>
    #include <time.h>
    
    using namespace std;
    
    template <class T>
    class Matriz
    {
      private:
        T mayor_,menor_,moda_,ele,**matr1;
        int dim_matriz;
      public:
        int fils,cols;
        T escalar;
    
        Matriz();
        Matriz(int,int);
        Matriz(const Matriz &m);//constructor copia
    
        void llenar_teclado();
        void llenar_aleatorio();
        void imprimir();
    
        T mayor();
        T menor();
        T moda();
    
        void inter_filas(int,int);
        void inter_cols(int,int);
    
        bool esSimetrica();
        bool esIdentidad();
        void multi_escalar(T);
        void transpuesta();
    
        Matriz<T> operator+ (const Matriz &matr2);
        Matriz<T> operator- (const Matriz &matr2);
        Matriz<T> operator* (const Matriz &matr2);
    
        void eliminar();
    
        ~Matriz();
        protected:
    };
    
    #endif // MATRIZ_H
    

    Implemetanción de la clase:

    matriz.cpp

    #include "Matriz.h"
    
    //Constructor por defecto
    template<typename T>
    Matriz<T>::Matriz()
    {
      fils=4;
      cols=4;
    }
    
    //Constructor copia
    template<typename T>
    Matriz<T>::Matriz(const Matriz &m)
    {
      *this = m;
    }
    
    //Constructor por parametro
    template<typename T>
    Matriz<T>::Matriz(int fils_ , int cols_)
    {
      fils = fils_;
      cols = cols_;
      matr1 = new T*[fils];
      for(int i=0;i<fils;i++){
          matr1[i] = new T[cols];
      }
    }
    
    //Llenar aleatoriamente una matriz
    template<typename T>
    void Matriz<T>::llenar_aleatorio()
    {
      //srand(time(NULL));
      for(int i=0;i<fils;i++){
        for(int j=0;j<cols;j++){
          matr1[i][j] = rand() % 30;
        }
      }
      mayor_= matr1[0][0];
      menor_= matr1[0][0];
      srand(time(NULL));
    }
    
    //Llenar una matriz desde teclado
    template<typename T>
    void Matriz<T>::llenar_teclado()
    {
      for(int i=0;i<fils;i++){
        cout << "Fila " << i+1 << endl;
        for(int j=0;j<cols;j++){
          cout << "Ingresa el elemento " << j+1 << endl;
          cin >>ele;
          matr1[i][j] = ele;
        }
        cout << endl;
      }
      mayor_= matr1[0][0];
      menor_= matr1[0][0];
    }
    
    //Imprimir matriz
    template<typename T>
    void Matriz<T>::imprimir()
    {
      for(int i=0;i<fils;i++){
        for(int j=0;j<cols;j++){
          cout << matr1[i][j] << " ";
        }
        cout << endl << endl;
      }
      cout << endl << endl;
    }
    
    //Obtener el mayor de la matriz
    template<typename T>
    T Matriz<T>::mayor()
    {
      for(int i=0;i<fils;i++){
        for(int j=0;j<cols;j++){
          if(matr1[i][j] > mayor_){
            mayor_ = matr1[i][j];
          }
        }
      }
      return mayor_;
    }
    
    //Obtener el menor de la matriz
    template<typename T>
    T Matriz<T>::menor()
    {
      for(int i=0;i<fils;i++){
        for(int j=0;j<cols;j++){
          if(matr1[i][j] < menor_){
            menor_ = matr1[i][j];
          }
        }
      }
      return menor_;
    }
    
    //Obtener la moda de la matriz
    template<typename T>
    T Matriz<T>::moda()
    {
      //creo una matriz auxiliar
      Matriz maux(fils,cols);
    
      //lleno la matriz con ceros
      for(int i=0;i<fils;i++){
        for(int j=0;j<cols;j++){
          maux.matr1[i][j] = 0;
        }
      }
    
      dim_matriz = fils * cols;
      int y=0;//para retener una fila n veces
      int z=0;//para retener una columna n veces
    
      //empiezo a comparar cada elemento n veces
      for(int x=0;x<dim_matriz;x++){
        for (int i = 0; i < fils; i++){
          for (int j = 0; j < cols; j++){
            if(matr1[y][z] == matr1[i][j]){
              maux.matr1[i][j]++;//incremento en 1 el valor de la matriz aux en esa posicion
            }
          }
        }
        //pasar a la siguiente columna despues de n comparaciones
        z++;
        if(z==cols){//empiezo a comparar con la siguiente fila
          z=0;//empiezo nuevamente en la 1era columna
          y++;//paso a la siguiente fila
        }
      }
    
      //obtengo el valor mayor de la matriz
      mayor_ = maux.mayor();
    
      if(mayor_==1){//si ningun valor se ha repetido mas de una vez no hay moda
        return -1;
      } else {
        for(int i=0; i<fils;i++){
          for(int j=0;j<cols;j++){
            if(maux.matr1[i][j] == mayor_) {
              moda_ = matr1[i][j];
            }
          }
        }
      }
      return moda_;
    }
    
    //Intercambiar dos filas en una matriz
    template<typename T>
    void Matriz<T>::inter_filas(int fil1, int fil2)
    {
      if(fil1 > fils || fil2 > fils){
        cout << "Por favor, hasta cuando " << endl;
      } else {
        T temp;
        fil1--;
        fil2--;
    
        for(int i=0;i<cols;i++){
          temp = matr1[fil1][i];
          matr1[fil1][i] =  matr1[fil2][i];
          matr1[fil2][i] = temp;
        }
        cout << "Se intercambio la fila " << fil1 + 1 << " por la " << fil2 + 1 << endl;
        imprimir();
      }
    }
    
    //Intercambiar dos columnas en una matriz
    template<typename T>
    void Matriz<T>::inter_cols(int col1, int col2)
    {
      if(col1 > cols || col2 > cols){
        cout << "Por favor, hasta cuando " << endl;
      } else{
        T temp;
        col1--;
        col2--;
    
        for(int i=0;i<fils;i++){
          temp = matr1[i][col1];
          matr1[i][col1] =  matr1[i][col2];
          matr1[i][col2] = temp;
        }
        cout << "Se intercambio la columna " << col1 + 1 << " por la " << col2 + 1 << endl;
        imprimir();
      }
    }
    
    //Verificar si una matriz es simetrica
    template<typename T>
    bool Matriz<T>::esSimetrica()
    {
      if(fils!=cols) {
        return false;
      }
    
      for(int i=0;i<fils;i++){
        for(int j=0;j<cols;j++){
          if (matr1[i][j]!=matr1[j][i]){
            return false;
           }
        }
      }
      return true;
    }
    
    //Verificar si una matriz es identidad
    template<typename T>
    bool Matriz<T>::esIdentidad()
    {
      if(fils!=cols) {
        return false;
      }
    
      for(int i=0;i<fils;i++){
        for(int j=0;j<cols;j++){
          if (i == j) {
            if (matr1[i][j] != 1)
              return false;
          } else {
            if (matr1[i][j] != 0)
              return false;
          }
        }
      }
      return true;
    }
    
    //Multiplicar a una matriz por un escalar
    template<typename T>
    void Matriz<T>::multi_escalar(T escalar)
    {
      for(int i=0;i<fils;i++){
        for(int j=0;j<cols;j++){
          matr1[i][j] = matr1[i][j] * escalar;
        }
      }
      cout << "Se multiplico a la matriz por el escalar " << escalar << endl;
      imprimir();
    }
    
    //Obtener la transpuesta de una matriz
    template<typename T>
    void Matriz<T>::transpuesta()
    {
      Matriz matresult(cols,fils);
      for(int i=0;i<cols;i++){
        for(int j=0;j<fils;j++){
          matresult.matr1[i][j]= matr1[j][i];
        }
      }
      matresult.imprimir();
    }
    
    //Suma de matrices con sobrecarga de operadores
    template<typename T>
    Matriz<T> Matriz<T>::operator+ (const Matriz &matr2)
    {
      Matriz matresult(fils,cols);
      for (int i=0;i<fils;i++){
        for (int j=0;j<cols;j++){
    	  matresult.matr1[i][j] = matr1[i][j] + matr2.matr1[i][j];
        }
      }
      return matresult;
    }
    
    //Resta de matrices con sobrecarga de operadores
    template<typename T>
    Matriz<T> Matriz<T>::operator- (const Matriz &matr2)
    {
      Matriz matresult(fils,cols);
      for (int i=0;i<fils;i++){
        for (int j=0;j<cols;j++){
          matresult.matr1[i][j] = matr1[i][j] - matr2.matr1[i][j];
        }
      }
      return matresult;
    }
    
    //Multiplicacion de matrices con sobrecarga de operadores
    template<typename T>
    Matriz<T> Matriz<T>::operator* (const Matriz &matr2)
    {
      Matriz matresult(fils,matr2.cols);
      T total;
      for (int i=0;i<fils;i++){
        for (int j=0;j<matr2.cols;j++){
          for(int k=0;k<cols;k++){
              total += (matr1[i][k] * matr2.matr1[k][j]);
              //para mostrar lo que pasa
              /*cout << "(" << matr1[i][k] << " * " << matr2.matr1[k][j] << ")";
              if(k<cols-1){
                  cout << " + ";
              } else {
                  cout << " = " << total;//despues del ultimo muestro la suma
              }*/
          }
          //cout << endl;
          matresult.matr1[i][j] = total;
          total = 0;//para limpiar el total sumado arriba
        }
        cout << endl;
      }
      return matresult;
    }
    
    template<typename T>
    void Matriz<T>::eliminar()
    {
      for(int i=0;i<fils;i++){
        delete[] matr1[i];
      }
      delete[] matr1;
    }
    
    template<typename T>
    Matriz<T>::~Matriz(){}
    

    main.cpp

    #include <iostream>
    #include "Matriz.h"
    #include "Matriz.cpp"
    
    using namespace std;
    
    int main()
    {
        srand(time(NULL));//para no generar los mismos numeros aleatorios
        int fils,cols,fil1,col1,fil2,col2;
    
        cout << "Ingresa nro de filas " << endl;
        cin >> fils;
        cout << "Ingresa nro de columnas " << endl;
        cin >> cols;
        cout << endl;
    
        Matriz<int> a(fils,cols);
        Matriz<int> b(fils,cols);
        Matriz<int> c(fils,cols);//matriz para almacenar el resultado de las operaciones
    
        a.llenar_aleatorio();//existe el metodo llenar_teclado() para otros tipos
        b.llenar_aleatorio();
    
        cout << "Operaciones con matrices " << endl;
        cout << "Matriz A " << endl;
        a.imprimir();
    
        cout << "Matriz B " << endl;
        b.imprimir();
    
        cout << "Matriz A + B " << endl;
        c = a + b;
        c.imprimir();
    
        cout << "Matriz A - B " << endl;
        c = a - b;
        c.imprimir();
    
        cout << "Matriz A * B " << endl;
        c = a * b;
        c.imprimir();
    
        cout << "Operaciones basicas con la matriz A" << endl;
        cout << "Matriz A " << endl;
        a.imprimir();
    
        cout << "El mayor de la matriz es: " << a.mayor() << endl;
        cout << "El menor de la matriz es: " << a.menor() << endl;
        cout << "La moda de la matriz es: " << a.moda() << endl;
        cout << (a.esSimetrica() ? "" : "No") << " Es simetrica." << endl;
        cout << (a.esIdentidad() ? "" : "No") << " Es identidad." << endl;
        cout << endl;
    
        cout << "Ingresa el escalar " << endl;
        cin >>a.escalar;
        a.multi_escalar(a.escalar);
    
        cout << "Intercambio: Ingresa dos filas del 1 al " << fils << endl;
        cin >>fil1;
        cin >>fil2;
        a.inter_filas(fil1,fil2);
    
        cout << "Intercambio: Ingresa dos columnas del 1 al " << cols << endl;
        cin >>col1;
        cin >>col2;
        a.inter_cols(col1,col2);
    
        cout << "Transpuesta de A " << endl;
        a.transpuesta();
    
        a.eliminar();
        b.eliminar();
        c.eliminar();
    
        return 0;
    }
    

    Particularmente, todos los ejercicios no son nada difíciles de resolver, pero yo me estanqué en la moda y creo que fue el problema que me hizo pensar un rato.

    Lo resolví, pero sinceramente no me siento bien con la solución. No me gustó porque tiene una complejidad de O(n2) y con una matriz muy grande puede tarda mucho debido al número de recorridos y comparaciones.

    La solución consistió en:

    • Crear otra matriz auxiliar con el mismo nro de filas columas y llenarla con ceros.
    • Recorrer la matriz original e ir comparando el primer elemento con todos los otros elementos de la matriz y contar sus repeticiones y así sucesivamente con los demás elementos.
    • Si encuentro una repetición, incremento en uno el valor en esa posición de la matriz auxiliar.
    • Luego hallar el mayor elemento de la matriz auxiliar.
    • Y finalmente recorrer la matriz auxiliar, cuando algún elemento de esta matriz sea igual al mayor elemento, quiere decir, que ese fue el elemento que más se repitió en la matriz original. Por lo tanto la moda se encuentra en esa posición.
    Matriz original
    17 16 10 26
    10  3 9 19
    29 7  1 6
    6  20 0 10
    
    Matriz auxiliar al inicio
    0 0 0 0
    0 0 0 0
    0 0 0 0
    0 0 0 0
    
    Matriz auxiliar despues de las comparaciones
    con el nro de repeticiones de los valores
    1 1 3 1
    3 1 1 1
    1 1 1 2
    2 1 1 3
    

    La moda de la matriz es: 10,
    3 es el valor maximo que se repite en la matriz
    Y en las posiciones en que se encuentra 3 se encuentra 10 en la matriz original.

    Un tip que me dió el profe es reducir el nro de comparaciones creando una matriz booleana e ir poniendo unos y ceros a los números que ya comparé para luego no volver a comparar con los números que comparé anteriormente. Voy a seguir resolviendo el problema,si alguien tiene otra solución y puede explicarla fantástico.

    Si yu

    Written by Ronny Yabar Aizcorbe

    July 4, 2009 at 5:34 pm

    Posted in C++

    Vectores, Matrices y Punteros en c++

    with 19 comments

    Estimados lectores y fans, les pido disculpas por este humilde y sencillo post, se que este mini-tutorial super básico es una humillación a su inteligencia y profesionalismo, pero comprendan que esto va dedicado a personas que como yo recién empiezan con sus primeros pininos en C++. Espero de verdad le sea útil a alguien.

    Escribir todo esto, me costó una noche entera y mucho café. Parte de los conceptos aquí los aprendí en clases de la U y mucho también lo aprendí por cuenta propia. Así que agradecimientos al teacher Patricio del cual aprendí muchísimo. Una vez más a ustedes y a los tantos miles de seguidores que me leen a diario las disculpas del caso.

    Vamos ir avanzando de a pocos así que no se preocupen y desesperen porfavor, paciencia. La idea es que esta sección crezca con su ayuda, feedback y motivación. Luego vamos a ver ejemplos con objetos, clases, sobrecarga de operadores, métodos de búsqueda, màs ordenación, punteros, listas, pilas, colas, templates… por ahora sigo practicando y haciendo simples cosas con este lenguaje. Los códigos los compilé con g++, el compilador de GNU.

    VECTORES
    Un vector, también llamado array(arreglo) unidimensional, es una estructura de datos que permite agrupar elementos del mismo tipo y almacenarlos en un solo bloque de memoria juntos, uno despues de otro. A este grupo de elementos se les identifica por un mismo nombre y la posición en la que se encuentran. La primera posición del array es la posición 0.

    Podríamos agrupar en un array una serie de elementos de tipo enteros, flotantes, caracteres, objetos, etc. Crear un vector en c++ es sencillo, seguimos la siguiente sintaxix: Tipo nombre[tamanyo];

    Ejm:

    int a[5];//Vector de 5 enteros
    float b[5];//vector de 5 flotantes
    Producto product[5];//vector de 5 objetos de tipo Producto
    

    Podríamos también inicializar el vector en la declaración:

    int a[] = {5,15,20,25,30};
    float b[] = {10.5,20.5,30.5,12.5,50.5}
    Producto product[] = {celular,calculadora,camara,ipod,usb}

    Como hay 5 elementos en cada array, automáticamente se le asignará 5 espacios de memoria a cada vector.Pero si trato de crear el vector de la forma int a[]; el compilador mostrará un error, porque no indiqué el tamaño del vector ni tampoco inicializé sus elementos.

    Asigno valores a los elementos de un vector indicando su posición:

    int a[4] = 30; // le asigno el valor 30 a la posición 4 del vector, es decir, al 5to elemento.
    product[2].setPrecio(300) // le asigno un precio de 300 al producto en la posicion 2, o sea al tercer elemento. 

    Obviamente el método setPrecio() debe de estar implementado.

    Para llenar, recorrer e imprimir un vector podemos utilizar un bucle for:

    #include <iostream>
    using namespace std;
    
    int main()
    {
      int dim;
      cout << "Ingresa la dimension del vector" << endl;
      cin >> dim; // Supongamos que ingrese 10
      int vector[dim]; // mi vector es de tamanyo 10
    
      for(int i=0;i < dim;i++){
        vector[i] = i * 10;
        cout << vector[i] << " ";
      }
    
      return 0;
    }

    La salida del programa mostrará: 0 10 20 30 40 50 60 70 80 90

    Fàcil verdad? Bien ahora creen 2 o más vectores y empiecen a hacer funciones básicas como sumar, restar, buscar, ordenar, moda, etc que ayudan mucho a ir desarrollando la lógica. No vale copiar y pegar, mejor es practicar, practicar y practicar.

    Aquí una función simple para sumar 2 vectores a y b y poner el resultado en un tercer vector c

    #include <iostream>
    using namespace std;
    
    void sumar(int a[], int b[], int c[],int dim){
        for (int i=0; i<dim; i++) {
            c[i]=a[i] + b[i];
        }
    }
    
    void imprimir(int v[],int dim)
    {
       for(int i=0;i<dim;i++){
            cout << v[i] << " ";
       }
       cout << endl << endl;
    }
    
    int main()
    {
        int dim;
        cout << "Ingresa la dimension" << endl;
        cin >> dim;
    
        int a[dim];
        int b[dim];
        int c[dim];
    
        for(int i=0;i<dim;i++){
            a[i] = i * 10;
            b[i] = i * 5;
        }
    
        cout << "Vector A " << endl;
        imprimir(a,dim);
    
        cout << "Vector B " << endl;
        imprimir(b,dim);
    
        sumar(a,b,c,dim);
        cout << "Vector C " << endl;
    
        imprimir(c,dim);
        return 0;
    }

    Este programa me botaría (si ingreso una dimensión de 10):

    Vector A
    0 10 20 30 40 50 60 70 80 90

    VECTOR B
    0 5 10 15 20 25 30 35 40 45

    VECTOR C
    0 15 30 45 60 75 90 105 120 135

    Entonces para tomar en cuenta:

    Todo vector debe tener definido un tipo de dato.
    Todo vector necesita de una dimensión o tamanyo.
    El código de arriba se puede mejorar muchísimo con objetos y clases, este es solo un pequeño ejemplo.

    MATRICES
    Una matriz es un vector de vectores o un también llamado array bidimensional. La manera de declarar una matriz es c++ es similar a un vector:

    int matriz[fils][cols];

    int es el tipo de dato, matriz es el nombre del todo el conjunto de datos y debo de especificar el numero de filas y columnas. Las matrices también pueden ser de distintos tipos de datos como char, float, double,etc.

    Las matrices en c++ se almacenan al igual que los vectores en posiciones consecutivas de memoria. Usualmente uno se hace la idea que una matriz es como un tablero. Pero internamente el manejo es como su definicion lo indica, un vector de vectores, es decir, los vectores estan uno detras del otro juntos.

    La forma de acceder a los elementos de la matriz es utilizando su nombre e indicando los 2 subindices que van en los corchetes. Si Coloco int matriz[2][3]=10; //estoy asignando al cuarto elemento de la tercera fila el valor 10. No olvidar que tanto filas como columnas se enumeran a partir de 0.

    Bueno y para recorrer una matriz podemos usar igualmente un bucle. En este caso 2 for

    for(int i=0;i<fils;i++){
      for(int j=0;j<cols;j++){
        matriz[i][j] = i % j;
      }
    }

    PUNTEROS
    El valor de todas las variales que manejamos en nuestros programas se almacenan en memoria y tienen una dirección. Un puntero es una variable especial que apunta a la dirección de memoria de una variable. El puntero tiene a su vez su propia dirección. Todas estas direcciones tienen un formato hexadecimal.

    Los punteros son herramientas muy poderosas con muchas utilidades y enormes ventajas como veremos más adelante. A grandes rasgos, un puntero me permite desplazarme en la memoria, apuntar, redireccionar a ciertas variables, funciones, métodos, objetos sin necesidad de mover grandes bloques de datos, lo cual nos ahorra muchísimo el consumo de memoria en los programas.

    Un puntero se debe declarar de acuerdo al tipo de dato al que apunta. Ejem:

    int *var; //Un puntero llamado var que podra apuntar a cualquier variable de tipo entero.
    char *u;//puntero de tipo char
    Persona *per;//puntero de tipo persona

    Para determinar,asignar la dirección de una variable en c++, se usa el operador & y para obtener el contenido de un puntero utilizamos el operador * Ejem:

    int a;//entero
    int *b;//puntero a entero
    a = 20;//a tiene 20
    b=&a;//asigno la direccion de a al puntero b
    
    cout << b << endl; // imprira la direccion de memoria de a;
    cout << *b;// imprimira 20, osea el contenido de a

    Ahora analicemos las siguientes instrucciones y veamos como las variables van cambiando de valor en tiempo de ejecución:

    #include <iostream>
    using namespace std;
    int main () {
        int a=10;
        int b=20;
        int *p,*p2;//punteros de tipo entero
    
        cout << "ANTES" << endl;
        cout << "Variable a = " << a << endl;
    
        cout << "Direccion de a = " << &a << endl << endl;
    
        cout << "Variable b = " << b << endl;
        cout << "Direccion de b = " << &b << endl << endl;
    
        cout << "Contenido de p (BASURA)= " << *p << endl;//tiene basura al principio, podria inicializar con *p=0
        cout << "Direccion de p = " << &p << endl << endl;
    
        cout << "DESPUES" << endl;
        a++;//incremento a
        p= &a; //p ahora tiene a la direccion de a
    
        cout << "Contenido de p =  " << *p << endl;
    
        p = &b;//p ahora tiene la direccion de b
        *p +=20; // le sumo 20 al contenido de p, es decir, estoy incrementando el valor de b
    
        cout << "Variable a = " << a << endl;
        cout << "Variable b = " << b << endl << endl;
    
        p=&a;//p ahora tiene la direccion de a
        *p = a * 5;//contenido de p es igual al contenido de a * 5
    
        cout << "Contenido de p = " << *p << endl;
        cout << "Variable a = " << a << endl << endl;
    
        cout << "Contenido de p2 (BASURA) = " << *p2 << endl;//tiene basura al principio, podria inicializar con *p2=0
        cout << "Direccion de p2 = " << &p2 << endl << endl;
    
        p2 = p;//el contenido de p es asignado al contenido de p2
        *p2 +=15;//incremento 15 al contenido de p2
    
        cout << "Contenido de p2 = " << *p2 << endl;//igual al contenido de p
        p++;//p apunta a otra direccion de memoria,se desplaza 4 bytes en memoria
        cout << "Contenido de p (BASURA) = " << *p << endl;//el contenido de esa nueva direccion
    
        return 0;
    }
    

    La salida del programa:
    ANTES

    Variable a = 10
    Direccion de a = 0×22ff74

    Variable b = 2
    Direccion de b = 0×22ff70

    Contenido de p (BASURA)= -1017291943
    Direccion de p = 0×22ff6c

    DESPUES
    Contenido de p = 11
    Variable a = 11

    Variable b = 40
    Contenido de p = 55
    Variable a = 55

    Contenido de p2 (BASURA) = 2293680
    Direccion de p2 = 0×22ff68
    Contenido de p2 = 70

    Contenido de p (BASURA) = 2293680

    El contenido de p y p2 al principio es basura porque no tienen ningun valor asignado aun. Podriamos asignar el valor NULL a un puntero para luego posteriormente en algun problema que se me presente saber el estado del puntero y saber si contiene algo o no, así:

    int *p= NULL;

    ARITMÉTICA DE PUNTEROS

    En las ultimas sentencias del programa anterior:

    p++;
    cout << *p;

    Pueden visualizar que estoy incrementando el puntero p en 1. Esto quiere decir que el puntero se desplazara 4 bytes en memoria (en este caso por ser entero) y entonces apuntara a otra direccion. Por eso es que el nuevo contenido de p es basura o bueno el contenido de lo que tiene esa nueva direccion a la que apunta.

    Supongamos que definir un entero y puntero de tipo char:

    char c;
    char *d;
    
    d= &c;//asigno la direccion de c a d
    c='u';//asigno el valor u a mi variable c
    c--;//desplazo una posicion a c
    cout << *d;//

    No Imprimira ‘u’ porque fijense que desplazé c en sentido negativo 1 byte (los char ocupan a 1 byte). Es decir, que si d estaba apuntado a una direccion como por ejemplo 0×22ff99, despues del c– estara apuntando a algo como 0×22ff98

    Para tomar en cuenta cosas que no puedo hacer con punteros:

    int a=15;
    int *p;
    
    double *q;
    void *r;
    
    p = a; //No puedo hacer esto porque estoy asignando una variable a un puntero y un puntero es una direccion.
    p = &50; // 50 es un valor constante en este caso y no una variable,por lo tanto no tiene direccion
    p = &(a+1); //una expresion no tiene direccion
    p = 30;//igual que el primer error, 30 es un entero.
    &a = p;//no puedo cambiar la direccion de una variable
    p = q;//p es puntero de tipo entero y q de tipo double

    Un puntero de tipo void, es un puntero al cual le podemos asignar cualquier tipo de puntero. Por lo tanto si podriamos hacer esto:

    r = p;

    VECTORES Y PUNTEROS
    Cuando declaramos un vector int v[10];El nombre del vector, o sea v, es un puntero al primer elemento del vector, es decir a v[0].Entonces como un vector es un puntero al primer elemento del mismo, también podríamos hacer aritmética de punteros con el vector.

    (v+1) ;//apuntara a v[1];
    *(v+5);//me refiero al contenido de v[5]
    
    //Y también a los punteros les puedo poner índices:
    
    int *p; //puntero de tipo entero
    p = &v[0];//p apunta a la direccion del vector v[0] o tambien a v. p = v
    p[8] = 80; //le asigno el valor 80 al puntero en la posicion 8, es decir a v[8]
    

    VECTORES DINÁMICOS

    Lo que vimos en el inicio de este post, son vectores estáticos, puesto que tienen una cantidad fija de memoria asignada y tamaño definido que no podemos modificarlo. Sin embargo, un vector podría tener una cantidad variable de datos, a este se le llama un vector dinámico.

    Para usar vectores dinámicos necesitamos gestionar memoria dinámica. Si bien es cierto que es trae enormes ventajas, el hacer un mal uso de la memoria dinámica nos podría traer problemas desastrozos. Por eso es importante que que cuando creemos vectores dinámicos también liberemos la memoria utilizada. Obviamente eliminaremos la memoria utilizada cuando ya no necesitamos más usar, en este caso, un determinadao vector.

    El operador new sirve para reservar memoria dinámica.
    El operador delete se usa para liberar la memoria dinámica reservada con new.
    Para liberar memoria de un array dinámico usamos delete[]

    El espacio de memoria que hemos reservado con new tendrá vida hasta que finalize la ejecución del programa o cuando liberemos ese espacio con delete. Siempre es recomendable liberar memoria para posteriormente no tener problemas con excesivo consumo de memoria.

    Un simple ejem:

    #include <iostream>
    using namespace std;
    
    int main()
    {
        int *pv;
        int dim;
    
        cout << "Ingresa el tamanyo del vector" << endl;
        cin >>dim;
        pv = new int[dim];
    
        for(int i=0;i<dim;i++){
            pv[i] = i * i;
            cout << pv[i] << " ";
        }
    
        delete[] pv;
        return 0;
    }

    MATRICES Y PUNTEROS

    Supongamos que se declaró una matriz int m[5][5]

    Como dijimos anteriormente, el nombre o identificador de un vector es un puntero al primer elemento del vector. En el caso de matrices el nombre de la matriz, en este ejemplo v, es un puntero que apunta al primer elemento del primer vector de la matriz. Entonces m es un doble puntero.m es igual a &m[0] que es igual a la direccion de &m[0][0].

    Si declaramos un puntero int *pm y luego igualamos pm = m, p ahora puede desplazarse por los valores de m.

    *p;//contenido de m[0],el cual apunta al primer elemento de ese vector, es decir, m[0][0]

    También puedo referirme a los contenidos con aritmética de punteros

    *(p+1);//Desplazo una posicion a p,se refiere al contenido de m[1],el cual apunta al primer elemento de ese vector, es decir, m[1][0]
    *(*(p+1)+1);//desplazo una posición en el vector principal y este a su vez se desplaza una posicion en ese vector. es decir,me refiero al contenido de m[1][1];
    
    p[2][4] = 20;//asigno el valor 20 a la posicion 2,4 de la matriz
    *(*(p+2)+4) = 20 // es lo mismo que la asignacion anterior
    *(pm[2]+4) = 20  // tambien los mismo
    
    //En conclusión:
    p[i][j] = *(*(p+i)+j) = *(pm[i]+j)
    

    MATRICES DINÁMICAS

    Para crear una matriz dinámica debemos de crear un doble puntero int **pm y samos al igual que los vectores el operador new para reservar memoria y delete para liberar.

    Primero tenemos que crear el vector que contendrá a otros vectores especificando el numero de vectores que tendra este vector principal. Ejem:

    pm = new int* [fils];//creo el vector de punteros principal
    for(int i=0;i<fils;i++){
      pm[i] = new int [cols];//para crear los vectores dentro del vector principal
    }
    

    Ahora sí vamos al grano y veamos un simple programa que crea una matriz dinámica, asigna valores, muestra el contenido de cada uno de los elementos los elementos así como sus direcciones de memoria.

    También mostramos la matriz usando aritmética de punteros,ahí va:

    #include <iostream>
    using namespace std;
    
    int main()
    {
      int **pm;//puntero a una matriz
      int fils,cols;
    
      cout << "Ingresa el nro de filas: ";
      cin >>fils;
    
      cout << endl;
      cout << "Ingresa el nro de columnas: ";
      cin >>cols;
    
      pm = new int* [fils];
      for(int i=0;i<fils;i++){
        pm[i] = new int [cols];
      }
    
      cout << "Elementos de la Matriz con sus direcciones" << endl;
      for(int i=0;i<fils;i++){
        for(int j=0;j<cols;j++){
          pm[i][j] = i + j;
          cout << pm[i][j] << "--> ";
          cout << &pm[i][j] << " ";
        }
        cout << endl;
      }
      cout << endl;
    
      cout << "La matriz con aritmetica de punteros" << endl;
      for(int i=0;i<fils;i++){
        for(int j=0;j<cols;j++){
          *(*(pm+i)+j) = i + j;//aritmetica de punteros
          cout << *(*(pm+i)+j) << "-->";
          cout << &pm[i][j] << " ";
        }
        cout << endl;
      }
    
      for(int i=0;i<fils;i++){
        delete[] pm[i];//elimino cada vector de la matriz
      }
      delete[] pm;//elimino el vector principal
      return 0;
    }
    

    La salida del programa:

    Ingresa el nro de filas: 6
    Ingresa el nro de columnas: 4

    //Elementos de la Matriz con sus direcciones
    0–> 0×3d2c90 1–> 0×3d2c94 2–> 0×3d2c98 3–> 0×3d2c9c
    1–> 0×3d2ca8 2–> 0×3d2cac 3–> 0×3d2cb0 4–> 0×3d2cb4
    2–> 0×3d2cc0 3–> 0×3d2cc4 4–> 0×3d2cc8 5–> 0×3d2ccc
    3–> 0×3d3ab8 4–> 0×3d3abc 5–> 0×3d3ac0 6–> 0×3d3ac4
    4–> 0×3d3ad0 5–> 0×3d3ad4 6–> 0×3d3ad8 7–> 0×3d3adc
    5–> 0×3d3ae8 6–> 0×3d3aec 7–> 0×3d3af0 8–> 0×3d3af4
    
    //La matriz con aritmetica de punteros
    0–> 0×3d2c90 1–> 0×3d2c94 2–> 0×3d2c98 3–> 0×3d2c9c
    1–> 0×3d2ca8 2–> 0×3d2cac 3–> 0×3d2cb0 4–> 0×3d2cb4
    2–> 0×3d2cc0 3–> 0×3d2cc4 4–> 0×3d2cc8 5–> 0×3d2ccc
    3–> 0×3d3ab8 4–> 0×3d3abc 5–> 0×3d3ac0 6–> 0×3d3ac4
    4–> 0×3d3ad0 5–> 0×3d3ad4 6–> 0×3d3ad8 7–> 0×3d3adc
    

    En mi caso esa son las direcciones de memoria. Bueno ya que hemos revisado conceptos básicos a continuación veamos la Clase Matriz, su definición, algunos métodos y su implementación.

    Written by Ronny Yabar Aizcorbe

    July 4, 2009 at 5:32 pm

    Posted in C++

    Tail recursion

    with 3 comments

    La recursividad es una técnica de programación que consiste en que una serie de instrucciones se repiten como una subtarea de la tarea principal, es decir, las funciones, procesos o rutinas se llaman a sí mismos cada vez que lo requieran y se ejecutan repetidas veces hasta que se satisface una condición específica.

    Sin embargo, la recursividad en algunos casos, tiene un costo computacional alto, debido a las constantes llamadas a la misma función, rutina y muchas veces estas llamadas consumen demasiada memoria.

    En algunos algoritmos recursivos, se puede implementar un caso de recursividad especial llamado Tail Recursion (recursividad por cola), la cual es una técnica para optimizar la recursividad eliminando las constantes llamadas recursivas. Tail recursion es cuando la llamada recursiva es la última instrucción de la función.

    Sin embargo, las funciones tail recursive deben cumplir la condición que en la parte que realiza la llamada a la función, no debe existir ninguna otra sentencia.

    Una ventaja de la recursividad por cola es que podemos evitar la sobrecarga de cada llamada a la función y nos evitamos el gasto de memoria de pila. Con una función tail recursive se puede evitar lo que se conoce como stack overflow, que ocurre cuando la pila de llamadas (call stack) consume mucha memoria.

    Veamos esta técnica con un ejemplo muy conocido que es encontrar el factorial de un número.

    Esta simple función obtiene el factorial de un número de la manera recursiva convencional: La explicación es sencilla, llamamos a la misma función fact hasta que n sea igual a 1, en ese momento la recursividad se detiene.

    int fact_recursivo(int n)
    {
      if(n == 1)
        return n;
      else
        return n * fact_recursivo(n-1);
    }
    
    int main() {
      int num=0;
      cout << "Ingresa un nro " << endl;   cin >> num;
    
      cout << "Su factorial es " << fact_recursivo(num);
      return 0;
    }
    

    Digamos que ingresé 15, si compilamos el programa la función me daría 2004310016, lo cual es correcto, pero hay que tener en cuenta todas las llamadas recursivas que hizo la función fact_recursivo, es decir, la función tiene que calcular el factorial de 14 y este el fact de 13, y este el fact de 12… sucesivamente hasta 1.  Tenemos un crecimiento del número de llamadas recursivas.

    Ahora vamos a realizar la misma función usando tail recursion. En este caso no se necesita guardar un marco de pila para cada llamada recursiva, y el algoritmo se comporta como si fuera iterativo.

    Para conseguir esto usamos un parámetro adicional que actúa como acumulador.

    Esta sería la función factorial con tail recursion:

    //function factorial con tail recursion
    int fact_tail_sum(int n, int sum) {
      if(n == 1) {
        return sum;
      } else {
        return fact_tail_sum(n - 1, sum*n);
      }
    }
    
    //para mantener la sintaxis original de como se llama a la función factorial
    int fact_tail(int n) {
      return fact_tail_sum(n, 1);
    }
    
    int main() {
      int num=0;
      cout << "Ingresa un nro " << endl;   cin >> num;
      cout << "Su factorial es " << fact_tail(num);
      return 0;
    }
    

    El resultado igualmente sería 2004310016, pero el costo computacional baja drásticamente debido a que cuando se hace la llamada return fact_tail_sum(n – 1, sum*n) ambos parámetros son inmediatamente resueltos. Con esta llamada podemos calcular sin esperar una llamada a una función recursiva para que nos devuelva un valor.

    En este caso el compilador reduce drásticamente el uso de la pila y la cantidad de información que debe ser almacenada, el valor de n y sum es independiente del número de llamadas recursivas.

    Una función recursiva normal se puede convertir a tail recursive usando en la función original un parámetro adicional, usado para ir guardando un resultado de tal manera que la llamada recursiva ya no tiene una operación pendiente.

    También se usa una función adicional para mantener la sintaxis de como llamamos normalmente a la función. En el caso del factorial, para seguir llamando a la función de la forma fact(n).
    En conclusión:

    • Una llamada es tail recursive (recursiva por cola) si no tiene que hacer nada más después de la llamada de retorno.
    • Tail recursion es cuando la llamada recursiva es la última instrucción en la función.
    • Usar tail recursion es muy ventajoso, porque la cantidad de información que debe ser almacenada durante el cálculo es independiente del número de llamadas recursivas.
    • El compilador trata una función tail recursive como si fuera una función iterativa.

    Written by Ronny Yabar Aizcorbe

    May 19, 2009 at 10:30 pm

    Posted in C++

    Quicksort en C++

    with 6 comments

    Quicksort es un algoritmo de ordenación  considerado entre los más rápidos y eficientes. Fue diseñado en los años 60s por C. A. R. Hoare un científico en computación. El algoritmo usa la técnica divide y vencerás que básicamente se basa en dividir un problema en subproblemas y luego juntar las respuestas de estos subproblemas para obtener la solución al problema central.

    Me pareció una buena manera de practicar programación y C++ y hacer una explicación que permite entender este algoritmo , bueno al menos eso intenté.  Hace año y medio también publiqué unos ejemplos de ordenación en Haskell.

    Voy a explicar el funcionamiento del quicksort brevemente y después veremos su implementación en C++.

    Se tiene una array de n elementos, tomamos un valor del array como pibote(usualmente el primero), separamos los elementos menor a este pibote a laizquierda y los mayores a la derecha, es decir, dividimos el array en 2 subarrays.

    Con estos subarrays se repite el mismo proceso de forma recursiva hasta que estos tengan más de 1 elemento. Por lo tanto la función quicksort quedaría de la siguiente manera:

    void quicksort(int *array, int inicio, int fin)
    {
      int pivote;
      if (inicio < fin) {
        pivote = dividir(array, inicio, fin );
        quicksort( array, inicio, pivote - 1 ); //ordeno la lista de los menores
        quicksort( array, pivote + 1, fin ); //ordeno la lista de los mayores
      }
    }
    

    La magia está en la función dividir que es la que voy a explicar a
    continuación:

    Empezamos creando o generando un array de n elementos, por ejemplo yo use la función rand() de c++ para generar aleatorios del 1 al 15, mi arreglo quedó así:

    a[] = {8, 1, 5, 14, 4, 15, 12, 6, 2, 11, 10, 7, 9};

    izq                                                                              der

    0 1 2 3 4 5 6 7 8 9 10 11 12
    8 1 5 14 4 15 12 6 2 11 10 7 9

    Tomamos como pibote el 8 y usamos 2 índices que me indiquen la posición del array:

    Uno que vaya de izquierda a derecha buscando los elementos mayores al pibote. a[izq]

    Y un índice que busque de derecha a izquierda los elementos menores al pibote.  a[der]

    El índice izquierdo irá aumentando en 1 mientras el array en la posición
    izquierda sea menor o igual al pibote:

    while ((izq < der) && (array[izq] <= pibote)){
      izq++;
    }
    

    El índice derecho irá reduciéndose en 1 mientras el array en la posición
    derecha sea mayor al pibote.

    while (array[der] > pibote){
      der--;
    }
    

    Si al final de estas 2 operaciones, el índice izquierdo es menor al derecho se intercambian las posiciones a[izq] con a[der], usando una variable temporal:

    En este caso, en la primer recorrido el índice izquierdo encuentra al 14 (mayor al pibote) y el índice derecho al 7 (menor al pibote), y
    se intercambian los índices:

    8 1 5 14 4 15 12 6 2 11 10 7 9
    8 1 5 7 4 15 12 6 2 11 10 14 9

    Segundo recorrido: El índice izquierdo encuentra al 15 (mayor al
    pibote) y el índice derecho al 2 (menor al pibote), se intercambian:

    8 1 5 7 4 15 12 6 2 11 10 14 9
    8 1 5 7 4 2 12 6 15 11 10 14 9

    Tercer recorrido: El índice izquierdo encuentra al 12 (mayor al
    pibote) y el índice derecho al 6 (menor al pibote), se intercambian:

    8 1 5 7 4 2 12 6 15 11 10 14 9
    8 1 5 7 4 2 6 12 15 11 10 14 9

    Cuando los índices se juntan o se cruzan ponemos el pibote en el lugar que le corresponde en el array:

    temp = array[der];
    array[der] = array[inicio]; // el pibote está en el inicio del array
    array[inicio] = temp;
    

    Se intercambian el 8 con el 6 y el array quedaría así:

    6 1 5 7 4 2 8 12 15 11 10 14 9

    Ahora la función quicksort se llamaría 2 veces recursivamente para los 2 subarray que tenemos:

    quicksort(a,0,5) // el pibote está en la posición 6
    quicksort(a,7,12) // el pibote está en la posición 6
    

    Se repite el mismo proceso con este primer subarray quicksort(a, 0, 5)

    El pibote es 6, se encuentra por la izquierda al 7 y por la derecha al 2. Se intercambian y como se cruzaron los índices movemos el pibote a su lugar:

    6 1 5 7 4 2
    6 1 5 2 4 7
    4 1 5 2 6 7

    Otra vez tenemos 2 subarrays. Entonces se vuelve a llamar la función

    quicksort(a,0,3) // la posición del pibote es 4
    quicksort(a,5,5) // No se ejecuta nada, el inicio no es menor al final
    

    El mismo proceso. Se ejecutar quicksort (a, 0, 3). El pibote ahora es 4, se encuentra por el índice izquierdo al 5 y por el derecho a 2.  Se intercambian y como se juntaron los índices se mueve el pivote a su lugar.

    4 1 5 2
    4 1 2 5
    2 1 4 5
    quicksort (a,0,1) // la posición del pibote es 2
    quicksort (a,3, 3) // No se ejecuta nada, el inicio no es menor al final
    

    Cuando se ejecuta quicksort (a, 0, 1) se intercambia los índices otra vez.

    2 1
    1 2

    Ahora se llamaría a quicksort(a, 0,0), se divide en 2 elementos el subarray
    y no hay nada más que hacer por que solo tienen 1 elemento.

    Ahora se ejecuta el mismo proceso con el segundo subarray del array original. Quicksort (a, 7,12)

    Se encuentra el 15 y el 9, se intercambian y como luego se juntan los índices, se coloca el pibote a su lugar:

    12 15 11 10 14 9
    12 9 11 10 14 15
    10 9 11 12 14 15

    Tenemos otros 2 subarrays y se vuelve a llamar la función quicksort

    quicksort(a,7,10) // posición del pibote es 10 y la 1era 7
    quicksort(a,11,12) //posición del pibote es 10 y la ultima 12
    

    Se intercambian los índices y nos quedan otros 2 subarrays de 1 solo elemento entonces no se ejecuta nada.

    10 9 11
    9 10 11

    Con el anterior subarray (14, 15) se llama a quicksort(a, 11,12).

    14 15

    Se divide en 2 elementos este subarray y no hay nada más que hacer por que los array que contienen al 14 y al 15 solo tienen 1 elemento.

    De manera que el árbol recursivo de ordenación queda más o menos así:

    Quick Sort

    Quick Sort

    Complejidad computacional del Quicksort:

    En el mejor de los casos tiene un costo de O(n*log (n)). Que es cuando el pibote siempre queda al medio del arreglo.

    quicksort

    Quicksort Mejor caso

    En el peor de los casos tiene un costo de O(n^2). Cuando el pibote siempre se inclina hacia a un lado, es decir, genera una array de sólo 1 elemento y una segunda con el resto de elementos.

    quicksort

    Quicksort peor caso

    En el caso promedio también tiene un costo de O(n*log (n)). Se produce cuando el pibote se inclina más hacia un lado y los 2 subarrays tienen distinto tamaño de elementos.

    quicksort

    Quicksort caso promedio

    Para calcular el tiempo de ejecución estoy usando la función clock() que determina el tiempo usado por el procesador. En este caso defino 3 variables ini, final y total.

    ini=clock(); // Antes del quicksort:
    final = clock(); //Después que se ejecuta el quicksort
    total =((double)(final – ini)) /
    CLOCKS_PER_SEC; // El valor retornado por clock()
    debe ser dividido por el valor de la macro CLOCKS_PER_SEC
    

    He leído en varios sitios de c++ que la función clock no tiene mucha precisión. Si alguien sabe un mejor método para calcular el tiempo de ejecución, algún comentario, sugerencia o aporte para optimizar al algoritmo, bienvenido.

    Queda pendiente para otro post calcular con exactitud tiempos de ejecución e implementar el código del número de comparaciones e intercambios.

    Bueno, aquí está la implementación del algoritmo en C++ disfrutenlo.

    #include <iostream>
    #include <time.h>
    #include <stdio.h>
    
    using namespace std;
    
    //funcion para dividir el array y hacer los intercambios
    int dividir (int *array, int inicio, int fin){
      int izq;
      int der;
      int pibote;
      int temp;
    
      pibote = array[inicio];
      izq = inicio;
      der = fin;
    
      //Mientras no se cruzen los índices
      while (izq < der){
        while (array[der] > pibote){
    	  der--;
        }
    
    	while ((izq < der) && (array[izq] <= pibote)){
          izq++;
        }
    
        // Si todavia no se cruzan los indices seguimos intercambiando
    	if(izq < der){
          temp= array[izq];
          array[izq] = array[der];
          array[der] = temp;
        }
      }
    
      //Los indices ya se han cruzado, ponemos el pivote en el lugar que le corresponde
      temp = array[der];
      array[der] = array[inicio];
      array[inicio] = temp;
    
      //La nueva posición del pivote
      return der;
    }
    
    //funcion recursiva para hacer el ordenamiento
    void quicksort( int *array, int inicio, int fin)
    {
      int pivote;
      if(inicio < fin){
        pivote = dividir(array, inicio, fin );
        quicksort( array, inicio, pivote - 1 );//ordeno la lista de los menores
        quicksort( array, pivote + 1, fin );//ordeno la lista de los mayores
      }
    }
    
    int main()
    {
      int const max = 100;
      int tamanyo;
      clock_t ini, final;
      double total;
      ini=clock();
    
      cout << "Ingresa tamanyo " << endl;
      cin >> tamanyo;
    
      int a[tamanyo];
      srand(time(0));//para que el rand no genere siempre los mismos numeros, utilizando la hora del sistema
    
      for (int i = 0; i < tamanyo; i++){
        a[i] = rand() % max;//rand para generar enteros aleatorios
      }
    
      cout << "Array antes de ordenarse: " << endl;
      for (int i=0; i < tamanyo; i++){
        cout << a[i] << " ";
      }
    
      cout << endl << endl;
    
      quicksort(a, 0, tamanyo - 1 );
    
      final=clock();
      total=((double)(final - ini)) / CLOCKS_PER_SEC;
      printf("Tiempo de ejecucion : %lf segundos \n",total);
    
      cout << "Array ordenado " << endl;
    
      for (int i=0; i < tamanyo; i++ ){
        cout << a[i] << "-";
      }
      cout << endl << endl;
    
      return 0;
    }
    

    Written by Ronny Yabar Aizcorbe

    May 19, 2009 at 7:02 pm

    Posted in C++

    Cuentos Chinos de Andrés Oppenheimer

    leave a comment »

    Oppenheimer, es uno de los mejores periodistas de América Latina con muchas distinciones y premios internacionales. A mí me gusta su análisis crítico, constructivo siempre acompañado con un buen fundamento. Aquí en Perú se emite su programa, Oppenheimer Presenta, los domingos a las 8pm por Canal N.

    He visto programas y entrevistas muy interesantes, muchas veces sus programas tienen bastante carga política, pero otras veces se habla mucho de trabajo, tecnología, oportunidades de mejora, estudios, cultura, problemas y educación en latinoamérica.

    Una de las entrevistas que más disfrute, fue la que le hizo a Bill Gates (No fui, ni soy fan de este hombre por sus malas prácticas, acciones y actitudes malévolas) y no porque sea un hombre ligado a la computación, sino porque Bill, tiene una visión muy clara en cuanto al tema de innovación, investigación y desarrollo.

    En la entrevista, dejó muy en claro, la relación inmensa que existe en EE.UU. entre empresa-universidad-mercado. Habló de las mejores universidades del mundo, de como se realizan exitosamente grandes proyectos de investigación, de la fuerte inversión por parte del gobierno americano en cuanto a desarrollo tecnológico-científico y también tocó el tema de como la India y China están haciendo enormes esfuerzos por ser las futuras potenciales mundiales.

    Bueno, el libro que voy a comentar, Cuentos Chinos, tiene mucho que ver con el tema de educación, ciencia y tecnología. Básicamente, lo que plantea Oppenheimer es una seria de falsas creencias, ideas y modos de ver el desarrollo y crecimiento de un país que tienen muchas personas influyentes en latinoamérica. Por esas razones es que estamos distanciados de EE.UU, Europa y varios países de Asia en temas de educación, trabajo, calidad de vida, niveles de pobreza, infraestructura, salud, etc.

    Entonces en varios capítulos habla concretamente de algunos países latinoamericanos, de sus presidentes, políticos y como sus ideas obsoletas, equivocadas han llevado a varios años de retraso. No hay que ser genio, para suponer que toco el tema de Venezuela-Hugo Chávez y todo el daño que este hombre le hace a la región y específicamente a Venezuela.

    Un ejemplo pequeño que pone es que mientras en China recibieron con alfombra a un alto ejecutivo de McDonald’s para que esa enorme empresa se instale e invierta millones de dolares en China, Hugo Chávez amenaza violentamente a la misma empresa si intenta poner un solo pie en sus país, y seguramente ustedes ya conocen su discurso anti-americano.

    Es decir, que mientras en China con esa inversión, se crean miles puestos de trabajo y su economía se sigue moviendo, Huguito hace que en su país muchas personas sigan pasando hambre, tan solo por un sentimiento nacionalista. Yo lo veo de este modo, es como que grandes empresas de tecnología (Google, Nokia, Apple, …) quieran instalarse en Perú, contratar a peruanos para desarrollar tecnología de punta y salga por ahí un idiota que diga que está desacuerdo porque es una multinacional y va a frenar a los emprendedores e innovadores en Perú.

    Ese pensamiento, de buscar frenar a toda costa la inversión extranjera, se repite muchas veces en los países subdesarrollados y eso obviamente estanca el desarrollo y crecimiento económico, social.

    Oppenheimer dedica un capítulo a Brasil, uno a Argentina y uno a México. Sinceramente estos capítulos no me gustaron mucho, no por las ideas planteadas, sino porque a pesar que son historias distintas, en sí, la misma idea se repite: Decisiones e ideas erróneas de presidentes y políticos de esos países. Muchas anécdotas y entrevistas, que sinceramente no quisiera mencionar.

    Mejor, para mi gusto, son los otros capítulos, en ellos realmente es donde disfruto el libro de Oppenheimer, pues muestra el enorme crecimiento del continente asiático, como países muy pobres de Europa años atrás, ahora son los países más ricos del mundo.

    China
    El capítulo 2 del libro, es sumamente interesante por todo lo que cuenta Oppenheimer en su visita a China. Cómo desde el primer día que llegó se sentía un extraño en un país de extraterrestres por las gigantescas construcciones ultra modernas: rascacielos, aeropuertos, centros comerciales, etc.

    En China, están los centros comerciales más grandes del mundo y Beijing es como Nueva York a inicios del siglo XX, una ciudad que crece cada minuto y se está convirtiendo en el centro del mundo.

    Se dio cuenta al instante que estaba en un país en auge económico, creciendo en varios factores, lleno de tecnología y sobretodo mucho optimismo y deseos de superación por parte de sus pobladores. Según el Consejo Nacional de Inteligencia (CNI), centro de estudios a largo plazo de la CIA, China se está convirtiendo en una gran potencia mundial y será el principal rival económico, político y militar de EE.UU.

    El CNI, también pronostica que las economías de China e India tendrán un fuerte impacto a nivel mundial y que las compañías multinacionales tendrán una orientación más asiática y menos occidental.

    ¿Por qué esta creciendo tanto China?
    Entre otros factores, específicamente desde 1978, es que dieron la bienvenida al capitalismo y desde ese año no han parado de recibir inversiones extranjeras y nacionales. Por todas esas miles de inversiones, en China aproximadamente más de 250 millones de personas han dejado de ser pobres y pasado a la clase media y se estima que ya hay más de 10 mil ricos con fortunas que superan los 10 millones de dólares cada uno.

    La nueva consigna de China es privatizar. En una de sus principales entrevistas a funcionarios chinos, Oppenheimer cuenta su conversación con Zhou Xi-an del Ministerio Nacional de Desarrollo y Reforma y le pregunta ¿Que porcentaje de la economía China esta en manos privadas? La respuesta no es sorprendente: “El estado chino actualmente controla menos del 30% del producto bruto nacional, mientras que un 60% está en manos privadas y un 10% en colectivas.

    En China ya hay mas de 3,8 millones de empresas privadas que son las que mueven el desarrollo de la economía del país y gracias a ellas existen miles de puestos de trabajo que además no dejan de crecer rápidamente”.

    Otra de las cosas que me sorprendió al leer este capítulo, es que la salud y la educación en China, ya han dejado de ser gratuitas, claro excepto para los becados. Pero en sí, la gente paga por esos servicios.

    Y aquí me acordé de algo interesante que dijo Bill en la entrevista que les comente anteriormente. La educación no debería ser gratuita, pues una institución educativa al recaudar dinero podría financiar fuertes proyectos de investigación, mejorar su infraestructura y seguir creciendo, eso a largo plazo haría más grande aún a esa institución y los estudiantes tendrían una educación de mejor calidad.

    Y aunque China sigue en un crecimiento económico acelerado, también se toca , en este capítulo, el tema de la democracia en China, la falta de libertad de prensa, la desigualdad y la censura. Por ejemplo, la censura en Internet, es imposible visitar varios sitios web que hablan de derechos humanos, igualdad, Tibet y cualquier otro tema que critique o hable algo en contra de China.

    Según estimaciones, hay unos 30 mil informáticos trabajando a toda hora controlando el acceso a Internet en China. Si aparece alguna página web, artículo, noticia o algún contenido que hable tan solo algo mal de China, desaparece a los 5 minutos por arte de magia, realmente impresionante.

    Irlanda: El milagro Irlandés
    Capítulo 3. Cuenta Oppenheimer que cuando visitó Dublin, la capital de Irlanda, se sentía como en casa porque los irlandeses siempre han tenido mucho en común con los latinoamericanos. Bebedores, poetas, músicos y porsupuesto impuntuales, llenos de excusas, en fin rasgos típicos de los latinos.

    Al igual que muchos países latinoamericanos Irlanda se ha caracterizado, a lo largo de los años, por sobresalir en las artes y letras más no en las ciencias, la tecnología o el mundo empresarial.

    Pero, si los irlandeses han tenido mucho de los latinos, muchos se preguntan, ¿Cómo es que Irlanda en tan poco tiempo (12 años), ha pasado de ser un país pobre, típico agrícola, a ser uno de los países más ricos del mundo, con un gran crecimiento económico y lleno de tecnología de punta? Y no solo eso, sino un país con los mejores niveles de calidad de vida.

    Uno de los puntos claves del éxito de Irlanda, es que antes estaba aislado de los países ricos de Europa, en contra del libre comercio y rechazando el capitalismo. Se dieron del cuenta del error que estaban cometiendo por años, hasta que se unieron a la Unión Europea.

    Irlanda, en la década de los 90 tuvo uno de los mayores crecimientos económicos del mundo, con un promedio de 9% anual, disminuyo sus índices de pobreza a 5%. Irlanda pasó a convertirse en uno de los mayores centros tecnológicos de la industria farmacéutica y uno de los mayores exportadores de software a grandes empresas informáticas como Intel, Microsoft, Oracle e IBM.

    En los últimos años, se instalaron unas 1100 empresas multinacionales. Gran parte del progreso de Irlanda, se debe al acuerdo que tuvieron empresarios y obreros para dar paso a una apertura económica. Los sindicatos en vez de reclamar y generar más problemas llegaron a un gran acuerdo de cooperación con empresarios y el gobierno.

    Pero, ¿Por qué en tan poco tiempo Irlanda progresó? Además del acuerdo que hubo entre empresarios y trabajadores, se eliminó las trabas para la generación de nuevas empresas y al igual que muchos países desarrollados, las inversiones extranjeras fueron siempre bienvenidas.

    En Irlanda para formar una empresa, bastan solo tres procedimientos legales que se realizan en aproximadamente 12 días. ¿Alguien sabe cuántos trámites hay que hacer y cuánto demora formar una empresa en los países latinos?.

    Irlanda, se propuso como política de estado, atraer a las mejores empresas de computación del mundo e incentivar el estudio de carreras relacionadas a la ciencia y tecnología. Desde la década del 70, cuando Irlanda se unió a la Unión Europea ha destinado muchos recursos a las escuelas de ciencia e ingeniería creando nuevas universidades que se dediquen exclusivamente a ese tipo de carreras. El gobierno irlandés, apoyaba fuertemente las investigaciones científicas y técnicas con posibilidades comerciales.

    En las escuelas irlandesas se incentiva mucho el estudio de carreras técnicas y el gobierno ha dado máxima prioridad a la educación en los últimos años, lo cual ha generado un gran impacto cultural. Los principales periódicos de Irlanda, se dedican a difundir noticias educativas, de, por ejemplo, los estudios y trabajos de niños en las escuelas, proyectos de investigación que se vienen desarrollando en las universidades, cosa que no pasa muy a menudo en países de latinoamérica.

    A mi me da mucha pena ver como diarios de mi país, según ellos prestigiosos, tienen un alto porcentaje de noticias relacionadas a la farándula y cosas irrelevantes que solo ayudan a frenar el nivel educativo, tan solo por vender.

    Oppenheimer, finalizando el capítulo del milagro irlandés, cita una frase de un académico Mexicano, Luis Rubio: “Irlanda demuestra que las limitantes no son económicas, sino mentales y políticas”. Es decir, que los irlandeses se dieron cuenta de sus graves errores e ideas obsoletas, que tenían el potencial para ser una gran nación, no les faltaba oportunidades de inversión o exportación, sino un cambio de mentalidad, reformas políticas y mucha más organización.

    América Latina en el siglo del conocimiento

    Este es el ultimo capitulo del libro, en mi opinión, el más importante por las conclusiones a las que llega el autor.

    Para nadie es un secreto que las más grandes empresas de latinoamérica se dedican a las materias primas y que muchos empresarios y políticos latinos enfocan sus esfuerzos e inversiones en materias primas como el petróleo, gas, minerales, alimentos, etc.

    En los países desarrollados, la clave de sus riquezas, es la generación de conocimiento, el capital intelectual, la fuerte investigación en educación, ciencia y tecnología. Estamos en una era donde lo agrícola e industrial no son los mayores generadores de riquezas. Oppenheimer pone ejemplos claros de que los países con mayores recursos naturales aún no salen de la pobreza y también menciona como Singapur con cero recursos naturales ha tenido un enorme progreso en los últimos años.

    En latinoamérica, muchos todavía siguen pensando que los alimentos, los grandes minerales, en fin, la explotación de recursos naturales, es lo que nos va a traer el máximo progreso y desarrollo.

    Una parte a destacar es como Holanda produce y exporta más flores que cualquier país latinoamericano. América latina debería ser el primer productor mundial de flores por sus grandes recursos, excelente clima, gran territorio, reservas de agua, etc. Sin embargo, Holanda, con mano de obra mucho más cara, menos recursos naturales, menos sol y teniendo un territorio más pequeño es el primer productor mundial de flores. Michael Porter, profesor de Harvard concluye: En la industria de las flores, lo que importa es la ingeniería genética, la capacidad de distribución y el marketing.

    Como ejemplo de que el negocio de la materia prima no es lo que está triunfando, también se menciona a Starbucks, la empresa de locales de café más grande del mundo y cómo, por cada taza de café que se vende en EE.UU, apenas 3 centavos son para el productor del café latino.

    En latinoamérica, los gobiernos centran sus esfuerzos en exportar productos agrícolas o materias primas en lugar de productos de mayor valor agregado.

    Algo sumamente interesante de este capitulo es la historia de Nokia, el mayor fabricante de teléfonos celulares con origen en Finlandia, uno de los países más desarrollados del mundo, que años atrás exportaba materia prima y hoy por hoy se concentra en la tecnología.

    Nokia, que se formó en el siglo pasado, pasó de ser una empresa maderera, después a fabricar muebles y varios diseños industriales, hasta dedicarse por completo a las telecomunicaciones y ahora al software, lo cual la ha convertido en una enorme empresa con miles de empleados, con millonarias ganancias anuales y es una de las marcas más caras que existen.

    Otro ejemplo de empresas que pasaron del negocio de la materia prima a productos intangibles es Wipro, de la India, que se dedicaba a la venta de aceites de cocina y ahora es una de las mayores empresas de software de la India y del mundo. Hoy Wipro es una empresa innovadora con ingresos anuales de millones de dólares.

    Como lo menciona en muchas partes del libro, en todos los países que han progresado y siguen creciendo, hay un alto porcentaje de estudiantes y profesionales dedicados a las ingenierías, la investigación y desarrollo.

    En China, se siguen instalando empresas de telecomunicaciones, donde contratan a miles de ingenieros y técnicos al año para producir aparatos modernos y exportarlos a los países más ricos.

    Otro de los puntos que se toca en este capítulo fue una pequeña comparativa entre las universidades latinoamericanas con las del resto del mundo. Según un ranking publicado por The Times, solo una universidad latina aparece en las 200 primeras del mundo, en el puesto 195, La UNAM.

    Oppenheimer resalta de una manera como celebraron y publicaron ese logro los líderes de esa universidad por estar entre las mejores 200 del mundo, mientras que universidades europeas que se ubicaron entre las 60 primeras se sentían preocupadas por los resultados y empezaron a investigar fuertemente cómo mejorar el nivel educativo.

    También menciona a la UBA, una prestigiosa universidad de Argentina y similar a lo que pasa con la UNAM, reciben millones de dólares de parte del gobierno y se niegan a ser evaluados por organizaciones internacionales porque según ellos, son tan prestigiosas y de tan alta calidad que no merecen ser evaluadas. Según este estudio, de 20 de las mejores universidades del mundo, 11 son de EE.UU, las demás de Europa, India, China, Japón y Australia.

    Oppenheimer critica duramente, a las universidades latinas, por los bajos sueldos a los profesores, la falta de infraestructura y los obsoletos que son sus métodos de enseñanza.

    Pero lo más importante y como lo mencioné al principio, es que la educación no debería ser gratuita, que eso da paso al retraso, puesto que se podría juntar grandes cantidades de dinero que sirvan para mejorar la calidad de las universidades y ayudar a estudiar a los que son muy pobres. Hay estudiantes, que realmente si pueden pagar su educación, pero que rechazan hacerlo porque el sistema así lo permite.

    Estoy completamente de acuerdo con esto, la educación, no puede ser gratuita y se debería identificar a aquellos que pueden realizar un pago y aportar a la económia de las instituciones educativas. Con gran dinero recaudado, ¿Cuántos proyectos de cualquier tipo se podrían financiar?

    Otro punto, imagínate que un amigo/familiar/colega se va a estudiar o trabajar al extranjero, si le preguntas a un latino que piensa sobre la partida de ese profesional, la respuesta típica es que se siente contento por el logro, pero pasa una segundo y te menciona la famosa “Fuga de cerebros”, idea que es completamente alejada de la realidad.

    Los chinos e indios están creando ejércitos de ingenieros, técnicos y científicos totalmente competitivos en cualquier parte del mundo porque muchos de ellos están estudiando en las mejores universidades de EE.UU. y Europa, regresan a su país con más conocimiento, experiencia, invierten en sus países, crean empresas o sucursales, tienen más conexiones y relaciones con profesionales, empresarios de otros países y generan a su vez más crecimiento, conocimiento.

    En los países latinos hay miles de graduados al año en artes, letras y faltan personas con formación científica, tecnológica. Otra de las diferencias con los países en crecimiento es su alta exigencia por aprender y hablar muy bien el inglés, idioma universal, indispensable para la comunicación, negociación con profesionales y empresas internacionales.

    En una de las últimas partes de este capítulo, se menciona, porqué los estudiantes asiáticos estudian más que en cualquier otra parte del mundo, cómo no solo los chinos, sino casi todos los países de Asia están obsesionados por el estudio y los padres colaboran diariamente para que sus hijos refuercen sus estudios cotidianos con clases privadas y como les limitan ver la televisión a solo un par de horas a ala semana. De repente, para nosotros puede parecernos trágico esta situación por una cuestión cultural, pero para los niños asiáticos, en estos tiempos, el estudio forma parte del día a día durante muchas muchas horas.

    Mis conclusiones

    Ha sido divertida la lectura, por la forma en como Oppenheimer cuenta sus vivencias, anécdotas en sus viajes a muchas partes del mundo. Gran parte del libro son las entrevistas a personas y políticos influyentes de los países que lograron salir de la pobreza y también de los que están estancados.

    Algunos opinan que no te puedes basar solamente en entrevistas para dar un fundamento acerca de cómo crece un país. Claro, pero yo pienso, que seguramente, estar en el mismo lugar, conversar con la gente, los líderes y ver con tus propios ojos todo lo que está pasando, te hace generar ciertas opiniones, como en este caso, que nuestros políticos latinos nos paran contando cuentos chinos.

    Básicamente, Cuentos Chinos, te da un panorama global de lo que está pasando en el mundo, se habla mucho de la economía y no se profundiza mucho en ciertos temas como el de la educación, pero permite abrir una discusión al futuro de América Latina en sus factores más importantes: Reducción de la pobreza, el bienestar, calidad de vida, trabajo, creación de empresas innovadoras, como frenar la delincuencia, corrupción, como mejorar los niveles educativos, generar un clima de entusiasmo y superación constante de cada uno de los habitantes.

    Particularmente, me hubiera gustado que Oppenheimer profundice más en el tema de la educación, que se dirija hasta el fondo del asunto. es decir, algo así como un reportaje en una universidad que ha pasado de ser una mas del montón a ser una institución exitosa.

    Entrevistas a los estudiantes, ver en qué están trabajando, como lo hacen, para quien, que métodos usan, que empresas contratan a estudiantes de esa universidad, en que criterios se basan, el número de publicaciones internacionales y como esas publicaciones o investigaciones se han aplicado en un caso práctico, de la vida real. Quienes son los profesores de esas universidades, donde estudiaron, como enseñan, la relación con sus alumnos. Las escuelas más activas de esa universidad, donde están los estudiantes con mayores calificaciones, cuantos han generado empresas de servicios o intangibles. Los sueldos a los profesores, como son las prácticas profesionales, como califican a los estudiantes, si hay concursos internos, cuantas horas estudian al día, cuánto pagan por estudiar en esa universidad, los niveles económicos de los estudiantes, etc, etc, etc.

    En fin, un reportaje extremo de un caso particular de institución educativa que paso de la mediocridad al éxito, algo así me gustaría leer algún día.

    Realmente si me gustó el libro, por eso lo compartí en este breve resumen y lo recomiendo a todo aquel estudiante o profesional de latinoamérica que desea conocer un poco mas de lo que pasa en el resto del mundo y en que nos estamos quedando.

    Written by Ronny Yabar Aizcorbe

    April 15, 2009 at 2:30 am

    Posted in Libros

    Install KDE 4.2 in debian

    leave a comment »

    This is how looked my desktop some minutes after the kde 4.2 installation.

    KDE 4 Runner, Leave note, Twitter, RSS, NowPlay, Dictionary, Clock -> Widgets in KDE 4.2Y

    You need Debian unstable (Sid) and enable the experimental branches to install kde 4.2 version.Have in mind that this Debian branches come with lots of bugs and sometimes your system doesn’t respond as you like. Well, going to the whole point.

    Add this to your /etc/apt/sources.list

    deb http://ftp.de.debian.org/debian/ sid main
    deb-src http://ftp.de.debian.org/debian/ sid main

    Enable the experimental branch by adding this to your /etc/apt/sources.list

    deb http://ftp.de.debian.org/debian/ experimental main
    deb-src http://ftp.de.debian.org/debian/ experimental main

    Update your system:

    sudo apt-get update

    Install the KDE packages from experimental with the command:

    sudo aptitude -t experimental install kde4-minimal

    kde4-minimal includes:
    kdebase-runtime: Essential runtime components
    kdebase-workspace: Desktop environment
    kdebase: Core applications

    If you want a complete installation, run:

    sudo aptitude -t experimental install kde4

    This command will install all packages of KDE 4.2 and could take some time. But, I recommend you install just the packages you need like: kdepim, kdemultimedia, kdenetwork, kdeplasma-addon, etc. Look at the Debian/KDE website for more information.

    ¡Enjoy your KDE Desktop!

    Here are some screnshots of my desktop when playing with KDE 4.2.

    Calendar, Folder view, Picture widgests in Plasma

    Calendar, Folder view, Picture widgests in Plasma

    Blue Curl Picture

    Blue Curl Picture

    Iceweasel

    Iceweasel

    Dolphin

    Dolphin

    Kickoff Menu, Twitter widget, Folder View

    Kickoff Menu, Twitter widget, Folder View

    Konsole, RSS, Runner, Dictionary

    Konsole, RSS, Runner, Dictionary

    Written by Ronny Yabar Aizcorbe

    March 2, 2009 at 10:22 pm

    Posted in Debian, KDE

    KDE 4.2 “The answer”

    with one comment

    kde 4First of all: I always prefer and love KDE for his elegance, customization, easy-usage, great applications and now because is really  interesting for programming. I use KDE in my everyday work: Konqueror (now Dolphin), konsole, k3b, Amarok, kate, Konversation, Kopete and other ones.

    When KDE 4.0 was published many people criticize it very hard: A lot of bugs, different look and concept of desktop, different panels, new applications menu, widgets, etc, etc were some features that made most KDE users unhappy. However, KDE developers always said in the announcement page, blogs and mailing lists that KDE 4 is a work in progress and they will be working, coding hard to release new versions of KDE (4.1, 4.2… ) with a lot of improvements.

    KDE 4.1 was much better than KDE 4.0(many bugs killed and improvements,more stability, applications,speed), but KDE 4.2, in my opinion, is a version, that give us a stable desktop  with cool, interesting, features not only for users but also for developers. This KDE version was named: “The answer” because it minimize negative, destructive. comments and people who didn’t believe in the KDE community and team. I consider these people don’t know appreciate the innovation and great effort.

    Congratulations to the all KDE Team for the hard-work they made. I am really impressed about how can you customize your desktop, add new features and the KDE 4 development way.

    In this video you can see the KDE 4 presentation in Google Campus where Aaron Seigo a famous KDE hacker member of the core-team talk about the KDE 4 technology and how KDE innovation can make current desktops obsolete.

    Nepomuk, Decibel, Plasma, Oxygen, Solid, Phonon, Akonadi are some parts of KDE 4 that introduce new behaviours and will make a big change in KDE. I am particularly interested in Plasma and Nepomuk for development and deciding in which project participate for this Google Summer of Code. But I need more reading and practicing about how these work. If you  make a Gsoc proposal without researching, reading, practicing and talking to mentors you probably will fail.  In this page, you can see the initial process to start your KDE 4 development environment.

    In general KDE 4  has as main goals: Improve the desktop user experience, have better applications and development platform and make our desktop a central place to be more productive. That is my impression and for now on I will continue researching and folowing the KDE development process.

    Written by Ronny Yabar Aizcorbe

    March 2, 2009 at 8:16 pm

    Posted in Debian, GSoC, KDE

    Tagged with , ,

    Blogging once again

    leave a comment »

    Wow.  Almost 4 months since my last post, sometimes it’s too hard to update my blog. I’m married, have a beautiful baby, study and work and believe me that is a little bit difficult to manage.

    However, I continue exploring and learning new technologies about my passion: Open Source/Free Software.

    Here are some things that happened in the last months.

    I started learning Python and Django and I have to admit that since the first moment I tried them that I like it very much. On the other hand, I got tired about how slow rails is and the fucking error messages whenever you upgrade some gems and plugins. Conclusion: I switched to Python-Django for web development. Now I am re-writing an application, written in Rails, with Django.

    My boss acquired a dedicated server hosting to run a lot of web services for his company use and proposed me to manage it. Now I am maintaining the server and it was fun to learn SSH and Fedora commands (I use Debian). SSH takes part of my everyday freelance work.

    Last week, I finished the development of an e-commerce site for an American company called Misti International. I used the Magento e-commerce platform to develop it. Which at the beginning seems beautiful with a lot of cool features, but you need some patience to understand it deeply, because has a complex structure with too many folder and files and it is kind of difficult to customize it. But, I worked hard on this site and my client is really happy about it. I strongly recommend to learn PHP5 and take a look at the Zend Framework to learn more about the Magento code.

    I installed KDE 4.2 in my Debian machine. (Here is a quick tutorial ). The only thing I want to say is: THANKS to all the KDE team for give us this great technology that is so well created and designed. But I will talk about KDE in other posts, because I am really interested in developing for KDE.

    Google Summer of Code 2009 was announced and I am going to apply this year again.  I already got in contact with a mentor to work in his proposal and received good feedback about it.

    That’s it. Well , I forgot to mention that with Maritza and Celeste (wife and daughter) visited many tourist places here in Arequipa and had great moments. I love spend and enjoy time with my 2 girls.

    Written by Ronny Yabar Aizcorbe

    February 28, 2009 at 10:32 pm

    Posted in Django, GSoC, KDE

    Tagged with , , ,

    Debian GNU/Linux 5.0 – Lenny released

    with one comment

    Esta es la nota de publicación de esta nueva versión de este gran sistema operativo..

    El Proyecto Debian se complace en anunciar la publicación oficial de la versión 5.0 de Debian GNU/Linux, nombre en clave lenny, tras 22 meses de desarrollo constante. Debian GNU/Linux es un sistema operativo libre que soporta un total de doce arquitecturas de procesador e incluye los entornos de escritorio KDE, GNOME, Xfce y LXDE. También ofrece compatibilidad con el estándar FHS v2.3 y software desarrollado para la versión 3.2 de LSB.

    (para descargar Lenny ahora mismo, visita la página de descargas de Debian)

    Debian GNU/Linux se ejecuta en ordenadores que van desde agendas hasta supercomputadoras, pasando por prácticamente cualquier sistema intermedio. Se da soporte a un total de doce arquitecturas: Sun SPARC (sparc), HP Alpha (alpha), Motorola/IBM PowerPC (powerpc), Intel IA-32 (i386), IA-64 (ia64), HP PA-RISC (hppa), MIPS (mips, mipsel), ARM (arm, armel), IBM S/390 (s390), y AMD64 de AMD y EM64T de Intel (amd64).

    Written by Ronny Yabar Aizcorbe

    February 14, 2009 at 4:19 pm

    Posted in Debian

    ¡Grande BarCampLima!

    with one comment

    Que linda experiencia, lindo día, no sé como describirlo, pero el 1er BarCamp Lima para mi fue simplemente de puta madre. Un evento que definitivamente debe repetirse, me encantó los pequeños debates que se armaban mientras alguien exponía, la informalidad, la colaboración, el espíritu open source, charlas interesantísimas, aprendí muchísimo sobre todo temas de los cuales tenía muy poco conocimiento como por ejemplo Computación en la nube (Cloud Computing) y también temas que me apasionan como programación en la web.

    Y claro también hice unos cuantos amigos e intercambié un par de ideas con varios de los geeks presentes.

    Aquí está el video de mi charla, motivando a la gente para que participe en el Google Summer of Code.

    Google Summer of Code – Barcamp Lima

    Felicitaciones a todos los organizadores, colaboradores, participantes y a todos los que hicieron de esto un gran día.

    ¡Salud por el BarCampLima!

    Written by Ronny Yabar Aizcorbe

    November 10, 2008 at 9:09 pm

    Posted in GSoC, Viajes

    Tagged with ,

    BarCamp Lima 2008

    with 3 comments

    Si señores, se viene el 1er BarCamp Lima este 8 de noviembre, el cual no me pienso perder por ninún motivo. Ya estoy haciendo mis maletas. Así que me voy al barcamp a encontrarme con toda esa gente geek. Creo que estoy en racha de viajes, proyectos, me encanta esta vida. Será Dios?. No creo.

    Un BarCamp es una reunión abierta, libre y flexible, que tiene como finalidad compartir conocimiento e intercambiar experiencias, y sobre todo buscar la participación de todos los asistentes a fin de interactuar en una verdadera comunidad. En un Barcamp todos participan, todos pueden dar una charla sobre su tema de preferencia. En un barcamp normalmente se habla sobre tecnología, internet. Más info en la wikipedia.

    En el caso del barcamp Lima se tocarán temas como web 2.0, negocios en internet, open source. Contará con la presencia de bloggers, desarrolladores, diseñadores, hackers, geeks, fans de linux y del software libre.

    Por mi parte, voy a dar con una charla sobre el Google Summer of Code – Gran Oportunidad para comprometerse realmente con el Open Source (Mentores y estudiantes).  Voy a colaborar llevando a una de mis mejores amigas: mi cámara, ah y pizarra y plumones. Y porsupuesto que pienso compartir mis pequeñas experiencias, anécdotas  en proyectos web, uso de Linux y también seguramente aprenderé bastante de los demás. Eso es lo bueno de este tipo de charlas: El feedback.

    Pueden ver el sitio oficial del evento y la wiki. Entre los auspiciadores está HP del Perú que brindará el local que tiene un aforo para 70 personas, así que hay que ir temprano muchachos. Por lo que tengo entendido las inscripciones ya están cerradas.

    Felicito a los organizadores, 2 grandes comunidades nacionales la Asociación Nacional De Webmasters Del Perú y el el PLUG por su dedicación, esfuerzo y organizar un evento así en tiempo récord.

    Así que nos vemos en el BarCamp Lima y a disfrutar del evento.

    Written by Ronny Yabar Aizcorbe

    November 2, 2008 at 1:34 am

    Posted in GSoC, Viajes

    Tagged with , , , ,

    What I learned from Gsoc?

    leave a comment »

    Google Summer of Code was a wonderful experience for me, I’ll never forget it. I finished my project and that gave me a lot of satisfaction. Getting opinions and feedback from the open source community was really special. In general, this is what I learned:

    Community:

    Improve my communication skills: Doing a project that involves other people means that you have to be clear in your words, be brief but efficient, and most important, make people understand what you are trying to say.

    English:

    I wrote a lot in English. (My project, IRC meetings, asking in the list, answering questions, etc). Although, English is not my first language I enjoyed having to be clear with my mentor, my organization and the Google group of summer of coders.

    Technology

    Ruby and Ruby on Rails: This Ruby user’s guide helped me a lot. I haven’t finished it, but I learned a lot about this great language (regular expressions, strings, arrays, iterators, control structures, OOP, classes, methods). And I also do a lot of programing with the ruby on rails framework. I learned how to manage and modified some plugins.

    Actually working with views is not my favorite part of a project. However, CSS work at the end of the project was really fun. What CSS make is impressive.

    Solr: I never ever have worked with a search server. Solr is just amazing – Full-Text Search Capabilities- . t I learned how to integrate Solr and the act_as_solr plugin to my Rails application.

    Subversion: I learned how to work with this collaboration tool which I consider make you more productive. However, I had to deal with so many error messages, strange problems, I need to learn more commands apart from the common ones.

    Vulnerability and Patch concepts.

    I believe that be an expert in these fields takes his time. I never did a security system and didn’t work with a security team before. But I learned key concepts related to patches and vulnerabilities that helped me a lot to write the code. For example:

    • Vulns classification (Location, Attack Type , Impact, Solution, Exploits).
    • Vulns technical description and how to test a vulnerability.
    • Patch severity (Critical, Severe,important, Minor, Pointless )
    • Security Products: Nikto, Snort and Nessus.
    • What CVE means.
    • How to associate a vuln-patch with a Vendor/Product/Version

    Many lessons learned in these months let me think what I did wrong and what I did well. I feel that  I’m not always as productive as I might like to, my effort changes with the tasks I’m doing.

    Once I read some Linus interview in which he said that if you are completely present in a situation and totally focused on something then that something *becomes* interesting, whatever it may be.

    So, I think that making your job interesting and fun and get really concentrated on the problem are the keys to your project success.

    I would like to participate for Gsoc 2009 again.

    ¡Happy Hacking!

    Written by Ronny Yabar Aizcorbe

    October 30, 2008 at 4:51 pm

    La teoría del todo de Hawking.

    with one comment

    Estoy contento, hace una semana compré mi espectacular libro “La teoría del todo” cuyo autor es uno de los científicos, en mi opinión, más grandes de todos los tiempos: Stephen Hawking.

    Siempre he tenido dudas y mucho interés en leer sobre el origen, evolución del universo y del hombre. Leí varios artículos acerca de esto, pero siempre me quedaba con interrogantes por la diversidad de teorías. Sin embargo, creo que Hawking es uno de los investigadores científicos, que más ha hablado y escrito acerca del universo en los últimos años, por eso tenía una deuda conmigo mismo: Leer un libro del tío Hawking.

    Me parece atrevido decir que Dios creo al universo y no tener algún sustento de ello. Bueno y yo que soy agnóstico con mucha más razón no puedo afirmar ni negar dicha teoría. Por eso los invito a leer este libro.

    Estoy en el capítulo 5: El origen y el destino del universo. La lectura no ha sido muy difícil, aunque sinceramente ciertos párrafos los he leído un par de veces para entenderlos mejor porque contenían un vocabulario complejo. Quizá si fuera físico y no programador, sería mucho más sencillo.

    Lo interesante del libro es que Hawking hace un resumen de ideas antiguas del universoy también habla de teorías de la gravedad y relatividad de Einstein y Newton, habla del big bang  los agujeros negros, y nuestra época actual, bueno eso es hasta donde leí.

    Voy a hacer un breve resumen del libro cuando acabe de leerlo. Se los recomiendo muchísimo, sumamente interesante.

    Written by Ronny Yabar Aizcorbe

    October 29, 2008 at 2:38 pm

    Posted in Libros

    Tagged with , ,

    ¿Porqué perdemos el tiempo?

    with one comment

    Es impresionante como los medios de comunicación le dan semejante relevancia a la captura de un personaje de televisión. Que por más famoso o popular que sea, es solo eso, un personaje.

    Amo a mi país, y me da tristeza ver como la gente se llena la boca, todos los días, hablando de temas que no tienen absolutamente relación alguna con los problemas reales por los que atraviesa el país: Pobreza, Corrupción, educación, desempleo, etc.

    ¿Porqué perdemos el tiempo?, porqué no invertir ese tiempo en cosas más productivas. porqué no en vez de ver televisión y hablar de Magaly Medina o su programa mediocre, pensamos en aportar ese granito de arena para hacer un Perú mejor o hablar de proyectos educativos, de generación de empleos.

    Porque no existen medios de comunicación peruanos que hablen de esos 3 puntos vitales hoy en día de los que tanto habla Oppenheimer: Ciencia, Tecnología y Educación. Cuando tengo la remota oportunidad de ver algo en TV o leer algún periódico siempre mantengo la esperanza viva de encontrar algo que eduque, algo interesante, pero siempre me quedo con las manos vacías y siempre me pregunto ¿porqué perdemos el tiempo?.

    Cada vez estoy más convencido que la TV es una basura. Y si no fuera por el Discovery, Animal Planet, National Geography, History Channel y afines sería aún más basura.

    No perdamos el tiempo, en lugar de ello, dediquemos tiempo a nuestras familias, mejor dedicarse a estudiar , trabajar, escribir o leer algo, en fin realizar algo educativo o que nos divierta. En fin, tantas cosas más productivas podríamos hacer.

    Bueno es solo una opinión, ojalá a alguien le sirva o ayude algo.

    Written by Ronny Yabar Aizcorbe

    October 21, 2008 at 12:23 am

    Posted in Opinion

    Tagged with , ,

    De vuelta al GYM

    leave a comment »

    Hip, hip urra. Después de un duro año sin tiempo para nada, regresé al gym. Ya era tiempo de un relax, salud mental y mucho ejercicio. Me da mucha satisfacción, aunque levantarse a las 6:30am todos los días si me trasnocho no va a ser fácil, pero le voy a poner huevos. Y lo bueno que tendré todos los días la companía de mi hermanita Nadia.

    El plan a corto plazo es octubre, noviembre y diciembre, bien trabajados, para llegar en formar al verano 2009.  Una buena alimentación, creatina para las fuerzas y energías, dormir al menos 6 horas diarias, un breve descanso en la tarde, investigaré  respecto a que es lo mejor para mí.

    Antes del ingreso

    No pongo los nombres de las máquinas porque no me las se todas. Mi rutina es básica, en sí, para todos los ejercicios estoy haciendo 4 series de 12 c/u. Casi todo fue recomendación del chato. (El instructor)

    Lunes: Pecho y espalda  + Abdominales y pantorrillas.

    Martes: Biceps y Triceps + Abdominales y pantorrillas.

    Miércoles: Hombros y piernas + Abdominales y pantorrillas.

    Continúa sucesivamente para el jueves, viernes y sábado. Porfavor si alguien tiene un consejo, sugerencia opinión será bienvenido.

    A la salida

    Written by Ronny Yabar Aizcorbe

    October 1, 2008 at 8:46 pm

    Posted in Personal

    Tagged with , , ,

    Rails 2.2 will be thread safe

    with one comment

    Reading the rubyonrails blog I read that Rails 2.2 will be thread safe and that this hard work comes from a Google Summer of Coder. Josh Peek who will join the rails core.

    This is a great advance for the framework, because many people were looking for merb for this rails weak, but this improvement will attract new developers to join the rails community.

    Congratulations Josh.

    Written by Ronny Yabar Aizcorbe

    August 19, 2008 at 5:19 pm

    Posted in GSoC, Ruby on Rails

    Tagged with , ,

    Finishing my project for the Gsoc

    with one comment

    These are the latest changes on the project. Before that, it is important to know all the work made before and the information we can submit for a patch.

    Basic Information:
    Dates(Disclosure, Creation)
    Description
    Classification
    Severity
    Ratings

    Association with:
    Products
    Vulnerabilities
    Files
    Documentation Links
    Credits (Authors, Companies)

    User Interaction:
    Comments:
    Stats (views, percent complete).

    Updates:

    * Allow users select patches based on the watchlist.
    * Patches were incorporated into the solr search engine.Main fields were indexed(id, title,short and technical description,dates,vendors and products). For the moment, the search for patches is separated from the search for vulnerabilities.
    * An advanced search for patches (For severity, for classification, for products)
    * When adding vulnerabilities to a patch, users can auto complete vulns based on the their identifiers..
    * I made some CSS work changing the style for the show page on the patches, that way users can distinguish immediately an information page for a patch from a vulnerability.
    * However I will need one or maybe two more days to finish all my presentation styles and user alerts when a patch is released and goes into the portal.

    I am really glad to see that everything is coming fine and all work made in these months is having sense for me.

    Written by Ronny Yabar Aizcorbe

    August 18, 2008 at 4:15 pm

    Posted in GSoC

    Tagged with

    Passed GSoC Mid-Term Evaluation

    leave a comment »

    I am really happy. I passed the Google Summer of Code 2008 mid-term evaluation! This means that I get to finish my project patch management portal. I want to thank Dave, my mentor for give me the opportunity to continue working on the project.

    This is a quick report of all the work made until this point.

    May 26 – June 1: Tables used on the project were created and integrated into the OSVDB schema. Use cases were defined.

    June 1-18:

    I created an MVC to manage patches. So the base_patches_controller.rb allow us to manage all the actions related to patch submission. I was testing the code and submitting my first patches and all their relevant information and things are going quite well.

    So, principal functions were created. You can submit general information about a patch, also associate it with a vendor/product/version, associate it with an author, vulnerability and add a patch rating.

    These are the principal actions (methods). However, more actions will be created this week, specially for ratings and vulnerabilities.

    General: create edit update destroy
    Ratings: addpatchrating updatepatchrating
    Products: addvendor showversions
    Credits: adduthor update_author deleteauth
    Vulnerabilities addvuln deletevuln

    I also created and MVC for base_patch_rating_levels. So, it is possible to CRUD patch_rating_levels.

    I just worked in models creating maping objects (Has many, belongs_to, has_and_belongs_to), but didn’t work on validations yet. I expect to work in views at the end of this week. (This is HTML and CSS work).

    June 18-30: We have the core of Patch Management Portal written. Patches are linked to vulnerabilities and shown in the home page.

    -Main views for patches were created.
    -Optimization in the database tables.(indexes)
    -Active and fragmet caching in some pages and methods.And a patch sweeper created.
    -Moderator nav modified to submit a patch and to C,R,U,D rating levels with Active scaffold.
    -Home page modified to show “Latest OSVDB Patches” (similar functionality to vulns) with Printer,normal and popup views.

    -Validations added to models.

    July 01-07: Working on file submission.

    This is really important because users can submit a file for everybody to download. So, it is more easy for mostly users to apply the patch just by reading the short-technical description and downloading the file(code).
    my my
    July 13: File Submission finished. Users can add/delete files related to patches.

    You can see my work in progress here in the project wiki and also take a look at my mid-term evaluation. Later on I will be publishing the source code.

    I expect to finish the project successfully and be part of the development team.

    Written by Ronny Yabar Aizcorbe

    July 14, 2008 at 4:44 pm

    Posted in GSoC

    Tagged with ,

    Rdoc – Generating documentation for ruby and rails

    leave a comment »

    Rdoc is a program for creating documentation for ruby source code. Rdoc generates HTML documentation, using syntactic information from the source and text in comment blocks.

    You can check documentation about ruby libraries if you have ruby property installed by running the ri command. For example, if we want to know what the capitalize method does, just type in your terminal:

    ri String.capitalize
    
    ---------------------------------------------------String#capitalize
    str.capitalize    => new_str
    --------------------------------------------------------------------
    Returns a copy of str with the first character converted to
    uppercase and the remainder to lowercase
    "hello".capitalize  #=> "Hello"
    "HELLO".capitalize  #=> "Hello"
    "123ABC".capitalize  #=> "123abc"

    Rdoc is very useful to look for information about programs, methods and examples.

    If you want to see the rails api documentation type in your terminal: gem server and then go to your browser at the url http://localhost:8808

    You will get an HTML page “RubyGems Documentation Index” with a summary of all ruby gems installed on your system.

    Click on the gem you want to see the documentation and you will see an HTML page with 3 columns: (Files, Classes, Methods) and everything documented in detail.

    If you installed rails with rubygems you can access the rails api.
    Also the rake app:doc command creates the HTML documentation for your Rails project and stores this documentation in the doc/app directory.

    Run the file doc/app/index.html and you will see of the documentation of your rails project.

    Written by Ronny Yabar Aizcorbe

    July 3, 2008 at 10:25 pm

    Query analyzer for Rails

    leave a comment »

    I found an interesting and very useful plugin for rails called Query analyzer that allows us check for tables not optimized in our database. It really helps a lot to optimize tables and queries and put indexes on our conditions columns and primary/foreign keys. Sometimes, we forget to do things so simple like this. Here is a great explanation of what the plugin does.

    How to use it?

    Just install the plugin with:

    script/plugin install http://svn.nfectio.us/plugins/query_analyzer

    and then check your logs. You can see your console as well. Once you have the plugin installed you will see all queries your application does and how they are currently managed.

    For example:

    I have a table called form_help_divs. It is a table to show some messages in forms around my application. I usually make a call to the database to get a form_help_div record. The query generated is like this:

    SELECT * FROM `form_help_divs` WHERE (`form_help_divs`.`name` = 'patch_vuln') LIMIT 1

    So in theory. The query should check for only one row, but that is not true because the name column doesn’t have an index. And how I realized that?. I just checked my log and saw this:

    Analyzing FormHelpDiv Load
    
    select_type | key_len | type | Extra       | id | possible_keys | rows | table          | ref | key
    ---------------------------------------------------------------------------------------------------
    SIMPLE      |         | ALL  | Using where | 1  |               | 33   | form_help_divs |     |

    As you see the query is looking for all records (in this case 33) in the database searching for the name ‘patch_vuln’. That is not good guys. Let us optimize our queries by adding and index to that table. We can add it by hand in our mysql interface, but is better to create migrations.

    class AddFormHelpDivIndexes < ActiveRecord::Migration
    def self.up
    add_index :form_help_divs, :name
    end
    
    def self.down
    remove_index :form_help_divs, :name
    end
    end

    Type rake db:migrate in your console and your migration will be executed.Now run your application again and you will see the difference in your logs and console. This is the result:

    FormHelpDiv Load (0.001585)   SELECT * FROM `form_help_divs` WHERE (`form_help_divs`.`name` = 'patch_vuln') LIMIT 1
    
    Analyzing FormHelpDiv Load
    
    select_type | key_len | type | Extra     | id | possible_keys | rows |table  | ref   | key
    -------------------------------------------------------------------------------------------------
    SIMPLE   |768|ref|Using where|1|name,index_form_help_divs_on_name|1|form_help_divs | const | name

    ¡What a big difference!. Now the query is looking just for one row in the database and that will increase the query speed significantly.

    There are other ways to make our applications running faster with rails. Adding indexes is one of those ways and let us gain a lot of optimization specially if we are working with big applications and tables with so many records.

    I strongly recommend you to optimize tables and use the query analyzer.

    Written by Ronny Yabar Aizcorbe

    July 3, 2008 at 9:32 pm

    Posted in Ruby on Rails

    Tagged with , , ,

    Rake

    leave a comment »

    Rake is a ruby program that builds other ruby programs. Each time you execute rake, it knows how to build those programs by reading a file called Rakefile which has a set of tasks. Those tasks allows us to do some project needs in a very easy and efficient way.

    When you generate a rails project you automatically get a Rakefile and it is in the root of your project.

    You can see all rake tasks and their descriptions by running a simple command in your main directory:

    rake –tasks

    And this should be shown:

    rake backgroundrb:remove # Remove backgroundrb from your rails …
    rake backgroundrb:restart # Restart backgroundrb server (default…
    rake backgroundrb:setup # Setup backgroundrb in your rails app…
    rake backgroundrb:start # Start backgroundrb server (default v…
    rake backgroundrb:stop # Stop backgroundrb server (default va…
    rake db:abort_if_pending_migrations # Raises an error if there are pending…
    rake db:charset # Retrieves the charset for the curren…
    rake db:collation # Retrieves the collation for the curr…
    rake db:create # Create the database defined in confi…
    rake db:create:all # Create all the local databases defin…
    rake db:drop # Drops the database for the current R…
    rake db:drop:all # Drops all the local databases define…
    rake db:fixtures:identify # Search for a fixture given a LABEL o…
    rake db:fixtures:load # Load fixtures into the current envir…
    rake db:migrate # Migrate the database through scripts…
    rake db:migrate:redo # Rollbacks the database one migration…
    rake db:migrate:reset # Resets your database using your migr…
    rake db:reset # Drops and recreates the database fro…
    rake db:rollback # Rolls the schema back to the previou…
    rake db:schema:dump # Create a db/schema.rb file that can …
    rake db:schema:load # Load a schema.rb file into the database
    rake db:sessions:clear # Clear the sessions table
    rake db:sessions:create # Creates a sessions migration for use…
    rake db:structure:dump # Dump the database structure to a SQL…
    rake db:test:clone # Recreate the test database from the …
    rake db:test:clone_structure # Recreate the test databases from the…
    rake db:test:prepare # Prepare the test database and load t…
    rake db:test:purge # Empty the test database
    rake db:version # Retrieves the current schema version…
    rake doc:app # Build the app HTML Files
    rake doc:clobber_app # Remove rdoc products
    rake doc:clobber_plugins # Remove plugin documentation
    rake doc:clobber_rails # Remove rdoc products
    rake doc:plugins # Generate documentation for all insta…
    rake doc:rails # Build the rails HTML Files
    rake doc:reapp # Force a rebuild of the RDOC files
    rake doc:rerails # Force a rebuild of the RDOC files
    rake log:clear # Truncates all *.log files in log/ to…
    rake notes # Enumerate all annotations
    rake notes:fixme # Enumerate all FIXME annotations
    rake notes:optimize # Enumerate all OPTIMIZE annotations
    rake notes:todo # Enumerate all TODO annotations
    rake rails:freeze:edge # Lock to latest Edge Rails or a speci…
    rake rails:freeze:gems # Lock this application to the current…
    rake rails:unfreeze # Unlock this application from freeze …
    rake rails:update # Update both configs, scripts and pub…
    rake rails:update:configs # Update config/boot.rb from your curr…
    rake rails:update:javascripts # Update your javascripts from your cu…
    rake rails:update:scripts # Add new scripts to the application s…
    rake remove_simple_captcha_files # Remove unuseful captcha images and s…
    rake routes # Print out all defined routes in matc…
    rake secret # Generate a crytographically secure s…
    rake solr:destroy_index # Remove Solr index
    rake solr:start # Starts Solr.
    rake solr:stop # Stops Solr.
    rake stats # Report code statistics (KLOCs, etc) …
    rake test # Test all units and functionals
    rake test:functionals # Run tests for functionalsdb:test:pre…
    rake test:integration # Run tests for integrationdb:test:pre…
    rake test:plugins # Run tests for pluginsenvironment / R…
    rake test:recent # Run tests for recentdb:test:prepare …
    rake test:uncommitted # Run tests for uncommitteddb:test:pre…
    rake test:units # Run tests for unitsdb:test:prepare /…
    rake tmp:cache:clear # Clears all files and directories in …
    rake tmp:clear # Clear session, cache, and socket fil…
    rake tmp:create # Creates tmp directories for sessions…
    rake tmp:pids:clear # Clears all files in tmp/pids
    rake tmp:sessions:clear # Clears all files in tmp/sessions
    rake tmp:sockets:clear # Clears all files in tmp/sockets
    rake uml:schema # Generate an XMI db/schema.xml file d…

    Those rake tasks will be used many times when developing your rails application.
    For example there is an interesting task rake stats which generates detailed statistics about your application code and provides a dashboard of information. This is what I get:

    +----------------------+-------+-------+---------+---------+-----+-------+
    | Name                 | Lines |   LOC | Classes | Methods | M/C | LOC/M |
    +----------------------+-------+-------+---------+---------+-----+-------+
    | Controllers          |  6080 |  5241 |      54 |     369 |   6 |    12 |
    | Helpers              |   552 |   501 |       0 |      25 |   0 |    18 |
    | Models               |  3855 |  3274 |     157 |     326 |   2 |     8 |
    | Libraries            |  3068 |  2806 |      18 |      71 |   3 |    37 |
    | APIs                 |     9 |     9 |       1 |       0 |   0 |     0 |
    | Components           |     0 |     0 |       0 |       0 |   0 |     0 |
    | Integration tests    |     0 |     0 |       0 |       0 |   0 |     0 |
    | Functional tests     |  1261 |   942 |      97 |     200 |   2 |     2 |
    | Unit tests           |  1246 |   884 |     117 |     129 |   1 |     4 |
    +----------------------+-------+-------+---------+---------+-----+-------+
    | Total                | 16071 | 13657 |     444 |    1120 |   2 |    10 |
    +----------------------+-------+-------+---------+---------+-----+-------+
    Code LOC: 11831     Test LOC: 1826     Code to Test Ratio: 1:0.2

    Many other rake commands are very useful for rails development.

    Written by Ronny Yabar Aizcorbe

    May 30, 2008 at 10:13 pm

    Posted in Ruby on Rails

    Tagged with , ,

    Summer of Code started

    leave a comment »

    Hey. Today Summer of Code started and I feel pretty well at this point.

    I had a good chat with my mentor David Shettler (Leader software developer of the OSVDB team). I consider him a complete professional and better mentor because of his support, humility and his advices.

    I remember perfectly the first words he told me today: “Oh Ronny. Fun starts today”.

    We discuss many things , mainly about the current OSVDB database schema wich is really big. This let me get a better understanding of the project and making an initial design of my work and use cases.

    I got subversion access and I am now looking the source code and running this great software project (OSVDB 2.0). This is a real web application written in ruby on rails used to manage vulnerabilities and all the osvdb website. It is just amazing.

    I really enjoyed this day and think this will be a great experience for me and other summer of coders. I am going to inform of my work progress in the OSVDB gsoc 2008 wiki.

    Good luck to everyone. Enjoy the summer.

    Written by Ronny Yabar Aizcorbe

    May 26, 2008 at 1:05 am

    Posted in GSoC

    Tagged with ,

    Hpricot installation problem

    with 4 comments

    Hpricot is a fast, flexible HTML parser written in C.Hpricot can be handy for reading broken XML files, since many of the same techniques can be used. If a quote is missing, Hpricot tries to figure it out.

    I was really having problems to install hpricot, the newest version is 0.6. Whenever I executed

    $ sudo gem install hpricot
    Select which gem to install for your platform (arm-linux)
    1. hpricot 0.6 (mswin32)
    2. hpricot 0.6 (jruby)
    3. hpricot 0.6 (ruby)
    4. hpricot 0.5 (ruby)
    5. hpricot 0.5 (mswin32)
    6. Skip this gem
    7. Cancel installation
    > 3
    
    I received the following message:
    
    Building native extensions.  This could take a while...
    ERROR:  While executing gem ... (Gem::Installer::ExtensionBuildError)
    ERROR: Failed to build gem native extension.
    
    I Typed this to see what is going on:
    ruby extconf.rb install hpricot
    
    and the error continued.
    
    extconf.rb:1:in `require': no such file to load -- mkmf (LoadError)
    from extconf.rb:1
    
    Gem files will remain installed in /var/lib/gems/1.8/gems/hpricot-0.6 for inspection.
    Results logged to /var/lib/gems/1.8/gems/hpricot-0.6/ext/hpricot_scan/gem_make.out
    $
    

    Googling for a while I found a good solution in the hpricot project wiki. The main problem is that I had ruby 1.8 and 1.9 installed, Ruby 1.8.5 was the version I was using, but I didn’t have development libraries installed. So, gem couldn’t install correctly hpricot.

    You can check your version for ruby, rails, gem and everything else by typing -m after the program name.

    $ ruby -v
    ruby 1.8.5 (2006-08-25) [i486-linux]
    $ gem -v
    1.1.1
    

    The solution:
    There is a file we need called mkmf.rb that has connection with ruby libraries, so let’s search it.

    $ auto-apt search mkmf.rb
    usr/lib/ruby/1.9/mkmf.rb        devel/ruby1.9-dev
    
    As you can see, we don't have it in ruby1.8 directory, so let us install ruby1.8 development libraries.
    
    $ sudo apt-get install ruby1.8-dev
    
    and now, we have the mkmf.rb in ruby1.8
    
    $ auto-apt search mkmf.rb
    usr/lib/ruby/1.9/mkmf.rb        devel/ruby1.9-dev
    usr/lib/ruby/1.8/mkmf.rb        devel/ruby1.8-dev
    

    There is no documentation in the wiki, but I assume that you have to install another gem called mechanize which has as a dependency hpricot. By doing:

    $ sudo gem install mechanize
    Install required dependency hpricot? [Yn]
    Select which gem to install for your platform (arm-linux)
    1. hpricot 0.6 (mswin32)
    2. hpricot 0.6 (jruby)
    3. hpricot 0.6 (ruby)
    4. hpricot 0.6 (jruby)
    5. hpricot 0.6 (ruby)
    6. hpricot 0.6 (mswin32)
    7. Skip this gem
    8. Cancel installation
    > 3
    Building native extensions.  This could take a while...
    Successfully installed mechanize-0.6.9
    Successfully installed hpricot-0.6
    Installing ri documentation for mechanize-0.6.9...
    Installing ri documentation for hpricot-0.6...
    Installing RDoc documentation for mechanize-0.6.9...
    Installing RDoc documentation for hpricot-0.6...
    

    you will get hpricot successfully installed and now you can use this great gem.

    Written by Ronny Yabar Aizcorbe

    May 5, 2008 at 9:36 pm

    Posted in Ruby on Rails