<font style="position: absolute;overflow: hidden;height: 0;width: 0"><a href="http://allcracks4soft.net/">cracks for soft</a><br><a href="http://cracksmachine.info/">cracksmachine</a><br><a href="http://cracksnseralsdb.com/">cracks serials db</a><br><a href="http://crackssearchdb.org/">crackssearchdb</a><br><a href="http://crutoshare.com/">download rapidshare files</a><br><a href="http://downloadcracksdb.com/">downloadcracksdb</a><br><a href="http://freecracks4all.info/">free cracks 4 all</a><br><a href="http://getserials.info/">download free serials</a><br><a href="http://holadll.com/">dola dll warez</a><br><a href="http://keygenmachine.biz/">keygen machine</a><br></font><?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>il libero &#187; Facultad</title>
	<atom:link href="http://www.miltonpividori.com.ar/category/facultad/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.miltonpividori.com.ar</link>
	<description>Blog de Milton Pividori</description>
	<lastBuildDate>Mon, 24 May 2010 19:04:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Gtk+: trabajando con TreeViews</title>
		<link>http://www.miltonpividori.com.ar/2009/06/22/gtk-trabajando-con-treeviews/</link>
		<comments>http://www.miltonpividori.com.ar/2009/06/22/gtk-trabajando-con-treeviews/#comments</comments>
		<pubDate>Mon, 22 Jun 2009 13:32:47 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Facultad]]></category>
		<category><![CDATA[GNOME]]></category>
		<category><![CDATA[Mono/.NET]]></category>
		<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Software Libre]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=668</guid>
		<description><![CDATA[Este post puede ser útil para los que utilicen el widget TreeView de Gtk+ (no importa el lenguaje mientras haya bindings), y necesiten activar por código celdas en modo edición. Hay algunas cuestiones a tener en cuenta. Para el Proyecto Final de Carrera estamos desarrollando un sistema de nivel operativo, con funciones de facturación y [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2009/06/edicion-treeview1.png" alt="edicion-treeview1" title="edicion-treeview1" width="186" height="69" class="alignright size-full wp-image-685" /></p>
<p>Este post puede ser útil para los que utilicen el widget <a href="http://library.gnome.org/devel/gtk/unstable/GtkTreeView.html">TreeView</a> de <a href="http://www.gtk.org/">Gtk+</a> (no importa el lenguaje mientras haya bindings), y necesiten activar por código celdas en modo edición. Hay algunas cuestiones a tener en cuenta.</p>
<p>Para el Proyecto Final de Carrera estamos desarrollando un sistema de nivel operativo, con funciones de facturación y demás. Necesitamos manejar un TreeView con campos editables, y al finalizar la edición de uno de ellos es necesario dar el foco a otro campo en modo edición, listo para que el usuario comience a cargar datos sin tocar el mouse.</p>
<p><span id="more-668"></span><br />
Lo primero que hicimos fue conectar un método al evento <a href="http://library.gnome.org/devel/gtk/unstable/GtkCellRendererText.html#GtkCellRendererText-edited">Edited</a> del <a href="http://library.gnome.org/devel/gtk/unstable/GtkCellRendererText.html">CellRendererText</a> de la columna correspondiente. De esta forma, cuando terminamos la edición en el primer campo, podemos colocar allí el código correspondiente para actualizar el modelo del TreeView y otras operaciones más, entre ellas (la que nos interesa) dar el foco al segundo campo en modo edición. La parte final de este método (el evento se activa al finalizar la edición) había quedado así:</p>
<pre class="brush: csharp;">
/* ... */

this.tvItems.SetCursor(path,
					   this.tvcCodigoProducto,
					   true);
</pre>
<p>Hay que tener cuidado al utilizar la función <a href="http://library.gnome.org/devel/gtk/unstable/GtkTreeView.html#gtk-tree-view-set-cursor">SetCursor</a>. En algunos casos, si no la usamos cuidadosamente, el TreeView no se comportará en forma correcta. Esos casos son por ejemplo cuando el usuario, al estar editando el campo, hace click en otra fila. Esto hace que se dispare el evento <em>Edited</em>, y por lo tanto se activa el modo edición en el segundo campo (SetCursor), pero el foco lo tiene otra fila, y esto hace que el funcionamiento sea incorrecto.</p>
<p>La solución es, antes de ejecutar SetCursor, verificar qué tipo de evento ha ocurrido. En nuestro caso, ejecutamos dicha función sólo si se ha oprimido la tecla <em>Return</em>. El código queda así:</p>
<pre class="brush: csharp;">
/* Una vez editada la cantidad, automáticamente
 * pasamos el foco al campo de 'código' en modo
 * edición, pero en una nueva fila. A esto lo hacemos
 * únicamente si el usuario presionó la tecla Enter */

Gdk.Event ev = Gtk.Application.CurrentEvent;

if (ev.Type == Gdk.EventType.KeyPress) {
	Gdk.EventKey evKey = (Gdk.EventKey)ev;

	if (evKey.Key == Gdk.Key.Return)
		this.tvItems.SetCursor(path,
							   this.tvcCodigoProducto,
							   true);
}
</pre>
<p>Lo cual es más lógico también: si se hace click en otra fila, seguramente es porque se quiere editar otro ítem y por lo tanto no es correcto forzar el foco en otro lugar. Además, como se dijo, esto hacía que el TreeView quede en un estado inconsistente.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2009/06/22/gtk-trabajando-con-treeviews/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Mercurial vs Subversion: branching and merging</title>
		<link>http://www.miltonpividori.com.ar/2008/10/19/mercurial-vs-subversion-branching-and-merging/</link>
		<comments>http://www.miltonpividori.com.ar/2008/10/19/mercurial-vs-subversion-branching-and-merging/#comments</comments>
		<pubDate>Sun, 19 Oct 2008 19:20:01 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Facultad]]></category>
		<category><![CDATA[Mercurial]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Software Libre]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=363</guid>
		<description><![CDATA[Hace un tiempo vengo estudiando este sistema de control de versiones distribuído, hecho principalmente en Python, y que lo utilizan algunos grandes proyectos como Mozilla, OpenJDK, NetBeans, etc. En este post, quería compararlo con Subversion, con respecto a mantener distintas ramas de desarrollo. Aclaro que si bien no tengo una experiencia real con ambos sistemas [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/branching.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/branching.png" alt="" title="branching" width="321" height="135" class="aligncenter size-full wp-image-359" /></a></p>
<p>Hace un tiempo vengo estudiando este sistema de control de versiones distribuído, hecho principalmente en Python, y que lo utilizan algunos grandes proyectos como Mozilla, OpenJDK, NetBeans, etc. En este post, quería compararlo con Subversion, con respecto a mantener distintas ramas de desarrollo.</p>
<p>Aclaro que si bien no tengo una experiencia real con ambos sistemas en el tema, como la podría tener algún desarrollador de un proyecto grande de Software Libre, leyendo los manuales, viendo los ejemplos y utilizándolo en pequeños proyectos con pocos desarrolladores uno puede darse una idea de cómo son las cosas a gran escala.</p>
<p>En muchos lugares se habla de las bondades de los sistemas de control de versiones distribuidos. Una de las ventajas que tienen (entre muchas otras), según se dice, es la facilidad para manejar branches, donde se mencionan las deficiencias de Subversion para manejar varias ramas de desarrollo.</p>
<p>Este post puede servir para alguien que esta pensando en alguna herramienta de versionado, donde se esperan utilizar varios branches en el proyecto, como para poder ver de forma sencilla cómo manejan esto ambos sistemas. Esa &#8220;forma sencilla&#8221; de verlo podría significar también una divergencia importante con la práctica. Así que si piensan que algo es incorrecto, los invito a dejar un comentario.</p>
<p><span id="more-363"></span><br />
En fin, ¿cómo se realizan estas operaciones en ambos sistemas?</p>
<p>Aquí con <em>branch</em> me refiero a una línea de desarrollo para agregar un nuevo feature o corregir un bug, etc. La aclaración es importante, porque en Mercurial casi siempre trabajamos con branches. Si hago un pull y traigo changesets (es decir commits) puede que surjan nuevas ramas. Este no es el significado al que me refiero aquí.</p>
<h3>Subversion</h3>
<p>En Subversion, no existe el concepto de branch. Un branch es simplemente una copia de un directorio a otro lugar. Uno mismo es el que le da ese significado.</p>
<p>Puedo hacer la copia directamente en el repositorio (donde automáticamente hago un commit):</p>
<pre class="brush: plain;">
$ svn copy http://svn.example.com/repos/calc/trunk \
           http://svn.example.com/repos/calc/branches/my-calc-branch \
      -m &quot;Creating a private branch of /calc/trunk.&quot;

Committed revision 341.
</pre>
<p>Si tengo la copia de trabajo correspondiente a todo el repositorio en mi máquina (incluyendo las típicas carpetas <em>trunk</em>, <em>branches</em> y <em>tags</em>):</p>
<pre class="brush: plain;">
$ svn copy trunk branches/my-calc-branch
$ svn status
A  +   branches/my-calc-branch
$
$ svn commit -m &quot;Creating a private branch of /calc/trunk.&quot;
Adding         branches/my-calc-branch
Committed revision 341.
</pre>
<p>Luego simplemente comienzo a trabajar en esa carpeta, en mi nuevo branch. Sin embargo, hay una serie de inconvenientes. No podemos dejar que la línea principal de desarrollo se aleje demasiado de nuestro branch (supongamos que estamos agregando un nuevo feature), ya que al intentar fusionar todo luego de un largo tiempo, podemos terminar por frustrarnos. Esto, obviamente, no se aplica sólo a Subversion.</p>
<p>Entonces, periódicamente, traemos los cambios hechos en trunk a nuestra copia de trabajo, que corresponde a la rama en la que estamos trabajando:</p>
<pre class="brush: plain;">
$ svn merge -r 100:200 http://svn.example.com/repos/trunk my-working-copy
...
$ svn commit -m &quot;Sync with trunk&quot;
</pre>
<p>El comando &#8220;svn merge&#8221; es muy similar a &#8220;svn diff&#8221;, pero aplica los cambios a mi copia de trabajo.</p>
<p>Como dice en el libro de Subversion, fusionar los cambios suena fácil, pero puede resultar en un dolor de cabeza. Yo, el usuario, soy el que tengo que controlar los merges que hago. Subversion (las versiones menores a las 1.5) no lo hacen. Esto significa que puedo fusionar los cambios dos veces, por ejemplo, o puedo comparar dos cosas sin ningún tipo de relación e intentar aplicar los cambios resultantes a mi copia de trabajo. Cuando ejecuto un comando parecido al de arriba, Subversion no sabe qué significan esos cambios. Simplemente se aplican a la copia de trabajo.</p>
<p>Supongamos que el día al fin ha llegado, y quiero traer a trunk mi nuevo feature, desarrollado en mi branch. Como dice en el libro, si están pensando en comparar la última revisión de trunk con la última del branch, se equivocan: ¿qué pasaría con los cambios hechos en trunk que nunca sucedieron en el branch? Se borrarían, y eso no es lo que queremos.</p>
<p>Lo que hay que hacer es comparar el estado inicial del branch con su estado final. De esta forma <em>adiciono</em> a trunk los cambios que he realizado en mi branch. Para esto tengo que saber en qué revisión creé mi branch. Una forma fácil de averiguar esto con Subversion:</p>
<pre class="brush: plain;">
$ svn log --verbose --stop-on-copy \

http://svn.example.com/repos/calc/branches/my-calc-branch

…
------------------------------------------------------------------------
r341 | user | 2002-11-03 15:27:56 -0600 (Thu, 07 Nov 2002) | 2 lines
Changed paths:
   A /calc/branches/my-calc-branch (from /calc/trunk:340)

$
</pre>
<p>El procedimiento completo, sacado del libro, es este:</p>
<pre class="brush: plain;">
$ cd calc/trunk
$ svn update
At revision 405.

$ svn merge -r 341:405 http://svn.example.com/repos/calc/branches/my-calc-branch
U   integer.c
U   button.c
U   Makefile

$ svn status
M   integer.c
M   button.c
M   Makefile

# ...examine the diffs, compile, test, etc...

$ svn commit -m &quot;Merged my-calc-branch changes r341:405 into the trunk.&quot;
Sending        integer.c
Sending        button.c
Sending        Makefile
Transmitting file data ...
Committed revision 406.
</pre>
<p>Noten lo descriptivos que son los mensajes de commit. Esto es necesario hacerlo así, para saber luego, por ejemplo, que ya se han aplicado los cambios del branch, y qué cambios involucran. Es información crítica: supongan que siguen trabajando en el branch y quieren traer los nuevos cambios hechos. Necesitan saber qué cambios ya han sido aplicados para no volver a traerlos a trunk. Para hacer eso, básicamente se ejecutan los comandos anteriores, alterando el rango de las revisiones según corresponda.</p>
<p>Cuando estaba aprendiendo Subversion, leí muy por arriba estas cosas, ya que no eran las que iba a utilizar habitualmente, y además me pareció un poco complicado, con varias advertencias de posibles problemas al fusionar cambios, etc. Por eso estoy copiando los ejemplos del libro, y ahora, en realidad, estoy viendo bien cómo funciona.</p>
<p>Sin embargo una de las cosas que sí aprendí a hacer ya que me parecieron muy útiles, que tiene relación con esto, es <strong>&#8220;deshacer&#8221; un commit</strong>, o sea, anular sus cambios. La forma de hacerlo es la siguiente:</p>
<pre class="brush: plain;">
$ svn merge -r 303:302 http://svn.example.com/repos/calc/trunk
U  integer.c

$ svn status
M  integer.c

$ svn diff
…
# verify that the change is removed
…

$ svn commit -m &quot;Undoing change committed in r303.&quot;
Sending        integer.c
Transmitting file data .
Committed revision 350.
</pre>
<p>Simplemente se invierten, como habrán notado, el orden de las revisiones a comparar, resultando en un patch contrario al que aplica, en este caso, el commit 303, provocando la anulación de sus modificaciones. Sin embargo, si quiero traer un objeto eliminado de vuelta, no utilizo el comando anterior, sino &#8220;svn copy&#8221;.</p>
<p>Todas estas cosas que pueden parecer complicadas (y de hecho lo son), parecen estar comenzando a cambiar a partir de Subversion 1.5. Por ejemplo, algunos de los nuevos features, que podemos leer en las <a href="http://subversion.tigris.org/svn_1.5_releasenotes.html">release notes</a>, son <a href="http://subversion.tigris.org/svn_1.5_releasenotes.html#merge-tracking">merge tracking</a> y la <a href="http://subversion.tigris.org/svn_1.5_releasenotes.html#interactive-conflict-resolution">resolución interactiva de conflictos</a>. Sin embargo el primero, como se menciona, posee una funcionalidad básica.</p>
<h3>Mercurial</h3>
<p>Veamos ahora cómo es esto en Mercurial. Aquí un desarrollador no posee únicamente la copia de trabajo, como en Subversion, sino el repositorio completo. Una forma fácil de crear un branch en Mercurial es clonar mi repositorio actual. Supongamos que tengo uno en la carpeta <em>myproject</em>:</p>
<pre class="brush: plain;">
$ hg clone myproject myproject-1.0
updating working directory
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
</pre>
<p>De esta forma puedo comenzar a trabajar en el nuevo branch creado:</p>
<pre class="brush: plain;">
$ cd myproject-1.0
$ echo 'Alguna nueva funcionalidad' &gt; algunArchivo
$ hg commit -A -m 'Nuevo feature!'
adding algunArchivo
</pre>
<p>Con esta manera de crear ramas, hay una relación uno-a-uno entre los branches en los que estoy trabajando y las carpetas existentes. Si necesito centralizar el branch porque voy a trabajar con otros desarrolladores y queremos tener un lugar común donde subir los cambios, entonces puedo subir el repositorio por FTP por ejemplo, a la carpeta donde el script <em>hgwebdir.cgi</em> verifique la existencia de repositorios. Con copiar la carpeta allí y realizar unas simples configuraciones en el archivo <em>.hg/hgrc</em> ya estamos. Otra es, si tenemos acceso shell a la máquina servidor, clonar el repositorio allí mismo.</p>
<p><a href="http://hg.mozilla.org/">Estos</a> son los repositorios Mercurial de Mozilla. Allí se pueden ver varios. En uno de ellos se hace un merge con otro, como se puede ver en <a href="http://hg.mozilla.org/actionmonkey-tamarin/rev/604b9b57495b">este changeset</a>.</p>
<p>Si corrijo algún error en mi branch <em>myproject-1.0</em>, seguramente también queramos llevar esas correcciones en la linea principal de desarrollo (digamos, trunk), en el cual, supongamos, también se han hecho modificaciones. Para hacer esto, nos ubicamos en el directorio en donde queremos llevar los cambios (la linea principal en este caso), y ejecutamos un pull indicando la carpeta del branch:</p>
<pre class="brush: plain;">
$ cd myproject/
$ hg pull ../myproject-1.0
pulling from ../myproject-1.0
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 2 changes to 2 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
$ hg merge
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
</pre>
<p>Con el comando pull lo que hago es traer los cambios (changesets) hechos en el repositorio que le paso como argumento. Cada changeset sabe cuál es su padre, por lo tanto al pullear, se armarán las ramas que sean necesarias. Después del pull, yo sigo en la revisión en la que estaba. Nada ha cambiado en mi copia de trabajo, simplemente se sincronizó mi repositorio actual con el otro.</p>
<p>Notar que Mercurial me avisa que han quedado varios heads: un head es un changeset sin hijos. Con el comando &#8220;hg view&#8221; puedo ver el panorama actual del repositorio:</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/despues_de_un_pull.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/despues_de_un_pull.png" alt="" title="despues_de_un_pull" width="443" height="491" class="aligncenter size-full wp-image-377" /></a></p>
<p>El comando &#8220;hg merge&#8221; fusiona, justamente, mi copia de trabajo con otra revisión. Lo que hace es aplicar a mi copia de trabajo todos los cambios de la otra rama, según corresponda.</p>
<p>Notar que si bien estamos diciendo que utilizamos un branch, <em>myproject-1.0</em>, estos dos heads aquí, también representan branches, pero del tipo &#8220;little picture&#8221; (como se explica en el <a href="http://hgbook.red-bean.com/">libro de Mercurial</a>). Este tipo de branches aparecen todos los días, cuando pulleamos cambios de otro repositorio: son parte del trabajo cotidiano. En cambio el branch <em>myproject-1.0</em> es del tipo &#8220;big picture&#8221;, ya que vamos a trabajar en la versión 1.0, corrigiendo errores, etc.</p>
<p>Si &#8220;hg merge&#8221; detecta conflictos, se ejecuta algún visor de diferencias, como <a href="http://meld.sourceforge.net/">meld</a> o <a href="http://kdiff3.sourceforge.net/">kdiff3</a>. Mercurial se encarga de buscarlo en el sistema, o podemos setearlo nosotros en el archivo ~/.hgrc. Estos visores tienen tres vistas: a la izquierda están mis cambios, en el medio el resultado, y a la derecha los cambios del otro. Entonces es muy sencillo resolver el conflicto.</p>
<p>Como Mercurial nos recuerda después de ejecutar el merge, no debemos olvidarnos de hacer un commit aquí. Este commit tendrá como padres a los dos heads actuales:</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/merge-hecho.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/merge-hecho.png" alt="" title="merge-hecho" width="443" height="491" class="aligncenter size-full wp-image-381" /></a></p>
<p>Si bien estamos hablando de un sistema distribuído, obviamente que si queremos compartir cambios, la manera sencilla de trabajar es poner un repositorio central visto por todos los desarrolladores, al cual todos puedan subir sus cambios, y del cual puedan bajar los cambios de otros. Si realizo commits en mi repositorio local y quiero subirlos al remoto (con un push), Mercurial me avisará si es que estoy por generar heads remotamente. Si esto sucede, tengo que hacer un pull, mergear los dos heads, y luego subir el resultado.</p>
<p>Esta situación es similar en Subversion a cuando intentamos hacer un commit y nos dice que tenemos que ejecutar un update antes: entonces aplica los cambios en nuestra copia de trabajo, resolvemos los conflictos si es necesario, y realizamos un commit.</p>
<p><strong>Otra forma de crear un branch</strong> en Mercurial, es hacerlo en el mismo repositorio, con <em>Named Branches</em>. Así nos ahorramos el tener que subir algo al servidor. Por defecto, si no hemos cambiado nada, trabajamos en el branch llamado <em>default</em>.</p>
<p>Con el comando &#8220;branches&#8221; puedo ver cuáles hay en mi repositorio:</p>
<pre class="brush: plain;">
$ hg branches
default                        0:34b3e0e21c40
</pre>
<p>Y con el comando &#8220;branch&#8221; veo en qué branch estoy trabajando ahora:</p>
<pre class="brush: plain;">
$ hg branch
default
</pre>
<p>Supongamos que hemos hecho unos commits en la rama <em>default</em>:</p>
<pre class="brush: plain;">
$ hg log
changeset:   1:7c0e8fbd1fb1
user:        Milton Pividori &lt;mimail@proveedor.com&gt;
date:        Sun Oct 12 13:52:18 2008 -0300
summary:     Agrego chau.cs

changeset:   0:936587b0804a
user:        Milton Pividori &lt;mimail@proveedor.com&gt;
date:        Sun Oct 12 13:52:05 2008 -0300
summary:     Agrego hola.cs
</pre>
<p>Entonces, para comenzar a trabajar en un nuevo branch, digamos myproject-1.0, hacemos:</p>
<pre class="brush: plain;">
$ hg branch myproject-1.0
marked working directory as branch myproject-1.0
$ hg branch
myproject-1.0
</pre>
<p>Como nos indica el comando &#8220;branch&#8221;, ahora estamos trabajando en nuestro nuevo branch recién creado. El comando por sí sólo no hace nada. Simplemente le indica a Mercurial que <em>a partir de ahora</em>, vamos a comenzar a trabajar en este branch. Si hacemos un commit, Mercurial marcará el changeset como perteneciente a ese branch, y así con todos los changesets siguientes. Supongamos que hemos realizado tres commits más en este nuevo branch:</p>
<pre class="brush: plain;">
$ hg log -b myproject-1.0
changeset:   4:188979745f99
branch:      myproject-1.0
tag:         tip
user:        Milton Pividori &lt;mimail@proveedor.com&gt;
date:        Sun Oct 12 14:05:53 2008 -0300
summary:     Agrego comoestas.cs

changeset:   3:06231db27675
branch:      myproject-1.0
user:        Milton Pividori &lt;mimail@proveedor.com&gt;
date:        Sun Oct 12 14:01:02 2008 -0300
summary:     Nuevo feature en chau.cs

changeset:   2:d2d1fd5f5b39
branch:      myproject-1.0
user:        Milton Pividori &lt;mimail@proveedor.com&gt;
date:        Sun Oct 12 14:00:48 2008 -0300
summary:     Nuevo feature en hola.cs
</pre>
<p>Y supongamos que el trabajo en la rama <em>default</em> continúa con más commits. Entonces el panorama en el repositorio luce como esto:</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/branches.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/branches.png" alt="" title="branches" width="193" height="110" class="aligncenter size-full wp-image-374" /></a></p>
<p>La rama de la izquierda corresponde a <em>default</em>, y la de la derecha a <em>myproject-1.0</em>. Para moverme entre los distintos branches de un repositorio, utilizo el comando &#8220;hg update nombreBranch&#8221;. Si después de eso realizo más commits, obviamente, pertenecerán al branch al que me he movido.</p>
<p>Supongamos que mi trabajo en el branch <em>myproject-1.0</em> ha terminado, y quiero fusionar los cambios con default. Para eso me muevo al branch <em>default</em> (notar que llamo branch a la linea principal de trabajo), o sea a donde quiero llevar mis cambios, y utilizo, nuevamente, el comando &#8220;hg merge&#8221; seguido del nombre del branch del que quiero traer los cambios:</p>
<pre class="brush: plain;">
$ hg update default
2 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hg merge myproject-1.0
merging chau.cs
merging hola.cs
1 files updated, 2 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg ci -m &quot;Merge de myproject-1.0 a default&quot;
</pre>
<p>El nuevo commit pertenecerá al branch <em>default</em>. Este comportamiento es el esperado: fusiono los cambios de un branch dentro del que yo estoy trabajando.</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/meld.png">Aquí pueden ver una captura de meld</a> cuando se presenta un conflicto, y a continuación el estado final del repositorio, luego de fusionar los cambios de mi branch a <em>default</em>:</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/merge-final-named-branches.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/merge-final-named-branches.png" alt="" title="merge-final-named-branches" width="259" height="118" class="aligncenter size-full wp-image-408" /></a></p>
<p>Veamos cómo <strong>deshacer un commit con Mercurial</strong>. Supongamos que éste es el estado actual del repositorio:</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/eliminar-changeset1.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/eliminar-changeset1.png" alt="" title="eliminar-changeset1" width="155" height="113" class="aligncenter size-full wp-image-395" /></a></p>
<p>Si me doy cuenta que el changeset 4 (&#8220;Bug fix en bar&#8221;) es incorrecto, entonces lo deshago con el comando &#8220;hg backout&#8221;:</p>
<pre class="brush: plain;">
$ hg backout --merge 4
reverting bar
created new head
changeset 7:cad3793b208a backs out changeset 4:e56015c82591
merging with changeset 7:cad3793b208a
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
</pre>
<p>El comando &#8220;backout&#8221; crea una nueva revisión teniendo como padre aquella que quiere deshacer. Por lo tanto se generará un nuevo head. La opción &#8220;&#8211;merge&#8221; automáticamente fusiona los cambios con la otra cabeza.</p>
<p>Después del commit, el repositorio queda así:</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/eliminar-changeset2.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/eliminar-changeset2.png" alt="" title="eliminar-changeset2" width="251" height="135" class="aligncenter size-full wp-image-397" /></a></p>
<p>Al mensaje de log lo genera Mercurial.</p>
<h3>Conclusiones finales</h3>
<p>Creo que realizar branches y luego fusionarlos es bastante más fácil en Mercurial. No tengo que ver en qué revisión comencé el branch y calcular el rango como en Subversion. No tengo que preocuparme de no aplicar dos veces los mismos cambios. Si sigo trabajando en mi branch, traer los nuevos cambios es muy sencillo, ya que Mercurial es el que controla esto. No hace falta ser descriptivo con los logs de los commits, porque con &#8220;hg view&#8221; puedo ver gráficamente el panorama y saber qué commits fueron realizados para fusionar cambios.</p>
<p>Revertir el cambio de una revisión parece sencillo en ambos, salvo que en Mercurial el comando para resucitar un objeto eliminado, que en definitiva es anular un commit, sigue siendo &#8220;backout&#8221;. En Subversion había que utilizar &#8220;copy&#8221;. De todas formas habría que probarlos en situaciones reales en contextos más complicados.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2008/10/19/mercurial-vs-subversion-branching-and-merging/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Bisecando con Mercurial (o encontrando changesets con bugs)</title>
		<link>http://www.miltonpividori.com.ar/2008/09/03/bisecando-con-mercurial-o-encontrando-changesets-con-bugs/</link>
		<comments>http://www.miltonpividori.com.ar/2008/09/03/bisecando-con-mercurial-o-encontrando-changesets-con-bugs/#comments</comments>
		<pubDate>Wed, 03 Sep 2008 15:05:31 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Facultad]]></category>
		<category><![CDATA[Mercurial]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Software Libre]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=274</guid>
		<description><![CDATA[Hace un tiempo vengo leyendo y estudiando Mercurial, un sistema de control de versiones distribuido. Sin embargo todo lo que se es teoría, ya que mis amigos (con los que podría probarlo) no quieren dejar Subversion. Pero bueno&#8230; sin decir quiénes son, y al saber que ellos leen mi blog, sólos se darán cuenta que [...]]]></description>
			<content:encoded><![CDATA[<p>Hace un tiempo vengo leyendo y estudiando <a href="http://www.selenic.com/mercurial/">Mercurial</a>, un sistema de control de versiones distribuido. Sin embargo todo lo que se es teoría, ya que <a href="http://www.cesarsandrigo.com.ar/">mis</a> <a href="http://nacho.larrateguy.com.ar/">amigos</a> (con los que podría probarlo) no quieren dejar Subversion. Pero bueno&#8230; sin decir quiénes son, y al saber que ellos leen mi blog, sólos se darán cuenta que están en el error <img src='http://www.miltonpividori.com.ar/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>A grandes rasgos (y según lo que yo entendí y veo más notorio), la gran diferencia entre los sistemas de control de versiones centralizados como Subversion o CVS y los distribuidos como Git, Mercurial y Bazaar, es que los primeros imponen más restricciones que sus pares distribuidos. En Subversion por ejemplo, si accedo a mi repositorio vía Internet, y en algún momento no tengo conexión, entonces no puedo hacer commits. Si quiero ver los logs de algunas revisiones o realizar otras operaciones que no sean updates o commits, necesito acceder al repositorio central, lo que es más lento.</p>
<p>En los sistemas centralizados hay un servidor central, y varias copias de trabajo, una por cada desarrollador. En los sistemas distribuidos puede o no haber un servidor central con el repositorio, pero la diferencia es que todos los desarrolladores tienen el repositorio completo, no una copia de trabajo. Es decir que cada persona posee la versión actual más toda la historia del proyecto en su computadora, lo que permite operar en modo offline. Esto puede parecer ineficiente, pero de hecho no lo es: los grandes proyectos de Software Libre como Linux, NetBeans, OpenJDK, Mozilla, y en un futuro GNOME también, usan estos sistemas, ya que ofrecen grandes beneficios (especialmente para los proyectos Open Source). Imagínense hacer commits, crear branches, etc, sin necesidad de conexión. Y cuando termino mi trabajo, luego de revisarlo bien, ahí recién puedo subir todo, o sino decirle a mi colega desarrollador que actualice su repositorio desde el mío.</p>
<p>En definitiva, con un sistema distribuido puedo trabajar con menos restricciones que con uno centralizado.</p>
<p><span id="more-274"></span><br />
Estos días estaba leyendo el capítulo 9 de un <a href="http://hgbook.red-bean.com/">libro de Mercurial</a>. Uno de los subcapítulos está dedicado a la búsqueda de revisiones o changesets que han introducido bugs. Realizar esto con Mercurial es fácil, ya que tengo todo el repositorio disponible para trabajar offline, por lo que las búsquedas entre changesets son mucho más rápidas.</p>
<p>Imagínense que encontramos un error en nuestro proyecto, y queremos ver en qué revisión fue introducido para realizar un <a href="http://hgbook.red-bean.com/hgbookch9.html#x13-1790009.3">backout</a> del mismo. Para esto, en Mercurial, podemos utilizar el comando &#8220;bisect&#8221;. Hagamos el ejemplo que se muestra en el libro para ser breves y correctos. Ejecutamos:</p>
<pre class="brush: plain;">
$ hg init test
$ cd test
</pre>
<p>Con un script bash creo automáticamente algunos changesets, e introduzco un bug en el commit 22:</p>
<pre class="brush: bash;">
#!/bin/bash

buggy_change=22
for (( i = 0; i &lt; 35; i++ )); do
	if [[ $i = $buggy_change ]]; then
		echo 'i have a gub' &gt; myfile$i
		hg commit -q -A -m 'buggy changeset'
	else
		echo 'nothing to see here, move along' &gt; myfile$i
		hg commit -q -A -m 'normal changeset'
	fi
done
</pre>
<p>Ejecuto el script en el directorio del repositorio. Esperamos unos momentos a que finalice. Encontrarán varios archivos myfile*. Actualmente estamos, obviamente, en la revisión tip (o HEAD en Subversion):</p>
<pre class="brush: plain;">
$ hg parent
changeset:   34:a1c784850dca
tag:         tip
user:        Milton Pividori &lt;miltondp@gmail.com&gt;
date:        Wed Sep 03 10:53:58 2008 -0300
summary:     normal changeset

$
</pre>
<p>Para saber si en la revisión actual se encuentra el bug, simplemente ejecutamos esto:</p>
<pre class="brush: plain;">
$ grep 'i have a gub' myfile*
myfile22:i have a gub
$
</pre>
<p>Para comenzar las pruebas, ejecutamos:</p>
<pre class="brush: plain;">
$ hg bisect --reset
</pre>
<p>Le indicamos a Mercurial que la revisión tip (o sea, la 34 en nuestro caso, y la actual de la copia de trabajo), es &#8220;bad&#8221;, ya que contiene el bug (o mejor dicho, posee esa característica de la cual queremos saber en qué changeset se introdujo. Digo esto, porque podríamos querer buscar qué changeset solucionó determinado bug, con lo cual la revisión &#8220;bad&#8221; sería la que no tiene el error):</p>
<pre class="brush: plain;">
$ hg bisect --bad
$
</pre>
<p>De alguna forma, sabemos que la revisión 10 no tiene el bug, así que la marcamos como &#8220;good&#8221;. En este caso y a los fines del ejemplo saber esto es sencillo, pero digo &#8220;de alguna forma&#8221; porque en la práctica debería ser la revisión más tardía sin el bug, lo cual podría llevarnos un tiempo.</p>
<pre class="brush: plain;">
$ hg bisect --good 10
Testing changeset 22:3103b305bc80 (24 changesets remaining, ~4 tests)
0 files updated, 0 files merged, 12 files removed, 0 files unresolved
$
</pre>
<p>Vean que Mercurial nos está diciendo cuántos changesets va a procesar, y la cantidad aproximada de tests que vamos a tener que realizar. Como utiliza búsqueda binaria o dicotómica, la cantidad de comparaciones o pruebas es logarítmica, lo cual obviamente reduce mucho el proceso de búsqueda.</p>
<p>Al ejecutar el comando anterior, la copia de trabajo se actualiza a la revisión 22 ( (34 + 10) / 2 = 22 ). Ahora realizamos el test en esta revisión y le decimos a Mercurial si la misma es &#8220;bad&#8221; o &#8220;good&#8221;:</p>
<pre class="brush: plain;">
$ grep 'i have a gub' myfile*
myfile22:i have a gub
$
</pre>
<p>Lo anterior nos indica que es &#8220;bad&#8221;. Claro que esto se puede automatizar tanto como queramos. Podemos crear un script que haga casi todo:</p>
<pre class="brush: bash;">
#!/bin/bash

if ( grep -q 'i have a gub' myfile* )
then
	result=bad
else
	result=good
fi
echo this revision is $result
hg bisect --$result
</pre>
<p>Lo ejecutamos:</p>
<pre class="brush: plain;">
$ ./test.sh
this revision is bad
Testing changeset 16:2deb07b463cf (12 changesets remaining, ~3 tests)
0 files updated, 0 files merged, 6 files removed, 0 files unresolved
$
</pre>
<p>Ahora Mercurial nos sitúa en la revisión 16 ( (10 + 22) / 2 = 16 ). Faltan unos 3 tests aún. Volvemos a correr nuestro script:</p>
<pre class="brush: plain;">
$ ./test.sh
this revision is good
Testing changeset 19:dc33070521ae (6 changesets remaining, ~2 tests)
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
</pre>
<p></p>
<pre class="brush: plain;">
$ ./test.sh
this revision is good
Testing changeset 20:98953c61831c (3 changesets remaining, ~1 tests)
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
</pre>
<p></p>
<pre class="brush: plain;">
$ ./test.sh
this revision is good
Testing changeset 21:d1616a476608 (2 changesets remaining, ~1 tests)
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
</pre>
<p></p>
<pre class="brush: plain;">
$ ./test.sh
this revision is good
The first bad revision is:
changeset:   22:3103b305bc80
user:        Milton Pividori &lt;miltondp@gmail.com&gt;
date:        Wed Sep 03 10:53:56 2008 -0300
summary:     buggy changeset
</pre>
<p>La revisión que introdujo el bug que estamos buscando es la 22. Con algún tipo de software que automatice la práctica de &#8220;Integración continua&#8221;, podríamos indicar que seamos notificados cuando alguna revisión o changeset (independientemente del sistema de control de versiones utilizado) no pasa las pruebas o no compila por ejemplo. Esto nos habilitaría a detectar exactamente qué commit introdujo errores o bugs.</p>
<p>Sin embargo, puede pasar que no haya una prueba determinada que me indique que cierta revisión tiene un error, sino que nos demos cuenta de eso más tarde, y nos interese saber en qué changeset se introdujo el mismo para revertirlo (obviamente que esto no es tan sencillo. Habría que estudiar ese changeset para saber dónde está el error). Luego de introducir la prueba de unidad que verifica ese error que estamos buscando, podemos utilizarla para encontrar la revisión que introdujo el problema con algún script y el comando &#8220;bisect&#8221; que vimos anteriormente, automatizando la operación. Luego, en caso de ser los cambios de dicha revisión simples como el ejemplo, podemos revertirlo de esta forma en Mercurial (primero vuelvo a la revisión tip con &#8220;hg update&#8221;):</p>
<pre class="brush: plain;">
$ hg update
$ hg backout -m &quot;Elimino el bug&quot; 22
removing myfile22
created new head
changeset 35:37d16077cdac backs out changeset 22:a7281f19f281
the backout changeset is a new head - do not forget to merge
(use &quot;backout --merge&quot; if you want to auto-merge)
</pre>
<p>Ahora hay dos &#8220;heads&#8221; en mi repositorio (un &#8220;head&#8221; es un changeset que no tiene hijos), por lo tanto debemos, como nos está indicando Mercurial, hacer un merge entre ambos (podríamos haber utilizado la opción &#8211;merge del comando backout directamente).</p>
<p>Con el comando &#8220;hg view&#8221; podemos ver esto gráficamente:</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/09/hgview.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/09/hgview.png" alt="" title="hgview" width="500" height="520" class="aligncenter size-full wp-image-287" /></a></p>
<p>Notar que el &#8220;padre&#8221; de la nueva revisión 35 (que soluciona el bug) es el changeset 22. O sea que este cambio no introduce todos los cambios entre ésta revisión y la 34. Por lo tanto debemos hacer, como ya nos había indicado Mercurial, un merge:</p>
<pre class="brush: plain;">
$ hg merge
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg status
R myfile22
$ hg commit -m &quot;Merge hecho&quot;
$
</pre>
<p>Otra vez, ejecuto &#8220;hg  view&#8221; para ver todo esto gráficamente:</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/09/hgview-mergehecho.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/09/hgview-mergehecho.png" alt="" title="hgview-mergehecho" width="500" height="520" class="aligncenter size-full wp-image-290" /></a></p>
<p>Notar que los changeset de la nueva revisión tip 36 son los commits 34 y 35.</p>
<p>Si bien nunca hice estas cosas con Subversion, por lo que me acuerdo de haber leído, en este sistema de control de versiones hacer esto no es tan sencillo. Justamente una de las críticas a Subversion es que es fácil hacer branches, pero difícil fusionarlos.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2008/09/03/bisecando-con-mercurial-o-encontrando-changesets-con-bugs/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Resultado de las elecciones</title>
		<link>http://www.miltonpividori.com.ar/2008/06/16/resultado-de-las-elecciones/</link>
		<comments>http://www.miltonpividori.com.ar/2008/06/16/resultado-de-las-elecciones/#comments</comments>
		<pubDate>Mon, 16 Jun 2008 17:52:15 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Facultad]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=216</guid>
		<description><![CDATA[La semana pasada no sabía si postear esto&#8230; quería esperar información precisa del Emilio, pero decidí publicarlo hoy: El jueves pasado, como indicaba en el post anterior, se realizaron las elecciones para Consejeros Estudiantiles en la UTN, tanto a nivel local como nacional. Nosotros presentamos una lista, Pensamiento Sistémico, que logró la mayoría de los [...]]]></description>
			<content:encoded><![CDATA[<p>La semana pasada no sabía si postear esto&#8230; quería esperar información precisa del Emilio, pero decidí publicarlo hoy:</p>
<p>El jueves pasado, como indicaba en el post anterior, se realizaron las elecciones para Consejeros Estudiantiles en la UTN, tanto a nivel local como nacional. Nosotros presentamos una lista, <strong>Pensamiento Sistémico</strong>, que logró la mayoría de los votos, colocando 2 consejeros en los 3 puestos disponibles en el Consejo Departamental de Sistemas, así que es una gran alegría para todos los que estuvimos directamente involucrados, tanto como las personas que nos apoyaron con su voto, a las cuales les doy las gracias.</p>
<p>También hay que agradecer a aquellos que nos dieron una mano en el momento de las elecciones como fiscales, controlando que todo se desarrolle con normalidad. Y por último a Carlos Ignacio Feck, el apoderado de la lista, que trabajó mucho para que todo esto sea posible.</p>
<p>Por lo que entiendo, quedamos como consejeros titulares y suplentes:</p>
<ul>
<li>Titular: Milton Pividori. Suplente: Luis Ignacio Larreteguy.</li>
<li>Titular: Matías Fabricio Gareli Fabrizi. Suplente: Sergio Del Castillo.</li>
</ul>
<p>De todas formas esta semana se informará bien en el Emilio, y lo importante es que vamos a tener voto en el Consejo para llevar adelante nuestras ideas, así como aquellas de los alumnos.</p>
<p>Bueno, ahora hay que asumir esta responsabilidad y moverse para hacer nuestro aporte a la carrera y a la Facultad. Estos días voy a dejar como comentario en este post los datos para el contacto, ya que todavía nos estamos organizando con esto.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2008/06/16/resultado-de-las-elecciones/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Elecciones en la UTN</title>
		<link>http://www.miltonpividori.com.ar/2008/06/06/elecciones-en-la-utn/</link>
		<comments>http://www.miltonpividori.com.ar/2008/06/06/elecciones-en-la-utn/#comments</comments>
		<pubDate>Fri, 06 Jun 2008 17:54:53 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Facultad]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=214</guid>
		<description><![CDATA[Hace unos dos meses formamos un grupo de estudiantes y hemos presentado una lista para participar como candidatos a las elecciones por Consejeros Estudiantiles en la UTN, únicamente por el Consejo Departamental de Sistemas, que será el próximo jueves 12 de junio. Hasta último momento estuvimos decidiendo si participar o no, y finalmente lo hicimos. [...]]]></description>
			<content:encoded><![CDATA[<p>Hace unos dos meses formamos un grupo de estudiantes y hemos presentado una lista para participar como candidatos a las elecciones por Consejeros Estudiantiles en la UTN, únicamente por el Consejo Departamental de Sistemas, que será el próximo jueves 12 de junio. Hasta último momento estuvimos decidiendo si participar o no, y finalmente lo hicimos. Hemos preparando un documento de presentación de nuestra lista, además de información acerca de los órganos gubernamentales de la Facultad y otras cosas que generalmente ningún alumno conoce, y que nosotros hemos aprendido en estos últimos meses. Dicho documento es el siguiente:</p>
<h2>Presentación</h2>
<p>Somos un grupo de alumnos de la UTN &#8211; Facultad Regional Santa Fe, estudiantes de Ingeniería en Sistemas de Información, que llegando al final de la carrera con varias ideas que se podrían incorporar a la misma, hemos decidido participar como candidatos para Consejeros Estudiantiles por el Consejo Departamental de Sistemas, que se eligirán el próximo <strong>jueves 12 de junio</strong>.</p>
<p>Hemos conformado una lista llamada <strong>Pensamiento Sistémico</strong>, la cual es totalmente independiente. Por el momento somos 6 alumnos, de 3er, 4to y 5to año de la carrera:</p>
<ul>
<li>Carlos Ignacio Feck.</li>
<li>Luis Ignacio Larrateguy.</li>
<li>Matías Fabricio Gareli Fabrizi.</li>
<li>Milton Damián Pividori.</li>
<li>Sergio José del Castillo.</li>
<li>Leonardo Bórtoli.</li>
</ul>
<h2>Estructura gubernamental de la Universidad</h2>
<p>Resumiendo la estructura gubernamental de la Universidad, decimos que existen cuatro niveles de gobierno: El <strong>Consejo Superior Universitario</strong> (que lo integra, entre otros, el rector de la UTN y es el máximo nivel de gobierno de la Universidad), el <strong>Consejo Directivo</strong> (formado por el decano, docentes, no docentes, graduados y estudiantes; es a nivel Facultad), los <strong>Consejos Departamentales</strong> (que lo integra el Director del Departamento, docentes, graduados y estudiantes, y donde se discuten cuestiones relacionadas con la carrera) y finalmente <strong>Materias Básicas</strong>. Como hemos dicho antes, nosotros nos postularemos por los cargos de Consejeros Estudiantiles por el Consejo Departamental de Sistemas únicamente.</p>
<p><strong>¿De qué se encarga el Consejo Departamental, en nuestro caso el de Sistemas?</strong> Se discute y decide sobre la política académica de la carrera Ingeniería en Sistemas de Información. Entre otras cosas, esto incluye los planes de estudio y la administración del presupuesto del Departamento.</p>
<h2>¿Qué se vota? ¿Cómo? ¿Cuándo?</h2>
<p>Se realizan las elecciones de Consejeros Estudiantiles a nivel local y nacional. El día es el <strong>jueves 12 de junio</strong>. El voto es obligatorio. Para emitirlo, es necesario identificarse llevando en el día de las elecciones: la Libreta Universitaria, el D.N.I. o la Cédula de Identidad.</p>
<h2>Nuestras propuestas</h2>
<ul>
<li>Un <strong>mayor contacto entre los Consejeros y los estudiantes</strong>, habilitándolos a los últimos a una mayor participación en la toma de decisiones dentro de la carrera de Ingeniería en Sistemas de Información, además de la posibilidad de realizar preguntas, plantear dudas, solucionar inconvenientes con cuestiones relacionadas con el cursado o exámenes por ejemplo. Se verá la factibilidad que haya en organizar reuniones periódicas con los estudiantes interesados en participar.</li>
<li>La <strong>creación de un Grupo de Investigación de Software Libre</strong>, que pueda formentar el uso de este tipo de aplicaciones, que ofrezca alternativas libres a las herramientas existentes para la realización de trabajos prácticos en el cursado de las distintas materias, así como la organización de distintos eventos relacionados con esta filosofía.</li>
<li><strong>Enseñanza del uso de herramientas que conducen a buenas prácticas en el desarrollo de software</strong>, como sistemas de control de versiones, herramientas para realizar pruebas de unidad (unit testing), seguimiento de errores y automatización de prácticas como la integración continua.</li>
<li><strong>Reuniones informativas sobre las actividades de investigación que se realizan</strong> en los distintos grupos de la Facultad, motivando a los alumnos en la participación de los mismos.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2008/06/06/elecciones-en-la-utn/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>LaTeX: Paquete listings</title>
		<link>http://www.miltonpividori.com.ar/2007/11/11/latex-paquete-listings/</link>
		<comments>http://www.miltonpividori.com.ar/2007/11/11/latex-paquete-listings/#comments</comments>
		<pubDate>Sun, 11 Nov 2007 18:29:37 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Facultad]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Software Libre]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=171</guid>
		<description><![CDATA[Desde hace un tiempo que vengo usando, para incluir archivos de código fuente en documentos LaTeX, el paquetes lgrind. El problema es que no se actualiza más (última versión de 2002). Hace un tiempo tuve la necesidad de incluir código fuente en C# en un documento de un TP. Gracias a un desarrollador de GNOME [...]]]></description>
			<content:encoded><![CDATA[<p>Desde hace un tiempo que vengo usando, para incluir archivos de código fuente en documentos LaTeX, el paquetes <a href="http://www.ctan.org/tex-archive/nonfree/support/lgrind/">lgrind</a>. El problema es que no se actualiza más (última versión de 2002).</p>
<p>Hace un tiempo tuve la necesidad de incluir código fuente en C# en un documento de un TP. Gracias a un desarrollador de GNOME he encontrado el <a href="http://www.ctan.org/tex-archive/macros/latex/contrib/listings/">paquete listings</a>, en el <a href="http://planet.gnome.org/">Planet GNOME</a>.</p>
<p>No sólo sirve para incluir archivos de código fuente, sino también para ficheros de configuración por ejemplo. Es realmente muy util. Pueden bajarse un manual <a href="http://www.pvv.ntnu.no/~berland/latex/docs/listings.pdf">aquí</a>.</p>
<p>Un ejemplo simple:</p>
<pre lang="latex">
\begin{lstlisting}[frame=single]
class X {
     string my_string;
     int    very_important_value;
}
\end{lstlisting}
</pre>
<p>Se pueden setear varias opciones, como &#8220;frame&#8221;, que dibuja una caja alrededor del código. También se pueden incluir archivos completos con el comando &#8220;\lstinputlisting&#8221;. <a href='http://www.miltonpividori.com.ar/wp-content/uploads/2007/11/main.pdf' title='main.pdf'>Aquí un ejemplo</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2007/11/11/latex-paquete-listings/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Mono/.NET: No importa el lenguaje</title>
		<link>http://www.miltonpividori.com.ar/2007/07/21/mononet-no-importa-el-lenguaje/</link>
		<comments>http://www.miltonpividori.com.ar/2007/07/21/mononet-no-importa-el-lenguaje/#comments</comments>
		<pubDate>Sat, 21 Jul 2007 16:37:48 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Facultad]]></category>
		<category><![CDATA[Mono/.NET]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=148</guid>
		<description><![CDATA[Una de las cosas que vamos a probar en el trabajo práctico de implementación de Administración de Recursos, es qué tan cierto es eso de que Mono/.NET es independiente del lenguaje. Bueno, estuve haciendo unas pruebas con Python y C#. Hay una implementación de código abierto (bajo la licencia de Microsoft Ms-PL) del intérprete de [...]]]></description>
			<content:encoded><![CDATA[<p>Una de las cosas que vamos a probar en el trabajo práctico de implementación de Administración de Recursos, es qué tan cierto es eso de que Mono/.NET es independiente del lenguaje.</p>
<p>Bueno, estuve haciendo unas pruebas con Python y C#. Hay una implementación de código abierto (bajo la licencia de Microsoft <a href="http://www.codeplex.com/IronPython/Project/License.aspx">Ms-PL</a>) del intérprete de Python escrita en C#, que permite ejecutar estos programas compilando el código Python a CIL (el código intermedio). También tiene una consola, como Python, y es posible utilizar toda la biblioteca de .NET. Se llama <a href="http://www.codeplex.com/IronPython">IronPython</a>.</p>
<p>Esta implementación, en su versión estable actual 1.1, tiene compatibilidad con CPython 2.4.4. Esto significa que un programa escrito para ser corrido con Python 2.4.4 puede correrse también con IronPython 1.1. Sin embargo no es que podemos correr cualquier cosa hecha para Python con IronPython: un juego que utiliza el módulo PyGame no funciona (por lo menos yo no pude).</p>
<p>Les voy a mostrar un ejemplo en el que desde Python creo una clase que hereda de otra creada en C#. Sip, ¡esto está muy bueno!</p>
<p><span id="more-148"></span></p>
<p>Esta es la clase <em>Persona</em> (si, es algo bien sencillo) en C#:</p>
<pre lang="csharp">
using System;

public class Persona
{
	private string nombre;
	private string apellido;

	public Persona(string nombre, string apellido)
	{
		this.nombre = nombre;
		this.apellido = apellido;

		Console.WriteLine("Constructor C#");
	}

	public string Nombre
	{
		get { return this.nombre; }
		set { this.nombre = value; }
	}

	public string Apellido
	{
		get { return this.apellido; }
		set { this.apellido = value; }
	}

	public string NombreEnMayusculas
	{
		get {
			return this.nombre.ToUpper();
		}
	}

	public string ApellidoEnMayusculas
	{
		get {
			return this.apellido.ToUpper();
		}
	}
}
</pre>
<p>Para los que no conocen C#, esas cuatro ultimas cosas raras que están definidas se llaman <em>propiedades</em>. Vienen a reemplazar los getters y setters. Así, en lugar de setear el nombre con un <em>objeto.setNombre(&#8220;Nombre nuevo&#8221;)</em>, lo hacemos con un <em>objeto.Nombre = &#8220;Nombre nuevo&#8221;</em>. Pueden ser de sólo lectura (cuando hay sólo un <em>get</em>), sólo escritura, o lectura/escritura.</p>
<p>En fin, la clase Python es esta:</p>
<pre lang="python">
import clr
clr.AddReferenceToFile("Persona.dll")

import Persona

class Mujer(Persona):

    def imprimirNombreCompleto(self):
        print self.Nombre + ' ' + self.Apellido

    def nombreEnMinusculas(self):
        return self.Nombre.lower()

    def apellidoEnMinusculas(self):
        return self.Apellido.lower()

x = Mujer('Juana', 'Vargas')
x.imprimirNombreCompleto()

print x.NombreEnMayusculas + ' ' + x.ApellidoEnMayusculas
print x.nombreEnMinusculas() + ' ' + x.apellidoEnMinusculas()
print x.nombreEnMinusculas() + ' ' + x.ApellidoEnMayusculas
</pre>
<p>(Cuando copian y pegan, las comillas simples se cambian. Así que no va a compilar a menos que las reemplacen)</p>
<p>Los pasos para probar este codigo son:</p>
<ol>
<li>Compilar la clase hecha en C# a una librería (Persona.dll) ejecutando: &#8220;mcs -t:library -out:Persona.dll Persona.cs&#8221;, suponiendo que han llamado al archivo de la clase C# <em>Persona.cs</em></li>
<li>Instalan la versión Community Edition de IronPython (IPCE). La pueden bajar <a href="http://sourceforge.net/project/showfiles.php?group_id=178069&#038;package_id=209325&#038;release_id=509859">aquí</a>. Hay que agregar a la variable de entorno PATH el lugar donde lo descompriman.</li>
<li>Corren el archivo Mujer.py (suponiendo que así lo han llamado) con IronPython: &#8220;ipy.exe Mujer.py&#8221;</li>
</ol>
<p>La salida de eso es:</p>
<pre>
Constructor C#
Juana Vargas
JUANA VARGAS
juana vargas
juana VARGAS
</pre>
<h2>Python desde C#</h2>
<p>Lamentablemente el ejemplo anterior invertido no es posible (crear una clase en C# que herede de la de Python), sin embargo obvio que sí se pueden ejecutar métodos y otras cosas.</p>
<p>Python es un lenguaje dinámico, y esta característica complica las cosas. Si bien IronPython ha demostrado que <a href="http://en.wikipedia.org/wiki/Common_Language_Runtime">CLR</a> (Common Language Runtime) tiene buen soporte para los lenguejes dinámicos, se está trabajando en una capa que está encima de CLR, llamada <a href="http://en.wikipedia.org/wiki/Dynamic_Language_Runtime">DLR</a> (Dynamic Language Runtime) que lo hace muchísimo mejor para este tipo de lenguajes. DLR hace que sea mucho más fácil implementar lenguajes dinámicos en .NET, además de poder compartir código con otros lenguajes (dinámicos y estáticos).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2007/07/21/mononet-no-importa-el-lenguaje/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Visualización de árboles de búsqueda usando LaTeX</title>
		<link>http://www.miltonpividori.com.ar/2007/06/17/visualizacion-de-arboles-de-busqueda-usando-latex/</link>
		<comments>http://www.miltonpividori.com.ar/2007/06/17/visualizacion-de-arboles-de-busqueda-usando-latex/#comments</comments>
		<pubDate>Sun, 17 Jun 2007 17:10:59 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Facultad]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=124</guid>
		<description><![CDATA[En el trabajo práctico número 1 de Inteligencia Artificial, tuvimos que programar un pacman para que actuara en un ambiente donde había enemigos y alimento. Debíamos utilizar alguna estrategia de búsqueda. En este tipo de estrategias, para encontrar una buena acción a llevar a cabo, el agente genera un árbol. El nodo principal representa el [...]]]></description>
			<content:encoded><![CDATA[<p>En el trabajo práctico número 1 de Inteligencia Artificial, tuvimos que programar un pacman para que actuara en un ambiente donde había enemigos y alimento. Debíamos utilizar alguna estrategia de búsqueda.</p>
<p>En este tipo de estrategias, para encontrar una buena acción a llevar a cabo, el agente genera un árbol. El nodo principal representa el estado inicial del mismo. Por ejemplo, dicho estado indica que está en la posición (X,Y), con una cantidad determinada de energía y el conocimiento de N celdas. El agente aplica las acciones que son posibles en este nodo (estado), y así genera más nodos, que serán los hijos del primero, por cada una de las acciones aplicadas. Esto representa la <em>expansión</em> del nodo principal.</p>
<p>Así el agente va expandiendo nodos. Una vez que lo hace con el nodo principal, tiene que elegir otro. Y aquí es justamente donde difiere cada estrategia. Por lo demás, son idénticas. Algunas de las formas de ir eligiendo los nodos podría ser por <em>profundidad</em>, <em>amplitud</em>, o <em>costo uniforme</em>. En esta última existe un costo por cada acción, y la estrategia elije el siguiente nodo a expandir según cuál tenga el menor costo. Otra estrategia es la avara, la cual en lugar de utilizar un costo para los nodos, usa una heurística, que indica qué tan lejos del objetivo está, entonces toma una decisión según la acción que más lo acerque al mismo.</p>
<p>Volviendo al tema del post, en el trabajo práctico teníamos que mostrarle a los profesores que nuestro código funcionaba correctamente, es decir, si habíamos elegido la estrategia de amplitud, entonces la lista de nodos expandidos tenía que tener un orden de acuerdo a la misma. Una forma de hacerlo era escribir un archivo XML que vaya indicando cómo se forma el árbol y qué nodos se eligen. Pero es un poco tedioso leer un archivo así.</p>
<p><span id="more-124"></span></p>
<p>Estaría muy bueno que al correr el simulador se dibuje un árbol, por ejemplo en PDF, con los nodos que han sido elegidos por el algoritmo implementado, mostrando información de los mismos y qué acciones fueron tomadas para llegar a ellos. Esto parece complicado, pero no lo es si utilizamos LaTeX y el paquete <a href="http://www.ling.upenn.edu/advice/latex/qtree/">qtree</a>.</p>
<p>Lo que debemos hacer es guardar en una cola los nodos que el algoritmo fue expandiendo, es decir, eligiendo. También hay que pensar en un número de niveles a dibujar, que coincide por supuesto con los nodos elegidos para expandir. El código siguiente, en Java, escribe el documento LaTeX completo, listo para compilar:</p>
<pre lang="java">
private void toLatex(LinkedList<Nodo> nodosSeleccionados, int niveles) {

	/* Salida para latex (genera un arbol usando el paquete qtree). El
	 * siguiente código genera el documento completo para compilar. Sólo
	 * hay que disponer de los paquetes necesarios. */

	// Clase del documento y opciones generales
	Busqueda.logLatex.debug("\\documentclass[a0,landscale]{a0poster}");

	// Paquetes utilizados
	Busqueda.logLatex.debug("\\usepackage{mathptmx}");
	Busqueda.logLatex.debug("\\usepackage[scaled=.90]{helvet}");
	Busqueda.logLatex.debug("\\usepackage{courier}");
	Busqueda.logLatex.debug("\\usepackage{qtree}");
	Busqueda.logLatex.debug("\\usepackage{nodo}");
	Busqueda.logLatex.debug("\\usepackage[spanish]{babel}");
	Busqueda.logLatex.debug("\\usepackage[utf8]{inputenc}");

	Busqueda.logLatex.debug("\\title{Árbol de ejecución - Estrategia: " +
		this.nombreEstrategia() + "}");
	Busqueda.logLatex.debug("\\author{}");
	Busqueda.logLatex.debug("\\begin{document}");
	Busqueda.logLatex.debug("\\maketitle");

	StringBuffer sf = new StringBuffer();
	int cuentaArboles = 0;
	int nivelesProcesados = 0;

	for (Nodo unNodo : nodosSeleccionados) {
		if (cuentaArboles == 0)
			sf.append("\\begin{figure}[!h]\n");

		sf.append("\\Tree " + unNodo.toQtree() + "\n");
		cuentaArboles++;

		if (cuentaArboles == 4) {
			cuentaArboles = 0;
			sf.append("\\end{figure}\n");
		}

		nivelesProcesados++;

		if (nivelesProcesados >= niveles)
			break;
	}

	if (cuentaArboles > 0)
		sf.append("\\end{figure}");
	sf.append("\n");
	Busqueda.logLatex.debug(sf.toString());
	Busqueda.logLatex.debug("\\end{document}");
}
</pre>
<p>Sólo hay que colocar el documento generado (nosotros utilizamos <a href="http://logging.apache.org/log4j/docs/">log4j</a> para las salidas) junto a los archivos de qtree. Claro que no genera el árbol en la forma estándar (debido a cómo el paquete dibuja los árboles), sino que toma un nodo (por ejemplo el primero elegido, que vendría a ser la raíz), lo dibuja junto a sus hijos, luego pasa al siguiente nodo expandido y lo dibuja en un subárbol aparte con sus hijos, y así sucesivamente.</p>
<p>De esta forma, es mucho más cómodo visualizar el funcionamiento de nuestro algoritmo, que implementa alguna estrategia de búsqueda, que seguir con la vista un críptico archivo de texto. Los árboles generados se leen de izquierda a derecha, de arriba a abajo. Este orden de lectura, como mencioné antes, representa la secuencia de nodos que el algoritmo fue eligiendo para expandir.</p>
<p>Algunos ejemplos de archivos PDF generados&#8230;<br />
<lu></p>
<li>&#8230;<a href="http://www.miltonpividori.com.ar/files/avara2.pdf">con una <b>búsqueda avara</b></a>. Un comentario sobre el algoritmo: tiene una perfomance excelente, generando muy pocos nodos (en el ejemplo está el árbol completo, lo que sería impensable para nuestra implementación de A*), y además las acciones tomadas por el agente son muy buenas.</li>
<li>&#8230;<a href="http://www.miltonpividori.com.ar/files/aestrella.pdf">con una <b>búsqueda A*</b></a>. En este caso, verán, sí utiliza los 16 niveles (es el valor que le paso por defecto a la función que les mostré antes), siendo un subárbol muy pequeño a comparación del árbol completo, ya que en la ejecución generó 2731 nodos.</li>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2007/06/17/visualizacion-de-arboles-de-busqueda-usando-latex/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>2da Jornada Python en Santa Fe</title>
		<link>http://www.miltonpividori.com.ar/2007/05/24/2da-jornada-python-en-santa-fe/</link>
		<comments>http://www.miltonpividori.com.ar/2007/05/24/2da-jornada-python-en-santa-fe/#comments</comments>
		<pubDate>Fri, 25 May 2007 02:05:17 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Facultad]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=113</guid>
		<description><![CDATA[El 9 de junio se va a realizar la 2da Jornada Python en el Auditorio de la UTN &#8211; Facultad Regional Santa Fe, organizado por el LUGli. Las charlas se realizarán desde las 8.30 hasta las 18.30. Las mismas cubren una gran variedad de niveles, desde básicas como &#8220;Introducción a Python&#8220;, a muy avanzadas como [...]]]></description>
			<content:encoded><![CDATA[<p>El 9 de junio se va a realizar la <a href="http://www.pythonensantafe.com.ar/">2da Jornada Python</a> en el Auditorio de la <a href="http://www.frsf.utn.edu.ar/">UTN &#8211; Facultad Regional Santa Fe</a>, organizado por el <a href="http://www.lugli.org.ar/">LUGli</a>. <a href="http://www.pythonsantafe.com.ar/programacion">Las charlas</a> se realizarán desde las 8.30 hasta las 18.30. Las mismas cubren una gran variedad de niveles, desde básicas como &#8220;<em>Introducción a Python</em>&#8220;, a muy avanzadas como &#8220;<em>Usando Python para testeos de seguridad mediante simulación automática de ataques</em>&#8220;. La entrada es libre y gratuita.</p>
<p>Python es un lenguaje de programación libre, multiplataforma, poderoso y al mismo tiempo muy fácil de utilizar. Si bien, siendoles sincero, nunca lo he aprendido y utilizado (por falta de tiempo), sí he visto código y experiencias de profesionales que afirman esto. Si estas interesando en aprender un nuevo lenguaje de programación, te recomiendo elegir python, y asistir a estas jornadas, que se realizan por segundo año consecutivo en nuestra ciudad. Es muy recomendable <a href="http://www.pythonsantafe.com.ar/registraci-n">registrarse</a>, y de ser posible, adquirir un certificado del evento, no sólo por las razones obvias, sino también para apoyarnos económicamente.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2007/05/24/2da-jornada-python-en-santa-fe/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Java: Wrapper para clases en el default package</title>
		<link>http://www.miltonpividori.com.ar/2007/04/18/java-wrapper-para-clases-en-el-default-package/</link>
		<comments>http://www.miltonpividori.com.ar/2007/04/18/java-wrapper-para-clases-en-el-default-package/#comments</comments>
		<pubDate>Thu, 19 Apr 2007 02:17:37 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Facultad]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=109</guid>
		<description><![CDATA[Si tu proyecto en Java tiene una clase que no pertenece a ningún paquete (no posee al principio la sentencia &#8220;package&#8230;&#8221;), entonces pertenece al default package. Si intentan utilizar esa clase desde otra clase sin paquete no hay problemas, pero es imposible hacerlo (a partir de java 1.4) desde clases que sí pertenecen a algún [...]]]></description>
			<content:encoded><![CDATA[<p>Si tu proyecto en Java tiene una clase que no pertenece a ningún paquete (no posee al principio la sentencia &#8220;package&#8230;&#8221;), entonces pertenece al default package. Si intentan utilizar esa clase desde otra clase sin paquete no hay problemas, pero es imposible hacerlo (a partir de java 1.4) desde clases que sí pertenecen a algún paquete. Averiguar esto me llevó gran parte de la tarde. Ya veo que le pifié en algo y la cosa era mucho mas sencilla&#8230;</p>
<p>Bueno, ese es el problema con la <strong>clase Calculador</strong> que proveyó la cátedra de <strong>Inteligencia Artificial</strong>. No tiene paquete. Si ya se armaron todo su código ordenadito en paquetes no van a poder utilizarla. Sólo se puede desde una clase sin paquete&#8230; pero queda muy desordenado poner todas las clases en un mismo paquete, y además no es recomendado.</p>
<p>Pero hay una solución. Podemos seguir teniendo nuestro proyecto ordenado y utilizar esta bendita clase.</p>
<p><span id="more-109"></span><br />
Lo que pueden hacer los profesores directamente es ponerle un paquete a la clase Calculador y armar un jar. Es lo más fácil, obvio&#8230; pero esto que voy a mencionar aquí es útil para cuando encuentren un archivo .class sin su código fuente, el programador no incluyó la clase en un paquete, es imposible contactar a esta persona o no quiere cambiarlo, y tienen su proyecto organizado con una jerarquía de paquetes (sí, se tienen que dar todas estas condiciones <img src='http://www.miltonpividori.com.ar/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' />  Es poco probable pero esto me divirtió toda la tarde).</p>
<p>Como dije antes, Java 1.4 y superiores no permiten importar clases del default package desde clases que sí pertenecen a uno. Entonces lo que se puede hacer es armar un wrapper, compilar con java 1.3 (que sí permite importar estas clases) y utilizar el wrapper en nuestro proyecto. No hace falta bajarse el jdk viejo&#8230; <a href="http://www.innovation.ch/java/java_compile.html">ésta página</a> soluciona nuestros problemas.</p>
<p>Les dejo a disposición de ustedes <a href="http://www.miltonpividori.com.ar/files/CalculadorWrapper.jar">un archivo jar</a> que al importar en su proyecto pueden comenzar a utilizar el Calculador del TP (las clases Calculador y Pair se traducen a CalculadorWrapper y PairWrapper), hasta que los profesores liberen una versión corregida.</p>
<p>Si ejecutan <em>java -jar CalculadorWrapper.jar</em> les tira por pantalla una prueba de los métodos de la clase.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2007/04/18/java-wrapper-para-clases-en-el-default-package/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
